This commit is contained in:
		
							
								
								
									
										74
									
								
								.woodpecker.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								.woodpecker.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
workspace:
 | 
			
		||||
  base: /studio
 | 
			
		||||
  path: idle-survivors
 | 
			
		||||
 | 
			
		||||
# We use a singleton "matrix" to set variables, because formal variables are a
 | 
			
		||||
# Woodpecker next feature.
 | 
			
		||||
matrix:
 | 
			
		||||
  include:
 | 
			
		||||
    - BUILD_NAME: idle-survivors
 | 
			
		||||
    - UNITY_ACTIVATION_FILE: ./unity3d.alf
 | 
			
		||||
    - IMAGE: unityci/editor
 | 
			
		||||
    - IMAGE_VERSION: 1
 | 
			
		||||
    # The GitLab version pulls the Unity version from the project information,
 | 
			
		||||
    # but I don't think Woodpecker will use that as a variable in image names.
 | 
			
		||||
    # We set the version as a variable instead and check that it's right.
 | 
			
		||||
    - UNITY_VERSION: 2022.3.4f1
 | 
			
		||||
    - UNITY_DIR: /studio/idle-survivors
 | 
			
		||||
    - VERSION_NUMBER_VAR: ${CI_COMMIT_BRANCH}-${CI_BUILD_NUMBER}
 | 
			
		||||
    - VERSION_BUILD_VAR: ${CI_COMMIT_HASH}
 | 
			
		||||
 | 
			
		||||
pipeline:
 | 
			
		||||
  check-unity-version:
 | 
			
		||||
    image: ${IMAGE}:${UNITY_VERSION}-base-${IMAGE_VERSION}
 | 
			
		||||
    commands:
 | 
			
		||||
      - test "$UNITY_VERSION" = $(grep "m_EditorVersion:" "${UNITY_DIR}/ProjectSettings/ProjectVersion.txt" | cut -d' ' -f2)
 | 
			
		||||
  setup-license:
 | 
			
		||||
    image: ${IMAGE}:${UNITY_VERSION}-base-${IMAGE_VERSION}
 | 
			
		||||
    commands:
 | 
			
		||||
      - chmod +x ${UNITY_DIR}/ci/before_script.sh
 | 
			
		||||
      - ${UNITY_DIR}/ci/before_script.sh
 | 
			
		||||
    secrets: [unity_license]
 | 
			
		||||
  test-playmode:
 | 
			
		||||
    image: ${IMAGE}:${UNITY_VERSION}-base-${IMAGE_VERSION}
 | 
			
		||||
    group: test
 | 
			
		||||
    commands:
 | 
			
		||||
      - chmod +x ${UNITY_DIR}/ci/test.sh
 | 
			
		||||
      - ${UNITY_DIR}/ci/test.sh
 | 
			
		||||
    environment:
 | 
			
		||||
      - TEST_PLATFORM=playmode
 | 
			
		||||
      - TESTING_TYPE=NUNIT
 | 
			
		||||
  test-editmode:
 | 
			
		||||
    image: ${IMAGE}:${UNITY_VERSION}-base-${IMAGE_VERSION}
 | 
			
		||||
    group: test
 | 
			
		||||
    commands:
 | 
			
		||||
      - chmod +x ${UNITY_DIR}/ci/test.sh
 | 
			
		||||
      - ${UNITY_DIR}/ci/test.sh
 | 
			
		||||
    environment:
 | 
			
		||||
      - TEST_PLATFORM=editmode
 | 
			
		||||
      - TESTING_TYPE=NUNIT
 | 
			
		||||
  build-standalone-windows:
 | 
			
		||||
    image: ${IMAGE}:${UNITY_VERSION}-windows-mono-${IMAGE_VERSION}
 | 
			
		||||
    group: build
 | 
			
		||||
    commands:
 | 
			
		||||
      - chmod +x ./ci/build.sh
 | 
			
		||||
      - ./ci/build.sh
 | 
			
		||||
    environment:
 | 
			
		||||
      - BUILD_TARGET=StandaloneWindows64
 | 
			
		||||
  package:
 | 
			
		||||
    image: ${IMAGE}:${UNITY_VERSION}-windows-mono-${IMAGE_VERSION}
 | 
			
		||||
    commands:
 | 
			
		||||
      - tar -C ${UNITY_DIR}/Builds -cvzf ${VERSION_NUMBER_VAR}.tar.gz .
 | 
			
		||||
    when:
 | 
			
		||||
      event: tag
 | 
			
		||||
  publish:
 | 
			
		||||
    image: woodpeckerci/plugin-gitea-release
 | 
			
		||||
    settings:
 | 
			
		||||
      api-key:
 | 
			
		||||
        from_secret: gitea_api_key
 | 
			
		||||
      files:
 | 
			
		||||
        - ${VERSION_NUMBER_VAR}.tar.gz
 | 
			
		||||
      target: main
 | 
			
		||||
      base_url: https://git.sunturtle.xyz
 | 
			
		||||
    when:
 | 
			
		||||
      event: tag
 | 
			
		||||
							
								
								
									
										288
									
								
								Assets/Scripts/Editor/BuildCommand.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								Assets/Scripts/Editor/BuildCommand.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,288 @@
 | 
			
		||||
using UnityEditor;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System;
 | 
			
		||||
using System.IO;
 | 
			
		||||
 | 
			
		||||
static class BuildCommand
 | 
			
		||||
{
 | 
			
		||||
    private const string KEYSTORE_PASS  = "KEYSTORE_PASS";
 | 
			
		||||
    private const string KEY_ALIAS_PASS = "KEY_ALIAS_PASS";
 | 
			
		||||
    private const string KEY_ALIAS_NAME = "KEY_ALIAS_NAME";
 | 
			
		||||
    private const string KEYSTORE       = "keystore.keystore";
 | 
			
		||||
    private const string BUILD_OPTIONS_ENV_VAR = "BuildOptions";
 | 
			
		||||
    private const string ANDROID_BUNDLE_VERSION_CODE = "VERSION_BUILD_VAR";
 | 
			
		||||
    private const string ANDROID_APP_BUNDLE = "BUILD_APP_BUNDLE";
 | 
			
		||||
    private const string SCRIPTING_BACKEND_ENV_VAR = "SCRIPTING_BACKEND";
 | 
			
		||||
    private const string VERSION_NUMBER_VAR = "VERSION_NUMBER_VAR";
 | 
			
		||||
    private const string VERSION_iOS = "VERSION_BUILD_VAR";
 | 
			
		||||
    
 | 
			
		||||
    static string GetArgument(string name)
 | 
			
		||||
    {
 | 
			
		||||
        string[] args = Environment.GetCommandLineArgs();
 | 
			
		||||
        for (int i = 0; i < args.Length; i++)
 | 
			
		||||
        {
 | 
			
		||||
            if (args[i].Contains(name))
 | 
			
		||||
            {
 | 
			
		||||
                return args[i + 1];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static string[] GetEnabledScenes()
 | 
			
		||||
    {
 | 
			
		||||
        return (
 | 
			
		||||
            from scene in EditorBuildSettings.scenes
 | 
			
		||||
            where scene.enabled
 | 
			
		||||
            where !string.IsNullOrEmpty(scene.path)
 | 
			
		||||
            select scene.path
 | 
			
		||||
        ).ToArray();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static BuildTarget GetBuildTarget()
 | 
			
		||||
    {
 | 
			
		||||
        string buildTargetName = GetArgument("customBuildTarget");
 | 
			
		||||
        Console.WriteLine(":: Received customBuildTarget " + buildTargetName);
 | 
			
		||||
 | 
			
		||||
        if (buildTargetName.ToLower() == "android")
 | 
			
		||||
        {
 | 
			
		||||
#if !UNITY_5_6_OR_NEWER
 | 
			
		||||
			// https://issuetracker.unity3d.com/issues/buildoptions-dot-acceptexternalmodificationstoplayer-causes-unityexception-unknown-project-type-0
 | 
			
		||||
			// Fixed in Unity 5.6.0
 | 
			
		||||
			// side effect to fix android build system:
 | 
			
		||||
			EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Internal;
 | 
			
		||||
#endif
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (buildTargetName.TryConvertToEnum(out BuildTarget target))
 | 
			
		||||
            return target;
 | 
			
		||||
 | 
			
		||||
        Console.WriteLine($":: {nameof(buildTargetName)} \"{buildTargetName}\" not defined on enum {nameof(BuildTarget)}, using {nameof(BuildTarget.NoTarget)} enum to build");
 | 
			
		||||
 | 
			
		||||
        return BuildTarget.NoTarget;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static string GetBuildPath()
 | 
			
		||||
    {
 | 
			
		||||
        string buildPath = GetArgument("customBuildPath");
 | 
			
		||||
        Console.WriteLine(":: Received customBuildPath " + buildPath);
 | 
			
		||||
        if (buildPath == "")
 | 
			
		||||
        {
 | 
			
		||||
            throw new Exception("customBuildPath argument is missing");
 | 
			
		||||
        }
 | 
			
		||||
        return buildPath;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static string GetBuildName()
 | 
			
		||||
    {
 | 
			
		||||
        string buildName = GetArgument("customBuildName");
 | 
			
		||||
        Console.WriteLine(":: Received customBuildName " + buildName);
 | 
			
		||||
        if (buildName == "")
 | 
			
		||||
        {
 | 
			
		||||
            throw new Exception("customBuildName argument is missing");
 | 
			
		||||
        }
 | 
			
		||||
        return buildName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static string GetFixedBuildPath(BuildTarget buildTarget, string buildPath, string buildName)
 | 
			
		||||
    {
 | 
			
		||||
        if (buildTarget.ToString().ToLower().Contains("windows")) {
 | 
			
		||||
            buildName += ".exe";
 | 
			
		||||
        } else if (buildTarget == BuildTarget.Android) {
 | 
			
		||||
#if UNITY_2018_3_OR_NEWER
 | 
			
		||||
            buildName += EditorUserBuildSettings.buildAppBundle ? ".aab" : ".apk";
 | 
			
		||||
#else
 | 
			
		||||
            buildName += ".apk";
 | 
			
		||||
#endif
 | 
			
		||||
        }
 | 
			
		||||
        return buildPath + buildName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static BuildOptions GetBuildOptions()
 | 
			
		||||
    {
 | 
			
		||||
        if (TryGetEnv(BUILD_OPTIONS_ENV_VAR, out string envVar)) {
 | 
			
		||||
            string[] allOptionVars = envVar.Split(',');
 | 
			
		||||
            BuildOptions allOptions = BuildOptions.None;
 | 
			
		||||
            BuildOptions option;
 | 
			
		||||
            string optionVar;
 | 
			
		||||
            int length = allOptionVars.Length;
 | 
			
		||||
 | 
			
		||||
            Console.WriteLine($":: Detecting {BUILD_OPTIONS_ENV_VAR} env var with {length} elements ({envVar})");
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < length; i++) {
 | 
			
		||||
                optionVar = allOptionVars[i];
 | 
			
		||||
 | 
			
		||||
                if (optionVar.TryConvertToEnum(out option)) {
 | 
			
		||||
                    allOptions |= option;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    Console.WriteLine($":: Cannot convert {optionVar} to {nameof(BuildOptions)} enum, skipping it.");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return allOptions;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return BuildOptions.None;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // https://stackoverflow.com/questions/1082532/how-to-tryparse-for-enum-value
 | 
			
		||||
    static bool TryConvertToEnum<TEnum>(this string strEnumValue, out TEnum value)
 | 
			
		||||
    {
 | 
			
		||||
        if (!Enum.IsDefined(typeof(TEnum), strEnumValue))
 | 
			
		||||
        {
 | 
			
		||||
            value = default;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        value = (TEnum)Enum.Parse(typeof(TEnum), strEnumValue);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static bool TryGetEnv(string key, out string value)
 | 
			
		||||
    {
 | 
			
		||||
        value = Environment.GetEnvironmentVariable(key);
 | 
			
		||||
        return !string.IsNullOrEmpty(value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void SetScriptingBackendFromEnv(BuildTarget platform) {
 | 
			
		||||
        var targetGroup = BuildPipeline.GetBuildTargetGroup(platform);
 | 
			
		||||
        if (TryGetEnv(SCRIPTING_BACKEND_ENV_VAR, out string scriptingBackend)) {
 | 
			
		||||
            if (scriptingBackend.TryConvertToEnum(out ScriptingImplementation backend)) {
 | 
			
		||||
                Console.WriteLine($":: Setting ScriptingBackend to {backend}");
 | 
			
		||||
                PlayerSettings.SetScriptingBackend(targetGroup, backend);
 | 
			
		||||
            } else {
 | 
			
		||||
                string possibleValues = string.Join(", ", Enum.GetValues(typeof(ScriptingImplementation)).Cast<ScriptingImplementation>());
 | 
			
		||||
                throw new Exception($"Could not find '{scriptingBackend}' in ScriptingImplementation enum. Possible values are: {possibleValues}");
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            var defaultBackend = PlayerSettings.GetDefaultScriptingBackend(targetGroup);
 | 
			
		||||
            Console.WriteLine($":: Using project's configured ScriptingBackend (should be {defaultBackend} for targetGroup {targetGroup}");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void PerformBuild()
 | 
			
		||||
    {
 | 
			
		||||
        var buildTarget = GetBuildTarget();
 | 
			
		||||
 | 
			
		||||
        Console.WriteLine(":: Performing build");
 | 
			
		||||
        if (TryGetEnv(VERSION_NUMBER_VAR, out var bundleVersionNumber))
 | 
			
		||||
        {
 | 
			
		||||
            if (buildTarget == BuildTarget.iOS)
 | 
			
		||||
            {
 | 
			
		||||
                bundleVersionNumber = GetIosVersion();
 | 
			
		||||
            }
 | 
			
		||||
            Console.WriteLine($":: Setting bundleVersionNumber to '{bundleVersionNumber}' (Length: {bundleVersionNumber.Length})");
 | 
			
		||||
            PlayerSettings.bundleVersion = bundleVersionNumber;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (buildTarget == BuildTarget.Android) {
 | 
			
		||||
            HandleAndroidAppBundle();
 | 
			
		||||
            HandleAndroidBundleVersionCode();
 | 
			
		||||
            HandleAndroidKeystore();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var buildPath      = GetBuildPath();
 | 
			
		||||
        var buildName      = GetBuildName();
 | 
			
		||||
        var buildOptions   = GetBuildOptions();
 | 
			
		||||
        var fixedBuildPath = GetFixedBuildPath(buildTarget, buildPath, buildName);
 | 
			
		||||
 | 
			
		||||
        SetScriptingBackendFromEnv(buildTarget);
 | 
			
		||||
 | 
			
		||||
        var buildReport = BuildPipeline.BuildPlayer(GetEnabledScenes(), fixedBuildPath, buildTarget, buildOptions);
 | 
			
		||||
 | 
			
		||||
        if (buildReport.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
 | 
			
		||||
            throw new Exception($"Build ended with {buildReport.summary.result} status");
 | 
			
		||||
 | 
			
		||||
        Console.WriteLine(":: Done with build");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void HandleAndroidAppBundle()
 | 
			
		||||
    {
 | 
			
		||||
        if (TryGetEnv(ANDROID_APP_BUNDLE, out string value))
 | 
			
		||||
        {
 | 
			
		||||
#if UNITY_2018_3_OR_NEWER
 | 
			
		||||
            if (bool.TryParse(value, out bool buildAppBundle))
 | 
			
		||||
            {
 | 
			
		||||
                EditorUserBuildSettings.buildAppBundle = buildAppBundle;
 | 
			
		||||
                Console.WriteLine($":: {ANDROID_APP_BUNDLE} env var detected, set buildAppBundle to {value}.");
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                Console.WriteLine($":: {ANDROID_APP_BUNDLE} env var detected but the value \"{value}\" is not a boolean.");
 | 
			
		||||
            }
 | 
			
		||||
#else
 | 
			
		||||
            Console.WriteLine($":: {ANDROID_APP_BUNDLE} env var detected but does not work with lower Unity version than 2018.3");
 | 
			
		||||
#endif
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void HandleAndroidBundleVersionCode()
 | 
			
		||||
    {
 | 
			
		||||
        if (TryGetEnv(ANDROID_BUNDLE_VERSION_CODE, out string value))
 | 
			
		||||
        {
 | 
			
		||||
            if (int.TryParse(value, out int version))
 | 
			
		||||
            {
 | 
			
		||||
                PlayerSettings.Android.bundleVersionCode = version;
 | 
			
		||||
                Console.WriteLine($":: {ANDROID_BUNDLE_VERSION_CODE} env var detected, set the bundle version code to {value}.");
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                Console.WriteLine($":: {ANDROID_BUNDLE_VERSION_CODE} env var detected but the version value \"{value}\" is not an integer.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static string GetIosVersion()
 | 
			
		||||
    {
 | 
			
		||||
        if (TryGetEnv(VERSION_iOS, out string value))
 | 
			
		||||
        {
 | 
			
		||||
            if (int.TryParse(value, out int version))
 | 
			
		||||
            {
 | 
			
		||||
                Console.WriteLine($":: {VERSION_iOS} env var detected, set the version to {value}.");
 | 
			
		||||
                return version.ToString();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                Console.WriteLine($":: {VERSION_iOS} env var detected but the version value \"{value}\" is not an integer.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new ArgumentNullException(nameof(value), $":: Error finding {VERSION_iOS} env var");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void HandleAndroidKeystore()
 | 
			
		||||
    {
 | 
			
		||||
#if UNITY_2019_1_OR_NEWER
 | 
			
		||||
        PlayerSettings.Android.useCustomKeystore = false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        if (!File.Exists(KEYSTORE)) {
 | 
			
		||||
            Console.WriteLine($":: {KEYSTORE} not found, skipping setup, using Unity's default keystore");
 | 
			
		||||
            return;    
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PlayerSettings.Android.keystoreName = KEYSTORE;
 | 
			
		||||
 | 
			
		||||
        string keystorePass;
 | 
			
		||||
        string keystoreAliasPass;
 | 
			
		||||
 | 
			
		||||
        if (TryGetEnv(KEY_ALIAS_NAME, out string keyaliasName)) {
 | 
			
		||||
            PlayerSettings.Android.keyaliasName = keyaliasName;
 | 
			
		||||
            Console.WriteLine($":: using ${KEY_ALIAS_NAME} env var on PlayerSettings");
 | 
			
		||||
        } else {
 | 
			
		||||
            Console.WriteLine($":: ${KEY_ALIAS_NAME} env var not set, using Project's PlayerSettings");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!TryGetEnv(KEYSTORE_PASS, out keystorePass)) {
 | 
			
		||||
            Console.WriteLine($":: ${KEYSTORE_PASS} env var not set, skipping setup, using Unity's default keystore");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!TryGetEnv(KEY_ALIAS_PASS, out keystoreAliasPass)) {
 | 
			
		||||
            Console.WriteLine($":: ${KEY_ALIAS_PASS} env var not set, skipping setup, using Unity's default keystore");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
#if UNITY_2019_1_OR_NEWER
 | 
			
		||||
        PlayerSettings.Android.useCustomKeystore = true;
 | 
			
		||||
#endif
 | 
			
		||||
        PlayerSettings.Android.keystorePass = keystorePass;
 | 
			
		||||
        PlayerSettings.Android.keyaliasPass = keystoreAliasPass;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								ci/before_script.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								ci/before_script.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
set -x
 | 
			
		||||
mkdir -p /root/.cache/unity3d
 | 
			
		||||
mkdir -p /root/.local/share/unity3d/Unity/
 | 
			
		||||
set +x
 | 
			
		||||
 | 
			
		||||
unity_license_destination=/root/.local/share/unity3d/Unity/Unity_lic.ulf
 | 
			
		||||
android_keystore_destination=keystore.keystore
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
upper_case_build_target=${BUILD_TARGET^^};
 | 
			
		||||
 | 
			
		||||
if [ "$upper_case_build_target" = "ANDROID" ]
 | 
			
		||||
then
 | 
			
		||||
    if [ -n $ANDROID_KEYSTORE_BASE64 ]
 | 
			
		||||
    then
 | 
			
		||||
        echo "'\$ANDROID_KEYSTORE_BASE64' found, decoding content into ${android_keystore_destination}"
 | 
			
		||||
        echo $ANDROID_KEYSTORE_BASE64 | base64 --decode > ${android_keystore_destination}
 | 
			
		||||
    else
 | 
			
		||||
        echo '$ANDROID_KEYSTORE_BASE64'" env var not found, building with Unity's default debug keystore"
 | 
			
		||||
    fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ -n "$UNITY_LICENSE" ]
 | 
			
		||||
then
 | 
			
		||||
    echo "Writing '\$UNITY_LICENSE' to license file ${unity_license_destination}"
 | 
			
		||||
    echo "${UNITY_LICENSE}" | tr -d '\r' > ${unity_license_destination}
 | 
			
		||||
else
 | 
			
		||||
    echo "'\$UNITY_LICENSE' env var not found"
 | 
			
		||||
fi
 | 
			
		||||
							
								
								
									
										36
									
								
								ci/build.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								ci/build.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
set -x
 | 
			
		||||
 | 
			
		||||
echo "Building for $BUILD_TARGET"
 | 
			
		||||
 | 
			
		||||
export BUILD_PATH=$UNITY_DIR/Builds/$BUILD_TARGET/
 | 
			
		||||
mkdir -p $BUILD_PATH
 | 
			
		||||
 | 
			
		||||
${UNITY_EXECUTABLE:-xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' unity-editor} \
 | 
			
		||||
  -projectPath $UNITY_DIR \
 | 
			
		||||
  -quit \
 | 
			
		||||
  -batchmode \
 | 
			
		||||
  -nographics \
 | 
			
		||||
  -buildTarget $BUILD_TARGET \
 | 
			
		||||
  -customBuildTarget $BUILD_TARGET \
 | 
			
		||||
  -customBuildName $BUILD_NAME \
 | 
			
		||||
  -customBuildPath $BUILD_PATH \
 | 
			
		||||
  -executeMethod BuildCommand.PerformBuild \
 | 
			
		||||
  -logFile /dev/stdout
 | 
			
		||||
 | 
			
		||||
UNITY_EXIT_CODE=$?
 | 
			
		||||
 | 
			
		||||
if [ $UNITY_EXIT_CODE -eq 0 ]; then
 | 
			
		||||
  echo "Run succeeded, no failures occurred";
 | 
			
		||||
elif [ $UNITY_EXIT_CODE -eq 2 ]; then
 | 
			
		||||
  echo "Run succeeded, some tests failed";
 | 
			
		||||
elif [ $UNITY_EXIT_CODE -eq 3 ]; then
 | 
			
		||||
  echo "Run failure (other failure)";
 | 
			
		||||
else
 | 
			
		||||
  echo "Unexpected exit code $UNITY_EXIT_CODE";
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
ls -la $BUILD_PATH
 | 
			
		||||
[ -n "$(ls -A $BUILD_PATH)" ] # fail job if build folder is empty
 | 
			
		||||
							
								
								
									
										14
									
								
								ci/docker_build.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								ci/docker_build.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
docker run \
 | 
			
		||||
  -e BUILD_NAME \
 | 
			
		||||
  -e UNITY_LICENSE \
 | 
			
		||||
  -e BUILD_TARGET \
 | 
			
		||||
  -e UNITY_USERNAME \
 | 
			
		||||
  -e UNITY_PASSWORD \
 | 
			
		||||
  -w /project/ \
 | 
			
		||||
  -v $UNITY_DIR:/project/ \
 | 
			
		||||
  $IMAGE_NAME \
 | 
			
		||||
  /bin/bash -c "/project/ci/before_script.sh && /project/ci/build.sh"
 | 
			
		||||
							
								
								
									
										13
									
								
								ci/docker_test.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								ci/docker_test.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
docker run \
 | 
			
		||||
  -e UNITY_LICENSE \
 | 
			
		||||
  -e TEST_PLATFORM \
 | 
			
		||||
  -e UNITY_USERNAME \
 | 
			
		||||
  -e UNITY_PASSWORD \
 | 
			
		||||
  -w /project/ \
 | 
			
		||||
  -v $UNITY_DIR:/project/ \
 | 
			
		||||
  $IMAGE_NAME \
 | 
			
		||||
  /bin/bash -c "/project/ci/before_script.sh && /project/ci/test.sh"
 | 
			
		||||
							
								
								
									
										49
									
								
								ci/get_activation_file.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								ci/get_activation_file.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
activation_file=${UNITY_ACTIVATION_FILE:-./unity3d.alf}
 | 
			
		||||
 | 
			
		||||
if [[ -z "${UNITY_USERNAME}" ]] || [[ -z "${UNITY_PASSWORD}" ]]; then
 | 
			
		||||
  echo "UNITY_USERNAME or UNITY_PASSWORD environment variables are not set, please refer to instructions in the readme and add these to your secret environment variables."
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
 | 
			
		||||
  unity-editor \
 | 
			
		||||
    -logFile /dev/stdout \
 | 
			
		||||
    -batchmode \
 | 
			
		||||
    -nographics \
 | 
			
		||||
    -username "$UNITY_USERNAME" -password "$UNITY_PASSWORD" |
 | 
			
		||||
      tee ./unity-output.log
 | 
			
		||||
 | 
			
		||||
cat ./unity-output.log |
 | 
			
		||||
  grep 'LICENSE SYSTEM .* Posting *' |
 | 
			
		||||
  sed 's/.*Posting *//' > "${activation_file}"
 | 
			
		||||
 | 
			
		||||
# Fail job if unity.alf is empty
 | 
			
		||||
ls "${UNITY_ACTIVATION_FILE:-./unity3d.alf}"
 | 
			
		||||
exit_code=$?
 | 
			
		||||
 | 
			
		||||
if [[ ${exit_code} -eq 0 ]]; then
 | 
			
		||||
  echo ""
 | 
			
		||||
  echo ""
 | 
			
		||||
  echo "### Congratulations! ###"
 | 
			
		||||
  echo "${activation_file} was generated successfully!"
 | 
			
		||||
  echo ""
 | 
			
		||||
  echo "### Next steps ###"
 | 
			
		||||
  echo ""
 | 
			
		||||
  echo "Complete the activation process manually"
 | 
			
		||||
  echo ""
 | 
			
		||||
  echo "   1. Download the artifact which should contain ${activation_file}"
 | 
			
		||||
  echo "   2. Visit https://license.unity3d.com/manual"
 | 
			
		||||
  echo "   3. Upload ${activation_file} in the form"
 | 
			
		||||
  echo "   4. Answer questions (unity pro vs personal edition, both will work, just pick the one you use)"
 | 
			
		||||
  echo "   5. Download 'Unity_v2019.x.ulf' file (year should match your unity version here, 'Unity_v2018.x.ulf' for 2018, etc.)"
 | 
			
		||||
  echo "   6. Copy the content of 'Unity_v2019.x.ulf' license file to your CI's environment variable 'UNITY_LICENSE'. (Open your project's parameters > CI/CD > Variables and add 'UNITY_LICENSE' as the key and paste the content of the license file into the value)"
 | 
			
		||||
  echo ""
 | 
			
		||||
  echo "Once you're done, hit retry on the pipeline where other jobs failed, or just push another commit. Things should be green"
 | 
			
		||||
  echo ""
 | 
			
		||||
  echo "(optional) For more details on why this is not fully automated, visit https://gitlab.com/gableroux/unity3d-gitlab-ci-example/issues/73"
 | 
			
		||||
else
 | 
			
		||||
  echo "License file could not be found at ${UNITY_ACTIVATION_FILE:-./unity3d.alf}"
 | 
			
		||||
fi
 | 
			
		||||
exit $exit_code
 | 
			
		||||
							
								
								
									
										19
									
								
								ci/nunit-transforms/LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								ci/nunit-transforms/LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
Copyright (c) 2016 Paul Hicks
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in
 | 
			
		||||
all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
THE SOFTWARE.
 | 
			
		||||
							
								
								
									
										69
									
								
								ci/nunit-transforms/nunit3-junit.xslt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								ci/nunit-transforms/nunit3-junit.xslt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 | 
			
		||||
  <xsl:output method="xml" indent="yes"/>
 | 
			
		||||
 | 
			
		||||
  <xsl:template match="/test-run">
 | 
			
		||||
    <testsuites tests="{@testcasecount}" failures="{@failed}" disabled="{@skipped}" time="{@duration}">
 | 
			
		||||
      <xsl:apply-templates/>
 | 
			
		||||
    </testsuites>
 | 
			
		||||
  </xsl:template>
 | 
			
		||||
 | 
			
		||||
  <xsl:template match="test-suite">
 | 
			
		||||
    <xsl:if test="test-case">
 | 
			
		||||
      <testsuite tests="{@testcasecount}" time="{@duration}" errors="{@testcasecount - @passed - @skipped - @failed}" failures="{@failed}" skipped="{@skipped}" timestamp="{@start-time}">
 | 
			
		||||
        <xsl:attribute name="name">
 | 
			
		||||
          <xsl:for-each select="ancestor-or-self::test-suite/@name">
 | 
			
		||||
            <xsl:value-of select="concat(., '.')"/>
 | 
			
		||||
          </xsl:for-each>
 | 
			
		||||
        </xsl:attribute>
 | 
			
		||||
        <xsl:apply-templates select="test-case"/>
 | 
			
		||||
      </testsuite>
 | 
			
		||||
      <xsl:apply-templates select="test-suite"/>
 | 
			
		||||
    </xsl:if>
 | 
			
		||||
    <xsl:if test="not(test-case)">
 | 
			
		||||
      <xsl:apply-templates/>
 | 
			
		||||
    </xsl:if>
 | 
			
		||||
  </xsl:template>
 | 
			
		||||
 | 
			
		||||
  <xsl:template match="test-case">
 | 
			
		||||
    <testcase name="{@name}" assertions="{@asserts}" time="{@duration}" status="{@result}" classname="{@classname}">
 | 
			
		||||
      <xsl:if test="@runstate = 'Skipped' or @runstate = 'Ignored'">
 | 
			
		||||
        <skipped/>
 | 
			
		||||
      </xsl:if>
 | 
			
		||||
      
 | 
			
		||||
      <xsl:apply-templates/>
 | 
			
		||||
    </testcase>
 | 
			
		||||
  </xsl:template>
 | 
			
		||||
 | 
			
		||||
  <xsl:template match="command-line"/>
 | 
			
		||||
  <xsl:template match="settings"/>
 | 
			
		||||
 | 
			
		||||
  <xsl:template match="output">
 | 
			
		||||
    <system-out>
 | 
			
		||||
      <xsl:value-of select="."/>
 | 
			
		||||
    </system-out>
 | 
			
		||||
  </xsl:template>
 | 
			
		||||
 | 
			
		||||
  <xsl:template match="stack-trace">
 | 
			
		||||
  </xsl:template>
 | 
			
		||||
 | 
			
		||||
  <xsl:template match="test-case/failure">
 | 
			
		||||
    <failure message="{./message}">
 | 
			
		||||
      <xsl:value-of select="./stack-trace"/>
 | 
			
		||||
    </failure>
 | 
			
		||||
  </xsl:template>
 | 
			
		||||
 | 
			
		||||
  <xsl:template match="test-suite/failure"/>
 | 
			
		||||
 | 
			
		||||
  <xsl:template match="test-case/reason">
 | 
			
		||||
    <skipped message="{./message}"/>
 | 
			
		||||
  </xsl:template>
 | 
			
		||||
  
 | 
			
		||||
  <xsl:template match="test-case/assertions">
 | 
			
		||||
  </xsl:template>
 | 
			
		||||
 | 
			
		||||
  <xsl:template match="test-suite/reason"/>
 | 
			
		||||
 | 
			
		||||
  <xsl:template match="properties"/>
 | 
			
		||||
</xsl:stylesheet>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										56
									
								
								ci/test.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								ci/test.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
set -x
 | 
			
		||||
 | 
			
		||||
echo "Testing for $TEST_PLATFORM, Unit Type: $TESTING_TYPE"
 | 
			
		||||
 | 
			
		||||
CODE_COVERAGE_PACKAGE="com.unity.testtools.codecoverage"
 | 
			
		||||
PACKAGE_MANIFEST_PATH="Packages/manifest.json"
 | 
			
		||||
 | 
			
		||||
${UNITY_EXECUTABLE:-xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' unity-editor} \
 | 
			
		||||
  -projectPath $UNITY_DIR \
 | 
			
		||||
  -runTests \
 | 
			
		||||
  -testPlatform $TEST_PLATFORM \
 | 
			
		||||
  -testResults $UNITY_DIR/$TEST_PLATFORM-results.xml \
 | 
			
		||||
  -logFile /dev/stdout \
 | 
			
		||||
  -batchmode \
 | 
			
		||||
  -nographics \
 | 
			
		||||
  -enableCodeCoverage \
 | 
			
		||||
  -coverageResultsPath $UNITY_DIR/$TEST_PLATFORM-coverage \
 | 
			
		||||
  -coverageOptions "generateAdditionalMetrics;generateHtmlReport;generateHtmlReportHistory;generateBadgeReport;" \
 | 
			
		||||
  -debugCodeOptimization
 | 
			
		||||
 | 
			
		||||
UNITY_EXIT_CODE=$?
 | 
			
		||||
 | 
			
		||||
if [ $UNITY_EXIT_CODE -eq 0 ]; then
 | 
			
		||||
  echo "Run succeeded, no failures occurred";
 | 
			
		||||
elif [ $UNITY_EXIT_CODE -eq 2 ]; then
 | 
			
		||||
  echo "Run succeeded, some tests failed";
 | 
			
		||||
  if [ $TESTING_TYPE == 'JUNIT' ]; then
 | 
			
		||||
    echo "Converting results to JUNit for analysis";
 | 
			
		||||
    saxonb-xslt -s $UNITY_DIR/$TEST_PLATFORM-results.xml -xsl $CI_PROJECT_DIR/ci/nunit-transforms/nunit3-junit.xslt >$UNITY_DIR/$TEST_PLATFORM-junit-results.xml
 | 
			
		||||
  fi
 | 
			
		||||
elif [ $UNITY_EXIT_CODE -eq 3 ]; then
 | 
			
		||||
  echo "Run failure (other failure)";
 | 
			
		||||
  if [ $TESTING_TYPE == 'JUNIT' ]; then
 | 
			
		||||
    echo "Not converting results to JUNit";
 | 
			
		||||
  fi
 | 
			
		||||
else
 | 
			
		||||
  echo "Unexpected exit code $UNITY_EXIT_CODE";
 | 
			
		||||
  if [ $TESTING_TYPE == 'JUNIT' ]; then
 | 
			
		||||
    echo "Not converting results to JUNit";
 | 
			
		||||
  fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if grep $CODE_COVERAGE_PACKAGE $PACKAGE_MANIFEST_PATH; then
 | 
			
		||||
  cat $UNITY_DIR/$TEST_PLATFORM-coverage/Report/Summary.xml | grep Linecoverage
 | 
			
		||||
  mv $UNITY_DIR/$TEST_PLATFORM-coverage/$CI_PROJECT_NAME-opencov/*Mode/TestCoverageResults_*.xml $UNITY_DIR/$TEST_PLATFORM-coverage/coverage.xml
 | 
			
		||||
  rm -r $UNITY_DIR/$TEST_PLATFORM-coverage/$CI_PROJECT_NAME-opencov/
 | 
			
		||||
else
 | 
			
		||||
  {
 | 
			
		||||
    echo -e "\033[33mCode Coverage package not found in $PACKAGE_MANIFEST_PATH. Please install the package \"Code Coverage\" through Unity's Package Manager to enable coverage reports.\033[0m"
 | 
			
		||||
  } 2> /dev/null
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
cat $UNITY_DIR/$TEST_PLATFORM-results.xml | grep test-run | grep Passed
 | 
			
		||||
exit $UNITY_EXIT_CODE
 | 
			
		||||
		Reference in New Issue
	
	Block a user