Skip to content

Commit

Permalink
Introduce subcommands in a backwards-compatible way (#1073)
Browse files Browse the repository at this point in the history
Co-authored-by: Casper da Costa-Luis <[email protected]>
Co-authored-by: Daniel Barnes <[email protected]>
  • Loading branch information
3 people authored Sep 6, 2022
1 parent 4ade9a5 commit 341f32e
Show file tree
Hide file tree
Showing 48 changed files with 1,462 additions and 1,398 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
node_modules/
runner/
.terraform/
.cml/
.DS_Store
Expand Down
56 changes: 50 additions & 6 deletions bin/cml.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,24 @@ const setupOpts = (opts) => {
if (process.env[oldName]) process.env[newName] = process.env[oldName];
}

const legacyEnvironmentPrefixes = {
CML_CI: 'CML_REPO',
CML_PUBLISH: 'CML_ASSET',
CML_RERUN_WORKFLOW: 'CML_WORKFLOW',
CML_SEND_COMMENT: 'CML_COMMENT',
CML_SEND_GITHUB_CHECK: 'CML_CHECK',
CML_TENSORBOARD_DEV: 'CML_TENSORBOARD'
};

for (const [oldPrefix, newPrefix] of Object.entries(
legacyEnvironmentPrefixes
)) {
for (const key in process.env) {
if (key.startsWith(`${oldPrefix}_`))
process.env[key.replace(oldPrefix, newPrefix)] = process.env[key];
}
}

const { markdownfile } = opts;
opts.markdownFile = markdownfile;
opts.cmlCommand = opts._[0];
Expand Down Expand Up @@ -80,22 +98,46 @@ const handleError = (message, error) => {
};

(async () => {
setupLogger({ log: 'debug' });
try {
await yargs
.env('CML')
.options({
log: {
type: 'string',
description: 'Maximum log level',
description: 'Logging verbosity',
choices: ['error', 'warn', 'info', 'debug'],
default: 'info'
default: 'info',
group: 'Global Options:'
},
driver: {
type: 'string',
choices: ['github', 'gitlab', 'bitbucket'],
defaultDescription: 'infer from the environment',
description: 'Git provider where the repository is hosted',
group: 'Global Options:'
},
repo: {
type: 'string',
defaultDescription: 'infer from the environment',
description: 'Repository URL or slug',
group: 'Global Options:'
},
token: {
type: 'string',
defaultDescription: 'infer from the environment',
description: 'Personal access token',
group: 'Global Options:'
}
})
.global('version', false)
.group('help', 'Global Options:')
.fail(handleError)
.middleware(setupOpts)
.middleware(setupLogger)
.middleware(setupTelemetry)
.commandDir('./cml', { exclude: /\.test\.js$/ })
.commandDir('./cml')
.commandDir('./legacy/commands')
.command(
'$0 <command>',
false,
Expand All @@ -110,9 +152,11 @@ const handleError = (message, error) => {
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 });
if (yargs.parsed.argv) {
const { telemetryEvent } = yargs.parsed.argv;
const event = { ...telemetryEvent, error: err.message };
await send({ event });
}
winston.error({ err });
process.exit(1);
}
Expand Down
33 changes: 18 additions & 15 deletions bin/cml.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,26 @@ describe('command-line interface tests', () => {
"cml.js <command>
Commands:
cml.js ci Fixes specific CI setups
cml.js pr <glob path...> Create a pull request with the
specified files
cml.js publish <asset> Upload an image to build a report
cml.js rerun-workflow Reruns a workflow given the jobId or
workflow Id
cml.js runner Launch and register a self-hosted
runner
cml.js send-comment <markdown file> Comment on a commit
cml.js send-github-check <markdown file> Create a check report
cml.js tensorboard-dev Get a tensorboard link
cml.js check Manage CI checks
cml.js comment Manage comments
cml.js pr <glob path...> Manage pull requests
cml.js runner Manage self-hosted (cloud & on-premise) CI runners
cml.js tensorboard Manage tensorboard.dev connections
cml.js workflow Manage CI workflows
cml.js ci Prepare Git repository for CML operations
Global Options:
--log Logging verbosity
[string] [choices: \\"error\\", \\"warn\\", \\"info\\", \\"debug\\"] [default: \\"info\\"]
--driver Git provider 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]
--help Show help [boolean]
Options:
--help Show help [boolean]
--version Show version number [boolean]
--log Maximum log level
[string] [choices: \\"error\\", \\"warn\\", \\"info\\", \\"debug\\"] [default: \\"info\\"]"
--version Show version number [boolean]"
`);
});
});
8 changes: 8 additions & 0 deletions bin/cml/asset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
exports.command = 'asset';
exports.description = false;
exports.builder = (yargs) =>
yargs
.commandDir('./asset', { exclude: /\.test\.js$/ })
.recommendCommands()
.demandCommand()
.strict();
73 changes: 73 additions & 0 deletions bin/cml/asset/publish.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
const fs = require('fs').promises;
const kebabcaseKeys = require('kebabcase-keys');
const winston = require('winston');

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

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

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

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

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

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

exports.options = kebabcaseKeys({
url: {
type: 'string',
description: 'Self-Hosted URL',
hidden: true
},
md: {
type: 'boolean',
description: 'Output in markdown format [title || name](url)'
},
title: {
type: 'string',
alias: 't',
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"
},
gitlabUploads: {
type: 'boolean',
hidden: true
},
rmWatermark: {
type: 'boolean',
description: 'Avoid CML watermark.'
},
mimeType: {
type: 'string',
defaultDescription: 'infer from the file contents',
description: 'MIME type'
},
file: {
type: 'string',
alias: 'f',
description:
'Append the output to the given file or 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.'
}
});
33 changes: 16 additions & 17 deletions bin/cml/publish.test.js → bin/cml/asset/publish.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const fs = require('fs');
const { exec } = require('../../src/utils');
const { exec } = require('../../../src/utils');

describe('CML e2e', () => {
test('cml publish --help', async () => {
Expand All @@ -8,26 +8,25 @@ describe('CML e2e', () => {
expect(output).toMatchInlineSnapshot(`
"cml.js publish <asset>
Upload an image to build a report
Global Options:
--log Logging verbosity
[string] [choices: \\"error\\", \\"warn\\", \\"info\\", \\"debug\\"] [default: \\"info\\"]
--driver Git provider where the repository is hosted
[string] [choices: \\"github\\", \\"gitlab\\", \\"bitbucket\\"] [default: infer from the
environment]
--repo Specifies the repo to be used. If not specified is extracted
from the CI ENV. [string] [default: infer from the environment]
--token Personal access token
[string] [default: infer from the environment]
--help Show help [boolean]
Options:
--help Show help [boolean]
--version Show version number [boolean]
--log Maximum log level
[string] [choices: \\"error\\", \\"warn\\", \\"info\\", \\"debug\\"] [default: \\"info\\"]
--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]
--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]
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]"
--mime-type MIME type [string] [default: infer from the file contents]"
`);
});

Expand Down
8 changes: 8 additions & 0 deletions bin/cml/check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
exports.command = 'check';
exports.description = 'Manage CI checks';
exports.builder = (yargs) =>
yargs
.commandDir('./check', { exclude: /\.test\.js$/ })
.recommendCommands()
.demandCommand()
.strict();
51 changes: 51 additions & 0 deletions bin/cml/check/create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const fs = require('fs').promises;
const kebabcaseKeys = require('kebabcase-keys');

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

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

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

exports.options = kebabcaseKeys({
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'
},
conclusion: {
type: 'string',
choices: [
'success',
'failure',
'neutral',
'cancelled',
'skipped',
'timed_out'
],
default: 'success',
description: 'Conclusion status of the check'
},
status: {
type: 'string',
choices: ['queued', 'in_progress', 'completed'],
default: 'completed',
description: 'Status of the check'
},
title: {
type: 'string',
default: 'CML Report',
description: 'Title of the check'
}
});
34 changes: 16 additions & 18 deletions bin/cml/send-github-check.test.js → bin/cml/check/create.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { exec } = require('../../src/utils');
const { exec } = require('../../../src/utils');
const fs = require('fs').promises;

describe('CML e2e', () => {
Expand Down Expand Up @@ -36,29 +36,27 @@ describe('CML e2e', () => {
expect(output).toMatchInlineSnapshot(`
"cml.js send-github-check <markdown file>
Create a check report
Global Options:
--log Logging verbosity
[string] [choices: \\"error\\", \\"warn\\", \\"info\\", \\"debug\\"] [default: \\"info\\"]
--driver Git provider 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 GITHUB_TOKEN or Github App token. Personal access token won't work
[string] [default: infer from the environment]
--help Show help [boolean]
Options:
--help Show help [boolean]
--version Show version number [boolean]
--log Maximum log level
[string] [choices: \\"error\\", \\"warn\\", \\"info\\", \\"debug\\"] [default: \\"info\\"]
--repo Specifies the repo to be used. If not specified is
extracted from the CI ENV. [string]
--token GITHUB_TOKEN or Github App token. Personal access
token won't work [string]
--driver If not specify it infers it from the ENV.
[string] [choices: \\"github\\", \\"gitlab\\", \\"bitbucket\\"]
--commit-sha, --head-sha Commit SHA linked to this comment. Defaults to HEAD.
[string]
--conclusion Sets the conclusion status of the check.
--commit-sha, --head-sha Commit SHA linked to this comment
[string] [default: HEAD]
--conclusion Conclusion status of the check
[string] [choices: \\"success\\", \\"failure\\", \\"neutral\\", \\"cancelled\\", \\"skipped\\",
\\"timed_out\\"] [default: \\"success\\"]
--status Sets the status of the check.
--status Status of the check
[string] [choices: \\"queued\\", \\"in_progress\\", \\"completed\\"] [default:
\\"completed\\"]
--title Sets title of the check.
[string] [default: \\"CML Report\\"]"
--title Title of the check [string] [default: \\"CML Report\\"]"
`);
});
});
Loading

0 comments on commit 341f32e

Please sign in to comment.