feat: use annotation to get project name
This commit is contained in:
@@ -23,7 +23,7 @@ import {
|
||||
} from '@octokit/types';
|
||||
|
||||
export class GithubActionsClient implements GithubActionsApi {
|
||||
reRunWorkflow({
|
||||
async reRunWorkflow({
|
||||
token,
|
||||
owner,
|
||||
repo,
|
||||
|
||||
@@ -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',
|
||||
}
|
||||
|
||||
+14
-14
@@ -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>(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 = () => {
|
||||
<Page theme={pageTheme.tool}>
|
||||
<Header
|
||||
title="GitHub Actions"
|
||||
subtitle="See recent worflow runs and their status"
|
||||
subtitle="See recent workflow runs and their status"
|
||||
>
|
||||
<HeaderLabel label="Owner" value="Spotify" />
|
||||
<HeaderLabel label="Lifecycle" value="Alpha" />
|
||||
@@ -187,16 +190,13 @@ export const WorkflowRunDetailsPage = () => {
|
||||
the GitHub Actions environment.
|
||||
</SupportButton>
|
||||
</ContentHeader>
|
||||
<Breadcrumbs aria-label="breadcrumb">
|
||||
<Link to="/github-actions">Workflow runs</Link>
|
||||
<Typography>Workflow run details</Typography>
|
||||
</Breadcrumbs>
|
||||
<Grid container spacing={3} direction="column">
|
||||
<Grid item>
|
||||
<div className={classes.root}>
|
||||
<Typography className={classes.title} variant="h3">
|
||||
<Link to="/github-actions">
|
||||
<Typography component="span" variant="h3" color="primary">
|
||||
< Back
|
||||
</Typography>
|
||||
</Link>
|
||||
</Typography>
|
||||
<TableContainer component={Paper} className={classes.table}>
|
||||
<Table>
|
||||
<TableBody>
|
||||
|
||||
@@ -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<Jobs>(async () => {
|
||||
|
||||
+2
-2
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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 (
|
||||
<Page theme={pageTheme.tool}>
|
||||
<Header
|
||||
title="GitHub Actions"
|
||||
subtitle="See recent worflow runs and their status"
|
||||
subtitle="See recent workflow runs and their status"
|
||||
>
|
||||
<HeaderLabel label="Owner" value="Spotify" />
|
||||
<HeaderLabel label="Lifecycle" value="Alpha" />
|
||||
@@ -52,7 +47,7 @@ export const WorkflowRunsPage = () => {
|
||||
</ContentHeader>
|
||||
<Grid container spacing={3} direction="column">
|
||||
<Grid item>
|
||||
<WorkflowRunsTable repo={repo} owner={owner} />
|
||||
<WorkflowRunsTable />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
|
||||
@@ -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<WorkflowRun>) => (
|
||||
<IconButton onClick={row.onReRunClick}>
|
||||
<RetryIcon />
|
||||
</IconButton>
|
||||
<Tooltip title="Rerun workflow">
|
||||
<IconButton onClick={row.onReRunClick}>
|
||||
<RetryIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
),
|
||||
width: '10%',
|
||||
},
|
||||
@@ -120,8 +123,8 @@ const WorkflowRunsTableView: FC<Props> = ({
|
||||
page={page}
|
||||
actions={[
|
||||
{
|
||||
icon: () => <RetryIcon />,
|
||||
tooltip: 'Refresh Data',
|
||||
icon: () => <SyncIcon />,
|
||||
tooltip: 'Reload workflow runs',
|
||||
isFreeAction: true,
|
||||
onClick: () => retry(),
|
||||
},
|
||||
@@ -141,17 +144,8 @@ const WorkflowRunsTableView: FC<Props> = ({
|
||||
);
|
||||
};
|
||||
|
||||
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 (
|
||||
<WorkflowRunsTableView
|
||||
{...tableProps}
|
||||
|
||||
@@ -19,16 +19,9 @@ 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';
|
||||
import { useProjectName } from '../useProjectName';
|
||||
|
||||
export function useWorkflowRuns({
|
||||
repo,
|
||||
owner,
|
||||
}: {
|
||||
repo: string;
|
||||
owner: string;
|
||||
}) {
|
||||
const catalogApi = useApi(catalogApiRef);
|
||||
export function useWorkflowRuns() {
|
||||
const api = useApi(githubActionsApiRef);
|
||||
const auth = useApi(githubAuthApiRef);
|
||||
|
||||
@@ -38,17 +31,15 @@ export function useWorkflowRuns({
|
||||
const [page, setPage] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(5);
|
||||
|
||||
const reRunWorkflow = async () => {};
|
||||
|
||||
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;
|
||||
|
||||
+13
-27
@@ -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<string>(async () => {
|
||||
const entity = await catalogApi.getEntityByName(name);
|
||||
return (
|
||||
entity?.metadata.annotations?.['backstage.io/github-actions-id'] ?? ''
|
||||
);
|
||||
});
|
||||
return value;
|
||||
};
|
||||
Reference in New Issue
Block a user