diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2de5cbf..0c1a5b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,8 @@ env: {} -# DO NOT EDIT BELOW - use `npx ghat fregante/ghatemplates/node --exclude jobs.Test` +# FILE GENERATED WITH: npx ghat fregante/ghatemplates/node +# SOURCE: https://github.com/fregante/ghatemplates +# OPTIONS: {"exclude":["jobs.Test"]} name: CI on: @@ -22,4 +24,4 @@ jobs: - name: install run: npm ci || npm install - name: build - run: npm run build --if-present + run: npm run build diff --git a/bin.js b/bin.js index c01849d..ddf008b 100644 --- a/bin.js +++ b/bin.js @@ -28,7 +28,6 @@ prog .action(async (source, options) => { normalizeFlagArray(options, 'exclude'); normalizeFlagArray(options, 'set'); - options.argv = process.argv; try { await ghat(source, options); diff --git a/lib.js b/lib.js index a465b45..4917fb9 100644 --- a/lib.js +++ b/lib.js @@ -6,9 +6,10 @@ const yaml = require('js-yaml'); const degit = require('degitto'); const dotProp = require('dot-prop'); const {outdent} = require('outdent'); -const shellEscape = require('shell-escape'); const splitOnFirst = require('split-on-first'); +const getRepoUrl = require('./parse-repo.js'); + class InputError extends Error {} async function loadYamlFile(path) { @@ -45,7 +46,7 @@ async function getWorkflows(directory) { return findYamlFiles(directory, '.github/workflows'); } -async function ghat(source, {exclude, set, argv}) { +async function ghat(source, {exclude, set}) { if (!source) { throw new InputError('No source was specified'); } @@ -94,6 +95,8 @@ async function ghat(source, {exclude, set, argv}) { } needsUpdate = true; + } else { + exclude = undefined; } if (set.length > 0) { @@ -103,15 +106,28 @@ async function ghat(source, {exclude, set, argv}) { } needsUpdate = true; + } else { + set = undefined; } if (needsUpdate) { remote.string = yaml.dump(remote.parsed, {noCompatMode: true}); } + const comments = [ + `FILE GENERATED WITH: npx ghat ${source}`, + `SOURCE: ${getRepoUrl(source).url}` + ]; + + if (exclude || set) { + comments.push( + `OPTIONS: ${JSON.stringify({exclude, set})}` + ); + } + await fs.writeFile(localWorkflowPath, outdent` ${yaml.dump({env})} - # DO NOT EDIT BELOW, USE: npx ghat ${shellEscape(argv.slice(2))} + ${comments.map(line => '# ' + line).join('\n')} ${await remote.string}` ); diff --git a/package-lock.json b/package-lock.json index d80e9e4..76125a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,6 @@ "js-yaml": "^4.0.0", "outdent": "^0.8.0", "sade": "^1.7.4", - "shell-escape": "^0.2.0", "split-on-first": "^2.0.1", "xo": "^0.37.1" } @@ -7113,12 +7112,6 @@ "node": ">=8" } }, - "node_modules/shell-escape": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/shell-escape/-/shell-escape-0.2.0.tgz", - "integrity": "sha1-aP0CXrBJC09WegJ/C/IkgLX4QTM=", - "dev": true - }, "node_modules/signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -14163,12 +14156,6 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "shell-escape": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/shell-escape/-/shell-escape-0.2.0.tgz", - "integrity": "sha1-aP0CXrBJC09WegJ/C/IkgLX4QTM=", - "dev": true - }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", diff --git a/package.json b/package.json index f15a1ff..51c4ba7 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "prepack": "npm run build", "test": "npm run build && xo" }, - "dependencies": {}, "devDependencies": { "@vercel/ncc": "^0.27.0", "degitto": "^2.8.2", @@ -38,7 +37,6 @@ "js-yaml": "^4.0.0", "outdent": "^0.8.0", "sade": "^1.7.4", - "shell-escape": "^0.2.0", "split-on-first": "^2.0.1", "xo": "^0.37.1" } diff --git a/parse-repo.js b/parse-repo.js new file mode 100644 index 0000000..6d05fab --- /dev/null +++ b/parse-repo.js @@ -0,0 +1,49 @@ +// Extracted from degit +// TODO: Export from degitto instead +const supported = new Set(['github', 'gitlab', 'bitbucket', 'git.sr.ht']); + +class DegitError extends Error { + constructor(message, options) { + super(message); + Object.assign(this, options); + } +} + +module.exports = src => { + const match = /^(?:(?:https:\/\/)?([^:/]+\.[^:/]+)\/|git@([^:/]+)[:/]|([^/]+):)?([^/\s]+)\/([^/\s#]+)(?:((?:\/[^/\s#]+)+))?\/?(?:#(.+))?/.exec( + src + ); + if (!match) { + throw new DegitError(`could not parse ${src}`, { + code: 'BAD_SRC' + }); + } + + const site = (match[1] || match[2] || match[3] || 'github').replace( + /\.(com|org)$/, + '' + ); + if (!supported.has(site)) { + throw new DegitError( + 'degit supports GitHub, GitLab, Sourcehut and BitBucket', + { + code: 'UNSUPPORTED_HOST' + } + ); + } + + const user = match[4]; + const name = match[5].replace(/\.git$/, ''); + const subdir = match[6]; + const ref = match[7] || 'HEAD'; + + const domain = `${site}.${ + site === 'bitbucket' ? 'org' : (site === 'git.sr.ht' ? '' : 'com') + }`; + const url = `https://${domain}/${user}/${name}`; + const ssh = `git@${domain}:${user}/${name}`; + + const mode = supported.has(site) ? 'tar' : 'git'; + + return {site, user, name, ref, url, ssh, subdir, mode}; +};