diff --git a/extensions/ql-vscode/src/remote-queries/gh-actions-api-client.ts b/extensions/ql-vscode/src/remote-queries/gh-actions-api-client.ts index a0fbfafbf50..f59c33f3007 100644 --- a/extensions/ql-vscode/src/remote-queries/gh-actions-api-client.ts +++ b/extensions/ql-vscode/src/remote-queries/gh-actions-api-client.ts @@ -10,6 +10,8 @@ import { RemoteQuery } from './remote-query'; import { RemoteQueryFailureIndexItem, RemoteQueryResultIndex, RemoteQuerySuccessIndexItem } from './remote-query-result-index'; import { getErrorMessage } from '../pure/helpers-pure'; +export const RESULT_INDEX_ARTIFACT_NAME = 'result-index'; + interface ApiSuccessIndexItem { nwo: string; id: string; @@ -44,7 +46,7 @@ export async function getRemoteQueryIndex( const artifactsUrlPath = `/repos/${owner}/${repoName}/actions/artifacts`; const artifactList = await listWorkflowRunArtifacts(credentials, owner, repoName, workflowRunId); - const resultIndexArtifactId = tryGetArtifactIDfromName('result-index', artifactList); + const resultIndexArtifactId = tryGetArtifactIDfromName(RESULT_INDEX_ARTIFACT_NAME, artifactList); if (!resultIndexArtifactId) { return undefined; } @@ -116,6 +118,27 @@ export async function downloadArtifactFromLink( return path.join(extractedPath, downloadLink.innerFilePath || ''); } +/** + * Checks whether a specific artifact is present in the list of artifacts of a workflow run. + * @param credentials Credentials for authenticating to the GitHub API. + * @param owner + * @param repo + * @param workflowRunId The ID of the workflow run to get the artifact for. + * @param artifactName The artifact name, as a string. + * @returns A boolean indicating if the artifact is available. + */ +export async function isArtifactAvailable( + credentials: Credentials, + owner: string, + repo: string, + workflowRunId: number, + artifactName: string, +): Promise { + const artifactList = await listWorkflowRunArtifacts(credentials, owner, repo, workflowRunId); + + return tryGetArtifactIDfromName(artifactName, artifactList) !== undefined; +} + /** * Downloads the result index artifact and extracts the result index items. * @param credentials Credentials for authenticating to the GitHub API. diff --git a/extensions/ql-vscode/src/remote-queries/remote-queries-monitor.ts b/extensions/ql-vscode/src/remote-queries/remote-queries-monitor.ts index 38905a31c97..164dcac813f 100644 --- a/extensions/ql-vscode/src/remote-queries/remote-queries-monitor.ts +++ b/extensions/ql-vscode/src/remote-queries/remote-queries-monitor.ts @@ -1,7 +1,7 @@ import * as vscode from 'vscode'; import { Credentials } from '../authentication'; import { Logger } from '../logging'; -import { getWorkflowStatus } from './gh-actions-api-client'; +import { getWorkflowStatus, isArtifactAvailable, RESULT_INDEX_ARTIFACT_NAME } from './gh-actions-api-client'; import { RemoteQuery } from './remote-query'; import { RemoteQueryWorkflowResult } from './remote-query-workflow-result'; @@ -42,7 +42,25 @@ export class RemoteQueriesMonitor { remoteQuery.controllerRepository.name, remoteQuery.actionsWorkflowRunId); - if (workflowStatus.status !== 'InProgress') { + // Even if the workflow indicates it has completed, artifacts + // might still take a while to become available. So we need to + // check for the artifact before we can declare the workflow + // as having completed. + if (workflowStatus.status === 'CompletedSuccessfully') { + const resultIndexAvailable = await isArtifactAvailable( + credentials, + remoteQuery.controllerRepository.owner, + remoteQuery.controllerRepository.name, + remoteQuery.actionsWorkflowRunId, + RESULT_INDEX_ARTIFACT_NAME + ); + + if (resultIndexAvailable) { + return workflowStatus; + } + + // We don't have a result-index yet, so we'll keep monitoring. + } else if (workflowStatus.status !== 'InProgress') { return workflowStatus; }