Skip to content

Commit

Permalink
Merge pull request #2172 from NetPenguins/master
Browse files Browse the repository at this point in the history
GithubActions Logging Implementation
  • Loading branch information
shmidt-i committed Sep 12, 2020
2 parents 3aee1a1 + b4d4af5 commit 4780043
Show file tree
Hide file tree
Showing 11 changed files with 288 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import React, { FC, Suspense, useEffect, useState } from 'react';
const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog'));
moment.relativeTimeThreshold('ss', 0);
const useStyles = makeStyles({
expansionPanelDetails: {
accordionDetails: {
padding: 0,
},
button: {
Expand Down Expand Up @@ -80,7 +80,7 @@ export const ActionOutput: FC<{
{name} ({timeElapsed})
</Typography>
</AccordionSummary>
<AccordionDetails className={classes.expansionPanelDetails}>
<AccordionDetails className={classes.accordionDetails}>
{messages.length === 0 ? (
'Nothing here...'
) : (
Expand Down
1 change: 1 addition & 0 deletions plugins/github-actions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"moment": "^2.27.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-lazylog": "^4.5.3",
"react-router": "6.0.0-beta.0",
"react-router-dom": "6.0.0-beta.0",
"react-use": "^15.3.3"
Expand Down
12 changes: 12 additions & 0 deletions plugins/github-actions/src/api/GithubActionsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
ActionsListWorkflowRunsForRepoResponseData,
ActionsGetWorkflowResponseData,
ActionsGetWorkflowRunResponseData,
EndpointInterface,
} from '@octokit/types';

export const githubActionsApiRef = createApiRef<GithubActionsApi>({
Expand Down Expand Up @@ -75,4 +76,15 @@ export type GithubActionsApi = {
repo: string;
runId: number;
}) => Promise<any>;
downloadJobLogsForWorkflowRun: ({
token,
owner,
repo,
runId,
}: {
token: string;
owner: string;
repo: string;
runId: number;
}) => Promise<EndpointInterface>;
};
21 changes: 21 additions & 0 deletions plugins/github-actions/src/api/GithubActionsClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
ActionsListWorkflowRunsForRepoResponseData,
ActionsGetWorkflowResponseData,
ActionsGetWorkflowRunResponseData,
EndpointInterface,
} from '@octokit/types';

export class GithubActionsClient implements GithubActionsApi {
Expand Down Expand Up @@ -102,4 +103,24 @@ export class GithubActionsClient implements GithubActionsApi {
});
return run.data;
}
async downloadJobLogsForWorkflowRun({
token,
owner,
repo,
runId,
}: {
token: string;
owner: string;
repo: string;
runId: number;
}): Promise<EndpointInterface> {
const workflow = await new Octokit({
auth: token,
}).actions.downloadJobLogsForWorkflowRun({
owner,
repo,
job_id: runId,
});
return workflow.data;
}
}
1 change: 1 addition & 0 deletions plugins/github-actions/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export type Job = {
conclusion: string;
started_at: string;
completed_at: string;
id: string;
name: string;
steps: Step[];
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Entity } from '@backstage/catalog-model';
import { Link } from '@backstage/core';
import {
Expand Down Expand Up @@ -45,6 +44,7 @@ import { useProjectName } from '../useProjectName';
import { WorkflowRunStatus } from '../WorkflowRunStatus';
import { useWorkflowRunJobs } from './useWorkflowRunJobs';
import { useWorkflowRunsDetails } from './useWorkflowRunsDetails';
import { WorkflowRunLogs } from '../WorkflowRunLogs';

const useStyles = makeStyles<Theme>(theme => ({
root: {
Expand All @@ -57,7 +57,7 @@ const useStyles = makeStyles<Theme>(theme => ({
table: {
padding: theme.spacing(1),
},
expansionPanelDetails: {
accordionDetails: {
padding: 0,
},
button: {
Expand All @@ -71,7 +71,7 @@ const useStyles = makeStyles<Theme>(theme => ({
},
}));

const JobsList = ({ jobs }: { jobs?: Jobs }) => {
const JobsList = ({ jobs, entity }: { jobs?: Jobs; entity: Entity }) => {
const classes = useStyles();
return (
<Box>
Expand All @@ -83,6 +83,7 @@ const JobsList = ({ jobs }: { jobs?: Jobs }) => {
className={
job.status !== 'success' ? classes.failed : classes.success
}
entity={entity}
/>
))}
</Box>
Expand Down Expand Up @@ -111,7 +112,15 @@ const StepView = ({ step }: { step: Step }) => {
);
};

const JobListItem = ({ job, className }: { job: Job; className: string }) => {
const JobListItem = ({
job,
className,
entity,
}: {
job: Job;
className: string;
entity: Entity;
}) => {
const classes = useStyles();
return (
<Accordion TransitionProps={{ unmountOnExit: true }} className={className}>
Expand All @@ -127,7 +136,7 @@ const JobListItem = ({ job, className }: { job: Job; className: string }) => {
{job.name} ({getElapsedTime(job.started_at, job.completed_at)})
</Typography>
</AccordionSummary>
<AccordionDetails className={classes.expansionPanelDetails}>
<AccordionDetails className={classes.accordionDetails}>
<TableContainer>
<Table>
{job.steps.map((step: Step) => (
Expand All @@ -136,6 +145,11 @@ const JobListItem = ({ job, className }: { job: Job; className: string }) => {
</Table>
</TableContainer>
</AccordionDetails>
{job.status === 'queued' || job.status === 'in_progress' ? (
<WorkflowRunLogs runId={job.id} inProgress entity={entity} />
) : (
<WorkflowRunLogs runId={job.id} inProgress={false} entity={entity} />
)}
</Accordion>
);
};
Expand Down Expand Up @@ -218,7 +232,7 @@ export const WorkflowRunDetails = ({ entity }: { entity: Entity }) => {
{jobs.loading ? (
<CircularProgress />
) : (
<JobsList jobs={jobs.value} />
<JobsList jobs={jobs.value} entity={entity} />
)}
</TableCell>
</TableRow>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
* 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 {
Accordion,
AccordionSummary,
CircularProgress,
Fade,
LinearProgress,
makeStyles,
Modal,
Theme,
Tooltip,
Typography,
Zoom,
} from '@material-ui/core';

import React, { Suspense } from 'react';
import { useDownloadWorkflowRunLogs } from './useDownloadWorkflowRunLogs';
import LinePart from 'react-lazylog/build/LinePart';
import { useProjectName } from '../useProjectName';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import DescriptionIcon from '@material-ui/icons/Description';
import { Entity } from '@backstage/catalog-model';

const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog'));

const useStyles = makeStyles<Theme>(() => ({
button: {
order: -1,
marginRight: 0,
marginLeft: '-20px',
},
modal: {
display: 'flex',
alignItems: 'center',
width: '85%',
height: '85%',
justifyContent: 'center',
margin: 'auto',
},
normalLog: {
height: '75vh',
width: '100%',
},
modalLog: {
height: '100%',
width: '100%',
},
}));

const DisplayLog = ({
jobLogs,
className,
}: {
jobLogs: any;
className: string;
}) => {
return (
<Suspense fallback={<LinearProgress />}>
<div className={className}>
<LazyLog
text={jobLogs ?? 'No Values Found'}
extraLines={1}
caseInsensitive
enableSearch
formatPart={line => {
if (
line.toLocaleLowerCase().includes('error') ||
line.toLocaleLowerCase().includes('failed') ||
line.toLocaleLowerCase().includes('failure')
) {
return (
<LinePart style={{ color: 'red' }} part={{ text: line }} />
);
}
return line;
}}
/>
</div>
</Suspense>
);
};

/**
* A component for Run Logs visualization.
*/
export const WorkflowRunLogs = ({
entity,
runId,
inProgress,
}: {
entity: Entity;
runId: string;
inProgress: boolean;
}) => {
const classes = useStyles();
const projectName = useProjectName(entity);

const [owner, repo] = projectName.value ? projectName.value.split('/') : [];
const jobLogs = useDownloadWorkflowRunLogs(repo, owner, runId);
const [open, setOpen] = React.useState(false);

const handleOpen = () => {
setOpen(true);
};

const handleClose = () => {
setOpen(false);
};

return (
<Accordion TransitionProps={{ unmountOnExit: true }} disabled={inProgress}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls={`panel-${name}-content`}
id={`panel-${name}-header`}
IconButtonProps={{
className: classes.button,
}}
>
<Typography variant="button">
{jobLogs.loading ? <CircularProgress /> : 'Job Log'}
</Typography>
<Tooltip title="Open Log" TransitionComponent={Zoom} arrow>
<DescriptionIcon
onClick={event => {
event.stopPropagation();
handleOpen();
}}
style={{ marginLeft: 'auto' }}
/>
</Tooltip>
<Modal
className={classes.modal}
onClick={event => event.stopPropagation()}
open={open}
onClose={handleClose}
>
<Fade in={open}>
<DisplayLog
jobLogs={jobLogs.value || undefined}
className={classes.modalLog}
/>
</Fade>
</Modal>
</AccordionSummary>
{jobLogs.value && (
<DisplayLog
jobLogs={jobLogs.value || undefined}
className={classes.normalLog}
/>
)}
</Accordion>
);
};
16 changes: 16 additions & 0 deletions plugins/github-actions/src/components/WorkflowRunLogs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* 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 { WorkflowRunLogs } from './WorkflowRunLogs';

0 comments on commit 4780043

Please sign in to comment.