diff --git a/.github/workflows/ci-status-fallback.yml b/.github/workflows/ci-status-fallback.yml deleted file mode 100644 index c05c9df8fe1c..000000000000 --- a/.github/workflows/ci-status-fallback.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: CI status fallback - -on: - # CI is intentionally path-filtered below. Branch protection still requires - # the aggregate `ci-status` context for every pull request, so this small - # companion reports a neutral success when the routed CI workflow is skipped. - # Keep this list in sync with .github/workflows/ci.yml's pull_request.paths. - pull_request: - paths-ignore: - - ghostty - - scripts/download-prebuilt-ghosttykit.sh - - scripts/validate-xcframework-archive.py - - scripts/ghosttykit-checksums.txt - - tests/test_ci_ghosttykit_release_check.sh - - tests/test_ci_change_areas.py - - .github/workflows/ci.yml - types: [opened, edited, reopened, synchronize, ready_for_review] - workflow_dispatch: {} - -permissions: {} - -jobs: - ci-status: - name: ci-status - runs-on: ${{ vars.LINUX_RUNNER || 'blacksmith-4vcpu-ubuntu-2404' }} - timeout-minutes: 5 - steps: - - name: Report filtered CI as successful - run: | - echo "CI workflow was skipped because no routed CI trigger path changed." - echo "No CI area was selected for this pull request; ci-status is satisfied." diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e04c9183bca5..f9dff743905b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,21 +1,8 @@ name: CI on: - # Keep the full suite available for explicit validation, while always - # Changes to CI guard scripts also retrigger the full workflow through this path. - # running the lightweight GhosttyKit provenance check when its pointer, - # checksum, or helper changes in a PR. pull_request: - paths: - - ghostty - - scripts/download-prebuilt-ghosttykit.sh - - scripts/validate-xcframework-archive.py - - scripts/ghosttykit-checksums.txt - - tests/test_ci_ghosttykit_release_check.sh - - Resources/bin/cmux-hermes-agent-wrapper - - tests/test_hermes_wrapper_hooks.py - - tests/test_ci_change_areas.py - - .github/workflows/ci.yml + types: [opened, reopened, synchronize, ready_for_review] workflow_dispatch: permissions: @@ -708,6 +695,21 @@ jobs: sleep $((attempt * 5)) done + - name: Compile cmuxTests target + if: ${{ matrix.shard == 1 }} + run: | + set -euo pipefail + xcodebuild \ + -project cmux.xcodeproj \ + -scheme cmux-unit \ + -configuration Debug \ + -derivedDataPath "$CMUX_DERIVED_DATA_PATH" \ + -clonedSourcePackagesDirPath "$PWD/.ci-source-packages" \ + -disableAutomaticPackageResolution \ + -destination "platform=macOS" \ + "SWIFT_ACTIVE_COMPILATION_CONDITIONS=\$(inherited) CMUX_CI_APP_HOST_ISOLATION_REQUIRED" \ + build-for-testing + - name: Run Ghostty split-theme appearance regression if: ${{ matrix.shard == fromJSON(env.CMUX_APP_HOST_FOCUSED_REGRESSION_SHARD) }} run: | diff --git a/tests/test_ci_change_areas.py b/tests/test_ci_change_areas.py index 7a52d188a56e..555a35372cb2 100644 --- a/tests/test_ci_change_areas.py +++ b/tests/test_ci_change_areas.py @@ -128,6 +128,10 @@ def test_app_source_runs_macos() -> None: assert_areas(["Sources/AppDelegate.swift"], macos=True, web=False) +def test_test_only_changes_run_macos() -> None: + assert_areas(["cmuxTests/SurfaceCatalogTests.swift"], macos=True, web=False) + + def test_workflow_changes_run_everything() -> None: assert_areas( [".github/workflows/ci.yml"], @@ -212,6 +216,49 @@ def run_linux_preflight(needs: dict[str, object]) -> subprocess.CompletedProcess ) +def test_compile_gate_builds_entire_test_target_and_propagates_failure() -> None: + script = workflow_job_step_script("app-host-unit-tests", "Compile cmuxTests target") + with tempfile.TemporaryDirectory() as temp_dir: + root = Path(temp_dir) + fake_bin = root / "bin" + fake_bin.mkdir() + arguments_file = root / "arguments" + compiler = fake_bin / "xcodebuild" + compiler.write_text( + '#!/bin/bash\nprintf "%s\\n" "$@" > "$COMPILER_ARGUMENTS"\n' + 'exit "$COMPILER_EXIT_CODE"\n', + encoding="utf-8", + ) + compiler.chmod(0o755) + for exit_code in (0, 65): + result = subprocess.run( + ["bash", "-c", script], + cwd=root, + env={ + **os.environ, + "PATH": f"{fake_bin}:{os.environ['PATH']}", + "CMUX_DERIVED_DATA_PATH": str(root / "derived data"), + "COMPILER_ARGUMENTS": str(arguments_file), + "COMPILER_EXIT_CODE": str(exit_code), + }, + text=True, + capture_output=True, + ) + assert result.returncode == exit_code, (result.stdout, result.stderr) + arguments = arguments_file.read_text(encoding="utf-8").splitlines() + assert arguments == [ + "-project", "cmux.xcodeproj", + "-scheme", "cmux-unit", + "-configuration", "Debug", + "-derivedDataPath", str(root / "derived data"), + "-clonedSourcePackagesDirPath", str(root.resolve() / ".ci-source-packages"), + "-disableAutomaticPackageResolution", + "-destination", "platform=macOS", + "SWIFT_ACTIVE_COMPILATION_CONDITIONS=$(inherited) CMUX_CI_APP_HOST_ISOLATION_REQUIRED", + "build-for-testing", + ], arguments + + def run_app_host_unit_test_step( shard_mode: str = "selectors", ) -> tuple[subprocess.CompletedProcess[str], bool]: