diff --git a/bin/cml/send-comment.js b/bin/cml/send-comment.js index bca571d5ce..b834ede279 100644 --- a/bin/cml/send-comment.js +++ b/bin/cml/send-comment.js @@ -1,4 +1,3 @@ -const fs = require('fs').promises; const kebabcaseKeys = require('kebabcase-keys'); const CML = require('../../src/cml').default; @@ -7,10 +6,8 @@ exports.command = 'send-comment '; exports.description = 'Comment on a commit'; exports.handler = async (opts) => { - const path = opts.markdownfile; - const report = await fs.readFile(path, 'utf-8'); const cml = new CML(opts); - console.log(await cml.commentCreate({ ...opts, report })); + console.log(await cml.commentCreate(opts)); }; exports.builder = (yargs) => diff --git a/package-lock.json b/package-lock.json index 8a59545085..33546ab565 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,9 @@ "@octokit/graphql": "^4.8.0", "@octokit/plugin-throttling": "^3.5.2", "@octokit/rest": "18.0.0", + "chokidar": "^3.5.3", "colors": "1.4.0", + "cross-platform-file-watch": "^3.5.2", "ec2-spot-notification": "^2.0.3", "exponential-backoff": "^3.1.0", "form-data": "^3.0.1", @@ -1675,7 +1677,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -1922,6 +1923,14 @@ "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==" }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -2105,6 +2114,43 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -2334,6 +2380,37 @@ "node": ">=10.0.0" } }, + "node_modules/cross-platform-file-watch": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/cross-platform-file-watch/-/cross-platform-file-watch-3.5.2.tgz", + "integrity": "sha512-Qu3rDxR0ld3bufcbXMcc6EInsC/2Ha+6k1h1yUYI5xSWbsdJfg+F3xdszvwWl2+LvklgIp6Ktk/v9I1M3Q7Ajg==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cross-platform-file-watch/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3628,7 +3705,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -4286,6 +4362,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -6554,7 +6641,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -7226,6 +7312,17 @@ "string_decoder": "~0.10.x" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -10294,7 +10391,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -10483,6 +10579,11 @@ "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==" }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -10609,6 +10710,31 @@ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.1.tgz", "integrity": "sha512-OzmutCf2Kmc+6DrFrrPS8/tDh2+DpnrfzdICHWhcVC9eOd0N1PXmQEE1a8iM4IziIAG+8tmTq3K+oo0ubH6RRQ==" }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, "chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -10802,6 +10928,31 @@ "nan": "^2.15.0" } }, + "cross-platform-file-watch": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/cross-platform-file-watch/-/cross-platform-file-watch-3.5.2.tgz", + "integrity": "sha512-Qu3rDxR0ld3bufcbXMcc6EInsC/2Ha+6k1h1yUYI5xSWbsdJfg+F3xdszvwWl2+LvklgIp6Ktk/v9I1M3Q7Ajg==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -11774,7 +11925,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "optional": true }, "ftp": { @@ -12250,6 +12400,14 @@ "has-bigints": "^1.0.1" } }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -13859,8 +14017,7 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "normalize-url": { "version": "6.1.0", @@ -14345,6 +14502,14 @@ "string_decoder": "~0.10.x" } }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", diff --git a/package.json b/package.json index 9c40afa83c..d39928a520 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,9 @@ "@octokit/graphql": "^4.8.0", "@octokit/plugin-throttling": "^3.5.2", "@octokit/rest": "18.0.0", + "chokidar": "^3.5.3", "colors": "1.4.0", + "cross-platform-file-watch": "^3.5.2", "ec2-spot-notification": "^2.0.3", "exponential-backoff": "^3.1.0", "form-data": "^3.0.1", diff --git a/report.md b/report.md deleted file mode 100644 index dca37dab41..0000000000 --- a/report.md +++ /dev/null @@ -1,3 +0,0 @@ -## Report - -![](./assets/logo.png) diff --git a/src/cml.js b/src/cml.js index 0452093af3..6f2475aadb 100755 --- a/src/cml.js +++ b/src/cml.js @@ -5,6 +5,7 @@ const globby = require('globby'); const git = require('simple-git')('./'); const path = require('path'); const fs = require('fs'); +const chokidar = require('chokidar'); const winston = require('winston'); @@ -22,8 +23,6 @@ const GITHUB = 'github'; const GITLAB = 'gitlab'; const BB = 'bitbucket'; -const paths = new Set(); - const uriNoTrailingSlash = (uri) => { return uri.endsWith('/') ? uri.substr(0, uri.length - 1) : uri; }; @@ -145,13 +144,13 @@ class CML { async commentCreate(opts = {}) { const triggerSha = await this.triggerSha(); const { - report: userReport, commitSha: inCommitSha = triggerSha, rmWatermark, update, pr, publish, markdownfile, + report: testReport, watch } = opts; @@ -165,13 +164,33 @@ class CML { ? '' : '![CML watermark](https://raw.githubusercontent.com/iterative/cml/master/assets/watermark.svg)'; + const userReport = + testReport || (await fs.promises.readFile(markdownfile, 'utf-8')); let report = `${userReport}\n\n${watermark}`; const drv = getDriver(this); const { remark } = await import('remark'); const { visit } = await import('unist-util-visit'); - paths.add(markdownfile); + const watcher = chokidar.watch(markdownfile, { + persistent: false, + followSymlinks: true, + disableGlobbing: true, + ignoreInitial: true, + awaitWriteFinish: { + stabilityThreshold: 4000, + pollInterval: 2000 + } + }); + + if (watch) { + watcher.on('all', (a, b) => { + console.log('updating report...' + a + '. ' + b); + this.commentCreate({ ...opts, update: true, watch: false }); + }); + } else { + await watcher.close(); + } const publishLocalFiles = () => async (tree) => { const nodes = []; @@ -180,13 +199,11 @@ class CML { const visitor = async (node) => { if (node.url && node.alt !== 'CML watermark') { + if (watch) watcher.add(node.url); + if (watch) console.log('ADD: ' + node.url); try { - await fs.promises.access(node.url, fs.constants.F_OK); - } catch { - return; - } - node.url = await this.publish({ ...opts, path: node.url }); - paths.add(node.url); + node.url = await this.publish({ ...opts, path: node.url }); + } catch {} // file may not exist } }; @@ -196,12 +213,6 @@ class CML { if (publish) report = String(await remark().use(publishLocalFiles).process(report)); - if (watch) - setInterval(() => { - console.log('updating report...'); - this.commentCreate({ ...opts, update: true, watch: false }); - }, 16384); // TODO: use a proper file watcher on the `paths` set - let comment; const updatableComment = (comments) => { return comments.reverse().find(({ body }) => {