feat: add verbosity and split parameters per command
parent
cae5ffaf6c
commit
a0372d1ec6
|
|
@ -6,3 +6,5 @@ lib/
|
|||
yarn-error.log
|
||||
.orig
|
||||
*.log
|
||||
logs/*
|
||||
!**/.gitkeep
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ export class BuildCommand implements CommandInterface {
|
|||
|
||||
public async execute(options: Options): Promise<boolean> {
|
||||
try {
|
||||
log.info('options', options);
|
||||
const { workspace, actionFolder } = Action;
|
||||
const { buildParameters } = options;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
import { CommandInterface } from '../command-interface.ts';
|
||||
import { Options } from '../../../config/options.ts';
|
||||
import { CloudRunner, ImageTag, Input, Output } from '../../../model/index.ts';
|
||||
import { core } from '../../../dependencies.ts';
|
||||
import { core, nanoid } from '../../../dependencies.ts';
|
||||
import Parameters from '../../../model/parameters.ts';
|
||||
import { GitRepoReader } from '../../../model/input-readers/git-repo.ts';
|
||||
import { Cli } from '../../../model/cli/cli.ts';
|
||||
import CloudRunnerConstants from '../../../model/cloud-runner/services/cloud-runner-constants.ts';
|
||||
import CloudRunnerBuildGuid from '../../../model/cloud-runner/services/cloud-runner-guid.ts';
|
||||
import { GithubCliReader } from '../../../model/input-readers/github-cli.ts';
|
||||
|
||||
// Todo - Verify this entire flow
|
||||
export class BuildRemoteCommand implements CommandInterface {
|
||||
|
|
@ -12,7 +17,39 @@ export class BuildRemoteCommand implements CommandInterface {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
public async parseParameters(input: Input, parameters: Parameters) {}
|
||||
public async parseParameters(input: Input, parameters: Parameters) {
|
||||
return {
|
||||
cloudRunnerBranch: input.cloudRunnerBranch.split('/').reverse()[0],
|
||||
cloudRunnerIntegrationTests: input.cloudRunnerTests,
|
||||
githubRepo: input.githubRepo || (await GitRepoReader.GetRemote()) || 'game-ci/unity-builder',
|
||||
gitPrivateToken: parameters.gitPrivateToken || (await GithubCliReader.GetGitHubAuthToken()),
|
||||
isCliMode: Cli.isCliMode,
|
||||
awsStackName: input.awsBaseStackName,
|
||||
cloudRunnerCluster: input.cloudRunnerCluster,
|
||||
cloudRunnerBuilderPlatform: input.cloudRunnerBuilderPlatform,
|
||||
awsBaseStackName: input.awsBaseStackName,
|
||||
kubeConfig: input.kubeConfig,
|
||||
cloudRunnerMemory: input.cloudRunnerMemory,
|
||||
cloudRunnerCpu: input.cloudRunnerCpu,
|
||||
kubeVolumeSize: input.kubeVolumeSize,
|
||||
kubeVolume: input.kubeVolume,
|
||||
postBuildSteps: input.postBuildSteps,
|
||||
preBuildSteps: input.preBuildSteps,
|
||||
runNumber: input.runNumber,
|
||||
gitSha: input.gitSha,
|
||||
logId: nanoid.customAlphabet(CloudRunnerConstants.alphabet, 9)(),
|
||||
buildGuid: CloudRunnerBuildGuid.generateGuid(input.runNumber, input.targetPlatform),
|
||||
customJobHooks: input.customJobHooks(),
|
||||
cachePullOverrideCommand: input.cachePullOverrideCommand(),
|
||||
cachePushOverrideCommand: input.cachePushOverrideCommand(),
|
||||
readInputOverrideCommand: input.readInputOverrideCommand(),
|
||||
readInputFromOverrideList: input.readInputFromOverrideList(),
|
||||
kubeStorageClass: input.kubeStorageClass,
|
||||
checkDependencyHealthOverride: input.checkDependencyHealthOverride,
|
||||
startDependenciesOverride: input.startDependenciesOverride,
|
||||
cacheKey: input.cacheKey,
|
||||
};
|
||||
}
|
||||
|
||||
public async execute(options: Options): Promise<boolean> {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export class Options {
|
|||
this.input = new Input(args);
|
||||
this.parameters = await new Parameters(this.input, this.env).registerCommand(this.command).parse();
|
||||
|
||||
log.debug('Parameters generated.');
|
||||
log.info('Parameters generated.');
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,24 @@ export class ArgumentsParser {
|
|||
const [commandName, ...rest] = cliArguments;
|
||||
const { subCommands, args } = parseArgv(rest);
|
||||
|
||||
let verbosity;
|
||||
if (args.has('vvv') || args.has('max-verbose') || args.has('maxVerbose') || args.has('debug')) {
|
||||
verbosity = 3;
|
||||
} else if (args.has('vv') || args.has('very-verbose') || args.has('veryVerbose')) {
|
||||
verbosity = 2;
|
||||
} else if (args.has('v') || args.has('verbose')) {
|
||||
verbosity = 1;
|
||||
} else if (args.has('q') || args.has('quiet')) {
|
||||
verbosity = -1;
|
||||
} else {
|
||||
verbosity = 0;
|
||||
}
|
||||
|
||||
return {
|
||||
commandName,
|
||||
subCommands,
|
||||
args,
|
||||
verbosity,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,65 @@
|
|||
import * as log from 'https://deno.land/std@0.151.0/log/mod.ts';
|
||||
import { fileFormatter, consoleFormatter } from './formatter.ts';
|
||||
|
||||
// Handlers
|
||||
const consoleHandler = new log.handlers.ConsoleHandler('DEBUG', { formatter: consoleFormatter });
|
||||
const fileHandler = new log.handlers.FileHandler('WARNING', { filename: './game-ci.log', formatter: fileFormatter });
|
||||
export enum Verbosity {
|
||||
quiet = -1,
|
||||
normal = 0,
|
||||
verbose = 1,
|
||||
veryVerbose = 2,
|
||||
maxVerbose = 3,
|
||||
}
|
||||
|
||||
// Make sure it saves on Ctrl+C interrupt https://github.com/denoland/deno_std/issues/2193
|
||||
Deno.addSignalListener('SIGINT', () => fileHandler.flush());
|
||||
export const configureLogger = async (verbosity: Verbosity) => {
|
||||
// Verbosity
|
||||
const isQuiet = verbosity === Verbosity.quiet;
|
||||
const isVerbose = verbosity >= Verbosity.verbose;
|
||||
const isVeryVerbose = verbosity >= Verbosity.veryVerbose;
|
||||
const isMaxVerbose = verbosity >= Verbosity.maxVerbose;
|
||||
|
||||
await log.setup({
|
||||
handlers: {
|
||||
consoleHandler,
|
||||
fileHandler,
|
||||
},
|
||||
// Handlers
|
||||
let consoleLevel = 'INFO';
|
||||
if (isQuiet) consoleLevel = 'ERROR';
|
||||
if (isVerbose) consoleLevel = 'DEBUG';
|
||||
const consoleHandler = new log.handlers.ConsoleHandler(consoleLevel, { formatter: consoleFormatter });
|
||||
const fileHandler = new log.handlers.FileHandler('WARNING', {
|
||||
filename: './logs/game-ci.log',
|
||||
formatter: fileFormatter,
|
||||
});
|
||||
|
||||
loggers: {
|
||||
default: {
|
||||
level: 'DEBUG',
|
||||
handlers: ['consoleHandler', 'fileHandler'],
|
||||
// Make sure it saves on Ctrl+C interrupt https://github.com/denoland/deno_std/issues/2193
|
||||
Deno.addSignalListener('SIGINT', () => fileHandler.flush());
|
||||
|
||||
await log.setup({
|
||||
handlers: {
|
||||
consoleHandler,
|
||||
fileHandler,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Allows using `log.debug` and other methods directly from anywhere
|
||||
*
|
||||
* Example
|
||||
* log.debug('something', [{ a: { b: { c: { d: ['a', 'b'] } } } }], 'something', {
|
||||
* a: { b: { c: { d: { e: { f: { g: 'foo' } } } } } },
|
||||
* });
|
||||
*
|
||||
* Outputs:
|
||||
* [DEBUG] something [ { a: { b: [Object] } } ] something { a: { b: { c: [Object] } } }
|
||||
*/
|
||||
window.log = log.getLogger();
|
||||
loggers: {
|
||||
default: {
|
||||
level: 'DEBUG',
|
||||
handlers: ['consoleHandler', 'fileHandler'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Allows using `log.debug` and other methods directly from anywhere
|
||||
*
|
||||
* Example
|
||||
* log.debug('something', [{ a: { b: { c: { d: ['a', 'b'] } } } }], 'something', {
|
||||
* a: { b: { c: { d: { e: { f: { g: 'foo' } } } } } },
|
||||
* });
|
||||
*
|
||||
* Outputs:
|
||||
* [DEBUG] something [ { a: { b: [Object] } } ] something { a: { b: { c: [Object] } } }
|
||||
*/
|
||||
window.log = log.getLogger();
|
||||
|
||||
// Verbosity
|
||||
window.log.verbosity = verbosity;
|
||||
window.log.isQuiet = isQuiet;
|
||||
window.log.isVerbose = isVerbose;
|
||||
window.log.isVeryVerbose = isVeryVerbose;
|
||||
window.log.isMaxVerbose = isMaxVerbose;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,17 @@
|
|||
import { Verbosity } from './core/logger/index.ts';
|
||||
|
||||
let log: {
|
||||
verbosity: Verbosity;
|
||||
isQuiet: boolean;
|
||||
isVerbose: boolean;
|
||||
isVeryVerbose: boolean;
|
||||
isMaxVerbose: boolean;
|
||||
debug: (msg: any, ...args: any[]) => void;
|
||||
info: (msg: any, ...args: any[]) => void;
|
||||
warning: (msg: any, ...args: any[]) => void;
|
||||
error: (msg: any, ...args: any[]) => void;
|
||||
};
|
||||
|
||||
interface Window {
|
||||
declare interface Window {
|
||||
log: any;
|
||||
}
|
||||
|
|
|
|||
10
src/index.ts
10
src/index.ts
|
|
@ -1,4 +1,4 @@
|
|||
import './core/logger/index.ts';
|
||||
import { configureLogger, Verbosity } from './core/logger/index.ts';
|
||||
import { Options } from './config/options.ts';
|
||||
import { CommandFactory } from './commands/command-factory.ts';
|
||||
import { ArgumentsParser } from './core/cli/arguments-parser.ts';
|
||||
|
|
@ -15,12 +15,16 @@ export class GameCI {
|
|||
|
||||
public async run() {
|
||||
try {
|
||||
const { commandName, subCommands, args } = new ArgumentsParser().parse(this.args);
|
||||
const { engine, engineVersion } = await new EngineDetector(subCommands, args).detect();
|
||||
const { commandName, subCommands, args, verbosity } = new ArgumentsParser().parse(this.args);
|
||||
|
||||
await configureLogger(verbosity);
|
||||
|
||||
const { engine, engineVersion } = await new EngineDetector(subCommands, args).detect();
|
||||
const command = new CommandFactory().selectEngine(engine, engineVersion).createCommand(commandName, subCommands);
|
||||
const options = await new Options(command, this.env).registerCommand(command).generateParameters(args);
|
||||
|
||||
if (log.isVerbose) log.info('Executing', command.name);
|
||||
|
||||
await command.execute(options);
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ import Platform from './platform.ts';
|
|||
import { CliArguments } from '../core/cli/cli-arguments.ts';
|
||||
|
||||
/**
|
||||
* Input variables specified in workflows using "with" prop.
|
||||
* Input variables specified directly on the commandline.
|
||||
*
|
||||
* Todo - check if the following statement is still correct:
|
||||
* Note that input is always passed as a string, even booleans.
|
||||
*
|
||||
* Todo: rename to UserInput and remove anything that is not direct input from the user / ci workflow
|
||||
|
|
@ -17,18 +18,17 @@ class Input {
|
|||
constructor(argumentsFromCli: CliArguments) {
|
||||
this.arguments = argumentsFromCli;
|
||||
|
||||
log.debug('Input initialised.');
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public static githubInputEnabled: boolean = true;
|
||||
|
||||
// Todo - Note that this is now invoked both statically and dynamically - which is a temporary mess.
|
||||
public getInput(query) {
|
||||
public getInput(query: string) {
|
||||
if (this && this.arguments) {
|
||||
const value = this.arguments.get(query);
|
||||
log.warning('arg', query, '=', value);
|
||||
|
||||
if (log.isVeryVerbose) log.debug('arg', query, '=', value);
|
||||
|
||||
return this.arguments.get(query);
|
||||
}
|
||||
|
|
@ -70,15 +70,17 @@ class Input {
|
|||
public get githubRepo() {
|
||||
return this.getInput('GITHUB_REPOSITORY') || this.getInput('GITHUB_REPO') || undefined;
|
||||
}
|
||||
|
||||
public get branch() {
|
||||
if (this.getInput(`GITHUB_REF`)) {
|
||||
return this.getInput(`GITHUB_REF`).replace('refs/', '').replace(`head/`, '').replace(`heads/`, '');
|
||||
} else if (this.getInput('branch')) {
|
||||
return this.getInput('branch');
|
||||
return this.getInput('branch').replace('/head', '');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public get cloudRunnerBuilderPlatform() {
|
||||
const input = this.getInput('cloudRunnerBuilderPlatform');
|
||||
if (input) {
|
||||
|
|
|
|||
|
|
@ -98,8 +98,6 @@ class Parameters {
|
|||
);
|
||||
log.debug('androidSdkManagerParameters', androidSdkManagerParameters);
|
||||
|
||||
// Todo - Don't use process.env directly, that's what the input model class is for.
|
||||
// ---
|
||||
let unitySerial = '';
|
||||
if (!this.env.UNITY_SERIAL && this.input.githubInputEnabled) {
|
||||
// No serial was present, so it is a personal license that we need to convert
|
||||
|
|
@ -114,13 +112,22 @@ class Parameters {
|
|||
unitySerial = this.env.UNITY_SERIAL!;
|
||||
}
|
||||
|
||||
const branch = (await Versioning.getCurrentBranch()) || (await GitRepoReader.GetBranch());
|
||||
log.info(`branch: "${branch}"`);
|
||||
|
||||
const projectPath = this.input.projectPath;
|
||||
log.info(`projectPath: "${projectPath}"`);
|
||||
|
||||
const targetPlatform = this.input.targetPlatform;
|
||||
log.info(`targetPlatform: "${targetPlatform}"`);
|
||||
|
||||
const parameters = {
|
||||
editorVersion,
|
||||
customImage: this.input.customImage,
|
||||
unitySerial,
|
||||
runnerTempPath: this.env.RUNNER_TEMP,
|
||||
targetPlatform: this.input.targetPlatform,
|
||||
projectPath: this.input.projectPath,
|
||||
targetPlatform,
|
||||
projectPath,
|
||||
buildName: this.input.buildName,
|
||||
buildPath: `${this.input.buildsPath}/${this.input.targetPlatform}`,
|
||||
buildFile,
|
||||
|
|
@ -136,41 +143,13 @@ class Parameters {
|
|||
androidSdkManagerParameters,
|
||||
customParameters: this.input.customParameters,
|
||||
sshAgent: this.input.sshAgent,
|
||||
gitPrivateToken: this.input.gitPrivateToken || (await GithubCliReader.GetGitHubAuthToken()),
|
||||
gitPrivateToken: this.input.gitPrivateToken,
|
||||
chownFilesTo: this.input.chownFilesTo,
|
||||
cloudRunnerCluster: this.input.cloudRunnerCluster,
|
||||
cloudRunnerBuilderPlatform: this.input.cloudRunnerBuilderPlatform,
|
||||
awsBaseStackName: this.input.awsBaseStackName,
|
||||
kubeConfig: this.input.kubeConfig,
|
||||
cloudRunnerMemory: this.input.cloudRunnerMemory,
|
||||
cloudRunnerCpu: this.input.cloudRunnerCpu,
|
||||
kubeVolumeSize: this.input.kubeVolumeSize,
|
||||
kubeVolume: this.input.kubeVolume,
|
||||
postBuildSteps: this.input.postBuildSteps,
|
||||
preBuildSteps: this.input.preBuildSteps,
|
||||
customJob: this.input.customJob,
|
||||
runNumber: this.input.runNumber,
|
||||
branch: this.input.branch.replace('/head', '') || (await GitRepoReader.GetBranch()),
|
||||
cloudRunnerBranch: this.input.cloudRunnerBranch.split('/').reverse()[0],
|
||||
cloudRunnerIntegrationTests: this.input.cloudRunnerTests,
|
||||
githubRepo: this.input.githubRepo || (await GitRepoReader.GetRemote()) || 'game-ci/unity-builder',
|
||||
isCliMode: Cli.isCliMode,
|
||||
awsStackName: this.input.awsBaseStackName,
|
||||
gitSha: this.input.gitSha,
|
||||
logId: nanoid.customAlphabet(CloudRunnerConstants.alphabet, 9)(),
|
||||
buildGuid: CloudRunnerBuildGuid.generateGuid(this.input.runNumber, this.input.targetPlatform),
|
||||
customJobHooks: this.input.customJobHooks(),
|
||||
cachePullOverrideCommand: this.input.cachePullOverrideCommand(),
|
||||
cachePushOverrideCommand: this.input.cachePushOverrideCommand(),
|
||||
readInputOverrideCommand: this.input.readInputOverrideCommand(),
|
||||
readInputFromOverrideList: this.input.readInputFromOverrideList(),
|
||||
kubeStorageClass: this.input.kubeStorageClass,
|
||||
checkDependencyHealthOverride: this.input.checkDependencyHealthOverride,
|
||||
startDependenciesOverride: this.input.startDependenciesOverride,
|
||||
cacheKey: this.input.cacheKey,
|
||||
branch,
|
||||
};
|
||||
|
||||
const commandParameterOverrides = this.command.parseParameters(this.input, parameters);
|
||||
const commandParameterOverrides = await this.command.parseParameters(this.input, parameters);
|
||||
|
||||
// Todo - Maybe return an instance instead
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -42,14 +42,20 @@ class System {
|
|||
|
||||
process.close();
|
||||
|
||||
const output = new TextDecoder().decode(outputBuffer);
|
||||
const error = new TextDecoder().decode(errorBuffer);
|
||||
const output = new TextDecoder().decode(outputBuffer).replace(/\n+$/, '');
|
||||
const error = new TextDecoder().decode(errorBuffer).replace(/\n+$/, '');
|
||||
|
||||
const result = { status, output };
|
||||
const symbol = status.success ? '✅' : '❗';
|
||||
|
||||
const truncatedOutput = output.length >= 30 ? `${output.slice(0, 27)}...` : output;
|
||||
log.debug('Command:', command, argsString, symbol, { status, output: truncatedOutput });
|
||||
// Log command output if verbose is enabled
|
||||
if (log.isVeryVerbose) {
|
||||
const symbol = status.success ? '✅' : '❗';
|
||||
const truncatedOutput = output.length >= 30 ? `${output.slice(0, 27)}...` : output;
|
||||
log.debug('Command:', command, argsString, symbol, {
|
||||
status,
|
||||
output: log.isMaxVerbose ? output : truncatedOutput,
|
||||
});
|
||||
}
|
||||
|
||||
if (error) throw new Error(error);
|
||||
|
||||
|
|
|
|||
|
|
@ -132,9 +132,8 @@ export default class Versioning {
|
|||
await this.fetch();
|
||||
}
|
||||
|
||||
await Versioning.logDiff();
|
||||
|
||||
if ((await this.isDirty()) && !allowDirtyBuild) {
|
||||
await Versioning.logDiff();
|
||||
throw new Error('Branch is dirty. Refusing to base semantic version on uncommitted changes');
|
||||
}
|
||||
|
||||
|
|
@ -290,6 +289,7 @@ export default class Versioning {
|
|||
*/
|
||||
static 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
|
||||
const result = await System.shellRun(command, { cwd: this.projectPath, silent: false });
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue