diff options
Diffstat (limited to 'source/features/github-actions-indicators.tsx')
-rw-r--r-- | source/features/github-actions-indicators.tsx | 72 |
1 files changed, 58 insertions, 14 deletions
diff --git a/source/features/github-actions-indicators.tsx b/source/features/github-actions-indicators.tsx index 93467b03..a73b9df6 100644 --- a/source/features/github-actions-indicators.tsx +++ b/source/features/github-actions-indicators.tsx @@ -1,7 +1,7 @@ import cache from 'webext-storage-cache'; import React from 'dom-chef'; import select from 'select-dom'; -import {PlayIcon} from '@primer/octicons-react'; +import {StopIcon, PlayIcon} from '@primer/octicons-react'; import {parseCron} from '@cheap-glitch/mi-cron'; import * as pageDetect from 'github-url-detection'; @@ -10,6 +10,11 @@ import * as api from '../github-helpers/api'; import {cacheByRepo} from '../github-helpers'; import observe from '../helpers/selector-observer'; +type Workflow = { + name: string; + isEnabled: boolean; +}; + type WorkflowDetails = { schedule?: string; manuallyDispatchable: boolean; @@ -25,7 +30,21 @@ function addTooltip(element: HTMLElement, tooltip: string): void { } } -const getWorkflowsDetails = cache.function('workflows', async (): Promise<Record<string, WorkflowDetails> | false> => { +// There is no way to get a workflow list in the v4 API #6543 +const getWorkflows = async (): Promise<Workflow[]> => { + const response = await api.v3('actions/workflows'); + + const workflows = response.workflows as any[]; + + // The response is not reliable: Some workflow's path is '' and deleted workflow's state is 'active' + return workflows + .map<Workflow>(workflow => ({ + name: workflow.path.split('/').pop()!, + isEnabled: workflow.state === 'active', + })); +}; + +const getFilesInWorkflowPath = async (): Promise<Record<string, string>> => { const {repository: {workflowFiles}} = await api.v4(` repository() { workflowFiles: object(expression: "HEAD:.github/workflows") { @@ -43,16 +62,33 @@ const getWorkflowsDetails = cache.function('workflows', async (): Promise<Record } `); - const workflows = workflowFiles?.entries ?? []; - if (workflows.length === 0) { - return false; + const workflows: any[] = workflowFiles?.entries ?? []; + + const result: Record<string, string> = {}; + for (const workflow of workflows) { + result[workflow.name] = workflow.object.text; } - const details: Record<string, WorkflowDetails> = {}; + return result; +}; + +const getWorkflowsDetails = cache.function('workflows-details', async (): Promise<Record<string, Workflow & WorkflowDetails>> => { + const [workflows, workflowFiles] = await Promise.all([getWorkflows(), getFilesInWorkflowPath()]); + + const details: Record<string, Workflow & WorkflowDetails> = {}; + for (const workflow of workflows) { - const workflowYaml: string = workflow.object.text; + const workflowYaml = workflowFiles[workflow.name]; + + if (workflowYaml === undefined) { + // Cannot find workflow yaml; workflow removed. + continue; + } + const cron = /schedule[:\s-]+cron[:\s'"]+([^'"\n]+)/m.exec(workflowYaml); + details[workflow.name] = { + ...workflow, schedule: cron?.[1], manuallyDispatchable: workflowYaml.includes('workflow_dispatch:'), }; @@ -66,24 +102,29 @@ const getWorkflowsDetails = cache.function('workflows', async (): Promise<Record }); async function addIndicators(workflowListItem: HTMLAnchorElement): Promise<void> { - // Memoized above - const workflows = await getWorkflowsDetails(); - if (!workflows) { - return; // Impossibru, for types only - } - + // There might be a disabled indicator already if (select.exists('.octicon-stop', workflowListItem)) { return; } + // Called in `init`, memoized + const workflows = await getWorkflowsDetails(); const workflowName = workflowListItem.href.split('/').pop()!; const workflow = workflows[workflowName]; if (!workflow) { return; } + const svgTrailer = <div className="ActionListItem-visual--trailing m-auto d-flex gap-2"/>; + workflowListItem.append(svgTrailer); + + if (!workflow.isEnabled) { + svgTrailer.append(<StopIcon className="m-auto"/>); + addTooltip(workflowListItem, 'This workflow is not enabled'); + } + if (workflow.manuallyDispatchable) { - workflowListItem.append(<PlayIcon className="ActionListItem-visual--trailing m-auto"/>); + svgTrailer.append(<PlayIcon className="m-auto"/>); addTooltip(workflowListItem, 'This workflow can be triggered manually'); } @@ -136,4 +177,7 @@ https://github.com/fregante/browser-extension-template/actions Manual + scheduled: https://github.com/fregante/eslint-formatters/actions +Manually disabled: +https://github.com/134130/134130/actions + */ |