Skip to content

Commit cc8f60c

Browse files
committed
ci: skip submodule update when failure issue is open
1 parent ed3a7ee commit cc8f60c

1 file changed

Lines changed: 99 additions & 4 deletions

File tree

.github/workflows/update-opencode-commit.yml

Lines changed: 99 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,59 @@ jobs:
1919
with:
2020
token: ${{ secrets.GITHUB_TOKEN }}
2121

22+
- name: Check for existing automated submodule failure issue
23+
id: failure_issue_gate
24+
uses: actions/github-script@v7
25+
with:
26+
script: |
27+
const failureMarker = 'Automated submodule update failed';
28+
const openAutomatedIssues = await github.paginate(
29+
github.rest.issues.listForRepo,
30+
{
31+
owner: context.repo.owner,
32+
repo: context.repo.repo,
33+
state: 'open',
34+
labels: 'automated',
35+
per_page: 100,
36+
},
37+
);
38+
39+
const matchingIssues = openAutomatedIssues.filter((issue) =>
40+
(issue.body || '').includes(failureMarker),
41+
);
42+
43+
matchingIssues.sort((a, b) => b.number - a.number);
44+
const existingIssue = matchingIssues[0] || null;
45+
const hasOpenFailureIssue = Boolean(existingIssue);
46+
const shouldBlock =
47+
context.eventName === 'schedule' && hasOpenFailureIssue;
48+
49+
core.info(
50+
`failure_issue_gate: event=${context.eventName}, has_open_failure_issue=${hasOpenFailureIssue}, should_block=${shouldBlock}`,
51+
);
52+
if (existingIssue) {
53+
core.info(
54+
`failure_issue_gate: using #${existingIssue.number} ${existingIssue.html_url}`,
55+
);
56+
}
57+
58+
core.setOutput('has_open_failure_issue', String(hasOpenFailureIssue));
59+
core.setOutput(
60+
'existing_failure_issue_number',
61+
existingIssue ? String(existingIssue.number) : '',
62+
);
63+
core.setOutput(
64+
'existing_failure_issue_url',
65+
existingIssue ? existingIssue.html_url : '',
66+
);
67+
core.setOutput(
68+
'existing_failure_issue_title',
69+
existingIssue ? existingIssue.title : '',
70+
);
71+
core.setOutput('should_block', String(shouldBlock));
72+
2273
- name: Initialize opencode submodule
74+
if: steps.failure_issue_gate.outputs.should_block != 'true'
2375
run: |
2476
# .gitmodules tracks opencode with an SSH URL. Actions runners
2577
# typically lack SSH deploy keys, so rewrite to HTTPS inline.
@@ -29,39 +81,47 @@ jobs:
2981
git submodule status --recursive
3082
3183
- name: Configure Git
84+
if: steps.failure_issue_gate.outputs.should_block != 'true'
3285
run: |
3386
git config user.name "github-actions[bot]"
3487
git config user.email "github-actions[bot]@users.noreply.github.com"
3588
3689
# Toolchain setup for running CI checks on the updated submodule.
3790
# Steps match ci-pre-publish.yml to ensure parity with normal CI.
3891
- name: Install Linux system dependencies
92+
if: steps.failure_issue_gate.outputs.should_block != 'true'
3993
run: |
4094
# Required by opencode-broker (libpam-sys links against -lpam).
4195
sudo apt-get update
4296
sudo apt-get install -y libpam0g-dev
4397
4498
- name: Install Rust
99+
if: steps.failure_issue_gate.outputs.should_block != 'true'
45100
uses: dtolnay/rust-toolchain@stable
46101
with:
47102
components: rustfmt, clippy
48103

49104
- name: Install just
105+
if: steps.failure_issue_gate.outputs.should_block != 'true'
50106
uses: extractions/setup-just@v3
51107

52108
- name: Setup Node.js
109+
if: steps.failure_issue_gate.outputs.should_block != 'true'
53110
uses: actions/setup-node@v5
54111
with:
55112
node-version: '20'
56113

57114
- name: Setup Bun
115+
if: steps.failure_issue_gate.outputs.should_block != 'true'
58116
uses: ./.github/actions/setup-bun
59117

60118
- name: Rust cache
119+
if: steps.failure_issue_gate.outputs.should_block != 'true'
61120
uses: Swatinem/rust-cache@v2
62121

63122
- name: Update opencode commit
64123
id: update
124+
if: steps.failure_issue_gate.outputs.should_block != 'true'
65125
run: |
66126
./scripts/update-opencode-commit.sh
67127
@@ -70,7 +130,7 @@ jobs:
70130
# If checks fail, the workflow fails and the broken commit is never pushed.
71131
- name: Auto-format and run CI checks
72132
id: ci_checks
73-
if: steps.update.outputs.needs_update == 'true'
133+
if: steps.failure_issue_gate.outputs.should_block != 'true' && steps.update.outputs.needs_update == 'true'
74134
run: |
75135
set -euo pipefail
76136
@@ -88,16 +148,18 @@ jobs:
88148
89149
- name: Run e2e tests
90150
id: e2e_checks
91-
if: steps.update.outputs.needs_update == 'true'
151+
if: steps.failure_issue_gate.outputs.should_block != 'true' && steps.update.outputs.needs_update == 'true'
92152
run: just ci-e2e
93153
timeout-minutes: 30
94154

95155
- name: Verify OCI description label
96156
id: verify_oci
157+
if: steps.failure_issue_gate.outputs.should_block != 'true'
97158
run: python3 scripts/extract-oci-description.py packages/core/src/docker/Dockerfile
98159

99160
- name: Commit and push if changed
100161
id: commit_push
162+
if: steps.failure_issue_gate.outputs.should_block != 'true'
101163
run: |
102164
if git diff --quiet; then
103165
echo "No changes to commit."
@@ -127,9 +189,25 @@ jobs:
127189
git push
128190
echo "pushed=true" >> "$GITHUB_OUTPUT"
129191
192+
- name: Notice skipped update due to existing open failure issue
193+
if: steps.failure_issue_gate.outputs.should_block == 'true'
194+
env:
195+
EXISTING_FAILURE_ISSUE_NUMBER: ${{ steps.failure_issue_gate.outputs.existing_failure_issue_number }}
196+
EXISTING_FAILURE_ISSUE_URL: ${{ steps.failure_issue_gate.outputs.existing_failure_issue_url }}
197+
EXISTING_FAILURE_ISSUE_TITLE: ${{ steps.failure_issue_gate.outputs.existing_failure_issue_title }}
198+
run: |
199+
set -euo pipefail
200+
echo "::notice title=Update skipped::Scheduled run skipped because an open failure issue already exists (#${EXISTING_FAILURE_ISSUE_NUMBER}): ${EXISTING_FAILURE_ISSUE_TITLE} (${EXISTING_FAILURE_ISSUE_URL})"
201+
130202
- name: Write summary
131203
if: always()
132204
env:
205+
FAILURE_ISSUE_GATE_OUTCOME: ${{ steps.failure_issue_gate.outcome }}
206+
HAS_OPEN_FAILURE_ISSUE: ${{ steps.failure_issue_gate.outputs.has_open_failure_issue }}
207+
EXISTING_FAILURE_ISSUE_NUMBER: ${{ steps.failure_issue_gate.outputs.existing_failure_issue_number }}
208+
EXISTING_FAILURE_ISSUE_URL: ${{ steps.failure_issue_gate.outputs.existing_failure_issue_url }}
209+
EXISTING_FAILURE_ISSUE_TITLE: ${{ steps.failure_issue_gate.outputs.existing_failure_issue_title }}
210+
SHOULD_BLOCK: ${{ steps.failure_issue_gate.outputs.should_block }}
133211
UPDATE_OUTCOME: ${{ steps.update.outcome }}
134212
CI_CHECKS_OUTCOME: ${{ steps.ci_checks.outcome }}
135213
E2E_CHECKS_OUTCOME: ${{ steps.e2e_checks.outcome }}
@@ -168,6 +246,11 @@ jobs:
168246
updated="$(fallback "${UPDATED:-}")"
169247
changed="$(fallback "${CHANGED:-}")"
170248
pushed="$(fallback "${PUSHED:-}")"
249+
has_open_failure_issue="$(fallback "${HAS_OPEN_FAILURE_ISSUE:-}")"
250+
should_block="$(fallback "${SHOULD_BLOCK:-}")"
251+
existing_failure_issue_number="$(fallback "${EXISTING_FAILURE_ISSUE_NUMBER:-}")"
252+
existing_failure_issue_url="$(fallback "${EXISTING_FAILURE_ISSUE_URL:-}")"
253+
existing_failure_issue_title="$(fallback "${EXISTING_FAILURE_ISSUE_TITLE:-}")"
171254
172255
superproject_repo_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}"
173256
commit_link="n/a"
@@ -181,7 +264,9 @@ jobs:
181264
fi
182265
183266
status_line="ℹ️ No update needed"
184-
if [[ "${UPDATE_OUTCOME:-}" == "failure" || "${CI_CHECKS_OUTCOME:-}" == "failure" || "${E2E_CHECKS_OUTCOME:-}" == "failure" || "${VERIFY_OCI_OUTCOME:-}" == "failure" || "${COMMIT_PUSH_OUTCOME:-}" == "failure" || "${UPDATE_OUTCOME:-}" == "cancelled" || "${CI_CHECKS_OUTCOME:-}" == "cancelled" || "${E2E_CHECKS_OUTCOME:-}" == "cancelled" || "${VERIFY_OCI_OUTCOME:-}" == "cancelled" || "${COMMIT_PUSH_OUTCOME:-}" == "cancelled" ]]; then
267+
if [[ "${SHOULD_BLOCK:-}" == "true" ]]; then
268+
status_line="⏭️ Skipped due to open failure issue"
269+
elif [[ "${UPDATE_OUTCOME:-}" == "failure" || "${CI_CHECKS_OUTCOME:-}" == "failure" || "${E2E_CHECKS_OUTCOME:-}" == "failure" || "${VERIFY_OCI_OUTCOME:-}" == "failure" || "${COMMIT_PUSH_OUTCOME:-}" == "failure" || "${UPDATE_OUTCOME:-}" == "cancelled" || "${CI_CHECKS_OUTCOME:-}" == "cancelled" || "${E2E_CHECKS_OUTCOME:-}" == "cancelled" || "${VERIFY_OCI_OUTCOME:-}" == "cancelled" || "${COMMIT_PUSH_OUTCOME:-}" == "cancelled" ]]; then
185270
status_line="❌ Failed"
186271
elif [[ "${PUSHED:-}" == "true" ]]; then
187272
status_line="✅ Updated and pushed"
@@ -201,6 +286,8 @@ jobs:
201286
echo "**Dockerfile pin:** \`${current_pin} -> ${updated_pin}\`"
202287
echo ""
203288
echo "**Update flags:**"
289+
echo "- has_open_failure_issue: \`${has_open_failure_issue}\`"
290+
echo "- should_block: \`${should_block}\`"
204291
echo "- needs_update: \`${needs_update}\`"
205292
echo "- updated: \`${updated}\`"
206293
echo "- changed: \`${changed}\`"
@@ -217,8 +304,16 @@ jobs:
217304
else
218305
echo "- pushed superproject commit: ${commit_link}"
219306
fi
307+
if [[ "${existing_failure_issue_url}" == "n/a" ]]; then
308+
echo "- open failure issue: n/a"
309+
elif [[ "${existing_failure_issue_number}" == "n/a" ]]; then
310+
echo "- open failure issue: [${existing_failure_issue_title}](${existing_failure_issue_url})"
311+
else
312+
echo "- open failure issue: [#${existing_failure_issue_number} ${existing_failure_issue_title}](${existing_failure_issue_url})"
313+
fi
220314
echo ""
221315
echo "**Step outcomes:**"
316+
echo "- failure_issue_gate: \`${FAILURE_ISSUE_GATE_OUTCOME:-n/a}\`"
222317
echo "- update: \`${UPDATE_OUTCOME:-n/a}\`"
223318
echo "- ci_checks: \`${CI_CHECKS_OUTCOME:-n/a}\`"
224319
echo "- e2e_checks: \`${E2E_CHECKS_OUTCOME:-n/a}\`"
@@ -227,7 +322,7 @@ jobs:
227322
} >> "${GITHUB_STEP_SUMMARY}"
228323
229324
- name: Create issue on CI failure
230-
if: failure() && (steps.ci_checks.outcome == 'failure' || steps.e2e_checks.outcome == 'failure')
325+
if: failure() && (steps.ci_checks.outcome == 'failure' || steps.e2e_checks.outcome == 'failure') && steps.failure_issue_gate.outputs.has_open_failure_issue != 'true'
231326
env:
232327
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
233328
LATEST_COMMIT: ${{ steps.update.outputs.latest_commit }}

0 commit comments

Comments
 (0)