This is an automated email from the ASF dual-hosted git repository.
davidzollo pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/seatunnel.git
The following commit(s) were added to refs/heads/dev by this push:
new 75599cf68b [Fix][CI] Retry and reconcile fork build status (#11888)
75599cf68b is described below
commit 75599cf68bacc2a73526510f065a63ed77ed078c
Author: Daniel <[email protected]>
AuthorDate: Thu Aug 20 21:15:16 2026 +0800
[Fix][CI] Retry and reconcile fork build status (#11888)
---
.github/workflows/notify_test_workflow.yml | 62 +++++++++++------
.github/workflows/update_build_status.yml | 107 ++++++++++++++++++++++-------
2 files changed, 122 insertions(+), 47 deletions(-)
diff --git a/.github/workflows/notify_test_workflow.yml
b/.github/workflows/notify_test_workflow.yml
index 2a0d1729f3..4563787e83 100644
--- a/.github/workflows/notify_test_workflow.yml
+++ b/.github/workflows/notify_test_workflow.yml
@@ -40,8 +40,10 @@ jobs:
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
- const endpoint = 'GET
/repos/:owner/:repo/actions/workflows/:id/runs?&branch=:branch'
- const check_run_endpoint = 'GET
/repos/:owner/:repo/commits/:ref/check-runs?per_page=100'
+ const endpoint = 'GET
/repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs'
+ const check_run_endpoint = 'GET
/repos/{owner}/{repo}/commits/{ref}/check-runs'
+ const MAX_LOOKUP_DURATION_MS = 60 * 1000
+ const LOOKUP_INTERVAL_MS = 5000
// TODO: Should use pull_request.user and
pull_request.user.repos_url?
// If a different person creates a commit to another forked repo,
@@ -49,34 +51,57 @@ jobs:
const params = {
owner: context.payload.pull_request.head.repo.owner.login,
repo: context.payload.pull_request.head.repo.name,
- id: 'build_main.yml',
+ workflow_id: 'build_main.yml',
branch: context.payload.pull_request.head.ref,
+ per_page: 100,
}
const check_run_params = {
owner: context.payload.pull_request.head.repo.owner.login,
repo: context.payload.pull_request.head.repo.name,
ref: context.payload.pull_request.head.ref,
+ per_page: 100,
}
console.log('Ref: ' + context.payload.pull_request.head.ref)
console.log('SHA: ' + context.payload.pull_request.head.sha)
- // Wait 3 seconds to make sure the fork repository triggered a
workflow.
- await new Promise(r => setTimeout(r, 3000))
-
- let runs
- try {
- runs = await github.request(endpoint, params)
- } catch (error) {
- console.error(error)
- // Assume that runs were not found.
- }
-
const name = 'Build'
const head_sha = context.payload.pull_request.head.sha
let status = 'queued'
- console.log('runs: ' + JSON.stringify(runs))
- if (!runs || runs.data.workflow_runs.length === 0) {
+
+ async function findBuildWorkflowRun() {
+ const lookupDeadline = Date.now() + MAX_LOOKUP_DURATION_MS
+ let attempt = 1
+
+ while (true) {
+ try {
+ const runs = await github.request(endpoint, params)
+ const buildRun = runs.data.workflow_runs.find(
+ (run) => run.head_sha === head_sha
+ )
+
+ console.log('runs: ' + JSON.stringify(runs))
+ if (buildRun) {
+ return buildRun
+ }
+ } catch (error) {
+ console.error(`Failed to find Build workflow run on attempt
${attempt}`, error)
+ }
+
+ const remainingLookupTime = lookupDeadline - Date.now()
+ if (remainingLookupTime <= 0) {
+ return null
+ }
+
+ await new Promise((resolve) =>
+ setTimeout(resolve, Math.min(LOOKUP_INTERVAL_MS,
remainingLookupTime))
+ )
+ attempt += 1
+ }
+ }
+
+ const build_run = await findBuildWorkflowRun()
+ if (!build_run) {
status = 'completed'
const conclusion = 'action_required'
@@ -109,13 +134,8 @@ jobs:
}
})
} else {
- const build_run = runs.data.workflow_runs[0]
const run_id = build_run.id
- if (build_run.head_sha != context.payload.pull_request.head.sha)
{
- throw new Error('There was a new unsynced commit pushed.
Please retrigger the workflow.');
- }
-
// Here we get check run ID to provide Check run view instead of
Actions view, see also SPARK-37879.
const check_runs = await github.request(check_run_endpoint,
check_run_params)
console.log('check_runs: ' + JSON.stringify(check_runs))
diff --git a/.github/workflows/update_build_status.yml
b/.github/workflows/update_build_status.yml
index 1e853f9700..b7cd76eeeb 100644
--- a/.github/workflows/update_build_status.yml
+++ b/.github/workflows/update_build_status.yml
@@ -74,6 +74,42 @@ jobs:
return items;
}
+ async function findWorkflowRunForPullRequest(pr) {
+ if (!pr.head.repo) {
+ console.log(` Skip PR #${pr.number}: head repository is
unavailable`);
+ return null;
+ }
+
+ const workflowRunParams = {
+ owner: pr.head.repo.owner.login,
+ repo: pr.head.repo.name,
+ workflow_id: 'build_main.yml',
+ branch: pr.head.ref,
+ per_page: 100
+ };
+ const workflowRuns = await github.request(
+ 'GET
/repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs',
+ workflowRunParams
+ );
+ const workflowRun = workflowRuns.data.workflow_runs.find(
+ (run) => run.head_sha === pr.head.sha
+ );
+
+ if (!workflowRun) {
+ console.log(` Skip PR #${pr.number}: no Build workflow run
for ${pr.head.sha}`);
+ return null;
+ }
+
+ return {
+ workflowRun,
+ workflowRunParams: {
+ owner: workflowRunParams.owner,
+ repo: workflowRunParams.repo,
+ run_id: workflowRun.id
+ }
+ };
+ }
+
function shouldSkipPatch(checkRun, workflowRun) {
const sameStatus = checkRun.status === workflowRun.status;
const sameConclusion =
@@ -206,40 +242,52 @@ jobs:
}
);
- const buildCheckRun = checkRuns.data.check_runs.find(
- (checkRun) =>
- checkRun.name === 'Build' && checkRun.conclusion !==
'action_required'
+ const buildCheckRuns = checkRuns.data.check_runs.filter(
+ (checkRun) => checkRun.name === 'Build'
);
+ const buildCheckRun =
+ buildCheckRuns.find(
+ (checkRun) => checkRun.conclusion !== 'action_required'
+ ) || buildCheckRuns[0];
if (!buildCheckRun) {
console.log(` Skip PR #${pr.number}: no eligible Build
check run`);
return;
}
- if (!buildCheckRun.output || !buildCheckRun.output.text) {
- console.log(` Skip PR #${pr.number}: Build check run
${buildCheckRun.id} has no run metadata`);
- return;
- }
-
let workflowRunParams;
- try {
- workflowRunParams = JSON.parse(buildCheckRun.output.text);
- } catch (error) {
- console.error(` Skip PR #${pr.number}: invalid JSON in
check run ${buildCheckRun.id}`, error);
- return;
- }
-
let workflowRun;
- try {
- workflowRun = (
- await github.request(
- 'GET /repos/{owner}/{repo}/actions/runs/{run_id}',
- workflowRunParams
- )
- ).data;
- } catch (error) {
- console.error(` Skip PR #${pr.number}: workflow run lookup
failed`, error);
- return;
+ if (buildCheckRun.conclusion === 'action_required') {
+ const matchedWorkflowRun = await
findWorkflowRunForPullRequest(pr);
+ if (!matchedWorkflowRun) {
+ return;
+ }
+ workflowRunParams = matchedWorkflowRun.workflowRunParams;
+ workflowRun = matchedWorkflowRun.workflowRun;
+ } else {
+ if (!buildCheckRun.output || !buildCheckRun.output.text) {
+ console.log(` Skip PR #${pr.number}: Build check run
${buildCheckRun.id} has no run metadata`);
+ return;
+ }
+
+ try {
+ workflowRunParams = JSON.parse(buildCheckRun.output.text);
+ } catch (error) {
+ console.error(` Skip PR #${pr.number}: invalid JSON in
check run ${buildCheckRun.id}`, error);
+ return;
+ }
+
+ try {
+ workflowRun = (
+ await github.request(
+ 'GET /repos/{owner}/{repo}/actions/runs/{run_id}',
+ workflowRunParams
+ )
+ ).data;
+ } catch (error) {
+ console.error(` Skip PR #${pr.number}: workflow run
lookup failed`, error);
+ return;
+ }
}
let normalizedWorkflowRun;
@@ -264,7 +312,14 @@ jobs:
owner: context.repo.owner,
repo: context.repo.repo,
check_run_id: buildCheckRun.id,
- output: buildCheckRun.output,
+ output:
+ buildCheckRun.conclusion === 'action_required'
+ ? {
+ title: 'Test results',
+ summary: `[See test
results](${workflowRun.html_url})`,
+ text: JSON.stringify(workflowRunParams)
+ }
+ : buildCheckRun.output,
status: normalizedWorkflowRun.status,
details_url: normalizedWorkflowRun.details_url
};