diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9e801a5284..055e6c398c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -209,8 +209,11 @@ jobs: needs: detect # apps/desktop/e2e/update: a real install.sh install + packaged Desktop, # first run, "Update now" hand-off/relaunch, concurrent-update refusal. - # Advisory until it has proven stable on CI: its shards run with continue-on-error, so a - # red shard shows on the PR but does not fail all-checks-pass. + # Required when it runs: a PR that touches the Desktop update path (the + # classifier's e2e_desktop_update lane) cannot merge on a red shard. Like + # the Linux e2e-upgrade shards and the Windows install + update journey + # (tests / tests-os, gated on e2e_upgrade), it is skipped — and the skip + # counts as success — when the PR does not touch that path. if: needs.detect.outputs.e2e_desktop_update == 'true' uses: ./.github/workflows/e2e-desktop-update.yml diff --git a/.github/workflows/e2e-desktop-update.yml b/.github/workflows/e2e-desktop-update.yml index 68ce12f3c5..a84971f334 100644 --- a/.github/workflows/e2e-desktop-update.yml +++ b/.github/workflows/e2e-desktop-update.yml @@ -28,8 +28,8 @@ jobs: name: Desktop install/update E2E (Linux, ${{ matrix.cell }}) runs-on: ubuntu-latest-32-core timeout-minutes: 30 - # Advisory until stable on CI (see ci.yaml): a red shard does not fail the caller. - continue-on-error: true + # Required whenever the e2e_desktop_update lane fires (see ci.yaml): it was + # advisory until it proved stable, and every main push shard since has passed. strategy: fail-fast: false # One install per shard (every spec restores it; paths are baked in, so diff --git a/.github/workflows/windows-venv-e2e.yml b/.github/workflows/windows-venv-e2e.yml index 33bf7ef72d..5ec4ab0892 100644 --- a/.github/workflows/windows-venv-e2e.yml +++ b/.github/workflows/windows-venv-e2e.yml @@ -67,7 +67,7 @@ jobs: tests/hermes_cli/test_venv_holder_windows_live.py \ tests/hermes_cli/test_taskkill_identity_windows_live.py \ tests/hermes_cli/test_git_trampoline_windows_live.py \ - tests/hermes_cli/test_runtime_repair.py::TestWindowsRuntimeSelfLock + tests/pm/test_held_entry_windows_live.py - name: Run Telegram CLOSE-WAIT reconnect live E2E (#87057) shell: bash diff --git a/tests/ci/test_classify_changes.py b/tests/ci/test_classify_changes.py index 54875f75af..715726fef0 100644 --- a/tests/ci/test_classify_changes.py +++ b/tests/ci/test_classify_changes.py @@ -542,6 +542,44 @@ def _iter_if_expressions(job: object): yield cond +# (caller workflow, job, called workflow, lane input) for every real-update +# suite: each runs on a PR exactly when its lane fires and then gates the merge. +_REAL_UPDATE_LANES = ( + ("ci.yaml", "tests", "tests.yml", "e2e_upgrade"), + ("ci.yaml", "tests-os", "tests-os.yml", "e2e_upgrade"), + ("ci.yaml", "e2e-desktop-update", "e2e-desktop-update.yml", "e2e_desktop_update"), + ("tests-os.yml", "install-update-e2e", "windows-install-update-e2e.yml", "e2e_upgrade"), +) + + +@pytest.mark.parametrize("caller,job,called,lane", _REAL_UPDATE_LANES) +def test_real_update_suites_gate_the_merge_when_their_lane_fires(caller, job, called, lane): + """A real-update suite that runs but cannot fail the merge is decoration. + + Each one must reach ``all-checks-pass`` (directly, or through the + reusable workflow that calls it), be gated on its lane, and never be + ``continue-on-error``: a red shard has to block the PR it ran for. + """ + ci = _yaml(".github/workflows/ci.yaml") + caller_jobs = _yaml(f".github/workflows/{caller}")["jobs"] + assert caller_jobs[job]["uses"] == f"./.github/workflows/{called}" + gate = caller_jobs[job].get("if", "") + json.dumps(caller_jobs[job].get("with") or {}) + assert lane in gate, f"{caller}::{job} is not gated on {lane}" + root = job if caller == "ci.yaml" else "tests-os" + assert root in ci["jobs"]["all-checks-pass"]["needs"] + for name, body in _yaml(f".github/workflows/{called}")["jobs"].items(): + assert not body.get("continue-on-error"), f"{called}::{name} cannot fail the merge" + + +def test_windows_venv_e2e_runs_only_test_files_that_exist(): + """``run_tests.sh`` drops a missing path (or a ``::node`` selector) without + a word, so a stale entry silently stops running on every wine2e push.""" + text = (_REPO / ".github/workflows/windows-venv-e2e.yml").read_text(encoding="utf-8") + paths = re.findall(r"(tests/[\w/.:-]+)", text) + assert paths + assert [p for p in paths if "::" in p or not (_REPO / p).is_file()] == [] + + def _write_event(tmp_path, number: int | None = 88442) -> Path: payload = {"pull_request": {"number": number}} if number is not None else {} path = tmp_path / "event.json"