From 38faab54943eb850ef0c40598968e9936b669ebe Mon Sep 17 00:00:00 2001 From: Erik Engervall Date: Thu, 15 Apr 2021 22:40:43 +0200 Subject: [PATCH] Normalize forceBranchHeadToTempCommit & merge Signed-off-by: Erik Engervall --- .../src/api/PluginApiClient.ts | 125 +++++++++++------- .../createRc/sideEffects/createRc.test.ts | 4 +- .../cards/createRc/sideEffects/createRc.ts | 4 +- .../src/cards/patchRc/PatchBody.tsx | 18 +-- .../src/cards/patchRc/sideEffects/patch.ts | 18 ++- .../src/test-helpers/test-helpers.test.ts | 37 +----- .../src/test-helpers/test-helpers.ts | 70 ++++++---- 7 files changed, 149 insertions(+), 127 deletions(-) diff --git a/plugins/github-release-manager/src/api/PluginApiClient.ts b/plugins/github-release-manager/src/api/PluginApiClient.ts index 1ad0053175..4a9404fad5 100644 --- a/plugins/github-release-manager/src/api/PluginApiClient.ts +++ b/plugins/github-release-manager/src/api/PluginApiClient.ts @@ -22,9 +22,7 @@ import { GhCreateCommitResponse, GhCreateReferenceResponse, GhCreateTagObjectResponse, - GhGetCommitResponse, GhGetReleaseResponse, - GhMergeResponse, GhUpdateReferenceResponse, GhUpdateReleaseResponse, } from '../types/types'; @@ -41,6 +39,8 @@ export type ApiMethodRetval< T extends (...args: any) => Promise > = UnboxPromise>; +export type UnboxArray = T extends (infer U)[] ? U : T; + type Todo = any; // TODO: type PartialProject = Omit; @@ -61,6 +61,7 @@ export interface IPluginApiClient { args: { releaseBranchName?: string } & PartialProject, ) => Promise<{ recentCommits: { + htmlUrl: string; sha: string; author: { htmlUrl?: string; @@ -69,6 +70,7 @@ export interface IPluginApiClient { commit: { message: string; }; + firstParentSha?: string; }[]; }>; @@ -99,7 +101,13 @@ export interface IPluginApiClient { args: { defaultBranch: string; } & PartialProject, - ) => Promise; + ) => Promise<{ + sha: string; + htmlUrl: string; + commit: { + message: string; + }; + }>; getBranch: ( args: { @@ -154,7 +162,9 @@ export interface IPluginApiClient { args: { tagParts: SemverTagParts | CalverTagParts; releaseBranchTree: string; - selectedPatchCommit: GhGetCommitResponse; + selectedPatchCommit: UnboxArray< + ApiMethodRetval['recentCommits'] + >; } & PartialProject, ) => Promise<{ message: string; @@ -168,17 +178,30 @@ export interface IPluginApiClient { IPluginApiClient['patch']['createTempCommit'] >; } & PartialProject, - ) => Promise; + ) => Promise; merge: ({ base, head, - }: { base: string; head: string } & PartialProject) => Promise; + }: { + base: string; + head: string; + } & PartialProject) => Promise<{ + htmlUrl: string; + commit: { + message: string; + tree: { + sha: string; + }; + }; + }>; createCherryPickCommit: ( args: { bumpedTag: string; - selectedPatchCommit: GhGetCommitResponse; + selectedPatchCommit: UnboxArray< + ApiMethodRetval['recentCommits'] + >; mergeTree: string; releaseBranchSha: string; } & PartialProject, @@ -213,7 +236,9 @@ export interface IPluginApiClient { ApiMethodRetval['latestRelease'] >; tagParts: SemverTagParts | CalverTagParts; - selectedPatchCommit: GhGetCommitResponse; + selectedPatchCommit: UnboxArray< + ApiMethodRetval['recentCommits'] + >; } & PartialProject, ) => Promise; }; @@ -344,6 +369,7 @@ export class PluginApiClient implements IPluginApiClient { return { recentCommits: recentCommitsResponse.data.map(commit => ({ + htmlUrl: commit.html_url, sha: commit.sha, author: { htmlUrl: commit.author?.html_url, @@ -352,6 +378,7 @@ export class PluginApiClient implements IPluginApiClient { commit: { message: commit.commit.message, }, + firstParentSha: commit.parents?.[0].sha, })), }; } @@ -407,16 +434,19 @@ export class PluginApiClient implements IPluginApiClient { defaultBranch, }: { defaultBranch: string } & PartialProject) { const { octokit } = await this.getOctokit(); - const latestCommit: GhGetCommitResponse = ( - await octokit.request( - `/repos/${this.getRepoPath({ - owner, - repo, - })}/commits/refs/heads/${defaultBranch}`, - ) - ).data; + const { data: latestCommit } = await octokit.repos.getCommit({ + owner, + repo, + ref: defaultBranch, + }); - return { latestCommit }; + return { + sha: latestCommit.sha, + htmlUrl: latestCommit.html_url, + commit: { + message: latestCommit.commit.message, + }, + }; } async getBranch({ @@ -534,7 +564,9 @@ export class PluginApiClient implements IPluginApiClient { }: { tagParts: SemverTagParts | CalverTagParts; releaseBranchTree: string; - selectedPatchCommit: GhGetCommitResponse; + selectedPatchCommit: UnboxArray< + ApiMethodRetval['recentCommits'] + >; } & PartialProject) => { const { octokit } = await this.getOctokit(); const { data: tempCommit } = await octokit.git.createCommit({ @@ -542,7 +574,7 @@ export class PluginApiClient implements IPluginApiClient { repo, message: `Temporary commit for patch ${tagParts.patch}`, tree: releaseBranchTree, - parents: [selectedPatchCommit.parents[0].sha], + parents: [selectedPatchCommit.firstParentSha ?? ''], // TODO: Avoid `??` }); return { @@ -563,20 +595,13 @@ export class PluginApiClient implements IPluginApiClient { >; } & PartialProject) => { const { octokit } = await this.getOctokit(); - - await octokit.request( - `/repos/${this.getRepoPath({ - owner, - repo, - })}/git/refs/heads/${releaseBranchName}`, - { - method: 'PATCH', - data: { - sha: tempCommit.sha, - force: true, - }, - }, - ); + await octokit.git.updateRef({ + owner, + repo, + ref: releaseBranchName, + sha: tempCommit.sha, + force: true, + }); }, merge: async ({ @@ -586,18 +611,22 @@ export class PluginApiClient implements IPluginApiClient { head, }: { base: string; head: string } & PartialProject) => { const { octokit } = await this.getOctokit(); + const { data: merge } = await octokit.repos.merge({ + owner, + repo, + base, + head, + }); - const merge: GhMergeResponse = ( - await octokit.request( - `/repos/${this.getRepoPath({ owner, repo })}/merges`, - { - method: 'POST', - data: { base, head }, + return { + htmlUrl: merge.html_url, + commit: { + message: merge.commit.message, + tree: { + sha: merge.commit.tree.sha, }, - ) - ).data; - - return { merge }; + }, + }; }, createCherryPickCommit: async ({ @@ -609,7 +638,9 @@ export class PluginApiClient implements IPluginApiClient { releaseBranchSha, }: { bumpedTag: string; - selectedPatchCommit: GhGetCommitResponse; + selectedPatchCommit: UnboxArray< + ApiMethodRetval['recentCommits'] + >; mergeTree: string; releaseBranchSha: string; } & PartialProject) => { @@ -732,7 +763,9 @@ export class PluginApiClient implements IPluginApiClient { ApiMethodRetval['latestRelease'] >; tagParts: SemverTagParts | CalverTagParts; - selectedPatchCommit: GhGetCommitResponse; + selectedPatchCommit: UnboxArray< + ApiMethodRetval['recentCommits'] + >; } & PartialProject) => { const { octokit } = await this.getOctokit(); @@ -747,7 +780,7 @@ export class PluginApiClient implements IPluginApiClient { tag_name: bumpedTag, body: `${latestRelease.body} - #### [Patch ${tagParts.patch}](${selectedPatchCommit.html_url}) + #### [Patch ${tagParts.patch}](${selectedPatchCommit.htmlUrl}) ${selectedPatchCommit.commit.message}`, }, diff --git a/plugins/github-release-manager/src/cards/createRc/sideEffects/createRc.test.ts b/plugins/github-release-manager/src/cards/createRc/sideEffects/createRc.test.ts index e9ad6aca5a..2f0b351973 100644 --- a/plugins/github-release-manager/src/cards/createRc/sideEffects/createRc.test.ts +++ b/plugins/github-release-manager/src/cards/createRc/sideEffects/createRc.test.ts @@ -38,9 +38,9 @@ describe('createRc', () => { expect(result).toMatchInlineSnapshot(` Array [ Object { - "link": "mock_latestCommit_html_url", + "link": "latestCommit.html_url", "message": "Fetched latest commit from \\"mock_defaultBranch\\"", - "secondaryMessage": "with message \\"mock_latestCommit_message\\"", + "secondaryMessage": "with message \\"latestCommit.commit.message\\"", }, Object { "message": "Cut Release Branch", diff --git a/plugins/github-release-manager/src/cards/createRc/sideEffects/createRc.ts b/plugins/github-release-manager/src/cards/createRc/sideEffects/createRc.ts index c136f33cc2..378fa22a82 100644 --- a/plugins/github-release-manager/src/cards/createRc/sideEffects/createRc.ts +++ b/plugins/github-release-manager/src/cards/createRc/sideEffects/createRc.ts @@ -51,14 +51,14 @@ export async function createRc({ /** * 1. Get the default branch's most recent commit */ - const { latestCommit } = await pluginApiClient.getLatestCommit({ + const latestCommit = await pluginApiClient.getLatestCommit({ ...project, defaultBranch, }); responseSteps.push({ message: `Fetched latest commit from "${defaultBranch}"`, secondaryMessage: `with message "${latestCommit.commit.message}"`, - link: latestCommit.html_url, + link: latestCommit.htmlUrl, }); /** diff --git a/plugins/github-release-manager/src/cards/patchRc/PatchBody.tsx b/plugins/github-release-manager/src/cards/patchRc/PatchBody.tsx index 1548327f45..8b9ba616be 100644 --- a/plugins/github-release-manager/src/cards/patchRc/PatchBody.tsx +++ b/plugins/github-release-manager/src/cards/patchRc/PatchBody.tsx @@ -33,14 +33,10 @@ import { import FileCopyIcon from '@material-ui/icons/FileCopy'; import OpenInNewIcon from '@material-ui/icons/OpenInNew'; -import { Differ } from '../../components/Differ'; -import { - ComponentConfigPatch, - GhGetCommitResponse, - SetRefetch, -} from '../../types/types'; import { CalverTagParts } from '../../helpers/tagParts/getCalverTagParts'; import { CenteredCircularProgress } from '../../components/CenteredCircularProgress'; +import { ComponentConfigPatch, SetRefetch } from '../../types/types'; +import { Differ } from '../../components/Differ'; import { patch } from './sideEffects/patch'; import { ResponseStepList } from '../../components/ResponseStepList/ResponseStepList'; import { SemverTagParts } from '../../helpers/tagParts/getSemverTagParts'; @@ -48,7 +44,11 @@ import { TEST_IDS } from '../../test-helpers/test-ids'; import { usePluginApiClientContext } from '../../contexts/PluginApiClientContext'; import { useProjectContext } from '../../contexts/ProjectContext'; import { useStyles } from '../../styles/styles'; -import { ApiMethodRetval, IPluginApiClient } from '../../api/PluginApiClient'; +import { + ApiMethodRetval, + IPluginApiClient, + UnboxArray, +} from '../../api/PluginApiClient'; interface PatchBodyProps { bumpedTag: string; @@ -92,7 +92,9 @@ export const PatchBody = ({ }); const [patchReleaseResponse, patchReleaseFn] = useAsyncFn(async (...args) => { - const selectedPatchCommit: GhGetCommitResponse = args[0]; + const selectedPatchCommit: UnboxArray< + ApiMethodRetval['recentCommits'] + > = args[0]; const patchResponseSteps = await patch({ project, pluginApiClient, diff --git a/plugins/github-release-manager/src/cards/patchRc/sideEffects/patch.ts b/plugins/github-release-manager/src/cards/patchRc/sideEffects/patch.ts index afb9c5564d..13c2bbb671 100644 --- a/plugins/github-release-manager/src/cards/patchRc/sideEffects/patch.ts +++ b/plugins/github-release-manager/src/cards/patchRc/sideEffects/patch.ts @@ -14,16 +14,13 @@ * limitations under the License. */ -import { - ComponentConfigPatch, - GhGetCommitResponse, - ResponseStep, -} from '../../../types/types'; +import { ComponentConfigPatch, ResponseStep } from '../../../types/types'; import { CalverTagParts } from '../../../helpers/tagParts/getCalverTagParts'; import { GitHubReleaseManagerError } from '../../../errors/GitHubReleaseManagerError'; import { ApiMethodRetval, IPluginApiClient, + UnboxArray, } from '../../../api/PluginApiClient'; import { Project } from '../../../contexts/ProjectContext'; import { SemverTagParts } from '../../../helpers/tagParts/getSemverTagParts'; @@ -35,7 +32,9 @@ interface Patch { >; pluginApiClient: IPluginApiClient; project: Project; - selectedPatchCommit: GhGetCommitResponse; + selectedPatchCommit: UnboxArray< + ApiMethodRetval['recentCommits'] + >; successCb?: ComponentConfigPatch['successCb']; tagParts: NonNullable; } @@ -55,7 +54,6 @@ export async function patch({ if (!selectedPatchCommit || !selectedPatchCommit.sha) { throw new GitHubReleaseManagerError('Invalid commit'); } - const releaseBranchName = latestRelease.targetCommitish; /** * 1. Here is the branch we want to cherry-pick to: @@ -105,7 +103,7 @@ export async function patch({ * 4. Merge the commit we want into this mess: * > merge = POST /repos/$owner/$repo/merges { "base": branchName, "head": commit.sha } */ - const { merge } = await pluginApiClient.patch.merge({ + const merge = await pluginApiClient.patch.merge({ ...project, base: releaseBranchName, head: selectedPatchCommit.sha, @@ -113,7 +111,7 @@ export async function patch({ responseSteps.push({ message: `Merged temporary commit into "${releaseBranchName}"`, secondaryMessage: `with message "${merge.commit.message}"`, - link: merge.html_url, + link: merge.htmlUrl, }); /** @@ -205,7 +203,7 @@ export async function patch({ updatedReleaseName: updatedRelease.name, previousTag: latestRelease.tagName, patchedTag: updatedRelease.tag_name, - patchCommitUrl: selectedPatchCommit.html_url, + patchCommitUrl: selectedPatchCommit.htmlUrl, patchCommitMessage: selectedPatchCommit.commit.message, }); diff --git a/plugins/github-release-manager/src/test-helpers/test-helpers.test.ts b/plugins/github-release-manager/src/test-helpers/test-helpers.test.ts index a690f44811..428e660e8f 100644 --- a/plugins/github-release-manager/src/test-helpers/test-helpers.test.ts +++ b/plugins/github-release-manager/src/test-helpers/test-helpers.test.ts @@ -69,32 +69,6 @@ describe('testHelpers', () => { "tagName": "rc-2020.01.01_1", "targetCommitish": "rc/1.2.3", }, - "mockRecentCommits": Array [ - Object { - "author": Object { - "html_url": "mock_recentCommits_author_html_url", - "login": "mock_recentCommit_author_login", - }, - "commit": Object { - "message": "mock_latestCommit_message", - }, - "html_url": "mock_latestCommit_html_url", - "node_id": "1", - "sha": "mock_latestCommit_sha", - }, - Object { - "author": Object { - "html_url": "mock_recentCommits_author_html_url", - "login": "mock_recentCommit_author_login", - }, - "commit": Object { - "message": "mock_latestCommit_message", - }, - "html_url": "mock_latestCommit_html_url", - "node_id": "2", - "sha": "mock_latestCommit_sha", - }, - ], "mockReleaseBranch": Object { "commit": Object { "commit": Object { @@ -118,15 +92,14 @@ describe('testHelpers', () => { }, "mockSelectedPatchCommit": Object { "author": Object { - "html_url": "mock_recentCommits_author_html_url", - "login": "mock_recentCommit_author_login", + "htmlUrl": "author_html_url", + "login": "author_login", }, "commit": Object { - "message": "mock_latestCommit_message", + "message": "commit_message", }, - "html_url": "mock_latestCommit_html_url", - "node_id": "mock_selected_patch_commit", - "sha": "mock_latestCommit_sha", + "firstParentSha": "mock_first_parent_sha", + "sha": "mock_sha_selected_patch_commit", }, "mockSemverProject": Object { "owner": "mock_owner", diff --git a/plugins/github-release-manager/src/test-helpers/test-helpers.ts b/plugins/github-release-manager/src/test-helpers/test-helpers.ts index e3de328fe7..0bc1246b8a 100644 --- a/plugins/github-release-manager/src/test-helpers/test-helpers.ts +++ b/plugins/github-release-manager/src/test-helpers/test-helpers.ts @@ -17,18 +17,19 @@ import { CalverTagParts } from '../helpers/tagParts/getCalverTagParts'; import { getRcGitHubInfo } from '../cards/createRc/getRcGitHubInfo'; import { - GhCreateCommitResponse, GhCreateReferenceResponse, GhCreateTagObjectResponse, - GhGetBranchResponse, - GhGetCommitResponse, GhGetReleaseResponse, GhMergeResponse, GhUpdateReferenceResponse, GhUpdateReleaseResponse, } from '../types/types'; import { Project } from '../contexts/ProjectContext'; -import { ApiMethodRetval, IPluginApiClient } from '../api/PluginApiClient'; +import { + ApiMethodRetval, + IPluginApiClient, + UnboxArray, +} from '../api/PluginApiClient'; export const mockSemverProject: Project = { owner: 'mock_owner', @@ -109,26 +110,34 @@ export const mockReleaseBranch = createMockBranch(); /** * MOCK COMMIT */ -const createMockCommit = ({ node_id = '1' }: Partial) => +const createMockCommit = ({ + ...rest +}: Partial< + NonNullable< + UnboxArray< + ApiMethodRetval['recentCommits'] + > + > +>) => ({ - node_id, author: { - html_url: 'mock_recentCommits_author_html_url', - login: 'mock_recentCommit_author_login', + htmlUrl: 'author_html_url', + login: 'author_login', }, commit: { - message: 'mock_latestCommit_message', + message: 'commit_message', }, - html_url: 'mock_latestCommit_html_url', - sha: 'mock_latestCommit_sha', - } as GhGetCommitResponse); -export const mockRecentCommits = [ - createMockCommit({ node_id: '1' }), - createMockCommit({ node_id: '2' }), -] as GhGetCommitResponse[]; + sha: 'mock_sha', + firstParentSha: 'mock_first_parent_sha', + ...rest, + } as NonNullable< + UnboxArray< + ApiMethodRetval['recentCommits'] + > + >); export const mockSelectedPatchCommit = createMockCommit({ - node_id: 'mock_selected_patch_commit', + sha: 'mock_sha_selected_patch_commit', }); /** @@ -146,7 +155,10 @@ export const mockApiClient: IPluginApiClient = { getUsername: jest.fn(), getRecentCommits: jest.fn().mockResolvedValue({ - recentCommits: mockRecentCommits, + recentCommits: [ + createMockCommit({ sha: 'mock_sha_recent_commits_1' }), + createMockCommit({ sha: 'mock_sha_recent_commits_2' }), + ], }), getLatestRelease: jest.fn(), // TODO: @@ -154,8 +166,12 @@ export const mockApiClient: IPluginApiClient = { getRepository: jest.fn(), getLatestCommit: jest.fn().mockResolvedValue({ - latestCommit: createMockCommit({ node_id: 'mock_latest_commit' }), - }), + sha: 'latestCommit.sha', + htmlUrl: 'latestCommit.html_url', + commit: { + message: 'latestCommit.commit.message', + }, + } as NonNullable>), getBranch: jest.fn().mockResolvedValue(createMockBranch()), @@ -202,14 +218,14 @@ export const mockApiClient: IPluginApiClient = { } as ApiMethodRetval), forceBranchHeadToTempCommit: jest.fn().mockResolvedValue(undefined), merge: jest.fn().mockResolvedValue({ - merge: { - commit: { - message: 'mock_merge_commit_message', - tree: { sha: 'mock_merge_commit_tree_sha' }, + htmlUrl: 'mock_merge_html_url', + commit: { + message: 'mock_merge_commit_message', + tree: { + sha: 'mock_merge_commit_tree_sha', }, - html_url: 'mock_merge_html_url', - } as GhMergeResponse, - }), + }, + } as ApiMethodRetval), replaceTempCommit: jest.fn().mockResolvedValue({ updatedReference: { ref: 'mock_reference_ref',