Repository: iterative/cml
Pull request #1232 (2022-10-19 00:12:33)

Provide Docs URLs in `--help` messaging
I did some very basic skimming of yargs to see if they had a better mechanism for this but didn't find anything (note  on the basic skimming,  I find their docs website difficult to read and search)

dacbd: That should be easy enough to add

Patch:
diff --git a/bin/cml/asset/publish.js b/bin/cml/asset/publish.js
index 09fce8e..1d09e12 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 <asset>';
-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 89ebcea..7eb86d9 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 <markdown file>';
-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 c0dea33..1c3d110 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 <markdown file>';
-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 adfdb64..2fddae7 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 <markdown file>';
-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.js b/bin/cml/pr/create.js
index dc98eda..7a68a28 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 <glob path...>';
-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 302f75c..a8943f4 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 c4bbc28..07482b7 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/tensorboard/connect.js b/bin/cml/tensorboard/connect.js
index 7e0b073..b0fac3c 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 4063943..4d9b434 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 8e9a762..b0e9d91 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",


Test patch:
diff --git a/bin/cml.test.js b/bin/cml.test.js
index 612fed3..2af1b3d 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/pr/create.e2e.test.js b/bin/cml/pr/create.e2e.test.js
index 86a7fd4..f2d6697 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 <glob path...>  Create a pull request with the specified
                                          files
+                                         https://cml.dev/doc/ref/pr
 
       Global Options:
         --log     Logging verbosity
diff --git a/bin/cml/runner/launch.test.js b/bin/cml/runner/launch.test.js
index 9dd29db..8034c8b 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