From 8d5b77529bdb52e15719b67dcc3065b2d6781221 Mon Sep 17 00:00:00 2001 From: Ryan Ling Date: Tue, 23 Nov 2021 03:48:31 +1100 Subject: [PATCH 1/5] Export Git helper functions --- .changeset/nice-trees-sip.md | 5 ++ docs/development-api/git.md | 70 ++++++++++++++++++++++++ src/api/git/commit.test.ts | 39 ++++++++++++++ src/api/git/commit.ts | 31 +++++++++++ src/api/git/index.ts | 4 ++ src/api/git/log.test.ts | 48 +++++++++++++++++ src/api/git/log.ts | 32 +++++++++++ src/api/git/push.test.ts | 52 ++++++++++++++++++ src/api/git/push.ts | 75 ++++++++++++++++++++++++++ src/api/git/remote.test.ts | 60 +++++++++++++++++++++ src/api/git/remote.ts | 52 ++++++++++++++++++ src/api/github/checkRun.ts | 10 ++-- src/cli/init/git.ts | 6 +-- src/index.ts | 3 +- src/utils/git.test.ts | 101 ----------------------------------- src/utils/git.ts | 93 -------------------------------- 16 files changed, 478 insertions(+), 203 deletions(-) create mode 100644 .changeset/nice-trees-sip.md create mode 100644 docs/development-api/git.md create mode 100644 src/api/git/commit.test.ts create mode 100644 src/api/git/commit.ts create mode 100644 src/api/git/index.ts create mode 100644 src/api/git/log.test.ts create mode 100644 src/api/git/log.ts create mode 100644 src/api/git/push.test.ts create mode 100644 src/api/git/push.ts create mode 100644 src/api/git/remote.test.ts create mode 100644 src/api/git/remote.ts delete mode 100644 src/utils/git.test.ts delete mode 100644 src/utils/git.ts diff --git a/.changeset/nice-trees-sip.md b/.changeset/nice-trees-sip.md new file mode 100644 index 000000000..1933c871f --- /dev/null +++ b/.changeset/nice-trees-sip.md @@ -0,0 +1,5 @@ +--- +"skuba": minor +--- + +git: Export helper functions diff --git a/docs/development-api/git.md b/docs/development-api/git.md new file mode 100644 index 000000000..84c9edf6b --- /dev/null +++ b/docs/development-api/git.md @@ -0,0 +1,70 @@ +--- +parent: Development API +--- + +# GitHub + +--- + +## commit + +Writes a commit to the local Git repository. + +```typescript +import { Git } from 'skuba'; + +await Git.commit({ dir, message: 'Test a commit' }); +``` + +--- + +## getHeadCommitId + +Gets the object ID of the head commit. + +This tries to extract the commit ID from common CI environment variables, +and falls back to the local Git repository log. + +```typescript +import { Git } from 'skuba'; + +const headCommitId = await Git.getHeadCommitId({ dir }); +``` + +--- + +## push + +Pushes the specified `ref` from the local Git repository to a remote. + +Currently, only GitHub app tokens are supported as an auth mechanism. + +```typescript +import { Git } from 'skuba'; + +await Git.push({ + auth: { type: 'gitHubApp' }, + dir, + ref: 'commit-id', + remoteRef: 'branch-name', +}); +``` + +--- + +### getOwnerAndRepo + +Extracts the owner and repository names from local Git remotes. + +Currently, only GitHub repository URLs are supported: + +```console +git@github.com:seek-oss/skuba.git +https://github.com/seek-oss/skuba.git +``` + +```typescript +import { Git } from 'skuba'; + +const { owner, repo } = await getOwnerAndRepo({ dir }); +``` diff --git a/src/api/git/commit.test.ts b/src/api/git/commit.test.ts new file mode 100644 index 000000000..aec2d1912 --- /dev/null +++ b/src/api/git/commit.test.ts @@ -0,0 +1,39 @@ +import git from 'isomorphic-git'; +import { mocked } from 'ts-jest/utils'; + +import { commit } from './commit'; + +jest.mock('isomorphic-git'); + +afterEach(jest.resetAllMocks); + +describe('commit', () => { + it('propagates props to isomorphic-git', async () => { + mocked(git.commit).mockResolvedValue('b'.repeat(40)); + + await expect( + commit({ + dir: '/workdir/skuba', + message: 'Test for regression', + }), + ).resolves.toBe('b'.repeat(40)); + + expect(git.commit).toHaveBeenCalledTimes(1); + expect(mocked(git.commit).mock.calls[0][0]).toMatchInlineSnapshot( + { fs: expect.any(Object) }, + ` + Object { + "author": Object { + "name": "skuba", + }, + "committer": Object { + "name": "skuba", + }, + "dir": "/workdir/skuba", + "fs": Any, + "message": "Test for regression", + } + `, + ); + }); +}); diff --git a/src/api/git/commit.ts b/src/api/git/commit.ts new file mode 100644 index 000000000..870379e6e --- /dev/null +++ b/src/api/git/commit.ts @@ -0,0 +1,31 @@ +import fs from 'fs-extra'; +import git from 'isomorphic-git'; + +interface Identity { + email?: string; + name?: string; +} + +interface CommitParameters { + author?: Identity; + committer?: Identity; + dir: string; + message: string; +} + +/** + * Writes a commit to the local Git repository. + */ +export const commit = async ({ + author = { name: 'skuba' }, + committer = { name: 'skuba' }, + dir, + message, +}: CommitParameters) => + git.commit({ + author, + committer, + dir, + fs, + message, + }); diff --git a/src/api/git/index.ts b/src/api/git/index.ts new file mode 100644 index 000000000..4d83d42ae --- /dev/null +++ b/src/api/git/index.ts @@ -0,0 +1,4 @@ +export { commit } from './commit'; +export { getHeadCommitId } from './log'; +export { push } from './push'; +export { getOwnerAndRepo } from './remote'; diff --git a/src/api/git/log.test.ts b/src/api/git/log.test.ts new file mode 100644 index 000000000..343631e74 --- /dev/null +++ b/src/api/git/log.test.ts @@ -0,0 +1,48 @@ +import git from 'isomorphic-git'; +import { mocked } from 'ts-jest/utils'; + +import { getHeadCommitId } from './log'; + +jest.mock('isomorphic-git'); + +const dir = process.cwd(); + +afterEach(jest.resetAllMocks); + +describe('getHeadCommitId', () => { + it('prefers a commit ID from a Buildkite environment', async () => { + await expect( + getHeadCommitId({ dir, env: { BUILDKITE_COMMIT: 'b'.repeat(40) } }), + ).resolves.toBe('b'.repeat(40)); + + expect(git.log).not.toHaveBeenCalled(); + }); + + it('prefers a commit ID from a GitHub Actions environment', async () => { + await expect( + getHeadCommitId({ dir, env: { GITHUB_SHA: 'c'.repeat(40) } }), + ).resolves.toBe('c'.repeat(40)); + + expect(git.log).not.toHaveBeenCalled(); + }); + + it('falls back to a commit ID from the Git log', async () => { + mocked(git.log).mockResolvedValue([{ oid: 'a'.repeat(40) } as any]); + + await expect(getHeadCommitId({ dir })).resolves.toBe('a'.repeat(40)); + + expect(git.log).toHaveBeenCalledTimes(1); + }); + + it('throws on an empty Git log', async () => { + mocked(git.log).mockResolvedValue([]); + + await expect( + getHeadCommitId({ dir }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Git log does not contain any commits"`, + ); + + expect(git.log).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/api/git/log.ts b/src/api/git/log.ts new file mode 100644 index 000000000..40446136d --- /dev/null +++ b/src/api/git/log.ts @@ -0,0 +1,32 @@ +import fs from 'fs-extra'; +import git from 'isomorphic-git'; + +interface GetHeadCommitIdParameters { + dir: string; + env?: Record; +} + +/** + * Gets the object ID of the head commit. + * + * This tries to extract the commit ID from common CI environment variables, + * and falls back to the local Git repository log. + */ +export const getHeadCommitId = async ({ + dir, + env = process.env, +}: GetHeadCommitIdParameters): Promise => { + const oidFromEnv = env.BUILDKITE_COMMIT ?? env.GITHUB_SHA; + + if (oidFromEnv) { + return oidFromEnv; + } + + const [headCommit] = await git.log({ depth: 1, dir, fs }); + + if (!headCommit) { + throw new Error('Git log does not contain any commits'); + } + + return headCommit.oid; +}; diff --git a/src/api/git/push.test.ts b/src/api/git/push.test.ts new file mode 100644 index 000000000..4fe8f08e5 --- /dev/null +++ b/src/api/git/push.test.ts @@ -0,0 +1,52 @@ +import git from 'isomorphic-git'; +import { mocked } from 'ts-jest/utils'; + +import { push } from './push'; + +jest.mock('isomorphic-git'); + +afterEach(jest.resetAllMocks); + +describe('push', () => { + it('propagates props to isomorphic-git', async () => { + mocked(git.listRemotes).mockResolvedValue([ + { remote: 'origin', url: 'git@github.com:seek-oss/skuba.git' }, + ]); + + mocked(git.push).mockResolvedValue({ + ok: true, + error: null, + refs: {}, + }); + + await expect( + push({ + auth: { token: 'abc', type: 'gitHubApp' }, + dir: '/workdir/skuba', + ref: 'c'.repeat(40), + remoteRef: 'feature-a', + }), + ).resolves.toStrictEqual({ + error: null, + ok: true, + refs: {}, + }); + + expect(git.push).toHaveBeenCalledTimes(1); + expect(mocked(git.push).mock.calls[0][0]).toMatchInlineSnapshot( + { http: expect.any(Object), fs: expect.any(Object) }, + ` + Object { + "dir": "/workdir/skuba", + "fs": Any, + "http": Any, + "onAuth": [Function], + "ref": "cccccccccccccccccccccccccccccccccccccccc", + "remote": undefined, + "remoteRef": "feature-a", + "url": "https://github.com/seek-oss/skuba", + } + `, + ); + }); +}); diff --git a/src/api/git/push.ts b/src/api/git/push.ts new file mode 100644 index 000000000..c4e8c6927 --- /dev/null +++ b/src/api/git/push.ts @@ -0,0 +1,75 @@ +import fs from 'fs-extra'; +import git from 'isomorphic-git'; +import http from 'isomorphic-git/http/node'; + +import { getOwnerAndRepo } from './remote'; + +/** + * Use a GitHub app token to auth the Git push. + * + * This defaults to the `GITHUB_API_TOKEN` and `GITHUB_TOKEN` environment + * variables if `token` is not provided. + */ +interface GitHubAppAuth { + type: 'gitHubApp'; + token?: string; +} + +interface PushParameters { + /** + * The auth mechanism for the push. + * + * Currently, only GitHub app tokens are supported. + */ + auth: GitHubAppAuth; + + dir: string; + + /** + * The reference to push to the remote. + * + * This may be a commit, branch or tag in the local repository. + */ + ref: string; + + remote?: string; + + /** + * The destination branch or tag on the remote. + * + * This defaults to `ref`. + */ + remoteRef?: string; +} + +/** + * Pushes the specified `ref` from the local Git repository to a remote. + */ +export const push = async ({ + auth, + dir, + ref, + remote, + remoteRef, +}: PushParameters) => { + const { owner, repo } = await getOwnerAndRepo({ dir }); + + const url = `https://github.com/${encodeURIComponent( + owner, + )}/${encodeURIComponent(repo)}`; + + return git.push({ + onAuth: () => ({ + username: 'x-access-token', + password: + auth.token ?? process.env.GITHUB_API_TOKEN ?? process.env.GITHUB_TOKEN, + }), + dir, + fs, + http, + ref, + remote, + remoteRef, + url, + }); +}; diff --git a/src/api/git/remote.test.ts b/src/api/git/remote.test.ts new file mode 100644 index 000000000..39a42f85c --- /dev/null +++ b/src/api/git/remote.test.ts @@ -0,0 +1,60 @@ +import git from 'isomorphic-git'; +import { mocked } from 'ts-jest/utils'; + +import { getOwnerAndRepo } from './remote'; + +jest.mock('isomorphic-git'); + +const dir = process.cwd(); + +afterEach(jest.resetAllMocks); + +describe('getOwnerAndRepo', () => { + it('extracts an owner and repo from an HTTP GitHub remote', async () => { + mocked(git.listRemotes).mockResolvedValue([ + { remote: 'origin', url: 'git@github.com:seek-oss/skuba.git' }, + ]); + + await expect(getOwnerAndRepo({ dir })).resolves.toStrictEqual({ + owner: 'seek-oss', + repo: 'skuba', + }); + }); + + it('extracts an owner and repo from an SSH GitHub remote', async () => { + mocked(git.listRemotes).mockResolvedValue([ + { remote: 'origin', url: 'git@github.com:SEEK-Jobs/secret-codebase.git' }, + ]); + + await expect(getOwnerAndRepo({ dir })).resolves.toStrictEqual({ + owner: 'SEEK-Jobs', + repo: 'secret-codebase', + }); + }); + + it('throws on zero remotes', async () => { + mocked(git.listRemotes).mockResolvedValue([]); + + await expect( + getOwnerAndRepo({ dir }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Could not find a GitHub remote"`, + ); + }); + + it('throws on unrecognised remotes', async () => { + mocked(git.listRemotes).mockResolvedValue([ + { remote: 'public', url: 'git@gitlab.com:seek-oss/skuba.git' }, + { + remote: 'private', + url: 'https://gitlab.com/SEEK-Jobs/secret-codebase.git', + }, + ]); + + await expect( + getOwnerAndRepo({ dir }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Could not find a GitHub remote"`, + ); + }); +}); diff --git a/src/api/git/remote.ts b/src/api/git/remote.ts new file mode 100644 index 000000000..19d20a0fd --- /dev/null +++ b/src/api/git/remote.ts @@ -0,0 +1,52 @@ +import fs from 'fs-extra'; +import git from 'isomorphic-git'; + +/** + * Matches the owner and repository names in a GitHub repository URL. + * + * For example, given the following input strings: + * + * ```console + * git@github.com:seek-oss/skuba.git + * https://github.com/seek-oss/skuba.git + * ``` + * + * This pattern will produce the following matches: + * + * 1. seek-oss + * 2. skuba + */ +const ownerRepoRegex = /github.com(?::|\/)(.+)\/(.+).git$/; + +interface GetOwnerAndRepoParameters { + dir: string; +} + +/** + * Extracts the owner and repository names from local Git remotes. + * + * Currently, only GitHub repository URLs are supported: + * + * ```console + * git@github.com:seek-oss/skuba.git + * https://github.com/seek-oss/skuba.git + * ``` + */ +export const getOwnerAndRepo = async ({ + dir, +}: GetOwnerAndRepoParameters): Promise<{ owner: string; repo: string }> => { + const remotes = await git.listRemotes({ dir, fs }); + + for (const { url } of remotes) { + const match = ownerRepoRegex.exec(url); + + const owner = match?.[1]; + const repo = match?.[2]; + + if (owner && repo) { + return { owner, repo }; + } + } + + throw new Error('Could not find a GitHub remote'); +}; diff --git a/src/api/github/checkRun.ts b/src/api/github/checkRun.ts index b7411ded8..cd1df8b8e 100644 --- a/src/api/github/checkRun.ts +++ b/src/api/github/checkRun.ts @@ -1,8 +1,8 @@ import { Octokit } from '@octokit/rest'; import type { Endpoints } from '@octokit/types'; -import { getHeadSha, getOwnerRepo } from '../../utils/git'; import { pluralise } from '../../utils/logging'; +import * as Git from '../git'; type Output = NonNullable< Endpoints['POST /repos/{owner}/{repo}/check-runs']['parameters']['output'] @@ -99,9 +99,9 @@ export const createCheckRun = async ({ }: CreateCheckRunParameters): Promise => { const dir = process.cwd(); - const [headSha, { owner, repo }] = await Promise.all([ - getHeadSha(dir), - getOwnerRepo(dir), + const [commitId, { owner, repo }] = await Promise.all([ + Git.getHeadCommitId(dir), + Git.getOwnerAndRepo(dir), ]); const client = new Octokit({ @@ -110,7 +110,7 @@ export const createCheckRun = async ({ await client.checks.create({ conclusion, - head_sha: headSha, + head_sha: commitId, name, output: { annotations: annotations.slice(0, GITHUB_MAX_ANNOTATIONS), diff --git a/src/cli/init/git.ts b/src/cli/init/git.ts index 2dba10293..9877cf5de 100644 --- a/src/cli/init/git.ts +++ b/src/cli/init/git.ts @@ -4,8 +4,8 @@ import fs from 'fs-extra'; import git from 'isomorphic-git'; import http from 'isomorphic-git/http/node'; +import * as Git from '../../api/git'; import { crawlDirectory } from '../../utils/dir'; -import { gitCommit } from '../../utils/git'; import { log } from '../../utils/logging'; interface GitHubProject { @@ -24,7 +24,7 @@ export const initialiseRepo = async ( fs, }); - await gitCommit({ + await Git.commit({ dir, message: 'Initial commit', }); @@ -44,7 +44,7 @@ export const commitChanges = async (dir: string, message: string) => { filepaths.map((filepath) => git.add({ dir, filepath, fs })), ); - await gitCommit({ + await Git.commit({ dir, message, }); diff --git a/src/index.ts b/src/index.ts index 2a4217ebe..fb9af1a83 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,7 +10,8 @@ * ``` */ -export * as GitHub from './api/github'; export * as Buildkite from './api/buildkite'; +export * as Git from './api/git'; +export * as GitHub from './api/github'; export * as Jest from './api/jest'; export * as Net from './api/net'; diff --git a/src/utils/git.test.ts b/src/utils/git.test.ts deleted file mode 100644 index f802ffd4a..000000000 --- a/src/utils/git.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -import type { ReadCommitResult } from 'isomorphic-git'; -import git from 'isomorphic-git'; -import { mocked } from 'ts-jest/utils'; - -import { getHeadSha, getOwnerRepo, gitCommit, gitPush } from './git'; - -jest.mock('isomorphic-git'); - -const dir = process.cwd(); - -beforeEach(() => { - mocked(git.listRemotes).mockResolvedValue([ - { remote: 'origin', url: 'git@github.com:seek-oss/skuba.git' }, - ]); - mocked(git.log).mockResolvedValue([ - { oid: 'a'.repeat(40) } as ReadCommitResult, - ]); - mocked(git.push).mockResolvedValue({ - ok: true, - error: null, - refs: {}, - }); - mocked(git.commit).mockResolvedValue('b'.repeat(40)); -}); - -afterEach(jest.resetAllMocks); - -describe('gitCommit', () => { - it('should propagate props to isomorphic-git', async () => { - await expect( - gitCommit({ - dir: '/workdir/skuba', - message: 'Test for regression', - }), - ).resolves.toBe('b'.repeat(40)); - - expect(git.commit).toHaveBeenCalledTimes(1); - expect(mocked(git.commit).mock.calls[0][0]).toMatchInlineSnapshot( - { fs: expect.any(Object) }, - ` - Object { - "author": Object { - "name": "skuba", - }, - "committer": Object { - "name": "skuba", - }, - "dir": "/workdir/skuba", - "fs": Any, - "message": "Test for regression", - } - `, - ); - }); -}); - -describe('gitPush', () => { - it('should propagate props to isomorphic-git', async () => { - await expect( - gitPush({ - auth: { token: 'abc', type: 'gitHubApp' }, - branch: 'feature-a', - commitOid: 'c'.repeat(40), - dir: '/workdir/skuba', - }), - ).resolves.toStrictEqual({ - error: null, - ok: true, - refs: {}, - }); - - expect(git.push).toHaveBeenCalledTimes(1); - expect(mocked(git.push).mock.calls[0][0]).toMatchInlineSnapshot( - { http: expect.any(Object), fs: expect.any(Object) }, - ` - Object { - "dir": "/workdir/skuba", - "fs": Any, - "http": Any, - "onAuth": [Function], - "ref": "cccccccccccccccccccccccccccccccccccccccc", - "remoteRef": "feature-a", - "url": "https://github.com/seek-oss/skuba", - } - `, - ); - }); -}); - -describe('getOwnerRepo', () => { - it('should extract a GitHub owner and repo from Git remotes', () => - expect(getOwnerRepo(dir)).resolves.toStrictEqual({ - owner: 'seek-oss', - repo: 'skuba', - })); -}); - -describe('getHeadSha', () => { - it('should extract a commit hash from the Git log', () => - expect(getHeadSha(dir)).resolves.toBe('a'.repeat(40))); -}); diff --git a/src/utils/git.ts b/src/utils/git.ts deleted file mode 100644 index aef3a4af2..000000000 --- a/src/utils/git.ts +++ /dev/null @@ -1,93 +0,0 @@ -import fs from 'fs-extra'; -import git from 'isomorphic-git'; -import http from 'isomorphic-git/http/node'; - -export const gitCommit = async ({ - dir, - message, -}: { - dir: string; - message: string; -}) => - git.commit({ - author: { name: 'skuba' }, - committer: { name: 'skuba' }, - dir, - fs, - message, - }); - -interface GitPushProps { - auth: { type: 'gitHubApp'; token: string }; - branch: string; - commitOid: string; - dir: string; -} - -export const gitPush = async ({ - auth, - branch, - commitOid, - dir, -}: GitPushProps) => { - const { owner, repo } = await getOwnerRepo(dir); - - const url = `https://github.com/${encodeURIComponent( - owner, - )}/${encodeURIComponent(repo)}`; - - return git.push({ - onAuth: () => ({ - username: 'x-access-token', - password: auth.token, - }), - http, - dir, - fs, - ref: commitOid, - remoteRef: branch, - url, - }); -}; - -export const getHeadSha = async (dir: string): Promise => { - const [commit] = await git.log({ depth: 1, dir, fs }); - - return commit.oid; -}; - -/** - * Matches the owner and repository names in a GitHub repository URL. - * - * For example, given the following input strings: - * - * ```console - * git@github.com:seek-oss/skuba.git - * https://github.com/seek-oss/skuba.git - * ``` - * - * This pattern will produce the following matches: - * - * 1. seek-oss - * 2. skuba - */ -const ownerRepoRegex = /github.com(?::|\/)(.+)\/(.+).git$/; - -export const getOwnerRepo = async ( - dir: string, -): Promise<{ owner: string; repo: string }> => { - const remotes = await git.listRemotes({ dir, fs }); - - for (const { url } of remotes) { - const match = ownerRepoRegex.exec(url); - - const owner = match?.[1]; - const repo = match?.[2]; - - if (owner && repo) { - return { owner, repo }; - } - } - - throw new Error('Could not find a GitHub remote'); -}; From 61992222e399a099c0b1ae845e9c913918fc27ec Mon Sep 17 00:00:00 2001 From: Ryan Ling Date: Tue, 23 Nov 2021 09:07:11 +1100 Subject: [PATCH 2/5] Fix params --- src/api/github/checkRun.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/github/checkRun.ts b/src/api/github/checkRun.ts index cd1df8b8e..1de2040be 100644 --- a/src/api/github/checkRun.ts +++ b/src/api/github/checkRun.ts @@ -100,8 +100,8 @@ export const createCheckRun = async ({ const dir = process.cwd(); const [commitId, { owner, repo }] = await Promise.all([ - Git.getHeadCommitId(dir), - Git.getOwnerAndRepo(dir), + Git.getHeadCommitId({ dir }), + Git.getOwnerAndRepo({ dir }), ]); const client = new Octokit({ From 6a339fec13f17e06c64abfec9d2d4b354b157c4e Mon Sep 17 00:00:00 2001 From: Ryan Ling Date: Tue, 23 Nov 2021 09:15:40 +1100 Subject: [PATCH 3/5] Try to fix test --- src/api/github/checkRun.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/api/github/checkRun.test.ts b/src/api/github/checkRun.test.ts index 215e74836..0ac4afca4 100644 --- a/src/api/github/checkRun.test.ts +++ b/src/api/github/checkRun.test.ts @@ -21,12 +21,14 @@ const mockClient = { }, }; -afterEach(() => { +beforeEach(() => { delete process.env.GITHUB_API_TOKEN; + delete process.env.GITHUB_REF; delete process.env.GITHUB_TOKEN; - jest.resetAllMocks(); }); +afterEach(jest.resetAllMocks); + const annotation: GitHub.Annotation = { annotation_level: 'failure', start_line: 0, From e973aa78871d3e51997bc17523241d9c09bdc5f7 Mon Sep 17 00:00:00 2001 From: Ryan Ling Date: Tue, 23 Nov 2021 09:16:26 +1100 Subject: [PATCH 4/5] Try the other env var --- src/api/github/checkRun.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/github/checkRun.test.ts b/src/api/github/checkRun.test.ts index 0ac4afca4..e2b022f52 100644 --- a/src/api/github/checkRun.test.ts +++ b/src/api/github/checkRun.test.ts @@ -23,7 +23,7 @@ const mockClient = { beforeEach(() => { delete process.env.GITHUB_API_TOKEN; - delete process.env.GITHUB_REF; + delete process.env.GITHUB_SHA; delete process.env.GITHUB_TOKEN; }); From 7d6800e5c2b5af92a1f1dac9ba5113e290ac1714 Mon Sep 17 00:00:00 2001 From: Ryan Ling Date: Tue, 23 Nov 2021 09:24:51 +1100 Subject: [PATCH 5/5] Ensure test does not read from `process.env` --- src/api/git/log.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/api/git/log.test.ts b/src/api/git/log.test.ts index 343631e74..793648f95 100644 --- a/src/api/git/log.test.ts +++ b/src/api/git/log.test.ts @@ -29,7 +29,9 @@ describe('getHeadCommitId', () => { it('falls back to a commit ID from the Git log', async () => { mocked(git.log).mockResolvedValue([{ oid: 'a'.repeat(40) } as any]); - await expect(getHeadCommitId({ dir })).resolves.toBe('a'.repeat(40)); + await expect(getHeadCommitId({ dir, env: {} })).resolves.toBe( + 'a'.repeat(40), + ); expect(git.log).toHaveBeenCalledTimes(1); }); @@ -38,7 +40,7 @@ describe('getHeadCommitId', () => { mocked(git.log).mockResolvedValue([]); await expect( - getHeadCommitId({ dir }), + getHeadCommitId({ dir, env: {} }), ).rejects.toThrowErrorMatchingInlineSnapshot( `"Git log does not contain any commits"`, );