diff --git a/.github/workflows/build-tests-ubuntu.yml b/.github/workflows/build-tests-ubuntu.yml index 9e67536c..0125357c 100644 --- a/.github/workflows/build-tests-ubuntu.yml +++ b/.github/workflows/build-tests-ubuntu.yml @@ -36,7 +36,8 @@ env: jobs: buildForAllPlatformsUbuntu: - name: ${{ matrix.targetPlatform }} on ${{ matrix.unityVersion }} + name: + "${{ matrix.targetPlatform }} on ${{ matrix.unityVersion}}${{startsWith(matrix.buildProfile, 'Assets') && ' (via Build Profile)' || '' }}" runs-on: ubuntu-latest strategy: fail-fast: false @@ -91,6 +92,12 @@ jobs: - targetPlatform: StandaloneWindows64 additionalParameters: -standaloneBuildSubtarget Server buildWithIl2cpp: true + include: + - unityVersion: 6000.0.36f1 + targetPlatform: WebGL + - unityVersion: 6000.0.36f1 + targetPlatform: WebGL + buildProfile: 'Assets/Settings/Build Profiles/Sample WebGL Build Profile.asset' steps: - name: Clear Space for Android Build @@ -136,6 +143,7 @@ jobs: with: buildName: 'GameCI Test Build' projectPath: ${{ matrix.projectPath }} + buildProfile: ${{ matrix.buildProfile }} unityVersion: ${{ matrix.unityVersion }} targetPlatform: ${{ matrix.targetPlatform }} customParameters: -profile SomeProfile -someBoolean -someValue exampleValue ${{ matrix.additionalParameters }} @@ -158,6 +166,7 @@ jobs: with: buildName: 'GameCI Test Build' projectPath: ${{ matrix.projectPath }} + buildProfile: ${{ matrix.buildProfile }} unityVersion: ${{ matrix.unityVersion }} targetPlatform: ${{ matrix.targetPlatform }} customParameters: -profile SomeProfile -someBoolean -someValue exampleValue ${{ matrix.additionalParameters }} @@ -179,6 +188,7 @@ jobs: with: buildName: 'GameCI Test Build' projectPath: ${{ matrix.projectPath }} + buildProfile: ${{ matrix.buildProfile }} unityVersion: ${{ matrix.unityVersion }} targetPlatform: ${{ matrix.targetPlatform }} customParameters: -profile SomeProfile -someBoolean -someValue exampleValue ${{ matrix.additionalParameters }} @@ -191,7 +201,6 @@ jobs: - uses: actions/upload-artifact@v4 with: name: - 'Build ${{ matrix.targetPlatform }} on Ubuntu (${{ matrix.unityVersion }}_il2cpp_${{ matrix.buildWithIl2cpp - }}_params_${{ matrix.additionalParameters }})' + "Build ${{ matrix.targetPlatform }}${{ startsWith(matrix.buildProfile, 'Assets') && ' (via Build Profile)' || '' }} on Ubuntu (${{ matrix.unityVersion }}_il2cpp_${{ matrix.buildWithIl2cpp }}_params_${{ matrix.additionalParameters }})" path: build retention-days: 14 diff --git a/action.yml b/action.yml index 7f58660e..791df50e 100644 --- a/action.yml +++ b/action.yml @@ -18,7 +18,11 @@ inputs: projectPath: required: false default: '' - description: 'Relative path to the project to be built.' + description: 'Path to the project to be built, relative to the repository root.' + buildProfile: + required: false + default: '' + description: 'Path to the build profile to activate, relative to the project root.' buildName: required: false default: '' diff --git a/dist/default-build-script/Assets/Editor/UnityBuilderAction/Builder.cs b/dist/default-build-script/Assets/Editor/UnityBuilderAction/Builder.cs index 453dd1f4..ac8e7e8e 100644 --- a/dist/default-build-script/Assets/Editor/UnityBuilderAction/Builder.cs +++ b/dist/default-build-script/Assets/Editor/UnityBuilderAction/Builder.cs @@ -6,6 +6,9 @@ using UnityBuilderAction.Reporting; using UnityBuilderAction.Versioning; using UnityEditor; using UnityEditor.Build.Reporting; +#if UNITY_6000_0_OR_NEWER +using UnityEditor.Build.Profile; +#endif using UnityEngine; namespace UnityBuilderAction @@ -17,47 +20,9 @@ namespace UnityBuilderAction // Gather values from args var options = ArgumentsParser.GetValidatedOptions(); - // Gather values from project - var scenes = EditorBuildSettings.scenes.Where(scene => scene.enabled).Select(s => s.path).ToArray(); - - // Get all buildOptions from options - BuildOptions buildOptions = BuildOptions.None; - foreach (string buildOptionString in Enum.GetNames(typeof(BuildOptions))) { - if (options.ContainsKey(buildOptionString)) { - BuildOptions buildOptionEnum = (BuildOptions) Enum.Parse(typeof(BuildOptions), buildOptionString); - buildOptions |= buildOptionEnum; - } - } - -#if UNITY_2021_2_OR_NEWER - // Determine subtarget - StandaloneBuildSubtarget buildSubtarget; - if (!options.TryGetValue("standaloneBuildSubtarget", out var subtargetValue) || !Enum.TryParse(subtargetValue, out buildSubtarget)) { - buildSubtarget = default; - } -#endif - - // Define BuildPlayer Options - var buildPlayerOptions = new BuildPlayerOptions { - scenes = scenes, - locationPathName = options["customBuildPath"], - target = (BuildTarget) Enum.Parse(typeof(BuildTarget), options["buildTarget"]), - options = buildOptions, -#if UNITY_2021_2_OR_NEWER - subtarget = (int) buildSubtarget -#endif - }; - // Set version for this build VersionApplicator.SetVersion(options["buildVersion"]); - - // Apply Android settings - if (buildPlayerOptions.target == BuildTarget.Android) - { - VersionApplicator.SetAndroidVersionCode(options["androidVersionCode"]); - AndroidSettings.Apply(options); - } - + // Execute default AddressableAsset content build, if the package is installed. // Version defines would be the best solution here, but Unity 2018 doesn't support that, // so we fall back to using reflection instead. @@ -78,6 +43,72 @@ namespace UnityBuilderAction } } + // Get all buildOptions from options + BuildOptions buildOptions = BuildOptions.None; + foreach (string buildOptionString in Enum.GetNames(typeof(BuildOptions))) { + if (options.ContainsKey(buildOptionString)) { + BuildOptions buildOptionEnum = (BuildOptions) Enum.Parse(typeof(BuildOptions), buildOptionString); + buildOptions |= buildOptionEnum; + } + } + + // Depending on whether the build is using a build profile, `buildPlayerOptions` will an instance + // of either `UnityEditor.BuildPlayerOptions` or `UnityEditor.BuildPlayerWithProfileOptions` + dynamic buildPlayerOptions; + + if (options["customBuildProfile"] != "") { + +#if UNITY_6000_0_OR_NEWER + // Load build profile from Assets folder + BuildProfile buildProfile = AssetDatabase.LoadAssetAtPath(options["customBuildProfile"]); + + // Set it as active + BuildProfile.SetActiveBuildProfile(buildProfile); + + // Define BuildPlayerWithProfileOptions + buildPlayerOptions = new BuildPlayerWithProfileOptions { + buildProfile = buildProfile, + locationPathName = options["customBuildPath"], + options = buildOptions, + }; +#else + throw new Exception("Build profiles are not supported by this version of Unity (" + Application.unityVersion +")"); +#endif + + } else { + + // Gather values from project + var scenes = EditorBuildSettings.scenes.Where(scene => scene.enabled).Select(s => s.path).ToArray(); + +#if UNITY_2021_2_OR_NEWER + // Determine subtarget + StandaloneBuildSubtarget buildSubtarget; + if (!options.TryGetValue("standaloneBuildSubtarget", out var subtargetValue) || !Enum.TryParse(subtargetValue, out buildSubtarget)) { + buildSubtarget = default; + } +#endif + + BuildTarget buildTarget = (BuildTarget) Enum.Parse(typeof(BuildTarget), options["buildTarget"]); + + // Define BuildPlayerOptions + buildPlayerOptions = new BuildPlayerOptions { + scenes = scenes, + locationPathName = options["customBuildPath"], + target = buildTarget, + options = buildOptions, +#if UNITY_2021_2_OR_NEWER + subtarget = (int) buildSubtarget +#endif + }; + + // Apply Android settings + if (buildTarget == BuildTarget.Android) { + VersionApplicator.SetAndroidVersionCode(options["androidVersionCode"]); + AndroidSettings.Apply(options); + } + + } + // Perform build BuildReport buildReport = BuildPipeline.BuildPlayer(buildPlayerOptions); diff --git a/dist/index.js b/dist/index.js index bb7e8cd3..5111463f 100644 Binary files a/dist/index.js and b/dist/index.js differ diff --git a/dist/index.js.map b/dist/index.js.map index 595cc560..b304c2c7 100644 Binary files a/dist/index.js.map and b/dist/index.js.map differ diff --git a/dist/platforms/mac/steps/build.sh b/dist/platforms/mac/steps/build.sh index b4ef8939..8149c49a 100755 --- a/dist/platforms/mac/steps/build.sh +++ b/dist/platforms/mac/steps/build.sh @@ -19,6 +19,23 @@ echo "Using build name \"$BUILD_NAME\"." echo "Using build target \"$BUILD_TARGET\"." +# +# Display the build profile +# + +if [ -z "$BUILD_PROFILE" ]; then + # User has not provided a build profile + # + echo "Doing a default \"$BUILD_TARGET\" platform build." + # +else + # User has provided a path to a build profile `.asset` file + # + echo "Using build profile \"$BUILD_PROFILE\" relative to \"$UNITY_PROJECT_PATH\"." + # +fi + + # # Display build path and file # @@ -139,6 +156,7 @@ echo "" -buildTarget "$BUILD_TARGET" \ -customBuildTarget "$BUILD_TARGET" \ -customBuildPath "$CUSTOM_BUILD_PATH" \ + -customBuildProfile "$BUILD_PROFILE" \ -executeMethod "$BUILD_METHOD" \ -buildVersion "$VERSION" \ -androidVersionCode "$ANDROID_VERSION_CODE" \ diff --git a/dist/platforms/ubuntu/steps/build.sh b/dist/platforms/ubuntu/steps/build.sh index 4cdb3e89..9e391651 100755 --- a/dist/platforms/ubuntu/steps/build.sh +++ b/dist/platforms/ubuntu/steps/build.sh @@ -19,6 +19,22 @@ echo "Using build name \"$BUILD_NAME\"." echo "Using build target \"$BUILD_TARGET\"." +# +# Display the build profile +# + +if [ -z "$BUILD_PROFILE" ]; then + # User has not provided a build profile + # + echo "Doing a default \"$BUILD_TARGET\" platform build." + # +else + # User has provided a path to a build profile `.asset` file + # + echo "Using build profile \"$BUILD_PROFILE\" relative to \"$UNITY_PROJECT_PATH\"." + # +fi + # # Display build path and file # @@ -112,6 +128,7 @@ unity-editor \ -buildTarget "$BUILD_TARGET" \ -customBuildTarget "$BUILD_TARGET" \ -customBuildPath "$CUSTOM_BUILD_PATH" \ + -customBuildProfile "$BUILD_PROFILE" \ -executeMethod "$BUILD_METHOD" \ -buildVersion "$VERSION" \ -androidVersionCode "$ANDROID_VERSION_CODE" \ diff --git a/dist/platforms/windows/build.ps1 b/dist/platforms/windows/build.ps1 index 0a85d346..6b126058 100644 --- a/dist/platforms/windows/build.ps1 +++ b/dist/platforms/windows/build.ps1 @@ -16,6 +16,25 @@ Write-Output "$('Using build name "')$($Env:BUILD_NAME)$('".')" Write-Output "$('Using build target "')$($Env:BUILD_TARGET)$('".')" +# +# Display the build profile +# + +if ($Env:BUILD_PROFILE) +{ + # User has provided a path to a build profile `.asset` file + # + Write-Output "$('Using build profile "')$($Env:BUILD_PROFILE)$('" relative to "')$($Env:UNITY_PROJECT_PATH)$('".')" + # +} +else +{ + # User has not provided a build profile + # + Write-Output "$('Doing a default "')$($Env:BUILD_TARGET)$('" platform build.')" + # +} + # # Display build path and file # @@ -143,6 +162,7 @@ $unityArgs = @( "-buildTarget", "`"$Env:BUILD_TARGET`"", "-customBuildTarget", "`"$Env:BUILD_TARGET`"", "-customBuildPath", "`"$Env:CUSTOM_BUILD_PATH`"", + "-customBuildProfile", "`"$Env:BUILD_PROFILE`"", "-buildVersion", "`"$Env:VERSION`"", "-androidVersionCode", "`"$Env:ANDROID_VERSION_CODE`"", "-androidKeystorePass", "`"$Env:ANDROID_KEYSTORE_PASS`"", diff --git a/src/model/build-parameters.test.ts b/src/model/build-parameters.test.ts index 595379d7..9b7ad666 100644 --- a/src/model/build-parameters.test.ts +++ b/src/model/build-parameters.test.ts @@ -71,6 +71,12 @@ describe('BuildParameters', () => { await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ projectPath: mockValue })); }); + it('returns the build profile', async () => { + const mockValue = 'path/to/build_profile.asset'; + jest.spyOn(Input, 'buildProfile', 'get').mockReturnValue(mockValue); + await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildProfile: mockValue })); + }); + it('returns the build name', async () => { const mockValue = 'someBuildName'; jest.spyOn(Input, 'buildName', 'get').mockReturnValue(mockValue); diff --git a/src/model/build-parameters.ts b/src/model/build-parameters.ts index 8cf60d59..55bc29bd 100644 --- a/src/model/build-parameters.ts +++ b/src/model/build-parameters.ts @@ -26,6 +26,7 @@ class BuildParameters { public runnerTempPath!: string; public targetPlatform!: string; public projectPath!: string; + public buildProfile!: string; public buildName!: string; public buildPath!: string; public buildFile!: string; @@ -152,6 +153,7 @@ class BuildParameters { runnerTempPath: Input.runnerTempPath, targetPlatform: Input.targetPlatform, projectPath: Input.projectPath, + buildProfile: Input.buildProfile, buildName: Input.buildName, buildPath: `${Input.buildsPath}/${Input.targetPlatform}`, buildFile, diff --git a/src/model/image-environment-factory.ts b/src/model/image-environment-factory.ts index 347d6944..5f621924 100644 --- a/src/model/image-environment-factory.ts +++ b/src/model/image-environment-factory.ts @@ -36,6 +36,7 @@ class ImageEnvironmentFactory { value: process.env.USYM_UPLOAD_AUTH_TOKEN, }, { name: 'PROJECT_PATH', value: parameters.projectPath }, + { name: 'BUILD_PROFILE', value: parameters.buildProfile }, { name: 'BUILD_TARGET', value: parameters.targetPlatform }, { name: 'BUILD_NAME', value: parameters.buildName }, { name: 'BUILD_PATH', value: parameters.buildPath }, diff --git a/src/model/input.test.ts b/src/model/input.test.ts index ae284547..777d864b 100644 --- a/src/model/input.test.ts +++ b/src/model/input.test.ts @@ -59,6 +59,19 @@ describe('Input', () => { }); }); + describe('buildProfile', () => { + it('returns the default value', () => { + expect(Input.buildProfile).toStrictEqual(''); + }); + + it('takes input from the users workflow', () => { + const mockValue = 'path/to/build_profile.asset'; + const spy = jest.spyOn(core, 'getInput').mockReturnValue(mockValue); + expect(Input.buildProfile).toStrictEqual(mockValue); + expect(spy).toHaveBeenCalledTimes(1); + }); + }); + describe('buildName', () => { it('returns the default value', () => { expect(Input.buildName).toStrictEqual(Input.targetPlatform); diff --git a/src/model/input.ts b/src/model/input.ts index 0e988884..a0b79b94 100644 --- a/src/model/input.ts +++ b/src/model/input.ts @@ -107,6 +107,10 @@ class Input { return rawProjectPath.replace(/\/$/, ''); } + static get buildProfile(): string { + return Input.getInput('buildProfile') ?? ''; + } + static get runnerTempPath(): string { return Input.getInput('RUNNER_TEMP') ?? ''; } diff --git a/src/model/platform-setup/setup-mac.ts b/src/model/platform-setup/setup-mac.ts index 4566e163..17c0d413 100644 --- a/src/model/platform-setup/setup-mac.ts +++ b/src/model/platform-setup/setup-mac.ts @@ -170,6 +170,7 @@ class SetupMac { process.env.UNITY_LICENSING_SERVER = buildParameters.unityLicensingServer; process.env.SKIP_ACTIVATION = buildParameters.skipActivation; process.env.PROJECT_PATH = buildParameters.projectPath; + process.env.BUILD_PROFILE = buildParameters.buildProfile; process.env.BUILD_TARGET = buildParameters.targetPlatform; process.env.BUILD_NAME = buildParameters.buildName; process.env.BUILD_PATH = buildParameters.buildPath; diff --git a/test-project/Assets/Settings.meta b/test-project/Assets/Settings.meta new file mode 100644 index 00000000..469fdc4c --- /dev/null +++ b/test-project/Assets/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 28bfc999a135648538355bfcb6a23aee +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/test-project/Assets/Settings/Build Profiles.meta b/test-project/Assets/Settings/Build Profiles.meta new file mode 100644 index 00000000..1bd4102a --- /dev/null +++ b/test-project/Assets/Settings/Build Profiles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cd91492ed9aca40c49d42156a4a8f387 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/test-project/Assets/Settings/Build Profiles/Sample WebGL Build Profile.asset b/test-project/Assets/Settings/Build Profiles/Sample WebGL Build Profile.asset new file mode 100644 index 00000000..50ee7f2b --- /dev/null +++ b/test-project/Assets/Settings/Build Profiles/Sample WebGL Build Profile.asset @@ -0,0 +1,46 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 15003, guid: 0000000000000000e000000000000000, type: 0} + m_Name: Sample WebGL Build Profile + m_EditorClassIdentifier: + m_AssetVersion: 1 + m_BuildTarget: 20 + m_Subtarget: 0 + m_PlatformId: 84a3bb9e7420477f885e98145999eb20 + m_PlatformBuildProfile: + rid: 200022742090383361 + m_OverrideGlobalSceneList: 0 + m_Scenes: [] + m_ScriptingDefines: [] + m_PlayerSettingsYaml: + m_Settings: [] + references: + version: 2 + RefIds: + - rid: 200022742090383361 + type: {class: WebGLPlatformSettings, ns: UnityEditor.WebGL, asm: UnityEditor.WebGL.Extensions} + data: + m_Development: 0 + m_ConnectProfiler: 0 + m_BuildWithDeepProfilingSupport: 0 + m_AllowDebugging: 0 + m_WaitForManagedDebugger: 0 + m_ManagedDebuggerFixedPort: 0 + m_ExplicitNullChecks: 0 + m_ExplicitDivideByZeroChecks: 0 + m_ExplicitArrayBoundsChecks: 0 + m_CompressionType: -1 + m_InstallInBuildFolder: 0 + m_CodeOptimization: 0 + m_WebGLClientBrowserPath: + m_WebGLClientBrowserType: 0 + m_WebGLTextureSubtarget: 0 diff --git a/test-project/Assets/Settings/Build Profiles/Sample WebGL Build Profile.asset.meta b/test-project/Assets/Settings/Build Profiles/Sample WebGL Build Profile.asset.meta new file mode 100644 index 00000000..5370e7d2 --- /dev/null +++ b/test-project/Assets/Settings/Build Profiles/Sample WebGL Build Profile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b9aac23ad2add4b439decb0cf65b0d68 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: