Merge branch 'master' into gcp-ua-header

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-01-22 00:49:01 +01:00
committed by GitHub
202 changed files with 5099 additions and 9304 deletions
@@ -29,17 +29,22 @@ export const cloudbuildApiRef = createApiRef<CloudbuildApi>({
export type CloudbuildApi = {
listWorkflowRuns: (options: {
projectId: string;
location: string;
cloudBuildFilter: string;
}) => Promise<ActionsListWorkflowRunsForRepoResponseData>;
getWorkflow: (options: {
projectId: string;
location: string;
id: string;
}) => Promise<ActionsGetWorkflowResponseData>;
getWorkflowRun: (options: {
projectId: string;
location: string;
id: string;
}) => Promise<ActionsGetWorkflowResponseData>;
reRunWorkflow: (options: {
projectId: string;
location: string;
runId: string;
}) => Promise<any>;
};
+14 -1
View File
@@ -28,11 +28,14 @@ export class CloudbuildClient implements CloudbuildApi {
async reRunWorkflow(options: {
projectId: string;
location: string;
runId: string;
}): Promise<void> {
await this.request(
`https://cloudbuild.googleapis.com/v1/projects/${encodeURIComponent(
options.projectId,
)}/locations/${encodeURIComponent(
options.location,
)}/builds/${encodeURIComponent(options.runId)}:retry`,
'POST',
);
@@ -40,11 +43,15 @@ export class CloudbuildClient implements CloudbuildApi {
async listWorkflowRuns(options: {
projectId: string;
location: string;
cloudBuildFilter: string;
}): Promise<ActionsListWorkflowRunsForRepoResponseData> {
const workflowRuns = await this.request(
`https://cloudbuild.googleapis.com/v1/projects/${encodeURIComponent(
options.projectId,
)}/builds`,
)}/locations/${encodeURIComponent(
options.location,
)}/builds?filter=${encodeURIComponent(options.cloudBuildFilter)}`,
);
const builds: ActionsListWorkflowRunsForRepoResponseData =
@@ -55,11 +62,14 @@ export class CloudbuildClient implements CloudbuildApi {
async getWorkflow(options: {
projectId: string;
location: string;
id: string;
}): Promise<ActionsGetWorkflowResponseData> {
const workflow = await this.request(
`https://cloudbuild.googleapis.com/v1/projects/${encodeURIComponent(
options.projectId,
)}/locations/${encodeURIComponent(
options.location,
)}/builds/${encodeURIComponent(options.id)}`,
);
@@ -70,11 +80,14 @@ export class CloudbuildClient implements CloudbuildApi {
async getWorkflowRun(options: {
projectId: string;
location: string;
id: string;
}): Promise<ActionsGetWorkflowResponseData> {
const workflow = await this.request(
`https://cloudbuild.googleapis.com/v1/projects/${encodeURIComponent(
options.projectId,
)}/locations/${encodeURIComponent(
options.location,
)}/builds/${encodeURIComponent(options.id)}`,
);
const build: ActionsGetWorkflowResponseData = await workflow.json();
+1 -1
View File
@@ -81,7 +81,7 @@ export interface Options {
export interface Substitutions {
COMMIT_SHA: string;
SHORT_SHA: string;
BRANCH_NAME: string;
REF_NAME: string;
REPO_NAME: string;
REVISION_ID: string;
}
@@ -22,6 +22,8 @@ import { WorkflowRunStatus } from '../WorkflowRunStatus';
import { makeStyles, LinearProgress } from '@material-ui/core';
import ExternalLinkIcon from '@material-ui/icons/Launch';
import { CLOUDBUILD_ANNOTATION } from '../useProjectName';
import { getLocation } from '../useLocation';
import { getCloudbuildFilter } from '../useCloudBuildFilter';
import {
InfoCard,
@@ -79,9 +81,13 @@ export const LatestWorkflowRunCard = (props: { branch: string }) => {
const { entity } = useEntity();
const errorApi = useApi(errorApiRef);
const projectId = entity?.metadata.annotations?.[CLOUDBUILD_ANNOTATION] || '';
const location = getLocation(entity);
const cloudBuildFilter = getCloudbuildFilter(entity);
const [{ runs, loading, error }] = useWorkflowRuns({
projectId,
location,
cloudBuildFilter,
});
const lastRun = runs?.[0] ?? ({} as WorkflowRun);
useEffect(() => {
@@ -34,6 +34,7 @@ import { useProjectName } from '../useProjectName';
import { WorkflowRunStatus } from '../WorkflowRunStatus';
import { useWorkflowRunsDetails } from './useWorkflowRunsDetails';
import { Breadcrumbs, Link, WarningPanel } from '@backstage/core-components';
import { getLocation } from '../useLocation';
const useStyles = makeStyles(theme => ({
root: {
@@ -63,8 +64,9 @@ const useStyles = makeStyles(theme => ({
export const WorkflowRunDetails = (props: { entity: Entity }) => {
const { value: projectName, loading, error } = useProjectName(props.entity);
const [projectId] = (projectName ?? '/').split('/');
const location = getLocation(props.entity);
const details = useWorkflowRunsDetails(projectId);
const details = useWorkflowRunsDetails(projectId, location);
const classes = useStyles();
if (error) {
@@ -96,9 +98,9 @@ export const WorkflowRunDetails = (props: { entity: Entity }) => {
<TableBody>
<TableRow>
<TableCell>
<Typography noWrap>Branch</Typography>
<Typography noWrap>Ref</Typography>
</TableCell>
<TableCell>{details.value?.substitutions.BRANCH_NAME}</TableCell>
<TableCell>{details.value?.substitutions.REF_NAME}</TableCell>
</TableRow>
<TableRow>
<TableCell>
@@ -18,13 +18,14 @@ import { cloudbuildApiRef } from '../../api';
import { useApi, useRouteRefParams } from '@backstage/core-plugin-api';
import { buildRouteRef } from '../../routes';
export const useWorkflowRunsDetails = (projectId: string) => {
export const useWorkflowRunsDetails = (projectId: string, location: string) => {
const api = useApi(cloudbuildApiRef);
const { id } = useRouteRefParams(buildRouteRef);
const details = useAsync(async () => {
return projectId
? api.getWorkflowRun({
projectId,
location,
id: id,
})
: Promise.reject('No projectId provided');
@@ -35,7 +35,7 @@ describe('<WorkflowRunsTableView />', () => {
substitutions: {
COMMIT_SHA: 'e3adasd2e3adasd2e3adasd2',
SHORT_SHA: 'f12j1231',
BRANCH_NAME: 'main',
REF_NAME: 'main',
REPO_NAME: 'backstage',
REVISION_ID: 'g123123',
},
@@ -26,6 +26,8 @@ import { buildRouteRef } from '../../routes';
import { DateTime } from 'luxon';
import { Table, TableColumn, Link } from '@backstage/core-components';
import { useRouteRef } from '@backstage/core-plugin-api';
import { getLocation } from '../useLocation';
import { getCloudbuildFilter } from '../useCloudBuildFilter';
const generatedColumns: TableColumn[] = [
{
@@ -71,7 +73,7 @@ const generatedColumns: TableColumn[] = [
title: 'Ref',
render: (row: Partial<WorkflowRun>) => (
<Typography variant="body2" noWrap>
{row.substitutions?.BRANCH_NAME}
{row.substitutions?.REF_NAME}
</Typography>
),
},
@@ -162,9 +164,12 @@ export const WorkflowRunsTableView = ({
export const WorkflowRunsTable = (props: { entity: Entity }) => {
const { value: projectName, loading } = useProjectName(props.entity);
const [projectId] = (projectName ?? '/').split('/');
const location = getLocation(props.entity);
const cloudBuildFilter = getCloudbuildFilter(props.entity);
const [tableProps, { retry, setPage, setPageSize }] = useWorkflowRuns({
projectId,
location,
cloudBuildFilter,
});
return (
@@ -0,0 +1,43 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Entity } from '@backstage/catalog-model';
const CLOUDBUILD_FILTER_REPO_STRING = 'substitutions.REPO_NAME=';
const CLOUDBUILD_FILTER_REPO_ANNOTATION = 'google.com/cloudbuild-repo-name';
const CLOUDBUILD_FILTER_TRIGGER_STRING = 'substitutions.TRIGGER_NAME=';
const CLOUDBUILD_FILTER_TRIGGER_ANNOTATION =
'google.com/cloudbuild-trigger-name';
/** @public */
export const getCloudbuildFilter = (entity: Entity) => {
const repoAnnotation =
entity?.metadata.annotations?.[CLOUDBUILD_FILTER_REPO_ANNOTATION] ?? '';
const triggerAnnotation =
entity?.metadata.annotations?.[CLOUDBUILD_FILTER_TRIGGER_ANNOTATION] ?? '';
if (repoAnnotation) {
const cloudbuildFilter = CLOUDBUILD_FILTER_REPO_STRING + repoAnnotation;
return cloudbuildFilter;
} else if (triggerAnnotation) {
const cloudbuildFilter =
CLOUDBUILD_FILTER_TRIGGER_STRING + triggerAnnotation;
return cloudbuildFilter;
}
const entityName = entity?.metadata.name ?? '';
const cloudbuildFilter = CLOUDBUILD_FILTER_REPO_STRING + entityName;
return cloudbuildFilter;
};
@@ -0,0 +1,30 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Entity } from '@backstage/catalog-model';
const CLOUDBUILD_LOCATION_ANNOTATION = 'google.com/cloudbuild-location';
/** @public */
export const getLocation = (entity: Entity) => {
const locationAnnotation =
entity?.metadata.annotations?.[CLOUDBUILD_LOCATION_ANNOTATION] ?? '';
if (locationAnnotation) {
return locationAnnotation;
}
return 'global';
};
@@ -33,8 +33,12 @@ export type WorkflowRun = {
rerun: () => void;
};
export function useWorkflowRuns(options: { projectId: string }) {
const { projectId } = options;
export function useWorkflowRuns(options: {
projectId: string;
location: string;
cloudBuildFilter: string;
}) {
const { projectId, location, cloudBuildFilter } = options;
const api = useApi(cloudbuildApiRef);
const errorApi = useApi(errorApiRef);
@@ -51,6 +55,8 @@ export function useWorkflowRuns(options: { projectId: string }) {
return api
.listWorkflowRuns({
projectId,
location,
cloudBuildFilter,
})
.then(
(
@@ -65,6 +71,7 @@ export function useWorkflowRuns(options: { projectId: string }) {
try {
await api.reRunWorkflow({
projectId,
location,
runId: run.id,
});
} catch (e) {