uTomate for custom builds

I was having a look at the cloud build tool and as far as I can see the build process is very static and not much open to extension except for the two preProcess and postProcess methods. Actually I would like to use a completely custom script, so I could use uTomate for building my cloud builds. That way I could prepare and test a complete automation plan on my local machine and then just have it run in the cloud. Also,I wouldn’t have to create two copies of build instructions (one for my local/inhouse development and one for Unity Cloud). I could just use one automation plan and that would be executed everywhere. Another upside would be, that I would not be dependent on the Unity guys implementing all the various settings/actions that might be required to make my build work. Has anyone found a way of truely running customized scripts or is this on the roadmap?

Hi @kork - That is an interesting idea. You’re welcome to request access to the advanced settings and see if you’re able to get this setup working. Good luck!

Hi @hypeNate , thank you. I have requested access to try that out (Ticket number is #15043). Once that is granted, I will try around a bit and report my results.

I have made uTomate run on the pre-execution method as a proof of concept. However after that, there seems to be an issue with creating the cloud build manifest:

[Unity] Creating Build Manifest text asset at Assets/__UnityCloud__/Resources/UnityCloudBuildManifest.json.txt
384: [Unity] UnityEngine.Debug:Internal_Log(Int32, String, Object)
385: [Unity] UnityEngine.Debug:Log(Object)
386: [Unity] UnityCloud.UnityCloudBuilder:Log(String, Object[]) (at Assets/__UnityCloud__/Scripts/Editor/UnityCloudBuilder.cs:106)
387: [Unity] UnityCloud.UnityCloudBuilder:Log(String, Object) (at Assets/__UnityCloud__/Scripts/Editor/UnityCloudBuilder.cs:101)
388: [Unity] UnityCloud.UnityCloudBuilder:SaveBuildManifestAssets(BuildManifestObject) (at Assets/__UnityCloud__/Scripts/Editor/UnityCloudBuilder.cs:610)
389: [Unity] UnityCloud.UnityCloudBuilder:Build() (at Assets/__UnityCloud__/Scripts/Editor/UnityCloudBuilder.cs:204)
390: [Unity] (Filename: Assets/__UnityCloud__/Scripts/Editor/UnityCloudBuilder.cs Line: 106)
391: [Unity] MissingReferenceException: The object of type 'BuildManifestObject' has been destroyed but you are still trying to access it.
392: [Unity] Your script should either check if it is null or you should not destroy the object.
393: [Unity] at (wrapper managed-to-native) UnityEditor.AssetDatabase:CreateAsset (UnityEngine.Object,string)
394: [Unity] at UnityCloud.UnityCloudBuilder.SaveBuildManifestAssets (UnityCloud.BuildManifestObject manifest) [0x0005f] in /BUILD_PATH/BVR_TEMP_DIR/d20141117-23524-1p45qy4/Assets/__UnityCloud__/Scripts/Editor/UnityCloudBuilder.cs:620
395: [Unity] at UnityCloud.UnityCloudBuilder.Build () [0x00092] in /BUILD_PATH/BVR_TEMP_DIR/d20141117-23524-1p45qy4/Assets/__UnityCloud__/Scripts/Editor/UnityCloudBuilder.cs:204
396: [Unity] (Filename: Assets/__UnityCloud__/Scripts/Editor/UnityCloudBuilder.cs Line: 620)
397: [Unity] executeMethod method UnityCloud.UnityCloudBuilder.Build threw exception.
398: [Unity] (Filename: /APPLICATION_PATH/buildAgent/work/d63dfc6385190b60/Runtime/Utilities/Argv.cpp Line: 117)
399: [Unity] Aborting batchmode due to failure:
400: [Unity] executeMethod method UnityCloud.UnityCloudBuilder.Build threw exception.

Could the be caused by the pre-execution method calling “AssetDatabase.Refresh”?

I also made a few more observations:

  • The pre/post methods should support co-routine-like behaviour. That this it should be possible for them to return an IEnumerator. If they return IEnumerator they should be processed per editor-frame for as long as their enumerator works. I currently have faked this by using a polling while loop, inside my script but I am not sure if Unity likes it when it’s main thread is blocked for a potentially long time when running the pre/post methods. Using the IEnumerator, one could execute a part of the script while not blocking the main thread for too long. If that is not a problem, I can live with the loop-hack as well.
  • The logging should not include stacktraces for every call to Debug.Log. While the editor will neatly tuck the traces away in the logging console, they introduce an immense amount of noise into the log files with no real added value.
  • There should be a third method which is called after the file is fully built (e…g for iOS builds, after XCode has finished creating the .ipa file). uTomate could then be used to upload the built image somehwere (e.g. to a corporate repository, to TestFlight (that would kill this bird Automate Push to Testflight - Unity Services - Unity Discussions with the same stone), or do any other postprocessing of the built files that is required, even notify other systems that the build is ready and can be fetched from cloud build. The method could for example take the path(s) of the build’s final output(s) as parameter.
1 Like

@kork - this is great feedback, thanks! That BuildManifest error is pretty strange - are you trying to access the BuildManifest specifically in your automation? Or is that error occurring even though you aren’t attempting to use it?

@hypeNate , the issue occurs even though I am not accessing the BuildManifest at all. My pre-script basically does the following things:

  • Open a scene.
  • Find a game object in that scene.
  • Modify a property of that game object.
  • Save the scene.
  • Modify the list of scenes.

(all of that is done through uTomate actions). The build manifest is not accessed at all. What uTomate does is, that it’s calling AssetDatabase.Refresh() at the end of the run. Could that cause issue with the build manifest?

1 Like

Hi @kork - that is interesting! We need to look into this a bit more, but this problem is likely related to opening / saving the scene. We should be marking the build manifest as “dontdestroyonload” so it doesn’t get removed after a scene load. You can try this yourself if you want, but we will also work on verifying that is what is happening - and if so, create a fix for it. Thanks for brining it to our attention!

Hi @hypeNate , I can confirm that removing steps 1-4 from the plan makes the issue go away, so I’d say it’s indeed related to opening the scene. I’ll keep exploring :slight_smile:

1 Like

My next project: I tried building an asset bundle, something that commonly happens and usually takes time, so ideal work to load off into the cloud.

  • Build failed again, as the BuildManifest is lost (same error message, probably because building an asset bundle triggers a complete refresh and any unsaved changes get lost). I’m not sure if a “DontDestroyOnLoad” would help here, rather the BuildManifest should be persisted. I assume it’s some kind of ScriptableObject.
  • There seems to be no way to retrieve built asset bundles from the UI. There should be a way to specify the path of the artifacts of your build (so the UI can pick them up).

Hi @kork - yes, although support for building asset bundles does not yet exist in Unity Cloud Build, it is something that we are aware of and that we consider a good use-case for the system. Thanks for the input - keep it coming!

I have spent another round on the integration, and for now found a reasonably straightforward (read “end-user-friendly”) way to make this happen (see GitHub - derkork/uTomate-UnityCloudBuildSample: A sample project for using uTomate with Unity Cloud Build for details).

I also fiddled around with the build manifest, as it is probably something that people may want to access during the build process. Of course one could use the suggested approach of reading the resource at runtime using a JSON parser. But the information could as well be extracted at build time and brought right into a format that wouldn’t need additional parsing and processing at runtime (and no additional JSON parser dependency).

So I took the liberty and did some scripted workspace introspection to find out how it’s all working under the hood and check if there would be a way to get access to this at build time. As an additional requirement, I would love to be able to test all the scripts outside of Unity cloud, so I don’t have a 3-5 minute turnaround cycle between build script iterations. So I came up with a minimal API for accessing the Build Manifest at build time (boastfully named CloudBuildAPI, though there is not much else except build manifests for now).

Here is how you would use that in a uTomate action (right now only for printing, but to get the idea):

Basically, it uses the UNITY_CLOUD_BUILD scripting define to determine if it’s actually running in the cloud. If so, it uses the classes used inside the cloud build workspace to access the information (why reinvent the wheel when it’s all already there, plus you get free bugfixes from Unity ;). When it’s not running in the cloud, it’s just falling back to a fake hash map. Build scripts can code against this API and can be tested locally and left unchanged when being deployed to the cloud. So far so good.

But - and there is always a but - it only works for post-export scripts so far, as the file is actually only saved after running the pre-export method. And before that, it’s in a rather undefined state. That is something that probably would need to be changed anyways (as there are issues when you do anything fancy in the pre-process method).

So bottom line for today: Some kind of API for accessing build-related stuff easily from custom build scripts would be nice (and not very hard to do). An additional plus would be if that API would fallback gracefully in non-cloud environments for easy testing (surely doable, but might get tricky from time to time).

Finally after having seen how everything works internally, I think it would be rather easy (technically, that is) to provide a way to do completely custom builds. You just provide your build script, you have an API that gives you access to things like output paths, manifest info and whatnot and you’re completely free to build whatever you need to build, prepare whatever you need to prepare, in the cloud. That API could also be used for reporting the paths of the built artifact(s) back to the UI, so you could then display all artifacts there (more a push-like solution, another way would be a text field in the UI where you could specify artifact paths, like in TeamCity).

Ow well, this post has gotten longer than I intended to, so I hit send for now and be back tomorrow for even more fun :slight_smile:

Hi @kork - It’s exciting to see UCB is developing interest from people like yourself, who excel at making tools! You’re definitely one of us :wink:

However, be aware that some of the aspects of the Unity Cloud Build system discussed here and in your API are intended to be internal details - they aren’t necessarily invisible in a build, but they could change at any time, and we do not support any attempts to modify them accordingly.

We do have plans to offer a lot more future customization options, some of which may help with automation work.

Thanks for all the interest and input, and please continue to watch for updates!

@hypeNate ,thank you very much for your kind words and the friendly reminder about using internal stuff. I am well aware that my current solution to access manifest implementations at build time is nothing more than a hack which will quickly break should you choose to implement it otherwise. Also I woudln’t go down the “lets modify Unity’s scripts through code” route; first and furthermost it wouldn’t work (it would trigger a recompile and then the build is interrupted). The second reason would be, that it would be just another hack.

Basically what I am trying to show with:

https://github.com/derkork/uTomate-…/Assets/CloudBuildAPI/Editor/CloudBuildAPI.cs

is, that an API which is designed like that would be helpful for anyone trying to implement custom build scripts for UCB. The basic problem is, that you would need some API code against so you could run the build scripts locally (or at least don’t get compile errors). That can easily be solved with a bunch of C# scripts provided by Unity (for example over the asset store) which give you an interface (and preferably a mock) on your local machine, and then integrate with the actual UCB when being run inside it. And it would work with any Unity version supported by UCB.

I will try to expand on that example, so you would get something that would allow you to run the complete UCB workflow locally. I am aware that this will break as soon as you decide to reimplement things on your side, but I just want to know if it would be possible to do (a proof of concept, if you so will).

For extremely simple projects where you just build a player and that’s it, that would of course be total overkill. But for anything more complex, e.g. for builds that come with asset bundles, or need preprocessing and postprocessing, being able to develop and test your build script locally is invaluable, as it saves you the 3-5 minute roundtrip through UCB.

Since this thread is quite old but the only one about uTomate I wanted to check what the current status is.

My builds also use uTomate extensively to calculate lightmaps, navmeshes, show/hide certain objects etc. Can uTomate be triggered from UCB? So instead of executing a build I’d execute a uTomate automation plan and that would then in turn execute the build? Or even multiple builds for different platforms? It’s kind of against the concept of javing one job per platform but would mean I can have the same locally as in the cloud.

The way UCB is built right now, you can only use uTomate to pre/postprocess the built player. Building the player is done by UCB. It’s very hard to do anything with UCB that isn’t provided by UCB itself as the UCB workflow is very rigid (I assume it has to be for security reasons). So technically: yes you can run uTomate in the cloud (I did it with the GitHub project i mentioned in my last post) but you are quite limited to what you can do, as you cannot just say “Run this uTomate plan and be done with it”.