Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into command-naming-cons…
Browse files Browse the repository at this point in the history
…istency
  • Loading branch information
0x2b3bfa0 committed Aug 18, 2022
2 parents c29c69e + d6c9a01 commit 08f4dc5
Show file tree
Hide file tree
Showing 33 changed files with 2,171 additions and 3,960 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ RUN add-apt-repository universe --yes \
&& apt-get clean \
&& rm --recursive --force /var/lib/apt/lists/* \
&& npm config set user 0 \
&& npm install --global canvas@2 vega@5 vega-cli@5 vega-lite@4
&& npm install --global canvas@2 vega@5 vega-cli@5 vega-lite@5

# CONFIGURE RUNNER PATH
ENV CML_RUNNER_PATH=/home/runner
Expand Down
147 changes: 80 additions & 67 deletions bin/cml.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,36 @@ const which = require('which');
const winston = require('winston');
const yargs = require('yargs');

const configureLogger = (level) => {
const CML = require('../src/cml').default;
const { jitsuEventPayload, send } = require('../src/analytics');

const setupOpts = (opts) => {
const legacyEnvironmentVariables = {
TB_CREDENTIALS: 'CML_TENSORBOARD_DEV_CREDENTIALS',
DOCKER_MACHINE: 'CML_RUNNER_DOCKER_MACHINE',
RUNNER_IDLE_TIMEOUT: 'CML_RUNNER_IDLE_TIMEOUT',
RUNNER_LABELS: 'CML_RUNNER_LABELS',
RUNNER_SINGLE: 'CML_RUNNER_SINGLE',
RUNNER_REUSE: 'CML_RUNNER_REUSE',
RUNNER_NO_RETRY: 'CML_RUNNER_NO_RETRY',
RUNNER_DRIVER: 'CML_RUNNER_DRIVER',
RUNNER_REPO: 'CML_RUNNER_REPO',
RUNNER_PATH: 'CML_RUNNER_PATH'
};

for (const [oldName, newName] of Object.entries(legacyEnvironmentVariables)) {
if (process.env[oldName]) process.env[newName] = process.env[oldName];
}

const { markdownfile } = opts;
opts.markdownFile = markdownfile;
opts.cmlCommand = opts._[0];
opts.cml = new CML(opts);
};

const setupLogger = (opts) => {
const { log: level } = opts;

winston.configure({
format: process.stdout.isTTY
? winston.format.combine(
Expand All @@ -29,79 +58,63 @@ const configureLogger = (level) => {
});
};

const setupTelemetry = async (opts) => {
const { cml, cmlCommand: action } = opts;
opts.telemetryEvent = await jitsuEventPayload({ action, cml });
};

const runPlugin = async ({ $0: executable, command }) => {
try {
if (command === undefined) throw new Error('no command');
const path = which.sync(`${basename(executable)}-${command}`);
const parameters = process.argv.slice(process.argv.indexOf(command) + 1); // HACK
process.exit(await pseudoexec(path, parameters));
} catch (error) {
yargs.showHelp();
winston.debug(error);
}
if (command === undefined) throw new Error('no command');
const { argv } = process.argv;
const path = which.sync(`${basename(executable)}-${command}`);
const parameters = argv.slice(argv.indexOf(command) + 1); // HACK
await pseudoexec(path, parameters);
};

const handleError = (message, error) => {
if (error) {
winston.error(error);
} else {
if (!error) {
yargs.showHelp();
console.error('\n' + message);
}
process.exit(1);
};

exports.options = {
log: {
type: 'string',
description: 'Maximum log level',
coerce: (value) => configureLogger(value) && value,
choices: ['error', 'warn', 'info', 'debug'],
default: 'info'
},
driver: {
type: 'string',
choices: ['github', 'gitlab', 'bitbucket'],
defaultDescription: 'infer from the environment',
description: 'Forge where the repository is hosted'
},
repo: {
type: 'string',
defaultDescription: 'infer from the environment',
description: 'Repository URL or slug'
},
token: {
type: 'string',
defaultDescription: 'infer from the environment',
description: 'Personal access token'
process.exit(1);
}
};

const legacyEnvironmentVariables = {
TB_CREDENTIALS: 'CML_TENSORBOARD_DEV_CREDENTIALS',
DOCKER_MACHINE: 'CML_RUNNER_DOCKER_MACHINE',
RUNNER_IDLE_TIMEOUT: 'CML_RUNNER_IDLE_TIMEOUT',
RUNNER_LABELS: 'CML_RUNNER_LABELS',
RUNNER_SINGLE: 'CML_RUNNER_SINGLE',
RUNNER_REUSE: 'CML_RUNNER_REUSE',
RUNNER_NO_RETRY: 'CML_RUNNER_NO_RETRY',
RUNNER_DRIVER: 'CML_RUNNER_DRIVER',
RUNNER_REPO: 'CML_RUNNER_REPO',
RUNNER_PATH: 'CML_RUNNER_PATH'
};

for (const [oldName, newName] of Object.entries(legacyEnvironmentVariables)) {
if (process.env[oldName]) process.env[newName] = process.env[oldName];
}
(async () => {
try {
await yargs
.env('CML')
.options({
log: {
type: 'string',
description: 'Maximum log level',
choices: ['error', 'warn', 'info', 'debug'],
default: 'info'
}
})
.fail(handleError)
.middleware(setupOpts)
.middleware(setupLogger)
.middleware(setupTelemetry)
.commandDir('./cml')
.commandDir('./legacy')
.command(
'$0 <command>',
false,
(builder) => builder.strict(false),
runPlugin
)
.recommendCommands()
.demandCommand()
.strict()
.parse();

yargs
.fail(handleError)
.env('CML')
.options(exports.options)
.commandDir('./cml')
.commandDir('./legacy')
.command('$0 <command>', false, (builder) => builder.strict(false), runPlugin)
.recommendCommands()
.demandCommand()
.strict()
.parse();
const { telemetryEvent } = yargs.parsed.argv;
await send({ event: telemetryEvent });
} catch (err) {
const { telemetryEvent } = yargs.parsed.argv;
const event = { ...telemetryEvent, error: err.message };
await send({ event });
winston.error({ err });
process.exit(1);
}
})();
10 changes: 2 additions & 8 deletions bin/cml.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,15 @@ describe('command-line interface tests', () => {
cml.js pr <glob path...> Manage pull requests
cml.js report Manage reports
cml.js repository Manage repository settings
cml.js runner Manage self-hosted (cloud & on-premise) CI runners
cml.js runner Manage continuous integration self-hosted runners
cml.js tensorboard Manage tensorboard.dev agents
cml.js workflow Manage continuous integration workflows
Options:
--help Show help [boolean]
--version Show version number [boolean]
--log Maximum log level
[string] [choices: \\"error\\", \\"warn\\", \\"info\\", \\"debug\\"] [default: \\"info\\"]
--driver Forge where the repository is hosted
[string] [choices: \\"github\\", \\"gitlab\\", \\"bitbucket\\"] [default: infer from the
environment]
--repo Repository URL or slug
[string] [default: infer from the environment]
--token Personal access token[string] [default: infer from the environment]"
[string] [choices: \\"error\\", \\"warn\\", \\"info\\", \\"debug\\"] [default: \\"info\\"]"
`);
});
});
44 changes: 25 additions & 19 deletions bin/cml/attachment/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,68 +2,74 @@ const fs = require('fs').promises;
const kebabcaseKeys = require('kebabcase-keys');
const winston = require('winston');

const CML = require('../../../src/cml').default;
const { CML, repoOptions } = require('../../../src/cml');

exports.command = 'publish <asset>';
exports.description = 'publish an asset';
exports.description = 'Publish an asset';

exports.handler = async (opts) => {
if (opts.gitlabUploads) {
winston.warn(
'--gitlab-uploads will be deprecated soon, use --native instead'
'--gitlab-uploads will be deprecated soon. Use --native instead.'
);
opts.native = true;
}

const { file, repo, native } = opts;

const path = opts.asset;
const { file, repo, native, asset: path } = opts;
const cml = new CML({ ...opts, repo: native ? repo : 'cml' });

const output = await cml.publish({
...opts,
path
});
const output = await cml.publish({ ...opts, path });

if (!file) console.log(output);
else await fs.writeFile(file, output);
};

exports.builder = (yargs) => yargs.env('CML_PUBLISH').options(exports.options);
exports.builder = (yargs) =>
yargs.env('CML_ATTACHMENT').options(exports.options);

exports.options = kebabcaseKeys({
...repoOptions,
url: {
type: 'string',
description: 'Self-Hosted URL',
hidden: true
},
md: {
type: 'boolean',
description: 'Output in markdown format [title || name](url)'
description: 'Output in markdown format [title || name](url).'
},
title: {
type: 'string',
alias: 't',
description: 'Markdown title [title](url) or ![](url title)'
description: 'Markdown title [title](url) or ![](url title).'
},
native: {
type: 'boolean',
description:
"Uses driver's native capabilities to upload assets instead of CML's storage; not available on GitHub"
"Uses driver's native capabilities to upload assets instead of CML's storage. Not available on GitHub."
},
gitlabUploads: {
type: 'boolean',
hidden: true
},
rmWatermark: {
type: 'boolean',
description: 'Avoid CML watermark'
description: 'Avoid CML watermark.'
},
mimeType: {
type: 'string',
defaultDescription: 'infer from the file contents',
description: 'MIME type'
description:
'Specifies the mime-type. If not set guess it from the content.'
},
file: {
type: 'string',
alias: 'f',
description:
'Append the output to the given file or create it if does not exist',
'Append the output to the given file. Create it if does not exist.',
hidden: true
},
repo: {
type: 'string',
description:
'Specifies the repo to be used. If not specified is extracted from the CI ENV.'
}
});
26 changes: 13 additions & 13 deletions bin/cml/attachment/publish.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ describe('CML e2e', () => {
--version Show version number [boolean]
--log Maximum log level
[string] [choices: \\"error\\", \\"warn\\", \\"info\\", \\"debug\\"] [default: \\"info\\"]
--driver Forge where the repository is hosted
[string] [choices: \\"github\\", \\"gitlab\\", \\"bitbucket\\"] [default: infer from the
environment]
--repo Repository URL or slug
[string] [default: infer from the environment]
--token Personal access token
[string] [default: infer from the environment]
--md Output in markdown format [title || name](url) [boolean]
-t, --title Markdown title [title](url) or ![](url title) [string]
--repo Specifies the repo to be used. If not specified is
extracted from the CI ENV. [string]
--token Personal access token to be used. If not specified is
extracted from ENV REPO_TOKEN. [string]
--driver If not specify it infers it from the ENV.
[string] [choices: \\"github\\", \\"gitlab\\", \\"bitbucket\\"]
--md Output in markdown format [title || name](url). [boolean]
-t, --title Markdown title [title](url) or ![](url title). [string]
--native Uses driver's native capabilities to upload assets instead
of CML's storage; not available on GitHub [boolean]
--rm-watermark Avoid CML watermark [boolean]
--mime-type MIME type [string] [default: infer from the file contents]"
of CML's storage. Not available on GitHub. [boolean]
--rm-watermark Avoid CML watermark. [boolean]
--mime-type Specifies the mime-type. If not set guess it from the
content. [string]"
`);
});

Expand Down Expand Up @@ -88,7 +88,7 @@ describe('CML e2e', () => {
);

expect(output.startsWith('https://')).toBe(true);
expect(output.endsWith('json')).toBe(true);
expect(output.includes('cml=json')).toBe(true);
});

test('cml publish assets/test.svg in Gitlab storage', async () => {
Expand Down
26 changes: 15 additions & 11 deletions bin/cml/check/create.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
const fs = require('fs').promises;
const kebabcaseKeys = require('kebabcase-keys');
const CML = require('../../../src/cml').default;

const { repoOptions } = require('../../../src/cml');

exports.command = 'create <markdown file>';
exports.description = 'Create a check report';

exports.handler = async (opts) => {
const path = opts.markdownfile;
const report = await fs.readFile(path, 'utf-8');
const cml = new CML({ ...opts });
const { cml, markdownfile } = opts;
const report = await fs.readFile(markdownfile, 'utf-8');
await cml.checkCreate({ ...opts, report });
};

exports.builder = (yargs) =>
yargs.env('CML_SEND_GITHUB_CHECK').options(exports.options);
exports.builder = (yargs) => yargs.env('CML_CHECK').options(exports.options);

exports.options = kebabcaseKeys({
...repoOptions,
token: {
type: 'string',
description:
"GITHUB_TOKEN or Github App token. Personal access token won't work"
},
commitSha: {
type: 'string',
alias: 'head-sha',
defaultDescription: 'HEAD',
description: 'Commit SHA linked to this comment'
description: 'Commit SHA linked to this comment. Defaults to HEAD.'
},
conclusion: {
type: 'string',
Expand All @@ -33,17 +37,17 @@ exports.options = kebabcaseKeys({
'timed_out'
],
default: 'success',
description: 'Conclusion status of the check'
description: 'Sets the conclusion status of the check.'
},
status: {
type: 'string',
choices: ['queued', 'in_progress', 'completed'],
default: 'completed',
description: 'Status of the check'
description: 'Sets the status of the check.'
},
title: {
type: 'string',
default: 'CML Report',
description: 'Title of the check'
description: 'Sets title of the check.'
}
});
Loading

1 comment on commit 08f4dc5

@0x2b3bfa0
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test Comment

CML watermark

Please sign in to comment.