refactor: parameters into cli structure
parent
6b32132ec0
commit
ccf0047c1c
|
|
@ -11,14 +11,14 @@ env:
|
|||
|
||||
jobs:
|
||||
buildForAllPlatformsUbuntu:
|
||||
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
|
||||
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.engineVersion }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
projectPath:
|
||||
- test-project
|
||||
unityVersion:
|
||||
engineVersion:
|
||||
- 2019.2.11f1
|
||||
- 2019.3.15f1
|
||||
targetPlatform:
|
||||
|
|
@ -59,7 +59,7 @@ jobs:
|
|||
- uses: ./
|
||||
with:
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
engineVersion: ${{ matrix.engineVersion }}
|
||||
targetPlatform: ${{ matrix.targetPlatform }}
|
||||
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||
|
||||
|
|
@ -68,6 +68,6 @@ jobs:
|
|||
###########################
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Build Ubuntu (${{ matrix.unityVersion }})
|
||||
name: Build Ubuntu (${{ matrix.engineVersion }})
|
||||
path: build
|
||||
retention-days: 14
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ jobs:
|
|||
matrix:
|
||||
projectPath:
|
||||
- test-project
|
||||
unityVersion:
|
||||
engineVersion:
|
||||
# - 2019.2.11f1
|
||||
- 2019.3.15f1
|
||||
targetPlatform:
|
||||
|
|
@ -82,7 +82,7 @@ jobs:
|
|||
cloudRunnerCluster: aws
|
||||
versioning: None
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
engineVersion: ${{ matrix.engineVersion }}
|
||||
targetPlatform: ${{ matrix.targetPlatform }}
|
||||
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
postBuildSteps: |
|
||||
|
|
@ -118,12 +118,12 @@ jobs:
|
|||
path: build-${{ steps.aws-fargate-unity-build.outputs.BUILD_GUID }}.tar
|
||||
retention-days: 14
|
||||
k8sBuilds:
|
||||
name: K8s (GKE Autopilot) build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
|
||||
name: K8s (GKE Autopilot) build for ${{ matrix.targetPlatform }} on version ${{ matrix.engineVersion }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
unityVersion:
|
||||
engineVersion:
|
||||
# - 2019.2.11f1
|
||||
- 2019.3.15f1
|
||||
targetPlatform:
|
||||
|
|
@ -166,7 +166,7 @@ jobs:
|
|||
TARGET_PLATFORM: ${{ matrix.targetPlatform }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
KUBE_CONFIG: ${{ steps.read-base64.outputs.base64 }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
engineVersion: ${{ matrix.engineVersion }}
|
||||
cloudRunnerTests: true
|
||||
versioning: None
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ jobs:
|
|||
kubeConfig: ${{ steps.read-base64.outputs.base64 }}
|
||||
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
projectPath: test-project
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
engineVersion: ${{ matrix.engineVersion }}
|
||||
versioning: None
|
||||
postBuildSteps: |
|
||||
- name: upload
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ env:
|
|||
|
||||
jobs:
|
||||
buildForAllPlatformsWindows:
|
||||
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
|
||||
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.engineVersion }}
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
projectPath:
|
||||
- test-project
|
||||
unityVersion:
|
||||
engineVersion:
|
||||
- 2020.3.24f1
|
||||
targetPlatform:
|
||||
- StandaloneOSX # Build a MacOS executable
|
||||
|
|
@ -58,7 +58,7 @@ jobs:
|
|||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||
with:
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
engineVersion: ${{ matrix.engineVersion }}
|
||||
targetPlatform: ${{ matrix.targetPlatform }}
|
||||
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||
# We use dirty build because we are replacing the default project settings file above
|
||||
|
|
@ -69,6 +69,6 @@ jobs:
|
|||
###########################
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Build MacOS (${{ matrix.unityVersion }})
|
||||
name: Build MacOS (${{ matrix.engineVersion }})
|
||||
path: build
|
||||
retention-days: 14
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ env:
|
|||
|
||||
jobs:
|
||||
buildForAllPlatformsWindows:
|
||||
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
|
||||
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.engineVersion }}
|
||||
runs-on: windows-2019
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
projectPath:
|
||||
- test-project
|
||||
unityVersion:
|
||||
engineVersion:
|
||||
- 2020.3.24f1
|
||||
targetPlatform:
|
||||
- StandaloneWindows64 # Build a Windows 64-bit standalone.
|
||||
|
|
@ -61,7 +61,7 @@ jobs:
|
|||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||
with:
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
engineVersion: ${{ matrix.engineVersion }}
|
||||
targetPlatform: ${{ matrix.targetPlatform }}
|
||||
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||
allowDirtyBuild: true
|
||||
|
|
@ -72,6 +72,6 @@ jobs:
|
|||
###########################
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Build Windows (${{ matrix.unityVersion }})
|
||||
name: Build Windows (${{ matrix.engineVersion }})
|
||||
path: build
|
||||
retention-days: 14
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ inputs:
|
|||
required: true
|
||||
default: ''
|
||||
description: 'Platform that the build should target.'
|
||||
unityVersion:
|
||||
engineVersion:
|
||||
required: false
|
||||
default: 'auto'
|
||||
description: 'Version of unity to use for building the project. Use "auto" to get from your ProjectSettings/ProjectVersion.txt'
|
||||
|
|
@ -184,7 +184,8 @@ runs:
|
|||
- run: |
|
||||
deno run --allow-run ./src/index.ts build \
|
||||
--targetPlatform="${{ inputs.targetPlatform }}" \
|
||||
--unityVersion="${{ inputs.unityVersion }}" \
|
||||
--engineVersion="${{ inputs.engineVersion }}" \
|
||||
--engineVersion="${{ inputs.engineVersion }}" \
|
||||
--customImage="${{ inputs.customImage }}" \
|
||||
--projectPath="${{ inputs.projectPath }}" \
|
||||
--buildName="${{ inputs.buildName }}" \
|
||||
|
|
|
|||
59
src/cli.ts
59
src/cli.ts
|
|
@ -1,12 +1,14 @@
|
|||
import yargs from 'https://deno.land/x/yargs@v17.5.1-deno/deno.ts';
|
||||
import { yargs, YargsInstance, YargsArguments } from './dependencies.ts';
|
||||
import { default as getHomeDir } from 'https://deno.land/x/dir@1.5.1/home_dir/mod.ts';
|
||||
import { engineDetection } from './middleware/engine-detection/index.ts';
|
||||
import { CommandInterface } from './command/command-interface.ts';
|
||||
import { configureLogger } from './middleware/logger-verbosity/index.ts';
|
||||
import { CommandFactory } from './command/command-factory.ts';
|
||||
import { Engine } from './model/engine/engine.ts';
|
||||
import { branchDetection } from './middleware/branch-detection/index.ts';
|
||||
|
||||
export class Cli {
|
||||
private readonly yargs: yargs.Argv;
|
||||
private readonly yargs: YargsInstance;
|
||||
private readonly cliStorageAbsolutePath: string;
|
||||
private readonly cliStorageCanonicalPath: string;
|
||||
private readonly configFileName: string;
|
||||
|
|
@ -28,6 +30,11 @@ export class Cli {
|
|||
|
||||
await this.parse();
|
||||
|
||||
if (log.isVeryVerbose) {
|
||||
log.debug(`Parsed command: ${this.command.name} (${this.command.constructor.name})`);
|
||||
log.debug(`Parsed arguments: ${JSON.stringify(this.options, null, 2)}`);
|
||||
}
|
||||
|
||||
return {
|
||||
command: this.command,
|
||||
options: this.options,
|
||||
|
|
@ -60,35 +67,43 @@ export class Cli {
|
|||
this.yargs
|
||||
.options('quiet', {
|
||||
alias: 'q',
|
||||
default: false,
|
||||
description: 'Suppress all output',
|
||||
type: 'boolean',
|
||||
demandOption: false,
|
||||
default: false,
|
||||
})
|
||||
.options('verbose', {
|
||||
alias: 'v',
|
||||
default: false,
|
||||
description: 'Enable verbose logging',
|
||||
type: 'boolean',
|
||||
demandOption: false,
|
||||
default: false,
|
||||
})
|
||||
.options('veryVerbose', {
|
||||
alias: 'vv',
|
||||
default: false,
|
||||
description: 'Enable very verbose logging',
|
||||
type: 'boolean',
|
||||
demandOption: false,
|
||||
default: false,
|
||||
})
|
||||
.options('maxVerbose', {
|
||||
alias: 'vvv',
|
||||
default: false,
|
||||
description: 'Enable debug logging',
|
||||
demandOption: false,
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
})
|
||||
.default([{ logLevel: 'placeholder' }, { logLevelName: 'placeholder' }])
|
||||
.middleware([configureLogger], true);
|
||||
}
|
||||
|
||||
private globalOptions() {
|
||||
this.yargs
|
||||
.help('help')
|
||||
.showHelpOnFail(false, 'Specify --help for available options')
|
||||
.epilogue('for more information, find our manual at https://game.ci/docs/cli')
|
||||
.middleware([])
|
||||
.showHelpOnFail(true)
|
||||
.exitProcess(true) // prevents `_handle` from being lost
|
||||
.strict(true);
|
||||
}
|
||||
|
||||
|
|
@ -98,17 +113,35 @@ export class Cli {
|
|||
.positional('projectPath', {
|
||||
describe: 'Path to the project',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '.',
|
||||
})
|
||||
.coerce('projectPath', async (arg) => {
|
||||
return arg.replace(/^~/, getHomeDir()).replace(/\/$/, '');
|
||||
})
|
||||
.middleware([engineDetection, branchDetection])
|
||||
|
||||
// Todo - remove these lines with release 3.0.0
|
||||
.option('unityVersion', {
|
||||
describe: 'Override the engine version to be used',
|
||||
type: 'string',
|
||||
})
|
||||
.deprecateOption('unityVersion', 'This parameter will be removed. Use engineVersion instead')
|
||||
.middleware([
|
||||
engineDetection, // Command is engine specific
|
||||
async (args) => {
|
||||
await this.registerCommand(args, yargs);
|
||||
if (!args.unityVersion || args.unityVersion === 'auto' || args.engine !== Engine.unity) return;
|
||||
|
||||
args.engineVersion = args.unityVersion;
|
||||
args.unityVersion = undefined;
|
||||
},
|
||||
]);
|
||||
])
|
||||
|
||||
// End todo
|
||||
.middleware([async (args) => this.registerCommand(args, yargs)]);
|
||||
});
|
||||
}
|
||||
|
||||
private async registerCommand(args: yargs.Arguments, yargs) {
|
||||
private async registerCommand(args: YargsArguments, yargs: YargsInstance) {
|
||||
const { engine, engineVersion, _: command } = args;
|
||||
|
||||
this.command = new CommandFactory().selectEngine(engine, engineVersion).createCommand(command);
|
||||
|
|
@ -117,6 +150,8 @@ export class Cli {
|
|||
}
|
||||
|
||||
private async parse() {
|
||||
this.options = await this.yargs.parseAsync();
|
||||
const { _, $0, ...options } = await this.yargs.parseAsync();
|
||||
|
||||
this.options = options;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
import { YargsInstance, YargsArguments } from '../dependencies.ts';
|
||||
|
||||
export class AndroidOptions {
|
||||
public static configureCommonOptions(yargs: YargsInstance): void {
|
||||
yargs
|
||||
.option('androidAppBundle', {
|
||||
description: 'Build an Android App Bundle',
|
||||
type: 'boolean',
|
||||
demandOption: false,
|
||||
default: false,
|
||||
})
|
||||
.options({
|
||||
androidKeystoreName: {
|
||||
description: 'Name of the keystore',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
},
|
||||
androidKeystoreBase64: {
|
||||
description: 'Base64 encoded contents of the keystore',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
},
|
||||
androidKeystorePass: {
|
||||
description: 'Password for the keystore',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
deprecated: 'Use androidKeystorePassword instead',
|
||||
},
|
||||
androidKeystorePassword: {
|
||||
description: 'Password for the keystore',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
},
|
||||
androidKeyAlias: {
|
||||
description: 'Alias for the keystore',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
},
|
||||
androidKeyAliasName: {
|
||||
description: 'Name of the keystore',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
deprecated: 'Use androidKeyAlias instead',
|
||||
},
|
||||
androidKeyAliasPassword: {
|
||||
description: 'Password for the androidKeyAlias',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
requires: ['androidKeyAlias'],
|
||||
},
|
||||
androidKeyAliasPass: {
|
||||
description: 'Password for the androidKeyAlias',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
deprecated: 'Use androidKeyAliasPassword instead',
|
||||
},
|
||||
})
|
||||
.option('androidTargetSdkVersion', {
|
||||
description: 'Custom Android SDK target version',
|
||||
type: 'number',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
})
|
||||
.default('androidSdkManagerParameters', '') // Placeholder, consumed in middleware
|
||||
.middleware([AndroidOptions.determineSdkManagerParameters]);
|
||||
}
|
||||
|
||||
private static determineSdkManagerParameters(argv: YargsArguments) {
|
||||
const { androidTargetSdkVersion } = argv;
|
||||
|
||||
if (!androidTargetSdkVersion) return;
|
||||
|
||||
argv.androidSdkManagerParameters = `platforms;android-${androidTargetSdkVersion}`;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import { YargsInstance } from '../dependencies.ts';
|
||||
import Unity from '../model/unity/unity.ts';
|
||||
|
||||
export class BuildOptions {
|
||||
public static configure(yargs: YargsInstance): void {
|
||||
yargs
|
||||
.demandOption('targetPlatform', 'Target platform is mandatory for builds')
|
||||
.option('buildName', {
|
||||
description: 'Name of the build',
|
||||
type: 'string',
|
||||
default: '',
|
||||
})
|
||||
.option('buildsPath', {
|
||||
description: 'Path for outputting the builds to',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: 'build',
|
||||
})
|
||||
.default('buildPath', '')
|
||||
.default('buildFile', '')
|
||||
.middleware(async (argv) => {
|
||||
const { buildName, buildsPath, targetPlatform, androidAppBundle } = argv;
|
||||
argv.buildName = buildName || targetPlatform;
|
||||
argv.buildPath = `${buildsPath}/${targetPlatform}`;
|
||||
argv.buildFile = Unity.determineBuildFileName(buildName, targetPlatform, androidAppBundle);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import type { YargsInstance } from '../dependencies.ts';
|
||||
import UnityTargetPlatform from '../model/unity/unity-target-platform.ts';
|
||||
import { UnityTargetPlatforms } from '../model/unity/unity-target-platforms.ts';
|
||||
|
||||
export class UnityOptions {
|
||||
public static configure = async (yargs: YargsInstance) => {
|
||||
yargs
|
||||
.option('targetPlatform', {
|
||||
alias: 't',
|
||||
description: 'The platform to build your project for',
|
||||
choices: UnityTargetPlatforms.all,
|
||||
demandOption: false,
|
||||
default: UnityTargetPlatform.default,
|
||||
})
|
||||
.options({
|
||||
unityEmail: {
|
||||
alias: 'u',
|
||||
description: 'Email address for your Unity account',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
},
|
||||
unityPassword: {
|
||||
alias: 'p',
|
||||
description: 'Password for your Unity account',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
},
|
||||
unitySerial: {
|
||||
alias: 's',
|
||||
description: 'Serial number identifying a pro-license seat',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
},
|
||||
unityLicense: {
|
||||
alias: 'l',
|
||||
description: 'Contents of, or path to your Unity License File (.ulf)',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
.coerce('unityLicense', async (arg) => {
|
||||
return arg.endsWith('.ulf') ? Deno.readTextFile(arg, { encoding: 'utf8' }) : arg;
|
||||
})
|
||||
.option('customImage', {
|
||||
description: String.dedent`
|
||||
Custom docker image to use inside the command.
|
||||
For more information see https://game.ci/docs/docker/versions`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('usymUploadAuthToken', {
|
||||
description: '<missing description>',
|
||||
type: 'string',
|
||||
demandOption: false,
|
||||
default: '',
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
import { YargsInstance } from '../dependencies.ts';
|
||||
import { VersioningStrategies } from '../model/versioning/versioning-strategies.ts';
|
||||
import { VersioningStrategy } from '../model/versioning/versioning-strategy.ts';
|
||||
import { buildVersioning } from '../middleware/build-versioning/index.ts';
|
||||
|
||||
export class VersioningOptions {
|
||||
public static async configure(yargs: YargsInstance): void {
|
||||
yargs
|
||||
.option('versioningStrategy', {
|
||||
description: 'Versioning strategy',
|
||||
choices: VersioningStrategies.all,
|
||||
demandOption: true,
|
||||
default: VersioningStrategy.Semantic,
|
||||
})
|
||||
.option('version', {
|
||||
description: String.dedent`
|
||||
Custom version to use for the build.
|
||||
Only used when versioningStrategy is set to Custom`,
|
||||
type: 'string',
|
||||
default: '',
|
||||
})
|
||||
.option('androidVersionCode', {
|
||||
description: String.dedent`
|
||||
Custom version code for android specifically.`,
|
||||
type: 'string',
|
||||
default: '',
|
||||
})
|
||||
.option('allowDirtyBuild', {
|
||||
description: 'Allow a dirty build',
|
||||
type: 'boolean',
|
||||
demandOption: false,
|
||||
default: false,
|
||||
})
|
||||
.default('buildVersion', 'placeholder')
|
||||
.middleware([buildVersioning]);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,10 @@ import { Action, Cache, Docker, ImageTag, Input, Output } from '../../model/inde
|
|||
import PlatformSetup from '../../model/platform-setup.ts';
|
||||
import MacBuilder from '../../model/mac-builder.ts';
|
||||
import { CommandBase } from '../command-base.ts';
|
||||
import { UnityOptions } from '../../command-options/unity-options.ts';
|
||||
import { YargsInstance } from '../../dependencies.ts';
|
||||
import { VersioningOptions } from '../../command-options/versioning-options.ts';
|
||||
import { BuildOptions } from '../../command-options/build-options.ts';
|
||||
|
||||
export class UnityBuildCommand extends CommandBase implements CommandInterface {
|
||||
public async execute(options): Promise<boolean> {
|
||||
|
|
@ -32,10 +36,9 @@ export class UnityBuildCommand extends CommandBase implements CommandInterface {
|
|||
}
|
||||
}
|
||||
|
||||
public async configureOptions(instance): Promise<void> {
|
||||
instance.option('buildName', {
|
||||
description: 'Name of the build',
|
||||
type: 'string',
|
||||
});
|
||||
public async configureOptions(yargs: YargsInstance): Promise<void> {
|
||||
await UnityOptions.configure(yargs);
|
||||
await VersioningOptions.configure(yargs);
|
||||
await BuildOptions.configure(yargs);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { NonExistentCommand } from './null/non-existent-command.ts';
|
|||
import { UnityBuildCommand } from './build/unity-build-command.ts';
|
||||
import { CommandInterface } from './command-interface.ts';
|
||||
import { UnityRemoteBuildCommand } from './remote/unity-remote-build-command.ts';
|
||||
import { Engine } from '../model/engine.ts';
|
||||
import { Engine } from '../model/engine/engine.ts';
|
||||
|
||||
export class CommandFactory {
|
||||
constructor() {}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ export const configureLogger = async (verbosity: Verbosity) => {
|
|||
|
||||
// Verbosity
|
||||
window.log.verbosity = verbosity;
|
||||
window.log.verbosityName = Verbosity[verbosity];
|
||||
window.log.isQuiet = isQuiet;
|
||||
window.log.isVerbose = isVerbose;
|
||||
window.log.isVeryVerbose = isVeryVerbose;
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ import { Command } from 'https://deno.land/x/cmd@v1.2.0/commander/index.ts';
|
|||
import { getUnityChangeset as getUnityChangeSet } from 'https://deno.land/x/unity_changeset@2.0.0/src/index.ts';
|
||||
import { Buffer } from 'https://deno.land/std@0.151.0/io/buffer.ts';
|
||||
import { config, configSync } from 'https://deno.land/std@0.151.0/dotenv/mod.ts';
|
||||
import yargs from 'https://deno.land/x/yargs@v17.4.0-deno/deno.ts';
|
||||
import * as yargsTypes from 'https://deno.land/x/yargs@v17.4.0-deno/deno-types.ts';
|
||||
import yargs from 'https://deno.land/x/yargs@v17.5.1-deno/deno.ts';
|
||||
import type { Arguments as YargsArguments } from 'https://deno.land/x/yargs@v17.5.1-deno/deno-types.ts';
|
||||
|
||||
// Internally managed packages
|
||||
import waitUntil from './module/wait-until.ts';
|
||||
|
|
@ -42,6 +42,9 @@ const __dirname = path.dirname(path.fromFileUrl(import.meta.url));
|
|||
|
||||
const { V1EnvVar, V1EnvVarSource, V1SecretKeySelector } = k8s;
|
||||
|
||||
type YargsInstance = yargs.Argv;
|
||||
|
||||
export type { YargsArguments, YargsInstance };
|
||||
export {
|
||||
__dirname,
|
||||
__filename,
|
||||
|
|
@ -74,5 +77,4 @@ export {
|
|||
Writable,
|
||||
yaml,
|
||||
yargs,
|
||||
yargsTypes,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
import { Verbosity } from './core/logger/index.ts';
|
||||
|
||||
declare global {
|
||||
interface String {
|
||||
dedent(indentedString: string): string;
|
||||
}
|
||||
|
||||
let log: {
|
||||
verbosity: Verbosity;
|
||||
isQuiet: boolean;
|
||||
|
|
@ -11,6 +16,11 @@ let log: {
|
|||
warning: (msg: any, ...args: any[]) => void;
|
||||
error: (msg: any, ...args: any[]) => void;
|
||||
};
|
||||
}
|
||||
|
||||
declare interface String {
|
||||
dedent(indentedString: string): string;
|
||||
}
|
||||
|
||||
declare interface Window {
|
||||
log: any;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ class GameCI {
|
|||
|
||||
if (!success) throw new Error(`${command.name} failed.`);
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
Deno.exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Parameters } from '../../../model/index.ts';
|
||||
import { fsSync as fs, getUnityChangeSet } from '../../../dependencies.ts';
|
||||
import System from '../../../model/system.ts';
|
||||
import System from '../../../model/system/system.ts';
|
||||
|
||||
class SetupMac {
|
||||
static unityHubPath = `"/Applications/Unity Hub.app/Contents/MacOS/Unity Hub"`;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { fsSync as fs } from '../../../dependencies.ts';
|
||||
import { Parameters } from '../../../model/index.ts';
|
||||
import ValidateWindows from '../platform-validation/validate-windows.ts';
|
||||
import System from '../../../model/system.ts';
|
||||
import System from '../../../model/system/system.ts';
|
||||
|
||||
class SetupWindows {
|
||||
public static async setup(parameters: Parameters) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import System from '../../model/system/system.ts';
|
||||
|
||||
export class BranchDetector {
|
||||
public static async getCurrentBranch(projectPath) {
|
||||
// GitHub pull request, GitHub non pull request
|
||||
let branchName = this.headRef || this.ref?.slice(11);
|
||||
|
||||
// Local
|
||||
if (!branchName) {
|
||||
const { status, output } = await System.shellRun('git branch --show-current', { cwd: projectPath });
|
||||
if (!status.success) throw new Error('did not expect "git branch --show-current"');
|
||||
branchName = output;
|
||||
}
|
||||
|
||||
return branchName;
|
||||
}
|
||||
|
||||
/**
|
||||
* For pull requests we can reliably use GITHUB_HEAD_REF
|
||||
* @deprecated
|
||||
*/
|
||||
private get headRef() {
|
||||
return Deno.env.get('GITHUB_HEAD_REF');
|
||||
}
|
||||
|
||||
/**
|
||||
* For branches GITHUB_REF will have format `refs/heads/feature-branch-1`
|
||||
* @deprecated
|
||||
*/
|
||||
private get ref() {
|
||||
return Deno.env.get('GITHUB_REF');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import System from '../../model/system/system.ts';
|
||||
import { BranchDetector } from './branch-detector.ts';
|
||||
|
||||
export const branchDetection = async (argv) => {
|
||||
const { projectPath } = argv;
|
||||
|
||||
const branch = await BranchDetector.getCurrentBranch(projectPath);
|
||||
|
||||
// Todo - determine if we ever want to run the cli on a project that has no git repo.
|
||||
if (!branch) throw new Error('Running GameCI CLI on a project without a git repository is not supported.');
|
||||
|
||||
argv.branch = branch;
|
||||
};
|
||||
|
|
@ -1,15 +1,7 @@
|
|||
import { semver } from '../dependencies.ts';
|
||||
import { semver } from '../../dependencies.ts';
|
||||
|
||||
export default class AndroidVersioning {
|
||||
static determineVersionCode(version, inputVersionCode) {
|
||||
if (!inputVersionCode) {
|
||||
return AndroidVersioning.versionToVersionCode(version);
|
||||
}
|
||||
|
||||
return inputVersionCode;
|
||||
}
|
||||
|
||||
static versionToVersionCode(version) {
|
||||
export default class AndroidBuildVersionGenerator {
|
||||
public static determineVersionCode(version) {
|
||||
if (version === 'none') {
|
||||
log.info(`Versioning strategy is set to ${version}, so android version code should not be applied.`);
|
||||
|
||||
|
|
@ -37,10 +29,4 @@ export default class AndroidVersioning {
|
|||
|
||||
return versionCode;
|
||||
}
|
||||
|
||||
static determineSdkManagerParameters(targetSdkVersion) {
|
||||
const parsedVersion = Number.parseInt(targetSdkVersion.slice(-2), 10);
|
||||
|
||||
return Number.isNaN(parsedVersion) ? '' : `platforms;android-${parsedVersion}`;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,102 +1,33 @@
|
|||
import NotImplementedException from './error/not-implemented-exception.ts';
|
||||
import ValidationError from './error/validation-error.ts';
|
||||
import Input from './input.ts';
|
||||
import System from './system.ts';
|
||||
import { Action } from './index.ts';
|
||||
import NotImplementedException from '../../model/error/not-implemented-exception.ts';
|
||||
import Input from '../../model/input.ts';
|
||||
import System from '../../model/system/system.ts';
|
||||
import { Action } from '../../model/index.ts';
|
||||
import { VersioningStrategy } from '../../model/versioning/versioning-strategy.ts';
|
||||
|
||||
export default class Versioning {
|
||||
static get projectPath() {
|
||||
return Input.projectPath;
|
||||
}
|
||||
|
||||
static get strategies() {
|
||||
return { None: 'None', Semantic: 'Semantic', Tag: 'Tag', Custom: 'Custom' };
|
||||
}
|
||||
|
||||
static get grepCompatibleInputVersionRegex() {
|
||||
return '^v?([0-9]+\\.)*[0-9]+.*';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the branch name of the (related) branch
|
||||
*/
|
||||
static async getCurrentBranch() {
|
||||
// GitHub pull request, GitHub non pull request
|
||||
let branchName = this.headRef || this.ref?.slice(11);
|
||||
|
||||
// Local
|
||||
if (!branchName) {
|
||||
const { status, output } = await System.shellRun('git branch --show-current');
|
||||
if (!status.success) throw new Error('did not expect "git branch --show-current"');
|
||||
branchName = output;
|
||||
}
|
||||
|
||||
return branchName;
|
||||
}
|
||||
|
||||
/**
|
||||
* For pull requests we can reliably use GITHUB_HEAD_REF
|
||||
*/
|
||||
static get headRef() {
|
||||
return Deno.env.get('GITHUB_HEAD_REF');
|
||||
}
|
||||
|
||||
/**
|
||||
* For branches GITHUB_REF will have format `refs/heads/feature-branch-1`
|
||||
*/
|
||||
static get ref() {
|
||||
return Deno.env.get('GITHUB_REF');
|
||||
}
|
||||
|
||||
/**
|
||||
* The commit SHA that triggered the workflow run.
|
||||
*/
|
||||
static get sha() {
|
||||
return Deno.env.get('GITHUB_SHA');
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum number of lines to print when logging the git diff
|
||||
*/
|
||||
static get maxDiffLines() {
|
||||
return 60;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regex to parse version description into separate fields
|
||||
*/
|
||||
static get descriptionRegex1() {
|
||||
return /^v?([\d.]+)-(\d+)-g(\w+)-?(\w+)*/g;
|
||||
}
|
||||
|
||||
static get descriptionRegex2() {
|
||||
return /^v?([\d.]+-\w+)-(\d+)-g(\w+)-?(\w+)*/g;
|
||||
}
|
||||
|
||||
static get descriptionRegex3() {
|
||||
return /^v?([\d.]+-\w+\.\d+)-(\d+)-g(\w+)-?(\w+)*/g;
|
||||
}
|
||||
|
||||
static async determineBuildVersion(strategy: string, inputVersion: string, allowDirtyBuild: boolean) {
|
||||
// Validate input
|
||||
if (!Object.hasOwnProperty.call(this.strategies, strategy)) {
|
||||
throw new ValidationError(`Versioning strategy should be one of ${Object.values(this.strategies).join(', ')}.`);
|
||||
export default class BuildVersionGenerator {
|
||||
private readonly maxDiffLines: number = 60;
|
||||
private readonly projectPath: string;
|
||||
|
||||
constructor(projectPath, currentBranch) {
|
||||
this.projectPath = projectPath;
|
||||
this.currentBranch = currentBranch;
|
||||
}
|
||||
|
||||
public async determineBuildVersion(strategy: string, inputVersion: string, allowDirtyBuild: boolean) {
|
||||
log.info('Versioning strategy:', strategy);
|
||||
|
||||
let version;
|
||||
switch (strategy) {
|
||||
case this.strategies.None:
|
||||
case VersioningStrategy.None:
|
||||
version = 'none';
|
||||
break;
|
||||
case this.strategies.Custom:
|
||||
case VersioningStrategy.Custom:
|
||||
version = inputVersion;
|
||||
break;
|
||||
case this.strategies.Semantic:
|
||||
case VersioningStrategy.Semantic:
|
||||
version = await this.generateSemanticVersion(allowDirtyBuild);
|
||||
break;
|
||||
case this.strategies.Tag:
|
||||
case VersioningStrategy.Tag:
|
||||
version = await this.generateTagVersion();
|
||||
break;
|
||||
default:
|
||||
|
|
@ -108,6 +39,38 @@ export default class Versioning {
|
|||
return version;
|
||||
}
|
||||
|
||||
private get grepCompatibleInputVersionRegex() {
|
||||
return '^v?([0-9]+\\.)*[0-9]+.*';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the branch name of the (related) branch
|
||||
*/
|
||||
private async getCurrentBranch() {}
|
||||
|
||||
/**
|
||||
* The commit SHA that triggered the workflow run.
|
||||
* @deprecated
|
||||
*/
|
||||
private get sha() {
|
||||
return Deno.env.get('GITHUB_SHA');
|
||||
}
|
||||
|
||||
/**
|
||||
* Regex to parse version description into separate fields
|
||||
*/
|
||||
private get descriptionRegex1() {
|
||||
return /^v?([\d.]+)-(\d+)-g(\w+)-?(\w+)*/g;
|
||||
}
|
||||
|
||||
private get descriptionRegex2() {
|
||||
return /^v?([\d.]+-\w+)-(\d+)-g(\w+)-?(\w+)*/g;
|
||||
}
|
||||
|
||||
private get descriptionRegex3() {
|
||||
return /^v?([\d.]+-\w+\.\d+)-(\d+)-g(\w+)-?(\w+)*/g;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log up to maxDiffLines of the git diff.
|
||||
*/
|
||||
|
|
@ -128,13 +91,13 @@ export default class Versioning {
|
|||
*
|
||||
* @See: https://semver.org/
|
||||
*/
|
||||
static async generateSemanticVersion(allowDirtyBuild) {
|
||||
private async generateSemanticVersion(allowDirtyBuild) {
|
||||
if (await this.isShallow()) {
|
||||
await this.fetch();
|
||||
}
|
||||
|
||||
if ((await this.isDirty()) && !allowDirtyBuild) {
|
||||
await Versioning.logDiff();
|
||||
await BuildVersionGenerator.logDiff();
|
||||
throw new Error('Branch is dirty. Refusing to base semantic version on uncommitted changes');
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +131,7 @@ export default class Versioning {
|
|||
/**
|
||||
* Generate the proper version for unity based on an existing tag.
|
||||
*/
|
||||
static async generateTagVersion() {
|
||||
private async generateTagVersion() {
|
||||
let tag = await this.getTag();
|
||||
|
||||
if (tag.charAt(0) === 'v') {
|
||||
|
|
@ -181,7 +144,7 @@ export default class Versioning {
|
|||
/**
|
||||
* Parses the versionDescription into their named parts.
|
||||
*/
|
||||
static async parseSemanticVersion() {
|
||||
private async parseSemanticVersion() {
|
||||
const description = await this.getVersionDescription();
|
||||
|
||||
try {
|
||||
|
|
@ -225,7 +188,7 @@ export default class Versioning {
|
|||
/**
|
||||
* Returns whether the repository is shallow.
|
||||
*/
|
||||
static async isShallow() {
|
||||
private async isShallow() {
|
||||
const output = await this.git('rev-parse --is-shallow-repository');
|
||||
|
||||
return output !== 'false';
|
||||
|
|
@ -238,7 +201,7 @@ export default class Versioning {
|
|||
*
|
||||
* Note: `--all` should not be used, and would break fetching for push event.
|
||||
*/
|
||||
static async fetch() {
|
||||
private async fetch() {
|
||||
try {
|
||||
await this.git('fetch --unshallow');
|
||||
} catch {
|
||||
|
|
@ -255,7 +218,7 @@ export default class Versioning {
|
|||
* In this format v0.12 is the latest tag, 24 are the number of commits since, and gd2198ab
|
||||
* identifies the current commit.
|
||||
*/
|
||||
static async getVersionDescription() {
|
||||
private async getVersionDescription() {
|
||||
let commitIsh = '';
|
||||
|
||||
// In CI the repo is checked out in detached head mode.
|
||||
|
|
@ -271,7 +234,7 @@ export default class Versioning {
|
|||
/**
|
||||
* Returns whether there are uncommitted changes that are not ignored.
|
||||
*/
|
||||
static async isDirty() {
|
||||
private async isDirty() {
|
||||
const output = await this.git('status --porcelain');
|
||||
const isDirty = output !== '';
|
||||
|
||||
|
|
@ -288,7 +251,7 @@ export default class Versioning {
|
|||
/**
|
||||
* Get the tag if there is one pointing at HEAD
|
||||
*/
|
||||
static async getTag() {
|
||||
private async getTag() {
|
||||
return await this.git('tag --points-at HEAD');
|
||||
}
|
||||
|
||||
|
|
@ -297,7 +260,7 @@ export default class Versioning {
|
|||
*
|
||||
* Note: Currently this is run in all OSes, so the syntax must be cross-platform.
|
||||
*/
|
||||
static async hasAnyVersionTags() {
|
||||
private async hasAnyVersionTags() {
|
||||
const command = `git tag --list --merged HEAD | grep -E '${this.grepCompatibleInputVersionRegex}' | wc -l`;
|
||||
|
||||
// Todo - make sure this cwd is actually passed in somehow
|
||||
|
|
@ -318,7 +281,7 @@ export default class Versioning {
|
|||
*
|
||||
* Note: HEAD should not be used, as it may be detached, resulting in an additional count.
|
||||
*/
|
||||
static async getTotalNumberOfCommits() {
|
||||
private async getTotalNumberOfCommits() {
|
||||
const numberOfCommitsAsString = await this.git(`rev-list --count ${this.sha}`);
|
||||
|
||||
return Number.parseInt(numberOfCommitsAsString, 10);
|
||||
|
|
@ -327,7 +290,7 @@ export default class Versioning {
|
|||
/**
|
||||
* Run git in the specified project path
|
||||
*/
|
||||
static async git(arguments_, options = {}) {
|
||||
private async git(arguments_, options = {}) {
|
||||
const result = await System.run(`git ${arguments_}`, { cwd: this.projectPath, ...options });
|
||||
|
||||
log.warning(result);
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import BuildVersionGenerator from './build-version-generator.ts';
|
||||
import AndroidBuildVersionGenerator from './android-build-version-generator.ts';
|
||||
|
||||
export const buildVersioning = async (argv) => {
|
||||
const { projectPath, versioningStrategy, version, allowDirtyBuild, androidVersionCode, buildVersion } = argv;
|
||||
|
||||
const buildVersionGenerator = new BuildVersionGenerator(projectPath);
|
||||
|
||||
argv.buildVersion = await buildVersionGenerator.determineBuildVersion(versioningStrategy, version, allowDirtyBuild);
|
||||
|
||||
if (!androidVersionCode) {
|
||||
argv.androidVersionCode = AndroidBuildVersionGenerator.determineVersionCode(buildVersion);
|
||||
}
|
||||
};
|
||||
|
|
@ -1,15 +1,22 @@
|
|||
export class EngineDetector {
|
||||
private projectPath: string;
|
||||
import UnityVersionDetector from './unity-version-detector.ts';
|
||||
|
||||
constructor(subCommands: string[], args: string[]) {
|
||||
this.projectPath = subCommands[0] || args.projectPath || '.';
|
||||
export class EngineDetector {
|
||||
private readonly projectPath: string;
|
||||
|
||||
constructor(projectPath) {
|
||||
this.projectPath = projectPath;
|
||||
}
|
||||
|
||||
public async detect(): Promise<{ engine: string; engineVersion: string }> {
|
||||
// Todo - detect and return real versions
|
||||
if (UnityVersionDetector.isUnityProject(this.projectPath)) {
|
||||
const engineVersion = await UnityVersionDetector.getUnityVersion(this.projectPath);
|
||||
|
||||
return { engine: 'unity', engineVersion };
|
||||
}
|
||||
|
||||
return {
|
||||
engine: 'unity',
|
||||
engineVersion: '2020.1.0f1',
|
||||
engine: 'unknown',
|
||||
engineVersion: 'unknown',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,35 @@
|
|||
import UnityVersioning from './unity-versioning.ts';
|
||||
import UnityVersionDetector from './unity-version-detector.ts';
|
||||
|
||||
describe('Unity Versioning', () => {
|
||||
describe('parse', () => {
|
||||
it('throws for empty string', () => {
|
||||
expect(() => UnityVersioning.parse('')).toThrow(Error);
|
||||
expect(() => UnityVersionDetector.parse('')).toThrow(Error);
|
||||
});
|
||||
|
||||
it('parses from ProjectVersion.txt', () => {
|
||||
const projectVersionContents = `m_EditorVersion: 2019.2.11f1
|
||||
m_EditorVersionWithRevision: 2019.2.11f1 (5f859a4cfee5)`;
|
||||
expect(UnityVersioning.parse(projectVersionContents)).toBe('2019.2.11f1');
|
||||
expect(UnityVersionDetector.parse(projectVersionContents)).toBe('2019.2.11f1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('read', () => {
|
||||
it('throws for invalid path', () => {
|
||||
expect(() => UnityVersioning.read('')).toThrow(Error);
|
||||
expect(() => UnityVersionDetector.read('')).toThrow(Error);
|
||||
});
|
||||
|
||||
it('reads from test-project', () => {
|
||||
expect(UnityVersioning.read('./test-project')).toBe('2019.2.11f1');
|
||||
expect(UnityVersionDetector.read('./test-project')).toBe('2019.2.11f1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('determineUnityVersion', () => {
|
||||
it('defaults to parsed version', () => {
|
||||
expect(UnityVersioning.determineUnityVersion('./test-project', 'auto')).toBe('2019.2.11f1');
|
||||
expect(UnityVersionDetector.determineUnityVersion('./test-project', 'auto')).toBe('2019.2.11f1');
|
||||
});
|
||||
|
||||
it('use specified unityVersion', () => {
|
||||
expect(UnityVersioning.determineUnityVersion('./test-project', '1.2.3')).toBe('1.2.3');
|
||||
expect(UnityVersionDetector.determineUnityVersion('./test-project', '1.2.3')).toBe('1.2.3');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,16 +1,22 @@
|
|||
import { fsSync as fs, path } from '../dependencies.ts';
|
||||
import { fsSync as fs, path } from '../../dependencies.ts';
|
||||
|
||||
export default class UnityVersioning {
|
||||
export default class UnityVersionDetector {
|
||||
static get versionPattern() {
|
||||
return /20\d{2}\.\d\.\w{3,4}|3/;
|
||||
}
|
||||
|
||||
static determineUnityVersion(projectPath, unityVersion) {
|
||||
if (unityVersion === 'auto') {
|
||||
return UnityVersioning.read(projectPath);
|
||||
public static isUnityProject(projectPath) {
|
||||
try {
|
||||
UnityVersionDetector.read(projectPath);
|
||||
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return unityVersion;
|
||||
static getUnityVersion(projectPath) {
|
||||
return UnityVersionDetector.read(projectPath);
|
||||
}
|
||||
|
||||
static read(projectPath) {
|
||||
|
|
@ -19,11 +25,11 @@ export default class UnityVersioning {
|
|||
throw new Error(`Project settings file not found at "${filePath}". Have you correctly set the projectPath?`);
|
||||
}
|
||||
|
||||
return UnityVersioning.parse(Deno.readTextFileSync(filePath, 'utf8'));
|
||||
return UnityVersionDetector.parse(Deno.readTextFileSync(filePath, 'utf8'));
|
||||
}
|
||||
|
||||
static parse(projectVersionTxt) {
|
||||
const matches = projectVersionTxt.match(UnityVersioning.versionPattern);
|
||||
const matches = projectVersionTxt.match(UnityVersionDetector.versionPattern);
|
||||
if (!matches || matches.length === 0) {
|
||||
throw new Error(`Failed to parse version from "${projectVersionTxt}".`);
|
||||
}
|
||||
|
|
@ -17,4 +17,12 @@ export const configureLogger = async (argv) => {
|
|||
}
|
||||
|
||||
await createLoggerAndSetVerbosity(verbosity);
|
||||
|
||||
argv.logLevel = log.verbosity;
|
||||
argv.logLevelName = log.verbosityName;
|
||||
|
||||
argv.quiet = undefined;
|
||||
argv.verbose = undefined;
|
||||
argv.veryVerbose = undefined;
|
||||
argv.maxVerbose = undefined;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Import this named export into your test file:
|
||||
import Platform from '../platform.ts';
|
||||
import UnityTargetPlatform from '../unity/unity-target-platform.ts';
|
||||
|
||||
export const mockGetFromUser = jest.fn().mockResolvedValue({
|
||||
editorVersion: '',
|
||||
targetPlatform: Platform.types.Test,
|
||||
targetPlatform: UnityTargetPlatform.Test,
|
||||
projectPath: '.',
|
||||
buildName: Platform.types.Test,
|
||||
buildName: UnityTargetPlatform.Test,
|
||||
buildsPath: 'build',
|
||||
buildMethod: undefined,
|
||||
buildVersion: '1.3.37',
|
||||
|
|
|
|||
|
|
@ -1,41 +1,41 @@
|
|||
import AndroidVersioning from './android-versioning.ts';
|
||||
import AndroidBuildVersionGenerator from '../middleware/build-versioning/android-build-version-generator.ts';
|
||||
|
||||
describe('Android Versioning', () => {
|
||||
describe('versionToVersionCode', () => {
|
||||
it('defaults to 0 when versioning strategy is none', () => {
|
||||
expect(AndroidVersioning.versionToVersionCode('none')).toBe(0);
|
||||
expect(AndroidBuildVersionGenerator.versionToVersionCode('none')).toBe(0);
|
||||
});
|
||||
|
||||
it('defaults to 1 when version is not a valid semver', () => {
|
||||
expect(AndroidVersioning.versionToVersionCode('abcd')).toBe(1);
|
||||
expect(AndroidBuildVersionGenerator.versionToVersionCode('abcd')).toBe(1);
|
||||
});
|
||||
|
||||
it('returns a number', () => {
|
||||
expect(AndroidVersioning.versionToVersionCode('123.456.789')).toBe(123_456_789);
|
||||
expect(AndroidBuildVersionGenerator.versionToVersionCode('123.456.789')).toBe(123_456_789);
|
||||
});
|
||||
|
||||
it('throw when generated version code is too large', () => {
|
||||
expect(() => AndroidVersioning.versionToVersionCode('2050.0.0')).toThrow();
|
||||
expect(() => AndroidBuildVersionGenerator.versionToVersionCode('2050.0.0')).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('determineVersionCode', () => {
|
||||
it('defaults to parsed version', () => {
|
||||
expect(AndroidVersioning.determineVersionCode('1.2.3', '')).toBe(1_002_003);
|
||||
expect(AndroidBuildVersionGenerator.determineVersionCode('1.2.3', '')).toBe(1_002_003);
|
||||
});
|
||||
|
||||
it('use specified code', () => {
|
||||
expect(AndroidVersioning.determineVersionCode('1.2.3', 2)).toBe(2);
|
||||
expect(AndroidBuildVersionGenerator.determineVersionCode('1.2.3', 2)).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('determineSdkManagerParameters', () => {
|
||||
it('defaults to blank', () => {
|
||||
expect(AndroidVersioning.determineSdkManagerParameters('AndroidApiLevelAuto')).toBe('');
|
||||
expect(AndroidBuildVersionGenerator.determineSdkManagerParameters('AndroidApiLevelAuto')).toBe('');
|
||||
});
|
||||
|
||||
it('uses the specified api level', () => {
|
||||
expect(AndroidVersioning.determineSdkManagerParameters('AndroidApiLevel30')).toBe('platforms;android-30');
|
||||
expect(AndroidBuildVersionGenerator.determineSdkManagerParameters('AndroidApiLevel30')).toBe('platforms;android-30');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
import Versioning from './versioning.ts';
|
||||
import UnityVersioning from './unity-versioning.ts';
|
||||
import AndroidVersioning from './android-versioning.ts';
|
||||
import BuildVersionGenerator from '../middleware/build-versioning/build-version-generator.ts';
|
||||
import UnityVersionDetector from '../middleware/engine-detection/unity-version-detector.ts';
|
||||
import AndroidBuildVersionGenerator from '../middleware/build-versioning/android-build-version-generator.ts';
|
||||
import Parameters from './parameters.ts';
|
||||
import Input from './input.ts';
|
||||
import Platform from './platform.ts';
|
||||
import UnityTargetPlatform from './unity/unity-target-platform.ts';
|
||||
|
||||
// Todo - Don't use process.env directly, that's what the input model class is for.
|
||||
const testLicense =
|
||||
'<?xml version="1.0" encoding="UTF-8"?><root>\n <License id="Terms">\n <MachineBindings>\n <Binding Key="1" Value="576562626572264761624c65526f7578"/>\n <Binding Key="2" Value="576562626572264761624c65526f7578"/>\n </MachineBindings>\n <MachineID Value="D7nTUnjNAmtsUMcnoyrqkgIbYdM="/>\n <SerialHash Value="2033b8ac3e6faa3742ca9f0bfae44d18f2a96b80"/>\n <Features>\n <Feature Value="33"/>\n <Feature Value="1"/>\n <Feature Value="12"/>\n <Feature Value="2"/>\n <Feature Value="24"/>\n <Feature Value="3"/>\n <Feature Value="36"/>\n <Feature Value="17"/>\n <Feature Value="19"/>\n <Feature Value="62"/>\n </Features>\n <DeveloperData Value="AQAAAEY0LUJHUlgtWEQ0RS1aQ1dWLUM1SlctR0RIQg=="/>\n <SerialMasked Value="F4-BGRX-XD4E-ZCWV-C5JW-XXXX"/>\n <StartDate Value="2021-02-08T00:00:00"/>\n <UpdateDate Value="2021-02-09T00:34:57"/>\n <InitialActivationDate Value="2021-02-08T00:34:56"/>\n <LicenseVersion Value="6.x"/>\n <ClientProvidedVersion Value="2018.4.30f1"/>\n <AlwaysOnline Value="false"/>\n <Entitlements>\n <Entitlement Ns="unity_editor" Tag="UnityPersonal" Type="EDITOR" ValidTo="9999-12-31T00:00:00"/>\n <Entitlement Ns="unity_editor" Tag="DarkSkin" Type="EDITOR_FEATURE" ValidTo="9999-12-31T00:00:00"/>\n </Entitlements>\n </License>\n<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI="#Terms"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>m0Db8UK+ktnOLJBtHybkfetpcKo=</DigestValue></Reference></SignedInfo><SignatureValue>o/pUbSQAukz7+ZYAWhnA0AJbIlyyCPL7bKVEM2lVqbrXt7cyey+umkCXamuOgsWPVUKBMkXtMH8L\n5etLmD0getWIhTGhzOnDCk+gtIPfL4jMo9tkEuOCROQAXCci23VFscKcrkB+3X6h4wEOtA2APhOY\nB+wvC794o8/82ffjP79aVAi57rp3Wmzx+9pe9yMwoJuljAy2sc2tIMgdQGWVmOGBpQm3JqsidyzI\nJWG2kjnc7pDXK9pwYzXoKiqUqqrut90d+kQqRyv7MSZXR50HFqD/LI69h68b7P8Bjo3bPXOhNXGR\n9YCoemH6EkfCJxp2gIjzjWW+l2Hj2EsFQi8YXw==</SignatureValue></Signature></root>';
|
||||
Deno.env.set('UNITY_LICENSE', testLicense);
|
||||
|
||||
const determineVersion = jest.spyOn(Versioning, 'determineBuildVersion').mockImplementation(async () => '1.3.37');
|
||||
const determineVersion = jest.spyOn(BuildVersionGenerator, 'determineBuildVersion').mockImplementation(async () => '1.3.37');
|
||||
const determineUnityVersion = jest
|
||||
.spyOn(UnityVersioning, 'determineUnityVersion')
|
||||
.spyOn(UnityVersionDetector, 'determineUnityVersion')
|
||||
.mockImplementation(() => '2019.2.11f1');
|
||||
const determineSdkManagerParameters = jest
|
||||
.spyOn(AndroidVersioning, 'determineSdkManagerParameters')
|
||||
.spyOn(AndroidBuildVersionGenerator, 'determineSdkManagerParameters')
|
||||
.mockImplementation(() => 'platforms;android-30');
|
||||
|
||||
afterEach(() => {
|
||||
|
|
@ -88,7 +88,7 @@ describe('BuildParameters', () => {
|
|||
expect(Parameters.create()).resolves.toEqual(expect.objectContaining({ buildFile: mockValue }));
|
||||
});
|
||||
|
||||
test.each([Platform.types.StandaloneWindows, Platform.types.StandaloneWindows64])(
|
||||
test.each([UnityTargetPlatform.StandaloneWindows, UnityTargetPlatform.StandaloneWindows64])(
|
||||
'appends exe for %s',
|
||||
async (targetPlatform) => {
|
||||
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
|
||||
|
|
@ -97,14 +97,14 @@ describe('BuildParameters', () => {
|
|||
},
|
||||
);
|
||||
|
||||
test.each([Platform.types.Android])('appends apk for %s', async (targetPlatform) => {
|
||||
test.each([UnityTargetPlatform.Android])('appends apk for %s', async (targetPlatform) => {
|
||||
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
|
||||
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
|
||||
jest.spyOn(Input, 'androidAppBundle', 'get').mockReturnValue(false);
|
||||
expect(Parameters.create()).resolves.toEqual(expect.objectContaining({ buildFile: `${targetPlatform}.apk` }));
|
||||
});
|
||||
|
||||
test.each([Platform.types.Android])('appends aab for %s', async (targetPlatform) => {
|
||||
test.each([UnityTargetPlatform.Android])('appends aab for %s', async (targetPlatform) => {
|
||||
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
|
||||
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
|
||||
jest.spyOn(Input, 'androidAppBundle', 'get').mockReturnValue(true);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import CloudRunner from './cloud-runner.ts';
|
|||
import Input from '../input.ts';
|
||||
import { CloudRunnerStatics } from './cloud-runner-statics.ts';
|
||||
import { TaskParameterSerializer } from './services/task-parameter-serializer.ts';
|
||||
import UnityVersioning from '../unity-versioning.ts';
|
||||
import UnityVersionDetector from '../../middleware/engine-detection/unity-version-detector.ts';
|
||||
import { Cli } from '../cli/cli.ts';
|
||||
import CloudRunnerLogger from './services/cloud-runner-logger.ts';
|
||||
import { v4 as uuidv4 } from '../../../node_modules/uuid';
|
||||
|
|
@ -20,7 +20,7 @@ describe('Cloud Runner', () => {
|
|||
Cli.options = {
|
||||
versioning: 'None',
|
||||
projectPath: 'test-project',
|
||||
unityVersion: UnityVersioning.read('test-project'),
|
||||
engineVersion: UnityVersionDetector.read('test-project'),
|
||||
targetPlatform: 'StandaloneLinux64',
|
||||
customJob: `
|
||||
- name: 'step 1'
|
||||
|
|
@ -68,7 +68,7 @@ describe('Cloud Runner', () => {
|
|||
Cli.options = {
|
||||
versioning: 'None',
|
||||
projectPath: 'test-project',
|
||||
unityVersion: UnityVersioning.determineUnityVersion('test-project', UnityVersioning.read('test-project')),
|
||||
engineVersion: UnityVersionDetector.determineUnityVersion('test-project', UnityVersionDetector.read('test-project')),
|
||||
targetPlatform: 'StandaloneLinux64',
|
||||
cacheKey: `test-case-${uuidv4()}`,
|
||||
};
|
||||
|
|
@ -96,7 +96,7 @@ describe('Cloud Runner', () => {
|
|||
Cli.options = {
|
||||
versioning: 'None',
|
||||
projectPath: 'test-project',
|
||||
unityVersion: UnityVersioning.read('test-project'),
|
||||
engineVersion: UnityVersionDetector.read('test-project'),
|
||||
cloudRunnerCluster: 'local-system',
|
||||
targetPlatform: 'StandaloneLinux64',
|
||||
customJob: `
|
||||
|
|
@ -124,7 +124,7 @@ describe('Cloud Runner', () => {
|
|||
Cli.options = {
|
||||
versioning: 'None',
|
||||
projectPath: 'test-project',
|
||||
unityVersion: UnityVersioning.read('test-project'),
|
||||
engineVersion: UnityVersionDetector.read('test-project'),
|
||||
cloudRunnerCluster: 'test',
|
||||
targetPlatform: 'StandaloneLinux64',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { fs, uuid, path, __dirname } from '../../../dependencies.ts';
|
|||
import Parameters from '../../parameters.ts';
|
||||
import { Cli } from '../../cli/cli.ts';
|
||||
import Input from '../../input.ts';
|
||||
import UnityVersioning from '../../unity-versioning.ts';
|
||||
import UnityVersionDetector from '../../../middleware/engine-detection/unity-version-detector.ts';
|
||||
import CloudRunner from '../cloud-runner.ts';
|
||||
import { CloudRunnerSystem } from '../services/cloud-runner-system/index.ts';
|
||||
import { Caching } from './caching.ts';
|
||||
|
|
@ -16,7 +16,7 @@ describe('Cloud Runner Caching', () => {
|
|||
Cli.options = {
|
||||
versioning: 'None',
|
||||
projectPath: 'test-project',
|
||||
unityVersion: UnityVersioning.read('test-project'),
|
||||
engineVersion: UnityVersionDetector.read('test-project'),
|
||||
targetPlatform: 'StandaloneLinux64',
|
||||
cacheKey: `test-case-${uuid()}`,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import ImageEnvironmentFactory from './image-environment-factory.ts';
|
||||
import { path, fsSync as fs } from '../dependencies.ts';
|
||||
import System from './system.ts';
|
||||
import System from './system/system.ts';
|
||||
|
||||
class Docker {
|
||||
static async run(image, parameters) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import Platform from './platform.ts';
|
||||
import UnityTargetPlatform from './unity/unity-target-platform.ts';
|
||||
|
||||
import Parameters from './parameters.ts';
|
||||
|
||||
|
|
@ -78,10 +78,10 @@ class ImageTag {
|
|||
|
||||
// @see: https://docs.unity3d.com/ScriptReference/BuildTarget.html
|
||||
switch (platform) {
|
||||
case Platform.types.StandaloneOSX:
|
||||
case UnityTargetPlatform.StandaloneOSX:
|
||||
return mac;
|
||||
case Platform.types.StandaloneWindows:
|
||||
case Platform.types.StandaloneWindows64:
|
||||
case UnityTargetPlatform.StandaloneWindows:
|
||||
case UnityTargetPlatform.StandaloneWindows64:
|
||||
// Can only build windows-il2cpp on a windows based system
|
||||
if (process.platform === 'win32') {
|
||||
// Unity versions before 2019.3 do not support il2cpp
|
||||
|
|
@ -94,7 +94,7 @@ class ImageTag {
|
|||
}
|
||||
|
||||
return windows;
|
||||
case Platform.types.StandaloneLinux64: {
|
||||
case UnityTargetPlatform.StandaloneLinux64: {
|
||||
// Unity versions before 2019.3 do not support il2cpp
|
||||
if (major >= 2020 || (major === 2019 && minor >= 3)) {
|
||||
return linuxIl2cpp;
|
||||
|
|
@ -102,45 +102,45 @@ class ImageTag {
|
|||
|
||||
return linux;
|
||||
}
|
||||
case Platform.types.iOS:
|
||||
case UnityTargetPlatform.iOS:
|
||||
return ios;
|
||||
case Platform.types.Android:
|
||||
case UnityTargetPlatform.Android:
|
||||
return android;
|
||||
case Platform.types.WebGL:
|
||||
case UnityTargetPlatform.WebGL:
|
||||
return webgl;
|
||||
case Platform.types.WSAPlayer:
|
||||
case UnityTargetPlatform.WSAPlayer:
|
||||
if (process.platform !== 'win32') {
|
||||
throw new Error(`WSAPlayer can only be built on a windows base OS`);
|
||||
}
|
||||
|
||||
return wsaPlayer;
|
||||
case Platform.types.PS4:
|
||||
case UnityTargetPlatform.PS4:
|
||||
return windows;
|
||||
case Platform.types.XboxOne:
|
||||
case UnityTargetPlatform.XboxOne:
|
||||
return windows;
|
||||
case Platform.types.tvOS:
|
||||
case UnityTargetPlatform.tvOS:
|
||||
if (process.platform !== 'win32') {
|
||||
throw new Error(`tvOS can only be built on a windows base OS`);
|
||||
}
|
||||
|
||||
return tvos;
|
||||
case Platform.types.Switch:
|
||||
case UnityTargetPlatform.Switch:
|
||||
return windows;
|
||||
|
||||
// Unsupported
|
||||
case Platform.types.Lumin:
|
||||
case UnityTargetPlatform.Lumin:
|
||||
return windows;
|
||||
case Platform.types.BJM:
|
||||
case UnityTargetPlatform.BJM:
|
||||
return windows;
|
||||
case Platform.types.Stadia:
|
||||
case UnityTargetPlatform.Stadia:
|
||||
return windows;
|
||||
case Platform.types.Facebook:
|
||||
case UnityTargetPlatform.Facebook:
|
||||
return facebook;
|
||||
case Platform.types.NoTarget:
|
||||
case UnityTargetPlatform.NoTarget:
|
||||
return generic;
|
||||
|
||||
// Test specific
|
||||
case Platform.types.Test:
|
||||
case UnityTargetPlatform.Test:
|
||||
return generic;
|
||||
default:
|
||||
throw new Error(`
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import Docker from './docker.ts';
|
|||
import Input from './input.ts';
|
||||
import ImageTag from './image-tag.ts';
|
||||
import Output from './output.ts';
|
||||
import Platform from './platform.ts';
|
||||
import UnityTargetPlatform from './unity/unity-target-platform.ts';
|
||||
import Project from './project.ts';
|
||||
import Unity from './unity.ts';
|
||||
import Versioning from './versioning.ts';
|
||||
import Unity from './unity/unity.ts';
|
||||
import BuildVersionGenerator from '../middleware/build-versioning/build-version-generator.ts';
|
||||
import CloudRunner from './cloud-runner/cloud-runner.ts';
|
||||
|
||||
export {
|
||||
|
|
@ -19,9 +19,9 @@ export {
|
|||
Input,
|
||||
ImageTag,
|
||||
Output,
|
||||
Platform,
|
||||
UnityTargetPlatform,
|
||||
Project,
|
||||
Unity,
|
||||
Versioning,
|
||||
BuildVersionGenerator,
|
||||
CloudRunner,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
import { core } from '../dependencies.ts';
|
||||
|
||||
import Input from './input.ts';
|
||||
import Platform from './platform.ts';
|
||||
import UnityTargetPlatform from './unity/unity-target-platform.ts';
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('Input', () => {
|
||||
describe('unityVersion', () => {
|
||||
describe('engineVersion', () => {
|
||||
it('returns the default value', () => {
|
||||
expect(Input.unityVersion).toStrictEqual('auto');
|
||||
expect(Input.engineVersion).toStrictEqual('auto');
|
||||
});
|
||||
|
||||
it('takes input from the users workflow', () => {
|
||||
const mockValue = '2020.4.99f9';
|
||||
const spy = jest.spyOn(core, 'getInput').mockReturnValue(mockValue);
|
||||
expect(Input.unityVersion).toStrictEqual(mockValue);
|
||||
expect(Input.engineVersion).toStrictEqual(mockValue);
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
@ -35,7 +35,7 @@ describe('Input', () => {
|
|||
|
||||
describe('targetPlatform', () => {
|
||||
it('returns the default value', () => {
|
||||
expect(Input.targetPlatform).toStrictEqual(Platform.default);
|
||||
expect(Input.targetPlatform).toStrictEqual(UnityTargetPlatform.default);
|
||||
});
|
||||
|
||||
it('takes input from the users workflow', () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { fsSync as fs, path, core } from '../dependencies.ts';
|
||||
import { Cli } from './cli/cli.ts';
|
||||
import CloudRunnerQueryOverride from './cloud-runner/services/cloud-runner-query-override.ts';
|
||||
import Platform from './platform.ts';
|
||||
import { CliArguments } from '../core/cli/cli-arguments.ts';
|
||||
|
||||
/**
|
||||
|
|
@ -102,42 +101,10 @@ class Input {
|
|||
return this.get('GITHUB_RUN_NUMBER') || '0';
|
||||
}
|
||||
|
||||
public get targetPlatform() {
|
||||
return this.get('targetPlatform') || Platform.default;
|
||||
}
|
||||
|
||||
public get unityVersion() {
|
||||
return this.get('unityVersion') || 'auto';
|
||||
}
|
||||
|
||||
public get unityEmail() {
|
||||
return this.get('unityEmail') || '';
|
||||
}
|
||||
|
||||
public get unityPassword() {
|
||||
return this.get('unityPassword') || '';
|
||||
}
|
||||
|
||||
public get unityLicense() {
|
||||
return this.get('unityLicense') || '';
|
||||
}
|
||||
|
||||
public get unityLicenseFile() {
|
||||
return this.get('unityLicenseFile') || '';
|
||||
}
|
||||
|
||||
public get unitySerial() {
|
||||
return this.get('unitySerial') || '';
|
||||
}
|
||||
|
||||
public get usymUploadAuthToken() {
|
||||
return this.get('usymUploadAuthToken') || '';
|
||||
}
|
||||
|
||||
public get customImage() {
|
||||
return this.get('customImage') || '';
|
||||
}
|
||||
|
||||
public get projectPath() {
|
||||
let input = this.get('projectPath');
|
||||
|
||||
|
|
@ -156,10 +123,6 @@ class Input {
|
|||
return this.get('buildName');
|
||||
}
|
||||
|
||||
public get buildsPath() {
|
||||
return this.get('buildsPath') || 'build';
|
||||
}
|
||||
|
||||
public get buildMethod() {
|
||||
return this.get('buildMethod') || ''; // Processed in docker file
|
||||
}
|
||||
|
|
@ -168,14 +131,6 @@ class Input {
|
|||
return this.get('customParameters') || '';
|
||||
}
|
||||
|
||||
public get versioningStrategy() {
|
||||
return this.get('versioning') || 'Semantic';
|
||||
}
|
||||
|
||||
public get specifiedVersion() {
|
||||
return this.get('version') || '';
|
||||
}
|
||||
|
||||
public get androidVersionCode() {
|
||||
return this.get('androidVersionCode');
|
||||
}
|
||||
|
|
@ -250,13 +205,6 @@ class Input {
|
|||
return this.get('chownFilesTo') || '';
|
||||
}
|
||||
|
||||
public get allowDirtyBuild() {
|
||||
const input = this.get('allowDirtyBuild');
|
||||
log.debug('input === ', input);
|
||||
|
||||
return input || false === true;
|
||||
}
|
||||
|
||||
public get postBuildSteps() {
|
||||
return this.get('postBuildSteps') || '';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Parameters } from './parameters.ts';
|
||||
import System from './system.ts';
|
||||
import System from './system/system.ts';
|
||||
|
||||
class MacBuilder {
|
||||
public static async run(actionFolder) {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { default as getHomeDir } from 'https://deno.land/x/dir@1.5.1/home_dir/mod.ts';
|
||||
import AndroidVersioning from './android-versioning.ts';
|
||||
import AndroidBuildVersionGenerator from '../middleware/build-versioning/android-build-version-generator.ts';
|
||||
import Input from './input.ts';
|
||||
import Platform from './platform.ts';
|
||||
import UnityVersioning from './unity-versioning.ts';
|
||||
import Versioning from './versioning.ts';
|
||||
import UnityTargetPlatform from './unity/unity-target-platform.ts';
|
||||
import UnityVersionDetector from '../middleware/engine-detection/unity-version-detector.ts';
|
||||
import BuildVersionGenerator from '../middleware/build-versioning/build-version-generator.ts';
|
||||
import { GitRepoReader } from './input-readers/git-repo.ts';
|
||||
import { CommandInterface } from '../command/command-interface.ts';
|
||||
import { Environment } from '../core/env/environment.ts';
|
||||
|
|
@ -94,39 +94,13 @@ class Parameters {
|
|||
}
|
||||
|
||||
public async parse(): Promise<Parameters> {
|
||||
const cliStoragePath = `${getHomeDir()}/.game-ci`;
|
||||
const targetPlatform = this.input.get('targetPlatform');
|
||||
const buildsPath = this.input.get('buildsPath');
|
||||
const projectPath = this.get('projectPath');
|
||||
const unityVersion = this.get('unityVersion');
|
||||
const versioningStrategy = this.get('versioningStrategy');
|
||||
const specifiedVersion = this.get('specifiedVersion');
|
||||
const allowDirtyBuild = this.get('allowDirtyBuild');
|
||||
const androidTargetSdkVersion = this.get('androidTargetSdkVersion');
|
||||
|
||||
const buildName = this.input.get('buildName') || targetPlatform;
|
||||
const buildFile = Parameters.parseBuildFile(buildName, targetPlatform, this.get('androidAppBundle'));
|
||||
const buildPath = `${buildsPath}/${targetPlatform}`;
|
||||
const editorVersion = UnityVersioning.determineUnityVersion(projectPath, unityVersion);
|
||||
const buildVersion = await Versioning.determineBuildVersion(versioningStrategy, specifiedVersion, allowDirtyBuild);
|
||||
const androidVersionCode = AndroidVersioning.determineVersionCode(buildVersion, this.get('androidVersionCode'));
|
||||
const androidSdkManagerParameters = AndroidVersioning.determineSdkManagerParameters(androidTargetSdkVersion);
|
||||
const branch = (await Versioning.getCurrentBranch()) || (await GitRepoReader.GetBranch());
|
||||
const branch = (await BuildVersionGenerator.getCurrentBranch()) || (await GitRepoReader.GetBranch());
|
||||
|
||||
const parameters = {
|
||||
branch,
|
||||
unityEmail: this.get('unityEmail'),
|
||||
unityPassword: this.get('unityPassword'),
|
||||
unityLicense: this.get('unityLicense'),
|
||||
unityLicenseFile: this.get('unityLicenseFile'),
|
||||
unitySerial: this.getUnitySerial(),
|
||||
cliStoragePath,
|
||||
editorVersion,
|
||||
customImage: this.get('customImage'),
|
||||
usymUploadAuthToken: this.get('usymUploadAuthToken'),
|
||||
editorVersion: engineVersion,
|
||||
runnerTempPath: this.env.get('RUNNER_TEMP'),
|
||||
targetPlatform,
|
||||
projectPath,
|
||||
buildName,
|
||||
buildPath,
|
||||
buildFile,
|
||||
|
|
@ -156,18 +130,6 @@ class Parameters {
|
|||
};
|
||||
}
|
||||
|
||||
static parseBuildFile(filename, platform, androidAppBundle) {
|
||||
if (Platform.isWindows(platform)) {
|
||||
return `${filename}.exe`;
|
||||
}
|
||||
|
||||
if (Platform.isAndroid(platform)) {
|
||||
return androidAppBundle ? `${filename}.aab` : `${filename}.apk`;
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
private getUnitySerial() {
|
||||
let unitySerial = this.get('unitySerial');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
import Platform from './platform.ts';
|
||||
|
||||
describe('Platform', () => {
|
||||
describe('default', () => {
|
||||
it('does not throw', () => {
|
||||
expect(() => Platform.default).not.toThrow();
|
||||
});
|
||||
|
||||
it('returns a string', () => {
|
||||
expect(typeof Platform.default).toStrictEqual('string');
|
||||
});
|
||||
|
||||
it('returns a platform', () => {
|
||||
expect(Object.values(Platform.types)).toContain(Platform.default);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isWindows', () => {
|
||||
it('returns true for windows', () => {
|
||||
expect(Platform.isWindows(Platform.types.StandaloneWindows64)).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('returns false for MacOS', () => {
|
||||
expect(Platform.isWindows(Platform.types.StandaloneOSX)).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAndroid', () => {
|
||||
it('returns true for Android', () => {
|
||||
expect(Platform.isAndroid(Platform.types.Android)).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('returns false for Windows', () => {
|
||||
expect(Platform.isAndroid(Platform.types.StandaloneWindows64)).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
class Platform {
|
||||
static get default() {
|
||||
return Platform.types.StandaloneWindows64;
|
||||
}
|
||||
|
||||
static get types() {
|
||||
return {
|
||||
StandaloneOSX: 'StandaloneOSX',
|
||||
StandaloneWindows: 'StandaloneWindows',
|
||||
StandaloneWindows64: 'StandaloneWindows64',
|
||||
StandaloneLinux64: 'StandaloneLinux64',
|
||||
iOS: 'iOS',
|
||||
Android: 'Android',
|
||||
WebGL: 'WebGL',
|
||||
WSAPlayer: 'WSAPlayer',
|
||||
PS4: 'PS4',
|
||||
XboxOne: 'XboxOne',
|
||||
tvOS: 'tvOS',
|
||||
Switch: 'Switch',
|
||||
|
||||
// Unsupported
|
||||
Lumin: 'Lumin',
|
||||
BJM: 'BJM',
|
||||
Stadia: 'Stadia',
|
||||
Facebook: 'Facebook',
|
||||
NoTarget: 'NoTarget',
|
||||
|
||||
// Test specific
|
||||
Test: 'Test',
|
||||
};
|
||||
}
|
||||
|
||||
static isWindows(platform) {
|
||||
switch (platform) {
|
||||
case Platform.types.StandaloneWindows:
|
||||
case Platform.types.StandaloneWindows64:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static isAndroid(platform) {
|
||||
switch (platform) {
|
||||
case Platform.types.Android:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Platform;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import Input from './input.ts';
|
||||
import Unity from './unity.ts';
|
||||
import Unity from './unity/unity.ts';
|
||||
import Action from './action.ts';
|
||||
|
||||
class Project {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
export interface RunOptions {
|
||||
pwd: string;
|
||||
cwd: string;
|
||||
attach: boolean;
|
||||
}
|
||||
|
||||
|
|
@ -14,12 +14,7 @@ class System {
|
|||
*
|
||||
* @throws {Error} if anything was output to stderr.
|
||||
*/
|
||||
static async run(rawCommand: string, options: RunOptions = {}): Promise<string> {
|
||||
const { pwd } = options;
|
||||
|
||||
let command = rawCommand;
|
||||
if (pwd) command = `cd ${pwd} ; ${command}`;
|
||||
|
||||
static async run(command: string, options: RunOptions = {}): Promise<string> {
|
||||
const isWindows = Deno.build.os === 'windows';
|
||||
const shellMethod = isWindows ? System.powershellRun : System.shellRun;
|
||||
|
||||
|
|
@ -28,14 +23,20 @@ class System {
|
|||
return shellMethod(command, options);
|
||||
}
|
||||
|
||||
static async shellRun(command: string, options: RunOptions = {}): Promise<string> {
|
||||
const { attach } = options;
|
||||
static async shellRun(rawCommand: string, options: RunOptions = {}): Promise<string> {
|
||||
const { attach, cwd } = options;
|
||||
|
||||
let command = rawCommand;
|
||||
if (cwd) command = `cd ${cwd} ; ${command}`;
|
||||
|
||||
return attach ? System.runAndAttach('sh', ['-c', command]) : System.runAndCapture('sh', ['-c', command]);
|
||||
}
|
||||
|
||||
static async powershellRun(command: string, options: RunOptions = {}): Promise<string> {
|
||||
const { attach } = options;
|
||||
static async powershellRun(rawCommand: string, options: RunOptions = {}): Promise<string> {
|
||||
const { attach, cwd } = options;
|
||||
|
||||
let command = rawCommand;
|
||||
if (cwd) command = `cd ${cwd} ; ${command}`;
|
||||
|
||||
return attach ? System.runAndAttach('powershell', [command]) : System.runAndCapture('powershell', [command]);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
class Unity {
|
||||
static get libraryFolder() {
|
||||
return 'Library';
|
||||
}
|
||||
}
|
||||
|
||||
export default Unity;
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
import UnityTargetPlatform from './unity-target-platform.ts';
|
||||
|
||||
describe('UnityTargetPlatform', () => {
|
||||
describe('default', () => {
|
||||
it('does not throw', () => {
|
||||
expect(() => UnityTargetPlatform.default).not.toThrow();
|
||||
});
|
||||
|
||||
it('returns a string', () => {
|
||||
expect(typeof UnityTargetPlatform.default).toStrictEqual('string');
|
||||
});
|
||||
|
||||
it('returns a platform', () => {
|
||||
expect(Object.values(UnityTargetPlatform.types)).toContain(UnityTargetPlatform.default);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isWindows', () => {
|
||||
it('returns true for windows', () => {
|
||||
expect(UnityTargetPlatform.isWindows(UnityTargetPlatform.StandaloneWindows64)).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('returns false for MacOS', () => {
|
||||
expect(UnityTargetPlatform.isWindows(UnityTargetPlatform.StandaloneOSX)).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAndroid', () => {
|
||||
it('returns true for Android', () => {
|
||||
expect(UnityTargetPlatform.isAndroid(UnityTargetPlatform.Android)).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('returns false for Windows', () => {
|
||||
expect(UnityTargetPlatform.isAndroid(UnityTargetPlatform.StandaloneWindows64)).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
class UnityTargetPlatform {
|
||||
public static readonly Android = 'Android';
|
||||
public static readonly iOS = 'iOS';
|
||||
public static readonly StandaloneLinux64 = 'StandaloneLinux64';
|
||||
public static readonly StandaloneOSX = 'StandaloneOSX';
|
||||
public static readonly StandaloneWindows = 'StandaloneWindows';
|
||||
public static readonly StandaloneWindows64 = 'StandaloneWindows64';
|
||||
public static readonly Switch = 'Switch';
|
||||
public static readonly tvOS = 'tvOS';
|
||||
public static readonly WebGL = 'WebGL';
|
||||
public static readonly WSAPlayer = 'WSAPlayer';
|
||||
public static readonly XboxOne = 'XboxOne';
|
||||
|
||||
// Unsupported
|
||||
public static readonly Lumin = 'Lumin';
|
||||
public static readonly BJM = 'BJM';
|
||||
public static readonly Stadia = 'Stadia';
|
||||
public static readonly Facebook = 'Facebook';
|
||||
public static readonly NoTarget = 'NoTarget';
|
||||
|
||||
// Test specific
|
||||
public static readonly Test = 'Test';
|
||||
|
||||
static get default() {
|
||||
return UnityTargetPlatform.StandaloneWindows64;
|
||||
}
|
||||
|
||||
static isWindows(platform) {
|
||||
switch (platform) {
|
||||
case UnityTargetPlatform.StandaloneWindows:
|
||||
case UnityTargetPlatform.StandaloneWindows64:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static isAndroid(platform) {
|
||||
switch (platform) {
|
||||
case UnityTargetPlatform.Android:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default UnityTargetPlatform;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { UnityTargetPlatform } from '../index.ts';
|
||||
|
||||
export class UnityTargetPlatforms {
|
||||
public static readonly all = [
|
||||
UnityTargetPlatform.Android,
|
||||
UnityTargetPlatform.iOS,
|
||||
UnityTargetPlatform.StandaloneLinux64,
|
||||
UnityTargetPlatform.StandaloneOSX,
|
||||
UnityTargetPlatform.StandaloneWindows,
|
||||
UnityTargetPlatform.StandaloneWindows64,
|
||||
UnityTargetPlatform.Switch,
|
||||
UnityTargetPlatform.tvOS,
|
||||
UnityTargetPlatform.WebGL,
|
||||
UnityTargetPlatform.WSAPlayer,
|
||||
UnityTargetPlatform.XboxOne,
|
||||
|
||||
// Unsupported
|
||||
UnityTargetPlatform.Lumin,
|
||||
UnityTargetPlatform.BJM,
|
||||
UnityTargetPlatform.Stadia,
|
||||
UnityTargetPlatform.Facebook,
|
||||
UnityTargetPlatform.NoTarget,
|
||||
|
||||
// Test specific
|
||||
UnityTargetPlatform.Test,
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import UnityTargetPlatform from './unity-target-platform.ts';
|
||||
|
||||
class Unity {
|
||||
static get libraryFolder() {
|
||||
return 'Library';
|
||||
}
|
||||
|
||||
static determineBuildFileName(buildName, platform, androidAppBundle) {
|
||||
if (UnityTargetPlatform.isWindows(platform)) {
|
||||
return `${buildName}.exe`;
|
||||
}
|
||||
|
||||
if (UnityTargetPlatform.isAndroid(platform)) {
|
||||
return androidAppBundle ? `${buildName}.aab` : `${buildName}.apk`;
|
||||
}
|
||||
|
||||
return buildName;
|
||||
}
|
||||
}
|
||||
|
||||
export default Unity;
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import { VersioningStrategy } from './versioning-strategy.ts';
|
||||
|
||||
export class VersioningStrategies {
|
||||
public static get all() {
|
||||
return [VersioningStrategy.None, VersioningStrategy.Semantic, VersioningStrategy.Tag, VersioningStrategy.Custom];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
export class VersioningStrategy {
|
||||
public static None: 'None';
|
||||
public static Semantic: 'Semantic';
|
||||
public static Tag: 'Tag';
|
||||
public static Custom: 'Custom';
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import { core } from '../../dependencies.ts';
|
||||
import NotImplementedException from './error/not-implemented-exception.ts';
|
||||
import System from './system.ts';
|
||||
import Versioning from './versioning.ts';
|
||||
import { validVersionTagInputs, invalidVersionTagInputs } from './__data__/versions.ts';
|
||||
import NotImplementedException from '../error/not-implemented-exception.ts';
|
||||
import System from '../system/system.ts';
|
||||
import BuildVersionGenerator from '../../middleware/build-versioning/build-version-generator.ts';
|
||||
import { validVersionTagInputs, invalidVersionTagInputs } from '../__data__/versions.ts';
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
|
|
@ -11,27 +11,27 @@ afterEach(() => {
|
|||
describe('Versioning', () => {
|
||||
describe('strategies', () => {
|
||||
it('returns an object', () => {
|
||||
expect(typeof Versioning.strategies).toStrictEqual('object');
|
||||
expect(typeof BuildVersionGenerator.strategies).toStrictEqual('object');
|
||||
});
|
||||
|
||||
it('has items', () => {
|
||||
expect(Object.values(Versioning.strategies).length).toBeGreaterThan(2);
|
||||
expect(Object.values(BuildVersionGenerator.strategies).length).toBeGreaterThan(2);
|
||||
});
|
||||
|
||||
it('has an opt out option', () => {
|
||||
expect(Versioning.strategies).toHaveProperty('None');
|
||||
expect(BuildVersionGenerator.strategies).toHaveProperty('None');
|
||||
});
|
||||
|
||||
it('has the semantic option', () => {
|
||||
expect(Versioning.strategies).toHaveProperty('Semantic');
|
||||
expect(BuildVersionGenerator.strategies).toHaveProperty('Semantic');
|
||||
});
|
||||
|
||||
it('has a strategy for tags', () => {
|
||||
expect(Versioning.strategies).toHaveProperty('Tag');
|
||||
expect(BuildVersionGenerator.strategies).toHaveProperty('Tag');
|
||||
});
|
||||
|
||||
it('has an option that allows custom input', () => {
|
||||
expect(Versioning.strategies).toHaveProperty('Custom');
|
||||
expect(BuildVersionGenerator.strategies).toHaveProperty('Custom');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ describe('Versioning', () => {
|
|||
// eslint-disable-next-line unicorn/consistent-function-scoping
|
||||
const matchInputUsingGrep = async (input) => {
|
||||
const output = await System.run('sh', undefined, {
|
||||
input: Buffer.from(`echo '${input}' | grep -E '${Versioning.grepCompatibleInputVersionRegex}'`),
|
||||
input: Buffer.from(`echo '${input}' | grep -E '${BuildVersionGenerator.grepCompatibleInputVersionRegex}'`),
|
||||
silent: true,
|
||||
});
|
||||
|
||||
|
|
@ -57,34 +57,34 @@ describe('Versioning', () => {
|
|||
|
||||
describe('branch', () => {
|
||||
it('returns headRef when set', async () => {
|
||||
const headReference = jest.spyOn(Versioning, 'headRef', 'get').mockReturnValue('feature-branch-1');
|
||||
const headReference = jest.spyOn(BuildVersionGenerator, 'headRef', 'get').mockReturnValue('feature-branch-1');
|
||||
|
||||
await expect(Versioning.getCurrentBranch).resolves.toStrictEqual('feature-branch-1');
|
||||
await expect(BuildVersionGenerator.getCurrentBranch).resolves.toStrictEqual('feature-branch-1');
|
||||
expect(headReference).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('returns part of Ref when set', () => {
|
||||
jest.spyOn(Versioning, 'headRef', 'get').mockImplementation();
|
||||
const reference = jest.spyOn(Versioning, 'ref', 'get').mockReturnValue('refs/heads/feature-branch-2');
|
||||
jest.spyOn(BuildVersionGenerator, 'headRef', 'get').mockImplementation();
|
||||
const reference = jest.spyOn(BuildVersionGenerator, 'ref', 'get').mockReturnValue('refs/heads/feature-branch-2');
|
||||
|
||||
await expect(Versioning.getCurrentBranch).resolves.toStrictEqual('feature-branch-2');
|
||||
await expect(BuildVersionGenerator.getCurrentBranch).resolves.toStrictEqual('feature-branch-2');
|
||||
expect(reference).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('prefers headRef over ref when set', () => {
|
||||
const headReference = jest.spyOn(Versioning, 'headRef', 'get').mockReturnValue('feature-branch-1');
|
||||
const reference = jest.spyOn(Versioning, 'ref', 'get').mockReturnValue('refs/heads/feature-2');
|
||||
const headReference = jest.spyOn(BuildVersionGenerator, 'headRef', 'get').mockReturnValue('feature-branch-1');
|
||||
const reference = jest.spyOn(BuildVersionGenerator, 'ref', 'get').mockReturnValue('refs/heads/feature-2');
|
||||
|
||||
await expect(Versioning.getCurrentBranch).resolves.toStrictEqual('feature-branch-1');
|
||||
await expect(BuildVersionGenerator.getCurrentBranch).resolves.toStrictEqual('feature-branch-1');
|
||||
expect(headReference).toHaveBeenCalledTimes(1);
|
||||
expect(reference).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('returns undefined when headRef and ref are not set', async () => {
|
||||
const headReference = jest.spyOn(Versioning, 'headRef', 'get').mockImplementation();
|
||||
const reference = jest.spyOn(Versioning, 'ref', 'get').mockImplementation();
|
||||
const headReference = jest.spyOn(BuildVersionGenerator, 'headRef', 'get').mockImplementation();
|
||||
const reference = jest.spyOn(BuildVersionGenerator, 'ref', 'get').mockImplementation();
|
||||
|
||||
await expect(Versioning.getCurrentBranch).resolves.not.toBeDefined();
|
||||
await expect(BuildVersionGenerator.getCurrentBranch).resolves.not.toBeDefined();
|
||||
|
||||
expect(headReference).toHaveBeenCalledTimes(1);
|
||||
expect(reference).toHaveBeenCalledTimes(1);
|
||||
|
|
@ -93,23 +93,23 @@ describe('Versioning', () => {
|
|||
|
||||
describe('headRef', () => {
|
||||
it('does not throw', () => {
|
||||
expect(() => Versioning.headRef).not.toThrow();
|
||||
expect(() => BuildVersionGenerator.headRef).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ref', () => {
|
||||
it('does not throw', () => {
|
||||
expect(() => Versioning.ref).not.toThrow();
|
||||
expect(() => BuildVersionGenerator.ref).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isDirtyAllowed', () => {
|
||||
it('does not throw', () => {
|
||||
expect(() => Versioning.isDirtyAllowed).not.toThrow();
|
||||
expect(() => BuildVersionGenerator.isDirtyAllowed).not.toThrow();
|
||||
});
|
||||
|
||||
it('returns false by default', () => {
|
||||
expect(Versioning.isDirtyAllowed).toStrictEqual(false);
|
||||
expect(BuildVersionGenerator.isDirtyAllowed).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -117,17 +117,17 @@ describe('Versioning', () => {
|
|||
it('calls git diff', async () => {
|
||||
// allowDirtyBuild: true
|
||||
jest.spyOn(core, 'getInput').mockReturnValue('true');
|
||||
jest.spyOn(Versioning, 'isShallow').mockResolvedValue(true);
|
||||
jest.spyOn(Versioning, 'isDirty').mockResolvedValue(false);
|
||||
jest.spyOn(Versioning, 'fetch').mockImplementation();
|
||||
jest.spyOn(Versioning, 'hasAnyVersionTags').mockResolvedValue(true);
|
||||
jest.spyOn(BuildVersionGenerator, 'isShallow').mockResolvedValue(true);
|
||||
jest.spyOn(BuildVersionGenerator, 'isDirty').mockResolvedValue(false);
|
||||
jest.spyOn(BuildVersionGenerator, 'fetch').mockImplementation();
|
||||
jest.spyOn(BuildVersionGenerator, 'hasAnyVersionTags').mockResolvedValue(true);
|
||||
jest
|
||||
.spyOn(Versioning, 'parseSemanticVersion')
|
||||
.spyOn(BuildVersionGenerator, 'parseSemanticVersion')
|
||||
.mockResolvedValue({ match: '', tag: 'mocktag', commits: 'abcdef', hash: '75822BCAF' });
|
||||
const logDiffSpy = jest.spyOn(Versioning, 'logDiff');
|
||||
const logDiffSpy = jest.spyOn(BuildVersionGenerator, 'logDiff');
|
||||
const gitSpy = jest.spyOn(System, 'run').mockImplementation();
|
||||
|
||||
await Versioning.generateSemanticVersion();
|
||||
await BuildVersionGenerator.generateSemanticVersion();
|
||||
|
||||
expect(logDiffSpy).toHaveBeenCalledTimes(1);
|
||||
expect(gitSpy).toHaveBeenCalledTimes(1);
|
||||
|
|
@ -140,39 +140,39 @@ describe('Versioning', () => {
|
|||
|
||||
describe('descriptionRegex1', () => {
|
||||
it('is a valid regex', () => {
|
||||
expect(Versioning.descriptionRegex1).toBeInstanceOf(RegExp);
|
||||
expect(BuildVersionGenerator.descriptionRegex1).toBeInstanceOf(RegExp);
|
||||
});
|
||||
|
||||
test.each(['v1.1-1-g12345678', 'v0.1-2-g12345678', 'v0.0-500-gA9B6C3D0-dirty'])(
|
||||
'is happy with valid %s',
|
||||
(description) => {
|
||||
expect(Versioning.descriptionRegex1.test(description)).toBeTruthy();
|
||||
expect(BuildVersionGenerator.descriptionRegex1.test(description)).toBeTruthy();
|
||||
},
|
||||
);
|
||||
|
||||
test.each(['1.1-1-g12345678', '0.1-2-g12345678', '0.0-500-gA9B6C3D0-dirty'])(
|
||||
'accepts valid semantic versions without v-prefix %s',
|
||||
(description) => {
|
||||
expect(Versioning.descriptionRegex1.test(description)).toBeTruthy();
|
||||
expect(BuildVersionGenerator.descriptionRegex1.test(description)).toBeTruthy();
|
||||
},
|
||||
);
|
||||
|
||||
test.each(['v0', 'v0.1', 'v0.1.2', 'v0.1-2', 'v0.1-2-g'])('does not like %s', (description) => {
|
||||
expect(Versioning.descriptionRegex1.test(description)).toBeFalsy();
|
||||
expect(BuildVersionGenerator.descriptionRegex1.test(description)).toBeFalsy();
|
||||
|
||||
// Also, never expect without the v to work for any of these cases.
|
||||
expect(Versioning.descriptionRegex1.test(description?.slice(1))).toBeFalsy();
|
||||
expect(BuildVersionGenerator.descriptionRegex1.test(description?.slice(1))).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('determineBuildVersion', () => {
|
||||
test.each(['somethingRandom'])('throws for invalid strategy %s', async (strategy) => {
|
||||
await expect(Versioning.determineBuildVersion(strategy, '')).rejects.toThrowErrorMatchingSnapshot();
|
||||
await expect(BuildVersionGenerator.determineBuildVersion(strategy, '')).rejects.toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
|
||||
describe('opt out strategy', () => {
|
||||
it("returns 'none'", async () => {
|
||||
await expect(Versioning.determineBuildVersion('None', 'v1.0')).resolves.toMatchInlineSnapshot(`"none"`);
|
||||
await expect(BuildVersionGenerator.determineBuildVersion('None', 'v1.0')).resolves.toMatchInlineSnapshot(`"none"`);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -180,25 +180,25 @@ describe('Versioning', () => {
|
|||
test.each(['v0.1', '1', 'CamelCase', 'dashed-version'])(
|
||||
'returns the inputVersion for %s',
|
||||
async (inputVersion) => {
|
||||
await expect(Versioning.determineBuildVersion('Custom', inputVersion)).resolves.toStrictEqual(inputVersion);
|
||||
await expect(BuildVersionGenerator.determineBuildVersion('Custom', inputVersion)).resolves.toStrictEqual(inputVersion);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('semantic strategy', () => {
|
||||
it('refers to generateSemanticVersion', async () => {
|
||||
const generateSemanticVersion = jest.spyOn(Versioning, 'generateSemanticVersion').mockResolvedValue('1.3.37');
|
||||
const generateSemanticVersion = jest.spyOn(BuildVersionGenerator, 'generateSemanticVersion').mockResolvedValue('1.3.37');
|
||||
|
||||
await expect(Versioning.determineBuildVersion('Semantic', '')).resolves.toStrictEqual('1.3.37');
|
||||
await expect(BuildVersionGenerator.determineBuildVersion('Semantic', '')).resolves.toStrictEqual('1.3.37');
|
||||
expect(generateSemanticVersion).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('tag strategy', () => {
|
||||
it('refers to generateTagVersion', async () => {
|
||||
const generateTagVersion = jest.spyOn(Versioning, 'generateTagVersion').mockResolvedValue('0.1');
|
||||
const generateTagVersion = jest.spyOn(BuildVersionGenerator, 'generateTagVersion').mockResolvedValue('0.1');
|
||||
|
||||
await expect(Versioning.determineBuildVersion('Tag', '')).resolves.toStrictEqual('0.1');
|
||||
await expect(BuildVersionGenerator.determineBuildVersion('Tag', '')).resolves.toStrictEqual('0.1');
|
||||
expect(generateTagVersion).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
@ -207,24 +207,24 @@ describe('Versioning', () => {
|
|||
it('throws a not implemented exception', async () => {
|
||||
const strategy = 'Test';
|
||||
// @ts-ignore
|
||||
jest.spyOn(Versioning, 'strategies', 'get').mockReturnValue({ [strategy]: strategy });
|
||||
await expect(Versioning.determineBuildVersion(strategy, '')).rejects.toThrowError(NotImplementedException);
|
||||
jest.spyOn(BuildVersionGenerator, 'strategies', 'get').mockReturnValue({ [strategy]: strategy });
|
||||
await expect(BuildVersionGenerator.determineBuildVersion(strategy, '')).rejects.toThrowError(NotImplementedException);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateTagVersion', () => {
|
||||
it('removes the v', async () => {
|
||||
jest.spyOn(Versioning, 'getTag').mockResolvedValue('v1.3.37');
|
||||
await expect(Versioning.generateTagVersion()).resolves.toStrictEqual('1.3.37');
|
||||
jest.spyOn(BuildVersionGenerator, 'getTag').mockResolvedValue('v1.3.37');
|
||||
await expect(BuildVersionGenerator.generateTagVersion()).resolves.toStrictEqual('1.3.37');
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseSemanticVersion', () => {
|
||||
it('returns the named parts', async () => {
|
||||
jest.spyOn(Versioning, 'getVersionDescription').mockResolvedValue('v0.1-2-g12345678');
|
||||
jest.spyOn(BuildVersionGenerator, 'getVersionDescription').mockResolvedValue('v0.1-2-g12345678');
|
||||
|
||||
await expect(Versioning.parseSemanticVersion()).resolves.toMatchObject({
|
||||
await expect(BuildVersionGenerator.parseSemanticVersion()).resolves.toMatchObject({
|
||||
tag: '0.1',
|
||||
commits: '2',
|
||||
hash: '12345678',
|
||||
|
|
@ -232,9 +232,9 @@ describe('Versioning', () => {
|
|||
});
|
||||
|
||||
it('throws when no match could be made', async () => {
|
||||
jest.spyOn(Versioning, 'getVersionDescription').mockResolvedValue('no-match-can-be-made');
|
||||
jest.spyOn(BuildVersionGenerator, 'getVersionDescription').mockResolvedValue('no-match-can-be-made');
|
||||
|
||||
await expect(Versioning.parseSemanticVersion()).toMatchObject({});
|
||||
await expect(BuildVersionGenerator.parseSemanticVersion()).toMatchObject({});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -242,7 +242,7 @@ describe('Versioning', () => {
|
|||
it('returns the commands output', async () => {
|
||||
const runOutput = 'someValue';
|
||||
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
|
||||
await expect(Versioning.getVersionDescription()).resolves.toStrictEqual(runOutput);
|
||||
await expect(BuildVersionGenerator.getVersionDescription()).resolves.toStrictEqual(runOutput);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -250,13 +250,13 @@ describe('Versioning', () => {
|
|||
it('returns true when the repo is shallow', async () => {
|
||||
const runOutput = 'true\n';
|
||||
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
|
||||
await expect(Versioning.isShallow()).resolves.toStrictEqual(true);
|
||||
await expect(BuildVersionGenerator.isShallow()).resolves.toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('returns false when the repo is not shallow', async () => {
|
||||
const runOutput = 'false\n';
|
||||
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
|
||||
await expect(Versioning.isShallow()).resolves.toStrictEqual(false);
|
||||
await expect(BuildVersionGenerator.isShallow()).resolves.toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -264,14 +264,14 @@ describe('Versioning', () => {
|
|||
it('awaits the command', async () => {
|
||||
jest.spyOn(core, 'warning').mockImplementation(() => {});
|
||||
jest.spyOn(System, 'run').mockImplementation();
|
||||
await expect(Versioning.fetch()).resolves.not.toThrow();
|
||||
await expect(BuildVersionGenerator.fetch()).resolves.not.toThrow();
|
||||
});
|
||||
|
||||
it('falls back to the second strategy when the first fails', async () => {
|
||||
jest.spyOn(core, 'warning').mockImplementation(() => {});
|
||||
const gitFetch = jest.spyOn(System, 'run').mockImplementation();
|
||||
|
||||
await expect(Versioning.fetch()).resolves.not.toThrow();
|
||||
await expect(BuildVersionGenerator.fetch()).resolves.not.toThrow();
|
||||
expect(gitFetch).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
@ -280,35 +280,35 @@ describe('Versioning', () => {
|
|||
it('returns a proper version from description', async () => {
|
||||
jest.spyOn(System, 'run').mockImplementation();
|
||||
jest.spyOn(core, 'info').mockImplementation(() => {});
|
||||
jest.spyOn(Versioning, 'isDirty').mockResolvedValue(false);
|
||||
jest.spyOn(Versioning, 'hasAnyVersionTags').mockResolvedValue(true);
|
||||
jest.spyOn(Versioning, 'getTotalNumberOfCommits').mockResolvedValue(2);
|
||||
jest.spyOn(Versioning, 'parseSemanticVersion').mockResolvedValue({
|
||||
jest.spyOn(BuildVersionGenerator, 'isDirty').mockResolvedValue(false);
|
||||
jest.spyOn(BuildVersionGenerator, 'hasAnyVersionTags').mockResolvedValue(true);
|
||||
jest.spyOn(BuildVersionGenerator, 'getTotalNumberOfCommits').mockResolvedValue(2);
|
||||
jest.spyOn(BuildVersionGenerator, 'parseSemanticVersion').mockResolvedValue({
|
||||
match: '0.1-2-g1b345678',
|
||||
tag: '0.1',
|
||||
commits: '2',
|
||||
hash: '1b345678',
|
||||
});
|
||||
|
||||
await expect(Versioning.generateSemanticVersion()).resolves.toStrictEqual('0.1.2');
|
||||
await expect(BuildVersionGenerator.generateSemanticVersion()).resolves.toStrictEqual('0.1.2');
|
||||
});
|
||||
|
||||
it('throws when dirty', async () => {
|
||||
jest.spyOn(System, 'run').mockImplementation();
|
||||
jest.spyOn(core, 'info').mockImplementation(() => {});
|
||||
jest.spyOn(Versioning, 'isDirty').mockResolvedValue(true);
|
||||
await expect(Versioning.generateSemanticVersion()).rejects.toThrowError();
|
||||
jest.spyOn(BuildVersionGenerator, 'isDirty').mockResolvedValue(true);
|
||||
await expect(BuildVersionGenerator.generateSemanticVersion()).rejects.toThrowError();
|
||||
});
|
||||
|
||||
it('falls back to commits only, when no tags are present', async () => {
|
||||
const commits = Math.round(Math.random() * 10);
|
||||
jest.spyOn(System, 'run').mockImplementation();
|
||||
jest.spyOn(core, 'info').mockImplementation(() => {});
|
||||
jest.spyOn(Versioning, 'isDirty').mockResolvedValue(false);
|
||||
jest.spyOn(Versioning, 'hasAnyVersionTags').mockResolvedValue(false);
|
||||
jest.spyOn(Versioning, 'getTotalNumberOfCommits').mockResolvedValue(commits);
|
||||
jest.spyOn(BuildVersionGenerator, 'isDirty').mockResolvedValue(false);
|
||||
jest.spyOn(BuildVersionGenerator, 'hasAnyVersionTags').mockResolvedValue(false);
|
||||
jest.spyOn(BuildVersionGenerator, 'getTotalNumberOfCommits').mockResolvedValue(commits);
|
||||
|
||||
await expect(Versioning.generateSemanticVersion()).resolves.toStrictEqual(`0.0.${commits}`);
|
||||
await expect(BuildVersionGenerator.generateSemanticVersion()).resolves.toStrictEqual(`0.0.${commits}`);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -316,13 +316,13 @@ describe('Versioning', () => {
|
|||
it('returns true when there are files listed', async () => {
|
||||
const runOutput = 'file.ext\nfile2.ext';
|
||||
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
|
||||
await expect(Versioning.isDirty()).resolves.toStrictEqual(true);
|
||||
await expect(BuildVersionGenerator.isDirty()).resolves.toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('returns false when there is no output', async () => {
|
||||
const runOutput = '';
|
||||
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
|
||||
await expect(Versioning.isDirty()).resolves.toStrictEqual(false);
|
||||
await expect(BuildVersionGenerator.isDirty()).resolves.toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -330,7 +330,7 @@ describe('Versioning', () => {
|
|||
it('returns the commands output', async () => {
|
||||
const runOutput = 'v1.0';
|
||||
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
|
||||
await expect(Versioning.getTag()).resolves.toStrictEqual(runOutput);
|
||||
await expect(BuildVersionGenerator.getTag()).resolves.toStrictEqual(runOutput);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -338,20 +338,20 @@ describe('Versioning', () => {
|
|||
it('returns false when the command returns 0', async () => {
|
||||
const runOutput = '0';
|
||||
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
|
||||
await expect(Versioning.hasAnyVersionTags()).resolves.toStrictEqual(false);
|
||||
await expect(BuildVersionGenerator.hasAnyVersionTags()).resolves.toStrictEqual(false);
|
||||
});
|
||||
|
||||
it('returns true when the command returns >= 0', async () => {
|
||||
const runOutput = '9';
|
||||
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
|
||||
await expect(Versioning.hasAnyVersionTags()).resolves.toStrictEqual(true);
|
||||
await expect(BuildVersionGenerator.hasAnyVersionTags()).resolves.toStrictEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTotalNumberOfCommits', () => {
|
||||
it('returns a number from the command', async () => {
|
||||
jest.spyOn(System, 'run').mockResolvedValue('9');
|
||||
await expect(Versioning.getTotalNumberOfCommits()).resolves.toStrictEqual(9);
|
||||
await expect(BuildVersionGenerator.getTotalNumberOfCommits()).resolves.toStrictEqual(9);
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue