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"