Merge branch 'master' of https://github.com/spotify/backstage
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-github-actions",
|
||||
"version": "0.1.1-alpha.20",
|
||||
"version": "0.1.1-alpha.21",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -22,11 +22,11 @@
|
||||
"mock-data": "./scripts/mock-data.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.1.1-alpha.20",
|
||||
"@backstage/core": "^0.1.1-alpha.20",
|
||||
"@backstage/core-api": "^0.1.1-alpha.20",
|
||||
"@backstage/plugin-catalog": "^0.1.1-alpha.20",
|
||||
"@backstage/theme": "^0.1.1-alpha.20",
|
||||
"@backstage/catalog-model": "^0.1.1-alpha.21",
|
||||
"@backstage/core": "^0.1.1-alpha.21",
|
||||
"@backstage/core-api": "^0.1.1-alpha.21",
|
||||
"@backstage/plugin-catalog": "^0.1.1-alpha.21",
|
||||
"@backstage/theme": "^0.1.1-alpha.21",
|
||||
"@material-ui/core": "^4.9.1",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.45",
|
||||
@@ -36,12 +36,13 @@
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-lazylog": "^4.5.3",
|
||||
"react-router": "6.0.0-beta.0",
|
||||
"react-router-dom": "6.0.0-beta.0",
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.1.1-alpha.20",
|
||||
"@backstage/dev-utils": "^0.1.1-alpha.20",
|
||||
"@backstage/cli": "^0.1.1-alpha.21",
|
||||
"@backstage/dev-utils": "^0.1.1-alpha.21",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
+9
-44
@@ -32,6 +32,7 @@ import {
|
||||
useApi,
|
||||
} from '@backstage/core';
|
||||
import ExternalLinkIcon from '@material-ui/icons/Launch';
|
||||
import { GITHUB_ACTIONS_ANNOTATION } from '../useProjectName';
|
||||
|
||||
const useStyles = makeStyles<Theme>({
|
||||
externalLinkIcon: {
|
||||
@@ -74,7 +75,7 @@ const WidgetContent = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const Widget = ({
|
||||
export const LatestWorkflowRunCard = ({
|
||||
entity,
|
||||
branch = 'master',
|
||||
}: {
|
||||
@@ -83,7 +84,7 @@ export const Widget = ({
|
||||
}) => {
|
||||
const errorApi = useApi(errorApiRef);
|
||||
const [owner, repo] = (
|
||||
entity?.metadata.annotations?.['backstage.io/github-actions-id'] ?? '/'
|
||||
entity?.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION] ?? '/'
|
||||
).split('/');
|
||||
const [{ runs, loading, error }] = useWorkflowRuns({
|
||||
owner,
|
||||
@@ -109,50 +110,14 @@ export const Widget = ({
|
||||
);
|
||||
};
|
||||
|
||||
const RecentWorkflowRunsCardContent = ({
|
||||
error,
|
||||
loading,
|
||||
branch,
|
||||
}: {
|
||||
error?: Error;
|
||||
loading?: boolean;
|
||||
branch: string;
|
||||
}) => {
|
||||
if (error) return <Typography>Couldn't fetch {branch} runs</Typography>;
|
||||
if (loading) return <LinearProgress />;
|
||||
return <WorkflowRunsTable />;
|
||||
};
|
||||
|
||||
export const RecentWorkflowRunsCard = ({
|
||||
export const LatestWorkflowsForBranchCard = ({
|
||||
entity,
|
||||
branch = 'master',
|
||||
}: {
|
||||
entity: Entity;
|
||||
branch: string;
|
||||
}) => {
|
||||
const errorApi = useApi(errorApiRef);
|
||||
const [owner, repo] = (
|
||||
entity?.metadata.annotations?.['backstage.io/github-actions-id'] ?? '/'
|
||||
).split('/');
|
||||
const [{ loading, error }] = useWorkflowRuns({
|
||||
owner,
|
||||
repo,
|
||||
branch,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
errorApi.post(error);
|
||||
}
|
||||
}, [error, errorApi]);
|
||||
|
||||
return (
|
||||
<InfoCard title={`${branch} builds`}>
|
||||
<RecentWorkflowRunsCardContent
|
||||
error={error}
|
||||
loading={loading}
|
||||
branch={branch}
|
||||
/>
|
||||
</InfoCard>
|
||||
);
|
||||
};
|
||||
}) => (
|
||||
<InfoCard title={`Last ${branch} build`}>
|
||||
<WorkflowRunsTable branch={branch} entity={entity} />
|
||||
</InfoCard>
|
||||
);
|
||||
+1
-2
@@ -13,5 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { WorkflowRunsPage } from './WorkflowRunsPage';
|
||||
export { LatestWorkflowRunCard, LatestWorkflowsForBranchCard } from './Cards';
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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 React from 'react';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { Routes, Route } from 'react-router';
|
||||
import { rootRouteRef, buildRouteRef } from '../plugin';
|
||||
import { WorkflowRunDetails } from './WorkflowRunDetails';
|
||||
import { WorkflowRunsTable } from './WorkflowRunsTable';
|
||||
import { GITHUB_ACTIONS_ANNOTATION } from './useProjectName';
|
||||
import { WarningPanel } from '@backstage/core';
|
||||
|
||||
const isPluginApplicableToEntity = (entity: Entity) =>
|
||||
Boolean(entity.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION]) &&
|
||||
entity.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION] !== '';
|
||||
|
||||
export const Router = ({ entity }: { entity: Entity }) =>
|
||||
// TODO(shmidt-i): move warning to a separate standardized component
|
||||
!isPluginApplicableToEntity(entity) ? (
|
||||
<WarningPanel title=" GitHubActions plugin:">
|
||||
`entity.metadata.annotations['
|
||||
{GITHUB_ACTIONS_ANNOTATION}']` key is missing on the entity.{' '}
|
||||
</WarningPanel>
|
||||
) : (
|
||||
<Routes>
|
||||
<Route
|
||||
path={`/${rootRouteRef.path}`}
|
||||
element={<WorkflowRunsTable entity={entity} />}
|
||||
/>
|
||||
<Route
|
||||
path={`/${buildRouteRef.path}`}
|
||||
element={<WorkflowRunDetails entity={entity} />}
|
||||
/>
|
||||
)
|
||||
</Routes>
|
||||
);
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
export { Widget, RecentWorkflowRunsCard } from './Widget';
|
||||
@@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { useEntityCompoundName } from '@backstage/plugin-catalog';
|
||||
import { useWorkflowRunsDetails } from './useWorkflowRunsDetails';
|
||||
import { useWorkflowRunJobs } from './useWorkflowRunJobs';
|
||||
import { useProjectName } from '../useProjectName';
|
||||
@@ -37,13 +36,16 @@ import {
|
||||
LinearProgress,
|
||||
CircularProgress,
|
||||
Theme,
|
||||
Link,
|
||||
Breadcrumbs,
|
||||
Link as MaterialLink,
|
||||
} from '@material-ui/core';
|
||||
import { Jobs, Job, Step } from '../../api';
|
||||
import moment from 'moment';
|
||||
import { WorkflowRunStatus } from '../WorkflowRunStatus';
|
||||
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
||||
import ExternalLinkIcon from '@material-ui/icons/Launch';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { Link } from '@backstage/core';
|
||||
|
||||
const useStyles = makeStyles<Theme>(theme => ({
|
||||
root: {
|
||||
@@ -154,18 +156,8 @@ const JobListItem = ({ job, className }: { job: Job; className: string }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const WorkflowRunDetails = () => {
|
||||
let entityCompoundName = useEntityCompoundName();
|
||||
if (!entityCompoundName.name) {
|
||||
// TODO(shmidt-i): remove when is fully integrated
|
||||
// into the entity view
|
||||
entityCompoundName = {
|
||||
kind: 'Component',
|
||||
name: 'backstage',
|
||||
namespace: 'default',
|
||||
};
|
||||
}
|
||||
const projectName = useProjectName(entityCompoundName);
|
||||
export const WorkflowRunDetails = ({ entity }: { entity: Entity }) => {
|
||||
const projectName = useProjectName(entity);
|
||||
|
||||
const [owner, repo] = projectName.value ? projectName.value.split('/') : [];
|
||||
const details = useWorkflowRunsDetails(repo, owner);
|
||||
@@ -184,6 +176,10 @@ export const WorkflowRunDetails = () => {
|
||||
}
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Breadcrumbs aria-label="breadcrumb">
|
||||
<Link to="..">Workflow runs</Link>
|
||||
<Typography>Workflow run details</Typography>
|
||||
</Breadcrumbs>
|
||||
<TableContainer component={Paper} className={classes.table}>
|
||||
<Table>
|
||||
<TableBody>
|
||||
@@ -225,10 +221,10 @@ export const WorkflowRunDetails = () => {
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{details.value?.html_url && (
|
||||
<Link target="_blank" href={details.value.html_url}>
|
||||
<MaterialLink target="_blank" href={details.value.html_url}>
|
||||
Workflow runs on GitHub{' '}
|
||||
<ExternalLinkIcon className={classes.externalLinkIcon} />
|
||||
</Link>
|
||||
</MaterialLink>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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 { Typography, Grid, Breadcrumbs } from '@material-ui/core';
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
Link,
|
||||
Page,
|
||||
Header,
|
||||
HeaderLabel,
|
||||
Content,
|
||||
ContentHeader,
|
||||
SupportButton,
|
||||
pageTheme,
|
||||
} from '@backstage/core';
|
||||
|
||||
import { WorkflowRunDetails } from '../WorkflowRunDetails';
|
||||
|
||||
/**
|
||||
* A component for Jobs visualization. Jobs are a property of a Workflow Run.
|
||||
*/
|
||||
export const WorkflowRunDetailsPage = () => {
|
||||
return (
|
||||
<Page theme={pageTheme.tool}>
|
||||
<Header
|
||||
title="GitHub Actions"
|
||||
subtitle="See recent workflow runs and their status"
|
||||
>
|
||||
<HeaderLabel label="Owner" value="Spotify" />
|
||||
<HeaderLabel label="Lifecycle" value="Alpha" />
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentHeader title="Workflow run details">
|
||||
<SupportButton>
|
||||
This plugin allows you to view and interact with your builds within
|
||||
the GitHub Actions environment.
|
||||
</SupportButton>
|
||||
</ContentHeader>
|
||||
<Breadcrumbs aria-label="breadcrumb">
|
||||
<Link to="/github-actions">Workflow runs</Link>
|
||||
<Typography>Workflow run details</Typography>
|
||||
</Breadcrumbs>
|
||||
<Grid container spacing={3} direction="column">
|
||||
<Grid item>
|
||||
<WorkflowRunDetails />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { WorkflowRunDetailsPage } from './WorkflowRunDetailsPage';
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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 {
|
||||
Header,
|
||||
HeaderLabel,
|
||||
pageTheme,
|
||||
Page,
|
||||
Content,
|
||||
ContentHeader,
|
||||
SupportButton,
|
||||
} from '@backstage/core';
|
||||
import { Grid } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
|
||||
import { WorkflowRunsTable } from '../WorkflowRunsTable';
|
||||
|
||||
export const WorkflowRunsPage = () => {
|
||||
return (
|
||||
<Page theme={pageTheme.tool}>
|
||||
<Header
|
||||
title="GitHub Actions"
|
||||
subtitle="See recent workflow runs and their status"
|
||||
>
|
||||
<HeaderLabel label="Owner" value="Spotify" />
|
||||
<HeaderLabel label="Lifecycle" value="Alpha" />
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentHeader title="Workflow runs">
|
||||
<SupportButton>
|
||||
This plugin allows you to view and interact with your builds within
|
||||
the GitHub Actions environment.
|
||||
</SupportButton>
|
||||
</ContentHeader>
|
||||
<Grid container spacing={3} direction="column">
|
||||
<Grid item>
|
||||
<WorkflowRunsTable />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
@@ -23,8 +23,8 @@ import { useWorkflowRuns } from '../useWorkflowRuns';
|
||||
import { WorkflowRunStatus } from '../WorkflowRunStatus';
|
||||
import SyncIcon from '@material-ui/icons/Sync';
|
||||
import { buildRouteRef } from '../../plugin';
|
||||
import { useEntityCompoundName } from '@backstage/plugin-catalog';
|
||||
import { useProjectName } from '../useProjectName';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
export type WorkflowRun = {
|
||||
id: string;
|
||||
@@ -134,6 +134,7 @@ export const WorkflowRunsTableView: FC<Props> = ({
|
||||
data={runs ?? []}
|
||||
onChangePage={onChangePage}
|
||||
onChangeRowsPerPage={onChangePageSize}
|
||||
style={{ width: '100%' }}
|
||||
title={
|
||||
<Box display="flex" alignItems="center">
|
||||
<GitHubIcon />
|
||||
@@ -146,25 +147,21 @@ export const WorkflowRunsTableView: FC<Props> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const WorkflowRunsTable = () => {
|
||||
let entityCompoundName = useEntityCompoundName();
|
||||
|
||||
if (!entityCompoundName.name) {
|
||||
// TODO(shmidt-i): remove when is fully integrated
|
||||
// into the entity view
|
||||
entityCompoundName = {
|
||||
kind: 'Component',
|
||||
name: 'backstage',
|
||||
namespace: 'default',
|
||||
};
|
||||
}
|
||||
|
||||
const { value: projectName, loading } = useProjectName(entityCompoundName);
|
||||
export const WorkflowRunsTable = ({
|
||||
entity,
|
||||
branch,
|
||||
}: {
|
||||
entity: Entity;
|
||||
branch?: string;
|
||||
}) => {
|
||||
const { value: projectName, loading } = useProjectName(entity);
|
||||
const [owner, repo] = (projectName ?? '/').split('/');
|
||||
const [tableProps, { retry, setPage, setPageSize }] = useWorkflowRuns({
|
||||
owner,
|
||||
repo,
|
||||
branch,
|
||||
});
|
||||
|
||||
return (
|
||||
<WorkflowRunsTableView
|
||||
{...tableProps}
|
||||
|
||||
@@ -15,15 +15,13 @@
|
||||
*/
|
||||
|
||||
import { useAsync } from 'react-use';
|
||||
import { catalogApiRef, EntityCompoundName } from '@backstage/plugin-catalog';
|
||||
import { useApi } from '@backstage/core';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
export const useProjectName = (name: EntityCompoundName) => {
|
||||
const catalogApi = useApi(catalogApiRef);
|
||||
export const GITHUB_ACTIONS_ANNOTATION = 'github.com/project-slug';
|
||||
|
||||
export const useProjectName = (entity: Entity) => {
|
||||
const { value, loading, error } = useAsync(async () => {
|
||||
const entity = await catalogApi.getEntityByName(name);
|
||||
return entity?.metadata.annotations?.['github.com/project-slug'] ?? '';
|
||||
return entity?.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION] ?? '';
|
||||
});
|
||||
return { value, loading, error };
|
||||
};
|
||||
|
||||
@@ -16,4 +16,6 @@
|
||||
|
||||
export { plugin } from './plugin';
|
||||
export * from './api';
|
||||
export { Widget } from './components/Widget';
|
||||
export { Router } from './components/Router';
|
||||
export * from './components/Cards';
|
||||
export { GITHUB_ACTIONS_ANNOTATION } from './components/useProjectName';
|
||||
|
||||
@@ -15,28 +15,18 @@
|
||||
*/
|
||||
|
||||
import { createPlugin, createRouteRef } from '@backstage/core';
|
||||
import { WorkflowRunDetailsPage } from './components/WorkflowRunDetailsPage';
|
||||
import { WorkflowRunsPage } from './components/WorkflowRunsPage';
|
||||
|
||||
// TODO(freben): This is just a demo route for now
|
||||
export const rootRouteRef = createRouteRef({
|
||||
path: '/github-actions',
|
||||
path: '',
|
||||
title: 'GitHub Actions',
|
||||
});
|
||||
export const projectRouteRef = createRouteRef({
|
||||
path: '/github-actions/:kind/:optionalNamespaceAndName/',
|
||||
title: 'GitHub Actions for project',
|
||||
});
|
||||
|
||||
export const buildRouteRef = createRouteRef({
|
||||
path: '/github-actions/workflow-run/:id',
|
||||
path: ':id',
|
||||
title: 'GitHub Actions Workflow Run',
|
||||
});
|
||||
|
||||
export const plugin = createPlugin({
|
||||
id: 'github-actions',
|
||||
register({ router }) {
|
||||
router.addRoute(rootRouteRef, WorkflowRunsPage);
|
||||
router.addRoute(projectRouteRef, WorkflowRunsPage);
|
||||
router.addRoute(buildRouteRef, WorkflowRunDetailsPage);
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user