From 45db33b86488c1043446d3efd045b943853ff11b Mon Sep 17 00:00:00 2001 From: Technote Date: Tue, 3 Mar 2020 18:33:00 +0900 Subject: [PATCH 1/2] feat: add test option (#45) --- __tests__/config.test.ts | 12 +-- __tests__/env.test.ts | 8 +- __tests__/index.test.ts | 160 +++++++++++++++++++++++++++++++++++++-- __tests__/misc.test.ts | 49 +++++++++++- src/config.ts | 4 +- src/env.ts | 3 +- src/index.ts | 13 ++-- src/misc.ts | 12 ++- 8 files changed, 231 insertions(+), 30 deletions(-) diff --git a/__tests__/config.test.ts b/__tests__/config.test.ts index 02c780a..18ee6fb 100644 --- a/__tests__/config.test.ts +++ b/__tests__/config.test.ts @@ -54,7 +54,7 @@ describe('getActionDefaultInputs', () => { describe('getConfig', () => { it('should get config 1', () => { - expect(getConfig(resolve(fixturesDir, 'test7'))).toEqual({ + expect(getConfig(resolve(fixturesDir, 'test7'), undefined)).toEqual({ 'inputs': { 'BRANCH_NAME': 'gh-actions', 'BUILD_COMMAND': '', @@ -80,7 +80,7 @@ describe('getConfig', () => { }); it('should get config 2', () => { - expect(getConfig(resolve(fixturesDir, 'test8'))).toEqual({ + expect(getConfig(resolve(fixturesDir, 'test8'), false)).toEqual({ 'inputs': { 'BRANCH_NAME': 'gh-actions', 'BUILD_COMMAND': '', @@ -105,7 +105,7 @@ describe('getConfig', () => { }); it('should get config 3', () => { - expect(getConfig(resolve(fixturesDir, 'test9'))).toEqual({ + expect(getConfig(resolve(fixturesDir, 'test9'), true)).toEqual({ 'inputs': { 'BRANCH_NAME': 'gh-actions', 'BUILD_COMMAND': '', @@ -122,7 +122,7 @@ describe('getConfig', () => { 'ORIGINAL_TAG_PREFIX': '', 'OUTPUT_BUILD_INFO_FILENAME': '', 'PACKAGE_MANAGER': '', - 'TEST_TAG_PREFIX': '', + 'TEST_TAG_PREFIX': 'test/', }, 'owner': 'owner9', 'repo': 'repo9', @@ -130,7 +130,7 @@ describe('getConfig', () => { }); it('should get config 4', () => { - expect(getConfig(resolve(fixturesDir, 'test10'))).toEqual({ + expect(getConfig(resolve(fixturesDir, 'test10'), undefined)).toEqual({ 'inputs': { 'BRANCH_NAME': 'gh-actions', 'BUILD_COMMAND': '', @@ -155,7 +155,7 @@ describe('getConfig', () => { }); it('should get config 5', () => { - expect(getConfig(resolve(fixturesDir, 'test12'))).toEqual({ + expect(getConfig(resolve(fixturesDir, 'test12'), undefined)).toEqual({ 'inputs': { 'BRANCH_NAME': 'gh-actions', 'BUILD_COMMAND': '', diff --git a/__tests__/env.test.ts b/__tests__/env.test.ts index 309a94a..d388d56 100644 --- a/__tests__/env.test.ts +++ b/__tests__/env.test.ts @@ -9,16 +9,14 @@ describe('setEnv', () => { testEnv(); it('should set env 1', () => { - delete process.env.INPUT_GITHUB_TOKEN; delete process.env.GITHUB_ACTOR; delete process.env.GITHUB_WORKSPACE; setEnv({ owner: 'test-owner', repo: 'test-repo', - }, 'token', '.'); + }, '.'); - expect(process.env).toHaveProperty('INPUT_GITHUB_TOKEN'); expect(process.env).toHaveProperty('GITHUB_ACTOR'); expect(process.env).toHaveProperty('GITHUB_WORKSPACE'); expect(process.env).not.toHaveProperty('INPUT_COMMIT_NAME'); @@ -26,7 +24,6 @@ describe('setEnv', () => { }); it('should set env 2', () => { - delete process.env.INPUT_GITHUB_TOKEN; delete process.env.GITHUB_ACTOR; delete process.env.GITHUB_WORKSPACE; @@ -37,9 +34,8 @@ describe('setEnv', () => { COMMIT_NAME: 'test name', FETCH_DEPTH: '5', }, - }, 'token', 'test'); + }, 'test'); - expect(process.env).toHaveProperty('INPUT_GITHUB_TOKEN'); expect(process.env).toHaveProperty('GITHUB_ACTOR'); expect(process.env).toHaveProperty('GITHUB_WORKSPACE'); expect(process.env).toHaveProperty('INPUT_COMMIT_NAME'); diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index 1d8fb45..cd385de 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -6,15 +6,23 @@ import { testChildProcess, spyOnExec, execCalledWith, - testFs, + testFs, setChildProcessParams, } from '@technote-space/github-action-test-helper'; import { Logger } from '@technote-space/github-action-helper'; +import commander from 'commander'; import { execute } from '../src'; -testFs(false); -const saveArgv = process.argv; +const setExists = testFs(false); +const saveArgv = process.argv; beforeEach(() => { Logger.resetForTesting(); + delete commander.token; + delete commander.package; + delete commander.test; + delete commander.tag; + delete commander.branch; + delete commander.workspace; + delete commander.dryRun; }); describe('execute', () => { @@ -24,7 +32,7 @@ describe('execute', () => { process.argv = saveArgv; }); - it('should throw error', async() => { + it('should throw error 1', async() => { process.argv = [ 'node', 'index.js', @@ -35,6 +43,17 @@ describe('execute', () => { await expect(execute()).rejects.toThrow(' is required.'); }); + it('should throw error 2', async() => { + process.argv = [ + 'node', + 'index.js', + '--token', + 'token', + ]; + + await expect(execute()).rejects.toThrow(' is required.'); + }); + it('should do nothing', async() => { const mockExec = spyOnExec(); const mockStdout = spyOnStdout(); @@ -55,7 +74,7 @@ describe('execute', () => { ]); }); - it('should push', async() => { + it('should push 1', async() => { const mockExec = spyOnExec(); const mockStdout = spyOnStdout(); const cwd = process.cwd(); @@ -201,6 +220,137 @@ describe('execute', () => { ]); }); + it('should push 2', async() => { + const mockExec = spyOnExec(); + const mockStdout = spyOnStdout(); + const cwd = process.cwd(); + process.argv = [ + 'node', + 'index.js', + '--token', + 'token', + '-p', + '__tests__/fixtures/test11', + '-w', + '__tests__/tmp', + '--test', + ]; + setChildProcessParams({ + stdout: (command) => { + if (command === 'git tag') { + return 'v1\nv1.2.3\n1.2'; + } + + return ''; + }, + }); + setExists([false, true, false]); + + await execute(); + + execCalledWith(mockExec, [ + 'git tag', + `rm -rdf ${cwd}/__tests__/tmp/.work/build ${cwd}/__tests__/tmp/.work/push`, + 'git init \'.\'', + 'git remote add origin \'https://test-owner:token@github.com/test-owner/test-repo.git\' > /dev/null 2>&1 || :', + 'git fetch --no-tags origin \'refs/heads/gh-actions:refs/remotes/origin/gh-actions\' || :', + 'git checkout -b gh-actions origin/gh-actions || :', + 'git init \'.\'', + 'git checkout --orphan gh-actions', + `rsync -ac -C '--filter=:- .gitignore' --exclude '.git' --exclude '.work' --exclude '.github' --delete './' '${cwd}/__tests__/tmp/.work/build'`, + 'rm -rdf node_modules', + 'npm install --production', + `mv -f '${cwd}/__tests__/tmp/.work/build/action.yaml' '${cwd}/__tests__/tmp/.work/push/action.yml' > /dev/null 2>&1 || :`, + `mv -f '${cwd}/__tests__/tmp/.work/build/action.yml' '${cwd}/__tests__/tmp/.work/push/action.yml' > /dev/null 2>&1 || :`, + 'rm -rdf .[!.]*', + 'rm -rdf *.js', + 'rm -rdf *.ts', + 'rm -rdf *.json', + 'rm -rdf *.lock', + 'rm -rdf *.yml', + 'rm -rdf *.yaml', + 'rm -rdf __tests__ src', + `mv -f '${cwd}/__tests__/tmp/.work/push/action.yml' '${cwd}/__tests__/tmp/.work/build/action.yml' > /dev/null 2>&1 || :`, + `rsync -rl --exclude '.git' --delete '${cwd}/__tests__/tmp/.work/build/' '${cwd}/__tests__/tmp/.work/push'`, + 'git config \'user.name\' \'github-actions[bot]\'', + 'git config \'user.email\' \'41898282+github-actions[bot]@users.noreply.github.com\'', + 'git add --all', + 'git commit --allow-empty -qm \'feat: Build for release\'', + 'git show \'--stat-count=10\' HEAD', + 'git tag', + 'git tag -d v1 \'v1.2.3\' \'1.2\' > /dev/null 2>&1', + 'git fetch \'https://test-owner:token@github.com/test-owner/test-repo.git\' --tags > /dev/null 2>&1', + 'git push \'https://test-owner:token@github.com/test-owner/test-repo.git\' --delete \'tags/test/v1.2.4\' > /dev/null 2>&1 || :', + 'git push \'https://test-owner:token@github.com/test-owner/test-repo.git\' --delete \'tags/test/v1.2\' > /dev/null 2>&1 || :', + 'git push \'https://test-owner:token@github.com/test-owner/test-repo.git\' --delete tags/test/v1 > /dev/null 2>&1 || :', + 'git tag -d \'test/v1.2.4\' || :', + 'git tag -d \'test/v1.2\' || :', + 'git tag -d test/v1 || :', + 'git tag \'test/v1.2.4\'', + 'git tag \'test/v1.2\'', + 'git tag test/v1', + 'git push --tags \'https://test-owner:token@github.com/test-owner/test-repo.git\' \'gh-actions:refs/heads/gh-actions\' > /dev/null 2>&1 || :', + ]); + stdoutCalledWith(mockStdout, [ + '[command]git tag', + ' >> v1', + ' >> v1.2.3', + ' >> 1.2', + '[command]rm -rdf ', + '::group::Fetching...', + '[command]git init \'.\'', + '[command]git remote add origin', + '[command]git fetch --no-tags origin \'refs/heads/gh-actions:refs/remotes/origin/gh-actions\'', + '::endgroup::', + '::group::Switching branch to [gh-actions]...', + '[command]git checkout -b gh-actions origin/gh-actions', + '> remote branch gh-actions not found.', + '> now branch: ', + '::endgroup::', + '::group::Initializing local git repo [gh-actions]...', + '[command]git init \'.\'', + '[command]git checkout --orphan gh-actions', + '::endgroup::', + '::group::Copying current source to build directory...', + '[command]rsync -ac -C \'--filter=:- .gitignore\' --exclude \'.git\' --exclude \'.work\' --exclude \'.github\' --delete \'./\' \'\'', + '::endgroup::', + '::group::Running build for release...', + '[command]rm -rdf node_modules', + '[command]npm install --production', + '[command]rm -rdf .[!.]*', + '[command]rm -rdf *.js', + '[command]rm -rdf *.ts', + '[command]rm -rdf *.json', + '[command]rm -rdf *.lock', + '[command]rm -rdf *.yml', + '[command]rm -rdf *.yaml', + '[command]rm -rdf __tests__ src', + '::endgroup::', + '::group::Copying contents to ...', + '[command]rsync -rl --exclude \'.git\' --delete \'/\' \'\'', + '::endgroup::', + '::group::Configuring git committer to be github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>...', + '[command]git config \'user.name\' \'github-actions[bot]\'', + '[command]git config \'user.email\' \'41898282+github-actions[bot]@users.noreply.github.com\'', + '[command]git add --all', + '[command]git commit --allow-empty -qm \'feat: Build for release\'', + '[command]git show \'--stat-count=10\' HEAD', + '::endgroup::', + '::group::Pushing to test-owner/test-repo@gh-actions (tag: test/v1.2.4)...', + '[command]git fetch origin --tags', + '[command]git push origin --delete tags/test/v1.2.4', + '[command]git push origin --delete tags/test/v1.2', + '[command]git push origin --delete tags/test/v1', + '[command]git tag -d \'test/v1.2.4\'', + '[command]git tag -d \'test/v1.2\'', + '[command]git tag -d test/v1', + '[command]git tag \'test/v1.2.4\'', + '[command]git tag \'test/v1.2\'', + '[command]git tag test/v1', + '[command]git push --tags origin gh-actions:refs/heads/gh-actions', + ]); + }); + it('should dry run', async() => { const mockExec = spyOnExec(); const mockStdout = spyOnStdout(); diff --git a/__tests__/misc.test.ts b/__tests__/misc.test.ts index 0e06e77..42cc9bc 100644 --- a/__tests__/misc.test.ts +++ b/__tests__/misc.test.ts @@ -1,9 +1,10 @@ /* eslint-disable no-magic-numbers */ import { resolve } from 'path'; -import { testEnv } from '@technote-space/github-action-test-helper'; +import { testEnv, testFs, setChildProcessParams } from '@technote-space/github-action-test-helper'; import { getRepository, getContext, getContextArgs, getGitHelper } from '../src/misc'; const fixturesDir = resolve(__dirname, 'fixtures'); +testFs(true); describe('getRepository', () => { it('should throw error 1', () => { @@ -59,8 +60,21 @@ describe('getContext', () => { }); describe('getContextArgs', () => { - it('should get context args', () => { - expect(getContextArgs('v1.2.3', 'release/v1.2.3', { + testEnv(); + + it('should throw', async() => { + process.env.INPUT_GITHUB_TOKEN = 'token'; + + await expect(getContextArgs(getGitHelper(), undefined, 'release/v1.2.3', '', { + owner: 'test-owner', + repo: 'test-repo', + })).rejects.toThrow(' is required.'); + }); + + it('should get context args 1', async() => { + process.env.INPUT_GITHUB_TOKEN = 'token'; + + expect(await getContextArgs(getGitHelper(), 'v1.2.3', 'release/v1.2.3', '', { owner: 'test-owner', repo: 'test-repo', })).toEqual({ @@ -70,6 +84,35 @@ describe('getContextArgs', () => { tagName: 'v1.2.3', }); }); + + it('should get context args 2', async() => { + process.env.INPUT_GITHUB_TOKEN = 'token'; + setChildProcessParams({ + stdout: (command) => { + if (command === 'git tag') { + return 'v1\nv1.2.3\n1.2'; + } + + return ''; + }, + }); + + expect(await getContextArgs(getGitHelper(), '', 'release/v1.2.3', '', { + owner: 'test-owner', + repo: 'test-repo', + inputs: { + TEST_TAG_PREFIX: 'test/', + }, + })).toEqual({ + owner: 'test-owner', + repo: 'test-repo', + branch: 'release/v1.2.3', + tagName: 'test/v1.2.4', + inputs: { + 'TEST_TAG_PREFIX': 'test/', + }, + }); + }); }); describe('getGitHelper', () => { diff --git a/src/config.ts b/src/config.ts index d23db94..1f39a4a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -24,7 +24,7 @@ export const getActionDefaultInputs = (): { [key: string]: string } => { }))); }; -export const getConfig = (dir: string): Config | never => { +export const getConfig = (dir: string, isTest: boolean | undefined): Config | never => { const explorer = cosmiconfigSync('releasega'); const {config = {}} = explorer.search(dir) || {}; if (!('owner' in config) || !('repo' in config)) { @@ -48,5 +48,5 @@ export const getConfig = (dir: string): Config | never => { } } - return {...config, inputs: {...getActionDefaultInputs(), ...normalizeConfigKeys(config.inputs ?? config.INPUTS ?? {})}}; + return {...config, inputs: {...getActionDefaultInputs(), ...{TEST_TAG_PREFIX: isTest ? 'test/' : ''}, ...normalizeConfigKeys(config.inputs ?? config.INPUTS ?? {})}}; }; diff --git a/src/env.ts b/src/env.ts index c7d077d..939aae5 100644 --- a/src/env.ts +++ b/src/env.ts @@ -12,8 +12,7 @@ export const loadTokenFromEnv = (dir: string): string | undefined => { return config.token ?? config.TOKEN; }; -export const setEnv = (config: Config, token: string, workspace: string): void => { - process.env.INPUT_GITHUB_TOKEN = token; +export const setEnv = (config: Config, workspace: string): void => { process.env.GITHUB_ACTOR = config.owner; process.env.GITHUB_WORKSPACE = resolve(process.cwd(), workspace); diff --git a/src/index.ts b/src/index.ts index 2e6cd79..85ece0a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,13 +6,14 @@ import { setEnv, loadTokenFromEnv } from './env'; export const execute = async(): Promise => { commander - .requiredOption('-t, --tag ', 'tag name') + .option('-t, --tag ', 'tag name') .option('--token ', 'token') .option('-b, --branch [branch]', 'branch name') .option('-w, --workspace [workspace]', 'working directory name', '.') .option('-p, --package [package]', 'package file directory name', process.cwd()) .option('-e, --env [env]', 'env file name', '.env') .option('-n, --dry-run', 'show what would have been pushed') + .option('--test', 'whether it is test') .parse(process.argv); const token = commander.token || loadTokenFromEnv(commander.package); @@ -20,15 +21,17 @@ export const execute = async(): Promise => { throw new Error(' is required.'); } - const config = getConfig(commander.package); - const args = getContextArgs(commander.tag, commander.branch, config); - setEnv(config, token, commander.workspace); + process.env.INPUT_GITHUB_TOKEN = token; + const helper = getGitHelper(); + const config = getConfig(commander.package, commander.test); + const args = await getContextArgs(helper, commander.tag, commander.branch, commander.package, config); + + setEnv(config, commander.workspace); if (!isValidContext(args)) { console.log('This is not target tag'); return; } - const helper = getGitHelper(); await prepare(helper, args); await commit(helper); if (!commander.dryRun) { diff --git a/src/misc.ts b/src/misc.ts index 64726d7..a91025a 100644 --- a/src/misc.ts +++ b/src/misc.ts @@ -22,7 +22,17 @@ export const getRepository = (dir: string): { owner: string; repo: string } | ne }; }; -export const getContextArgs = (tagName: string, branch: string | undefined, config: Config): ContextArgs => ({...config, tagName, branch}); +export const getContextArgs = async(helper: GitHelper, tagName: string | undefined, branch: string | undefined, dir: string, config: Config): Promise => { + if (!tagName) { + if (!config.inputs?.TEST_TAG_PREFIX) { + throw new Error(' is required.'); + } + + return {...config, tagName: config.inputs.TEST_TAG_PREFIX + await helper.getNewPatchVersion(dir), branch}; + } + + return {...config, tagName, branch}; +}; export const getContext = (args: ContextArgs): Context => ({ payload: { From 4007d00d7f0ff1d1ffca611918a9f2d898c1bc0b Mon Sep 17 00:00:00 2001 From: Technote Date: Tue, 3 Mar 2020 19:01:17 +0900 Subject: [PATCH 2/2] docs: add test option description --- README.ja.md | 8 ++++++++ README.md | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/README.ja.md b/README.ja.md index 94008ed..477c1f9 100644 --- a/README.ja.md +++ b/README.ja.md @@ -86,6 +86,8 @@ -t v1.2.3 ``` +[`test`](#test) オプションを設定している場合は不要です。 + ### オプション #### branch ビルドに使用するブランチ名 @@ -124,6 +126,12 @@ -p /tmp/test-repo ``` +#### test +テストモード + +タグ名は最新のタグから決まります。 +テスト用タグプリフィックスに `test/` が設定されます。 + ## 設定 `Release GitHub Actions CLI` は `.releasegarc`, `.releasegarc.json`, `.releasegarc.js`, `.releasega.config.js` または `package.json` の `releasega` プロパティで設定できます。 diff --git a/README.md b/README.md index be31f01..fadc6aa 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,8 @@ e.g. -t v1.2.3 ``` +Not required if [`test`](# test) option is set. + ### Option #### branch Branch name to use for build. @@ -124,6 +126,12 @@ e.g. -p /tmp/test-repo ``` +#### test +Test mode + +The tag name is determined from the latest tag. +`test/` is set as the test tag prefix. + ## Settings `Release GitHub Actions CLI` can be configured using `.releasegarc`, `.releasegarc.json`, `.releasegarc.js`, `.releasega.config.js` or `releasega` property in `package.json`.