Continue renaming code from GitHub to Git
Signed-off-by: Erik Engervall <erik.engervall@gmail.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# GitHub Release Manager (GRM)
|
||||
# Git Release Manager (GRM)
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
|
||||
Does it build and ship your code? **No**.
|
||||
|
||||
What `GRM` does is manage your **[releases](https://docs.github.com/en/github/administering-a-repository/managing-releases-in-a-repository)** on GitHub, building and shipping is entirely up to you as a developer to handle in your CI.
|
||||
What `GRM` does is manage your Git **[releases](https://docs.github.com/en/github/administering-a-repository/managing-releases-in-a-repository)**, building and shipping is entirely up to you as a developer to handle in your CI.
|
||||
|
||||
`GRM` is built with industry standards in mind and the flow is as follows:
|
||||
|
||||

|
||||
|
||||
> **GitHub**: The source control system where releases reside in a practical sense. Read more about [GitHub releases](https://docs.github.com/en/github/administering-a-repository/managing-releases-in-a-repository). (Note that this plugin works just as well with GitHub Enterprise.)
|
||||
> **Git**: The source control system where releases reside in a practical sense. Read more about [Git releases](https://docs.github.com/en/github/administering-a-repository/managing-releases-in-a-repository). (Note that this plugin works just as well with any system implementing `Git`.)
|
||||
>
|
||||
> **Release Candidate (RC)**: A GitHub pre-release intended primarily for internal testing
|
||||
> **Release Candidate (RC)**: A Git pre-release intended primarily for internal testing
|
||||
>
|
||||
> **Release Version**: A GitHub release intended for end users
|
||||
> **Release Version**: A Git release intended for end users
|
||||
|
||||
Looking at the flow above, a common release lifecycle could be:
|
||||
|
||||
@@ -24,7 +24,7 @@ Looking at the flow above, a common release lifecycle could be:
|
||||
- `GRM`
|
||||
1. Creates a release branch `rc/<version>`
|
||||
1. Creates Release Candidate tag `rc-<version>`
|
||||
1. Creates a GitHub prerelease with Release Candidate tag
|
||||
1. Creates a Git prerelease with Release Candidate tag
|
||||
- Your CI
|
||||
1. Detects the new tag by matching the git reference `refs/tags/rc-.*`
|
||||
1. Builds and deploys to staging environment for testing
|
||||
@@ -32,14 +32,14 @@ Looking at the flow above, a common release lifecycle could be:
|
||||
- `GRM`
|
||||
1. The selected commit is cherry-picked to the release branch
|
||||
1. The release tag is bumped
|
||||
1. Updates GitHub release's tag and description with the patch's details
|
||||
1. Updates Git release's tag and description with the patch's details
|
||||
- Your CI
|
||||
1. Detects the new tag by matching the git reference `refs/tags/(rc|version)-.*` (Release Versions are patchable as well)
|
||||
1. Builds and deploys to staging (or production if Release Version) for testing
|
||||
- User presses **Promote Release Candidate to Release Version**
|
||||
- `GRM`
|
||||
1. Creates Release Version tag `version-<version>`
|
||||
1. Promotes the GitHub release by removing the prerelease flag
|
||||
1. Promotes the Git release by removing the prerelease flag
|
||||
- Your CI
|
||||
1. Detects the new tag by matching the git reference `refs/tags/version-.*`
|
||||
1. Builds and deploys to production for testing
|
||||
@@ -48,7 +48,7 @@ Looking at the flow above, a common release lifecycle could be:
|
||||
|
||||
### Importing
|
||||
|
||||
The plugin exports a single full-page extension `GitHubReleaseManagerPage`, which one can add to an app like a usual top-level tool on a dedicated route.
|
||||
The plugin exports a single full-page extension `GitReleaseManagerPage`, which one can add to an app like a usual top-level tool on a dedicated route.
|
||||
|
||||
### Configuration
|
||||
|
||||
|
||||
@@ -18,14 +18,11 @@ import React from 'react';
|
||||
import { createDevApp } from '@backstage/dev-utils';
|
||||
import { Box, Typography } from '@material-ui/core';
|
||||
|
||||
import {
|
||||
gitHubReleaseManagerPlugin,
|
||||
GitHubReleaseManagerPage,
|
||||
} from '../src/plugin';
|
||||
import { gitReleaseManagerPlugin, GitReleaseManagerPage } from '../src/plugin';
|
||||
import { InfoCardPlus } from '../src/components/InfoCardPlus';
|
||||
|
||||
createDevApp()
|
||||
.registerPlugin(gitHubReleaseManagerPlugin)
|
||||
.registerPlugin(gitReleaseManagerPlugin)
|
||||
.addPage({
|
||||
title: 'Dynamic',
|
||||
path: '/dynamic',
|
||||
@@ -36,7 +33,7 @@ createDevApp()
|
||||
<Typography>Configure plugin via select inputs</Typography>
|
||||
</InfoCardPlus>
|
||||
|
||||
<GitHubReleaseManagerPage />
|
||||
<GitReleaseManagerPage />
|
||||
</Box>
|
||||
),
|
||||
})
|
||||
@@ -53,7 +50,7 @@ createDevApp()
|
||||
</Typography>
|
||||
</InfoCardPlus>
|
||||
|
||||
<GitHubReleaseManagerPage
|
||||
<GitReleaseManagerPage
|
||||
project={{
|
||||
owner: 'eengervall-playground',
|
||||
repo: 'RMaaS-semver',
|
||||
@@ -74,7 +71,7 @@ createDevApp()
|
||||
<Typography>Success callbacks can also be added</Typography>
|
||||
</InfoCardPlus>
|
||||
|
||||
<GitHubReleaseManagerPage
|
||||
<GitReleaseManagerPage
|
||||
project={{
|
||||
owner: 'eengervall-playground',
|
||||
repo: 'playground-semver',
|
||||
|
||||
+5
-5
@@ -27,7 +27,7 @@ import {
|
||||
} from './types/types';
|
||||
import { Features } from './features/Features';
|
||||
import { CenteredCircularProgress } from './components/CenteredCircularProgress';
|
||||
import { githubReleaseManagerApiRef } from './api/serviceApiRef';
|
||||
import { gitReleaseManagerApiRef } from './api/serviceApiRef';
|
||||
import { InfoCardPlus } from './components/InfoCardPlus';
|
||||
import { isProjectValid } from './helpers/isProjectValid';
|
||||
import { ProjectContext, Project } from './contexts/ProjectContext';
|
||||
@@ -35,7 +35,7 @@ import { RepoDetailsForm } from './features/RepoDetailsForm/RepoDetailsForm';
|
||||
import { useQueryHandler } from './hooks/useQueryHandler';
|
||||
import { useStyles } from './styles/styles';
|
||||
|
||||
export interface GitHubReleaseManagerProps {
|
||||
interface GitReleaseManagerProps {
|
||||
project?: Omit<Project, 'isProvidedViaProps'>;
|
||||
features?: {
|
||||
info?: Pick<ComponentConfig<void>, 'omit'>;
|
||||
@@ -46,8 +46,8 @@ export interface GitHubReleaseManagerProps {
|
||||
};
|
||||
}
|
||||
|
||||
export function GitHubReleaseManager(props: GitHubReleaseManagerProps) {
|
||||
const pluginApiClient = useApi(githubReleaseManagerApiRef);
|
||||
export function GitReleaseManager(props: GitReleaseManagerProps) {
|
||||
const pluginApiClient = useApi(gitReleaseManagerApiRef);
|
||||
const classes = useStyles();
|
||||
|
||||
const { getParsedQuery } = useQueryHandler();
|
||||
@@ -83,7 +83,7 @@ export function GitHubReleaseManager(props: GitHubReleaseManagerProps) {
|
||||
return (
|
||||
<ProjectContext.Provider value={{ project }}>
|
||||
<div className={classes.root}>
|
||||
<ContentHeader title="GitHub Release Manager" />
|
||||
<ContentHeader title="Git Release Manager" />
|
||||
|
||||
<InfoCardPlus>
|
||||
<RepoDetailsForm username={usernameResponse.value.username} />
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import { ConfigReader, OAuthApi } from '@backstage/core';
|
||||
|
||||
import { PluginApiClient } from './PluginApiClient';
|
||||
import { GitReleaseApiClient } from './PluginApiClient';
|
||||
|
||||
describe('PluginApiClient', () => {
|
||||
it('should return the default plugin api client', () => {
|
||||
@@ -24,10 +24,13 @@ describe('PluginApiClient', () => {
|
||||
const githubAuthApi: OAuthApi = {
|
||||
getAccessToken: jest.fn(),
|
||||
};
|
||||
const pluginApiClient = new PluginApiClient({ configApi, githubAuthApi });
|
||||
const pluginApiClient = new GitReleaseApiClient({
|
||||
configApi,
|
||||
githubAuthApi,
|
||||
});
|
||||
|
||||
expect(pluginApiClient).toMatchInlineSnapshot(`
|
||||
PluginApiClient {
|
||||
GitReleaseApiClient {
|
||||
"baseUrl": "https://api.github.com",
|
||||
"createRc": Object {
|
||||
"createRef": [Function],
|
||||
|
||||
@@ -23,7 +23,7 @@ import { DISABLE_CACHE } from '../constants/constants';
|
||||
import { Project } from '../contexts/ProjectContext';
|
||||
import { SemverTagParts } from '../helpers/tagParts/getSemverTagParts';
|
||||
|
||||
export class PluginApiClient implements IPluginApiClient {
|
||||
export class GitReleaseApiClient implements GitReleaseApi {
|
||||
private readonly githubAuthApi: OAuthApi;
|
||||
private readonly baseUrl: string;
|
||||
readonly host: string;
|
||||
@@ -774,7 +774,7 @@ type CreateTempCommit = (
|
||||
tagParts: SemverTagParts | CalverTagParts;
|
||||
releaseBranchTree: string;
|
||||
selectedPatchCommit: UnboxArray<
|
||||
UnboxReturnedPromise<IPluginApiClient['getRecentCommits']>
|
||||
UnboxReturnedPromise<GitReleaseApi['getRecentCommits']>
|
||||
>;
|
||||
} & OwnerRepo,
|
||||
) => Promise<{
|
||||
@@ -812,7 +812,7 @@ type CreateCherryPickCommit = (
|
||||
args: {
|
||||
bumpedTag: string;
|
||||
selectedPatchCommit: UnboxArray<
|
||||
UnboxReturnedPromise<IPluginApiClient['getRecentCommits']>
|
||||
UnboxReturnedPromise<GitReleaseApi['getRecentCommits']>
|
||||
>;
|
||||
mergeTree: string;
|
||||
releaseBranchSha: string;
|
||||
@@ -827,7 +827,7 @@ type ReplaceTempCommit = (
|
||||
args: {
|
||||
releaseBranchName: string;
|
||||
cherryPickCommit: UnboxReturnedPromise<
|
||||
IPluginApiClient['patch']['createCherryPickCommit']
|
||||
GitReleaseApi['patch']['createCherryPickCommit']
|
||||
>;
|
||||
} & OwnerRepo,
|
||||
) => Promise<{
|
||||
@@ -924,7 +924,7 @@ type GetCommit = (
|
||||
}>;
|
||||
export type GetCommitResult = UnboxReturnedPromise<GetCommit>;
|
||||
|
||||
export interface IPluginApiClient {
|
||||
export interface GitReleaseApi {
|
||||
getHost: GetHost;
|
||||
getRepoPath: GetRepoPath;
|
||||
getOwners: GetOwners;
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { githubReleaseManagerApiRef } from './serviceApiRef';
|
||||
import { gitReleaseManagerApiRef } from './serviceApiRef';
|
||||
|
||||
describe('githubReleaseManagerApiRef', () => {
|
||||
describe('gitReleaseManagerApiRef', () => {
|
||||
it('should work', () => {
|
||||
const result = githubReleaseManagerApiRef;
|
||||
const result = gitReleaseManagerApiRef;
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
ApiRefImpl {
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
import { createApiRef } from '@backstage/core';
|
||||
|
||||
import { IPluginApiClient } from './PluginApiClient';
|
||||
import { GitReleaseApi } from './PluginApiClient';
|
||||
|
||||
export const githubReleaseManagerApiRef = createApiRef<IPluginApiClient>({
|
||||
export const gitReleaseManagerApiRef = createApiRef<GitReleaseApi>({
|
||||
id: 'plugin.git-release-manager.service',
|
||||
description: 'Used by the Git Release Manager plugin to make requests',
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ import DynamicFeedIcon from '@material-ui/icons/DynamicFeed';
|
||||
import GitHubIcon from '@material-ui/icons/GitHub';
|
||||
import LocalOfferIcon from '@material-ui/icons/LocalOffer';
|
||||
|
||||
import { GitHubReleaseManagerError } from '../errors/GitHubReleaseManagerError';
|
||||
import { GitReleaseManagerError } from '../errors/GitReleaseManagerError';
|
||||
import { TEST_IDS } from '../test-helpers/test-ids';
|
||||
|
||||
interface DifferProps {
|
||||
@@ -115,6 +115,6 @@ function Icon({ icon }: IconProps) {
|
||||
);
|
||||
|
||||
default:
|
||||
throw new GitHubReleaseManagerError('Invalid Differ icon');
|
||||
throw new GitReleaseManagerError('Invalid Differ icon');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
import { VERSIONING_STRATEGIES } from '../constants/constants';
|
||||
import { GitHubReleaseManagerError } from '../errors/GitHubReleaseManagerError';
|
||||
import { GitReleaseManagerError } from '../errors/GitReleaseManagerError';
|
||||
|
||||
export interface Project {
|
||||
/**
|
||||
@@ -57,7 +57,7 @@ export const useProjectContext = () => {
|
||||
const { project } = useContext(ProjectContext) ?? {};
|
||||
|
||||
if (!project) {
|
||||
throw new GitHubReleaseManagerError('project not found');
|
||||
throw new GitReleaseManagerError('project not found');
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
import { GitHubReleaseManagerError } from '../errors/GitHubReleaseManagerError';
|
||||
import { GitReleaseManagerError } from '../errors/GitReleaseManagerError';
|
||||
|
||||
export const RefetchContext = createContext<
|
||||
| {
|
||||
@@ -30,7 +30,7 @@ export const useRefetchContext = () => {
|
||||
const refetch = useContext(RefetchContext);
|
||||
|
||||
if (!refetch) {
|
||||
throw new GitHubReleaseManagerError('refetch not found');
|
||||
throw new GitReleaseManagerError('refetch not found');
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
+2
-2
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export class GitHubReleaseManagerError extends Error {
|
||||
export class GitReleaseManagerError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
|
||||
this.name = 'GitHubReleaseManagerError';
|
||||
this.name = 'GitReleaseManagerError';
|
||||
}
|
||||
}
|
||||
+11
-11
@@ -19,15 +19,15 @@ import { render } from '@testing-library/react';
|
||||
|
||||
import {
|
||||
mockCalverProject,
|
||||
mockNextGitHubInfoSemver,
|
||||
mockNextGitInfoSemver,
|
||||
mockReleaseBranch,
|
||||
mockReleaseCandidateCalver,
|
||||
mockReleaseVersionCalver,
|
||||
mockSemverProject,
|
||||
} from '../../test-helpers/test-helpers';
|
||||
import { CreateRc } from './CreateRc';
|
||||
import { CreateReleaseCandidate } from './CreateReleaseCandidate';
|
||||
import { TEST_IDS } from '../../test-helpers/test-ids';
|
||||
import { useCreateRc } from './hooks/useCreateRc';
|
||||
import { useCreateReleaseCandidate } from './hooks/useCreateReleaseCandidate';
|
||||
import { useProjectContext } from '../../contexts/ProjectContext';
|
||||
|
||||
jest.mock('../../contexts/ProjectContext', () => ({
|
||||
@@ -35,23 +35,23 @@ jest.mock('../../contexts/ProjectContext', () => ({
|
||||
project: mockCalverProject,
|
||||
})),
|
||||
}));
|
||||
jest.mock('../../helpers/getRcGitHubInfo', () => ({
|
||||
getRcGitHubInfo: () => mockNextGitHubInfoSemver,
|
||||
jest.mock('../../helpers/getReleaseCandidateGitInfo', () => ({
|
||||
getReleaseCandidateGitInfo: () => mockNextGitInfoSemver,
|
||||
}));
|
||||
jest.mock('./hooks/useCreateRc', () => ({
|
||||
useCreateRc: () =>
|
||||
jest.mock('./hooks/useCreateReleaseCandidate', () => ({
|
||||
useCreateReleaseCandidate: () =>
|
||||
({
|
||||
run: jest.fn(),
|
||||
responseSteps: [],
|
||||
progress: 0,
|
||||
runInvoked: false,
|
||||
} as ReturnType<typeof useCreateRc>),
|
||||
} as ReturnType<typeof useCreateReleaseCandidate>),
|
||||
}));
|
||||
|
||||
describe('CreateRc', () => {
|
||||
describe('CreateReleaseCandidate', () => {
|
||||
it('should display CTA', () => {
|
||||
const { getByTestId } = render(
|
||||
<CreateRc
|
||||
<CreateReleaseCandidate
|
||||
defaultBranch="mockDefaultBranch"
|
||||
latestRelease={mockReleaseCandidateCalver}
|
||||
releaseBranch={mockReleaseBranch}
|
||||
@@ -67,7 +67,7 @@ describe('CreateRc', () => {
|
||||
});
|
||||
|
||||
const { getByTestId } = render(
|
||||
<CreateRc
|
||||
<CreateReleaseCandidate
|
||||
defaultBranch="mockDefaultBranch"
|
||||
latestRelease={mockReleaseVersionCalver}
|
||||
releaseBranch={mockReleaseBranch}
|
||||
+25
-20
@@ -32,16 +32,16 @@ import {
|
||||
} from '../../api/PluginApiClient';
|
||||
import { ComponentConfigCreateRc } from '../../types/types';
|
||||
import { Differ } from '../../components/Differ';
|
||||
import { getRcGitHubInfo } from '../../helpers/getRcGitHubInfo';
|
||||
import { getReleaseCandidateGitInfo } from '../../helpers/getReleaseCandidateGitInfo';
|
||||
import { InfoCardPlus } from '../../components/InfoCardPlus';
|
||||
import { ResponseStepDialog } from '../../components/ResponseStepDialog/ResponseStepDialog';
|
||||
import { SEMVER_PARTS } from '../../constants/constants';
|
||||
import { TEST_IDS } from '../../test-helpers/test-ids';
|
||||
import { useCreateRc } from './hooks/useCreateRc';
|
||||
import { useCreateReleaseCandidate } from './hooks/useCreateReleaseCandidate';
|
||||
import { useProjectContext } from '../../contexts/ProjectContext';
|
||||
import { useStyles } from '../../styles/styles';
|
||||
|
||||
interface CreateRcProps {
|
||||
interface CreateReleaseCandidateProps {
|
||||
defaultBranch: GetRepositoryResult['defaultBranch'];
|
||||
latestRelease: GetLatestReleaseResult;
|
||||
releaseBranch: GetBranchResult | null;
|
||||
@@ -60,32 +60,37 @@ const InfoCardPlusWrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const CreateRc = ({
|
||||
export const CreateReleaseCandidate = ({
|
||||
defaultBranch,
|
||||
latestRelease,
|
||||
releaseBranch,
|
||||
successCb,
|
||||
}: CreateRcProps) => {
|
||||
}: CreateReleaseCandidateProps) => {
|
||||
const { project } = useProjectContext();
|
||||
const classes = useStyles();
|
||||
|
||||
const [semverBumpLevel, setSemverBumpLevel] = useState<'major' | 'minor'>(
|
||||
SEMVER_PARTS.minor,
|
||||
);
|
||||
const [nextGitHubInfo, setNextGitHubInfo] = useState(
|
||||
getRcGitHubInfo({ latestRelease, project, semverBumpLevel }),
|
||||
const [releaseCandidateGitInfo, setReleaseCandidateGitInfo] = useState(
|
||||
getReleaseCandidateGitInfo({ latestRelease, project, semverBumpLevel }),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setNextGitHubInfo(
|
||||
getRcGitHubInfo({ latestRelease, project, semverBumpLevel }),
|
||||
setReleaseCandidateGitInfo(
|
||||
getReleaseCandidateGitInfo({ latestRelease, project, semverBumpLevel }),
|
||||
);
|
||||
}, [semverBumpLevel, setNextGitHubInfo, latestRelease, project]);
|
||||
}, [semverBumpLevel, setReleaseCandidateGitInfo, latestRelease, project]);
|
||||
|
||||
const { progress, responseSteps, run, runInvoked } = useCreateRc({
|
||||
const {
|
||||
progress,
|
||||
responseSteps,
|
||||
run,
|
||||
runInvoked,
|
||||
} = useCreateReleaseCandidate({
|
||||
defaultBranch,
|
||||
latestRelease,
|
||||
nextGitHubInfo,
|
||||
releaseCandidateGitInfo,
|
||||
project,
|
||||
successCb,
|
||||
});
|
||||
@@ -99,15 +104,15 @@ export const CreateRc = ({
|
||||
);
|
||||
}
|
||||
|
||||
if (nextGitHubInfo.error !== undefined) {
|
||||
if (releaseCandidateGitInfo.error !== undefined) {
|
||||
return (
|
||||
<InfoCardPlusWrapper>
|
||||
<Alert severity="error">
|
||||
{nextGitHubInfo.error.title && (
|
||||
<AlertTitle>{nextGitHubInfo.error.title}</AlertTitle>
|
||||
{releaseCandidateGitInfo.error.title && (
|
||||
<AlertTitle>{releaseCandidateGitInfo.error.title}</AlertTitle>
|
||||
)}
|
||||
|
||||
{nextGitHubInfo.error.subtitle}
|
||||
{releaseCandidateGitInfo.error.subtitle}
|
||||
</Alert>
|
||||
</InfoCardPlusWrapper>
|
||||
);
|
||||
@@ -115,7 +120,7 @@ export const CreateRc = ({
|
||||
|
||||
const tagAlreadyExists =
|
||||
latestRelease !== null &&
|
||||
latestRelease.tagName === nextGitHubInfo.rcReleaseTag;
|
||||
latestRelease.tagName === releaseCandidateGitInfo.rcReleaseTag;
|
||||
const conflictingPreRelease =
|
||||
latestRelease !== null && latestRelease.prerelease;
|
||||
|
||||
@@ -159,7 +164,7 @@ export const CreateRc = ({
|
||||
{tagAlreadyExists && (
|
||||
<Alert className={classes.paragraph} severity="warning">
|
||||
There's already a tag named{' '}
|
||||
<strong>{nextGitHubInfo.rcReleaseTag}</strong>
|
||||
<strong>{releaseCandidateGitInfo.rcReleaseTag}</strong>
|
||||
</Alert>
|
||||
)}
|
||||
</>
|
||||
@@ -169,7 +174,7 @@ export const CreateRc = ({
|
||||
<Differ
|
||||
icon="branch"
|
||||
current={releaseBranch?.name}
|
||||
next={nextGitHubInfo.rcBranch}
|
||||
next={releaseCandidateGitInfo.rcBranch}
|
||||
/>
|
||||
</Typography>
|
||||
|
||||
@@ -177,7 +182,7 @@ export const CreateRc = ({
|
||||
<Differ
|
||||
icon="tag"
|
||||
current={latestRelease?.tagName}
|
||||
next={nextGitHubInfo.rcReleaseTag}
|
||||
next={releaseCandidateGitInfo.rcReleaseTag}
|
||||
/>
|
||||
</Typography>
|
||||
</div>
|
||||
+7
-7
@@ -21,25 +21,25 @@ import {
|
||||
mockApiClient,
|
||||
mockCalverProject,
|
||||
mockDefaultBranch,
|
||||
mockNextGitHubInfoCalver,
|
||||
mockNextGitInfoCalver,
|
||||
mockReleaseVersionCalver,
|
||||
} from '../../../test-helpers/test-helpers';
|
||||
import { useCreateRc } from './useCreateRc';
|
||||
import { useCreateReleaseCandidate } from './useCreateReleaseCandidate';
|
||||
|
||||
jest.mock('@backstage/core', () => ({
|
||||
useApi: () => mockApiClient,
|
||||
createApiRef: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('useCreateRc', () => {
|
||||
describe('useCreateReleaseCandidate', () => {
|
||||
beforeEach(jest.clearAllMocks);
|
||||
|
||||
it('should return the expected responseSteps and progress', async () => {
|
||||
const { result } = renderHook(() =>
|
||||
useCreateRc({
|
||||
useCreateReleaseCandidate({
|
||||
defaultBranch: mockDefaultBranch,
|
||||
latestRelease: mockReleaseVersionCalver,
|
||||
nextGitHubInfo: mockNextGitHubInfoCalver,
|
||||
releaseCandidateGitInfo: mockNextGitInfoCalver,
|
||||
project: mockCalverProject,
|
||||
}),
|
||||
);
|
||||
@@ -54,10 +54,10 @@ describe('useCreateRc', () => {
|
||||
|
||||
it('should return the expected responseSteps and progress (with successCb)', async () => {
|
||||
const { result } = renderHook(() =>
|
||||
useCreateRc({
|
||||
useCreateReleaseCandidate({
|
||||
defaultBranch: mockDefaultBranch,
|
||||
latestRelease: mockReleaseVersionCalver,
|
||||
nextGitHubInfo: mockNextGitHubInfoCalver,
|
||||
releaseCandidateGitInfo: mockNextGitInfoCalver,
|
||||
project: mockCalverProject,
|
||||
successCb: jest.fn(),
|
||||
}),
|
||||
+22
-22
@@ -23,35 +23,35 @@ import {
|
||||
GetRepositoryResult,
|
||||
} from '../../../api/PluginApiClient';
|
||||
import { CardHook, ComponentConfigCreateRc } from '../../../types/types';
|
||||
import { getRcGitHubInfo } from '../../../helpers/getRcGitHubInfo';
|
||||
import { githubReleaseManagerApiRef } from '../../../api/serviceApiRef';
|
||||
import { GitHubReleaseManagerError } from '../../../errors/GitHubReleaseManagerError';
|
||||
import { getReleaseCandidateGitInfo } from '../../../helpers/getReleaseCandidateGitInfo';
|
||||
import { gitReleaseManagerApiRef } from '../../../api/serviceApiRef';
|
||||
import { GitReleaseManagerError } from '../../../errors/GitReleaseManagerError';
|
||||
import { Project } from '../../../contexts/ProjectContext';
|
||||
import { useResponseSteps } from '../../../hooks/useResponseSteps';
|
||||
|
||||
interface CreateRC {
|
||||
interface UseCreateReleaseCandidate {
|
||||
defaultBranch: GetRepositoryResult['defaultBranch'];
|
||||
latestRelease: GetLatestReleaseResult;
|
||||
nextGitHubInfo: ReturnType<typeof getRcGitHubInfo>;
|
||||
releaseCandidateGitInfo: ReturnType<typeof getReleaseCandidateGitInfo>;
|
||||
project: Project;
|
||||
successCb?: ComponentConfigCreateRc['successCb'];
|
||||
}
|
||||
|
||||
export function useCreateRc({
|
||||
export function useCreateReleaseCandidate({
|
||||
defaultBranch,
|
||||
latestRelease,
|
||||
nextGitHubInfo,
|
||||
releaseCandidateGitInfo,
|
||||
project,
|
||||
successCb,
|
||||
}: CreateRC): CardHook<void> {
|
||||
const pluginApiClient = useApi(githubReleaseManagerApiRef);
|
||||
}: UseCreateReleaseCandidate): CardHook<void> {
|
||||
const pluginApiClient = useApi(gitReleaseManagerApiRef);
|
||||
|
||||
if (nextGitHubInfo.error) {
|
||||
throw new GitHubReleaseManagerError(
|
||||
if (releaseCandidateGitInfo.error) {
|
||||
throw new GitReleaseManagerError(
|
||||
`Unexpected error: ${
|
||||
nextGitHubInfo.error.title
|
||||
? `${nextGitHubInfo.error.title} (${nextGitHubInfo.error.subtitle})`
|
||||
: nextGitHubInfo.error.subtitle
|
||||
releaseCandidateGitInfo.error.title
|
||||
? `${releaseCandidateGitInfo.error.title} (${releaseCandidateGitInfo.error.subtitle})`
|
||||
: releaseCandidateGitInfo.error.subtitle
|
||||
}`,
|
||||
);
|
||||
}
|
||||
@@ -98,12 +98,12 @@ export function useCreateRc({
|
||||
owner: project.owner,
|
||||
repo: project.repo,
|
||||
mostRecentSha: latestCommitRes.value.latestCommit.sha,
|
||||
targetBranch: nextGitHubInfo.rcBranch,
|
||||
targetBranch: releaseCandidateGitInfo.rcBranch,
|
||||
})
|
||||
.catch(error => {
|
||||
if (error?.body?.message === 'Reference already exists') {
|
||||
throw new GitHubReleaseManagerError(
|
||||
`Branch "${nextGitHubInfo.rcBranch}" already exists: .../tree/${nextGitHubInfo.rcBranch}`,
|
||||
throw new GitReleaseManagerError(
|
||||
`Branch "${releaseCandidateGitInfo.rcBranch}" already exists: .../tree/${releaseCandidateGitInfo.rcBranch}`,
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
@@ -130,7 +130,7 @@ export function useCreateRc({
|
||||
const previousReleaseBranch = latestRelease
|
||||
? latestRelease.targetCommitish
|
||||
: defaultBranch;
|
||||
const nextReleaseBranch = nextGitHubInfo.rcBranch;
|
||||
const nextReleaseBranch = releaseCandidateGitInfo.rcBranch;
|
||||
const comparison = await pluginApiClient.createRc
|
||||
.getComparison({
|
||||
owner: project.owner,
|
||||
@@ -173,16 +173,16 @@ export function useCreateRc({
|
||||
.createRelease({
|
||||
owner: project.owner,
|
||||
repo: project.repo,
|
||||
rcReleaseTag: nextGitHubInfo.rcReleaseTag,
|
||||
releaseName: nextGitHubInfo.releaseName,
|
||||
rcBranch: nextGitHubInfo.rcBranch,
|
||||
rcReleaseTag: releaseCandidateGitInfo.rcReleaseTag,
|
||||
releaseName: releaseCandidateGitInfo.releaseName,
|
||||
rcBranch: releaseCandidateGitInfo.rcBranch,
|
||||
releaseBody: getComparisonRes.value.releaseBody,
|
||||
})
|
||||
.catch(asyncCatcher);
|
||||
|
||||
addStepToResponseSteps({
|
||||
message: `Created Release Candidate "${createReleaseResult.name}"`,
|
||||
secondaryMessage: `with tag "${nextGitHubInfo.rcReleaseTag}"`,
|
||||
secondaryMessage: `with tag "${releaseCandidateGitInfo.rcReleaseTag}"`,
|
||||
link: createReleaseResult.htmlUrl,
|
||||
});
|
||||
|
||||
@@ -66,7 +66,7 @@ describe('Features', () => {
|
||||
class="MuiTypography-root MuiTypography-body1"
|
||||
>
|
||||
<strong>
|
||||
GitHub
|
||||
Git
|
||||
</strong>
|
||||
: The source control system where releases reside in a practical sense. Read more about
|
||||
|
||||
@@ -75,9 +75,9 @@ describe('Features', () => {
|
||||
href="https://docs.github.com/en/github/administering-a-repository/managing-releases-in-a-repository"
|
||||
target="_blank"
|
||||
>
|
||||
GitHub releases
|
||||
Git releases
|
||||
</a>
|
||||
. (Note that this plugin works just as well with GitHub Enterprise.)
|
||||
.
|
||||
</p>
|
||||
<p
|
||||
class="MuiTypography-root MuiTypography-body1"
|
||||
@@ -85,12 +85,11 @@ describe('Features', () => {
|
||||
<strong>
|
||||
Release Candidate
|
||||
</strong>
|
||||
: A GitHub
|
||||
: A Git
|
||||
<i>
|
||||
prerelease
|
||||
</i>
|
||||
|
||||
intended primarily for internal testing
|
||||
intended primarily for internal testing
|
||||
</p>
|
||||
<p
|
||||
class="MuiTypography-root MuiTypography-body1"
|
||||
@@ -98,7 +97,7 @@ describe('Features', () => {
|
||||
<strong>
|
||||
Release Version
|
||||
</strong>
|
||||
: A GitHub release intended for end users
|
||||
: A Git release intended for end users
|
||||
</p>
|
||||
</div>
|
||||
`);
|
||||
|
||||
@@ -14,19 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, ComponentProps } from 'react';
|
||||
import { Alert, AlertTitle } from '@material-ui/lab';
|
||||
import { ErrorBoundary, useApi } from '@backstage/core';
|
||||
|
||||
import { CenteredCircularProgress } from '../components/CenteredCircularProgress';
|
||||
import { CreateRc } from './CreateRc/CreateRc';
|
||||
import { githubReleaseManagerApiRef } from '../api/serviceApiRef';
|
||||
import { GitHubReleaseManagerProps } from '../GitHubReleaseManager';
|
||||
import { CreateReleaseCandidate } from './CreateReleaseCandidate/CreateReleaseCandidate';
|
||||
import { GitReleaseManager } from '../GitReleaseManager';
|
||||
import { gitReleaseManagerApiRef } from '../api/serviceApiRef';
|
||||
import { Info } from './Info/Info';
|
||||
import { Patch } from './Patch/Patch';
|
||||
import { PromoteRc } from './PromoteRc/PromoteRc';
|
||||
import { RefetchContext } from '../contexts/RefetchContext';
|
||||
import { useGetGitHubBatchInfo } from '../hooks/useGetGitHubBatchInfo';
|
||||
import { useGetGitBatchInfo } from '../hooks/useGetGitBatchInfo';
|
||||
import { useProjectContext } from '../contexts/ProjectContext';
|
||||
import { useVersioningStrategyMatchesRepoTags } from '../hooks/useVersioningStrategyMatchesRepoTags';
|
||||
import { validateTagName } from '../helpers/tagParts/validateTagName';
|
||||
@@ -34,43 +34,43 @@ import { validateTagName } from '../helpers/tagParts/validateTagName';
|
||||
export function Features({
|
||||
features,
|
||||
}: {
|
||||
features: GitHubReleaseManagerProps['features'];
|
||||
features: ComponentProps<typeof GitReleaseManager>['features'];
|
||||
}) {
|
||||
const pluginApiClient = useApi(githubReleaseManagerApiRef);
|
||||
const pluginApiClient = useApi(gitReleaseManagerApiRef);
|
||||
const { project } = useProjectContext();
|
||||
const [refetchTrigger, setRefetchTrigger] = useState(0);
|
||||
const { gitHubBatchInfo } = useGetGitHubBatchInfo({
|
||||
const { gitBatchInfo } = useGetGitBatchInfo({
|
||||
pluginApiClient,
|
||||
project,
|
||||
refetchTrigger,
|
||||
});
|
||||
|
||||
const { versioningStrategyMatches } = useVersioningStrategyMatchesRepoTags({
|
||||
latestReleaseTagName: gitHubBatchInfo.value?.latestRelease?.tagName,
|
||||
latestReleaseTagName: gitBatchInfo.value?.latestRelease?.tagName,
|
||||
project,
|
||||
repositoryName: gitHubBatchInfo.value?.repository.name,
|
||||
repositoryName: gitBatchInfo.value?.repository.name,
|
||||
});
|
||||
|
||||
if (gitHubBatchInfo.error) {
|
||||
if (gitBatchInfo.error) {
|
||||
return (
|
||||
<Alert severity="error">
|
||||
Error occured while fetching information for "{project.owner}/
|
||||
{project.repo}" ({gitHubBatchInfo.error.message})
|
||||
{project.repo}" ({gitBatchInfo.error.message})
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
if (gitHubBatchInfo.loading) {
|
||||
if (gitBatchInfo.loading) {
|
||||
return <CenteredCircularProgress />;
|
||||
}
|
||||
|
||||
if (gitHubBatchInfo.value === undefined) {
|
||||
if (gitBatchInfo.value === undefined) {
|
||||
return (
|
||||
<Alert severity="error">Failed to fetch latest GitHub release</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
if (!gitHubBatchInfo.value.repository.pushPermissions) {
|
||||
if (!gitBatchInfo.value.repository.pushPermissions) {
|
||||
return (
|
||||
<Alert severity="error">
|
||||
You lack push permissions for repository "{project.owner}/{project.repo}
|
||||
@@ -81,7 +81,7 @@ export function Features({
|
||||
|
||||
const { tagNameError } = validateTagName({
|
||||
project,
|
||||
tagName: gitHubBatchInfo.value.latestRelease?.tagName,
|
||||
tagName: gitBatchInfo.value.latestRelease?.tagName,
|
||||
});
|
||||
if (tagNameError) {
|
||||
return (
|
||||
@@ -95,20 +95,20 @@ export function Features({
|
||||
return (
|
||||
<RefetchContext.Provider value={{ refetchTrigger, setRefetchTrigger }}>
|
||||
<ErrorBoundary>
|
||||
{gitHubBatchInfo.value.latestRelease && !versioningStrategyMatches && (
|
||||
{gitBatchInfo.value.latestRelease && !versioningStrategyMatches && (
|
||||
<Alert severity="warning" style={{ marginBottom: 20 }}>
|
||||
Versioning mismatch, expected {project.versioningStrategy} version,
|
||||
got "{gitHubBatchInfo.value.latestRelease.tagName}"
|
||||
got "{gitBatchInfo.value.latestRelease.tagName}"
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{!gitHubBatchInfo.value.latestRelease && (
|
||||
{!gitBatchInfo.value.latestRelease && (
|
||||
<Alert severity="info" style={{ marginBottom: 20 }}>
|
||||
This repository doesn't have any releases yet
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{!gitHubBatchInfo.value.releaseBranch && (
|
||||
{!gitBatchInfo.value.releaseBranch && (
|
||||
<Alert severity="info" style={{ marginBottom: 20 }}>
|
||||
This repository doesn't have any release branches
|
||||
</Alert>
|
||||
@@ -116,32 +116,32 @@ export function Features({
|
||||
|
||||
{!features?.info?.omit && (
|
||||
<Info
|
||||
latestRelease={gitHubBatchInfo.value.latestRelease}
|
||||
releaseBranch={gitHubBatchInfo.value.releaseBranch}
|
||||
latestRelease={gitBatchInfo.value.latestRelease}
|
||||
releaseBranch={gitBatchInfo.value.releaseBranch}
|
||||
statsEnabled={features?.stats?.omit !== true}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!features?.createRc?.omit && (
|
||||
<CreateRc
|
||||
latestRelease={gitHubBatchInfo.value.latestRelease}
|
||||
releaseBranch={gitHubBatchInfo.value.releaseBranch}
|
||||
defaultBranch={gitHubBatchInfo.value.repository.defaultBranch}
|
||||
<CreateReleaseCandidate
|
||||
latestRelease={gitBatchInfo.value.latestRelease}
|
||||
releaseBranch={gitBatchInfo.value.releaseBranch}
|
||||
defaultBranch={gitBatchInfo.value.repository.defaultBranch}
|
||||
successCb={features?.createRc?.successCb}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!features?.promoteRc?.omit && (
|
||||
<PromoteRc
|
||||
latestRelease={gitHubBatchInfo.value.latestRelease}
|
||||
latestRelease={gitBatchInfo.value.latestRelease}
|
||||
successCb={features?.promoteRc?.successCb}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!features?.patch?.omit && (
|
||||
<Patch
|
||||
latestRelease={gitHubBatchInfo.value.latestRelease}
|
||||
releaseBranch={gitHubBatchInfo.value.releaseBranch}
|
||||
latestRelease={gitBatchInfo.value.latestRelease}
|
||||
releaseBranch={gitBatchInfo.value.releaseBranch}
|
||||
successCb={features?.patch?.successCb}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -51,25 +51,24 @@ export const Info = ({
|
||||
<Typography variant="h6">Terminology</Typography>
|
||||
|
||||
<Typography>
|
||||
<strong>GitHub</strong>: The source control system where releases
|
||||
reside in a practical sense. Read more about{' '}
|
||||
<strong>Git</strong>: The source control system where releases reside
|
||||
in a practical sense. Read more about{' '}
|
||||
<Link
|
||||
href="https://docs.github.com/en/github/administering-a-repository/managing-releases-in-a-repository"
|
||||
target="_blank"
|
||||
>
|
||||
GitHub releases
|
||||
Git releases
|
||||
</Link>
|
||||
. (Note that this plugin works just as well with GitHub Enterprise.)
|
||||
.
|
||||
</Typography>
|
||||
|
||||
<Typography>
|
||||
<strong>Release Candidate</strong>: A GitHub <i>prerelease</i>{' '}
|
||||
intended primarily for internal testing
|
||||
<strong>Release Candidate</strong>: A Git <i>prerelease</i> intended
|
||||
primarily for internal testing
|
||||
</Typography>
|
||||
|
||||
<Typography>
|
||||
<strong>Release Version</strong>: A GitHub release intended for end
|
||||
users
|
||||
<strong>Release Version</strong>: A Git release intended for end users
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
@@ -77,7 +76,7 @@ export const Info = ({
|
||||
<Typography variant="h6">Flow</Typography>
|
||||
|
||||
<Typography className={classes.paragraph}>
|
||||
GitHub Release Manager is built with a specific flow in mind. For
|
||||
Git Release Manager is built with a specific flow in mind. For
|
||||
example, it assumes your project is configured to react to tags
|
||||
prefixed with <b>rc</b> or <b>version</b>.
|
||||
</Typography>
|
||||
|
||||
@@ -42,8 +42,8 @@ import { CalverTagParts } from '../../helpers/tagParts/getCalverTagParts';
|
||||
import { CenteredCircularProgress } from '../../components/CenteredCircularProgress';
|
||||
import { ComponentConfigPatch } from '../../types/types';
|
||||
import { Differ } from '../../components/Differ';
|
||||
import { githubReleaseManagerApiRef } from '../../api/serviceApiRef';
|
||||
import { GitHubReleaseManagerError } from '../../errors/GitHubReleaseManagerError';
|
||||
import { gitReleaseManagerApiRef } from '../../api/serviceApiRef';
|
||||
import { GitReleaseManagerError } from '../../errors/GitReleaseManagerError';
|
||||
import { ResponseStepDialog } from '../../components/ResponseStepDialog/ResponseStepDialog';
|
||||
import { SemverTagParts } from '../../helpers/tagParts/getSemverTagParts';
|
||||
import { TEST_IDS } from '../../test-helpers/test-ids';
|
||||
@@ -66,11 +66,11 @@ export const PatchBody = ({
|
||||
successCb,
|
||||
tagParts,
|
||||
}: PatchBodyProps) => {
|
||||
const pluginApiClient = useApi(githubReleaseManagerApiRef);
|
||||
const pluginApiClient = useApi(gitReleaseManagerApiRef);
|
||||
const { project } = useProjectContext();
|
||||
const [checkedCommitIndex, setCheckedCommitIndex] = useState(-1);
|
||||
|
||||
const githubDataResponse = useAsync(async () => {
|
||||
const gitDataResponse = useAsync(async () => {
|
||||
const [
|
||||
recentCommitsOnDefaultBranch,
|
||||
recentCommitsOnReleaseBranch,
|
||||
@@ -109,15 +109,15 @@ export const PatchBody = ({
|
||||
);
|
||||
}
|
||||
|
||||
if (githubDataResponse.error) {
|
||||
if (gitDataResponse.error) {
|
||||
return (
|
||||
<Alert data-testid={TEST_IDS.patch.error} severity="error">
|
||||
Unexpected error: {githubDataResponse.error.message}
|
||||
Unexpected error: {gitDataResponse.error.message}
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
if (githubDataResponse.loading) {
|
||||
if (gitDataResponse.loading) {
|
||||
return <CenteredCircularProgress data-testid={TEST_IDS.patch.loading} />;
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ export const PatchBody = ({
|
||||
severity="info"
|
||||
>
|
||||
<AlertTitle>
|
||||
The current GitHub release is a <b>Release Version</b>
|
||||
The current Git release is a <b>Release Version</b>
|
||||
</AlertTitle>
|
||||
It's still possible to patch it, but be extra mindful of changes
|
||||
</Alert>
|
||||
@@ -147,16 +147,16 @@ export const PatchBody = ({
|
||||
}
|
||||
|
||||
function CommitList() {
|
||||
if (!githubDataResponse.value?.recentCommitsOnDefaultBranch) {
|
||||
if (!gitDataResponse.value?.recentCommitsOnDefaultBranch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<List>
|
||||
{githubDataResponse.value.recentCommitsOnDefaultBranch.map(
|
||||
{gitDataResponse.value.recentCommitsOnDefaultBranch.map(
|
||||
(commit, index) => {
|
||||
// FIXME: Performance improvement opportunity: Convert to object lookup
|
||||
const commitExistsOnReleaseBranch = !!githubDataResponse.value?.recentCommitsOnReleaseBranch.find(
|
||||
const commitExistsOnReleaseBranch = !!gitDataResponse.value?.recentCommitsOnReleaseBranch.find(
|
||||
releaseBranchCommit =>
|
||||
releaseBranchCommit.sha === commit.sha ||
|
||||
releaseBranchCommit.commit.message.includes(commit.sha), // The selected patch commit's sha is included in the commit message
|
||||
@@ -277,11 +277,11 @@ export const PatchBody = ({
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
const selectedPatchCommit =
|
||||
githubDataResponse.value?.recentCommitsOnDefaultBranch[
|
||||
gitDataResponse.value?.recentCommitsOnDefaultBranch[
|
||||
checkedCommitIndex
|
||||
];
|
||||
if (!selectedPatchCommit) {
|
||||
throw new GitHubReleaseManagerError(
|
||||
throw new GitReleaseManagerError(
|
||||
'Could not find selected patch commit',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
} from '../../../api/PluginApiClient';
|
||||
import { CalverTagParts } from '../../../helpers/tagParts/getCalverTagParts';
|
||||
import { ComponentConfigPatch, CardHook } from '../../../types/types';
|
||||
import { githubReleaseManagerApiRef } from '../../../api/serviceApiRef';
|
||||
import { gitReleaseManagerApiRef } from '../../../api/serviceApiRef';
|
||||
import { Project } from '../../../contexts/ProjectContext';
|
||||
import { SemverTagParts } from '../../../helpers/tagParts/getSemverTagParts';
|
||||
import { useResponseSteps } from '../../../hooks/useResponseSteps';
|
||||
@@ -45,7 +45,7 @@ export function usePatch({
|
||||
tagParts,
|
||||
successCb,
|
||||
}: Patch): CardHook<GetRecentCommitsResultSingle> {
|
||||
const pluginApiClient = useApi(githubReleaseManagerApiRef);
|
||||
const pluginApiClient = useApi(gitReleaseManagerApiRef);
|
||||
const {
|
||||
responseSteps,
|
||||
addStepToResponseSteps,
|
||||
|
||||
@@ -46,9 +46,7 @@ export const PromoteRc = ({ latestRelease, successCb }: PromoteRcProps) => {
|
||||
className={classes.paragraph}
|
||||
severity="warning"
|
||||
>
|
||||
<AlertTitle>
|
||||
Latest GitHub release is not a Release Candidate
|
||||
</AlertTitle>
|
||||
<AlertTitle>Latest Git release is not a Release Candidate</AlertTitle>
|
||||
One can only promote Release Candidates to Release Versions
|
||||
</Alert>
|
||||
);
|
||||
|
||||
@@ -20,7 +20,7 @@ import { useApi } from '@backstage/core';
|
||||
|
||||
import { CardHook, ComponentConfigPromoteRc } from '../../../types/types';
|
||||
import { GetLatestReleaseResult } from '../../../api/PluginApiClient';
|
||||
import { githubReleaseManagerApiRef } from '../../../api/serviceApiRef';
|
||||
import { gitReleaseManagerApiRef } from '../../../api/serviceApiRef';
|
||||
import { useProjectContext } from '../../../contexts/ProjectContext';
|
||||
import { useResponseSteps } from '../../../hooks/useResponseSteps';
|
||||
|
||||
@@ -35,7 +35,7 @@ export function usePromoteRc({
|
||||
releaseVersion,
|
||||
successCb,
|
||||
}: PromoteRc): CardHook<void> {
|
||||
const pluginApiClient = useApi(githubReleaseManagerApiRef);
|
||||
const pluginApiClient = useApi(gitReleaseManagerApiRef);
|
||||
const { project } = useProjectContext();
|
||||
const {
|
||||
responseSteps,
|
||||
|
||||
@@ -27,14 +27,14 @@ import {
|
||||
import { useApi } from '@backstage/core';
|
||||
|
||||
import { CenteredCircularProgress } from '../../components/CenteredCircularProgress';
|
||||
import { githubReleaseManagerApiRef } from '../../api/serviceApiRef';
|
||||
import { gitReleaseManagerApiRef } from '../../api/serviceApiRef';
|
||||
import { TEST_IDS } from '../../test-helpers/test-ids';
|
||||
import { useFormClasses } from './styles';
|
||||
import { useProjectContext } from '../../contexts/ProjectContext';
|
||||
import { useQueryHandler } from '../../hooks/useQueryHandler';
|
||||
|
||||
export function Owner({ username }: { username: string }) {
|
||||
const pluginApiClient = useApi(githubReleaseManagerApiRef);
|
||||
const pluginApiClient = useApi(gitReleaseManagerApiRef);
|
||||
const { project } = useProjectContext();
|
||||
const formClasses = useFormClasses();
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -27,14 +27,14 @@ import {
|
||||
import { useApi } from '@backstage/core';
|
||||
|
||||
import { CenteredCircularProgress } from '../../components/CenteredCircularProgress';
|
||||
import { githubReleaseManagerApiRef } from '../../api/serviceApiRef';
|
||||
import { gitReleaseManagerApiRef } from '../../api/serviceApiRef';
|
||||
import { TEST_IDS } from '../../test-helpers/test-ids';
|
||||
import { useFormClasses } from './styles';
|
||||
import { useProjectContext } from '../../contexts/ProjectContext';
|
||||
import { useQueryHandler } from '../../hooks/useQueryHandler';
|
||||
|
||||
export function Repo() {
|
||||
const pluginApiClient = useApi(githubReleaseManagerApiRef);
|
||||
const pluginApiClient = useApi(gitReleaseManagerApiRef);
|
||||
const { project } = useProjectContext();
|
||||
const navigate = useNavigate();
|
||||
const formClasses = useFormClasses();
|
||||
|
||||
@@ -20,7 +20,7 @@ import { DateTime } from 'luxon';
|
||||
import { useApi } from '@backstage/core';
|
||||
|
||||
import { getReleaseCommitPairs } from '../helpers/getReleaseCommitPairs';
|
||||
import { githubReleaseManagerApiRef } from '../../../../api/serviceApiRef';
|
||||
import { gitReleaseManagerApiRef } from '../../../../api/serviceApiRef';
|
||||
import { useProjectContext } from '../../../../contexts/ProjectContext';
|
||||
import { useReleaseStatsContext } from '../../contexts/ReleaseStatsContext';
|
||||
|
||||
@@ -46,7 +46,7 @@ type ReleaseTime = {
|
||||
};
|
||||
|
||||
export function useGetReleaseTimes() {
|
||||
const pluginApiClient = useApi(githubReleaseManagerApiRef);
|
||||
const pluginApiClient = useApi(gitReleaseManagerApiRef);
|
||||
const { project } = useProjectContext();
|
||||
const { releaseStats } = useReleaseStatsContext();
|
||||
const [averageReleaseTime, setAverageReleaseTime] = useState<ReleaseTime[]>(
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
import { GitHubReleaseManagerError } from '../../../errors/GitHubReleaseManagerError';
|
||||
import { GitReleaseManagerError } from '../../../errors/GitReleaseManagerError';
|
||||
|
||||
export interface ReleaseStats {
|
||||
unmappableTags: string[];
|
||||
@@ -55,7 +55,7 @@ export const useReleaseStatsContext = () => {
|
||||
const { releaseStats } = useContext(ReleaseStatsContext) ?? {};
|
||||
|
||||
if (!releaseStats) {
|
||||
throw new GitHubReleaseManagerError('releaseStats not found');
|
||||
throw new GitReleaseManagerError('releaseStats not found');
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -17,17 +17,17 @@
|
||||
import { useAsync } from 'react-use';
|
||||
import { useApi } from '@backstage/core';
|
||||
|
||||
import { githubReleaseManagerApiRef } from '../../../api/serviceApiRef';
|
||||
import { GitHubReleaseManagerError } from '../../../errors/GitHubReleaseManagerError';
|
||||
import { gitReleaseManagerApiRef } from '../../../api/serviceApiRef';
|
||||
import { GitReleaseManagerError } from '../../../errors/GitReleaseManagerError';
|
||||
import { useProjectContext } from '../../../contexts/ProjectContext';
|
||||
|
||||
export const useGetCommit = ({ ref }: { ref?: string }) => {
|
||||
const pluginApiClient = useApi(githubReleaseManagerApiRef);
|
||||
const pluginApiClient = useApi(gitReleaseManagerApiRef);
|
||||
const { project } = useProjectContext();
|
||||
|
||||
const commit = useAsync(async () => {
|
||||
if (!ref) {
|
||||
throw new GitHubReleaseManagerError('Missing ref to get commit');
|
||||
throw new GitReleaseManagerError('Missing ref to get commit');
|
||||
}
|
||||
|
||||
return pluginApiClient.stats.getCommit({
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
import { useApi } from '@backstage/core';
|
||||
import { useAsync } from 'react-use';
|
||||
|
||||
import { githubReleaseManagerApiRef } from '../../../api/serviceApiRef';
|
||||
import { gitReleaseManagerApiRef } from '../../../api/serviceApiRef';
|
||||
import { useProjectContext } from '../../../contexts/ProjectContext';
|
||||
|
||||
export const useGetStats = () => {
|
||||
const pluginApiClient = useApi(githubReleaseManagerApiRef);
|
||||
const pluginApiClient = useApi(gitReleaseManagerApiRef);
|
||||
const { project } = useProjectContext();
|
||||
|
||||
const stats = useAsync(async () => {
|
||||
|
||||
+5
-5
@@ -22,9 +22,9 @@ import {
|
||||
mockReleaseVersionSemver,
|
||||
mockSemverProject,
|
||||
} from '../test-helpers/test-helpers';
|
||||
import { getRcGitHubInfo } from './getRcGitHubInfo';
|
||||
import { getReleaseCandidateGitInfo } from './getReleaseCandidateGitInfo';
|
||||
|
||||
describe('getRcGitHubInfo', () => {
|
||||
describe('getReleaseCandidateGitInfo', () => {
|
||||
describe('DateTime', () => {
|
||||
it('should format dates as expected', () => {
|
||||
const formattedDate = DateTime.now().toFormat('yyyy.MM.dd');
|
||||
@@ -36,7 +36,7 @@ describe('getRcGitHubInfo', () => {
|
||||
describe('calver', () => {
|
||||
it('should return correct GitHub info', () => {
|
||||
expect(
|
||||
getRcGitHubInfo({
|
||||
getReleaseCandidateGitInfo({
|
||||
project: mockCalverProject,
|
||||
latestRelease: mockReleaseVersionCalver,
|
||||
semverBumpLevel: 'minor',
|
||||
@@ -55,7 +55,7 @@ describe('getRcGitHubInfo', () => {
|
||||
describe('semver', () => {
|
||||
it("should return correct GitHub info when there's previous releases", () => {
|
||||
expect(
|
||||
getRcGitHubInfo({
|
||||
getReleaseCandidateGitInfo({
|
||||
project: mockSemverProject,
|
||||
latestRelease: mockReleaseVersionSemver,
|
||||
semverBumpLevel: 'minor',
|
||||
@@ -71,7 +71,7 @@ describe('getRcGitHubInfo', () => {
|
||||
|
||||
it("should return correct GitHub info when there's no previous release", () => {
|
||||
expect(
|
||||
getRcGitHubInfo({
|
||||
getReleaseCandidateGitInfo({
|
||||
project: mockSemverProject,
|
||||
latestRelease: null,
|
||||
semverBumpLevel: 'minor',
|
||||
+1
-1
@@ -22,7 +22,7 @@ import { getSemverTagParts } from './tagParts/getSemverTagParts';
|
||||
import { Project } from '../contexts/ProjectContext';
|
||||
import { SEMVER_PARTS } from '../constants/constants';
|
||||
|
||||
export const getRcGitHubInfo = ({
|
||||
export const getReleaseCandidateGitInfo = ({
|
||||
project,
|
||||
latestRelease,
|
||||
semverBumpLevel,
|
||||
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { GitHubReleaseManagerError } from '../errors/GitHubReleaseManagerError';
|
||||
import { GitReleaseManagerError } from '../errors/GitReleaseManagerError';
|
||||
|
||||
export function getShortCommitHash(hash: string) {
|
||||
const shortCommitHash = hash.substr(0, 7);
|
||||
|
||||
if (shortCommitHash.length < 7) {
|
||||
throw new GitHubReleaseManagerError(
|
||||
throw new GitReleaseManagerError(
|
||||
'Invalid shortCommitHash: less than 7 characters',
|
||||
);
|
||||
}
|
||||
|
||||
+8
-8
@@ -18,12 +18,12 @@ import { renderHook, act } from '@testing-library/react-hooks';
|
||||
import { waitFor } from '@testing-library/react';
|
||||
|
||||
import { mockApiClient, mockSemverProject } from '../test-helpers/test-helpers';
|
||||
import { useGetGitHubBatchInfo } from './useGetGitHubBatchInfo';
|
||||
import { useGetGitBatchInfo } from './useGetGitBatchInfo';
|
||||
|
||||
describe('useGetGitHubBatchInfo', () => {
|
||||
describe('useGetHubBatchInfo', () => {
|
||||
it('should handle repositories with releases', async () => {
|
||||
const { result } = renderHook(() =>
|
||||
useGetGitHubBatchInfo({
|
||||
useGetGitBatchInfo({
|
||||
pluginApiClient: mockApiClient,
|
||||
project: mockSemverProject,
|
||||
refetchTrigger: 1337,
|
||||
@@ -31,10 +31,10 @@ describe('useGetGitHubBatchInfo', () => {
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await waitFor(() => result.current.gitHubBatchInfo !== undefined);
|
||||
await waitFor(() => result.current.gitBatchInfo !== undefined);
|
||||
});
|
||||
|
||||
expect(result.current.gitHubBatchInfo).toMatchInlineSnapshot(`
|
||||
expect(result.current.gitBatchInfo).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"loading": false,
|
||||
"value": Object {
|
||||
@@ -73,7 +73,7 @@ describe('useGetGitHubBatchInfo', () => {
|
||||
(mockApiClient.getLatestRelease as jest.Mock).mockResolvedValueOnce(null);
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useGetGitHubBatchInfo({
|
||||
useGetGitBatchInfo({
|
||||
pluginApiClient: mockApiClient,
|
||||
project: mockSemverProject,
|
||||
refetchTrigger: 1337,
|
||||
@@ -81,10 +81,10 @@ describe('useGetGitHubBatchInfo', () => {
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await waitFor(() => result.current.gitHubBatchInfo !== undefined);
|
||||
await waitFor(() => result.current.gitBatchInfo !== undefined);
|
||||
});
|
||||
|
||||
expect(result.current.gitHubBatchInfo).toMatchInlineSnapshot(`
|
||||
expect(result.current.gitBatchInfo).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"loading": false,
|
||||
"value": Object {
|
||||
+7
-7
@@ -16,21 +16,21 @@
|
||||
|
||||
import { useAsync } from 'react-use';
|
||||
|
||||
import { IPluginApiClient } from '../api/PluginApiClient';
|
||||
import { GitReleaseApi } from '../api/PluginApiClient';
|
||||
import { Project } from '../contexts/ProjectContext';
|
||||
|
||||
interface GetGitHubBatchInfo {
|
||||
interface GetGitBatchInfo {
|
||||
project: Project;
|
||||
pluginApiClient: IPluginApiClient;
|
||||
pluginApiClient: GitReleaseApi;
|
||||
refetchTrigger: number;
|
||||
}
|
||||
|
||||
export const useGetGitHubBatchInfo = ({
|
||||
export const useGetGitBatchInfo = ({
|
||||
project,
|
||||
pluginApiClient,
|
||||
refetchTrigger,
|
||||
}: GetGitHubBatchInfo) => {
|
||||
const gitHubBatchInfo = useAsync(async () => {
|
||||
}: GetGitBatchInfo) => {
|
||||
const gitBatchInfo = useAsync(async () => {
|
||||
const [repository, latestRelease] = await Promise.all([
|
||||
pluginApiClient.getRepository({ ...project }),
|
||||
pluginApiClient.getLatestRelease({ ...project }),
|
||||
@@ -57,6 +57,6 @@ export const useGetGitHubBatchInfo = ({
|
||||
}, [project, refetchTrigger]);
|
||||
|
||||
return {
|
||||
gitHubBatchInfo,
|
||||
gitBatchInfo,
|
||||
};
|
||||
};
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
export {
|
||||
gitHubReleaseManagerPlugin,
|
||||
GitHubReleaseManagerPage,
|
||||
githubReleaseManagerApiRef,
|
||||
gitReleaseManagerPlugin,
|
||||
GitReleaseManagerPage,
|
||||
gitReleaseManagerApiRef,
|
||||
} from './plugin';
|
||||
|
||||
@@ -20,9 +20,9 @@ describe('git-release-manager', () => {
|
||||
it('should export plugin & friends', () => {
|
||||
expect(Object.keys(plugin)).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"githubReleaseManagerApiRef",
|
||||
"gitHubReleaseManagerPlugin",
|
||||
"GitHubReleaseManagerPage",
|
||||
"gitReleaseManagerApiRef",
|
||||
"gitReleaseManagerPlugin",
|
||||
"GitReleaseManagerPage",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
@@ -22,26 +22,26 @@ import {
|
||||
createRoutableExtension,
|
||||
} from '@backstage/core';
|
||||
|
||||
import { githubReleaseManagerApiRef } from './api/serviceApiRef';
|
||||
import { PluginApiClient } from './api/PluginApiClient';
|
||||
import { gitReleaseManagerApiRef } from './api/serviceApiRef';
|
||||
import { GitReleaseApiClient } from './api/PluginApiClient';
|
||||
import { rootRouteRef } from './routes';
|
||||
|
||||
export { githubReleaseManagerApiRef };
|
||||
export { gitReleaseManagerApiRef };
|
||||
|
||||
export const gitHubReleaseManagerPlugin = createPlugin({
|
||||
export const gitReleaseManagerPlugin = createPlugin({
|
||||
id: 'git-release-manager',
|
||||
routes: {
|
||||
root: rootRouteRef,
|
||||
},
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: githubReleaseManagerApiRef,
|
||||
api: gitReleaseManagerApiRef,
|
||||
deps: {
|
||||
configApi: configApiRef,
|
||||
githubAuthApi: githubAuthApiRef,
|
||||
},
|
||||
factory: ({ configApi, githubAuthApi }) => {
|
||||
return new PluginApiClient({
|
||||
return new GitReleaseApiClient({
|
||||
configApi,
|
||||
githubAuthApi,
|
||||
});
|
||||
@@ -50,10 +50,10 @@ export const gitHubReleaseManagerPlugin = createPlugin({
|
||||
],
|
||||
});
|
||||
|
||||
export const GitHubReleaseManagerPage = gitHubReleaseManagerPlugin.provide(
|
||||
export const GitReleaseManagerPage = gitReleaseManagerPlugin.provide(
|
||||
createRoutableExtension({
|
||||
component: () =>
|
||||
import('./GitHubReleaseManager').then(m => m.GitHubReleaseManager),
|
||||
import('./GitReleaseManager').then(m => m.GitReleaseManager),
|
||||
mountPoint: rootRouteRef,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -18,11 +18,11 @@ import {
|
||||
GetBranchResult,
|
||||
GetLatestReleaseResult,
|
||||
GetRecentCommitsResultSingle,
|
||||
IPluginApiClient,
|
||||
GitReleaseApi,
|
||||
} from '../api/PluginApiClient';
|
||||
import { CalverTagParts } from '../helpers/tagParts/getCalverTagParts';
|
||||
import { Project } from '../contexts/ProjectContext';
|
||||
import { getRcGitHubInfo } from '../helpers/getRcGitHubInfo';
|
||||
import { getReleaseCandidateGitInfo } from '../helpers/getReleaseCandidateGitInfo';
|
||||
|
||||
const mockOwner = 'mock_owner';
|
||||
const mockRepo = 'mock_repo';
|
||||
@@ -59,13 +59,17 @@ export const mockSearchSemver = `?versioningStrategy=${mockSemverProject.version
|
||||
|
||||
export const mockDefaultBranch = 'mock_defaultBranch';
|
||||
|
||||
export const mockNextGitHubInfoSemver: ReturnType<typeof getRcGitHubInfo> = {
|
||||
export const mockNextGitInfoSemver: ReturnType<
|
||||
typeof getReleaseCandidateGitInfo
|
||||
> = {
|
||||
rcBranch: MOCK_RELEASE_BRANCH_NAME_SEMVER,
|
||||
rcReleaseTag: MOCK_RELEASE_CANDIDATE_TAG_NAME_SEMVER,
|
||||
releaseName: MOCK_RELEASE_NAME_SEMVER,
|
||||
};
|
||||
|
||||
export const mockNextGitHubInfoCalver: ReturnType<typeof getRcGitHubInfo> = {
|
||||
export const mockNextGitInfoCalver: ReturnType<
|
||||
typeof getReleaseCandidateGitInfo
|
||||
> = {
|
||||
rcBranch: MOCK_RELEASE_BRANCH_NAME_CALVER,
|
||||
rcReleaseTag: MOCK_RELEASE_CANDIDATE_TAG_NAME_CALVER,
|
||||
releaseName: MOCK_RELEASE_NAME_CALVER,
|
||||
@@ -168,7 +172,7 @@ export const mockSelectedPatchCommit = createMockRecentCommit({
|
||||
/**
|
||||
* MOCK API CLIENT
|
||||
*/
|
||||
export const mockApiClient: IPluginApiClient = {
|
||||
export const mockApiClient: GitReleaseApi = {
|
||||
getHost: jest.fn(() => 'github.com'),
|
||||
|
||||
getRepoPath: jest.fn(() => `${mockOwner}/${mockRepo}`),
|
||||
|
||||
@@ -72,7 +72,7 @@ export const TEST_IDS = {
|
||||
icons: {
|
||||
tag: 'grm--differ--icons--tag',
|
||||
branch: 'grm--differ--icons--branch',
|
||||
github: 'grm--differ--icons--github',
|
||||
github: 'grm--differ--icons--git',
|
||||
slack: 'grm--differ--icons--slack',
|
||||
versioning: 'grm--differ--icons--versioning',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user