From 97130d08e19e39b12776f6614769c8ae77427eb6 Mon Sep 17 00:00:00 2001 From: Wolfgang Walther Date: Mon, 16 Jun 2025 16:19:42 +0200 Subject: [PATCH] workflows/labels: add more error context The original error is kept, but the PR number is printed as well. Makes debugging much easier. --- .github/workflows/labels.yml | 156 ++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 76 deletions(-) diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index ac1f3c7b5777..5d69dfe4e071 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -100,97 +100,101 @@ jobs: ...prEventCondition }, async (response, done) => (await Promise.allSettled(response.data.map(async (pull_request) => { - const log = (k,v) => core.info(`PR #${pull_request.number} - ${k}: ${v}`) + try { + const log = (k,v) => core.info(`PR #${pull_request.number} - ${k}: ${v}`) - log('Last updated at', pull_request.updated_at) - if (new Date(pull_request.updated_at) < cutoff) return done() + log('Last updated at', pull_request.updated_at) + if (new Date(pull_request.updated_at) < cutoff) return done() - const run_id = (await github.rest.actions.listWorkflowRuns({ - ...context.repo, - workflow_id: 'eval.yml', - event: 'pull_request_target', - // For PR events, the workflow run is still in progress with this job itself. - status: prEventCondition ? 'in_progress' : 'success', - exclude_pull_requests: true, - head_sha: pull_request.head.sha - })).data.workflow_runs[0]?.id + const run_id = (await github.rest.actions.listWorkflowRuns({ + ...context.repo, + workflow_id: 'eval.yml', + event: 'pull_request_target', + // For PR events, the workflow run is still in progress with this job itself. + status: prEventCondition ? 'in_progress' : 'success', + exclude_pull_requests: true, + head_sha: pull_request.head.sha + })).data.workflow_runs[0]?.id - // Newer PRs might not have run Eval to completion, yet. We can skip them, because this - // job will be run as part of that Eval run anyway. - log('Last eval run', run_id) - if (!run_id) return; + // Newer PRs might not have run Eval to completion, yet. We can skip them, because this + // job will be run as part of that Eval run anyway. + log('Last eval run', run_id) + if (!run_id) return; - const artifact = (await github.rest.actions.listWorkflowRunArtifacts({ - ...context.repo, - run_id, - name: 'comparison' - })).data.artifacts[0] + const artifact = (await github.rest.actions.listWorkflowRunArtifacts({ + ...context.repo, + run_id, + name: 'comparison' + })).data.artifacts[0] - // Instead of checking the boolean artifact.expired, we will give us a minute to - // actually download the artifact in the next step and avoid that race condition. - log('Artifact expires at', artifact.expires_at) - if (new Date(artifact.expires_at) < new Date(new Date().getTime() + 60 * 1000)) return; + // Instead of checking the boolean artifact.expired, we will give us a minute to + // actually download the artifact in the next step and avoid that race condition. + log('Artifact expires at', artifact.expires_at) + if (new Date(artifact.expires_at) < new Date(new Date().getTime() + 60 * 1000)) return; - await artifactClient.downloadArtifact(artifact.id, { - findBy: { - repositoryName: context.repo.repo, - repositoryOwner: context.repo.owner, - token: core.getInput('github-token') - }, - path: path.resolve(pull_request.number.toString()), - expectedHash: artifact.digest - }) + await artifactClient.downloadArtifact(artifact.id, { + findBy: { + repositoryName: context.repo.repo, + repositoryOwner: context.repo.owner, + token: core.getInput('github-token') + }, + path: path.resolve(pull_request.number.toString()), + expectedHash: artifact.digest + }) - // Get all currently set labels that we manage - const before = - pull_request.labels.map(({ name }) => name) - .filter(name => - name.startsWith('10.rebuild') || - name == '11.by: package-maintainer' || - name.startsWith('12.approvals:') || - name == '12.approved-by: package-maintainer' + // Get all currently set labels that we manage + const before = + pull_request.labels.map(({ name }) => name) + .filter(name => + name.startsWith('10.rebuild') || + name == '11.by: package-maintainer' || + name.startsWith('12.approvals:') || + name == '12.approved-by: package-maintainer' + ) + + const approvals = new Set( + (await github.paginate(github.rest.pulls.listReviews, { + ...context.repo, + pull_number: pull_request.number + })) + .filter(review => review.state == 'APPROVED') + .map(review => review.user.id) ) - const approvals = new Set( - (await github.paginate(github.rest.pulls.listReviews, { - ...context.repo, - pull_number: pull_request.number - })) - .filter(review => review.state == 'APPROVED') - .map(review => review.user.id) - ) + const maintainers = new Set(Object.keys( + JSON.parse(await readFile(`${pull_request.number}/maintainers.json`, 'utf-8')) + )) - const maintainers = new Set(Object.keys( - JSON.parse(await readFile(`${pull_request.number}/maintainers.json`, 'utf-8')) - )) + // And the labels that should be there + const after = JSON.parse(await readFile(`${pull_request.number}/changed-paths.json`, 'utf-8')).labels + if (approvals.size > 0) after.push(`12.approvals: ${approvals.size > 2 ? '3+' : approvals.size}`) + if (Array.from(maintainers).some(m => approvals.has(m))) after.push('12.approved-by: package-maintainer') - // And the labels that should be there - const after = JSON.parse(await readFile(`${pull_request.number}/changed-paths.json`, 'utf-8')).labels - if (approvals.size > 0) after.push(`12.approvals: ${approvals.size > 2 ? '3+' : approvals.size}`) - if (Array.from(maintainers).some(m => approvals.has(m))) after.push('12.approved-by: package-maintainer') + // Remove the ones not needed anymore + await Promise.all( + before.filter(name => !after.includes(name)) + .map(name => github.rest.issues.removeLabel({ + ...context.repo, + issue_number: pull_request.number, + name + })) + ) - // Remove the ones not needed anymore - await Promise.all( - before.filter(name => !after.includes(name)) - .map(name => github.rest.issues.removeLabel({ - ...context.repo, - issue_number: pull_request.number, - name - })) - ) - - // And add the ones that aren't set already - const added = after.filter(name => !before.includes(name)) - if (added.length > 0) { - await github.rest.issues.addLabels({ - ...context.repo, - issue_number: pull_request.number, - labels: added - }) + // And add the ones that aren't set already + const added = after.filter(name => !before.includes(name)) + if (added.length > 0) { + await github.rest.issues.addLabels({ + ...context.repo, + issue_number: pull_request.number, + labels: added + }) + } + } catch (cause) { + throw new Error(`Labeling PR #${pull_request.number} failed.`, { cause }) } }))) .filter(({ status }) => status == 'rejected') - .map(({ reason }) => core.setFailed(reason)) + .map(({ reason }) => core.setFailed(`${reason.message}\n${reason.cause.stack}`)) ) - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0