Add input to set version code

Use action input `androidVersionCode` when provided. Generate the androidVersionCode from the version otherwise.
This commit is contained in:
Benoit Dion 2020-06-24 18:02:05 -04:00 committed by Webber Takken
parent 401ddcaae0
commit bdc3a88d22
17 changed files with 130 additions and 7 deletions

View File

@ -74,6 +74,7 @@ jobs:
projectPath: ${{ matrix.projectPath }} projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }} unityVersion: ${{ matrix.unityVersion }}
targetPlatform: ${{ matrix.targetPlatform }} targetPlatform: ${{ matrix.targetPlatform }}
androidVersionCode: ${{ github.run_number }}
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v1
with: with:

View File

@ -295,6 +295,12 @@ No version will be set by Builder. **(not recommended)**
> Not recommended unless you generate a new version in a pre-commit hook. Manually > Not recommended unless you generate a new version in a pre-commit hook. Manually
> setting versions is error-prone. > setting versions is error-prone.
#### androidVersionCode
Configure the android `versionCode`.
When not specified, the version code is generated from the version using the `major * 1000000 + minor * 1000 + patch` scheme;
#### allowDirtyBuild #### allowDirtyBuild
Allows the branch of the build to be dirty, and still generate the build. Allows the branch of the build to be dirty, and still generate the build.

View File

@ -26,6 +26,14 @@ inputs:
required: false required: false
default: '' default: ''
description: 'Path to a Namespace.Class.StaticMethod to run to perform the build.' description: 'Path to a Namespace.Class.StaticMethod to run to perform the build.'
versioning:
required: false
default: 'Semantic'
description: 'The versioning scheme to use when building the project'
androidVersionCode:
required: false
default: ''
description: 'The android versionCode'
outputs: {} outputs: {}
branding: branding:
icon: 'box' icon: 'box'

View File

@ -28,6 +28,7 @@ namespace UnityBuilderAction
// Set version for this build // Set version for this build
VersionApplicator.SetVersion(options["version"]); VersionApplicator.SetVersion(options["version"]);
VersionApplicator.SetAndroidVersionCode(options["androidVersionCode"]);
// Perform build // Perform build
BuildReport buildReport = BuildPipeline.BuildPlayer(buildOptions); BuildReport buildReport = BuildPipeline.BuildPlayer(buildOptions);

View File

@ -1,5 +1,4 @@
using System; using System;
using JetBrains.Annotations;
using UnityEditor; using UnityEditor;
namespace UnityBuilderAction.Versioning namespace UnityBuilderAction.Versioning
@ -11,10 +10,14 @@ namespace UnityBuilderAction.Versioning
if (version == "none") { if (version == "none") {
return; return;
} }
Apply(version); Apply(version);
} }
public static void SetAndroidVersionCode(string androidVersionCode) {
PlayerSettings.Android.bundleVersionCode = Int32.Parse(androidVersionCode);
}
static void Apply(string version) static void Apply(string version)
{ {
PlayerSettings.bundleVersion = version; PlayerSettings.bundleVersion = version;

File diff suppressed because one or more lines are too long

View File

@ -109,8 +109,8 @@ xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
-customBuildTarget "$BUILD_TARGET" \ -customBuildTarget "$BUILD_TARGET" \
-customBuildPath "$CUSTOM_BUILD_PATH" \ -customBuildPath "$CUSTOM_BUILD_PATH" \
-executeMethod "$BUILD_METHOD" \ -executeMethod "$BUILD_METHOD" \
-versioning "$VERSIONING" \
-version "$VERSION" \ -version "$VERSION" \
-androidVersionCode "$ANDROID_VERSION_CODE" \
$CUSTOM_PARAMETERS $CUSTOM_PARAMETERS
# Catch exit code # Catch exit code

View File

@ -10,12 +10,14 @@
"prebuild": "yarn", "prebuild": "yarn",
"build": "ncc build src --out action --minify", "build": "ncc build src --out action --minify",
"lint": "prettier --check \"src/**/*.js\" && eslint src", "lint": "prettier --check \"src/**/*.js\" && eslint src",
"format": "prettier --write \"src/**/*.js\"",
"test": "jest" "test": "jest"
}, },
"dependencies": { "dependencies": {
"@actions/core": "^1.2.4", "@actions/core": "^1.2.4",
"@actions/exec": "1.0.4", "@actions/exec": "1.0.4",
"@actions/github": "^2.1.1" "@actions/github": "^2.1.1",
"semver": "^7.3.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/cli": "7.8.4", "@babel/cli": "7.8.4",

View File

@ -0,0 +1,33 @@
import * as core from '@actions/core';
import * as semver from 'semver';
export default class AndroidVersioning {
static determineVersionCode(version, inputVersionCode) {
if (!inputVersionCode) {
return AndroidVersioning.versionToVersionCode(version);
}
return inputVersionCode;
}
static versionToVersionCode(version) {
const parsedVersion = semver.parse(version);
if (!parsedVersion) {
core.warning(`Could not parse "${version}" to semver, defaulting android version code to 1`);
return 1;
}
// The greatest value Google Plays allows is 2100000000.
// Allow for 3 patch digits, 3 minor digits and 3 major digits.
const versionCode =
parsedVersion.major * 1000000 + parsedVersion.minor * 1000 + parsedVersion.patch;
if (versionCode >= 1000000000) {
throw new Error(
`Generated versionCode ${versionCode} is dangerously close to the maximum allowed number 2100000000. Consider a different versioning scheme to be able to continue updating your application.`,
);
}
core.info(`Using android versionCode ${versionCode}`);
return versionCode;
}
}

View File

@ -0,0 +1,27 @@
import AndroidVersioning from './android-versioning';
describe('Android Versioning', () => {
describe('versionToVersionCode', () => {
it('defaults to 1 when version is not a valid semver', () => {
expect(AndroidVersioning.versionToVersionCode('abcd')).toBe(1);
});
it('returns a number', () => {
expect(AndroidVersioning.versionToVersionCode('123.456.789')).toBe(123456789);
});
it('throw when generated version code is too large', () => {
expect(() => AndroidVersioning.versionToVersionCode('1234.0.0')).toThrow();
});
});
describe('determineVersionCode', () => {
it('defaults to parsed version', () => {
expect(AndroidVersioning.determineVersionCode('1.2.3', '')).toBe(1002003);
});
it('use specified code', () => {
expect(AndroidVersioning.determineVersionCode('1.2.3', 2)).toBe(2);
});
});
});

View File

@ -1,3 +1,4 @@
import AndroidVersioning from './android-versioning';
import Input from './input'; import Input from './input';
import Platform from './platform'; import Platform from './platform';
import Versioning from './versioning'; import Versioning from './versioning';
@ -10,6 +11,11 @@ class BuildParameters {
Input.specifiedVersion, Input.specifiedVersion,
); );
const androidVersionCode = AndroidVersioning.determineVersionCode(
buildVersion,
Input.androidVersionCode,
);
return { return {
version: Input.unityVersion, version: Input.unityVersion,
platform: Input.targetPlatform, platform: Input.targetPlatform,
@ -19,6 +25,7 @@ class BuildParameters {
buildFile, buildFile,
buildMethod: Input.buildMethod, buildMethod: Input.buildMethod,
buildVersion, buildVersion,
androidVersionCode,
customParameters: Input.customParameters, customParameters: Input.customParameters,
}; };
} }

View File

@ -30,6 +30,22 @@ describe('BuildParameters', () => {
); );
}); });
it('returns the android version code with provided input', async () => {
const mockValue = '42';
jest.spyOn(Input, 'androidVersionCode', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ androidVersionCode: mockValue }),
);
});
it('returns the android version code from version by default', async () => {
const mockValue = '';
jest.spyOn(Input, 'androidVersionCode', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ androidVersionCode: 1003037 }),
);
});
it('returns the platform', async () => { it('returns the platform', async () => {
const mockValue = 'somePlatform'; const mockValue = 'somePlatform';
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(mockValue); jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(mockValue);

View File

@ -29,6 +29,7 @@ class Docker {
buildMethod, buildMethod,
buildVersion, buildVersion,
customParameters, customParameters,
androidVersionCode,
} = parameters; } = parameters;
const command = `docker run \ const command = `docker run \
@ -47,6 +48,7 @@ class Docker {
--env BUILD_FILE="${buildFile}" \ --env BUILD_FILE="${buildFile}" \
--env BUILD_METHOD="${buildMethod}" \ --env BUILD_METHOD="${buildMethod}" \
--env VERSION="${buildVersion}" \ --env VERSION="${buildVersion}" \
--env ANDROID_VERSION_CODE="${androidVersionCode}" \
--env CUSTOM_PARAMETERS="${customParameters}" \ --env CUSTOM_PARAMETERS="${customParameters}" \
--env HOME=/github/home \ --env HOME=/github/home \
--env GITHUB_REF \ --env GITHUB_REF \

View File

@ -25,7 +25,7 @@ describe('Docker', () => {
const parameters = { const parameters = {
workspace: Action.rootFolder, workspace: Action.rootFolder,
projectPath: `${Action.rootFolder}/test-project`, projectPath: `${Action.rootFolder}/test-project`,
buildName: 'someBulidName', buildName: 'someBuildName',
buildsPath: 'build', buildsPath: 'build',
method: '', method: '',
}; };

View File

@ -41,6 +41,10 @@ class Input {
return core.getInput('version') || ''; return core.getInput('version') || '';
} }
static get androidVersionCode() {
return core.getInput('androidVersionCode');
}
static get allowDirtyBuild() { static get allowDirtyBuild() {
const input = core.getInput('allowDirtyBuild') || 'false'; const input = core.getInput('allowDirtyBuild') || 'false';

View File

@ -118,6 +118,19 @@ describe('Input', () => {
}); });
}); });
describe('androidVersionCode', () => {
it('defaults to null', () => {
expect(Input.androidVersionCode).toBeFalsy();
});
it('takes input from the users workflow', () => {
const mockValue = '42';
const spy = jest.spyOn(core, 'getInput').mockReturnValue(mockValue);
expect(Input.androidVersionCode).toStrictEqual(mockValue);
expect(spy).toHaveBeenCalledTimes(1);
});
});
describe('allowDirtyBuild', () => { describe('allowDirtyBuild', () => {
it('returns the default value', () => { it('returns the default value', () => {
expect(Input.allowDirtyBuild).toStrictEqual('false'); expect(Input.allowDirtyBuild).toStrictEqual('false');

View File

@ -5045,7 +5045,7 @@ semver@^6.0.0, semver@^6.1.2, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.1.3: semver@^7.1.3, semver@^7.3.2:
version "7.3.2" version "7.3.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==