How to get git commit hash during PreExport?

Hello!

We would like to make the current git hash visible in our builds. When we build locally, our build script grabs the current git hash and sticks it in a .txt file that we can display at runtime.

It does not seem like our PreExport script works with Unity Cloud Build. Is there a way we can grab this hash and write it to a .txt file right before building?

Here is the code we are running on PreExport.

using UnityEngine;
using System;

public static class PreExport {

    public static void DoIt()
    {
        try
        {
            Debug.Log("Going to attempt getting git hash from command line.");
            // Get the short commit hash of the current branch.
            string cmdArguments = "/c git rev-parse --short HEAD";
            Debug.Log("About to create ProcessStartInfo.");
            var procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", cmdArguments);
            Debug.Log("Made the ProcessStartInfo. now setting some properties.");

            // The following commands are needed to redirect the standard output.
            // This means that it will be redirected to the Process.StandardOutput StreamReader.
            procStartInfo.RedirectStandardOutput = true;
            procStartInfo.UseShellExecute = false;
            // Do not create the black window.
            procStartInfo.CreateNoWindow = true;
            Debug.Log("Properties set. Now making a new Process.");
            // Now we create a process, assign its ProcessStartInfo and start it
            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            Debug.Log("Assigning ProcessStartInfo to this Process.");
            proc.StartInfo = procStartInfo;
            Debug.Log("Running git process.");
            proc.Start(); // EXCEPTION here?
            // Get the output into a string
            Debug.Log("Attempting to get output."); // Never runs
            string result = proc.StandardOutput.ReadToEnd();
            Debug.Log("Got git result: " + result);
        }
        catch (Exception e)
        {
            Debug.Log("Unable to run command to get git commit hash. Got exception");
            Debug.Log(e); // Does not seem to give us any info.
        }
        Debug.Log("Unable to get git hash.");
    }
}

It seems to give us an error when we try to start the process with proc.Start() . However, I can’t tell what type of exception we are getting. Here is the output from Unity Cloud Build.

1023: [Unity] Going to attempt getting git hash from command line.
1024: [Unity] UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
1025: [Unity] UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
1026: [Unity] UnityEngine.Logger:Log(LogType, Object)
1027: [Unity] UnityEngine.Debug:Log(Object)
1028: [Unity] PreExport:smile:oIt() (at Assets/Editor/PreExport.cs:11)
1029: [Unity] System.Reflection.MonoMethod:InternalInvoke(Object, Object[], Exception&)
1030: [Unity] UnityEditor.CloudBuild.UnityReflector:CallStaticEditorMethod(String, Boolean, Object[])
1031: [Unity] UnityEditor.CloudBuild.Builder:Build()
1032: [Unity] (Filename: Assets/Editor/PreExport.cs Line: 11)
1033: [Unity] About to create ProcessStartInfo.
1034: [Unity] UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
1035: [Unity] UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
1036: [Unity] UnityEngine.Logger:Log(LogType, Object)
1037: [Unity] UnityEngine.Debug:Log(Object)
1038: [Unity] PreExport:smile:oIt() (at Assets/Editor/PreExport.cs:14)
1039: [Unity] System.Reflection.MonoMethod:InternalInvoke(Object, Object[], Exception&)
1040: [Unity] UnityEditor.CloudBuild.UnityReflector:CallStaticEditorMethod(String, Boolean, Object[])
1041: [Unity] UnityEditor.CloudBuild.Builder:Build()
1042: [Unity] (Filename: Assets/Editor/PreExport.cs Line: 14)
1043: [Unity] Made the ProcessStartInfo. now setting some properties.
1044: [Unity] UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
1045: [Unity] UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
1046: [Unity] UnityEngine.Logger:Log(LogType, Object)
1047: [Unity] UnityEngine.Debug:Log(Object)
1048: [Unity] PreExport:smile:oIt() (at Assets/Editor/PreExport.cs:16)
1049: [Unity] System.Reflection.MonoMethod:InternalInvoke(Object, Object[], Exception&)
1050: [Unity] UnityEditor.CloudBuild.UnityReflector:CallStaticEditorMethod(String, Boolean, Object[])
1051: [Unity] UnityEditor.CloudBuild.Builder:Build()
1052: [Unity] (Filename: Assets/Editor/PreExport.cs Line: 16)
1053: [Unity] Properties set. Now making a new Process.
1054: [Unity] UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
1055: [Unity] UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
1056: [Unity] UnityEngine.Logger:Log(LogType, Object)
1057: [Unity] UnityEngine.Debug:Log(Object)
1058: [Unity] PreExport:smile:oIt() (at Assets/Editor/PreExport.cs:24)
1059: [Unity] System.Reflection.MonoMethod:InternalInvoke(Object, Object[], Exception&)
1060: [Unity] UnityEditor.CloudBuild.UnityReflector:CallStaticEditorMethod(String, Boolean, Object[])
1061: [Unity] UnityEditor.CloudBuild.Builder:Build()
1062: [Unity] (Filename: Assets/Editor/PreExport.cs Line: 24)
1063: [Unity] Assigning ProcessStartInfo to this Process.
1064: [Unity] UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
1065: [Unity] UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
1066: [Unity] UnityEngine.Logger:Log(LogType, Object)
1067: [Unity] UnityEngine.Debug:Log(Object)
1068: [Unity] PreExport:smile:oIt() (at Assets/Editor/PreExport.cs:27)
1069: [Unity] System.Reflection.MonoMethod:InternalInvoke(Object, Object[], Exception&)
1070: [Unity] UnityEditor.CloudBuild.UnityReflector:CallStaticEditorMethod(String, Boolean, Object[])
1071: [Unity] UnityEditor.CloudBuild.Builder:Build()
1072: [Unity] (Filename: Assets/Editor/PreExport.cs Line: 27)
1073: [Unity] Running git process.
1074: [Unity] UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
1075: [Unity] UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
1076: [Unity] UnityEngine.Logger:Log(LogType, Object)
1077: [Unity] UnityEngine.Debug:Log(Object)
1078: [Unity] PreExport:smile:oIt() (at Assets/Editor/PreExport.cs:29)
1079: [Unity] System.Reflection.MonoMethod:InternalInvoke(Object, Object[], Exception&)
1080: [Unity] UnityEditor.CloudBuild.UnityReflector:CallStaticEditorMethod(String, Boolean, Object[])
1081: [Unity] UnityEditor.CloudBuild.Builder:Build()
1082: [Unity] (Filename: Assets/Editor/PreExport.cs Line: 29)
1083: [Unity] Unable to run command to get git commit hash. Got exception
1084: [Unity] UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
1085: [Unity] UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
1086: [Unity] UnityEngine.Logger:Log(LogType, Object)
1087: [Unity] UnityEngine.Debug:Log(Object)
1088: [Unity] PreExport:smile:oIt() (at Assets/Editor/PreExport.cs:38)
1089: [Unity] System.Reflection.MonoMethod:InternalInvoke(Object, Object[], Exception&)
1090: [Unity] UnityEditor.CloudBuild.UnityReflector:CallStaticEditorMethod(String, Boolean, Object[])
1091: [Unity] UnityEditor.CloudBuild.Builder:Build()
1092: [Unity] (Filename: Assets/Editor/PreExport.cs Line: 38)
1093: [Unity] at System.Diagnostics.Process.Start_noshell (System.Diagnostics.ProcessStartInfo startInfo, System.Diagnostics.Process process) [0x00000] in <filename unknown>:0
1094: [Unity] at System.Diagnostics.Process.Start_common (System.Diagnostics.ProcessStartInfo startInfo, System.Diagnostics.Process process) [0x00000] in <filename unknown>:0
1095: [Unity] at System.Diagnostics.Process.Start () [0x00000] in <filename unknown>:0
1096: [Unity] at (wrapper remoting-invoke-with-check) System.Diagnostics.Process:Start ()
1097: [Unity] at PreExport.DoIt () [0x00070] in /BUILD_PATH/garth-smith.githash.default-android/Assets/Editor/PreExport.cs:30
1098: [Unity] UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
1099: [Unity] UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
1100: [Unity] UnityEngine.Logger:Log(LogType, Object)
1101: [Unity] UnityEngine.Debug:Log(Object)
1102: [Unity] PreExport:smile:oIt() (at Assets/Editor/PreExport.cs:39)
1103: [Unity] System.Reflection.MonoMethod:InternalInvoke(Object, Object[], Exception&)
1104: [Unity] UnityEditor.CloudBuild.UnityReflector:CallStaticEditorMethod(String, Boolean, Object[])
1105: [Unity] UnityEditor.CloudBuild.Builder:Build()
1106: [Unity] (Filename: Assets/Editor/PreExport.cs Line: 39)
1107: [Unity] Unable to get git hash.
1108: [Unity] UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
1109: [Unity] UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
1110: [Unity] UnityEngine.Logger:Log(LogType, Object)
1111: [Unity] UnityEngine.Debug:Log(Object)
1112: [Unity] PreExport:smile:oIt() (at Assets/Editor/PreExport.cs:41)
1113: [Unity] System.Reflection.MonoMethod:InternalInvoke(Object, Object[], Exception&)
1114: [Unity] UnityEditor.CloudBuild.UnityReflector:CallStaticEditorMethod(String, Boolean, Object[])
1115: [Unity] UnityEditor.CloudBuild.Builder:Build()
1116: [Unity] (Filename: Assets/Editor/PreExport.cs Line: 41)

Is there a way we can have Unity Cloud Build grab the git hash right before building?

It seems like there is a way for UCB to pass in the commit hash on PreExport.

See: Unity ID

Your pre export method can receive a BuildManifestObject object instance. This object is “injected” by the cloud build process and contains data about the currently running build (see the link above).

Personally, we’ve had some issues setting this up initially:

  • The BuildManifestObject is not referenced locally… it is “injected” during builds.
  • The class’s interface was not documented; i see that it is documented now, but i think we’ve had issues since there were some differences between how it is implemented and what the docs say.
  • The docs are kinda confusing as it gives you 2 options (load as json or use BuildManifestObject). Not sure why you would need both options.
  • Lastly, the whole code that uses BuildManifestObject has to be #ifdef’d for cloud build only (not shown in the sample).

Here’s a code example that you can use to get the hash:

using UnityEngine;
using UnityEditor;
using System;

#if UNITY_CLOUD_BUILD

public static class CloudBuildHelper
{
    public static void PreExport(UnityEngine.CloudBuild.BuildManifestObject manifest)
    {
        var commit = manifest.GetValue("scmCommitId", "unknown");
    }
}

#endif
1 Like

Hi liortal, I’ve tried both your the docs’ version and your version of accessing the BuildManifestObject, but with no success. When I try your code, I get the following error:

801: [Unity] Assets/Scripts/CloudBuildHelper.cs(11,64): error CS1525: Unexpected symbol )', expecting ,’ or `;’

The culprit appears to be the first closing paren after “unknown”. Is it possible that the GetValue() function has changed syntax in the last three weeks since your message? I doubt it, but why else would mine fail in this manner?

Can you post your code? That sounds like a syntax error. Here is the stub class I use for BuildManifestObject. Note, that I had to add the CLOUD_BUILD to the build config.

#if !CLOUDBUILD
using System.Collections.Generic;

namespace UnityEngine.CloudBuild
{
    /// <summary>
    /// This is a stub for Unity Cloud Builds. This is not available on a local machine yet,
    /// but it is defined in the Unity Cloud Build environment.
    ///
    /// IMPORTANT! This means this file should be added to .gitignore. This file only exists
    /// so we can write code using it, but UCB will provide their own version of this class.
    /// </summary>

    public class BuildManifestObject : ScriptableObject
    {
        // Tries to get a manifest value - returns true if key was found and could be cast to type T, false otherwise.
        public bool TryGetValue<T>(string key, out T result)
        {
            result = default(T);
            return false;
        }

        // Retrieve a manifest value or throw an exception if the given key isn't found.
        public T GetValue<T>(string key) { return default(T); }

        // Sets the value for a given key.
        public void SetValue(string key, object value) { }

        // Copy values from a dictionary. ToString() will be called on dictionary values before being stored.
        public void SetValues(Dictionary<string, object> sourceDict) { }

        // Remove all key/value pairs
        public void ClearValues() { }

        // Returns a Dictionary that represents the current BuildManifestObject
        public Dictionary<string, object> ToDictionary() { return new Dictionary<string, object>(); }

        // Returns a JSON formatted string that represents the current BuildManifestObject
        public string ToJson() { return null; }

        // Returns an INI formatted string that represents the current BuildManifestObject
        public override string ToString() { return null; }
    }
}
#endif

Oh looking at var commit = manifest.GetValue(“scmCommitId”, “unknown”)); yeah there’s an extra parenthesis on there. It should be var commit = manifest.GetValue("scmCommitId", "unknown"); Untested! Just syntax-wise there is an unmatched ) with no ( to go with it.

Here is the code I use to grab the git commit hash.

public static void UpdateStuff(UnityEngine.CloudBuild.BuildManifestObject manifest)
{
  string currentHashString = null;
  if (manifest.TryGetValue<string>("scmCommitId", out currentHashString))
  {
    Debug.Log("Current commit hash is: " + currentHashString);
  }
}

sorry, i modified the code a bit before pasting it here (since it was actually a bit different). I corrected that, so apart from syntax errors it should now work.

Phooey, I can’t believe I missed that! Well, regardless, my project still does not build. This time, I get no errors until the very end:

1603: [Unity] ERROR: preExportMethod 'CloudBuildHelper.PreExport' failed, aborting.

Throughout the log before that are several lines with the warning
warning CS0618: UnityEngine.CloudBuild.BuildManifestObject.GetValue(string, string)’ is obsolete: Use GetValue<type>(string, object) instead.'

For completeness, here is my current code:

using UnityEngine;
using UnityEditor;
using System;

#if UNITY_CLOUD_BUILD
public static class CloudBuildHelper
{
    public static void PreExport(UnityEngine.CloudBuild.BuildManifestObject manifest)
    {
        var commit = manifest.GetValue("scmCommitId", "unknown");
        string currentHashString = null;
        if (manifest.TryGetValue<string>("scmCommitId", out currentHashString))
        {
            Debug.Log("Current commit hash is: " + currentHashString);
        }
    }
}
#endif

That is saved as Assets/Scripts/CloudBuildHelper.cs and I set my Unity Cloud Build advanced settings to have a Pre-Export Method Name of “CloudBuildHelper.PreExport” (no quotes). What am I missing? Is there another class or something I have to add to my scripts folder?

Thanks so much for your help, both of you!

Oh, I totally missed this before I posted my last response!! I do not have that defined in my config, I will try that and report back!

You want either GetValue or TryGetValue but not both. You should be able to get rid of the var commit = manifest.GetValue("scmCommitId", "unknown"); and have it still work.

If you want to use GetValue and not TryGetValue, well Unity had some incorrect documentation so I think this will work instead.

// var commit = manifest.GetValue("scmCommitId", "unknown");
// Use this instead.
try {
    string hash = manifest.GetValue<string>("scmCommitId");
}
catch (Exception e) {
    Debug.LogError("Unable to manifest.GetValue received exception " + e + ", " + e.Message);
}

If it is still failing, I would maybe put a try-catch block around the entire Pre-Export function and see what exception is getting thrown.

Garth-Smith, the builds are still failing. Looking into the log, I see that UNITY_CLOUD_BUILD is put in as a custom define without my intervention. So in my code, I don’t think I need a custom define in the config. Still, I tried both ways, and it didn’t make a lick of difference.

Thanks for the suggestion to use a try/catch block, but I’m seeing neither message in my full build log. Am I putting it in the right place?

On the plus side, using the syntax manifest.GetValue<string>("scmCommitId") has put an end to those error messages about obsolete syntax!

using UnityEngine;
using UnityEditor;
using System;

#if UNITY_CLOUD_BUILD
public static class CloudBuildHelper
{
    public static void PreExport(UnityEngine.CloudBuild.BuildManifestObject manifest)
    {
        try {
            string hash = manifest.GetValue<string>("scmCommitId");
            Debug.Log("Current commit hash is: " + hash);
        }
        catch (Exception e)
        {
            Debug.LogError("Error in pre-export! Received exception " + e + ", " + e.Message);
        }
    }
}
#endif

@sam_ettinger_sm : the script needs to be in an Editor/ folder within your project.

1 Like

That’s all it took to get a functional method! Thanks for the quick reply! I hope the documentation gets updated to be more clear, and to use the non-obsolete version of GetValue.

1 Like

It’s pointed out in the docs, but probably not clearly enough. Will look at updating that.