Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
494 changes: 12 additions & 482 deletions .github/workflows/ci-macos.yml

Large diffs are not rendered by default.

457 changes: 457 additions & 0 deletions .github/workflows/ci-release.yml

Large diffs are not rendered by default.

36 changes: 34 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,8 @@ jobs:
.github/workflows/ci.yml \
.github/workflows/ci-guards.yml \
.github/workflows/ci-web.yml \
.github/workflows/ci-macos.yml
.github/workflows/ci-macos.yml \
.github/workflows/ci-release.yml
do
mkdir -p "$trusted_root/$(dirname "$trusted_path")"
if [ -z "$trusted_base" ] || ! git show "$trusted_base:$trusted_path" > "$trusted_root/$trusted_path"; then
Expand Down Expand Up @@ -906,7 +907,7 @@ jobs:
for name in base_jobs.keys() | head_jobs.keys()
if base_jobs.get(name) != head_jobs.get(name)
}
release_only_jobs = {"release-admission", "release-build", "macos-status"}
release_only_jobs = {"macos-status"}
raise SystemExit(0 if changed and changed <= release_only_jobs else 1)
PY
then
Expand Down Expand Up @@ -1345,6 +1346,37 @@ jobs:
secrets:
GLAEDA_ROUTE_APP_KEY: ${{ secrets.GLAEDA_ROUTE_APP_KEY }}

# The unsigned Release app, reported on the pull request but not required:
# neither ci-status nor tests waits for it. It runs on a full suite whose
# router selected release_build, once the macOS workflow is done and its
# package lane built the Ghostty helper, and linux-preflight passed. A red
# app-host shard does not skip it, as it did not in ci-macos.yml. Main's
# full suite runs it on every run, so a Release break is red there too.
release:
needs:
- changes
- static-preflight
- linux-preflight
- macos
if: ${{ !cancelled() && needs.macos.outputs.ghostty_helper_sha256 != '' && needs.linux-preflight.result == 'success' && needs.changes.outputs.macos == 'true' && needs.changes.outputs.full_suite == 'true' && needs.changes.outputs.release_build == 'true' }}
permissions:
actions: read
attestations: read
contents: read
uses: ./.github/workflows/ci-release.yml
with:
cache_backend: ${{ inputs.cache_backend }}
release_archs: ${{ needs.macos.outputs.release_archs }}
ghostty_helper_sha256: ${{ needs.macos.outputs.ghostty_helper_sha256 }}
ghostty_helper_toolchain_sha256: ${{ needs.macos.outputs.ghostty_helper_toolchain_sha256 }}
ghostty_helper_sdk: ${{ needs.macos.outputs.ghostty_helper_sdk }}
# The picker's placement, as the macos call passes it. The picker never
# gives release-build the light pool, so it reads the std side label.
pr_runner: ${{ needs.changes.outputs.macos_pr_runner }}
pr_side_runner: ${{ needs.changes.outputs.macos_pr_side_runner }}
pr_owned_jobs: ${{ needs.changes.outputs.macos_pr_owned_jobs }}
pr_xcode_app: ${{ needs.changes.outputs.macos_pr_xcode_app }}

tests:
name: tests
needs:
Expand Down
2 changes: 1 addition & 1 deletion docs/ci-runners.md
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ and the retired self-hosted fleet failed `codesign` with
| `app-host-test-rerun.yml` `rerun` | `CI_SIDE_LANE_RUNNER` for macOS 26 products, attempt 1 only; macOS 15 products on Blacksmith macOS 15 | gui; it takes the product's root itself (`glaeda-canonical-root take`) |
| `cmux-tui.yml` macOS `lint`, `test`, `cdp-browser-smoke` | `CI_SIDE_LANE_RUNNER`, attempt 1 only | isolated (glaeda classes them by workflow and id) |
| `cmux-tui.yml` release-path dogfood `build` (`cmux-tui-build-package.yml`) | Blacksmith macOS 15 | the release packaging build, shared with the release and nightly callers; its matrix is planned once, so a re-run could not leave the minis |
| `ci-macos.yml` `release-build` | owned side lane via the picker (`release-build`, the picked std pool's side label, never the light pool), pull requests (attempt 1 or a manual re-run) and main's full-suite dispatch (attempt 1); else `MACOS_RUNNER_26` | isolated: an unsigned universal Release into its own DerivedData, Xcode 26.6 |
| `ci-release.yml` `release-build` | owned side lane via the picker (`release-build`, the picked std pool's side label, never the light pool), pull requests (attempt 1 or a manual re-run) and main's full-suite dispatch (attempt 1); else `MACOS_RUNNER_26` | isolated: an unsigned universal Release into its own DerivedData, Xcode 26.6 |
| `reload-build.yml` `build` | `CI_SIDE_LANE_RUNNER` for a macOS build when the runner input is `auto` or `blacksmith-6vcpu-macos-26`, attempt 1 only (iOS builds take Blacksmith); any other label as given | isolated: a Debug build into the workspace |
| low-volume GUI dispatches: `test-macos-suite`, `tmux-corpus`, `perf-activation`, command palette benchmarks | Blacksmith or the caller's runner input | 0 to 1 runs a week; they drive the app in the runner's own session, which a mini's runner lacks (E2E and the rerun use its console session) |
| `iroh-release-gate` version skew | Blacksmith macOS 15 | pins the macOS 15 pool's Xcode 26.3 |
Expand Down
18 changes: 16 additions & 2 deletions scripts/ci/detect_ci_change_areas.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ def normalize_path(path: str) -> str:
GUARD_WORKFLOW_PATH = ".github/workflows/ci-guards.yml"
WEB_WORKFLOW_PATH = ".github/workflows/ci-web.yml"
MACOS_WORKFLOW_PATH = ".github/workflows/ci-macos.yml"
# The Release build, called after ci-macos.yml and reported without gating ci-status.
RELEASE_WORKFLOW_PATH = ".github/workflows/ci-release.yml"
MACOS_XCODE_PROJECT_PATH = "cmux.xcodeproj/project.pbxproj"
MACOS_PRODUCT_TARGET = "cmux"
CLI_PRODUCT_TARGET = "cmux-cli"
Expand Down Expand Up @@ -320,6 +322,10 @@ def _changed_workflow_jobs(
macos=False, web=True, agent_session_web=True, cli=False,
swift_packages=False, release_build=False,
),
RELEASE_WORKFLOW_PATH: ChangeAreas(
macos=True, web=False, agent_session_web=False, cli=False,
swift_packages=False, release_build=True,
),
}
_JOB_CALL_RE = re.compile(
r"""(?m)^ uses:[ \t]*["']?\./(\.github/workflows/[A-Za-z0-9_.-]+\.ya?ml)["']?[ \t]*$"""
Expand Down Expand Up @@ -597,7 +603,7 @@ def _routed_job_areas(workflow: str, text: str, token: str) -> Optional[ChangeAr
cli=bool(naming & MACOS_CLI_LANE_JOBS), swift_packages=False,
release_build=bool(naming & _release_jobs(jobs)),
)
if workflow == WEB_WORKFLOW_PATH:
if workflow in {WEB_WORKFLOW_PATH, RELEASE_WORKFLOW_PATH}:
return _CALLED_WORKFLOW_AREAS[workflow]
selected = NO_AREAS
for name in naming:
Expand Down Expand Up @@ -783,7 +789,10 @@ def _load_macos_job_test_references(root: Path) -> Optional[tuple[frozenset[str]
)
if not indirect_guard_references:
return None
for workflow_path in (CI_WORKFLOW_PATH, GUARD_WORKFLOW_PATH, WEB_WORKFLOW_PATH, MACOS_WORKFLOW_PATH):
for workflow_path in (CI_WORKFLOW_PATH, GUARD_WORKFLOW_PATH, WEB_WORKFLOW_PATH, MACOS_WORKFLOW_PATH, RELEASE_WORKFLOW_PATH):
# A tree from before the Release workflow split has none.
if workflow_path == RELEASE_WORKFLOW_PATH and not (root / workflow_path).exists():
continue
references = macos_job_test_references(
(root / workflow_path).read_text(encoding="utf-8"),
indirect_guard_references,
Expand Down Expand Up @@ -1930,6 +1939,11 @@ def classify_files(paths: Iterable[str], *,
# but they cannot affect the web deployment or Release app bytes.
macos = True
continue
if path == RELEASE_WORKFLOW_PATH:
# The Release build's own workflow: it runs behind the macOS area.
macos = True
release_build = True
continue
if path == MACOS_WORKFLOW_PATH:
# A reusable macOS workflow edit exercises the Mac jobs it owns.
# Compared job by job against the base, the Release check runs
Expand Down
4 changes: 2 additions & 2 deletions scripts/ci/pr_runner_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ def light_side_lanes(plan: "RunJobs", runners: Sequence[Mapping[str, Any]], owne
label = side_label(light)
if not plan.side or not label or owned_slots.get(light, 0) <= owned_slots.get(root_label(light), 0):
return "", ()
# release-build stays with the picked pool: ci-macos.yml gives it only side_runner.
# release-build stays with the picked pool: ci.yml gives it only side_runner.
lanes = tuple(key for key in plan.side if key != RELEASE_BUILD_JOB)[:max(0, live_owned_free(runners, [label])[label])]
return (label, lanes) if lanes else ("", ())

Expand Down Expand Up @@ -722,7 +722,7 @@ def run_plan(*, macos: str | None, full_suite: str | None, unit_suite: str | Non
# Blacksmith macOS 15 image carries (the minis have Xcode 26.6 alone), so only
# a run without that helper build places it on an owned pool.
SWIFT_PACKAGE_JOB = "swift-package"
# ci-macos.yml release-build: the unsigned universal Release app nightly signs,
# ci-release.yml release-build: the unsigned universal Release app nightly signs,
# into its own workspace DerivedData with the lane's Xcode 26.6 (glaeda's hook
# classes it isolated: no GUI, product, canonical root or secrets). It runs
# after admission and swift-package-tests on its own machine.
Expand Down
2 changes: 1 addition & 1 deletion scripts/ci/reuse_release_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ def producer_for(api, artifact: dict, value: dict, current_run: str, current_att
if len(batch) < 100:
break
if not any(
job.get("name") in {"release-build", "macos / release-build"}
job.get("name") in {"release-build", "macos / release-build", "release / release-build"}
and job.get("status") == "completed"
and job.get("conclusion") == "success"
for job in jobs
Expand Down
1 change: 1 addition & 0 deletions scripts/ci/workflow_guard_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
# than naming them in a `run:`, so every group observes an edit to them.
".github/workflows/ci-macos.yml": frozenset(GROUPS),
".github/workflows/ci-web.yml": frozenset(GROUPS),
".github/workflows/ci-release.yml": frozenset(GROUPS),
".github/workflows/web-complexity.yml": frozenset(("ci",)),
".github/workflows/web-complexity-trusted.yml": frozenset(("ci",)),
".github/review-fabric-policy.json": frozenset(("preflight",)),
Expand Down
Loading
Loading