Skip to content

Wait for Swift CI before TestFlight ships - #245

Merged
jaywedgeworth22 merged 2 commits into
mainfrom
cursor/compile-gate-ship-wait-08e1
Oct 15, 2026
Merged

jaywedgeworth22 merged 2 commits into
mainfrom
cursor/compile-gate-ship-wait-08e1

Conversation

@jaywedgeworth22

@jaywedgeworth22 jaywedgeworth22 commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Contexts: Mac package build and test, iOS companion compile, gitleaks. Do not require the workflow titles. Leave #241 unmerged; it adds another macos-latest job and a different check name.

Summary

Adds a compile-gate wait ahead of every TestFlight and Sparkle ship lane so a macOS runner is only started after the Swift CI compile checks have succeeded on the exact commit. The ship/no-ship decision and the wait both run on ubuntu-latest, so a skipped scheduled tick no longer queues a macOS runner at all.

Changes

Workflow restructure

  • .github/workflows/ios-ship.yml: Split the single macOS job into a gate job (runs on ubuntu-latest) and a ship job (runs on macos-latest). The gate still evaluates whether the commit should ship, and when it should, it waits for the Swift CI compile checks on that commit. The ship job now needs: gate and runs only when the gate succeeded and reported should_ship == '1'. The per-step should_ship guards were removed because the ship job is now already gated by its needs condition, and checks: read was added to the workflow permissions.
  • .github/workflows/macos-ship.yml: Added a new await-swift-ci job on ubuntu-latest that waits for Swift CI on main, and made the Mac TestFlight ship job depend on it via needs with a required success result. checks: read was added to workflow permissions.
  • .github/workflows/mac-release.yml: The existing await-swift-ci job now runs for every non-fork event (previously push only), checks out the repo, and delegates the polling to the new script. It targets the pull request head SHA when available, otherwise the commit SHA. The inline polling loop was removed, and the release job no longer uses always() / skipped-needs handling — it now requires await-swift-ci to succeed.

New scripts

  • scripts/await-swift-ci-checks.sh: Polls GitHub check runs until every named check's newest github-actions run succeeds. Defaults to the Mac package build and test and iOS companion compile Swift CI jobs, and accepts custom check names. Supports a configurable deadline and poll interval, a one-shot mode (ONCE) for decisions without polling, and a CHECKS_JSON fixture mode for offline use. Exits 0 on success, 1 on failure or timeout, and 2 when checks are still pending.
  • scripts/swift_ci_check_status.py: Classifies check-run payloads into success, failure, or pending. The newest run for each requested name wins so a rerun supersedes a cancelled attempt; a concluded non-success (including skipped) fails the gate; failure takes precedence over pending; runs from other apps are ignored.
  • scripts/compile_gate_ruleset.py: Builds the repository ruleset update body that adds required status checks for Mac package build and test, iOS companion compile, and gitleaks, preserving other rules, bypass actors, and conditions. Does not call GitHub.
  • scripts/apply-main-compile-gate-ruleset.sh: Applies that ruleset change. Dry-run by default; --apply refuses unless the required checks are already successful on the default branch tip. Prints the current vs. proposed contexts and retained rules.
  • scripts/compile_gate_checks_test.py: Unit tests covering the check classifier, the ruleset body construction, and the await script's fixture behavior.

Docs

  • docs/rollouts/2026-10-15-cc19-compile-gate.md: Updated to describe the ubuntu-based wait for Mac Release and the iOS/Mac TestFlight lanes, the new ruleset script, and the updated verification commands.

cursoragent and others added 2 commits October 15, 2026 07:23
Mac Release already waits on push.  workflow_dispatch now uses the same check, and a skipped companion fails the wait instead of polling until timeout.  iOS and Mac TestFlight wait on ubuntu before taking a macOS runner, and the scheduled iOS skip no longer queues one.  The ruleset script refuses to require the new check names until they are green on main.

Co-authored-by: Jay Wedgeworth <jaywedgeworth22@users.noreply.github.com>
A pull request that touches the release workflow was still starting a macos-latest bundle build beside Swift CI.  The ubuntu wait now covers that event, using the pull request head SHA where the checks are reported.

Co-authored-by: Jay Wedgeworth <jaywedgeworth22@users.noreply.github.com>
@jaywedgeworth22
jaywedgeworth22 merged commit 7111f49 into main Oct 15, 2026
2 checks passed
@kody-ai

kody-ai Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Code Review Completed! 🔥

The code review was successfully completed based on your current configurations.

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug ✅
Performance ✅
Security ✅
Business Logic ✅

Access your configuration settings here.

​

@kody-ai

kody-ai Bot commented Oct 15, 2026

Copy link
Copy Markdown

kody code-review Business Logic medium

🤔 Insufficient Task Context

I found a task linked to this PR, but it only contains minimal information (title only, no description or acceptance criteria). To perform a meaningful business rules validation, I need more details.

🔍 What I need to validate:

  • Business requirements and acceptance criteria
  • Expected behavior and business rules
  • Edge cases and constraints to consider

💡 How to improve the task context:

  • Add a description to the linked ticket
  • Include acceptance criteria or business rules
  • Describe the expected behavior after the change

⚠️ Important:

A task title alone is not sufficient to determine whether the implementation is correct or complete.


💡 This validation runs automatically only on the first review of a pull request. To run it again, comment @kody -v business-logic.

## Verification (agents)

```bash
python3 scripts/compile_gate_checks_test.py

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kody code-review Kody Rules medium

Verification section gap in docs/rollouts/2026-10-15-cc19-compile-gate.md: rule 14 requires the section to list, in order, npm run lint, npx tsc --noEmit, npm test, and npm run build, each paired with a pass/fail outcome, but the added line is a bare python3 scripts/compile_gate_checks_test.py that names none of the four required CI guard commands and carries no pass/fail status, so the note reads as ad-hoc verification rather than the mandated four-step build/test gate.

Also found in:

  • docs/rollouts/2026-10-15-cc19-compile-gate.md:40-40
  • docs/rollouts/2026-10-15-cc19-compile-gate.md:39-39

Kody rule violation: Mandatory pre-commit handoff protocol and verification trio before claiming work done

Prompt for LLM

File docs/rollouts/2026-10-15-cc19-compile-gate.md:

Line 36:

Verification section gap in `docs/rollouts/2026-10-15-cc19-compile-gate.md`: rule 14 requires the section to list, in order, `npm run lint`, `npx tsc --noEmit`, `npm test`, and `npm run build`, each paired with a pass/fail outcome, but the added line is a bare `python3 scripts/compile_gate_checks_test.py` that names none of the four required CI guard commands and carries no pass/fail status, so the note reads as ad-hoc verification rather than the mandated four-step build/test gate.

**Also found in:**
- `docs/rollouts/2026-10-15-cc19-compile-gate.md:40-40`
- `docs/rollouts/2026-10-15-cc19-compile-gate.md:39-39`

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

​

​

Comment on lines +61 to +71
updated_rules = []
replaced = False
new_rule = required_status_checks_rule()
for rule in ruleset.get("rules") or []:
if rule.get("type") == "required_status_checks":
updated_rules.append(new_rule)
replaced = True
else:
updated_rules.append(rule)
if not replaced:
updated_rules.append(new_rule)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kody code-review Bug high

Duplicate rule bug in with_required_checks (scripts/compile_gate_ruleset.py): the loop appends new_rule for every existing required_status_checks entry while replaced = True is set on the first match, and if not replaced appends again, producing N copies per N old rules — an input with multiple required_status_checks entries yields a PUT body with duplicates that the ruleset API rejects. The test at line 163 only covers the single-rule case, so the gap is silent. Fix it by building kept_rules = [r for r in (ruleset.get("rules") or []) if r.get("type") != "required_status_checks"] and setting updated_rules = kept_rules + [required_status_checks_rule()].

kept_rules = [
    rule for rule in (ruleset.get("rules") or [])
    if rule.get("type") != "required_status_checks"
]
updated_rules = kept_rules + [required_status_checks_rule()]
Prompt for LLM

File scripts/compile_gate_ruleset.py:

Line 61 to 71:

Duplicate rule bug in `with_required_checks` (`scripts/compile_gate_ruleset.py`): the loop appends `new_rule` for every existing `required_status_checks` entry while `replaced = True` is set on the first match, and `if not replaced` appends again, producing N copies per N old rules — an input with multiple `required_status_checks` entries yields a PUT body with duplicates that the ruleset API rejects. The test at line 163 only covers the single-rule case, so the gap is silent. Fix it by building `kept_rules = [r for r in (ruleset.get("rules") or []) if r.get("type") != "required_status_checks"]` and setting `updated_rules = kept_rules + [required_status_checks_rule()]`.

Suggested Code:

    kept_rules = [
        rule for rule in (ruleset.get("rules") or [])
        if rule.get("type") != "required_status_checks"
    ]
    updated_rules = kept_rules + [required_status_checks_rule()]

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

​

​

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants