From ee8d4c5540afcaa66588ac69557c82a69eac1188 Mon Sep 17 00:00:00 2001 From: Daniel Barnes Date: Wed, 19 Oct 2022 10:59:22 -0700 Subject: [PATCH 01/11] Provide Docs URLs in `--help` messaging (#1232) * initial setup * npm run do_snapshots * now with a test * Update bin/cml.test.js --- bin/cml.test.js | 19 +++++++++++++++++++ bin/cml/asset/publish.js | 6 +++++- bin/cml/check/create.js | 6 +++++- bin/cml/comment/create.js | 6 +++++- bin/cml/comment/update.js | 6 +++++- bin/cml/pr/create.e2e.test.js | 1 + bin/cml/pr/create.js | 6 +++++- bin/cml/repo/prepare.js | 6 +++++- bin/cml/runner/launch.js | 6 +++++- bin/cml/runner/launch.test.js | 1 + bin/cml/tensorboard/connect.js | 7 ++++++- bin/cml/workflow/rerun.js | 7 ++++++- package-lock.json | 2 +- 13 files changed, 69 insertions(+), 10 deletions(-) diff --git a/bin/cml.test.js b/bin/cml.test.js index 612fed3ab..2af1b3d84 100644 --- a/bin/cml.test.js +++ b/bin/cml.test.js @@ -1,4 +1,5 @@ const { exec } = require('../src/utils'); +const fetch = require('node-fetch'); describe('command-line interface tests', () => { test('cml --help', async () => { @@ -31,3 +32,21 @@ describe('command-line interface tests', () => { `); }); }); + +describe('Valid Docs URLs', () => { + test.each([ + 'workflow/rerun', + 'tensorboard/connect', + 'runner/launch', + 'repo/prepare', + 'pr/create', + 'comment/create', + 'comment/update', + 'check/create', + 'asset/publish' + ])('Check Docs Link', async (cmd) => { + const { DOCSURL } = require(`./cml/${cmd}`); + const { status } = await fetch(DOCSURL); + expect(status).toBe(200); + }); +}); diff --git a/bin/cml/asset/publish.js b/bin/cml/asset/publish.js index 09fce8e20..1d09e12b8 100644 --- a/bin/cml/asset/publish.js +++ b/bin/cml/asset/publish.js @@ -4,8 +4,11 @@ const winston = require('winston'); const { CML } = require('../../../src/cml'); +const DESCRIPTION = 'Publish an asset'; +const DOCSURL = 'https://cml.dev/doc/usage#cml-reports'; + exports.command = 'publish '; -exports.description = 'Publish an asset'; +exports.description = `${DESCRIPTION}\n${DOCSURL}`; exports.handler = async (opts) => { if (opts.gitlabUploads) { @@ -76,3 +79,4 @@ exports.options = kebabcaseKeys({ 'Specifies the repo to be used. If not specified is extracted from the CI ENV.' } }); +exports.DOCSURL = DOCSURL; diff --git a/bin/cml/check/create.js b/bin/cml/check/create.js index 89ebcea9b..7eb86d978 100755 --- a/bin/cml/check/create.js +++ b/bin/cml/check/create.js @@ -1,8 +1,11 @@ const fs = require('fs').promises; const kebabcaseKeys = require('kebabcase-keys'); +const DESCRIPTION = 'Create a check report'; +const DOCSURL = 'https://cml.dev/doc/ref/check'; + exports.command = 'create '; -exports.description = 'Create a check report'; +exports.description = `${DESCRIPTION}\n${DOCSURL}`; exports.handler = async (opts) => { const { cml, markdownfile } = opts; @@ -53,3 +56,4 @@ exports.options = kebabcaseKeys({ description: 'Title of the check' } }); +exports.DOCSURL = DOCSURL; diff --git a/bin/cml/comment/create.js b/bin/cml/comment/create.js index c0dea33c8..1c3d110f0 100644 --- a/bin/cml/comment/create.js +++ b/bin/cml/comment/create.js @@ -1,7 +1,10 @@ const kebabcaseKeys = require('kebabcase-keys'); +const DESCRIPTION = 'Create a comment'; +const DOCSURL = 'https://cml.dev/doc/ref/comment#create'; + exports.command = 'create '; -exports.description = 'Create a comment'; +exports.description = `${DESCRIPTION}\n${DOCSURL}`; exports.handler = async (opts) => { const { cml } = opts; @@ -66,3 +69,4 @@ exports.options = kebabcaseKeys({ telemetryData: 'name' } }); +exports.DOCSURL = DOCSURL; diff --git a/bin/cml/comment/update.js b/bin/cml/comment/update.js index adfdb6483..2fddae716 100644 --- a/bin/cml/comment/update.js +++ b/bin/cml/comment/update.js @@ -1,10 +1,14 @@ const { builder, handler } = require('./create'); +const DESCRIPTION = 'Update a comment'; +const DOCSURL = 'https://cml.dev/doc/ref/comment#update'; + exports.command = 'update '; -exports.description = 'Update a comment'; +exports.description = `${DESCRIPTION}\n${DOCSURL}`; exports.handler = async (opts) => { await handler({ ...opts, update: true }); }; exports.builder = builder; +exports.DOCSURL = DOCSURL; diff --git a/bin/cml/pr/create.e2e.test.js b/bin/cml/pr/create.e2e.test.js index 86a7fd446..f2d669799 100644 --- a/bin/cml/pr/create.e2e.test.js +++ b/bin/cml/pr/create.e2e.test.js @@ -12,6 +12,7 @@ describe('CML e2e', () => { Commands: cml.js pr create Create a pull request with the specified files + https://cml.dev/doc/ref/pr Global Options: --log Logging verbosity diff --git a/bin/cml/pr/create.js b/bin/cml/pr/create.js index dc98eda9c..7a68a2801 100755 --- a/bin/cml/pr/create.js +++ b/bin/cml/pr/create.js @@ -6,8 +6,11 @@ const { GIT_USER_EMAIL } = require('../../../src/cml'); +const DESCRIPTION = 'Create a pull request with the specified files'; +const DOCSURL = 'https://cml.dev/doc/ref/pr'; + exports.command = 'create '; -exports.description = 'Create a pull request with the specified files'; +exports.description = `${DESCRIPTION}\n${DOCSURL}`; exports.handler = async (opts) => { const { cml, globpath: globs } = opts; @@ -78,3 +81,4 @@ exports.options = kebabcaseKeys({ description: 'Git user name' } }); +exports.DOCSURL = DOCSURL; diff --git a/bin/cml/repo/prepare.js b/bin/cml/repo/prepare.js index 302f75c5c..a8943f4ce 100644 --- a/bin/cml/repo/prepare.js +++ b/bin/cml/repo/prepare.js @@ -2,8 +2,11 @@ const kebabcaseKeys = require('kebabcase-keys'); const { GIT_USER_NAME, GIT_USER_EMAIL } = require('../../../src/cml'); +const DESCRIPTION = 'Prepare the cloned repository'; +const DOCSURL = 'https://cml.dev/doc/ref/ci'; + exports.command = 'prepare'; -exports.description = 'Prepare the cloned repository'; +exports.description = `${DESCRIPTION}\n${DOCSURL}`; exports.handler = async (opts) => { const { cml } = opts; @@ -33,3 +36,4 @@ exports.options = kebabcaseKeys({ description: 'Git user name' } }); +exports.DOCSURL = DOCSURL; diff --git a/bin/cml/runner/launch.js b/bin/cml/runner/launch.js index c4bbc28ad..07482b725 100755 --- a/bin/cml/runner/launch.js +++ b/bin/cml/runner/launch.js @@ -404,8 +404,11 @@ const run = async (opts) => { else await runLocal(opts); }; +const DESCRIPTION = 'Launch and register a self-hosted runner'; +const DOCSURL = 'https://cml.dev/doc/ref/runner'; + exports.command = 'launch'; -exports.description = 'Launch and register a self-hosted runner'; +exports.description = `${DESCRIPTION}\n${DOCSURL}`; exports.handler = async (opts) => { ({ cml } = opts); @@ -579,3 +582,4 @@ exports.options = kebabcaseKeys({ 'Seconds to wait for collecting logs on failure (https://github.com/iterative/cml/issues/413)' } }); +exports.DOCSURL = DOCSURL; diff --git a/bin/cml/runner/launch.test.js b/bin/cml/runner/launch.test.js index 9dd29db73..8034c8b65 100644 --- a/bin/cml/runner/launch.test.js +++ b/bin/cml/runner/launch.test.js @@ -11,6 +11,7 @@ describe('CML e2e', () => { Commands: cml.js runner launch Launch and register a self-hosted runner + https://cml.dev/doc/ref/runner Global Options: --log Logging verbosity diff --git a/bin/cml/tensorboard/connect.js b/bin/cml/tensorboard/connect.js index 7e0b073f3..b0fac3c67 100644 --- a/bin/cml/tensorboard/connect.js +++ b/bin/cml/tensorboard/connect.js @@ -73,8 +73,12 @@ const launchAndWaitLink = async (opts = {}) => { }; exports.tbLink = tbLink; + +const DESCRIPTION = 'Connect to tensorboard.dev and get a link'; +const DOCSURL = 'https://cml.dev/doc/ref/tensorboard'; + exports.command = 'connect'; -exports.description = 'Connect to tensorboard.dev and get a link'; +exports.description = `${DESCRIPTION}\n${DOCSURL}`; exports.handler = async (opts) => { const { file, credentials, name, description } = opts; @@ -144,3 +148,4 @@ exports.options = kebabcaseKeys({ telemetryData: 'name' } }); +exports.DOCSURL = DOCSURL; diff --git a/bin/cml/workflow/rerun.js b/bin/cml/workflow/rerun.js index 40639434f..4d9b43485 100644 --- a/bin/cml/workflow/rerun.js +++ b/bin/cml/workflow/rerun.js @@ -1,7 +1,10 @@ const kebabcaseKeys = require('kebabcase-keys'); +const DESCRIPTION = 'Rerun a workflow given the jobId or workflowId'; +const DOCSURL = 'https://cml.dev/doc/ref/workflow'; + exports.command = 'rerun'; -exports.description = 'Rerun a workflow given the jobId or workflowId'; +exports.description = `${DESCRIPTION}\n${DOCSURL}`; exports.handler = async (opts) => { const { cml } = opts; @@ -20,3 +23,5 @@ exports.options = kebabcaseKeys({ description: 'Run identifier to be rerun' } }); + +exports.DOCSURL = DOCSURL; diff --git a/package-lock.json b/package-lock.json index 8e9a76296..b0e9d91d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "git-url-parse": "^13.1.0", "globby": "^11.0.4", "https-proxy-agent": "^5.0.1", - "is-docker": "^2.2.1", + "is-docker": "2.2.1", "js-base64": "^3.7.2", "kebabcase-keys": "^1.0.0", "node-fetch": "^2.6.5", From f8384a14921a8c9224dbdedcd1f3d19d5badba39 Mon Sep 17 00:00:00 2001 From: Helio Machado <0x2b3bfa0+git@googlemail.com> Date: Wed, 26 Oct 2022 00:13:55 +0200 Subject: [PATCH 02/11] Exclude `error` from successful analytics payloads (#1236) --- src/analytics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analytics.js b/src/analytics.js index bb810f3be..163f53e6d 100644 --- a/src/analytics.js +++ b/src/analytics.js @@ -145,7 +145,7 @@ const OS = () => { const jitsuEventPayload = async ({ action = '', - error = '', + error, extra = {}, cml } = {}) => { From cbfa46b5e0111ff80f9249a250c8bb78d85c675e Mon Sep 17 00:00:00 2001 From: "Olivaw[bot]" <64868532+iterative-olivaw@users.noreply.github.com> Date: Wed, 26 Oct 2022 00:20:14 +0200 Subject: [PATCH 03/11] 0.18.7 (#1237) --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b0e9d91d9..278a86b8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@dvcorg/cml", - "version": "0.18.6", + "version": "0.18.7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@dvcorg/cml", - "version": "0.18.6", + "version": "0.18.7", "license": "Apache-2.0", "dependencies": { "@actions/core": "^1.9.1", diff --git a/package.json b/package.json index 431ffebde..6e228598c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dvcorg/cml", - "version": "0.18.6", + "version": "0.18.7", "description": "

", "author": { "name": "Iterative Inc", From 150a0eb5479e33877c670adb5ad88b3bd03d97d0 Mon Sep 17 00:00:00 2001 From: Domas Monkus Date: Wed, 26 Oct 2022 21:58:25 +0300 Subject: [PATCH 04/11] Configure winston logging when running terraform tests. (#1238) Otherwise warnings are printed about unconfigured transports. --- src/terraform.test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/terraform.test.js b/src/terraform.test.js index 8299f0ba3..e61a72ff2 100644 --- a/src/terraform.test.js +++ b/src/terraform.test.js @@ -1,6 +1,18 @@ +const winston = require('winston'); const { iterativeCmlRunnerTpl } = require('./terraform'); describe('Terraform tests', () => { + beforeAll(() => { + winston.configure({ + transports: [ + new winston.transports.Console({ + level: 'error', + handleExceptions: true + }) + ] + }); + }); + test('default options', async () => { const output = iterativeCmlRunnerTpl({}); expect(JSON.stringify(output, null, 2)).toMatchInlineSnapshot(` From b6c5bd6cf0af6bda474721e4cc65a7b274a6d76d Mon Sep 17 00:00:00 2001 From: Deepyaman Datta Date: Wed, 26 Oct 2022 16:53:14 -0400 Subject: [PATCH 05/11] Hide `--rm-watermark` option when invoking CML CLI (#1235) * Hide `--rm-watermark` flag on `cml comment create` * Update create.test.js * Update connect.js * Update connect.test.js * Update publish.js * Update publish.test.js * Update publish.test.js * Update connect.test.js Co-authored-by: Daniel Barnes --- bin/cml/asset/publish.js | 1 + bin/cml/asset/publish.test.js | 11 +++++------ bin/cml/comment/create.js | 1 + bin/cml/comment/create.test.js | 4 +--- bin/cml/tensorboard/connect.js | 1 + bin/cml/tensorboard/connect.test.js | 19 +++++++++---------- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/bin/cml/asset/publish.js b/bin/cml/asset/publish.js index 1d09e12b8..fa07e165d 100644 --- a/bin/cml/asset/publish.js +++ b/bin/cml/asset/publish.js @@ -59,6 +59,7 @@ exports.options = kebabcaseKeys({ rmWatermark: { type: 'boolean', description: 'Avoid CML watermark.', + hidden: true, telemetryData: 'name' }, mimeType: { diff --git a/bin/cml/asset/publish.test.js b/bin/cml/asset/publish.test.js index 0d130912d..f210666bf 100644 --- a/bin/cml/asset/publish.test.js +++ b/bin/cml/asset/publish.test.js @@ -20,12 +20,11 @@ describe('CML cli test', () => { --help Show help [boolean] Options: - --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]" + --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] + --mime-type MIME type [string] [default: infer from the file contents]" `); }); }); diff --git a/bin/cml/comment/create.js b/bin/cml/comment/create.js index 1c3d110f0..409b9df9c 100644 --- a/bin/cml/comment/create.js +++ b/bin/cml/comment/create.js @@ -66,6 +66,7 @@ exports.options = kebabcaseKeys({ type: 'boolean', description: 'Avoid watermark; CML needs a watermark to be able to distinguish CML comments from others', + hidden: true, telemetryData: 'name' } }); diff --git a/bin/cml/comment/create.test.js b/bin/cml/comment/create.test.js index 681ae8b05..4e36101e2 100644 --- a/bin/cml/comment/create.test.js +++ b/bin/cml/comment/create.test.js @@ -30,9 +30,7 @@ describe('Comment integration tests', () => { [string] [default: \\"https://asset.cml.dev\\"] --publish-native, --native Uses driver's native capabilities to upload assets instead of CML's storage; not available on GitHub - [boolean] - --rm-watermark Avoid watermark; CML needs a watermark to be able - to distinguish CML comments from others [boolean]" + [boolean]" `); }); }); diff --git a/bin/cml/tensorboard/connect.js b/bin/cml/tensorboard/connect.js index b0fac3c67..5f61f5469 100644 --- a/bin/cml/tensorboard/connect.js +++ b/bin/cml/tensorboard/connect.js @@ -145,6 +145,7 @@ exports.options = kebabcaseKeys({ rmWatermark: { type: 'boolean', description: 'Avoid CML watermark', + hidden: true, telemetryData: 'name' } }); diff --git a/bin/cml/tensorboard/connect.test.js b/bin/cml/tensorboard/connect.test.js index b6d23f9d1..66c332805 100644 --- a/bin/cml/tensorboard/connect.test.js +++ b/bin/cml/tensorboard/connect.test.js @@ -20,17 +20,16 @@ describe('CML e2e', () => { --help Show help [boolean] Options: - -c, --credentials TensorBoard credentials as JSON, usually found at - ~/.config/tensorboard/credentials/uploader-creds.json + -c, --credentials TensorBoard credentials as JSON, usually found at + ~/.config/tensorboard/credentials/uploader-creds.json [string] [required] - --logdir Directory containing the logs to process [string] - --name Tensorboard experiment title; max 100 characters [string] - --description Tensorboard experiment description in Markdown format; max - 600 characters [string] - --md Output as markdown [title || name](url) [boolean] - -t, --title Markdown title, if not specified, param name will be used - [string] - --rm-watermark Avoid CML watermark [boolean]" + --logdir Directory containing the logs to process [string] + --name Tensorboard experiment title; max 100 characters [string] + --description Tensorboard experiment description in Markdown format; max + 600 characters [string] + --md Output as markdown [title || name](url) [boolean] + -t, --title Markdown title, if not specified, param name will be used + [string]" `); }); }); From bb0407696f5ea841af59797b27005c47614aed44 Mon Sep 17 00:00:00 2001 From: Deepyaman Datta Date: Thu, 27 Oct 2022 17:07:56 -0400 Subject: [PATCH 06/11] Add `ci --fetch-depth`, deprecate `ci --unshallow` (#1233) * Add `ci --fetch-depth`, deprecate `ci --unshallow` * Edit formatting of expected `cml ci --help` output * Remove `isNaN` check, already handled by Yargs lib * Fix negative `fetchDepth`s using `coerce` in Yargs * Apply suggestions from code review Co-authored-by: Daniel Barnes * Reduce duplicate logic, and replace `coerce` with different condition Co-authored-by: Casper da Costa-Luis * Assignment to constant variable Co-authored-by: Helio Machado <0x2b3bfa0+git@googlemail.com> Co-authored-by: Daniel Barnes Co-authored-by: Casper da Costa-Luis --- bin/cml/repo/prepare.js | 9 ++++++++- bin/cml/repo/prepare.test.js | 8 ++++---- src/cml.js | 8 ++++++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/bin/cml/repo/prepare.js b/bin/cml/repo/prepare.js index a8943f4ce..21d97bb10 100644 --- a/bin/cml/repo/prepare.js +++ b/bin/cml/repo/prepare.js @@ -20,10 +20,17 @@ exports.builder = (yargs) => .options(exports.options); exports.options = kebabcaseKeys({ + fetchDepth: { + type: 'number', + default: 1, + description: + 'Number of commits to fetch. 0 indicates all history for all branches and tags' + }, unshallow: { type: 'boolean', description: - 'Fetch as much as possible, converting a shallow repository to a complete one' + 'Fetch as much as possible, converting a shallow repository to a complete one', + hidden: true }, userEmail: { type: 'string', diff --git a/bin/cml/repo/prepare.test.js b/bin/cml/repo/prepare.test.js index 02fbc1615..72254b0ba 100644 --- a/bin/cml/repo/prepare.test.js +++ b/bin/cml/repo/prepare.test.js @@ -20,10 +20,10 @@ describe('CML e2e', () => { --help Show help [boolean] Options: - --unshallow Fetch as much as possible, converting a shallow repository to a - complete one [boolean] - --user-email Git user email [string] [default: \\"olivaw@iterative.ai\\"] - --user-name Git user name [string] [default: \\"Olivaw[bot]\\"]" + --fetch-depth Number of commits to fetch. 0 indicates all history for all + branches and tags [number] [default: 1] + --user-email Git user email [string] [default: \\"olivaw@iterative.ai\\"] + --user-name Git user name [string] [default: \\"Olivaw[bot]\\"]" `); }); }); diff --git a/src/cml.js b/src/cml.js index b303942d8..a43f22e4c 100755 --- a/src/cml.js +++ b/src/cml.js @@ -469,15 +469,19 @@ class CML { userName = GIT_USER_NAME, remote = GIT_REMOTE } = opts; + let { fetchDepth = 1 } = opts; const driver = this.getDriver(); await exec(await driver.updateGitConfig({ userName, userEmail, remote })); if (unshallow) { if ((await exec('git rev-parse --is-shallow-repository')) === 'true') { - await exec('git fetch --unshallow'); + fetchDepth = 0; } } - await exec('git fetch --all'); + if (fetchDepth <= 0) { + return await exec('git fetch --all --unshallow'); + } + return await exec(`git fetch --all --depth=${fetchDepth}`); } async prCreate(opts = {}) { From 1df8532d3b2c89391a203becf01818e00c477b7c Mon Sep 17 00:00:00 2001 From: Helio Machado <0x2b3bfa0+git@googlemail.com> Date: Fri, 28 Oct 2022 18:54:53 +0200 Subject: [PATCH 07/11] Add cloud instance & accelerator types telemetry (#1242) --- bin/cml/runner/launch.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/cml/runner/launch.js b/bin/cml/runner/launch.js index 07482b725..d3087670a 100755 --- a/bin/cml/runner/launch.js +++ b/bin/cml/runner/launch.js @@ -495,7 +495,8 @@ exports.options = kebabcaseKeys({ cloudType: { type: 'string', description: - 'Instance type. Choices: [m, l, xl]. Also supports native types like i.e. t2.micro' + 'Instance type. Choices: [m, l, xl]. Also supports native types like i.e. t2.micro', + telemetryData: 'full' }, cloudPermissionSet: { type: 'string', @@ -518,7 +519,8 @@ exports.options = kebabcaseKeys({ type: 'string', description: 'GPU type. Choices: k80, v100, or native types e.g. nvidia-tesla-t4', - coerce: (val) => (val === 'nogpu' ? undefined : val) + coerce: (val) => (val === 'nogpu' ? undefined : val), + telemetryData: 'full' }, cloudHddSize: { type: 'number', From 329ed4232c52b2e135ef3846ff1a2461110c635b Mon Sep 17 00:00:00 2001 From: Helio Machado <0x2b3bfa0+git@googlemail.com> Date: Sat, 29 Oct 2022 18:22:36 +0200 Subject: [PATCH 08/11] Fix Tensorboard credentials environment variable (#1244) --- bin/cml.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cml.js b/bin/cml.js index 80df965e1..e207e5e0e 100755 --- a/bin/cml.js +++ b/bin/cml.js @@ -12,7 +12,7 @@ const { jitsuEventPayload, send } = require('../src/analytics'); const setupOpts = (opts) => { const legacyEnvironmentVariables = { - TB_CREDENTIALS: 'CML_TENSORBOARD_DEV_CREDENTIALS', + TB_CREDENTIALS: 'CML_TENSORBOARD_CREDENTIALS', DOCKER_MACHINE: 'CML_RUNNER_DOCKER_MACHINE', RUNNER_IDLE_TIMEOUT: 'CML_RUNNER_IDLE_TIMEOUT', RUNNER_LABELS: 'CML_RUNNER_LABELS', From 17a045e9dd8121dc4b7e155d6c647813db1e6345 Mon Sep 17 00:00:00 2001 From: Domas Monkus Date: Sat, 29 Oct 2022 20:01:29 +0300 Subject: [PATCH 09/11] Augment watermark with label (#1173) * Augment watermark with label. The label may contain special strings `{workflow}` or `{run}` as an easy way to make updatable comments specific to the workflow or execution. * Check for presence of a node title. * Specify conflict between commentLabel and rmWatermark flags. * Update bin/cml/comment/create.js Co-authored-by: Casper da Costa-Luis * Update cli flag for comment label. * Rename --label to --id * Rename parameter to commentTag. * Update src/cml.js Co-authored-by: Helio Machado <0x2b3bfa0+git@googlemail.com> * Rename commentTag flag to watermarkTitle. * Update bin/cml/comment/create.js Co-authored-by: Casper da Costa-Luis * Update snapshots. * Refactor watermark function. * Fix test. * Use markdown-escape to escape markdown control characters in comment watermark titles. * Revert "Use markdown-escape to escape markdown control characters in comment watermark titles." This reverts commit 14006850423ce15d69c3c4c5b1206311c7f15013. * Simplify escaping of markdown control characters. It appears that github only escapes asterisks and underscores. * Add more patterns to escape. * Run replacement on title, not full watermark. Co-authored-by: Casper da Costa-Luis Co-authored-by: Helio Machado <0x2b3bfa0+git@googlemail.com> Co-authored-by: Daniel Barnes --- bin/cml/comment/create.js | 7 +++++ bin/cml/comment/create.test.js | 6 +++-- src/cml.js | 48 ++++++++++++++++++++++++++++------ src/drivers/bitbucket_cloud.js | 16 ++++++++++-- src/drivers/github.js | 19 ++++++++++---- src/drivers/gitlab.js | 11 +++++++- src/utils.js | 6 ++--- 7 files changed, 92 insertions(+), 21 deletions(-) diff --git a/bin/cml/comment/create.js b/bin/cml/comment/create.js index 409b9df9c..eda8df3ff 100644 --- a/bin/cml/comment/create.js +++ b/bin/cml/comment/create.js @@ -68,6 +68,13 @@ exports.options = kebabcaseKeys({ 'Avoid watermark; CML needs a watermark to be able to distinguish CML comments from others', hidden: true, telemetryData: 'name' + }, + watermarkTitle: { + type: 'string', + description: + 'Hidden comment marker (used for targeting in subsequent `cml comment update`); "{workflow}" & "{run}" are auto-replaced', + default: '', + conflicts: ['rmWatermark'] } }); exports.DOCSURL = DOCSURL; diff --git a/bin/cml/comment/create.test.js b/bin/cml/comment/create.test.js index 4e36101e2..c4aebf9dc 100644 --- a/bin/cml/comment/create.test.js +++ b/bin/cml/comment/create.test.js @@ -3,7 +3,6 @@ const { exec } = require('../../../src/utils'); describe('Comment integration tests', () => { test('cml send-comment --help', async () => { const output = await exec(`node ./bin/cml.js send-comment --help`); - expect(output).toMatchInlineSnapshot(` "cml.js send-comment @@ -30,7 +29,10 @@ describe('Comment integration tests', () => { [string] [default: \\"https://asset.cml.dev\\"] --publish-native, --native Uses driver's native capabilities to upload assets instead of CML's storage; not available on GitHub - [boolean]" + [boolean] + --watermark-title Hidden comment marker (used for targeting in + subsequent \`cml comment update\`); \\"{workflow}\\" & + \\"{run}\\" are auto-replaced [string] [default: \\"\\"]" `); }); }); diff --git a/src/cml.js b/src/cml.js index a43f22e4c..8087e9e51 100755 --- a/src/cml.js +++ b/src/cml.js @@ -23,6 +23,7 @@ const { const { GITHUB_REPOSITORY, CI_PROJECT_URL, BITBUCKET_REPO_UUID } = process.env; +const WATERMARK_IMAGE = 'https://cml.dev/watermark.png'; const GIT_USER_NAME = 'Olivaw[bot]'; const GIT_USER_EMAIL = 'olivaw@iterative.ai'; const GIT_REMOTE = 'origin'; @@ -164,26 +165,55 @@ class CML { const triggerSha = await this.triggerSha(); const { commitSha: inCommitSha = triggerSha, - rmWatermark, - update, + markdownFile, pr, publish, publishUrl, - markdownFile, report: testReport, + rmWatermark, + triggerFile, + update, watch, - triggerFile + watermarkTitle } = opts; + const drv = this.getDriver(); + const commitSha = (await this.revParse({ ref: inCommitSha })) || inCommitSha; if (rmWatermark && update) throw new Error('watermarks are mandatory for updateable comments'); + // Create the watermark. + const genWatermark = (opts = {}) => { + const { label = '', workflow, run } = opts; + // Replace {workflow} and {run} placeholders in label with actual values. + const lbl = label.replace('{workflow}', workflow).replace('{run}', run); + + let title = `CML watermark ${lbl}`.trim(); + // Github appears to escape underscores and asterisks in markdown content. + // Without escaping them, the watermark content in comments retrieved + // from github will not match the input. + const patterns = [ + [/_/g, '\\_'], // underscore + [/\*/g, '\\*'], // asterisk + [/\[/g, '\\['], // opening square bracket + [/ label.replace(pattern[0], pattern[1]), + title + ); + return `![](${WATERMARK_IMAGE} "${title}")`; + }; const watermark = rmWatermark ? '' - : '![CML watermark](https://raw.githubusercontent.com/iterative/cml/master/assets/watermark.svg)'; + : genWatermark({ + label: watermarkTitle, + workflow: drv.workflowId, + run: drv.runId + }); let userReport = testReport; try { @@ -195,15 +225,17 @@ class CML { } let report = `${userReport}\n\n${watermark}`; - const drv = this.getDriver(); const publishLocalFiles = async (tree) => { const nodes = []; visit(tree, ['definition', 'image', 'link'], (node) => nodes.push(node)); + const isWatermark = (node) => { + return node.title && node.title.startsWith('CML watermark'); + }; const visitor = async (node) => { - if (node.url && node.alt !== 'CML watermark') { + if (node.url && !isWatermark(node)) { const absolutePath = path.resolve( path.dirname(markdownFile), node.url @@ -264,7 +296,7 @@ class CML { let comment; const updatableComment = (comments) => { return comments.reverse().find(({ body }) => { - return body.includes('watermark.svg'); + return body.includes(watermark); }); }; diff --git a/src/drivers/bitbucket_cloud.js b/src/drivers/bitbucket_cloud.js index 0c6a668dd..9c160a558 100644 --- a/src/drivers/bitbucket_cloud.js +++ b/src/drivers/bitbucket_cloud.js @@ -8,8 +8,12 @@ const ProxyAgent = require('proxy-agent'); const { fetchUploadData, exec, gpuPresent, sleep } = require('../utils'); -const { BITBUCKET_COMMIT, BITBUCKET_BRANCH, BITBUCKET_PIPELINE_UUID } = - process.env; +const { + BITBUCKET_COMMIT, + BITBUCKET_BRANCH, + BITBUCKET_PIPELINE_UUID, + BITBUCKET_BUILD_NUMBER +} = process.env; class BitbucketCloud { constructor(opts = {}) { @@ -421,6 +425,14 @@ class BitbucketCloud { return command; } + get workflowId() { + return BITBUCKET_PIPELINE_UUID; + } + + get runId() { + return BITBUCKET_BUILD_NUMBER; + } + get sha() { return BITBUCKET_COMMIT; } diff --git a/src/drivers/github.js b/src/drivers/github.js index d36bdce25..273fa0a55 100644 --- a/src/drivers/github.js +++ b/src/drivers/github.js @@ -18,14 +18,15 @@ const CHECK_TITLE = 'CML Report'; process.env.RUNNER_ALLOW_RUNASROOT = 1; const { - GITHUB_REPOSITORY, - GITHUB_SHA, - GITHUB_REF, - GITHUB_HEAD_REF, + CI, GITHUB_EVENT_NAME, + GITHUB_HEAD_REF, + GITHUB_REF, + GITHUB_REPOSITORY, GITHUB_RUN_ID, + GITHUB_SHA, GITHUB_TOKEN, - CI, + GITHUB_WORKFLOW, TPI_TASK } = process.env; @@ -705,6 +706,14 @@ class Github { return command; } + get workflowId() { + return GITHUB_WORKFLOW; + } + + get runId() { + return GITHUB_RUN_ID; + } + warn(message) { console.error(`::warning::${message}`); } diff --git a/src/drivers/gitlab.js b/src/drivers/gitlab.js index afad6a368..6cd59fe0a 100644 --- a/src/drivers/gitlab.js +++ b/src/drivers/gitlab.js @@ -11,7 +11,8 @@ const winston = require('winston'); const { fetchUploadData, download, gpuPresent } = require('../utils'); -const { IN_DOCKER, CI_PIPELINE_ID } = process.env; +const { CI_JOB_ID, CI_PIPELINE_ID, IN_DOCKER } = process.env; + const API_VER = 'v4'; class Gitlab { constructor(opts = {}) { @@ -444,6 +445,14 @@ class Gitlab { return command; } + get workflowId() { + return CI_PIPELINE_ID; + } + + get runId() { + return CI_JOB_ID; + } + get sha() { return process.env.CI_COMMIT_SHA; } diff --git a/src/utils.js b/src/utils.js index a29aaa937..9fe41e45d 100644 --- a/src/utils.js +++ b/src/utils.js @@ -136,14 +136,14 @@ const isProcRunning = async (opts) => { }; const watermarkUri = ({ uri, type } = {}) => { - return uriParmam({ uri, param: 'cml', value: type }); + return uriParam({ uri, param: 'cml', value: type }); }; const preventcacheUri = ({ uri } = {}) => { - return uriParmam({ uri, param: 'cache-bypass', value: uuid.v4() }); + return uriParam({ uri, param: 'cache-bypass', value: uuid.v4() }); }; -const uriParmam = (opts = {}) => { +const uriParam = (opts = {}) => { const { uri, param, value } = opts; const url = new URL(uri); url.searchParams.set(param, value); From fc9e235679ff850a646d977da016a4ad2d682634 Mon Sep 17 00:00:00 2001 From: Daniel Barnes Date: Mon, 31 Oct 2022 14:54:15 -0700 Subject: [PATCH 10/11] Remove default value for `--fetch-depth` (#1246) * temp * no default for fetch-depth * test update * tidy unshallow logic checks * slight docs update Co-authored-by: Casper da Costa-Luis --- bin/cml/repo/prepare.js | 4 +--- bin/cml/repo/prepare.test.js | 4 ++-- src/cml.js | 16 ++++++++-------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/bin/cml/repo/prepare.js b/bin/cml/repo/prepare.js index 21d97bb10..82ae22a4f 100644 --- a/bin/cml/repo/prepare.js +++ b/bin/cml/repo/prepare.js @@ -22,9 +22,7 @@ exports.builder = (yargs) => exports.options = kebabcaseKeys({ fetchDepth: { type: 'number', - default: 1, - description: - 'Number of commits to fetch. 0 indicates all history for all branches and tags' + description: 'Number of commits to fetch (use `0` for all branches & tags)' }, unshallow: { type: 'boolean', diff --git a/bin/cml/repo/prepare.test.js b/bin/cml/repo/prepare.test.js index 72254b0ba..6a765847b 100644 --- a/bin/cml/repo/prepare.test.js +++ b/bin/cml/repo/prepare.test.js @@ -20,8 +20,8 @@ describe('CML e2e', () => { --help Show help [boolean] Options: - --fetch-depth Number of commits to fetch. 0 indicates all history for all - branches and tags [number] [default: 1] + --fetch-depth Number of commits to fetch (use \`0\` for all branches & tags) + [number] --user-email Git user email [string] [default: \\"olivaw@iterative.ai\\"] --user-name Git user name [string] [default: \\"Olivaw[bot]\\"]" `); diff --git a/src/cml.js b/src/cml.js index 8087e9e51..f02dfd7d2 100755 --- a/src/cml.js +++ b/src/cml.js @@ -501,19 +501,19 @@ class CML { userName = GIT_USER_NAME, remote = GIT_REMOTE } = opts; - let { fetchDepth = 1 } = opts; + const { fetchDepth = unshallow ? 0 : undefined } = opts; const driver = this.getDriver(); await exec(await driver.updateGitConfig({ userName, userEmail, remote })); - if (unshallow) { - if ((await exec('git rev-parse --is-shallow-repository')) === 'true') { - fetchDepth = 0; + if (fetchDepth !== undefined) { + if (fetchDepth <= 0) { + if ((await exec('git rev-parse --is-shallow-repository')) === 'true') { + return await exec('git fetch --all --unshallow'); + } + } else { + return await exec(`git fetch --all --depth=${fetchDepth}`); } } - if (fetchDepth <= 0) { - return await exec('git fetch --all --unshallow'); - } - return await exec(`git fetch --all --depth=${fetchDepth}`); } async prCreate(opts = {}) { From 1a2b24506532d9128259566cd7cd579007a445ed Mon Sep 17 00:00:00 2001 From: Helio Machado <0x2b3bfa0+git@googlemail.com> Date: Tue, 1 Nov 2022 16:07:18 +0100 Subject: [PATCH 11/11] Fix environment variable aliases (#1247) * Fix environment variable aliases * Fix linter nitpick * Invert order of operations * remove .. Co-authored-by: DavidGOrtega --- bin/cml.js | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/bin/cml.js b/bin/cml.js index e207e5e0e..4dae11193 100755 --- a/bin/cml.js +++ b/bin/cml.js @@ -10,24 +10,7 @@ const yargs = require('yargs'); const CML = require('../src/cml').default; const { jitsuEventPayload, send } = require('../src/analytics'); -const setupOpts = (opts) => { - const legacyEnvironmentVariables = { - TB_CREDENTIALS: 'CML_TENSORBOARD_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 aliasLegacyEnvironmentVariables = () => { const legacyEnvironmentPrefixes = { CML_CI: 'CML_REPO', CML_PUBLISH: 'CML_ASSET', @@ -46,6 +29,25 @@ const setupOpts = (opts) => { } } + const legacyEnvironmentVariables = { + TB_CREDENTIALS: 'CML_TENSORBOARD_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 setupOpts = (opts) => { const { markdownfile } = opts; opts.markdownFile = markdownfile; opts.cml = new CML(opts); @@ -117,6 +119,7 @@ const handleError = (message, error) => { }; (async () => { + aliasLegacyEnvironmentVariables(); setupLogger({ log: 'debug' }); try {