From 64c0c67c8fca840a37babe9d5d2ef83199493350 Mon Sep 17 00:00:00 2001 From: Nikita Nek Dudnik Date: Mon, 20 Jul 2020 09:21:29 +0200 Subject: [PATCH 01/10] feat: github actions details view --- app-config.yaml | 4 + plugins/github-actions/package.json | 2 + .../src/api/GithubActionsApi.ts | 2 +- .../src/api/GithubActionsClient.ts | 4 +- .../BuildDetailsPage/BuildDetailsPage.tsx | 143 ----------- .../BuildInfoCard/BuildInfoCard.tsx | 107 -------- .../WorkflowRunDetailsPage.tsx | 228 ++++++++++++++++++ .../index.ts | 2 +- .../useWorkflowRunJobs.ts} | 11 +- .../useWorkflowRunsDetails.ts | 35 +++ .../WorkflowRunStatusIndicator.tsx} | 41 ++-- .../index.ts | 2 +- .../WorkflowRunsPage.tsx} | 15 +- .../index.ts | 2 +- .../WorkflowRunsTable.tsx} | 57 +++-- .../index.ts | 4 +- .../useWorkflowRuns.ts} | 56 +++-- .../github-actions/src/components/types.ts | 45 ++++ plugins/github-actions/src/plugin.ts | 12 +- yarn.lock | 5 + 20 files changed, 439 insertions(+), 338 deletions(-) delete mode 100644 plugins/github-actions/src/components/BuildDetailsPage/BuildDetailsPage.tsx delete mode 100644 plugins/github-actions/src/components/BuildInfoCard/BuildInfoCard.tsx create mode 100644 plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx rename plugins/github-actions/src/components/{BuildDetailsPage => WorkflowRunDetailsPage}/index.ts (89%) rename plugins/github-actions/src/components/{BuildInfoCard/index.ts => WorkflowRunDetailsPage/useWorkflowRunJobs.ts} (64%) create mode 100644 plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunsDetails.ts rename plugins/github-actions/src/components/{BuildStatusIndicator/BuildStatusIndicator.tsx => WorkflowRunStatusIndicator/WorkflowRunStatusIndicator.tsx} (67%) rename plugins/github-actions/src/components/{BuildStatusIndicator => WorkflowRunStatusIndicator}/index.ts (88%) rename plugins/github-actions/src/components/{BuildListPage/BuildListPage.tsx => WorkflowRunsPage/WorkflowRunsPage.tsx} (75%) rename plugins/github-actions/src/components/{BuildListPage => WorkflowRunsPage}/index.ts (91%) rename plugins/github-actions/src/components/{BuildListTable/BuildListTable.tsx => WorkflowRunsTable/WorkflowRunsTable.tsx} (78%) rename plugins/github-actions/src/components/{BuildListTable => WorkflowRunsTable}/index.ts (84%) rename plugins/github-actions/src/components/{BuildListTable/useBuilds.ts => WorkflowRunsTable/useWorkflowRuns.ts} (64%) create mode 100644 plugins/github-actions/src/components/types.ts diff --git a/app-config.yaml b/app-config.yaml index 9a4a14b923..7dacdc56ac 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -20,6 +20,10 @@ proxy: organization: name: Spotify +github-actions: + owner: CircleCITest3 + repo: try-ssr + techdocs: storageUrl: https://techdocs-mock-sites.storage.googleapis.com diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index ce0068c35a..ce83f44e5f 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -30,8 +30,10 @@ "@material-ui/lab": "4.0.0-alpha.45", "@octokit/rest": "^18.0.0", "@octokit/types": "^5.0.1", + "moment": "^2.27.0", "react": "^16.13.1", "react-dom": "^16.13.1", + "react-lazylog": "^4.5.2", "react-router-dom": "6.0.0-beta.0", "react-use": "^14.2.0" }, diff --git a/plugins/github-actions/src/api/GithubActionsApi.ts b/plugins/github-actions/src/api/GithubActionsApi.ts index eedf9686f3..bb54fae703 100644 --- a/plugins/github-actions/src/api/GithubActionsApi.ts +++ b/plugins/github-actions/src/api/GithubActionsApi.ts @@ -72,5 +72,5 @@ export type GithubActionsApi = { owner: string; repo: string; runId: number; - }) => void; + }) => Promise; }; diff --git a/plugins/github-actions/src/api/GithubActionsClient.ts b/plugins/github-actions/src/api/GithubActionsClient.ts index 1606c268f4..6e6f1cb1e2 100644 --- a/plugins/github-actions/src/api/GithubActionsClient.ts +++ b/plugins/github-actions/src/api/GithubActionsClient.ts @@ -33,8 +33,8 @@ export class GithubActionsClient implements GithubActionsApi { owner: string; repo: string; runId: number; - }) { - new Octokit({ auth: token }).actions.reRunWorkflow({ + }): Promise { + return new Octokit({ auth: token }).actions.reRunWorkflow({ owner, repo, run_id: runId, diff --git a/plugins/github-actions/src/components/BuildDetailsPage/BuildDetailsPage.tsx b/plugins/github-actions/src/components/BuildDetailsPage/BuildDetailsPage.tsx deleted file mode 100644 index 55c568106c..0000000000 --- a/plugins/github-actions/src/components/BuildDetailsPage/BuildDetailsPage.tsx +++ /dev/null @@ -1,143 +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 { - Button, - LinearProgress, - makeStyles, - Paper, - Table, - TableBody, - TableCell, - TableContainer, - TableRow, - Theme, - Typography, -} from '@material-ui/core'; -import React from 'react'; -import { useParams } from 'react-router-dom'; -import { useAsync } from 'react-use'; -import { Link, useApi, githubAuthApiRef } from '@backstage/core'; -import { githubActionsApiRef } from '../../api'; - -const useStyles = makeStyles(theme => ({ - root: { - maxWidth: 720, - margin: theme.spacing(2), - }, - title: { - padding: theme.spacing(1, 0, 2, 0), - }, - table: { - padding: theme.spacing(1), - }, -})); - -export const BuildDetailsPage = () => { - const repo = 'try-ssr'; - const owner = 'CircleCITest3'; - const api = useApi(githubActionsApiRef); - const auth = useApi(githubAuthApiRef); - - const classes = useStyles(); - const { id } = useParams(); - const status = useAsync(async () => { - const token = await auth.getAccessToken(['repo', 'user']); - return api - .getWorkflowRun({ - token, - owner, - repo, - id: parseInt(id, 10), - }) - .then(data => { - return data; - }); - }, [location.search]); - - if (status.loading) { - return ; - } else if (status.error) { - return ( - - Failed to load build, {status.error.message} - - ); - } - - const details = status.value; - - return ( -
- - - - < - - - Build Details - - - - - - - Branch - - {details?.head_branch} - - - - Message - - {details?.head_commit.message} - - - - Commit ID - - {details?.head_commit.id} - - - - Status - - {details?.status} - - - - Author - - {`${details?.head_commit.author.name} (${details?.head_commit.author.email})`} - - - - Links - - - {details?.html_url && ( - - )} - - - -
-
-
- ); -}; diff --git a/plugins/github-actions/src/components/BuildInfoCard/BuildInfoCard.tsx b/plugins/github-actions/src/components/BuildInfoCard/BuildInfoCard.tsx deleted file mode 100644 index acc1b496ec..0000000000 --- a/plugins/github-actions/src/components/BuildInfoCard/BuildInfoCard.tsx +++ /dev/null @@ -1,107 +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 { - LinearProgress, - makeStyles, - Table, - TableBody, - TableCell, - TableRow, - Theme, - Typography, -} from '@material-ui/core'; -import React from 'react'; -import { useAsync } from 'react-use'; -import { BuildStatusIndicator } from '../BuildStatusIndicator'; -import { githubActionsApiRef, BuildStatus } from '../../api'; -import { Link, useApi, githubAuthApiRef } from '@backstage/core'; - -const useStyles = makeStyles(theme => ({ - root: { - // height: 400, - }, - title: { - paddingBottom: theme.spacing(1), - }, -})); - -const BuildInfoCardContent = () => { - const api = useApi(githubActionsApiRef); - const auth = useApi(githubAuthApiRef); - - const status = useAsync(async () => { - const token = await auth.getAccessToken(['repo', 'user']); - return api.listWorkflowRuns({ token, owner: 'spotify', repo: 'backstage' }); - }); - - if (status.loading) { - return ; - } else if (status.error) { - return ( - - Failed to load builds, {status.error.message} - - ); - } - - // const [build] = - // status.value?.filter(({ branch }) => branch === 'master') ?? []; - - return ( - - - - - Message - - - - build message - - - - - - Commit ID - - build commit id - - - - Status - - - - - - -
- ); -}; - -export const BuildInfoCard = () => { - const classes = useStyles(); - - return ( -
- - Master Build - - -
- ); -}; diff --git a/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx b/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx new file mode 100644 index 0000000000..0bf72c77fd --- /dev/null +++ b/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx @@ -0,0 +1,228 @@ +/* + * 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 { + Button, + LinearProgress, + makeStyles, + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableRow, + Theme, + Typography, + Box, + ExpansionPanelDetails, + ExpansionPanel, + ExpansionPanelSummary, + ListItem, + List, + ListItemText, + CircularProgress, +} from '@material-ui/core'; +import moment from 'moment'; + +import React from 'react'; +import { Link, useApi, configApiRef } from '@backstage/core'; +import { Job, Step, Jobs } from '../types'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import { WorkflowRunStatusIndicator } from '../WorkflowRunStatusIndicator'; +import { useWorkflowRunsDetails } from './useWorkflowRunsDetails'; +import { useWorkflowRunJobs } from './useWorkflowRunJobs'; + +const useStyles = makeStyles(theme => ({ + root: { + maxWidth: 720, + margin: theme.spacing(2), + }, + title: { + padding: theme.spacing(1, 0, 2, 0), + }, + table: { + padding: theme.spacing(1), + }, + expansionPanelDetails: { + padding: 0, + }, + button: { + order: -1, + marginRight: 0, + marginLeft: '-20px', + }, +})); + +const JobsList = ({ jobs }: { jobs?: Jobs }) => { + const classes = useStyles(); + return ( + + {jobs && + jobs.total_count > 0 && + jobs.jobs.map((job: Job) => ( + + ))} + + ); +}; + +const getElapsedTime = (start: string, end: string) => { + const diff = moment(moment(end || moment()).diff(moment(start))); + const timeElapsed = diff.format('m [minutes] s [seconds]'); + return timeElapsed; +}; + +const StepView = ({ step }: { step: Step }) => { + return ( + + + + ); +}; + +const JobListItem = ({ job, className }: { job: Job; className: string }) => { + const classes = useStyles(); + return ( + + } + aria-controls={`panel-${name}-content`} + id={`panel-${name}-header`} + IconButtonProps={{ + className: classes.button, + }} + > + + {job.name} ({getElapsedTime(job.started_at, job.completed_at)}) + + + + + {job.steps.map((step: Step) => ( + + ))} + + + + ); +}; + +/** + * A component for Jobs visualization. Jobs are a property of a Workflow Run. + */ +export const WorkflowRunDetailsPage = () => { + const configApi = useApi(configApiRef); + const repo = configApi.getString('github-actions.repo'); + const owner = configApi.getString('github-actions.owner'); + const details = useWorkflowRunsDetails(repo, owner); + const jobs = useWorkflowRunJobs(details.value?.jobs_url); + + const classes = useStyles(); + + if (details.loading) { + return ; + } else if (details.error) { + return ( + + Failed to load build, {details.error.message} + + ); + } + + return ( +
+ + + + < + + + Workflow Run Details + + + + + + + Branch + + {details.value?.head_branch} + + + + Message + + {details.value?.head_commit.message} + + + + Commit ID + + {details.value?.head_commit.id} + + + + Status + + + + + + + + Author + + {`${details.value?.head_commit.author.name} (${details.value?.head_commit.author.email})`} + + + + Links + + + {details.value?.html_url && ( + + )} + + + + + Jobs + {jobs.loading ? ( + + ) : ( + + )} + + + +
+
+
+ ); +}; diff --git a/plugins/github-actions/src/components/BuildDetailsPage/index.ts b/plugins/github-actions/src/components/WorkflowRunDetailsPage/index.ts similarity index 89% rename from plugins/github-actions/src/components/BuildDetailsPage/index.ts rename to plugins/github-actions/src/components/WorkflowRunDetailsPage/index.ts index d59d0fc396..443bcacc88 100644 --- a/plugins/github-actions/src/components/BuildDetailsPage/index.ts +++ b/plugins/github-actions/src/components/WorkflowRunDetailsPage/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { BuildDetailsPage } from './BuildDetailsPage'; +export { WorkflowRunDetailsPage } from './WorkflowRunDetailsPage'; diff --git a/plugins/github-actions/src/components/BuildInfoCard/index.ts b/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunJobs.ts similarity index 64% rename from plugins/github-actions/src/components/BuildInfoCard/index.ts rename to plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunJobs.ts index a6409e682a..c941ed6389 100644 --- a/plugins/github-actions/src/components/BuildInfoCard/index.ts +++ b/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunJobs.ts @@ -13,5 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { useAsync } from 'react-use'; +import { Jobs } from '../types'; -export { BuildInfoCard } from './BuildInfoCard'; +export const useWorkflowRunJobs = (jobsUrl?: string) => { + const jobs = useAsync(async () => { + if (jobsUrl === undefined) return []; + const data = await fetch(jobsUrl).then(d => d.json()); + return data; + }, [jobsUrl]); + return jobs; +}; diff --git a/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunsDetails.ts b/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunsDetails.ts new file mode 100644 index 0000000000..088c286d94 --- /dev/null +++ b/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunsDetails.ts @@ -0,0 +1,35 @@ +/* + * 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 { useApi, githubAuthApiRef } from '@backstage/core'; +import { useParams } from 'react-router-dom'; +import { useAsync } from 'react-use'; +import { githubActionsApiRef } from '../../api'; + +export const useWorkflowRunsDetails = (repo: string, owner: string) => { + const api = useApi(githubActionsApiRef); + const auth = useApi(githubAuthApiRef); + const { id } = useParams(); + const details = useAsync(async () => { + const token = await auth.getAccessToken(['repo', 'user']); + return api.getWorkflowRun({ + token, + owner, + repo, + id: parseInt(id, 10), + }); + }, [id]); + return details; +}; diff --git a/plugins/github-actions/src/components/BuildStatusIndicator/BuildStatusIndicator.tsx b/plugins/github-actions/src/components/WorkflowRunStatusIndicator/WorkflowRunStatusIndicator.tsx similarity index 67% rename from plugins/github-actions/src/components/BuildStatusIndicator/BuildStatusIndicator.tsx rename to plugins/github-actions/src/components/WorkflowRunStatusIndicator/WorkflowRunStatusIndicator.tsx index 1a198f4df2..a22c60cdcb 100644 --- a/plugins/github-actions/src/components/BuildStatusIndicator/BuildStatusIndicator.tsx +++ b/plugins/github-actions/src/components/WorkflowRunStatusIndicator/WorkflowRunStatusIndicator.tsx @@ -15,16 +15,14 @@ */ import { IconComponent } from '@backstage/core'; -import { makeStyles, Theme } from '@material-ui/core'; +import { makeStyles, Theme, Typography } from '@material-ui/core'; import ProgressIcon from '@material-ui/icons/Autorenew'; import SuccessIcon from '@material-ui/icons/CheckCircle'; -import FailureIcon from '@material-ui/icons/Error'; import UnknownIcon from '@material-ui/icons/Help'; import React from 'react'; -import { BuildStatus } from '../../api/types'; type Props = { - status?: BuildStatus; + status?: string; }; type StatusStyle = { @@ -32,43 +30,50 @@ type StatusStyle = { color: string; }; -const styles: { [key in BuildStatus]: StatusStyle } = { - [BuildStatus.Null]: { +const styles: { [key: string]: StatusStyle } = { + unknown: { icon: UnknownIcon, color: '#f49b20', }, - [BuildStatus.Success]: { + completed: { icon: SuccessIcon, color: '#1db855', }, - [BuildStatus.Failure]: { - icon: FailureIcon, - color: '#CA001B', - }, - [BuildStatus.Pending]: { + queued: { icon: UnknownIcon, color: '#5BC0DE', }, - [BuildStatus.Running]: { + in_progress: { icon: ProgressIcon, color: '#BEBEBE', }, }; +const getIconStyle = (status?: string): StatusStyle => { + return styles[status ?? 'unknown'] ?? styles.unknown; +}; + const useStyles = makeStyles({ icon: style => ({ color: style.color, }), }); -export const BuildStatusIndicator = ({ status }: Props) => { - const style = (status && styles[status]) || styles[BuildStatus.Null]; +export const WorkflowRunStatusIndicator = ({ status }: Props) => { + const style = getIconStyle(status); const classes = useStyles(style); const Icon = style.icon; return ( -
- -
+ +  {`${status}`} + ); }; diff --git a/plugins/github-actions/src/components/BuildStatusIndicator/index.ts b/plugins/github-actions/src/components/WorkflowRunStatusIndicator/index.ts similarity index 88% rename from plugins/github-actions/src/components/BuildStatusIndicator/index.ts rename to plugins/github-actions/src/components/WorkflowRunStatusIndicator/index.ts index 520de525ec..463970a30c 100644 --- a/plugins/github-actions/src/components/BuildStatusIndicator/index.ts +++ b/plugins/github-actions/src/components/WorkflowRunStatusIndicator/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { BuildStatusIndicator } from './BuildStatusIndicator'; +export { WorkflowRunStatusIndicator } from './WorkflowRunStatusIndicator'; diff --git a/plugins/github-actions/src/components/BuildListPage/BuildListPage.tsx b/plugins/github-actions/src/components/WorkflowRunsPage/WorkflowRunsPage.tsx similarity index 75% rename from plugins/github-actions/src/components/BuildListPage/BuildListPage.tsx rename to plugins/github-actions/src/components/WorkflowRunsPage/WorkflowRunsPage.tsx index 172b3611bf..a4cb576468 100644 --- a/plugins/github-actions/src/components/BuildListPage/BuildListPage.tsx +++ b/plugins/github-actions/src/components/WorkflowRunsPage/WorkflowRunsPage.tsx @@ -22,24 +22,29 @@ import { Content, ContentHeader, SupportButton, + useApi, + configApiRef, } from '@backstage/core'; import { Grid } from '@material-ui/core'; import React from 'react'; -import { BuildListTable } from '../BuildListTable'; +import { WorkflowRunsTable } from '../WorkflowRunsTable'; -export const BuildListPage = () => { +export const WorkflowRunsPage = () => { + const configApi = useApi(configApiRef); + const repo = configApi.getString('github-actions.repo'); + const owner = configApi.getString('github-actions.owner'); return (
- + This plugin allows you to view and interact with your builds within the GitHub Actions environment. @@ -47,7 +52,7 @@ export const BuildListPage = () => { - + diff --git a/plugins/github-actions/src/components/BuildListPage/index.ts b/plugins/github-actions/src/components/WorkflowRunsPage/index.ts similarity index 91% rename from plugins/github-actions/src/components/BuildListPage/index.ts rename to plugins/github-actions/src/components/WorkflowRunsPage/index.ts index 2134913e51..ef511763f7 100644 --- a/plugins/github-actions/src/components/BuildListPage/index.ts +++ b/plugins/github-actions/src/components/WorkflowRunsPage/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { BuildListPage } from './BuildListPage'; +export { WorkflowRunsPage } from './WorkflowRunsPage'; diff --git a/plugins/github-actions/src/components/BuildListTable/BuildListTable.tsx b/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx similarity index 78% rename from plugins/github-actions/src/components/BuildListTable/BuildListTable.tsx rename to plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx index b5fd4636f5..a76f0002f9 100644 --- a/plugins/github-actions/src/components/BuildListTable/BuildListTable.tsx +++ b/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx @@ -19,20 +19,18 @@ import RetryIcon from '@material-ui/icons/Replay'; import GitHubIcon from '@material-ui/icons/GitHub'; import { Link as RouterLink } from 'react-router-dom'; import { - StatusError, - StatusWarning, StatusOK, StatusPending, StatusRunning, Table, TableColumn, } from '@backstage/core'; -import { useBuilds } from './useBuilds'; +import { useWorkflowRuns } from './useWorkflowRuns'; -export type Build = { +export type WorkflowRun = { id: string; - buildName: string; - buildUrl?: string; + message: string; + url?: string; source: { branchName: string; commit: { @@ -41,24 +39,20 @@ export type Build = { }; }; status: string; - onRestartClick: () => void; + onReRunClick: () => void; }; // retried, canceled, infrastructure_fail, timedout, not_run, running, failed, queued, scheduled, not_running, no_tests, fixed, success const getStatusComponent = (status: string | undefined = '') => { switch (status.toLowerCase()) { case 'queued': - case 'scheduled': return ; - case 'running': + case 'in_progress': return ; - case 'failed': - return ; - case 'success': + case 'completed': return ; - case 'canceled': default: - return ; + return ; } }; @@ -70,18 +64,21 @@ const generatedColumns: TableColumn[] = [ width: '150px', }, { - title: 'Build', - field: 'buildName', + title: 'Message', + field: 'message', highlight: true, - render: (row: Partial) => ( - - {row.buildName} + render: (row: Partial) => ( + + {row.message} ), }, { title: 'Source', - render: (row: Partial) => ( + render: (row: Partial) => ( <>

{row.source?.branchName}

{row.source?.commit.hash}

@@ -90,7 +87,7 @@ const generatedColumns: TableColumn[] = [ }, { title: 'Status', - render: (row: Partial) => ( + render: (row: Partial) => ( {getStatusComponent(row.status)} @@ -100,8 +97,8 @@ const generatedColumns: TableColumn[] = [ }, { title: 'Actions', - render: (row: Partial) => ( - + render: (row: Partial) => ( + ), @@ -112,7 +109,7 @@ const generatedColumns: TableColumn[] = [ type Props = { loading: boolean; retry: () => void; - builds?: Build[]; + runs?: WorkflowRun[]; projectName: string; page: number; onChangePage: (page: number) => void; @@ -121,13 +118,13 @@ type Props = { onChangePageSize: (pageSize: number) => void; }; -const BuildListTableView: FC = ({ +const WorkflowRunsTableView: FC = ({ projectName, loading, pageSize, page, retry, - builds, + runs, onChangePage, onChangePageSize, total, @@ -146,7 +143,7 @@ const BuildListTableView: FC = ({ onClick: () => retry(), }, ]} - data={builds ?? []} + data={runs ?? []} onChangePage={onChangePage} onChangeRowsPerPage={onChangePageSize} title={ @@ -161,19 +158,19 @@ const BuildListTableView: FC = ({ ); }; -export const BuildListTable = ({ +export const WorkflowRunsTable = ({ repo, owner, }: { repo: string; owner: string; }) => { - const [tableProps, { retry, setPage, setPageSize }] = useBuilds({ + const [tableProps, { retry, setPage, setPageSize }] = useWorkflowRuns({ repo, owner, }); return ( - {}; + const reRunWorkflow = async () => {}; - const { loading, value: builds, retry } = useAsyncRetry(async () => { + const { loading, value: runs, retry } = useAsyncRetry< + WorkflowRun[] + >(async () => { const token = await auth.getAccessToken(['repo', 'user']); return ( @@ -38,19 +48,25 @@ export function useBuilds({ repo, owner }: { repo: string; owner: string }) { // GitHub API pagination count starts from 1 .listWorkflowRuns({ token, owner, repo, pageSize, page: page + 1 }) .then( - (allBuilds: ActionsListWorkflowRunsForRepoResponseData): Build[] => { - setTotal(allBuilds.total_count); + ( + workflowRunsData: ActionsListWorkflowRunsForRepoResponseData, + ): WorkflowRun[] => { + setTotal(workflowRunsData.total_count); // Transformation here - return allBuilds.workflow_runs.map(run => ({ - buildName: run.head_commit.message, + return workflowRunsData.workflow_runs.map(run => ({ + message: run.head_commit.message, id: `${run.id}`, - onRestartClick: () => { - api.reRunWorkflow({ - token, - owner, - repo, - runId: run.id, - }); + onReRunClick: async () => { + try { + await api.reRunWorkflow({ + token, + owner, + repo, + runId: run.id, + }); + } catch (e) { + errorApi.post(e); + } }, source: { branchName: run.head_branch, @@ -63,7 +79,7 @@ export function useBuilds({ repo, owner }: { repo: string; owner: string }) { }, }, status: run.status, - buildUrl: run.url, + url: run.url, })); }, ) @@ -76,15 +92,15 @@ export function useBuilds({ repo, owner }: { repo: string; owner: string }) { page, pageSize, loading, - builds, + runs, projectName, total, }, { - builds, + runs, setPage, setPageSize, - restartBuild, + reRunWorkflow, retry, }, ] as const; diff --git a/plugins/github-actions/src/components/types.ts b/plugins/github-actions/src/components/types.ts new file mode 100644 index 0000000000..3174cd23c0 --- /dev/null +++ b/plugins/github-actions/src/components/types.ts @@ -0,0 +1,45 @@ +/* + * 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 type Step = { + name: string; + status: string; + conclusion: string; + number: number; // starts from 1 + started_at: string; + completed_at: string; +}; + +export type Job = { + html_url: string; + status: string; + conclusion: string; + started_at: string; + completed_at: string; + name: string; + steps: Step[]; +}; + +export type Jobs = { + total_count: number; + jobs: Job[]; +}; + +export enum BuildStatus { + 'success', + 'failure', + 'pending', + 'running', +} diff --git a/plugins/github-actions/src/plugin.ts b/plugins/github-actions/src/plugin.ts index b728296cbc..7faee4e624 100644 --- a/plugins/github-actions/src/plugin.ts +++ b/plugins/github-actions/src/plugin.ts @@ -15,8 +15,8 @@ */ import { createPlugin, createRouteRef } from '@backstage/core'; -import { BuildDetailsPage } from './components/BuildDetailsPage'; -import { BuildListPage } from './components/BuildListPage'; +import { WorkflowRunDetailsPage } from './components/WorkflowRunDetailsPage'; +import { WorkflowRunsPage } from './components/WorkflowRunsPage'; // TODO(freben): This is just a demo route for now export const rootRouteRef = createRouteRef({ @@ -24,14 +24,14 @@ export const rootRouteRef = createRouteRef({ title: 'GitHub Actions', }); export const buildRouteRef = createRouteRef({ - path: '/github-actions/build/:id', - title: 'GitHub Actions Build', + path: '/github-actions/workflow-run/:id', + title: 'GitHub Actions Workflow Run', }); export const plugin = createPlugin({ id: 'github-actions', register({ router }) { - router.addRoute(rootRouteRef, BuildListPage); - router.addRoute(buildRouteRef, BuildDetailsPage); + router.addRoute(rootRouteRef, WorkflowRunsPage); + router.addRoute(buildRouteRef, WorkflowRunDetailsPage); }, }); diff --git a/yarn.lock b/yarn.lock index 6c0ff99388..8b2af1f211 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13075,6 +13075,11 @@ moment@2.26.0, moment@^2.25.3, moment@^2.26.0: resolved "https://registry.npmjs.org/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a" integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw== +moment@^2.27.0: + version "2.27.0" + resolved "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d" + integrity sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ== + monaco-editor@^0.20.0: version "0.20.0" resolved "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.20.0.tgz#5d5009343a550124426cb4d965a4d27a348b4dea" From b4e8a798b6284c9f5ced09fa0c516de789d9472e Mon Sep 17 00:00:00 2001 From: Nikita Nek Dudnik Date: Thu, 23 Jul 2020 10:15:14 +0200 Subject: [PATCH 02/10] fix: PR comments --- app-config.yaml | 4 +- .../WorkflowRunDetailsPage.tsx | 211 +++++++++++------- .../WorkflowRunStatusIcon.tsx | 36 +++ .../index.ts | 2 +- .../WorkflowRunStatusIndicator.tsx | 79 ------- .../WorkflowRunsTable/WorkflowRunsTable.tsx | 33 +-- 6 files changed, 173 insertions(+), 192 deletions(-) create mode 100644 plugins/github-actions/src/components/WorkflowRunStatusIcon/WorkflowRunStatusIcon.tsx rename plugins/github-actions/src/components/{WorkflowRunStatusIndicator => WorkflowRunStatusIcon}/index.ts (88%) delete mode 100644 plugins/github-actions/src/components/WorkflowRunStatusIndicator/WorkflowRunStatusIndicator.tsx diff --git a/app-config.yaml b/app-config.yaml index 7dacdc56ac..9440c57854 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -21,8 +21,8 @@ organization: name: Spotify github-actions: - owner: CircleCITest3 - repo: try-ssr + owner: spotify + repo: backstage techdocs: storageUrl: https://techdocs-mock-sites.storage.googleapis.com diff --git a/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx b/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx index 0bf72c77fd..6bda0f50b8 100644 --- a/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx +++ b/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx @@ -30,20 +30,30 @@ import { ExpansionPanelDetails, ExpansionPanel, ExpansionPanelSummary, - ListItem, - List, ListItemText, CircularProgress, + Grid, } from '@material-ui/core'; import moment from 'moment'; import React from 'react'; -import { Link, useApi, configApiRef } from '@backstage/core'; +import { + Link, + useApi, + configApiRef, + Page, + Header, + HeaderLabel, + Content, + ContentHeader, + SupportButton, + pageTheme, +} from '@backstage/core'; import { Job, Step, Jobs } from '../types'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; -import { WorkflowRunStatusIndicator } from '../WorkflowRunStatusIndicator'; import { useWorkflowRunsDetails } from './useWorkflowRunsDetails'; import { useWorkflowRunJobs } from './useWorkflowRunJobs'; +import { WorkflowRunStatusIcon } from '../WorkflowRunStatusIcon/WorkflowRunStatusIcon'; const useStyles = makeStyles(theme => ({ root: { @@ -92,12 +102,18 @@ const getElapsedTime = (start: string, end: string) => { const StepView = ({ step }: { step: Step }) => { return ( - - - + + + + + + + {step.status} + + ); }; @@ -121,11 +137,13 @@ const JobListItem = ({ job, className }: { job: Job; className: string }) => { - - {job.steps.map((step: Step) => ( - - ))} - + + + {job.steps.map((step: Step) => ( + + ))} +
+
); @@ -154,75 +172,98 @@ export const WorkflowRunDetailsPage = () => { } return ( -
- - - - < - - - Workflow Run Details - - - - - - - Branch - - {details.value?.head_branch} - - - - Message - - {details.value?.head_commit.message} - - - - Commit ID - - {details.value?.head_commit.id} - - - - Status - - - - - - - - Author - - {`${details.value?.head_commit.author.name} (${details.value?.head_commit.author.email})`} - - - - Links - - - {details.value?.html_url && ( - - )} - - - - - Jobs - {jobs.loading ? ( - - ) : ( - - )} - - - -
-
-
+ +
+ + +
+ + + + This plugin allows you to view and interact with your builds within + the GitHub Actions environment. + + + + +
+ + + + < Back + + + + + + + + + Branch + + {details.value?.head_branch} + + + + Message + + + {details.value?.head_commit.message} + + + + + Commit ID + + {details.value?.head_commit.id} + + + + Status + + + {' '} + {details.value?.status.toUpperCase()} + + + + + Author + + {`${details.value?.head_commit.author.name} (${details.value?.head_commit.author.email})`} + + + + Links + + + {details.value?.html_url && ( + + )} + + + + + Jobs + {jobs.loading ? ( + + ) : ( + + )} + + + +
+
+
+
+
+
+
); }; diff --git a/plugins/github-actions/src/components/WorkflowRunStatusIcon/WorkflowRunStatusIcon.tsx b/plugins/github-actions/src/components/WorkflowRunStatusIcon/WorkflowRunStatusIcon.tsx new file mode 100644 index 0000000000..645224ad24 --- /dev/null +++ b/plugins/github-actions/src/components/WorkflowRunStatusIcon/WorkflowRunStatusIcon.tsx @@ -0,0 +1,36 @@ +/* + * 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 { StatusPending, StatusRunning, StatusOK } from '@backstage/core'; +import React from 'react'; + +export const WorkflowRunStatusIcon = ({ + status, +}: { + status: string | undefined; +}) => { + if (status === undefined) return null; + switch (status.toLowerCase()) { + case 'queued': + return ; + case 'in_progress': + return ; + case 'completed': + return ; + default: + return ; + } +}; diff --git a/plugins/github-actions/src/components/WorkflowRunStatusIndicator/index.ts b/plugins/github-actions/src/components/WorkflowRunStatusIcon/index.ts similarity index 88% rename from plugins/github-actions/src/components/WorkflowRunStatusIndicator/index.ts rename to plugins/github-actions/src/components/WorkflowRunStatusIcon/index.ts index 463970a30c..05fff3f46d 100644 --- a/plugins/github-actions/src/components/WorkflowRunStatusIndicator/index.ts +++ b/plugins/github-actions/src/components/WorkflowRunStatusIcon/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { WorkflowRunStatusIndicator } from './WorkflowRunStatusIndicator'; +export { WorkflowRunStatusIcon } from './WorkflowRunStatusIcon'; diff --git a/plugins/github-actions/src/components/WorkflowRunStatusIndicator/WorkflowRunStatusIndicator.tsx b/plugins/github-actions/src/components/WorkflowRunStatusIndicator/WorkflowRunStatusIndicator.tsx deleted file mode 100644 index a22c60cdcb..0000000000 --- a/plugins/github-actions/src/components/WorkflowRunStatusIndicator/WorkflowRunStatusIndicator.tsx +++ /dev/null @@ -1,79 +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 { IconComponent } from '@backstage/core'; -import { makeStyles, Theme, Typography } from '@material-ui/core'; -import ProgressIcon from '@material-ui/icons/Autorenew'; -import SuccessIcon from '@material-ui/icons/CheckCircle'; -import UnknownIcon from '@material-ui/icons/Help'; -import React from 'react'; - -type Props = { - status?: string; -}; - -type StatusStyle = { - icon: IconComponent; - color: string; -}; - -const styles: { [key: string]: StatusStyle } = { - unknown: { - icon: UnknownIcon, - color: '#f49b20', - }, - completed: { - icon: SuccessIcon, - color: '#1db855', - }, - queued: { - icon: UnknownIcon, - color: '#5BC0DE', - }, - in_progress: { - icon: ProgressIcon, - color: '#BEBEBE', - }, -}; - -const getIconStyle = (status?: string): StatusStyle => { - return styles[status ?? 'unknown'] ?? styles.unknown; -}; - -const useStyles = makeStyles({ - icon: style => ({ - color: style.color, - }), -}); - -export const WorkflowRunStatusIndicator = ({ status }: Props) => { - const style = getIconStyle(status); - const classes = useStyles(style); - const Icon = style.icon; - - return ( - -  {`${status}`} - - ); -}; diff --git a/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx b/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx index a76f0002f9..4c54d12121 100644 --- a/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx +++ b/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx @@ -18,14 +18,9 @@ import { Link, Typography, Box, IconButton } from '@material-ui/core'; import RetryIcon from '@material-ui/icons/Replay'; import GitHubIcon from '@material-ui/icons/GitHub'; import { Link as RouterLink } from 'react-router-dom'; -import { - StatusOK, - StatusPending, - StatusRunning, - Table, - TableColumn, -} from '@backstage/core'; +import { Table, TableColumn } from '@backstage/core'; import { useWorkflowRuns } from './useWorkflowRuns'; +import { WorkflowRunStatusIcon } from '../WorkflowRunStatusIcon'; export type WorkflowRun = { id: string; @@ -42,20 +37,6 @@ export type WorkflowRun = { onReRunClick: () => void; }; -// retried, canceled, infrastructure_fail, timedout, not_run, running, failed, queued, scheduled, not_running, no_tests, fixed, success -const getStatusComponent = (status: string | undefined = '') => { - switch (status.toLowerCase()) { - case 'queued': - return ; - case 'in_progress': - return ; - case 'completed': - return ; - default: - return ; - } -}; - const generatedColumns: TableColumn[] = [ { title: 'ID', @@ -79,19 +60,21 @@ const generatedColumns: TableColumn[] = [ { title: 'Source', render: (row: Partial) => ( - <> +

{row.source?.branchName}

{row.source?.commit.hash}

- +
), }, { title: 'Status', render: (row: Partial) => ( - {getStatusComponent(row.status)} + - {row.status} + + {row.status} + ), }, From 9bdb010432b9ad8a149d1f9bf4e819b91053aa4d Mon Sep 17 00:00:00 2001 From: Nikita Nek Dudnik Date: Thu, 23 Jul 2020 19:35:00 +0200 Subject: [PATCH 03/10] Merge --- plugins/github-actions/package.json | 1 + .../WorkflowRunsTable/useWorkflowRuns.ts | 8 +- yarn.lock | 127 ++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index ce83f44e5f..eccc1449f9 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -25,6 +25,7 @@ "@backstage/core": "^0.1.1-alpha.16", "@backstage/core-api": "^0.1.1-alpha.16", "@backstage/theme": "^0.1.1-alpha.16", + "@backstage/plugin-catalog": "^0.1.1-alpha.16", "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", diff --git a/plugins/github-actions/src/components/WorkflowRunsTable/useWorkflowRuns.ts b/plugins/github-actions/src/components/WorkflowRunsTable/useWorkflowRuns.ts index 62bffe122d..a2a3162bec 100644 --- a/plugins/github-actions/src/components/WorkflowRunsTable/useWorkflowRuns.ts +++ b/plugins/github-actions/src/components/WorkflowRunsTable/useWorkflowRuns.ts @@ -19,6 +19,7 @@ import { WorkflowRun } from './WorkflowRunsTable'; import { githubActionsApiRef } from '../../api/GithubActionsApi'; import { useApi, githubAuthApiRef, errorApiRef } from '@backstage/core'; import { ActionsListWorkflowRunsForRepoResponseData } from '@octokit/types'; +import { catalogApiRef } from '@backstage/plugin-catalog'; export function useWorkflowRuns({ repo, @@ -27,6 +28,7 @@ export function useWorkflowRuns({ repo: string; owner: string; }) { + const catalogApi = useApi(catalogApiRef); const api = useApi(githubActionsApiRef); const auth = useApi(githubAuthApiRef); @@ -42,7 +44,11 @@ export function useWorkflowRuns({ WorkflowRun[] >(async () => { const token = await auth.getAccessToken(['repo', 'user']); - + const entity = await catalogApi.getEntityByName({ + kind: 'Component', + name: 'backstage-site', + }); + console.log(entity); return ( api // GitHub API pagination count starts from 1 diff --git a/yarn.lock b/yarn.lock index 8b2af1f211..c662364db6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -939,6 +939,133 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@backstage/catalog-model@^0.1.1-alpha.15": + version "0.1.1-alpha.15" + resolved "https://registry.npmjs.org/@backstage/catalog-model/-/catalog-model-0.1.1-alpha.15.tgz#d1bb2eb53ff12af6868f49a24693fb2c0c209c78" + integrity sha512-nHfdeVpeyUpSyL4sjXRgCZ53ODP66o9Koc7oAXM2Gih07Z+thefIXDpY2bjWRcz+VLkVJJyVxRj/5VhrN2bukg== + dependencies: + "@backstage/config" "^0.1.1-alpha.13" + "@types/json-schema" "^7.0.5" + "@types/yup" "^0.28.2" + json-schema "^0.2.5" + lodash "^4.17.15" + uuid "^8.0.0" + yup "^0.29.1" + +"@backstage/core-api@^0.1.1-alpha.15": + version "0.1.1-alpha.15" + resolved "https://registry.npmjs.org/@backstage/core-api/-/core-api-0.1.1-alpha.15.tgz#c5d70339ee1b0646841c95f69665be9094b54331" + integrity sha512-U4MWV2MZS+0tEUod0HaugYEbsBB2VLG2t41UXm2kYYhLc3JfCr99DRR2KXJSyl2To6fc9//l7IMg4efpfhpWYw== + dependencies: + "@backstage/config" "^0.1.1-alpha.13" + "@backstage/theme" "^0.1.1-alpha.15" + "@material-ui/core" "^4.9.1" + "@material-ui/icons" "^4.9.1" + "@types/react" "^16.9" + prop-types "^15.7.2" + react "^16.12.0" + react-router-dom "6.0.0-beta.0" + react-use "^14.2.0" + zen-observable "^0.8.15" + +"@backstage/core@^0.1.1-alpha.15": + version "0.1.1-alpha.15" + resolved "https://registry.npmjs.org/@backstage/core/-/core-0.1.1-alpha.15.tgz#bb998f84643d6e6c88dfe6e8c3b1855cc35d7ed9" + integrity sha512-DaKwwj+mS5fa1Wq4R9+jbWMJdPj0JXv+Rzyy1iFKq9Ng9z1Rwum8h3R+q/DlPwSdSNlWaTdikZyw1C43Z+3FYw== + dependencies: + "@backstage/config" "^0.1.1-alpha.13" + "@backstage/core-api" "^0.1.1-alpha.15" + "@backstage/theme" "^0.1.1-alpha.15" + "@material-ui/core" "^4.9.1" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.45" + "@types/react" "^16.9" + "@types/react-sparklines" "^1.7.0" + classnames "^2.2.6" + clsx "^1.1.0" + lodash "^4.17.15" + material-table "1.62.x" + prop-types "^15.7.2" + rc-progress "^3.0.0" + react "^16.12.0" + react-dom "^16.12.0" + react-helmet "6.1.0" + react-hook-form "^5.7.2" + react-router "6.0.0-beta.0" + react-router-dom "6.0.0-beta.0" + react-sparklines "^1.7.0" + react-syntax-highlighter "^12.2.1" + react-use "^14.2.0" + +"@backstage/plugin-catalog@^0.1.1-alpha.15": + version "0.1.1-alpha.15" + resolved "https://registry.npmjs.org/@backstage/plugin-catalog/-/plugin-catalog-0.1.1-alpha.15.tgz#438b2bf035ea2acf21cddda9c33363ffc6629b55" + integrity sha512-4wGs4AROaF+nq7DsQzpgdtifwjQnTfWRO541zSNh117qJe7yIHXzY+XVAzQ5ct421hYXn7ofxwKUsGI4hYgVRg== + dependencies: + "@backstage/catalog-model" "^0.1.1-alpha.15" + "@backstage/core" "^0.1.1-alpha.15" + "@backstage/plugin-scaffolder" "^0.1.1-alpha.15" + "@backstage/plugin-sentry" "^0.1.1-alpha.15" + "@backstage/theme" "^0.1.1-alpha.15" + "@material-ui/core" "^4.9.1" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.45" + moment "^2.26.0" + react "^16.13.1" + react-dom "^16.13.1" + react-router "6.0.0-beta.0" + react-router-dom "6.0.0-beta.0" + react-use "^14.2.0" + swr "^0.2.2" + +"@backstage/plugin-scaffolder@^0.1.1-alpha.15": + version "0.1.1-alpha.15" + resolved "https://registry.npmjs.org/@backstage/plugin-scaffolder/-/plugin-scaffolder-0.1.1-alpha.15.tgz#935d21a5c815c530bd4fed89b9c1d4cb983a57bb" + integrity sha512-+HZ/aPlMcacuT7JYN2hYlZqWA8jYoAEoh7laBripm1nIxhxCLi4BuPX4X0W73a3cpCv+MYefvUq0g7yYDJvQJw== + dependencies: + "@backstage/catalog-model" "^0.1.1-alpha.15" + "@backstage/core" "^0.1.1-alpha.15" + "@backstage/plugin-catalog" "^0.1.1-alpha.15" + "@backstage/theme" "^0.1.1-alpha.15" + "@material-ui/core" "^4.9.1" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.45" + "@rjsf/core" "^2.1.0" + "@rjsf/material-ui" "^2.1.0" + classnames "^2.2.6" + moment "^2.26.0" + react "^16.13.1" + react-dom "^16.13.1" + react-lazylog "^4.5.2" + react-router "6.0.0-beta.0" + react-router-dom "6.0.0-beta.0" + react-use "^14.2.0" + swr "^0.2.2" + +"@backstage/plugin-sentry@^0.1.1-alpha.15": + version "0.1.1-alpha.15" + resolved "https://registry.npmjs.org/@backstage/plugin-sentry/-/plugin-sentry-0.1.1-alpha.15.tgz#8a507f7143766582dc5bed7a9ee09ea256cbdd0d" + integrity sha512-wBOSqOvF6qedZ9gAYR3aQ8rqbgCUQz5WA5Mw7KZVa0FeWdjLIKYsDl0oI6EE3EQZV9iZef6kzY7W/8gjJV3fHQ== + dependencies: + "@backstage/core" "^0.1.1-alpha.15" + "@backstage/theme" "^0.1.1-alpha.15" + "@material-ui/core" "^4.9.1" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.45" + "@types/react" "^16.9" + react "^16.13.1" + react-dom "^16.13.1" + react-sparklines "^1.7.0" + react-use "^14.2.0" + timeago.js "^4.0.2" + +"@backstage/theme@^0.1.1-alpha.15": + version "0.1.1-alpha.15" + resolved "https://registry.npmjs.org/@backstage/theme/-/theme-0.1.1-alpha.15.tgz#b30ec50ef0aba672f3b6f6ed3fb0209ec2990008" + integrity sha512-cyE3jj3Oynd8NHYSVm7H1Dhz573oe7V6vOAetdoqt7fX7I28onoSrUzv8x9eVM8uX4FiMck8PISPVKPGddCDZQ== + dependencies: + "@material-ui/core" "^4.9.1" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" From 25e41d227436cabec1f0786158a10de53b41f9c6 Mon Sep 17 00:00:00 2001 From: Nikita Nek Dudnik Date: Thu, 23 Jul 2020 21:05:55 +0200 Subject: [PATCH 04/10] feat: use annotation to get project name --- .../examples/shuffle-api-component.yaml | 2 + .../src/api/GithubActionsClient.ts | 2 +- plugins/github-actions/src/api/types.ts | 228 ++---------------- .../WorkflowRunDetailsPage.tsx | 28 +-- .../useWorkflowRunJobs.ts | 2 +- .../useWorkflowRunsDetails.ts | 4 +- .../WorkflowRunsPage/WorkflowRunsPage.tsx | 9 +- .../WorkflowRunsTable/WorkflowRunsTable.tsx | 28 +-- .../WorkflowRunsTable/useWorkflowRuns.ts | 31 +-- .../{types.ts => useProjectName.ts} | 40 +-- .../react-ssr-template/template.yaml | 17 +- yarn.lock | 127 ---------- 12 files changed, 95 insertions(+), 423 deletions(-) rename plugins/github-actions/src/components/{types.ts => useProjectName.ts} (54%) diff --git a/packages/catalog-model/examples/shuffle-api-component.yaml b/packages/catalog-model/examples/shuffle-api-component.yaml index 275c48d6ba..1726f7aec7 100644 --- a/packages/catalog-model/examples/shuffle-api-component.yaml +++ b/packages/catalog-model/examples/shuffle-api-component.yaml @@ -3,6 +3,8 @@ kind: Component metadata: name: shuffle-api description: Shuffle API + annotations: + backstage.io/github-actions-id: 'spotify/backstage' spec: type: service lifecycle: production diff --git a/plugins/github-actions/src/api/GithubActionsClient.ts b/plugins/github-actions/src/api/GithubActionsClient.ts index 6e6f1cb1e2..a96f5341fd 100644 --- a/plugins/github-actions/src/api/GithubActionsClient.ts +++ b/plugins/github-actions/src/api/GithubActionsClient.ts @@ -23,7 +23,7 @@ import { } from '@octokit/types'; export class GithubActionsClient implements GithubActionsApi { - reRunWorkflow({ + async reRunWorkflow({ token, owner, repo, diff --git a/plugins/github-actions/src/api/types.ts b/plugins/github-actions/src/api/types.ts index 8a7b2ca548..cd74a20cda 100644 --- a/plugins/github-actions/src/api/types.ts +++ b/plugins/github-actions/src/api/types.ts @@ -14,211 +14,33 @@ * limitations under the License. */ -export enum BuildStatus { - Null, - Success, - Failure, - Pending, - Running, -} - -export type Build = { - commitId: string; - message: string; - branch: string; - status: BuildStatus; - uri: string; -}; - -export type BuildDetails = { - build: Build; - author: string; - logUrl: string; - overviewUrl: string; -}; - -export interface Author { +export type Step = { name: string; - email: string; -} - -export interface Committer { - name: string; - email: string; -} - -export interface HeadCommit { - id: string; - tree_id: string; - message: string; - timestamp: Date; - author: Author; - committer: Committer; -} - -export interface Owner { - login: string; - id: number; - node_id: string; - avatar_url: string; - gravatar_id: string; - url: string; - html_url: string; - followers_url: string; - following_url: string; - gists_url: string; - starred_url: string; - subscriptions_url: string; - organizations_url: string; - repos_url: string; - events_url: string; - received_events_url: string; - type: string; - site_admin: boolean; -} - -export interface Repository { - id: number; - node_id: string; - name: string; - full_name: string; - private: boolean; - owner: Owner; - html_url: string; - description?: any; - fork: boolean; - url: string; - forks_url: string; - keys_url: string; - collaborators_url: string; - teams_url: string; - hooks_url: string; - issue_events_url: string; - events_url: string; - assignees_url: string; - branches_url: string; - tags_url: string; - blobs_url: string; - git_tags_url: string; - git_refs_url: string; - trees_url: string; - statuses_url: string; - languages_url: string; - stargazers_url: string; - contributors_url: string; - subscribers_url: string; - subscription_url: string; - commits_url: string; - git_commits_url: string; - comments_url: string; - issue_comment_url: string; - contents_url: string; - compare_url: string; - merges_url: string; - archive_url: string; - downloads_url: string; - issues_url: string; - pulls_url: string; - milestones_url: string; - notifications_url: string; - labels_url: string; - releases_url: string; - deployments_url: string; -} - -export interface Owner2 { - login: string; - id: number; - node_id: string; - avatar_url: string; - gravatar_id: string; - url: string; - html_url: string; - followers_url: string; - following_url: string; - gists_url: string; - starred_url: string; - subscriptions_url: string; - organizations_url: string; - repos_url: string; - events_url: string; - received_events_url: string; - type: string; - site_admin: boolean; -} - -export interface HeadRepository { - id: number; - node_id: string; - name: string; - full_name: string; - private: boolean; - owner: Owner2; - html_url: string; - description?: any; - fork: boolean; - url: string; - forks_url: string; - keys_url: string; - collaborators_url: string; - teams_url: string; - hooks_url: string; - issue_events_url: string; - events_url: string; - assignees_url: string; - branches_url: string; - tags_url: string; - blobs_url: string; - git_tags_url: string; - git_refs_url: string; - trees_url: string; - statuses_url: string; - languages_url: string; - stargazers_url: string; - contributors_url: string; - subscribers_url: string; - subscription_url: string; - commits_url: string; - git_commits_url: string; - comments_url: string; - issue_comment_url: string; - contents_url: string; - compare_url: string; - merges_url: string; - archive_url: string; - downloads_url: string; - issues_url: string; - pulls_url: string; - milestones_url: string; - notifications_url: string; - labels_url: string; - releases_url: string; - deployments_url: string; -} - -export interface WorkflowRun { - id: number; - node_id: string; - head_branch: string; - head_sha: string; - run_number: number; - event: string; status: string; conclusion: string; - workflow_id: number; - url: string; + number: number; // starts from 1 + started_at: string; + completed_at: string; +}; + +export type Job = { html_url: string; - pull_requests: any[]; - created_at: Date; - updated_at: Date; - jobs_url: string; - logs_url: string; - check_suite_url: string; - artifacts_url: string; - cancel_url: string; - rerun_url: string; - workflow_url: string; - head_commit: HeadCommit; - repository: Repository; - head_repository: HeadRepository; + status: string; + conclusion: string; + started_at: string; + completed_at: string; + name: string; + steps: Step[]; +}; + +export type Jobs = { + total_count: number; + jobs: Job[]; +}; + +export enum BuildStatus { + 'success', + 'failure', + 'pending', + 'running', } diff --git a/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx b/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx index 6bda0f50b8..a8ddcfef12 100644 --- a/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx +++ b/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx @@ -33,14 +33,13 @@ import { ListItemText, CircularProgress, Grid, + Breadcrumbs, } from '@material-ui/core'; import moment from 'moment'; import React from 'react'; import { Link, - useApi, - configApiRef, Page, Header, HeaderLabel, @@ -49,11 +48,12 @@ import { SupportButton, pageTheme, } from '@backstage/core'; -import { Job, Step, Jobs } from '../types'; +import { Job, Step, Jobs } from '../../api/types'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { useWorkflowRunsDetails } from './useWorkflowRunsDetails'; import { useWorkflowRunJobs } from './useWorkflowRunJobs'; import { WorkflowRunStatusIcon } from '../WorkflowRunStatusIcon/WorkflowRunStatusIcon'; +import { useProjectName } from '../useProjectName'; const useStyles = makeStyles(theme => ({ root: { @@ -153,9 +153,12 @@ const JobListItem = ({ job, className }: { job: Job; className: string }) => { * A component for Jobs visualization. Jobs are a property of a Workflow Run. */ export const WorkflowRunDetailsPage = () => { - const configApi = useApi(configApiRef); - const repo = configApi.getString('github-actions.repo'); - const owner = configApi.getString('github-actions.owner'); + const [owner, repo] = ( + useProjectName({ + kind: 'Component', + name: 'backstage-site', + }) ?? '/' + ).split('/'); const details = useWorkflowRunsDetails(repo, owner); const jobs = useWorkflowRunJobs(details.value?.jobs_url); @@ -175,7 +178,7 @@ export const WorkflowRunDetailsPage = () => {
@@ -187,16 +190,13 @@ export const WorkflowRunDetailsPage = () => { the GitHub Actions environment. + + Workflow runs + Workflow run details +
- - - - < Back - - - diff --git a/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunJobs.ts b/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunJobs.ts index c941ed6389..d4c09abf7d 100644 --- a/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunJobs.ts +++ b/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunJobs.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { useAsync } from 'react-use'; -import { Jobs } from '../types'; +import { Jobs } from '../../api/types'; export const useWorkflowRunJobs = (jobsUrl?: string) => { const jobs = useAsync(async () => { diff --git a/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunsDetails.ts b/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunsDetails.ts index 088c286d94..623f55eea6 100644 --- a/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunsDetails.ts +++ b/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunsDetails.ts @@ -23,13 +23,13 @@ export const useWorkflowRunsDetails = (repo: string, owner: string) => { const auth = useApi(githubAuthApiRef); const { id } = useParams(); const details = useAsync(async () => { - const token = await auth.getAccessToken(['repo', 'user']); + const token = await auth.getAccessToken(['repo']); return api.getWorkflowRun({ token, owner, repo, id: parseInt(id, 10), }); - }, [id]); + }, [repo, owner, id]); return details; }; diff --git a/plugins/github-actions/src/components/WorkflowRunsPage/WorkflowRunsPage.tsx b/plugins/github-actions/src/components/WorkflowRunsPage/WorkflowRunsPage.tsx index a4cb576468..b75a70f326 100644 --- a/plugins/github-actions/src/components/WorkflowRunsPage/WorkflowRunsPage.tsx +++ b/plugins/github-actions/src/components/WorkflowRunsPage/WorkflowRunsPage.tsx @@ -22,8 +22,6 @@ import { Content, ContentHeader, SupportButton, - useApi, - configApiRef, } from '@backstage/core'; import { Grid } from '@material-ui/core'; import React from 'react'; @@ -31,14 +29,11 @@ import React from 'react'; import { WorkflowRunsTable } from '../WorkflowRunsTable'; export const WorkflowRunsPage = () => { - const configApi = useApi(configApiRef); - const repo = configApi.getString('github-actions.repo'); - const owner = configApi.getString('github-actions.owner'); return (
@@ -52,7 +47,7 @@ export const WorkflowRunsPage = () => { - + diff --git a/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx b/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx index 4c54d12121..313a51e28a 100644 --- a/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx +++ b/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx @@ -14,13 +14,14 @@ * limitations under the License. */ import React, { FC } from 'react'; -import { Link, Typography, Box, IconButton } from '@material-ui/core'; +import { Link, Typography, Box, IconButton, Tooltip } from '@material-ui/core'; import RetryIcon from '@material-ui/icons/Replay'; import GitHubIcon from '@material-ui/icons/GitHub'; import { Link as RouterLink } from 'react-router-dom'; import { Table, TableColumn } from '@backstage/core'; import { useWorkflowRuns } from './useWorkflowRuns'; import { WorkflowRunStatusIcon } from '../WorkflowRunStatusIcon'; +import SyncIcon from '@material-ui/icons/Sync'; export type WorkflowRun = { id: string; @@ -81,9 +82,11 @@ const generatedColumns: TableColumn[] = [ { title: 'Actions', render: (row: Partial) => ( - - - + + + + + ), width: '10%', }, @@ -120,8 +123,8 @@ const WorkflowRunsTableView: FC = ({ page={page} actions={[ { - icon: () => , - tooltip: 'Refresh Data', + icon: () => , + tooltip: 'Reload workflow runs', isFreeAction: true, onClick: () => retry(), }, @@ -141,17 +144,8 @@ const WorkflowRunsTableView: FC = ({ ); }; -export const WorkflowRunsTable = ({ - repo, - owner, -}: { - repo: string; - owner: string; -}) => { - const [tableProps, { retry, setPage, setPageSize }] = useWorkflowRuns({ - repo, - owner, - }); +export const WorkflowRunsTable = () => { + const [tableProps, { retry, setPage, setPageSize }] = useWorkflowRuns(); return ( {}; - + const projectName = useProjectName({ + kind: 'Component', + name: 'backstage-site', + }); const { loading, value: runs, retry } = useAsyncRetry< WorkflowRun[] >(async () => { - const token = await auth.getAccessToken(['repo', 'user']); - const entity = await catalogApi.getEntityByName({ - kind: 'Component', - name: 'backstage-site', - }); - console.log(entity); + const token = await auth.getAccessToken(['repo']); + const [owner, repo] = (projectName ?? '/').split('/'); return ( api // GitHub API pagination count starts from 1 @@ -90,23 +81,21 @@ export function useWorkflowRuns({ }, ) ); - }, [page, pageSize]); + }, [page, pageSize, projectName]); - const projectName = `${owner}/${repo}`; return [ { page, pageSize, loading, runs, - projectName, + projectName: projectName ?? '', total, }, { runs, setPage, setPageSize, - reRunWorkflow, retry, }, ] as const; diff --git a/plugins/github-actions/src/components/types.ts b/plugins/github-actions/src/components/useProjectName.ts similarity index 54% rename from plugins/github-actions/src/components/types.ts rename to plugins/github-actions/src/components/useProjectName.ts index 3174cd23c0..d6fe9bd35d 100644 --- a/plugins/github-actions/src/components/types.ts +++ b/plugins/github-actions/src/components/useProjectName.ts @@ -13,33 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export type Step = { - name: string; - status: string; - conclusion: string; - number: number; // starts from 1 - started_at: string; - completed_at: string; -}; -export type Job = { - html_url: string; - status: string; - conclusion: string; - started_at: string; - completed_at: string; - name: string; - steps: Step[]; -}; +import { useAsync } from 'react-use'; +import { catalogApiRef, EntityCompoundName } from '@backstage/plugin-catalog'; +import { useApi } from '@backstage/core'; -export type Jobs = { - total_count: number; - jobs: Job[]; -}; +export const useProjectName = (name: EntityCompoundName) => { + const catalogApi = useApi(catalogApiRef); -export enum BuildStatus { - 'success', - 'failure', - 'pending', - 'running', -} + const { value } = useAsync(async () => { + const entity = await catalogApi.getEntityByName(name); + return ( + entity?.metadata.annotations?.['backstage.io/github-actions-id'] ?? '' + ); + }); + return value; +}; diff --git a/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml b/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml index 71f75c7695..dc9fb22aa8 100644 --- a/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml @@ -13,7 +13,7 @@ spec: type: website path: '.' schema: - required: + required: - component_id - description properties: @@ -22,7 +22,18 @@ spec: type: string description: Unique name of the component description: - title: Description + title: Description type: string description: Description of the component - +--- +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-site + description: backstage.io + annotations: + backstage.io/github-actions-id: 'spotify/backstage' +spec: + type: website + lifecycle: production + owner: guest diff --git a/yarn.lock b/yarn.lock index c662364db6..8b2af1f211 100644 --- a/yarn.lock +++ b/yarn.lock @@ -939,133 +939,6 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" -"@backstage/catalog-model@^0.1.1-alpha.15": - version "0.1.1-alpha.15" - resolved "https://registry.npmjs.org/@backstage/catalog-model/-/catalog-model-0.1.1-alpha.15.tgz#d1bb2eb53ff12af6868f49a24693fb2c0c209c78" - integrity sha512-nHfdeVpeyUpSyL4sjXRgCZ53ODP66o9Koc7oAXM2Gih07Z+thefIXDpY2bjWRcz+VLkVJJyVxRj/5VhrN2bukg== - dependencies: - "@backstage/config" "^0.1.1-alpha.13" - "@types/json-schema" "^7.0.5" - "@types/yup" "^0.28.2" - json-schema "^0.2.5" - lodash "^4.17.15" - uuid "^8.0.0" - yup "^0.29.1" - -"@backstage/core-api@^0.1.1-alpha.15": - version "0.1.1-alpha.15" - resolved "https://registry.npmjs.org/@backstage/core-api/-/core-api-0.1.1-alpha.15.tgz#c5d70339ee1b0646841c95f69665be9094b54331" - integrity sha512-U4MWV2MZS+0tEUod0HaugYEbsBB2VLG2t41UXm2kYYhLc3JfCr99DRR2KXJSyl2To6fc9//l7IMg4efpfhpWYw== - dependencies: - "@backstage/config" "^0.1.1-alpha.13" - "@backstage/theme" "^0.1.1-alpha.15" - "@material-ui/core" "^4.9.1" - "@material-ui/icons" "^4.9.1" - "@types/react" "^16.9" - prop-types "^15.7.2" - react "^16.12.0" - react-router-dom "6.0.0-beta.0" - react-use "^14.2.0" - zen-observable "^0.8.15" - -"@backstage/core@^0.1.1-alpha.15": - version "0.1.1-alpha.15" - resolved "https://registry.npmjs.org/@backstage/core/-/core-0.1.1-alpha.15.tgz#bb998f84643d6e6c88dfe6e8c3b1855cc35d7ed9" - integrity sha512-DaKwwj+mS5fa1Wq4R9+jbWMJdPj0JXv+Rzyy1iFKq9Ng9z1Rwum8h3R+q/DlPwSdSNlWaTdikZyw1C43Z+3FYw== - dependencies: - "@backstage/config" "^0.1.1-alpha.13" - "@backstage/core-api" "^0.1.1-alpha.15" - "@backstage/theme" "^0.1.1-alpha.15" - "@material-ui/core" "^4.9.1" - "@material-ui/icons" "^4.9.1" - "@material-ui/lab" "4.0.0-alpha.45" - "@types/react" "^16.9" - "@types/react-sparklines" "^1.7.0" - classnames "^2.2.6" - clsx "^1.1.0" - lodash "^4.17.15" - material-table "1.62.x" - prop-types "^15.7.2" - rc-progress "^3.0.0" - react "^16.12.0" - react-dom "^16.12.0" - react-helmet "6.1.0" - react-hook-form "^5.7.2" - react-router "6.0.0-beta.0" - react-router-dom "6.0.0-beta.0" - react-sparklines "^1.7.0" - react-syntax-highlighter "^12.2.1" - react-use "^14.2.0" - -"@backstage/plugin-catalog@^0.1.1-alpha.15": - version "0.1.1-alpha.15" - resolved "https://registry.npmjs.org/@backstage/plugin-catalog/-/plugin-catalog-0.1.1-alpha.15.tgz#438b2bf035ea2acf21cddda9c33363ffc6629b55" - integrity sha512-4wGs4AROaF+nq7DsQzpgdtifwjQnTfWRO541zSNh117qJe7yIHXzY+XVAzQ5ct421hYXn7ofxwKUsGI4hYgVRg== - dependencies: - "@backstage/catalog-model" "^0.1.1-alpha.15" - "@backstage/core" "^0.1.1-alpha.15" - "@backstage/plugin-scaffolder" "^0.1.1-alpha.15" - "@backstage/plugin-sentry" "^0.1.1-alpha.15" - "@backstage/theme" "^0.1.1-alpha.15" - "@material-ui/core" "^4.9.1" - "@material-ui/icons" "^4.9.1" - "@material-ui/lab" "4.0.0-alpha.45" - moment "^2.26.0" - react "^16.13.1" - react-dom "^16.13.1" - react-router "6.0.0-beta.0" - react-router-dom "6.0.0-beta.0" - react-use "^14.2.0" - swr "^0.2.2" - -"@backstage/plugin-scaffolder@^0.1.1-alpha.15": - version "0.1.1-alpha.15" - resolved "https://registry.npmjs.org/@backstage/plugin-scaffolder/-/plugin-scaffolder-0.1.1-alpha.15.tgz#935d21a5c815c530bd4fed89b9c1d4cb983a57bb" - integrity sha512-+HZ/aPlMcacuT7JYN2hYlZqWA8jYoAEoh7laBripm1nIxhxCLi4BuPX4X0W73a3cpCv+MYefvUq0g7yYDJvQJw== - dependencies: - "@backstage/catalog-model" "^0.1.1-alpha.15" - "@backstage/core" "^0.1.1-alpha.15" - "@backstage/plugin-catalog" "^0.1.1-alpha.15" - "@backstage/theme" "^0.1.1-alpha.15" - "@material-ui/core" "^4.9.1" - "@material-ui/icons" "^4.9.1" - "@material-ui/lab" "4.0.0-alpha.45" - "@rjsf/core" "^2.1.0" - "@rjsf/material-ui" "^2.1.0" - classnames "^2.2.6" - moment "^2.26.0" - react "^16.13.1" - react-dom "^16.13.1" - react-lazylog "^4.5.2" - react-router "6.0.0-beta.0" - react-router-dom "6.0.0-beta.0" - react-use "^14.2.0" - swr "^0.2.2" - -"@backstage/plugin-sentry@^0.1.1-alpha.15": - version "0.1.1-alpha.15" - resolved "https://registry.npmjs.org/@backstage/plugin-sentry/-/plugin-sentry-0.1.1-alpha.15.tgz#8a507f7143766582dc5bed7a9ee09ea256cbdd0d" - integrity sha512-wBOSqOvF6qedZ9gAYR3aQ8rqbgCUQz5WA5Mw7KZVa0FeWdjLIKYsDl0oI6EE3EQZV9iZef6kzY7W/8gjJV3fHQ== - dependencies: - "@backstage/core" "^0.1.1-alpha.15" - "@backstage/theme" "^0.1.1-alpha.15" - "@material-ui/core" "^4.9.1" - "@material-ui/icons" "^4.9.1" - "@material-ui/lab" "4.0.0-alpha.45" - "@types/react" "^16.9" - react "^16.13.1" - react-dom "^16.13.1" - react-sparklines "^1.7.0" - react-use "^14.2.0" - timeago.js "^4.0.2" - -"@backstage/theme@^0.1.1-alpha.15": - version "0.1.1-alpha.15" - resolved "https://registry.npmjs.org/@backstage/theme/-/theme-0.1.1-alpha.15.tgz#b30ec50ef0aba672f3b6f6ed3fb0209ec2990008" - integrity sha512-cyE3jj3Oynd8NHYSVm7H1Dhz573oe7V6vOAetdoqt7fX7I28onoSrUzv8x9eVM8uX4FiMck8PISPVKPGddCDZQ== - dependencies: - "@material-ui/core" "^4.9.1" - "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" From c82c045ee842872d4dcd68ad8af36e6df2e2d577 Mon Sep 17 00:00:00 2001 From: Nikita Nek Dudnik Date: Fri, 24 Jul 2020 15:56:48 +0200 Subject: [PATCH 05/10] feat(github-actions): add a separate data mock --- app-config.yaml | 10 +++------- plugins/github-actions/package.json | 3 ++- .../WorkflowRunDetailsPage.tsx | 2 +- .../components/WorkflowRunsTable/useWorkflowRuns.ts | 2 +- .../react-ssr-template/template.yaml | 12 ------------ 5 files changed, 7 insertions(+), 22 deletions(-) diff --git a/app-config.yaml b/app-config.yaml index 9440c57854..35cc7b6e1a 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -11,19 +11,15 @@ backend: credentials: true proxy: - "/circleci/api": - target: "https://circleci.com/api/v1.1" + '/circleci/api': + target: 'https://circleci.com/api/v1.1' changeOrigin: true pathRewrite: - "^/proxy/circleci/api/": "/" + '^/proxy/circleci/api/': '/' organization: name: Spotify -github-actions: - owner: spotify - repo: backstage - techdocs: storageUrl: https://techdocs-mock-sites.storage.googleapis.com diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index eccc1449f9..3f3e154b7b 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -18,7 +18,8 @@ "diff": "backstage-cli plugin:diff", "prepack": "backstage-cli prepack", "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "clean": "backstage-cli clean", + "mock-data": "./scripts/mock-data.sh" }, "dependencies": { "@backstage/catalog-model": "^0.1.1-alpha.16", diff --git a/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx b/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx index a8ddcfef12..308ae297d8 100644 --- a/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx +++ b/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx @@ -156,7 +156,7 @@ export const WorkflowRunDetailsPage = () => { const [owner, repo] = ( useProjectName({ kind: 'Component', - name: 'backstage-site', + name: 'backstage', }) ?? '/' ).split('/'); const details = useWorkflowRunsDetails(repo, owner); diff --git a/plugins/github-actions/src/components/WorkflowRunsTable/useWorkflowRuns.ts b/plugins/github-actions/src/components/WorkflowRunsTable/useWorkflowRuns.ts index 753d08be54..4f72f88de0 100644 --- a/plugins/github-actions/src/components/WorkflowRunsTable/useWorkflowRuns.ts +++ b/plugins/github-actions/src/components/WorkflowRunsTable/useWorkflowRuns.ts @@ -33,7 +33,7 @@ export function useWorkflowRuns() { const projectName = useProjectName({ kind: 'Component', - name: 'backstage-site', + name: 'backstage', }); const { loading, value: runs, retry } = useAsyncRetry< WorkflowRun[] diff --git a/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml b/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml index dc9fb22aa8..ba0e877662 100644 --- a/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml @@ -25,15 +25,3 @@ spec: title: Description type: string description: Description of the component ---- -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: backstage-site - description: backstage.io - annotations: - backstage.io/github-actions-id: 'spotify/backstage' -spec: - type: website - lifecycle: production - owner: guest From c31b0e904998e5e3835f5b4d5c9372f1def4513a Mon Sep 17 00:00:00 2001 From: Nikita Nek Dudnik Date: Fri, 24 Jul 2020 15:57:32 +0200 Subject: [PATCH 06/10] chore: remove obsolete library --- plugins/github-actions/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index 3f3e154b7b..e20b719c31 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -35,7 +35,6 @@ "moment": "^2.27.0", "react": "^16.13.1", "react-dom": "^16.13.1", - "react-lazylog": "^4.5.2", "react-router-dom": "6.0.0-beta.0", "react-use": "^14.2.0" }, From f6df232ed9545af74c17c71d44bb76c5fece8f28 Mon Sep 17 00:00:00 2001 From: Nikita Nek Dudnik Date: Fri, 24 Jul 2020 15:58:55 +0200 Subject: [PATCH 07/10] chore: remove mock data leftovers --- packages/catalog-model/examples/shuffle-api-component.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/catalog-model/examples/shuffle-api-component.yaml b/packages/catalog-model/examples/shuffle-api-component.yaml index 1726f7aec7..275c48d6ba 100644 --- a/packages/catalog-model/examples/shuffle-api-component.yaml +++ b/packages/catalog-model/examples/shuffle-api-component.yaml @@ -3,8 +3,6 @@ kind: Component metadata: name: shuffle-api description: Shuffle API - annotations: - backstage.io/github-actions-id: 'spotify/backstage' spec: type: service lifecycle: production From b94a1b3cfff1b4ac31f4019d2b9cb54065a0d9c6 Mon Sep 17 00:00:00 2001 From: Nikita Nek Dudnik Date: Fri, 24 Jul 2020 16:19:48 +0200 Subject: [PATCH 08/10] fix: add missing files --- plugins/github-actions/scripts/mock-data.sh | 8 ++++++++ plugins/github-actions/scripts/sample.yaml | 11 +++++++++++ 2 files changed, 19 insertions(+) create mode 100755 plugins/github-actions/scripts/mock-data.sh create mode 100644 plugins/github-actions/scripts/sample.yaml diff --git a/plugins/github-actions/scripts/mock-data.sh b/plugins/github-actions/scripts/mock-data.sh new file mode 100755 index 0000000000..2653a415dd --- /dev/null +++ b/plugins/github-actions/scripts/mock-data.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + + curl \ + --location \ + --request POST 'localhost:7000/catalog/locations' \ + --header 'Content-Type: application/json' \ + --data-raw "{\"type\": \"file\", \"target\": \"$(pwd)/scripts/sample.yaml\"}" + echo diff --git a/plugins/github-actions/scripts/sample.yaml b/plugins/github-actions/scripts/sample.yaml new file mode 100644 index 0000000000..3aa75200f5 --- /dev/null +++ b/plugins/github-actions/scripts/sample.yaml @@ -0,0 +1,11 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage + description: backstage.io + annotations: + backstage.io/github-actions-id: 'spotify/backstage' +spec: + type: website + lifecycle: production + owner: guest From ab6dfa3aa2a29dd1f546d267bcca49f9c9f17edf Mon Sep 17 00:00:00 2001 From: Nikita Nek Dudnik Date: Mon, 27 Jul 2020 10:42:06 +0200 Subject: [PATCH 09/10] feat: add github icon and more descriptive text --- .../WorkflowRunDetailsPage.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx b/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx index 308ae297d8..283fd60ec6 100644 --- a/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx +++ b/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx @@ -54,6 +54,7 @@ import { useWorkflowRunsDetails } from './useWorkflowRunsDetails'; import { useWorkflowRunJobs } from './useWorkflowRunJobs'; import { WorkflowRunStatusIcon } from '../WorkflowRunStatusIcon/WorkflowRunStatusIcon'; import { useProjectName } from '../useProjectName'; +import GitHubIcon from '@material-ui/icons/GitHub'; const useStyles = makeStyles(theme => ({ root: { @@ -241,9 +242,15 @@ export const WorkflowRunDetailsPage = () => { {details.value?.html_url && ( - + + + )} From 504358df5ad2ec17d8858d50a7f0d8c818bfd117 Mon Sep 17 00:00:00 2001 From: Nikita Nek Dudnik Date: Mon, 27 Jul 2020 11:41:40 +0200 Subject: [PATCH 10/10] docs: add documentation --- plugins/github-actions/README.md | 73 ++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/plugins/github-actions/README.md b/plugins/github-actions/README.md index b0b339a1b0..72f991e814 100644 --- a/plugins/github-actions/README.md +++ b/plugins/github-actions/README.md @@ -1,13 +1,70 @@ -# github-actions +# GitHub Actions Plugin -Welcome to the github-actions plugin! +Website: [https://github.com/actions](https://github.com/actions) -_This plugin was created through the Backstage CLI_ +## Screenshots -## Getting started +TBD -Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/github-actions](http://localhost:3000/github-actions). +## Setup +### Generic Requirements +1. Provide OAuth credentials: + 1. [Create an OAuth App](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) with callback URL set to ```https://localhost:3000/auth/github```. + 2. Take Client ID and Client Secret from the newly created app's settings page and put them into ```AUTH_GITHUB_CLIENT_ID``` and ```AUTH_GITHUB_CLIENT_SECRET``` env variables. +2. Annotate your component with a correct GitHub Actions repository and owner: + + The annotation key is ```backstage.io/github-actions-id```. -You can also serve the plugin in isolation by running `yarn start` in the plugin directory. -This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads. -It is only meant for local development, and the setup for it can be found inside the [/dev](/dev) directory. + Example: + ``` + apiVersion: backstage.io/v1alpha1 + kind: Component + metadata: + name: backstage + description: backstage.io + annotations: + backstage.io/github-actions-id: 'spotify/backstage' + spec: + type: website + lifecycle: production + owner: guest + ``` +### Standalone app requirements +If you didn't clone this repo you have to do some extra work. + +1. Add plugin API to your Backstage instance: + +```bash +yarn add @backstage/plugin-github-actions +``` + +```js +// packages/app/src/api.ts +import { ApiRegistry } from '@backstage/core'; +import { GithubActionsClient, githubActionsApiRef } from '@backstage/plugin-github-actions'; + +const builder = ApiRegistry.builder(); +builder.add(githubActionsApiRef, new GithubActionsClient()); + +export default builder.build() as ApiHolder; +``` + +2. Add plugin itself: + +```js +// packages/app/src/plugins.ts +export { plugin as GithubActions } from '@backstage/plugin-github-actions'; +``` + +3. Run the app with `yarn start` and the backend with `yarn --cwd packages/backend start`, navigate to `/github-actions/`. + +## Features + +- List workflow runs for a project +- Dive into one run to see a job steps +- Retry runs +- Pagination for runs + +## Limitations + +- There is a limit of 100 apps for one OAuth client/token pair