This commit is contained in:
parent
3241788427
commit
148e3843f6
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
|
Loading…
Reference in New Issue
Block a user