Further improvements to API interface

Signed-off-by: Erik Engervall <erik.engervall@gmail.com>
This commit is contained in:
Erik Engervall
2021-04-16 22:46:55 +02:00
parent 61b20f011d
commit de5f9f8729
26 changed files with 549 additions and 522 deletions
@@ -66,15 +66,16 @@ export function GitHubReleaseManager({
}: GitHubReleaseManagerProps) {
const pluginApiClient = useApi(githubReleaseManagerApiRef);
const classes = useStyles();
const usernameResponse = useAsync(() => pluginApiClient.getUsername());
const query = useQuery();
const parsedQuery = getParsedQuery({ query });
const project: Project = {
owner: parsedQuery.owner ?? '',
repo: parsedQuery.repo ?? '',
versioningStrategy: parsedQuery.versioningStrategy ?? 'semver',
};
const usernameResponse = useAsync(() =>
pluginApiClient.getUsername({ owner: project.owner, repo: project.repo }),
);
if (usernameResponse.error) {
return <Alert severity="error">{usernameResponse.error.message}</Alert>;
@@ -19,6 +19,7 @@ import { Octokit } from '@octokit/rest';
import { readGitHubIntegrationConfigs } from '@backstage/integration';
import { CalverTagParts } from '../helpers/tagParts/getCalverTagParts';
import { DISABLE_CACHE } from '../constants/constants';
import { getRcGitHubInfo } from '../cards/createRc/getRcGitHubInfo';
import { Project } from '../contexts/ProjectContext';
import { SemverTagParts } from '../helpers/tagParts/getSemverTagParts';
@@ -27,258 +28,296 @@ type UnboxPromise<T extends Promise<any>> = T extends Promise<infer U>
? U
: never;
export type ApiMethodRetval<
type UnboxReturnedPromise<
T extends (...args: any) => Promise<any>
> = UnboxPromise<ReturnType<T>>;
export type UnboxArray<T> = T extends (infer U)[] ? U : T;
type UnboxArray<T> = T extends (infer U)[] ? U : T;
type PartialProject = Omit<Project, 'versioningStrategy'>;
type OwnerRepo = {
owner: Project['owner'];
repo: Project['repo'];
};
export interface IPluginApiClient {
getHost: () => string;
type GetHost = () => string;
getRepoPath: (args: PartialProject) => string;
type GetRepoPath = (args: OwnerRepo) => string;
getOwners: () => Promise<{ owners: string[] }>;
type GetOwners = () => Promise<{
owners: string[];
}>;
export type GetOwnersResult = UnboxReturnedPromise<GetOwners>;
getRepositories: (args: {
owner: string;
}) => Promise<{ repositories: string[] }>;
type GetRepositories = (args: {
owner: string;
}) => Promise<{
repositories: string[];
}>;
export type GetRepositoriesResult = UnboxReturnedPromise<GetRepositories>;
getUsername: () => Promise<{ username: string }>;
type GetUsername = (
args: OwnerRepo,
) => Promise<{
username: string;
}>;
export type GetUsernameResult = UnboxReturnedPromise<GetUsername>;
getRecentCommits: (
args: { releaseBranchName?: string } & PartialProject,
) => Promise<
{
htmlUrl: string;
sha: string;
author: {
htmlUrl?: string;
login?: string;
};
commit: {
message: string;
};
firstParentSha?: string;
}[]
>;
getLatestRelease: (
args: PartialProject,
) => Promise<{
latestRelease: {
targetCommitish: string;
tagName: string;
prerelease: boolean;
id: number;
htmlUrl: string;
body?: string | null;
} | null;
}>;
getRepository: (
args: PartialProject,
) => Promise<{
repository: {
pushPermissions: boolean | undefined;
defaultBranch: string;
name: string;
};
}>;
getLatestCommit: (
args: {
defaultBranch: string;
} & PartialProject,
) => Promise<{
sha: string;
type GetRecentCommits = (
args: {
releaseBranchName?: string;
} & OwnerRepo,
) => Promise<
{
htmlUrl: string;
sha: string;
author: {
htmlUrl?: string;
login?: string;
};
commit: {
message: string;
};
}>;
firstParentSha?: string;
}[]
>;
export type GetRecentCommitsResult = UnboxReturnedPromise<GetRecentCommits>;
export type GetRecentCommitsResultSingle = UnboxArray<GetRecentCommitsResult>;
getBranch: (
args: {
branchName: string;
} & PartialProject,
) => Promise<{
name: string;
links: {
html: string;
};
commit: {
sha: string;
commit: {
tree: {
sha: string;
};
};
};
}>;
type GetLatestRelease = (
args: OwnerRepo,
) => Promise<{
targetCommitish: string;
tagName: string;
prerelease: boolean;
id: number;
htmlUrl: string;
body?: string | null;
} | null>;
export type GetLatestReleaseResult = UnboxReturnedPromise<GetLatestRelease>;
createRc: {
createRef: (
args: {
mostRecentSha: string;
targetBranch: string;
} & PartialProject,
) => Promise<{ ref: string }>;
type GetRepository = (
args: OwnerRepo,
) => Promise<{
pushPermissions: boolean | undefined;
defaultBranch: string;
name: string;
}>;
export type GetRepositoryResult = UnboxReturnedPromise<GetRepository>;
getComparison: (
args: {
previousReleaseBranch: string;
nextReleaseBranch: string;
} & PartialProject,
) => Promise<{ htmlUrl: string; aheadBy: number }>;
createRelease: (
args: {
nextGitHubInfo: ReturnType<typeof getRcGitHubInfo>;
releaseBody: string;
} & PartialProject,
) => Promise<{
createReleaseResponse: {
name: string | null;
htmlUrl: string;
tagName: string;
};
}>;
type GetLatestCommit = (
args: {
defaultBranch: string;
} & OwnerRepo,
) => Promise<{
sha: string;
htmlUrl: string;
commit: {
message: string;
};
}>;
export type GetLatestCommitResult = UnboxReturnedPromise<GetLatestCommit>;
patch: {
createTempCommit: (
args: {
tagParts: SemverTagParts | CalverTagParts;
releaseBranchTree: string;
selectedPatchCommit: UnboxArray<
ApiMethodRetval<IPluginApiClient['getRecentCommits']>
>;
} & PartialProject,
) => Promise<{
message: string;
sha: string;
}>;
forceBranchHeadToTempCommit: (
args: {
releaseBranchName: string;
tempCommit: ApiMethodRetval<
IPluginApiClient['patch']['createTempCommit']
>;
} & PartialProject,
) => Promise<void>;
merge: ({
base,
head,
}: {
base: string;
head: string;
} & PartialProject) => Promise<{
htmlUrl: string;
commit: {
message: string;
tree: {
sha: string;
};
};
}>;
createCherryPickCommit: (
args: {
bumpedTag: string;
selectedPatchCommit: UnboxArray<
ApiMethodRetval<IPluginApiClient['getRecentCommits']>
>;
mergeTree: string;
releaseBranchSha: string;
} & PartialProject,
) => Promise<{
message: string;
sha: string;
}>;
replaceTempCommit: (
args: {
releaseBranchName: string;
cherryPickCommit: ApiMethodRetval<
IPluginApiClient['patch']['createCherryPickCommit']
>;
} & PartialProject,
) => Promise<{
ref: string;
object: {
type GetBranch = (
args: {
branchName: string;
} & OwnerRepo,
) => Promise<{
name: string;
links: {
html: string;
};
commit: {
sha: string;
commit: {
tree: {
sha: string;
};
}>;
createTagObject: ({
bumpedTag,
updatedReference,
}: {
bumpedTag: string;
updatedReference: ApiMethodRetval<
IPluginApiClient['patch']['replaceTempCommit']
>;
} & PartialProject) => Promise<{
tag: string;
sha: string;
}>;
createReference: (
args: {
bumpedTag: string;
createdTagObject: ApiMethodRetval<
IPluginApiClient['patch']['createTagObject']
>;
} & PartialProject,
) => Promise<{
ref: string;
}>;
updateRelease: (
args: {
bumpedTag: string;
latestRelease: NonNullable<
ApiMethodRetval<IPluginApiClient['getLatestRelease']>['latestRelease']
>;
tagParts: SemverTagParts | CalverTagParts;
selectedPatchCommit: UnboxArray<
ApiMethodRetval<IPluginApiClient['getRecentCommits']>
>;
} & PartialProject,
) => Promise<{
name: string | null;
tagName: string;
htmlUrl: string;
}>;
};
};
}>;
export type GetBranchResult = UnboxReturnedPromise<GetBranch>;
type CreateRef = (
args: {
mostRecentSha: string;
targetBranch: string;
} & OwnerRepo,
) => Promise<{
ref: string;
}>;
export type CreateRefResult = UnboxReturnedPromise<CreateRef>;
type GetComparison = (
args: {
previousReleaseBranch: string;
nextReleaseBranch: string;
} & OwnerRepo,
) => Promise<{
htmlUrl: string;
aheadBy: number;
}>;
export type GetComparisonResult = UnboxReturnedPromise<GetComparison>;
type CreateRelease = (
args: {
nextGitHubInfo: ReturnType<typeof getRcGitHubInfo>;
releaseBody: string;
} & OwnerRepo,
) => Promise<{
name: string | null;
htmlUrl: string;
tagName: string;
}>;
export type CreateReleaseResult = UnboxReturnedPromise<CreateRelease>;
type CreateTempCommit = (
args: {
tagParts: SemverTagParts | CalverTagParts;
releaseBranchTree: string;
selectedPatchCommit: UnboxArray<
UnboxReturnedPromise<IPluginApiClient['getRecentCommits']>
>;
} & OwnerRepo,
) => Promise<{
message: string;
sha: string;
}>;
export type CreateTempCommitResult = UnboxReturnedPromise<CreateTempCommit>;
type ForceBranchHeadToTempCommit = (
args: {
releaseBranchName: string;
tempCommit: CreateTempCommitResult;
} & OwnerRepo,
) => Promise<void>;
export type ForceBranchHeadToTempCommitResult = UnboxReturnedPromise<ForceBranchHeadToTempCommit>;
type Merge = ({
base,
head,
}: {
base: string;
head: string;
} & OwnerRepo) => Promise<{
htmlUrl: string;
commit: {
message: string;
tree: {
sha: string;
};
};
}>;
export type MergeResult = UnboxReturnedPromise<Merge>;
type CreateCherryPickCommit = (
args: {
bumpedTag: string;
selectedPatchCommit: UnboxArray<
UnboxReturnedPromise<IPluginApiClient['getRecentCommits']>
>;
mergeTree: string;
releaseBranchSha: string;
} & OwnerRepo,
) => Promise<{
message: string;
sha: string;
}>;
export type CreateCherryPickCommitResult = UnboxReturnedPromise<CreateCherryPickCommit>;
type ReplaceTempCommit = (
args: {
releaseBranchName: string;
cherryPickCommit: UnboxReturnedPromise<
IPluginApiClient['patch']['createCherryPickCommit']
>;
} & OwnerRepo,
) => Promise<{
ref: string;
object: {
sha: string;
};
}>;
export type ReplaceTempCommitResult = UnboxReturnedPromise<ReplaceTempCommit>;
type CreateTagObject = ({
bumpedTag,
updatedReference,
}: {
bumpedTag: string;
updatedReference: ReplaceTempCommitResult;
} & OwnerRepo) => Promise<{
tag: string;
sha: string;
}>;
export type CreateTagObjectResult = UnboxReturnedPromise<CreateTagObject>;
type CreateReference = (
args: {
bumpedTag: string;
createdTagObject: CreateTagObjectResult;
} & OwnerRepo,
) => Promise<{
ref: string;
}>;
export type CreateReferenceResult = UnboxReturnedPromise<CreateReference>;
type UpdateRelease = (
args: {
bumpedTag: string;
latestRelease: NonNullable<GetLatestReleaseResult>;
tagParts: SemverTagParts | CalverTagParts;
selectedPatchCommit: GetRecentCommitsResultSingle;
} & OwnerRepo,
) => Promise<{
name: string | null;
tagName: string;
htmlUrl: string;
}>;
export type UpdateReleaseResult = UnboxReturnedPromise<UpdateRelease>;
type PromoteRelease = (
args: {
releaseId: NonNullable<GetLatestReleaseResult>['id'];
releaseVersion: string;
} & OwnerRepo,
) => Promise<{
name: string | null;
tagName: string;
htmlUrl: string;
}>;
export type PromoteReleaseResult = UnboxReturnedPromise<PromoteRelease>;
export interface IPluginApiClient {
getHost: GetHost;
getRepoPath: GetRepoPath;
getOwners: GetOwners;
getRepositories: GetRepositories;
getUsername: GetUsername;
getRecentCommits: GetRecentCommits;
getLatestRelease: GetLatestRelease;
getRepository: GetRepository;
getLatestCommit: GetLatestCommit;
getBranch: GetBranch;
createRc: {
createRef: CreateRef;
getComparison: GetComparison;
createRelease: CreateRelease;
};
patch: {
createTempCommit: CreateTempCommit;
forceBranchHeadToTempCommit: ForceBranchHeadToTempCommit;
merge: Merge;
createCherryPickCommit: CreateCherryPickCommit;
replaceTempCommit: ReplaceTempCommit;
createTagObject: CreateTagObject;
createReference: CreateReference;
updateRelease: UpdateRelease;
};
promoteRc: {
promoteRelease: (
args: {
releaseId: NonNullable<
ApiMethodRetval<IPluginApiClient['getLatestRelease']>['latestRelease']
>['id'];
releaseVersion: string;
} & PartialProject,
) => Promise<{
name: string | null;
tagName: string;
htmlUrl: string;
}>;
promoteRelease: PromoteRelease;
};
}
const DISABLE_CACHE = {
headers: {
'If-None-Match': '',
},
};
export class PluginApiClient implements IPluginApiClient {
private readonly githubAuthApi: OAuthApi;
private readonly baseUrl: string;
@@ -331,7 +370,7 @@ export class PluginApiClient implements IPluginApiClient {
return this.host;
}
public getRepoPath({ owner, repo }: PartialProject) {
public getRepoPath({ owner, repo }: OwnerRepo) {
return `${owner}/${repo}`;
}
@@ -385,7 +424,7 @@ export class PluginApiClient implements IPluginApiClient {
releaseBranchName,
}: {
releaseBranchName?: string;
} & PartialProject) {
} & OwnerRepo) {
const { octokit } = await this.getOctokit();
const recentCommitsResponse = await octokit.repos.listCommits({
owner,
@@ -408,7 +447,7 @@ export class PluginApiClient implements IPluginApiClient {
}));
}
async getLatestRelease({ owner, repo }: PartialProject) {
async getLatestRelease({ owner, repo }: OwnerRepo) {
const { octokit } = await this.getOctokit();
const { data: latestReleases } = await octokit.repos.listReleases({
owner,
@@ -418,26 +457,22 @@ export class PluginApiClient implements IPluginApiClient {
});
if (latestReleases.length === 0) {
return {
latestRelease: null,
};
return null;
}
const latestRelease = latestReleases[0];
return {
latestRelease: {
targetCommitish: latestRelease.target_commitish,
tagName: latestRelease.tag_name,
prerelease: latestRelease.prerelease,
id: latestRelease.id,
htmlUrl: latestRelease.html_url,
body: latestRelease.body,
},
targetCommitish: latestRelease.target_commitish,
tagName: latestRelease.tag_name,
prerelease: latestRelease.prerelease,
id: latestRelease.id,
htmlUrl: latestRelease.html_url,
body: latestRelease.body,
};
}
async getRepository({ owner, repo }: PartialProject) {
async getRepository({ owner, repo }: OwnerRepo) {
const { octokit } = await this.getOctokit();
const { data: repository } = await octokit.repos.get({
owner,
@@ -446,11 +481,9 @@ export class PluginApiClient implements IPluginApiClient {
});
return {
repository: {
pushPermissions: repository.permissions?.push,
defaultBranch: repository.default_branch,
name: repository.name,
},
pushPermissions: repository.permissions?.push,
defaultBranch: repository.default_branch,
name: repository.name,
};
}
@@ -458,7 +491,9 @@ export class PluginApiClient implements IPluginApiClient {
owner,
repo,
defaultBranch,
}: { defaultBranch: string } & PartialProject) {
}: {
defaultBranch: GetRepositoryResult['defaultBranch'];
} & OwnerRepo) {
const { octokit } = await this.getOctokit();
const { data: latestCommit } = await octokit.repos.getCommit({
owner,
@@ -480,7 +515,9 @@ export class PluginApiClient implements IPluginApiClient {
owner,
repo,
branchName,
}: { branchName: string } & PartialProject) {
}: {
branchName: string;
} & OwnerRepo) {
const { octokit } = await this.getOctokit();
const { data: branch } = await octokit.repos.getBranch({
@@ -515,7 +552,7 @@ export class PluginApiClient implements IPluginApiClient {
}: {
mostRecentSha: string;
targetBranch: string;
} & PartialProject) => {
} & OwnerRepo) => {
const { octokit } = await this.getOctokit();
const createRefResponse = await octokit.git.createRef({
owner,
@@ -537,7 +574,7 @@ export class PluginApiClient implements IPluginApiClient {
}: {
previousReleaseBranch: string;
nextReleaseBranch: string;
} & PartialProject) => {
} & OwnerRepo) => {
const { octokit } = await this.getOctokit();
const compareCommitsResponse = await octokit.repos.compareCommits({
owner,
@@ -560,7 +597,7 @@ export class PluginApiClient implements IPluginApiClient {
}: {
nextGitHubInfo: ReturnType<typeof getRcGitHubInfo>;
releaseBody: string;
} & PartialProject) => {
} & OwnerRepo) => {
const { octokit } = await this.getOctokit();
const createReleaseResponse = await octokit.repos.createRelease({
owner,
@@ -573,11 +610,9 @@ export class PluginApiClient implements IPluginApiClient {
});
return {
createReleaseResponse: {
name: createReleaseResponse.data.name,
htmlUrl: createReleaseResponse.data.html_url,
tagName: createReleaseResponse.data.tag_name,
},
name: createReleaseResponse.data.name,
htmlUrl: createReleaseResponse.data.html_url,
tagName: createReleaseResponse.data.tag_name,
};
},
};
@@ -592,10 +627,8 @@ export class PluginApiClient implements IPluginApiClient {
}: {
tagParts: SemverTagParts | CalverTagParts;
releaseBranchTree: string;
selectedPatchCommit: UnboxArray<
ApiMethodRetval<IPluginApiClient['getRecentCommits']>
>;
} & PartialProject) => {
selectedPatchCommit: GetRecentCommitsResultSingle;
} & OwnerRepo) => {
const { octokit } = await this.getOctokit();
const { data: tempCommit } = await octokit.git.createCommit({
owner,
@@ -618,15 +651,14 @@ export class PluginApiClient implements IPluginApiClient {
tempCommit,
}: {
releaseBranchName: string;
tempCommit: ApiMethodRetval<
IPluginApiClient['patch']['createTempCommit']
>;
} & PartialProject) => {
tempCommit: CreateTempCommitResult;
} & OwnerRepo) => {
const { octokit } = await this.getOctokit();
// await octokit.request("PATCH reposrefs")
await octokit.git.updateRef({
owner,
repo,
ref: releaseBranchName,
ref: `heads/${releaseBranchName}`,
sha: tempCommit.sha,
force: true,
});
@@ -637,7 +669,7 @@ export class PluginApiClient implements IPluginApiClient {
repo,
base,
head,
}: { base: string; head: string } & PartialProject) => {
}: { base: string; head: string } & OwnerRepo) => {
const { octokit } = await this.getOctokit();
const { data: merge } = await octokit.repos.merge({
owner,
@@ -666,12 +698,10 @@ export class PluginApiClient implements IPluginApiClient {
releaseBranchSha,
}: {
bumpedTag: string;
selectedPatchCommit: UnboxArray<
ApiMethodRetval<IPluginApiClient['getRecentCommits']>
>;
selectedPatchCommit: GetRecentCommitsResultSingle;
mergeTree: string;
releaseBranchSha: string;
} & PartialProject) => {
} & OwnerRepo) => {
const { octokit } = await this.getOctokit();
const { data: cherryPickCommit } = await octokit.git.createCommit({
owner,
@@ -694,15 +724,13 @@ export class PluginApiClient implements IPluginApiClient {
cherryPickCommit,
}: {
releaseBranchName: string;
cherryPickCommit: ApiMethodRetval<
IPluginApiClient['patch']['createCherryPickCommit']
>;
} & PartialProject) => {
cherryPickCommit: CreateCherryPickCommitResult;
} & OwnerRepo) => {
const { octokit } = await this.getOctokit();
const { data: updatedReference } = await octokit.git.updateRef({
owner,
repo,
ref: releaseBranchName,
ref: `heads/${releaseBranchName}`,
sha: cherryPickCommit.sha,
force: true,
});
@@ -722,10 +750,8 @@ export class PluginApiClient implements IPluginApiClient {
updatedReference,
}: {
bumpedTag: string;
updatedReference: ApiMethodRetval<
IPluginApiClient['patch']['replaceTempCommit']
>;
} & PartialProject) => {
updatedReference: ReplaceTempCommitResult;
} & OwnerRepo) => {
const { octokit } = await this.getOctokit();
const { data: createdTagObject } = await octokit.git.createTag({
owner,
@@ -750,10 +776,8 @@ export class PluginApiClient implements IPluginApiClient {
createdTagObject,
}: {
bumpedTag: string;
createdTagObject: ApiMethodRetval<
IPluginApiClient['patch']['createTagObject']
>;
} & PartialProject) => {
createdTagObject: CreateTagObjectResult;
} & OwnerRepo) => {
const { octokit } = await this.getOctokit();
const { data: reference } = await octokit.git.createRef({
owner,
@@ -776,14 +800,10 @@ export class PluginApiClient implements IPluginApiClient {
selectedPatchCommit,
}: {
bumpedTag: string;
latestRelease: NonNullable<
ApiMethodRetval<IPluginApiClient['getLatestRelease']>['latestRelease']
>;
latestRelease: NonNullable<GetLatestReleaseResult>;
tagParts: SemverTagParts | CalverTagParts;
selectedPatchCommit: UnboxArray<
ApiMethodRetval<IPluginApiClient['getRecentCommits']>
>;
} & PartialProject) => {
selectedPatchCommit: GetRecentCommitsResultSingle;
} & OwnerRepo) => {
const { octokit } = await this.getOctokit();
const { data: updatedRelease } = await octokit.repos.updateRelease({
owner,
@@ -792,9 +812,9 @@ export class PluginApiClient implements IPluginApiClient {
tag_name: bumpedTag,
body: `${latestRelease.body}
#### [Patch ${tagParts.patch}](${selectedPatchCommit.htmlUrl})
#### [Patch ${tagParts.patch}](${selectedPatchCommit.htmlUrl})
${selectedPatchCommit.commit.message}`,
${selectedPatchCommit.commit.message}`,
});
return {
@@ -812,11 +832,9 @@ export class PluginApiClient implements IPluginApiClient {
releaseId,
releaseVersion,
}: {
releaseId: NonNullable<
ApiMethodRetval<IPluginApiClient['getLatestRelease']>['latestRelease']
>['id'];
releaseId: NonNullable<GetLatestReleaseResult>['id'];
releaseVersion: string;
} & PartialProject) => {
} & OwnerRepo) => {
const { octokit } = await this.getOctokit();
const { data: promotedRelease } = await octokit.repos.updateRelease({
owner,
@@ -18,13 +18,13 @@ import React from 'react';
import { render } from '@testing-library/react';
import {
mockApiClient,
mockCalverProject,
mockNextGitHubInfo,
mockRcRelease,
mockReleaseCandidate,
mockReleaseBranch,
mockReleaseVersion,
mockReleaseVersionCalver,
mockSemverProject,
mockApiClient,
} from '../../test-helpers/test-helpers';
import { TEST_IDS } from '../../test-helpers/test-ids';
@@ -46,7 +46,7 @@ describe('CreateRc', () => {
const { getByTestId } = render(
<CreateRc
defaultBranch="mockDefaultBranch"
latestRelease={mockRcRelease}
latestRelease={mockReleaseCandidate}
releaseBranch={mockReleaseBranch}
/>,
);
@@ -60,7 +60,7 @@ describe('CreateRc', () => {
const { getByTestId } = render(
<CreateRc
defaultBranch="mockDefaultBranch"
latestRelease={mockReleaseVersion}
latestRelease={mockReleaseVersionCalver}
releaseBranch={mockReleaseBranch}
/>,
);
@@ -26,27 +26,27 @@ import {
} from '@material-ui/core';
import { useAsyncFn } from 'react-use';
import { ComponentConfigCreateRc } from '../../types/types';
import { createRc } from './sideEffects/createRc';
import { Differ } from '../../components/Differ';
import { getRcGitHubInfo } from './getRcGitHubInfo';
import { InfoCardPlus } from '../../components/InfoCardPlus';
import { ComponentConfigCreateRc } from '../../types/types';
import { ResponseStepList } from '../../components/ResponseStepList/ResponseStepList';
import { SEMVER_PARTS } from '../../constants/constants';
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 {
GetBranchResult,
GetLatestReleaseResult,
GetRepositoryResult,
} from '../../api/PluginApiClient';
interface CreateRcProps {
defaultBranch: ApiMethodRetval<
IPluginApiClient['getRepository']
>['repository']['defaultBranch'];
latestRelease: ApiMethodRetval<
IPluginApiClient['getLatestRelease']
>['latestRelease'];
releaseBranch: ApiMethodRetval<IPluginApiClient['getBranch']> | null;
defaultBranch: GetRepositoryResult['defaultBranch'];
latestRelease: GetLatestReleaseResult;
releaseBranch: GetBranchResult | null;
successCb?: ComponentConfigCreateRc['successCb'];
}
@@ -16,10 +16,11 @@
import { DateTime } from 'luxon';
import { ApiMethodRetval, IPluginApiClient } from '../../api/PluginApiClient';
import {
mockSemverProject,
mockCalverProject,
mockReleaseVersionCalver,
mockReleaseVersionSemver,
} from '../../test-helpers/test-helpers';
import { getRcGitHubInfo } from './getRcGitHubInfo';
@@ -33,15 +34,11 @@ describe('getRcGitHubInfo', () => {
});
describe('calver', () => {
const latestRelease = {
tagName: 'rc-2020.01.01_0',
} as ApiMethodRetval<IPluginApiClient['getLatestRelease']>['latestRelease'];
it('should return correct GitHub info', () => {
expect(
getRcGitHubInfo({
project: mockCalverProject,
latestRelease,
latestRelease: mockReleaseVersionCalver,
semverBumpLevel: 'minor',
injectedDate: '2021.01.28',
}),
@@ -56,22 +53,18 @@ describe('getRcGitHubInfo', () => {
});
describe('semver', () => {
const latestRelease = {
tagName: 'rc-1.1.1',
} as ApiMethodRetval<IPluginApiClient['getLatestRelease']>['latestRelease'];
it("should return correct GitHub info when there's previous releases", () => {
expect(
getRcGitHubInfo({
project: mockSemverProject,
latestRelease,
latestRelease: mockReleaseVersionSemver,
semverBumpLevel: 'minor',
}),
).toMatchInlineSnapshot(`
Object {
"rcBranch": "rc/1.2.0",
"rcReleaseTag": "rc-1.2.0",
"releaseName": "Version 1.2.0",
"rcBranch": "rc/1.3.0",
"rcReleaseTag": "rc-1.3.0",
"releaseName": "Version 1.3.0",
}
`);
});
@@ -17,10 +17,10 @@
import { DateTime } from 'luxon';
import { getBumpedSemverTagParts } from '../../helpers/getBumpedTag';
import { GetLatestReleaseResult } from '../../api/PluginApiClient';
import { getSemverTagParts } from '../../helpers/tagParts/getSemverTagParts';
import { SEMVER_PARTS } from '../../constants/constants';
import { Project } from '../../contexts/ProjectContext';
import { ApiMethodRetval, IPluginApiClient } from '../../api/PluginApiClient';
import { SEMVER_PARTS } from '../../constants/constants';
export const getRcGitHubInfo = ({
project,
@@ -29,9 +29,7 @@ export const getRcGitHubInfo = ({
injectedDate = DateTime.now().toFormat('yyyy.MM.dd'),
}: {
project: Project;
latestRelease: ApiMethodRetval<
IPluginApiClient['getLatestRelease']
>['latestRelease'];
latestRelease: GetLatestReleaseResult;
semverBumpLevel: keyof typeof SEMVER_PARTS;
injectedDate?: string;
}) => {
@@ -19,7 +19,7 @@ import {
mockCalverProject,
mockDefaultBranch,
mockNextGitHubInfo,
mockReleaseVersion,
mockReleaseVersionCalver,
} from '../../../test-helpers/test-helpers';
import { createRc } from './createRc';
@@ -29,7 +29,7 @@ describe('createRc', () => {
it('should work', async () => {
const result = await createRc({
defaultBranch: mockDefaultBranch,
latestRelease: mockReleaseVersion,
latestRelease: mockReleaseVersionCalver,
nextGitHubInfo: mockNextGitHubInfo,
pluginApiClient: mockApiClient,
project: mockCalverProject,
@@ -17,19 +17,16 @@
import { getRcGitHubInfo } from '../getRcGitHubInfo';
import { ComponentConfigCreateRc, ResponseStep } from '../../../types/types';
import {
ApiMethodRetval,
GetLatestReleaseResult,
GetRepositoryResult,
IPluginApiClient,
} from '../../../api/PluginApiClient';
import { GitHubReleaseManagerError } from '../../../errors/GitHubReleaseManagerError';
import { Project } from '../../../contexts/ProjectContext';
interface CreateRC {
defaultBranch: ApiMethodRetval<
IPluginApiClient['getRepository']
>['repository']['defaultBranch'];
latestRelease: ApiMethodRetval<
IPluginApiClient['getLatestRelease']
>['latestRelease'];
defaultBranch: GetRepositoryResult['defaultBranch'];
latestRelease: GetLatestReleaseResult;
nextGitHubInfo: ReturnType<typeof getRcGitHubInfo>;
pluginApiClient: IPluginApiClient;
project: Project;
@@ -50,7 +47,8 @@ export async function createRc({
* 1. Get the default branch's most recent commit
*/
const latestCommit = await pluginApiClient.getLatestCommit({
...project,
owner: project.owner,
repo: project.repo,
defaultBranch,
});
responseSteps.push({
@@ -65,7 +63,8 @@ export async function createRc({
const mostRecentSha = latestCommit.sha;
const createdRef = await pluginApiClient.createRc
.createRef({
...project,
owner: project.owner,
repo: project.repo,
mostRecentSha,
targetBranch: nextGitHubInfo.rcBranch,
})
@@ -90,7 +89,8 @@ export async function createRc({
: defaultBranch;
const nextReleaseBranch = nextGitHubInfo.rcBranch;
const comparison = await pluginApiClient.createRc.getComparison({
...project,
owner: project.owner,
repo: project.repo,
previousReleaseBranch,
nextReleaseBranch,
});
@@ -112,25 +112,24 @@ export async function createRc({
/**
* 4. Creates the release itself in GitHub
*/
const {
createReleaseResponse,
} = await pluginApiClient.createRc.createRelease({
...project,
const createReleaseResult = await pluginApiClient.createRc.createRelease({
owner: project.owner,
repo: project.repo,
nextGitHubInfo: nextGitHubInfo,
releaseBody,
});
responseSteps.push({
message: `Created Release Candidate "${createReleaseResponse.name}"`,
message: `Created Release Candidate "${createReleaseResult.name}"`,
secondaryMessage: `with tag "${nextGitHubInfo.rcReleaseTag}"`,
link: createReleaseResponse.htmlUrl,
link: createReleaseResult.htmlUrl,
});
await successCb?.({
gitHubReleaseUrl: createReleaseResponse.htmlUrl,
gitHubReleaseName: createReleaseResponse.name,
gitHubReleaseUrl: createReleaseResult.htmlUrl,
gitHubReleaseName: createReleaseResult.name,
comparisonUrl: comparison.htmlUrl,
previousTag: latestRelease?.tagName,
createdTag: createReleaseResponse.tagName,
createdTag: createReleaseResult.tagName,
});
return responseSteps;
@@ -23,13 +23,14 @@ import { TEST_IDS } from '../../test-helpers/test-ids';
import { useProjectContext } from '../../contexts/ProjectContext';
import { useStyles } from '../../styles/styles';
import flowImage from './flow.png';
import { ApiMethodRetval, IPluginApiClient } from '../../api/PluginApiClient';
import {
GetBranchResult,
GetLatestReleaseResult,
} from '../../api/PluginApiClient';
interface InfoCardProps {
releaseBranch: ApiMethodRetval<IPluginApiClient['getBranch']> | null;
latestRelease: ApiMethodRetval<
IPluginApiClient['getLatestRelease']
>['latestRelease'];
releaseBranch: GetBranchResult | null;
latestRelease: GetLatestReleaseResult;
}
export const Info = ({ releaseBranch, latestRelease }: InfoCardProps) => {
@@ -17,7 +17,10 @@
import React from 'react';
import { Typography } from '@material-ui/core';
import { ApiMethodRetval, IPluginApiClient } from '../../api/PluginApiClient';
import {
GetBranchResult,
GetLatestReleaseResult,
} from '../../api/PluginApiClient';
import { ComponentConfigPatch } from '../../types/types';
import { getBumpedTag } from '../../helpers/getBumpedTag';
import { InfoCardPlus } from '../../components/InfoCardPlus';
@@ -27,10 +30,8 @@ import { useProjectContext } from '../../contexts/ProjectContext';
import { useStyles } from '../../styles/styles';
interface PatchProps {
latestRelease: ApiMethodRetval<
IPluginApiClient['getLatestRelease']
>['latestRelease'];
releaseBranch: ApiMethodRetval<IPluginApiClient['getBranch']> | null;
latestRelease: GetLatestReleaseResult;
releaseBranch: GetBranchResult | null;
successCb?: ComponentConfigPatch['successCb'];
}
@@ -21,9 +21,9 @@ import {
mockApiClient,
mockBumpedTag,
mockCalverProject,
mockRcRelease,
mockReleaseCandidate,
mockReleaseBranch,
mockReleaseVersion,
mockReleaseVersionCalver,
mockTagParts,
} from '../../test-helpers/test-helpers';
@@ -48,7 +48,7 @@ describe('PatchBody', () => {
const { getByTestId } = render(
<PatchBody
bumpedTag={mockBumpedTag}
latestRelease={mockRcRelease}
latestRelease={mockReleaseCandidate}
releaseBranch={mockReleaseBranch}
tagParts={mockTagParts}
/>,
@@ -64,7 +64,7 @@ describe('PatchBody', () => {
it('should render not-prerelease description', async () => {
const { getByTestId } = render(
<PatchBody
latestRelease={mockReleaseVersion}
latestRelease={mockReleaseVersionCalver}
releaseBranch={mockReleaseBranch}
bumpedTag={mockBumpedTag}
tagParts={mockTagParts}
@@ -45,18 +45,16 @@ import { usePluginApiClientContext } from '../../contexts/PluginApiClientContext
import { useProjectContext } from '../../contexts/ProjectContext';
import { useStyles } from '../../styles/styles';
import {
ApiMethodRetval,
IPluginApiClient,
UnboxArray,
GetBranchResult,
GetLatestReleaseResult,
GetRecentCommitsResultSingle,
} from '../../api/PluginApiClient';
import { GitHubReleaseManagerError } from '../../errors/GitHubReleaseManagerError';
interface PatchBodyProps {
bumpedTag: string;
latestRelease: NonNullable<
ApiMethodRetval<IPluginApiClient['getLatestRelease']>['latestRelease']
>;
releaseBranch: ApiMethodRetval<IPluginApiClient['getBranch']>;
latestRelease: NonNullable<GetLatestReleaseResult>;
releaseBranch: GetBranchResult;
successCb?: ComponentConfigPatch['successCb'];
tagParts: NonNullable<CalverTagParts | SemverTagParts>;
}
@@ -95,9 +93,7 @@ export const PatchBody = ({
});
const [patchReleaseResponse, patchReleaseFn] = useAsyncFn(async (...args) => {
const selectedPatchCommit: UnboxArray<
ApiMethodRetval<IPluginApiClient['getRecentCommits']>
> = args[0];
const selectedPatchCommit: GetRecentCommitsResultSingle = args[0];
const patchResponseSteps = await patch({
project,
pluginApiClient,
@@ -242,7 +238,8 @@ export const PatchBody = ({
disabled={commitExistsOnReleaseBranch || !releaseBranch}
onClick={() => {
const repoPath = pluginApiClient.getRepoPath({
...project,
owner: project.owner,
repo: project.repo,
});
const host = pluginApiClient.getHost();
@@ -277,16 +274,16 @@ export const PatchBody = ({
);
}
const selectedPatchCommit =
githubDataResponse.value?.recentCommitsOnDefaultBranch[
checkedCommitIndex
];
return (
<Button
disabled={checkedCommitIndex === -1 || !selectedPatchCommit}
disabled={checkedCommitIndex === -1}
variant="contained"
color="primary"
onClick={() => {
const selectedPatchCommit =
githubDataResponse.value?.recentCommitsOnDefaultBranch[
checkedCommitIndex
];
if (!selectedPatchCommit) {
throw new GitHubReleaseManagerError(
'Could not find selected patch commit',
@@ -18,7 +18,7 @@ import {
mockApiClient,
mockBumpedTag,
mockCalverProject,
mockReleaseVersion,
mockReleaseVersionCalver,
mockSelectedPatchCommit,
mockTagParts,
} from '../../../test-helpers/test-helpers';
@@ -30,7 +30,7 @@ describe('patch', () => {
it('should work', async () => {
const result = await patch({
bumpedTag: mockBumpedTag,
latestRelease: mockReleaseVersion,
latestRelease: mockReleaseVersionCalver,
pluginApiClient: mockApiClient,
project: mockCalverProject,
selectedPatchCommit: mockSelectedPatchCommit,
@@ -17,23 +17,19 @@
import { ComponentConfigPatch, ResponseStep } from '../../../types/types';
import { CalverTagParts } from '../../../helpers/tagParts/getCalverTagParts';
import {
ApiMethodRetval,
GetLatestReleaseResult,
GetRecentCommitsResultSingle,
IPluginApiClient,
UnboxArray,
} from '../../../api/PluginApiClient';
import { Project } from '../../../contexts/ProjectContext';
import { SemverTagParts } from '../../../helpers/tagParts/getSemverTagParts';
interface Patch {
bumpedTag: string;
latestRelease: NonNullable<
ApiMethodRetval<IPluginApiClient['getLatestRelease']>['latestRelease']
>;
latestRelease: NonNullable<GetLatestReleaseResult>;
pluginApiClient: IPluginApiClient;
project: Project;
selectedPatchCommit: UnboxArray<
ApiMethodRetval<IPluginApiClient['getRecentCommits']>
>;
selectedPatchCommit: GetRecentCommitsResultSingle;
successCb?: ComponentConfigPatch['successCb'];
tagParts: NonNullable<CalverTagParts | SemverTagParts>;
}
@@ -49,8 +45,8 @@ export async function patch({
tagParts,
}: Patch) {
const responseSteps: ResponseStep[] = [];
const releaseBranchName = latestRelease.targetCommitish;
/**
* 1. Here is the branch we want to cherry-pick to:
* > branch = GET /repos/$owner/$repo/branches/$branchName
@@ -58,7 +54,8 @@ export async function patch({
* > branchTree = branch.commit.commit.tree.sha
*/
const releaseBranch = await pluginApiClient.getBranch({
...project,
owner: project.owner,
repo: project.repo,
branchName: releaseBranchName,
});
const releaseBranchSha = releaseBranch.commit.sha;
@@ -75,7 +72,8 @@ export async function patch({
* > tempCommit = POST /repos/$owner/$repo/git/commits { "message": "temp", "tree": branchTree, "parents": [parentSha] }
*/
const tempCommit = await pluginApiClient.patch.createTempCommit({
...project,
owner: project.owner,
repo: project.repo,
releaseBranchTree,
selectedPatchCommit,
tagParts,
@@ -90,7 +88,8 @@ export async function patch({
* > PATCH /repos/$owner/$repo/git/refs/heads/$refName { sha = tempCommit.sha, force = true }
*/
await pluginApiClient.patch.forceBranchHeadToTempCommit({
...project,
owner: project.owner,
repo: project.repo,
tempCommit,
releaseBranchName,
});
@@ -100,7 +99,8 @@ export async function patch({
* > merge = POST /repos/$owner/$repo/merges { "base": branchName, "head": commit.sha }
*/
const merge = await pluginApiClient.patch.merge({
...project,
owner: project.owner,
repo: project.repo,
base: releaseBranchName,
head: selectedPatchCommit.sha,
});
@@ -122,7 +122,8 @@ export async function patch({
* > cherry = POST /repos/$owner/$repo/git/commits { "message": "looks good!", "tree": mergeTree, "parents": [branchSha] }
*/
const cherryPickCommit = await pluginApiClient.patch.createCherryPickCommit({
...project,
owner: project.owner,
repo: project.repo,
bumpedTag,
mergeTree,
releaseBranchSha,
@@ -138,7 +139,8 @@ export async function patch({
* > PATCH /repos/$owner/$repo/git/refs/heads/$refName { sha = cherry.sha, force = true }
*/
const updatedReference = await pluginApiClient.patch.replaceTempCommit({
...project,
owner: project.owner,
repo: project.repo,
cherryPickCommit,
releaseBranchName,
});
@@ -151,7 +153,8 @@ export async function patch({
* > POST /repos/:owner/:repo/git/tags
*/
const createdTagObject = await pluginApiClient.patch.createTagObject({
...project,
owner: project.owner,
repo: project.repo,
bumpedTag,
updatedReference,
});
@@ -165,7 +168,8 @@ export async function patch({
* > POST /repos/:owner/:repo/git/refs
*/
const reference = await pluginApiClient.patch.createReference({
...project,
owner: project.owner,
repo: project.repo,
bumpedTag,
createdTagObject,
});
@@ -178,7 +182,8 @@ export async function patch({
* 9. Update release
*/
const updatedRelease = await pluginApiClient.patch.updateRelease({
...project,
owner: project.owner,
repo: project.repo,
bumpedTag,
latestRelease,
selectedPatchCommit,
@@ -18,8 +18,8 @@ import React from 'react';
import { render } from '@testing-library/react';
import {
mockRcRelease,
mockReleaseVersion,
mockReleaseCandidate,
mockReleaseVersionCalver,
} from '../../test-helpers/test-helpers';
import { TEST_IDS } from '../../test-helpers/test-ids';
@@ -42,14 +42,16 @@ describe('PromoteRc', () => {
it('should display not-rc warning', () => {
const { getByTestId } = render(
<PromoteRc latestRelease={mockReleaseVersion} />,
<PromoteRc latestRelease={mockReleaseVersionCalver} />,
);
expect(getByTestId(TEST_IDS.promoteRc.notRcWarning)).toBeInTheDocument();
});
it('should display PromoteRcBody', () => {
const { getByTestId } = render(<PromoteRc latestRelease={mockRcRelease} />);
const { getByTestId } = render(
<PromoteRc latestRelease={mockReleaseCandidate} />,
);
expect(
getByTestId(TEST_IDS.promoteRc.mockedPromoteRcBody),
@@ -24,12 +24,10 @@ import { ComponentConfigPromoteRc } from '../../types/types';
import { PromoteRcBody } from './PromoteRcBody';
import { useStyles } from '../../styles/styles';
import { TEST_IDS } from '../../test-helpers/test-ids';
import { ApiMethodRetval, IPluginApiClient } from '../../api/PluginApiClient';
import { GetLatestReleaseResult } from '../../api/PluginApiClient';
interface PromoteRcProps {
latestRelease: ApiMethodRetval<
IPluginApiClient['getLatestRelease']
>['latestRelease'];
latestRelease: GetLatestReleaseResult;
successCb?: ComponentConfigPromoteRc['successCb'];
}
@@ -20,7 +20,7 @@ import { render } from '@testing-library/react';
import {
mockApiClient,
mockCalverProject,
mockRcRelease,
mockReleaseCandidate,
} from '../../test-helpers/test-helpers';
import { TEST_IDS } from '../../test-helpers/test-ids';
@@ -35,7 +35,9 @@ import { PromoteRcBody } from './PromoteRcBody';
describe('PromoteRcBody', () => {
it('should display CTA', () => {
const { getByTestId } = render(<PromoteRcBody rcRelease={mockRcRelease} />);
const { getByTestId } = render(
<PromoteRcBody rcRelease={mockReleaseCandidate} />,
);
expect(getByTestId(TEST_IDS.promoteRc.cta)).toBeInTheDocument();
});
@@ -27,12 +27,10 @@ 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 { GetLatestReleaseResult } from '../../api/PluginApiClient';
interface PromoteRcBodyProps {
rcRelease: NonNullable<
ApiMethodRetval<IPluginApiClient['getLatestRelease']>['latestRelease']
>;
rcRelease: NonNullable<GetLatestReleaseResult>;
successCb?: ComponentConfigPromoteRc['successCb'];
}
@@ -16,7 +16,7 @@
import {
mockApiClient,
mockRcRelease,
mockReleaseCandidate,
mockSemverProject,
} from '../../../test-helpers/test-helpers';
import { promoteRc } from './promoteRc';
@@ -27,7 +27,7 @@ describe('promoteRc', () => {
it('should work', async () => {
const result = await promoteRc({
pluginApiClient: mockApiClient,
rcRelease: mockRcRelease,
rcRelease: mockReleaseCandidate,
releaseVersion: 'version-1.2.3',
project: mockSemverProject,
})();
@@ -16,7 +16,7 @@
import { ComponentConfigPromoteRc, ResponseStep } from '../../../types/types';
import {
ApiMethodRetval,
GetLatestReleaseResult,
IPluginApiClient,
} from '../../../api/PluginApiClient';
import { Project } from '../../../contexts/ProjectContext';
@@ -24,9 +24,7 @@ import { Project } from '../../../contexts/ProjectContext';
interface PromoteRc {
pluginApiClient: IPluginApiClient;
project: Project;
rcRelease: NonNullable<
ApiMethodRetval<IPluginApiClient['getLatestRelease']>['latestRelease']
>;
rcRelease: NonNullable<GetLatestReleaseResult>;
releaseVersion: string;
successCb?: ComponentConfigPromoteRc['successCb'];
}
@@ -17,12 +17,11 @@
import React from 'react';
import { render } from '@testing-library/react';
import { mockRefetch } from '../../test-helpers/test-helpers';
import { ResponseStepList } from './ResponseStepList';
import { TEST_IDS } from '../../test-helpers/test-ids';
jest.mock('../../contexts/RefetchContext', () => ({
useRefetchContext: jest.fn(() => mockRefetch),
useRefetchContext: () => jest.fn(),
}));
describe('ResponseStepList', () => {
@@ -20,6 +20,11 @@ describe('constants', () => {
it('should match snapshot', () => {
expect(constants).toMatchInlineSnapshot(`
Object {
"DISABLE_CACHE": Object {
"headers": Object {
"If-None-Match": "",
},
},
"SEMVER_PARTS": Object {
"major": "major",
"minor": "minor",
@@ -23,3 +23,9 @@ export const SEMVER_PARTS: {
minor: 'minor',
patch: 'patch',
} as const;
export const DISABLE_CACHE = {
headers: {
'If-None-Match': '',
},
} as const;
@@ -26,7 +26,7 @@ export const getGitHubBatchInfo = ({
project,
pluginApiClient,
}: GetGitHubBatchInfo) => async () => {
const [{ repository }, { latestRelease }] = await Promise.all([
const [repository, latestRelease] = await Promise.all([
pluginApiClient.getRepository({ ...project }),
pluginApiClient.getLatestRelease({ ...project }),
]);
@@ -62,14 +62,6 @@ describe('testHelpers', () => {
"rcReleaseTag": "rc-1.2.3",
"releaseName": "Version 1.2.3",
},
"mockRcRelease": Object {
"htmlUrl": "mock_release_html_url",
"id": 1,
"prerelease": true,
"tagName": "rc-2020.01.01_1",
"targetCommitish": "rc/1.2.3",
},
"mockRefetch": [MockFunction],
"mockReleaseBranch": Object {
"commit": Object {
"commit": Object {
@@ -84,13 +76,27 @@ describe('testHelpers', () => {
},
"name": "rc/1.2.3",
},
"mockReleaseVersion": Object {
"mockReleaseCandidate": Object {
"htmlUrl": "mock_release_html_url",
"id": 1,
"prerelease": true,
"tagName": "rc-2020.01.01_1",
"targetCommitish": "rc/1.2.3",
},
"mockReleaseVersionCalver": Object {
"htmlUrl": "mock_release_html_url",
"id": 1,
"prerelease": false,
"tagName": "version-2020.01.01_1",
"targetCommitish": "rc/1.2.3",
},
"mockReleaseVersionSemver": Object {
"htmlUrl": "mock_release_html_url",
"id": 1,
"prerelease": false,
"tagName": "version-1.2.3",
"targetCommitish": "rc/1.2.3",
},
"mockSelectedPatchCommit": Object {
"author": Object {
"htmlUrl": "author_html_url",
@@ -100,6 +106,7 @@ describe('testHelpers', () => {
"message": "commit_message",
},
"firstParentSha": "mock_first_parent_sha",
"htmlUrl": "mock_htmlUrl",
"sha": "mock_sha_selected_patch_commit",
},
"mockSemverProject": Object {
@@ -18,9 +18,10 @@ import { CalverTagParts } from '../helpers/tagParts/getCalverTagParts';
import { getRcGitHubInfo } from '../cards/createRc/getRcGitHubInfo';
import { Project } from '../contexts/ProjectContext';
import {
ApiMethodRetval,
GetBranchResult,
GetLatestReleaseResult,
GetRecentCommitsResultSingle,
IPluginApiClient,
UnboxArray,
} from '../api/PluginApiClient';
export const mockSemverProject: Project = {
@@ -59,74 +60,69 @@ const createMockRelease = ({
prerelease = false,
...rest
}: Partial<
NonNullable<
ApiMethodRetval<IPluginApiClient['getLatestRelease']>['latestRelease']
>
> = {}) =>
({
id: 1,
htmlUrl: 'mock_release_html_url',
prerelease,
...rest,
} as NonNullable<
ApiMethodRetval<IPluginApiClient['getLatestRelease']>['latestRelease']
>);
export const mockRcRelease = createMockRelease({
NonNullable<GetLatestReleaseResult>
> = {}): NonNullable<GetLatestReleaseResult> => ({
id: 1,
htmlUrl: 'mock_release_html_url',
prerelease,
tagName: 'rc-2020.01.01_1',
targetCommitish: 'rc/1.2.3',
...rest,
});
export const mockReleaseCandidate = createMockRelease({
prerelease: true,
tagName: 'rc-2020.01.01_1',
targetCommitish: 'rc/1.2.3',
});
export const mockReleaseVersion = createMockRelease({
export const mockReleaseVersionCalver = createMockRelease({
prerelease: false,
tagName: 'version-2020.01.01_1',
targetCommitish: 'rc/1.2.3',
});
export const mockReleaseVersionSemver = createMockRelease({
prerelease: false,
tagName: 'version-1.2.3',
targetCommitish: 'rc/1.2.3',
});
/**
* MOCK BRANCH
*/
const createMockBranch = ({
...rest
}: Partial<NonNullable<ApiMethodRetval<IPluginApiClient['getBranch']>>> = {}) =>
({
name: 'rc/1.2.3',
commit: {
sha: 'mock_branch_commit_sha',
commit: { tree: { sha: 'mock_branch_commit_commit_tree_sha' } },
},
links: { html: 'mock_branch_links_html' },
...rest,
} as NonNullable<ApiMethodRetval<IPluginApiClient['getBranch']>>);
}: Partial<GetBranchResult> = {}): GetBranchResult => ({
name: 'rc/1.2.3',
commit: {
sha: 'mock_branch_commit_sha',
commit: { tree: { sha: 'mock_branch_commit_commit_tree_sha' } },
},
links: { html: 'mock_branch_links_html' },
...rest,
});
export const mockReleaseBranch = createMockBranch();
/**
* MOCK COMMIT
*/
const createMockCommit = ({
const createMockRecentCommit = ({
...rest
}: Partial<
NonNullable<UnboxArray<ApiMethodRetval<IPluginApiClient['getRecentCommits']>>>
>) =>
({
author: {
htmlUrl: 'author_html_url',
login: 'author_login',
},
commit: {
message: 'commit_message',
},
sha: 'mock_sha',
firstParentSha: 'mock_first_parent_sha',
...rest,
} as NonNullable<
UnboxArray<ApiMethodRetval<IPluginApiClient['getRecentCommits']>>
>);
export const mockSelectedPatchCommit = createMockCommit({
sha: 'mock_sha_selected_patch_commit',
}: Partial<GetRecentCommitsResultSingle>): GetRecentCommitsResultSingle => ({
author: {
htmlUrl: 'author_html_url',
login: 'author_login',
},
commit: {
message: 'commit_message',
},
sha: 'mock_sha',
firstParentSha: 'mock_first_parent_sha',
htmlUrl: 'mock_htmlUrl',
...rest,
});
export const mockRefetch = jest.fn();
export const mockSelectedPatchCommit = createMockRecentCommit({
sha: 'mock_sha_selected_patch_commit',
});
/**
* MOCK API CLIENT
@@ -136,74 +132,77 @@ export const mockApiClient: IPluginApiClient = {
getRepoPath: jest.fn(() => 'erikengervall/playground'),
getOwners: jest.fn(),
getOwners: jest.fn(async () => ({
owners: ['owner1', 'owner2'],
})),
getRepositories: jest.fn(),
getRepositories: jest.fn(async () => ({
repositories: ['repo1', 'repo2'],
})),
getUsername: jest.fn(),
getUsername: jest.fn(async () => ({
username: 'erikengervall',
})),
getRecentCommits: jest
.fn()
.mockResolvedValue([
createMockCommit({ sha: 'mock_sha_recent_commits_1' }),
createMockCommit({ sha: 'mock_sha_recent_commits_2' }),
]),
getRecentCommits: jest.fn(async () => [
createMockRecentCommit({ sha: 'mock_sha_recent_commits_1' }),
createMockRecentCommit({ sha: 'mock_sha_recent_commits_2' }),
]),
getLatestRelease: jest.fn(), // TODO:
getLatestRelease: jest.fn(),
getRepository: jest.fn(),
getLatestCommit: jest.fn().mockResolvedValue({
getLatestCommit: jest.fn(async () => ({
sha: 'latestCommit.sha',
htmlUrl: 'latestCommit.html_url',
commit: {
message: 'latestCommit.commit.message',
},
} as NonNullable<ApiMethodRetval<IPluginApiClient['getLatestCommit']>>),
})),
getBranch: jest.fn().mockResolvedValue(createMockBranch()),
getBranch: jest.fn(async () => createMockBranch()),
createRc: {
createRef: jest.fn().mockResolvedValue({
createRef: jest.fn(async () => ({
ref: 'mock_createRef_ref',
} as NonNullable<ApiMethodRetval<IPluginApiClient['createRc']['createRef']>>),
})),
createRelease: jest.fn().mockResolvedValue({
createReleaseResponse: {
name: 'mock_createRelease_name',
htmlUrl: 'mock_createRelease_html_url',
tagName: 'mock_createRelease_tag_name',
},
} as NonNullable<ApiMethodRetval<IPluginApiClient['createRc']['createRelease']>>),
createRelease: jest.fn(async () => ({
name: 'mock_createRelease_name',
htmlUrl: 'mock_createRelease_html_url',
tagName: 'mock_createRelease_tag_name',
})),
getComparison: jest.fn().mockResolvedValue({
getComparison: jest.fn(async () => ({
htmlUrl: 'mock_compareCommits_html_url',
aheadBy: 1,
} as NonNullable<ApiMethodRetval<IPluginApiClient['createRc']['getComparison']>>),
})),
},
patch: {
createCherryPickCommit: jest.fn().mockResolvedValue({
createCherryPickCommit: jest.fn(async () => ({
message: 'mock_cherrypick_message',
sha: 'mock_cherrypick_sha',
} as NonNullable<ApiMethodRetval<IPluginApiClient['patch']['createCherryPickCommit']>>),
})),
createReference: jest.fn().mockResolvedValue({
createReference: jest.fn(async () => ({
ref: 'mock_reference_ref',
} as ApiMethodRetval<IPluginApiClient['patch']['createReference']>),
})),
createTagObject: jest.fn().mockResolvedValue({
createTagObject: jest.fn(async () => ({
tag: 'mock_tag_object_tag',
sha: 'mock_tag_object_sha',
} as ApiMethodRetval<IPluginApiClient['patch']['createTagObject']>),
})),
createTempCommit: jest.fn().mockResolvedValue({
createTempCommit: jest.fn(async () => ({
message: 'mock_commit_message',
sha: 'mock_commit_sha',
} as ApiMethodRetval<IPluginApiClient['patch']['createTempCommit']>),
forceBranchHeadToTempCommit: jest.fn().mockResolvedValue(undefined),
})),
merge: jest.fn().mockResolvedValue({
forceBranchHeadToTempCommit: jest.fn(async () => undefined),
merge: jest.fn(async () => ({
htmlUrl: 'mock_merge_html_url',
commit: {
message: 'mock_merge_commit_message',
@@ -211,27 +210,27 @@ export const mockApiClient: IPluginApiClient = {
sha: 'mock_merge_commit_tree_sha',
},
},
} as ApiMethodRetval<IPluginApiClient['patch']['merge']>),
})),
replaceTempCommit: jest.fn().mockResolvedValue({
replaceTempCommit: jest.fn(async () => ({
ref: 'mock_reference_ref',
object: {
sha: 'mock_reference_object_sha',
},
} as ApiMethodRetval<IPluginApiClient['patch']['replaceTempCommit']>),
})),
updateRelease: jest.fn().mockResolvedValue({
updateRelease: jest.fn(async () => ({
name: 'mock_update_release_name',
tagName: 'mock_update_release_tag_name',
htmlUrl: 'mock_update_release_html_url',
} as ApiMethodRetval<IPluginApiClient['patch']['updateRelease']>),
})),
},
promoteRc: {
promoteRelease: jest.fn().mockResolvedValue({
promoteRelease: jest.fn(async () => ({
name: 'mock_release_name',
tagName: 'mock_release_tag_name',
htmlUrl: 'mock_release_html_url',
} as ApiMethodRetval<IPluginApiClient['promoteRc']['promoteRelease']>),
})),
},
};