From fd6e5fc7ce07cfd94a2311f7ac112bd797c3aee7 Mon Sep 17 00:00:00 2001 From: Shohei Ueda <30958501+peaceiris@users.noreply.github.com> Date: Sat, 7 Mar 2020 00:41:30 +0900 Subject: [PATCH] test: Add testing for set-tokens.ts (#126) * test: remove main * test: add getPublishRepo() * test: Add setPersonalToken() * test: Add setGithubToken() * test: add showInputs() * test: .nojekyll already exists * test: ignore jest/expect-expect * refactor: squash inputs log * fix: throw error message --- __tests__/get-inputs.test.ts | 93 ++++++++++++++++++++++++++++++- __tests__/main.test.ts | 32 ----------- __tests__/set-tokens.test.ts | 105 +++++++++++++++++++++++++++++++++++ __tests__/utils.test.ts | 51 +++++++++++------ src/get-inputs.ts | 40 ++++++------- src/git-utils.ts | 4 +- src/index.ts | 2 +- src/main.ts | 7 ++- src/set-tokens.ts | 78 ++++++++++++++++---------- 9 files changed, 306 insertions(+), 106 deletions(-) delete mode 100644 __tests__/main.test.ts create mode 100644 __tests__/set-tokens.test.ts diff --git a/__tests__/get-inputs.test.ts b/__tests__/get-inputs.test.ts index 01872ce..34bad60 100644 --- a/__tests__/get-inputs.test.ts +++ b/__tests__/get-inputs.test.ts @@ -1,6 +1,7 @@ // import * as main from '../src/main'; import {Inputs} from '../src/interfaces'; -import {getInputs} from '../src/get-inputs'; +import {showInputs, getInputs} from '../src/get-inputs'; +import os from 'os'; beforeEach(() => { jest.resetModules(); @@ -25,6 +26,96 @@ afterEach(() => { delete process.env['INPUT_CNAME']; }); +// Assert that process.stdout.write calls called only with the given arguments. +// cf. https://github.com/actions/toolkit/blob/8b0300129f08728419263b016de8630f1d426d5f/packages/core/__tests__/core.test.ts +function assertWriteCalls(calls: string[]): void { + expect(process.stdout.write).toHaveBeenCalledTimes(calls.length); + + for (let i = 0; i < calls.length; i++) { + expect(process.stdout.write).toHaveBeenNthCalledWith(i + 1, calls[i]); + } +} + +function setTestInputs(): void { + process.env['INPUT_PUBLISH_BRANCH'] = 'master'; + process.env['INPUT_PUBLISH_DIR'] = 'out'; + process.env['INPUT_EXTERNAL_REPOSITORY'] = 'user/repo'; + process.env['INPUT_ALLOW_EMPTY_COMMIT'] = 'true'; + process.env['INPUT_KEEP_FILES'] = 'true'; + process.env['INPUT_FORCE_ORPHAN'] = 'true'; + process.env['INPUT_USER_NAME'] = 'username'; + process.env['INPUT_USER_EMAIL'] = 'github@github.com'; + process.env['INPUT_COMMIT_MESSAGE'] = 'feat: Add new feature'; + process.env['INPUT_TAG_NAME'] = 'deploy-v1.2.3'; + process.env['INPUT_TAG_MESSAGE'] = 'Deployment v1.2.3'; + process.env['INPUT_DISABLE_NOJEKYLL'] = 'true'; + process.env['INPUT_CNAME'] = 'github.com'; +} + +function getInputsLog(authMethod: string, inps: Inputs): string { + return `\ +[INFO] ${authMethod}: true +[INFO] PublishBranch: ${inps.PublishBranch} +[INFO] PublishDir: ${inps.PublishDir} +[INFO] ExternalRepository: ${inps.ExternalRepository} +[INFO] AllowEmptyCommit: ${inps.AllowEmptyCommit} +[INFO] KeepFiles: ${inps.KeepFiles} +[INFO] ForceOrphan: ${inps.ForceOrphan} +[INFO] UserName: ${inps.UserName} +[INFO] UserEmail: ${inps.UserEmail} +[INFO] CommitMessage: ${inps.CommitMessage} +[INFO] TagName: ${inps.TagName} +[INFO] TagMessage: ${inps.TagMessage} +[INFO] DisableNoJekyll: ${inps.DisableNoJekyll} +[INFO] CNAME: ${inps.CNAME} +`; +} + +describe('showInputs()', () => { + beforeEach(() => { + process.stdout.write = jest.fn(); + }); + + // eslint-disable-next-line jest/expect-expect + test('print all inputs DeployKey', () => { + process.env['INPUT_DEPLOY_KEY'] = 'test_deploy_key'; + setTestInputs(); + + const inps: Inputs = getInputs(); + showInputs(inps); + + const authMethod = 'DeployKey'; + const test = getInputsLog(authMethod, inps); + assertWriteCalls([`${test}${os.EOL}`]); + }); + + // eslint-disable-next-line jest/expect-expect + test('print all inputs GithubToken', () => { + process.env['INPUT_GITHUB_TOKEN'] = 'test_github_token'; + setTestInputs(); + + const inps: Inputs = getInputs(); + showInputs(inps); + + const authMethod = 'GithubToken'; + const test = getInputsLog(authMethod, inps); + assertWriteCalls([`${test}${os.EOL}`]); + }); + + // eslint-disable-next-line jest/expect-expect + test('print all inputs PersonalToken', () => { + process.env['INPUT_PERSONAL_TOKEN'] = 'test_personal_token'; + setTestInputs(); + + const inps: Inputs = getInputs(); + showInputs(inps); + + const authMethod = 'PersonalToken'; + const test = getInputsLog(authMethod, inps); + assertWriteCalls([`${test}${os.EOL}`]); + }); +}); + describe('getInputs()', () => { test('get default inputs', () => { process.env['INPUT_DEPLOY_KEY'] = 'test_deploy_key'; diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts deleted file mode 100644 index 940b6c7..0000000 --- a/__tests__/main.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -// import {run} from '../src/main'; - -beforeEach(() => { - jest.resetModules(); -}); - -afterEach(() => { - delete process.env['INPUT_DEPLOY_KEY']; - delete process.env['INPUT_GITHUB_TOKEN']; - delete process.env['INPUT_PERSONAL_TOKEN']; - delete process.env['INPUT_PUBLISH_BRANCH']; - delete process.env['INPUT_PUBLISH_DIR']; - delete process.env['INPUT_EXTERNAL_REPOSITORY']; - delete process.env['INPUT_ALLOW_EMPTY_COMMIT']; - delete process.env['INPUT_KEEP_FILES']; - delete process.env['INPUT_FORCE_ORPHAN']; - delete process.env['INPUT_USER_NAME']; - delete process.env['INPUT_USER_EMAIL']; - delete process.env['INPUT_COMMIT_MESSAGE']; - delete process.env['INPUT_TAG_NAME']; - delete process.env['INPUT_TAG_MESSAGE']; - delete process.env['INPUT_TAG_OVERWRITE']; -}); - -describe('Integration testing run()', () => { - test('succeed in pushing using deploy key', async () => { - // process.env['INPUT_DEPLOY_KEY'] = 'test_deploy_key'; - // process.env['GITHUB_REPOSITORY'] = 'owner/repo'; - // const exitcode = await run(); - expect(0).toBe(0); - }); -}); diff --git a/__tests__/set-tokens.test.ts b/__tests__/set-tokens.test.ts new file mode 100644 index 0000000..7780c92 --- /dev/null +++ b/__tests__/set-tokens.test.ts @@ -0,0 +1,105 @@ +import { + getPublishRepo, + setPersonalToken, + setGithubToken +} from '../src/set-tokens'; + +beforeEach(() => { + jest.resetModules(); +}); + +// afterEach(() => { + +// }); + +describe('getPublishRepo()', () => { + test('return repository name', () => { + const test = getPublishRepo('', 'owner', 'repo'); + expect(test).toMatch('owner/repo'); + }); + + test('return external repository name', () => { + const test = getPublishRepo('extOwner/extRepo', 'owner', 'repo'); + expect(test).toMatch('extOwner/extRepo'); + }); +}); + +describe('setGithubToken()', () => { + test('return remote url with GITHUB_TOKEN gh-pages', () => { + const expected = + 'https://x-access-token:GITHUB_TOKEN@github.com/owner/repo.git'; + const test = setGithubToken( + 'GITHUB_TOKEN', + 'owner/repo', + 'gh-pages', + '', + 'refs/heads/master', + 'push' + ); + expect(test).toMatch(expected); + }); + + test('return remote url with GITHUB_TOKEN master', () => { + const expected = + 'https://x-access-token:GITHUB_TOKEN@github.com/owner/repo.git'; + const test = setGithubToken( + 'GITHUB_TOKEN', + 'owner/repo', + 'master', + '', + 'refs/heads/source', + 'push' + ); + expect(test).toMatch(expected); + }); + + test('throw error master to master', () => { + expect(() => { + setGithubToken( + 'GITHUB_TOKEN', + 'owner/repo', + 'master', + '', + 'refs/heads/master', + 'push' + ); + }).toThrowError('You deploy from master to master'); + }); + + test('throw error external repository with GITHUB_TOKEN', () => { + expect(() => { + setGithubToken( + 'GITHUB_TOKEN', + 'owner/repo', + 'gh-pages', + 'extOwner/extRepo', + 'refs/heads/master', + 'push' + ); + }).toThrowError( + 'GITHUB_TOKEN does not support to push to an external repository' + ); + }); + + test('return remote url with GITHUB_TOKEN pull_request', () => { + const expected = + 'https://x-access-token:GITHUB_TOKEN@github.com/owner/repo.git'; + const test = setGithubToken( + 'GITHUB_TOKEN', + 'owner/repo', + 'gh-pages', + '', + 'refs/pull/29/merge', + 'pull_request' + ); + expect(test).toMatch(expected); + }); +}); + +describe('setPersonalToken()', () => { + test('return remote url with personal access token', () => { + const expected = 'https://x-access-token:pat@github.com/owner/repo.git'; + const test = setPersonalToken('pat', 'owner/repo'); + expect(test).toMatch(expected); + }); +}); diff --git a/__tests__/utils.test.ts b/__tests__/utils.test.ts index ba3f331..23b7c3b 100644 --- a/__tests__/utils.test.ts +++ b/__tests__/utils.test.ts @@ -77,8 +77,8 @@ describe('addNoJekyll()', () => { const filepath = path.join(workDir, '.nojekyll'); await addNoJekyll(workDir, false, 'gh-pages'); - const test1 = fs.existsSync(filepath); - expect(test1).toBe(true); + const test = fs.existsSync(filepath); + expect(test).toBe(true); fs.unlinkSync(filepath); }); @@ -91,8 +91,23 @@ describe('addNoJekyll()', () => { const filepath = path.join(workDir, '.nojekyll'); await addNoJekyll(workDir, false, 'master'); - const test2 = fs.existsSync(filepath); - expect(test2).toBe(true); + const test = fs.existsSync(filepath); + expect(test).toBe(true); + + fs.unlinkSync(filepath); + }); + + test('.nojekyll already exists', async () => { + let workDir = ''; + (async (): Promise => { + workDir = await getWorkDir(); + })(); + const filepath = path.join(workDir, '.nojekyll'); + fs.closeSync(fs.openSync(filepath, 'w')); + + await addNoJekyll(workDir, false, 'master'); + const test = fs.existsSync(filepath); + expect(test).toBe(true); fs.unlinkSync(filepath); }); @@ -105,8 +120,8 @@ describe('addNoJekyll()', () => { const filepath = path.join(workDir, '.nojekyll'); await addNoJekyll(workDir, true, 'gh-pages'); - const test3 = fs.existsSync(filepath); - expect(test3).toBe(false); + const test = fs.existsSync(filepath); + expect(test).toBe(false); }); test('not add .nojekyll disable_nojekyll master', async () => { @@ -117,8 +132,8 @@ describe('addNoJekyll()', () => { const filepath = path.join(workDir, '.nojekyll'); await addNoJekyll(workDir, true, 'master'); - const test4 = fs.existsSync(filepath); - expect(test4).toBe(false); + const test = fs.existsSync(filepath); + expect(test).toBe(false); }); test('not add .nojekyll other-branch', async () => { @@ -129,8 +144,8 @@ describe('addNoJekyll()', () => { const filepath = path.join(workDir, '.nojekyll'); await addNoJekyll(workDir, false, 'other-branch'); - const test5 = fs.existsSync(filepath); - expect(test5).toBe(false); + const test = fs.existsSync(filepath); + expect(test).toBe(false); }); test('not add .nojekyll disable_nojekyll other-branch', async () => { @@ -141,8 +156,8 @@ describe('addNoJekyll()', () => { const filepath = path.join(workDir, '.nojekyll'); await addNoJekyll(workDir, true, 'other-branch'); - const test6 = fs.existsSync(filepath); - expect(test6).toBe(false); + const test = fs.existsSync(filepath); + expect(test).toBe(false); }); }); @@ -155,8 +170,8 @@ describe('addCNAME()', () => { const filepath = path.join(workDir, 'CNAME'); await addCNAME(workDir, 'github.com'); - const test1 = fs.readFileSync(filepath, 'utf8'); - expect(test1).toMatch('github.com'); + const test = fs.readFileSync(filepath, 'utf8'); + expect(test).toMatch('github.com'); fs.unlinkSync(filepath); }); @@ -169,8 +184,8 @@ describe('addCNAME()', () => { const filepath = path.join(workDir, 'CNAME'); await addCNAME(workDir, ''); - const test2 = fs.existsSync(filepath); - expect(test2).toBe(false); + const test = fs.existsSync(filepath); + expect(test).toBe(false); }); test('CNAME already exists', async () => { @@ -182,8 +197,8 @@ describe('addCNAME()', () => { await addCNAME(workDir, 'github.io'); await addCNAME(workDir, 'github.com'); - const test3 = fs.readFileSync(filepath, 'utf8'); - expect(test3).toMatch('github.io'); + const test = fs.readFileSync(filepath, 'utf8'); + expect(test).toMatch('github.io'); fs.unlinkSync(filepath); }); diff --git a/src/get-inputs.ts b/src/get-inputs.ts index 032f605..2cf71bb 100644 --- a/src/get-inputs.ts +++ b/src/get-inputs.ts @@ -1,28 +1,32 @@ import * as core from '@actions/core'; import {Inputs} from './interfaces'; -function showInputs(inps: Inputs): void { +export function showInputs(inps: Inputs): void { + let authMethod = ''; if (inps.DeployKey) { - core.info(`[INFO] DeployKey: true`); + authMethod = 'DeployKey'; } else if (inps.GithubToken) { - core.info(`[INFO] GithubToken: true`); + authMethod = 'GithubToken'; } else if (inps.PersonalToken) { - core.info(`[INFO] PersonalToken: true`); + authMethod = 'PersonalToken'; } - core.info(`[INFO] PublishBranch: ${inps.PublishBranch}`); - core.info(`[INFO] PublishDir: ${inps.PublishDir}`); - core.info(`[INFO] ExternalRepository: ${inps.ExternalRepository}`); - core.info(`[INFO] AllowEmptyCommit: ${inps.AllowEmptyCommit}`); - core.info(`[INFO] KeepFiles: ${inps.KeepFiles}`); - core.info(`[INFO] ForceOrphan: ${inps.ForceOrphan}`); - core.info(`[INFO] UserName: ${inps.UserName}`); - core.info(`[INFO] UserEmail: ${inps.UserEmail}`); - core.info(`[INFO] CommitMessage: ${inps.CommitMessage}`); - core.info(`[INFO] TagName: ${inps.TagName}`); - core.info(`[INFO] TagMessage: ${inps.TagMessage}`); - core.info(`[INFO] DisableNoJekyll: ${inps.DisableNoJekyll}`); - core.info(`[INFO] CNAME: ${inps.CNAME}`); + core.info(`\ +[INFO] ${authMethod}: true +[INFO] PublishBranch: ${inps.PublishBranch} +[INFO] PublishDir: ${inps.PublishDir} +[INFO] ExternalRepository: ${inps.ExternalRepository} +[INFO] AllowEmptyCommit: ${inps.AllowEmptyCommit} +[INFO] KeepFiles: ${inps.KeepFiles} +[INFO] ForceOrphan: ${inps.ForceOrphan} +[INFO] UserName: ${inps.UserName} +[INFO] UserEmail: ${inps.UserEmail} +[INFO] CommitMessage: ${inps.CommitMessage} +[INFO] TagName: ${inps.TagName} +[INFO] TagMessage: ${inps.TagMessage} +[INFO] DisableNoJekyll: ${inps.DisableNoJekyll} +[INFO] CNAME: ${inps.CNAME} +`); } export function getInputs(): Inputs { @@ -49,7 +53,5 @@ export function getInputs(): Inputs { CNAME: core.getInput('cname') }; - showInputs(inps); - return inps; } diff --git a/src/git-utils.ts b/src/git-utils.ts index c56eb7a..cf291ef 100644 --- a/src/git-utils.ts +++ b/src/git-utils.ts @@ -94,7 +94,7 @@ export async function setRepo( core.info( `[INFO] first deployment, create new branch ${inps.PublishBranch}` ); - core.info(e); + core.info(e.message); await createWorkDir(workDir); process.chdir(workDir); await createBranchForce(inps.PublishBranch); @@ -156,7 +156,7 @@ export async function commit( } } catch (e) { core.info('[INFO] skip commit'); - core.debug(`[INFO] skip commit ${e}`); + core.debug(`[INFO] skip commit ${e.message}`); } } diff --git a/src/index.ts b/src/index.ts index 6b02c74..0133eaf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,6 @@ import * as main from './main'; try { await main.run(); } catch (e) { - core.setFailed(`Action failed with "${e}"`); + core.setFailed(`Action failed with "${e.message}"`); } })(); diff --git a/src/main.ts b/src/main.ts index 98bc554..876cccf 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,7 @@ import * as core from '@actions/core'; import * as exec from '@actions/exec'; import {Inputs} from './interfaces'; -import {getInputs} from './get-inputs'; +import {showInputs, getInputs} from './get-inputs'; import {setTokens} from './set-tokens'; import * as git from './git-utils'; import {getWorkDirName, addNoJekyll, addCNAME} from './utils'; @@ -9,6 +9,7 @@ import {getWorkDirName, addNoJekyll, addCNAME} from './utils'; export async function run(): Promise { try { const inps: Inputs = getInputs(); + showInputs(inps); await git.setConfig(inps.UserName, inps.UserEmail); @@ -26,7 +27,7 @@ export async function run(): Promise { try { await exec.exec('git', ['remote', 'rm', 'origin']); } catch (e) { - core.info(`[INFO] ${e}`); + core.info(`[INFO] ${e.message}`); } await exec.exec('git', ['remote', 'add', 'origin', remoteURL]); await exec.exec('git', ['add', '--all']); @@ -43,6 +44,6 @@ export async function run(): Promise { return; } catch (e) { - throw new Error(e); + throw new Error(e.message); } } diff --git a/src/set-tokens.ts b/src/set-tokens.ts index 667f572..f9d9219 100644 --- a/src/set-tokens.ts +++ b/src/set-tokens.ts @@ -9,13 +9,6 @@ const cpexec = require('child_process').execFileSync; import {Inputs} from './interfaces'; import {getHomeDir} from './utils'; -export function setPublishRepo(insp: Inputs): string { - if (insp.ExternalRepository) { - return insp.ExternalRepository; - } - return `${github.context.repo.owner}/${github.context.repo.repo}`; -} - export async function setSSHKey( inps: Inputs, publishRepo: string @@ -66,57 +59,82 @@ Host github return `git@github.com:${publishRepo}.git`; } -export async function setGithubToken( - inps: Inputs, - publishRepo: string -): Promise { +export function setGithubToken( + githubToken: string, + publishRepo: string, + publishBranch: string, + externalRepository: string, + ref: string, + eventName: string +): string { core.info('[INFO] setup GITHUB_TOKEN'); - const context = github.context; - core.debug(`ref: ${context.ref}`); - core.debug(`eventName: ${context.eventName}`); + core.debug(`ref: ${ref}`); + core.debug(`eventName: ${eventName}`); let isProhibitedBranch = false; - const ref = context.ref; - if (context.eventName === 'push') { - isProhibitedBranch = ref.includes(`refs/heads/${inps.PublishBranch}`); + if (eventName === 'push') { + isProhibitedBranch = ref.includes(`refs/heads/${publishBranch}`); if (isProhibitedBranch) { - throw new Error( - `You deploy from ${inps.PublishBranch} to ${inps.PublishBranch}` - ); + throw new Error(`You deploy from ${publishBranch} to ${publishBranch}`); } } - if (inps.ExternalRepository) { + if (externalRepository) { throw new Error( 'GITHUB_TOKEN does not support to push to an external repository' ); } - return `https://x-access-token:${inps.GithubToken}@github.com/${publishRepo}.git`; + return `https://x-access-token:${githubToken}@github.com/${publishRepo}.git`; } -export async function setPersonalToken( - inps: Inputs, +export function setPersonalToken( + personalToken: string, publishRepo: string -): Promise { +): string { core.info('[INFO] setup personal access token'); - return `https://x-access-token:${inps.PersonalToken}@github.com/${publishRepo}.git`; + return `https://x-access-token:${personalToken}@github.com/${publishRepo}.git`; +} + +export function getPublishRepo( + externalRepository: string, + owner: string, + repo: string +): string { + if (externalRepository) { + return externalRepository; + } + return `${owner}/${repo}`; } export async function setTokens(inps: Inputs): Promise { try { - const publishRepo = setPublishRepo(inps); + const publishRepo = getPublishRepo( + inps.ExternalRepository, + github.context.repo.owner, + github.context.repo.repo + ); if (inps.DeployKey) { return setSSHKey(inps, publishRepo); } else if (inps.GithubToken) { - return setGithubToken(inps, publishRepo); + const context = github.context; + const ref = context.ref; + const eventName = context.eventName; + return setGithubToken( + inps.GithubToken, + publishRepo, + inps.PublishBranch, + inps.ExternalRepository, + ref, + eventName + ); } else if (inps.PersonalToken) { - return setPersonalToken(inps, publishRepo); + return setPersonalToken(inps.PersonalToken, publishRepo); } else { throw new Error('not found deploy key or tokens'); } } catch (e) { - throw new Error(e); + throw new Error(e.message); } }