From 38285d014cd8b49c51344348e5f19c304e9a154b Mon Sep 17 00:00:00 2001 From: Webber Date: Sat, 6 Aug 2022 22:43:27 +0200 Subject: [PATCH] chore: convert core logger to global logger --- .eslintrc.json | 12 ++++-- src/core/logger/formatter.ts | 10 ++++- src/global.d.ts | 16 ++++---- src/index.ts | 7 ++-- src/model/android-versioning.ts | 6 +-- src/model/cache.ts | 2 +- src/model/cli/cli.ts | 8 ++-- .../providers/aws/aws-base-stack.ts | 2 +- .../cloud-runner/providers/aws/aws-error.ts | 2 +- .../providers/aws/aws-task-runner.ts | 2 +- src/model/cloud-runner/providers/k8s/index.ts | 4 +- .../providers/k8s/kubernetes-storage.ts | 10 ++--- .../providers/k8s/kubernetes-task-runner.ts | 4 +- .../services/cloud-runner-logger.ts | 10 ++--- .../services/follow-log-stream-service.ts | 6 +-- src/model/input-readers/github-cli.test.ts | 2 +- src/model/input-readers/github-cli.ts | 2 +- src/model/system.ts | 8 ++-- src/model/versioning.ts | 22 +++++++---- src/modules/actions/exec.ts | 38 +++++++++++++------ 20 files changed, 104 insertions(+), 69 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 0060d7e6..61b4ebef 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -55,6 +55,8 @@ "no-continue": "off", // From experience, named exports are almost always desired. I got tired of this rule "import/prefer-default-export": "off", + // Disable in favour of TS equivalent + "no-unused-vars": "off", // Unused vars are useful to keep method signatures consistent and documented "@typescript-eslint/no-unused-vars": "off", // For this project only use kebab-case @@ -65,9 +67,13 @@ "unicorn/prevent-abbreviations": "off", // Allow disabling eslint per file "eslint-comments/no-use": "off", - // Deno import style + // Deno import style not supported (enable after upgrading) "import/extensions": "off", - // Deno import style - "import/no-unresolved": "off" + // Deno import style not supported (enable after upgrading) + "import/no-unresolved": "off", + // App it not yet internationalised + "i18n-text/no-en": "off", + // Showing false positives (enable after upgrading) + "no-shadow": "off" } } diff --git a/src/core/logger/formatter.ts b/src/core/logger/formatter.ts index aaa04ea8..96025646 100644 --- a/src/core/logger/formatter.ts +++ b/src/core/logger/formatter.ts @@ -11,7 +11,13 @@ export const createFormatter = ({ showBrackets = true, depth = 3, } = {}): FormatterFunction => { - const column = (value: string) => (showBrackets ? `[${value}]` : ` ${value}`); + const column = (input: string, { width = 0, align = 'left' } = {}) => { + const totalWidth = showBrackets ? width + 2 : width; + const value = showBrackets ? `[${input}]` : ` ${input}`; + const paddingOptions = { side: align === 'left' ? 'right' : 'left' }; + + return pad(value, totalWidth, paddingOptions); + }; return ({ level, levelName, msg, args, loggerName }: LogRecord) => { let line = ''; @@ -31,7 +37,7 @@ export const createFormatter = ({ if (showLevelName) { const shortName = levelName.length <= 5 ? levelName : levelName.slice(0, 4); - line += column(`${pad(shortName, 5, { side: 'left' })}`); + line += column(shortName, { width: 5, align: 'right' }); } if (showLevel) { diff --git a/src/global.d.ts b/src/global.d.ts index 6bfc33a7..a3668700 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -1,10 +1,10 @@ -/* eslint-disable no-unused-vars */ -export type Level = 'debug' | 'info' | 'warn' | 'error' | 'critical'; +let log: { + debug: (msg: any, ...args: any[]) => void; + info: (msg: any, ...args: any[]) => void; + warning: (msg: any, ...args: any[]) => void; + error: (msg: any, ...args: any[]) => void; +}; -declare global { - const log: (level: Level, ...args: any[]) => void; - - interface Window { - log: any; - } +interface Window { + log: any; } diff --git a/src/index.ts b/src/index.ts index 40a193ea..4c392bc1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,7 +8,8 @@ import PlatformSetup from './model/platform-setup.ts'; async function runMain() { try { if (Cli.InitCliMode()) { - log.debug('CloudBuilder CLI mode'); + // Todo - this is only here for testing the entire flow in deno and making sure I'm hitting the right path + log.error('CloudBuilder CLI mode'); await Cli.RunCli(); return; @@ -28,7 +29,7 @@ async function runMain() { if (buildParameters.cloudRunnerCluster !== 'local') { await CloudRunner.run(buildParameters, baseImage.toString()); } else { - core.info('Building locally'); + log.info('Building locally'); await PlatformSetup.setup(buildParameters, actionFolder); if (process.platform === 'darwin') { MacBuilder.run(actionFolder, workspace, buildParameters); @@ -40,7 +41,7 @@ async function runMain() { // Set output await Output.setBuildVersion(buildParameters.buildVersion); } catch (error) { - core.error(error); + log.error(error); core.setFailed((error as Error).message); } } diff --git a/src/model/android-versioning.ts b/src/model/android-versioning.ts index 4f31dc03..8318fead 100644 --- a/src/model/android-versioning.ts +++ b/src/model/android-versioning.ts @@ -11,7 +11,7 @@ export default class AndroidVersioning { static versionToVersionCode(version) { if (version === 'none') { - core.info(`Versioning strategy is set to ${version}, so android version code should not be applied.`); + log.info(`Versioning strategy is set to ${version}, so android version code should not be applied.`); return 0; } @@ -19,7 +19,7 @@ export default class AndroidVersioning { const parsedVersion = semver.parse(version); if (!parsedVersion) { - core.warning(`Could not parse "${version}" to semver, defaulting android version code to 1`); + log.warning(`Could not parse "${version}" to semver, defaulting android version code to 1`); return 1; } @@ -33,7 +33,7 @@ export default class AndroidVersioning { `Generated versionCode ${versionCode} is dangerously close to the maximum allowed number 2100000000. Consider a different versioning scheme to be able to continue updating your application.`, ); } - core.info(`Using android versionCode ${versionCode}`); + log.info(`Using android versionCode ${versionCode}`); return versionCode; } diff --git a/src/model/cache.ts b/src/model/cache.ts index 0b392754..39877c1b 100644 --- a/src/model/cache.ts +++ b/src/model/cache.ts @@ -14,7 +14,7 @@ class Cache { return; } - core.warning(` + log.warning(` Library folder does not exist. Consider setting up caching to speed up your workflow, if this is not your first build. diff --git a/src/model/cli/cli.ts b/src/model/cli/cli.ts index f13b5790..4cc19eca 100644 --- a/src/model/cli/cli.ts +++ b/src/model/cli/cli.ts @@ -68,8 +68,8 @@ export class Cli { @CliFunction(`print-input`, `prints all input`) private static logInput() { - core.info(`\n`); - core.info(`INPUT:`); + log.info(`\n`); + log.info(`INPUT:`); const properties = Object.getOwnPropertyNames(Input); for (const element of properties) { if ( @@ -80,10 +80,10 @@ export class Cli { element !== 'cliOptions' && element !== 'prototype' ) { - core.info(`${element} ${Input[element]}`); + log.info(`${element} ${Input[element]}`); } } - core.info(`\n`); + log.info(`\n`); } @CliFunction(`cli`, `runs a cloud runner build`) diff --git a/src/model/cloud-runner/providers/aws/aws-base-stack.ts b/src/model/cloud-runner/providers/aws/aws-base-stack.ts index 267566d3..da328047 100644 --- a/src/model/cloud-runner/providers/aws/aws-base-stack.ts +++ b/src/model/cloud-runner/providers/aws/aws-base-stack.ts @@ -96,7 +96,7 @@ export class AWSBaseStack { } CloudRunnerLogger.log('base stack is now ready'); } catch (error) { - core.error(JSON.stringify(await describeStack(), undefined, 4)); + log.error(JSON.stringify(await describeStack(), undefined, 4)); throw error; } } diff --git a/src/model/cloud-runner/providers/aws/aws-error.ts b/src/model/cloud-runner/providers/aws/aws-error.ts index c8f4aac6..8187b5aa 100644 --- a/src/model/cloud-runner/providers/aws/aws-error.ts +++ b/src/model/cloud-runner/providers/aws/aws-error.ts @@ -5,7 +5,7 @@ import CloudRunner from '../../cloud-runner.ts'; export class AWSError { static async handleStackCreationFailure(error: any, CF: aws.CloudFormation, taskDefStackName: string) { CloudRunnerLogger.log('aws error: '); - core.error(JSON.stringify(error, undefined, 4)); + log.error(JSON.stringify(error, undefined, 4)); if (CloudRunner.buildParameters.cloudRunnerIntegrationTests) { CloudRunnerLogger.log('Getting events and resources for task stack'); const events = (await CF.describeStackEvents({ StackName: taskDefStackName }).promise()).StackEvents; diff --git a/src/model/cloud-runner/providers/aws/aws-task-runner.ts b/src/model/cloud-runner/providers/aws/aws-task-runner.ts index bbe09c5c..614f6762 100644 --- a/src/model/cloud-runner/providers/aws/aws-task-runner.ts +++ b/src/model/cloud-runner/providers/aws/aws-task-runner.ts @@ -96,7 +96,7 @@ class AWSTaskRunner { ); core.setFailed(error); - core.error(error); + log.error(error); } } diff --git a/src/model/cloud-runner/providers/k8s/index.ts b/src/model/cloud-runner/providers/k8s/index.ts index fa475818..3a135be4 100644 --- a/src/model/cloud-runner/providers/k8s/index.ts +++ b/src/model/cloud-runner/providers/k8s/index.ts @@ -131,7 +131,7 @@ class Kubernetes implements ProviderInterface { return output; } catch (error) { CloudRunnerLogger.log('Running job failed'); - core.error(JSON.stringify(error, undefined, 4)); + log.error(JSON.stringify(error, undefined, 4)); await this.cleanupTaskResources(); throw error; } @@ -151,7 +151,7 @@ class Kubernetes implements ProviderInterface { await new Promise((promise) => setTimeout(promise, 5000)); } catch (error) { CloudRunnerLogger.log('Failed to cleanup, error:'); - core.error(JSON.stringify(error, undefined, 4)); + log.error(JSON.stringify(error, undefined, 4)); CloudRunnerLogger.log('Abandoning cleanup, build error:'); throw error; } diff --git a/src/model/cloud-runner/providers/k8s/kubernetes-storage.ts b/src/model/cloud-runner/providers/k8s/kubernetes-storage.ts index bd603b9f..78d1f237 100644 --- a/src/model/cloud-runner/providers/k8s/kubernetes-storage.ts +++ b/src/model/cloud-runner/providers/k8s/kubernetes-storage.ts @@ -37,8 +37,8 @@ class KubernetesStorage { try { return (await kubeClient.readNamespacedPersistentVolumeClaim(name, namespace)).body.status?.phase; } catch (error) { - core.error('Failed to get PVC phase'); - core.error(JSON.stringify(error, undefined, 4)); + log.error('Failed to get PVC phase'); + log.error(JSON.stringify(error, undefined, 4)); throw error; } } @@ -57,9 +57,9 @@ class KubernetesStorage { }, ); } catch (error: any) { - core.error('Failed to watch PVC'); - core.error(error.toString()); - core.error( + log.error('Failed to watch PVC'); + log.error(error.toString()); + log.error( `PVC Body: ${JSON.stringify( (await kubeClient.readNamespacedPersistentVolumeClaim(name, namespace)).body, undefined, diff --git a/src/model/cloud-runner/providers/k8s/kubernetes-task-runner.ts b/src/model/cloud-runner/providers/k8s/kubernetes-task-runner.ts index 98c6ce10..1855e93b 100644 --- a/src/model/cloud-runner/providers/k8s/kubernetes-task-runner.ts +++ b/src/model/cloud-runner/providers/k8s/kubernetes-task-runner.ts @@ -44,8 +44,8 @@ class KubernetesTaskRunner { throw resultError; } if (!didStreamAnyLogs) { - core.error('Failed to stream any logs, listing namespace events, check for an error with the container'); - core.error( + log.error('Failed to stream any logs, listing namespace events, check for an error with the container'); + log.error( JSON.stringify( { events: (await kubeClient.listNamespacedEvent(namespace)).body.items diff --git a/src/model/cloud-runner/services/cloud-runner-logger.ts b/src/model/cloud-runner/services/cloud-runner-logger.ts index 2defa616..92c1382f 100644 --- a/src/model/cloud-runner/services/cloud-runner-logger.ts +++ b/src/model/cloud-runner/services/cloud-runner-logger.ts @@ -10,24 +10,24 @@ class CloudRunnerLogger { } public static log(message: string) { - core.info(message); + log.info(message); } public static logWarning(message: string) { - core.warning(message); + log.warning(message); } public static logLine(message: string) { - core.info(`${message}\n`); + log.info(`${message}\n`); } public static error(message: string) { - core.error(message); + log.error(message); } public static logWithTime(message: string) { const newTimestamp = this.createTimestamp(); - core.info( + log.info( `${message} (Since previous: ${this.calculateTimeDiff( newTimestamp, this.timestamp, diff --git a/src/model/cloud-runner/services/follow-log-stream-service.ts b/src/model/cloud-runner/services/follow-log-stream-service.ts index db03cffb..513f4f33 100644 --- a/src/model/cloud-runner/services/follow-log-stream-service.ts +++ b/src/model/cloud-runner/services/follow-log-stream-service.ts @@ -9,19 +9,19 @@ export class FollowLogStreamService { CloudRunnerLogger.log('End of log transmission received'); shouldReadLogs = false; } else if (message.includes('Rebuilding Library because the asset database could not be found!')) { - core.warning('LIBRARY NOT FOUND!'); + log.warning('LIBRARY NOT FOUND!'); core.setOutput('library-found', 'false'); } else if (message.includes('Build succeeded')) { core.setOutput('build-result', 'success'); } else if (message.includes('Build fail')) { core.setOutput('build-result', 'failed'); core.setFailed('unity build failed'); - core.error('BUILD FAILED!'); + log.error('BUILD FAILED!'); } else if (CloudRunner.buildParameters.cloudRunnerIntegrationTests && message.includes(': Listening for Jobs')) { core.setOutput('cloud runner stop watching', 'true'); shouldReadLogs = false; shouldCleanup = false; - core.warning('cloud runner stop watching'); + log.warning('cloud runner stop watching'); } message = `[${CloudRunnerStatics.logPrefix}] ${message}`; if (CloudRunner.buildParameters.cloudRunnerIntegrationTests) { diff --git a/src/model/input-readers/github-cli.test.ts b/src/model/input-readers/github-cli.test.ts index b47fc29f..562fb312 100644 --- a/src/model/input-readers/github-cli.test.ts +++ b/src/model/input-readers/github-cli.test.ts @@ -7,6 +7,6 @@ describe(`github cli`, () => { const token = await GithubCliReader.GetGitHubAuthToken(); // Todo - use expect(result).toStrictEqual(something) - core.info(token); + log.info(token); }); }); diff --git a/src/model/input-readers/github-cli.ts b/src/model/input-readers/github-cli.ts index fbcf7067..d74a89e7 100644 --- a/src/model/input-readers/github-cli.ts +++ b/src/model/input-readers/github-cli.ts @@ -18,7 +18,7 @@ export class GithubCliReader { .replace(/ /g, '') .replace(/\n/g, ''); } catch (error: any) { - core.info(error || 'Failed to get github auth token from gh cli'); + log.info(error || 'Failed to get github auth token from gh cli'); return ''; } diff --git a/src/model/system.ts b/src/model/system.ts index 56519c54..bbb560b0 100644 --- a/src/model/system.ts +++ b/src/model/system.ts @@ -20,19 +20,19 @@ class System { const showOutput = () => { if (debug !== '' && shouldLog) { - core.debug(debug); + log.debug(debug); } if (result !== '' && shouldLog) { - core.info(result); + log.info(result); } if (error !== '' && shouldLog) { - core.warning(error); + log.warning(error); } }; - const throwContextualError = (message) => { + const throwContextualError = (message: string) => { let commandAsString = command; if (Array.isArray(arguments_)) { commandAsString += ` ${arguments_.join(' ')}`; diff --git a/src/model/versioning.ts b/src/model/versioning.ts index 7a5f4650..b29fa9fc 100644 --- a/src/model/versioning.ts +++ b/src/model/versioning.ts @@ -89,6 +89,8 @@ export default class Versioning { throw new ValidationError(`Versioning strategy should be one of ${Object.values(this.strategies).join(', ')}.`); } + log.info('Versioning strategy:', strategy); + let version; switch (strategy) { case this.strategies.None: @@ -107,6 +109,8 @@ export default class Versioning { throw new NotImplementedException(`Strategy ${strategy} is not implemented.`); } + log.info('Version of this build:', version); + return version; } @@ -133,7 +137,7 @@ export default class Versioning { if (!(await this.hasAnyVersionTags())) { const version = `0.0.${await this.getTotalNumberOfCommits()}`; - core.info(`Generated version ${version} (no version tags found).`); + log.info(`Generated version ${version} (no version tags found).`); return version; } @@ -146,13 +150,13 @@ export default class Versioning { const [major, minor, patch] = `${tag}.${commits}`.split('.'); const threeDigitVersion = /^\d+$/.test(patch) ? `${major}.${minor}.${patch}` : `${major}.0.${minor}`; - core.info(`Found semantic version ${threeDigitVersion} for ${this.branch}@${hash}`); + log.info(`Found semantic version ${threeDigitVersion} for ${this.branch}@${hash}`); return `${threeDigitVersion}`; } const version = `0.0.${await this.getTotalNumberOfCommits()}`; - core.info(`Generated version ${version} (semantic version couldn't be determined).`); + log.info(`Generated version ${version} (semantic version couldn't be determined).`); return version; } @@ -206,7 +210,7 @@ export default class Versioning { hash, }; } catch { - core.warning( + log.warning( `Failed to parse git describe output or version can not be determined through: "${description}".`, ); @@ -235,8 +239,10 @@ export default class Versioning { static async fetch() { try { await this.git(['fetch', '--unshallow']); - } catch (error) { - core.warning(`Fetch --unshallow caught: ${error}`); + } catch { + log.warning( + `fetch --unshallow did not work, falling back to regular fetch (which probably just means it's not running on GH actions)`, + ); await this.git(['fetch']); } } @@ -261,8 +267,8 @@ export default class Versioning { const isDirty = output !== ''; if (isDirty) { - core.warning('Changes were made to the following files and folders:\n'); - core.warning(output); + log.warning('Changes were made to the following files and folders:\n'); + log.warning(output); } return isDirty; diff --git a/src/modules/actions/exec.ts b/src/modules/actions/exec.ts index 9f818482..531b8c2a 100644 --- a/src/modules/actions/exec.ts +++ b/src/modules/actions/exec.ts @@ -1,4 +1,4 @@ -import { exec as originalExec } from 'https://deno.land/x/exec/mod.ts'; +import { exec as originalExec } from 'https://deno.land/x/exec@0.0.5/mod.ts'; import { core } from './core.ts'; export enum OutputMode { @@ -8,22 +8,34 @@ export enum OutputMode { Tee, // both dump and capture the output } -export interface IExecResponse { - code: number; +export interface ICommandResult { + status?: { + code: number; + success: boolean; + }; + output: string; +} + +export interface ISanitisedCommandResult { + exitCode: number; success: boolean; output: string; } interface IOptions { + silent?: boolean; + ignoreReturnCode?: boolean; output?: OutputMode; verbose?: boolean; continueOnError?: boolean; } // Todo - change signature of exec inside the code instead of adapting the exec method -const exec = async (command, args: string | string[] = [], ghActionsOptions: IOptions = {}): Promise => { - core.info('Running command: ', command, args); - +const exec = async ( + command: string, + args: string | string[] = [], + ghActionsOptions: IOptions = {}, +): Promise => { const options = { output: OutputMode.Tee, verbose: false, @@ -31,16 +43,20 @@ const exec = async (command, args: string | string[] = [], ghActionsOptions: IOp }; const { silent = false, ignoreReturnCode } = ghActionsOptions; - if (silent) options.output = OutputMode.None; + if (silent) options.output = OutputMode.Capture; if (ignoreReturnCode) options.continueOnError = true; - const result = await originalExec(`${command} ${args.join(' ')}`, options); - core.info('result:', result); + const argsString = typeof args === 'string' ? args : args.join(' '); + log.debug('Command: ', command, argsString); - const { status = {}, output = '' } = result; + const result: ICommandResult = await originalExec(`${command} ${argsString}`, options); + + log.debug('Result:', result); + + const { status, output = '' } = result; const { code: exitCode, success } = status; - return { exitCode, success, output }; + return { exitCode, success, output: output.trim() }; }; export { exec };