From d3e101b22a7fdafdea0ada4d31548c63be5c7423 Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Thu, 13 May 2021 02:23:35 +0200 Subject: [PATCH] Add dry-run input (#144) Co-authored-by: CrazyMax --- .github/workflows/ci.yml | 5 ++ README.md | 1 + action.yml | 4 ++ dist/index.js | 119 ++++++++++++++++++++++----------------- src/git.ts | 50 ++++++++-------- src/main.ts | 66 +++++++++++++--------- 6 files changed, 143 insertions(+), 102 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f2242f271c8..86d8be98fce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,10 @@ on: branches: - 'dev' - 'releases/v*' + pull_request: + branches: + - 'dev' + - 'releases/v*' jobs: ci: @@ -92,5 +96,6 @@ jobs: target_branch: ${{ matrix.target_branch }} keep_history: ${{ matrix.keep_history }} build_dir: public + dry-run: ${{ github.event_name == 'pull_request' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index 1569259d1a9..26a5f3a0616 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ Following inputs can be used as `step.with` keys | `commit_message` | String | Commit message (default `Deploy to GitHub pages`) | | `fqdn` | String | Write the given domain name to the CNAME file | | `jekyll` | Bool | Allow Jekyll to build your site (default `true`) | +| `dry-run` | Bool | If enabled, nothing will be pushed (default `false`) | ### environment variables diff --git a/action.yml b/action.yml index 7eb429fc669..f71993091c8 100644 --- a/action.yml +++ b/action.yml @@ -45,6 +45,10 @@ inputs: description: 'Allow Jekyll to build your site' default: 'true' required: false + dry-run: + description: 'If enabled, nothing will be pushed' + default: 'false' + required: false runs: using: 'node12' diff --git a/dist/index.js b/dist/index.js index 6c2ae7c8200..b6128261126 100644 --- a/dist/index.js +++ b/dist/index.js @@ -100,72 +100,74 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.push = exports.showStat = exports.commit = exports.add = exports.setConfig = exports.hasChanges = exports.isDirty = exports.checkout = exports.init = exports.clone = exports.remoteBranchExists = exports.defaults = void 0; -const exec = __importStar(__webpack_require__(7757)); +const mexec = __importStar(__webpack_require__(7757)); +const exec = __importStar(__webpack_require__(1514)); exports.defaults = { targetBranch: 'gh-pages', committer: 'GitHub ', author: 'github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>', message: 'Deploy to GitHub pages' }; -const git = (args = []) => __awaiter(void 0, void 0, void 0, function* () { - return yield exec.exec(`git`, args, true).then(res => { - if (res.stderr != '' && !res.success) { - throw new Error(res.stderr); - } - return res.stdout.trim(); - }); -}); function remoteBranchExists(remoteURL, branch) { return __awaiter(this, void 0, void 0, function* () { - return yield git(['ls-remote', '--heads', remoteURL, branch]).then(output => { - return output.trim().length > 0; + return yield mexec.exec('git', ['ls-remote', '--heads', remoteURL, branch], true).then(res => { + if (res.stderr != '' && !res.success) { + throw new Error(res.stderr); + } + return res.stdout.trim().length > 0; }); }); } exports.remoteBranchExists = remoteBranchExists; function clone(remoteURL, branch, dest) { return __awaiter(this, void 0, void 0, function* () { - yield git(['clone', '--quiet', '--branch', branch, '--depth', '1', remoteURL, dest]); + yield exec.exec('git', ['clone', '--quiet', '--branch', branch, '--depth', '1', remoteURL, dest]); }); } exports.clone = clone; function init(dest) { return __awaiter(this, void 0, void 0, function* () { - yield git(['init', dest]); + yield exec.exec('git', ['init', dest]); }); } exports.init = init; function checkout(branch) { return __awaiter(this, void 0, void 0, function* () { - yield git(['checkout', '--orphan', branch]); + yield exec.exec('git', ['checkout', '--orphan', branch]); }); } exports.checkout = checkout; function isDirty() { return __awaiter(this, void 0, void 0, function* () { - return yield git(['status', '--short']).then(output => { - return output.trim().length > 0; + return yield mexec.exec('git', ['status', '--short'], true).then(res => { + if (res.stderr != '' && !res.success) { + throw new Error(res.stderr); + } + return res.stdout.trim().length > 0; }); }); } exports.isDirty = isDirty; function hasChanges() { return __awaiter(this, void 0, void 0, function* () { - return yield git(['status', '--porcelain']).then(output => { - return output.trim().length > 0; + return yield mexec.exec('git', ['status', '--porcelain'], true).then(res => { + if (res.stderr != '' && !res.success) { + throw new Error(res.stderr); + } + return res.stdout.trim().length > 0; }); }); } exports.hasChanges = hasChanges; function setConfig(key, value) { return __awaiter(this, void 0, void 0, function* () { - yield git(['config', key, value]); + yield exec.exec('git', ['config', key, value]); }); } exports.setConfig = setConfig; function add(pattern) { return __awaiter(this, void 0, void 0, function* () { - yield git(['add', '--all', pattern]); + yield exec.exec('git', ['add', '--all', pattern]); }); } exports.add = add; @@ -180,14 +182,17 @@ function commit(allowEmptyCommit, author, message) { args.push('--author', author); } args.push('--message', message); - yield git(args); + yield exec.exec('git', args); }); } exports.commit = commit; function showStat() { return __awaiter(this, void 0, void 0, function* () { - return yield git(['show', `--stat-count=2000`, 'HEAD']).then(output => { - return output; + return yield mexec.exec('git', ['show', `--stat-count=2000`, 'HEAD'], true).then(res => { + if (res.stderr != '' && !res.success) { + throw new Error(res.stderr); + } + return res.stdout.trim(); }); }); } @@ -200,7 +205,7 @@ function push(remoteURL, branch, force) { args.push('--force'); } args.push(remoteURL, branch); - yield git(args); + yield exec.exec('git', args); }); } exports.push = push; @@ -266,6 +271,7 @@ function run() { const commitMessage = core.getInput('commit_message') || git.defaults.message; const fqdn = core.getInput('fqdn'); const nojekyll = /false/i.test(core.getInput('jekyll')); + const dryRun = /true/i.test(core.getInput('dry-run')); if (!fs.existsSync(buildDir)) { core.setFailed('Build dir does not exist'); return; @@ -273,17 +279,17 @@ function run() { let remoteURL = String('https://'); if (process.env['GH_PAT']) { core.debug(`Use GH_PAT`); - remoteURL = remoteURL.concat(process.env['GH_PAT'].trim()); + remoteURL = remoteURL.concat(process.env['GH_PAT'].trim(), '@'); } else if (process.env['GITHUB_TOKEN']) { core.debug(`Use GITHUB_TOKEN`); - remoteURL = remoteURL.concat('x-access-token:', process.env['GITHUB_TOKEN'].trim()); + remoteURL = remoteURL.concat('x-access-token:', process.env['GITHUB_TOKEN'].trim(), '@'); } - else { + else if (!dryRun) { core.setFailed('You have to provide a GITHUB_TOKEN or GH_PAT'); return; } - remoteURL = remoteURL.concat('@', domain, '/', repo, '.git'); + remoteURL = remoteURL.concat(domain, '/', repo, '.git'); core.debug(`remoteURL=${remoteURL}`); const remoteBranchExists = yield git.remoteBranchExists(remoteURL, targetBranch); core.debug(`remoteBranchExists=${remoteBranchExists}`); @@ -293,61 +299,72 @@ function run() { core.debug(`currentdir=${currentdir}`); process.chdir(tmpdir); if (keepHistory && remoteBranchExists) { - core.info(`🌀 Cloning ${repo}`); + core.startGroup(`Cloning ${repo}`); yield git.clone(remoteURL, targetBranch, '.'); + core.endGroup(); } else { - core.info(`✨ Initializing local git repo`); + core.startGroup(`Initializing local git repo`); yield git.init('.'); yield git.checkout(targetBranch); + core.endGroup(); } - core.info(`🏃 Copying ${path.join(currentdir, buildDir)} contents to ${tmpdir}`); - yield fs_extra_1.copySync(path.join(currentdir, buildDir), tmpdir, { - overwrite: true, - errorOnExist: false, - dereference: true - }); + yield core.group(`Copying ${path.join(currentdir, buildDir)} to ${tmpdir}`, () => __awaiter(this, void 0, void 0, function* () { + yield fs_extra_1.copy(path.join(currentdir, buildDir), tmpdir, { + filter: (src, dest) => { + core.info(`${src} => ${dest}`); + return true; + } + }).catch(error => { + core.error(error); + }); + })); if (fqdn) { - core.info(`✍️ Writing ${fqdn} domain name to ${path.join(tmpdir, 'CNAME')}`); + core.info(`Writing ${fqdn} domain name to ${path.join(tmpdir, 'CNAME')}`); yield fs.writeFileSync(path.join(tmpdir, 'CNAME'), fqdn.trim()); } if (nojekyll) { - core.info(`🚫 Disabling Jekyll support via ${path.join(tmpdir, '.nojekyll')}`); + core.info(`Disabling Jekyll support via ${path.join(tmpdir, '.nojekyll')}`); yield fs.writeFileSync(path.join(tmpdir, '.nojekyll'), ''); } const isDirty = yield git.isDirty(); core.debug(`isDirty=${isDirty}`); if (keepHistory && remoteBranchExists && !isDirty) { - core.info('⚠️ No changes to commit'); + core.info('No changes to commit'); return; } const committerPrs = addressparser_1.default(committer)[0]; - core.info(`🔨 Configuring git committer as ${committerPrs.name} <${committerPrs.address}>`); + core.startGroup(`Configuring git committer`); yield git.setConfig('user.name', committerPrs.name); yield git.setConfig('user.email', committerPrs.address); + core.endGroup(); if (!(yield git.hasChanges())) { - core.info('⚠️ Nothing to deploy'); + core.info('Nothing to deploy'); return; } - core.info(`📐 Updating index of working tree`); + core.startGroup(`Updating index of working tree`); yield git.add('.'); - if (allowEmptyCommit) { - core.debug(`Allow empty commit`); - } + core.endGroup(); const authorPrs = addressparser_1.default(author)[0]; - yield core.group(`📦 Committing changes as ${authorPrs.name} <${authorPrs.address}> author`, () => __awaiter(this, void 0, void 0, function* () { + yield core.group(`Committing changes`, () => __awaiter(this, void 0, void 0, function* () { yield git.commit(allowEmptyCommit, `${authorPrs.name} <${authorPrs.address}>`, commitMessage); yield git.showStat().then(output => { core.info(output); }); })); - core.info(`🏃 Pushing ${buildDir} directory to ${targetBranch} branch on ${repo} repo`); - if (!keepHistory) { - core.debug(`Force push`); + if (!dryRun) { + core.startGroup(`Pushing ${buildDir} directory to ${targetBranch} branch on ${repo} repo`); + if (!keepHistory) { + core.debug(`Force push`); + } + yield git.push(remoteURL, targetBranch, !keepHistory); + core.endGroup(); + core.info(`Content of ${buildDir} has been deployed to GitHub Pages!`); + } + else { + core.warning(`Push disabled (dry run)`); } - yield git.push(remoteURL, targetBranch, !keepHistory); process.chdir(currentdir); - core.info(`🎉 Content of ${buildDir} has been deployed to GitHub Pages`); } catch (error) { core.setFailed(error.message); diff --git a/src/git.ts b/src/git.ts index 9f4d523d6a0..ada52808076 100644 --- a/src/git.ts +++ b/src/git.ts @@ -1,4 +1,5 @@ -import * as exec from './exec'; +import * as mexec from './exec'; +import * as exec from '@actions/exec'; export const defaults = { targetBranch: 'gh-pages', @@ -7,51 +8,51 @@ export const defaults = { message: 'Deploy to GitHub pages' }; -const git = async (args: string[] = []): Promise => { - return await exec.exec(`git`, args, true).then(res => { +export async function remoteBranchExists(remoteURL: string, branch: string): Promise { + return await mexec.exec('git', ['ls-remote', '--heads', remoteURL, branch], true).then(res => { if (res.stderr != '' && !res.success) { throw new Error(res.stderr); } - return res.stdout.trim(); - }); -}; - -export async function remoteBranchExists(remoteURL: string, branch: string): Promise { - return await git(['ls-remote', '--heads', remoteURL, branch]).then(output => { - return output.trim().length > 0; + return res.stdout.trim().length > 0; }); } export async function clone(remoteURL: string, branch: string, dest: string): Promise { - await git(['clone', '--quiet', '--branch', branch, '--depth', '1', remoteURL, dest]); + await exec.exec('git', ['clone', '--quiet', '--branch', branch, '--depth', '1', remoteURL, dest]); } export async function init(dest: string): Promise { - await git(['init', dest]); + await exec.exec('git', ['init', dest]); } export async function checkout(branch: string): Promise { - await git(['checkout', '--orphan', branch]); + await exec.exec('git', ['checkout', '--orphan', branch]); } export async function isDirty(): Promise { - return await git(['status', '--short']).then(output => { - return output.trim().length > 0; + return await mexec.exec('git', ['status', '--short'], true).then(res => { + if (res.stderr != '' && !res.success) { + throw new Error(res.stderr); + } + return res.stdout.trim().length > 0; }); } export async function hasChanges(): Promise { - return await git(['status', '--porcelain']).then(output => { - return output.trim().length > 0; + return await mexec.exec('git', ['status', '--porcelain'], true).then(res => { + if (res.stderr != '' && !res.success) { + throw new Error(res.stderr); + } + return res.stdout.trim().length > 0; }); } export async function setConfig(key: string, value: string): Promise { - await git(['config', key, value]); + await exec.exec('git', ['config', key, value]); } export async function add(pattern: string): Promise { - await git(['add', '--all', pattern]); + await exec.exec('git', ['add', '--all', pattern]); } export async function commit(allowEmptyCommit: boolean, author: string, message: string): Promise { @@ -64,12 +65,15 @@ export async function commit(allowEmptyCommit: boolean, author: string, message: args.push('--author', author); } args.push('--message', message); - await git(args); + await exec.exec('git', args); } export async function showStat(): Promise { - return await git(['show', `--stat-count=2000`, 'HEAD']).then(output => { - return output; + return await mexec.exec('git', ['show', `--stat-count=2000`, 'HEAD'], true).then(res => { + if (res.stderr != '' && !res.success) { + throw new Error(res.stderr); + } + return res.stdout.trim(); }); } @@ -80,5 +84,5 @@ export async function push(remoteURL: string, branch: string, force: boolean): P args.push('--force'); } args.push(remoteURL, branch); - await git(args); + await exec.exec('git', args); } diff --git a/src/main.ts b/src/main.ts index d4f5f13bf47..8bc9b8c75ee 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,5 @@ import addressparser from 'addressparser'; -import {copySync} from 'fs-extra'; +import {copy} from 'fs-extra'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; @@ -19,6 +19,7 @@ async function run() { const commitMessage: string = core.getInput('commit_message') || git.defaults.message; const fqdn: string = core.getInput('fqdn'); const nojekyll: boolean = /false/i.test(core.getInput('jekyll')); + const dryRun: boolean = /true/i.test(core.getInput('dry-run')); if (!fs.existsSync(buildDir)) { core.setFailed('Build dir does not exist'); @@ -28,15 +29,15 @@ async function run() { let remoteURL = String('https://'); if (process.env['GH_PAT']) { core.debug(`Use GH_PAT`); - remoteURL = remoteURL.concat(process.env['GH_PAT'].trim()); + remoteURL = remoteURL.concat(process.env['GH_PAT'].trim(), '@'); } else if (process.env['GITHUB_TOKEN']) { core.debug(`Use GITHUB_TOKEN`); - remoteURL = remoteURL.concat('x-access-token:', process.env['GITHUB_TOKEN'].trim()); - } else { + remoteURL = remoteURL.concat('x-access-token:', process.env['GITHUB_TOKEN'].trim(), '@'); + } else if (!dryRun) { core.setFailed('You have to provide a GITHUB_TOKEN or GH_PAT'); return; } - remoteURL = remoteURL.concat('@', domain, '/', repo, '.git'); + remoteURL = remoteURL.concat(domain, '/', repo, '.git'); core.debug(`remoteURL=${remoteURL}`); const remoteBranchExists: boolean = await git.remoteBranchExists(remoteURL, targetBranch); @@ -49,71 +50,80 @@ async function run() { process.chdir(tmpdir); if (keepHistory && remoteBranchExists) { - core.info(`🌀 Cloning ${repo}`); + core.startGroup(`Cloning ${repo}`); await git.clone(remoteURL, targetBranch, '.'); + core.endGroup(); } else { - core.info(`✨ Initializing local git repo`); + core.startGroup(`Initializing local git repo`); await git.init('.'); await git.checkout(targetBranch); + core.endGroup(); } - core.info(`🏃 Copying ${path.join(currentdir, buildDir)} contents to ${tmpdir}`); - await copySync(path.join(currentdir, buildDir), tmpdir, { - overwrite: true, - errorOnExist: false, - dereference: true + await core.group(`Copying ${path.join(currentdir, buildDir)} to ${tmpdir}`, async () => { + await copy(path.join(currentdir, buildDir), tmpdir, { + filter: (src, dest) => { + core.info(`${src} => ${dest}`); + return true; + } + }).catch(error => { + core.error(error); + }); }); if (fqdn) { - core.info(`✍️ Writing ${fqdn} domain name to ${path.join(tmpdir, 'CNAME')}`); + core.info(`Writing ${fqdn} domain name to ${path.join(tmpdir, 'CNAME')}`); await fs.writeFileSync(path.join(tmpdir, 'CNAME'), fqdn.trim()); } if (nojekyll) { - core.info(`🚫 Disabling Jekyll support via ${path.join(tmpdir, '.nojekyll')}`); + core.info(`Disabling Jekyll support via ${path.join(tmpdir, '.nojekyll')}`); await fs.writeFileSync(path.join(tmpdir, '.nojekyll'), ''); } const isDirty: boolean = await git.isDirty(); core.debug(`isDirty=${isDirty}`); if (keepHistory && remoteBranchExists && !isDirty) { - core.info('⚠️ No changes to commit'); + core.info('No changes to commit'); return; } const committerPrs: addressparser.Address = addressparser(committer)[0]; - core.info(`🔨 Configuring git committer as ${committerPrs.name} <${committerPrs.address}>`); + core.startGroup(`Configuring git committer`); await git.setConfig('user.name', committerPrs.name); await git.setConfig('user.email', committerPrs.address); + core.endGroup(); if (!(await git.hasChanges())) { - core.info('⚠️ Nothing to deploy'); + core.info('Nothing to deploy'); return; } - core.info(`📐 Updating index of working tree`); + core.startGroup(`Updating index of working tree`); await git.add('.'); - - if (allowEmptyCommit) { - core.debug(`Allow empty commit`); - } + core.endGroup(); const authorPrs: addressparser.Address = addressparser(author)[0]; - await core.group(`📦 Committing changes as ${authorPrs.name} <${authorPrs.address}> author`, async () => { + await core.group(`Committing changes`, async () => { await git.commit(allowEmptyCommit, `${authorPrs.name} <${authorPrs.address}>`, commitMessage); await git.showStat().then(output => { core.info(output); }); }); - core.info(`🏃 Pushing ${buildDir} directory to ${targetBranch} branch on ${repo} repo`); - if (!keepHistory) { - core.debug(`Force push`); + if (!dryRun) { + core.startGroup(`Pushing ${buildDir} directory to ${targetBranch} branch on ${repo} repo`); + if (!keepHistory) { + core.debug(`Force push`); + } + await git.push(remoteURL, targetBranch, !keepHistory); + core.endGroup(); + core.info(`Content of ${buildDir} has been deployed to GitHub Pages!`); + } else { + core.warning(`Push disabled (dry run)`); } - await git.push(remoteURL, targetBranch, !keepHistory); process.chdir(currentdir); - core.info(`🎉 Content of ${buildDir} has been deployed to GitHub Pages`); } catch (error) { core.setFailed(error.message); }