From d6f1c69bde00cd2f08795edabe70d33345485cb0 Mon Sep 17 00:00:00 2001 From: Yaraslau Tamashevich Date: Mon, 21 Sep 2026 20:44:53 +0200 Subject: [PATCH] ci: make a failed Clang download fail the step that downloads it, at all ten sites (fixes #681) Ten steps across `ci.yml` and `mutation.yml` installed the pinned Clang with wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} `wget -q` writes no error document, so on an HTTP 4xx/5xx it exits 8 having written zero bytes. `bash` then reads an empty script, does nothing, and exits 0. GitHub runs a bare `run:` as `bash -e {0}` -- errexit, and *not* pipefail -- so the pipeline's status is bash's. The step reported success having installed no compiler, and the leg went red several steps later at Configure, naming a missing `clang++` rather than the download that never happened. All ten now use the same three lines the `Install sccache` steps got in #683 (morph#672), so the repository has one download idiom rather than two: curl -sSL --fail -o /tmp/llvm.sh https://apt.llvm.org/llvm.sh test -s /tmp/llvm.sh sudo bash /tmp/llvm.sh ${{ env.CLANG_VERSION }} `--fail` makes curl report the HTTP status as its own exit code; writing to a file means nothing downstream runs when it does not arrive; `test -s` covers the one case `--fail` cannot see, a 200 with an empty body. This is not a retry policy and it does not make an apt.llvm.org outage less likely -- it makes the step that failed be the step the log names. The sites: ci.yml's linux-compilers, linux-sanitizers, linux-coverage, kanban-tsan, bank-sanitizers, ladder-sanitizers, linux-all-features (the `else` branch of its gcc/clang split), clang-format and clang-tidy, plus mutation.yml's install step. The full argument lives once, on linux-compilers; the other nine carry a three-line pointer to it. Proof, not assertion: each shape written to a file and run as `bash -e `, which is what GitHub does, against a local origin that serves `/llvm.sh` and 404s everything else. =========== OLD SHAPE, 404 (the defect) =========== step exit=0 =========== OLD SHAPE, 200 (the happy path) =========== llvm.sh ran, version argument = 22 step exit=0 =========== NEW SHAPE, 404 (must be non-zero) =========== curl: (22) The requested URL returned error: 404 step exit=22 =========== NEW SHAPE, 200 EMPTY BODY (must be non-zero) =========== step exit=1 =========== NEW SHAPE, 200 (must be zero and must run the script) =========== llvm.sh ran, version argument = 22 step exit=0 The old shape's 404 and its 200 are indistinguishable, which is the ticket. And against apt.llvm.org itself rather than a local stand-in: $ curl -sSL -o llvm.sh https://apt.llvm.org/does-not-exist.sh exit=0 564 bytes of error page $ curl -sSL --fail -o llvm.sh https://apt.llvm.org/does-not-exist.sh curl: (22) The requested URL returned error: 404 exit=22 Measured on 7d4ca453, GNU wget 1.25.0, curl 8.22.0, bash 5.3.15, Arch Linux. Not verified: the behaviour of `ubuntu-24.04`'s own curl and wget builds, and no CI run has yet exercised a deliberate 404 on a runner. The claim this rests on is that `curl --fail` exits non-zero on an HTTP error status, which is curl's documented contract and is the same property #683 already depends on at ten sccache sites on those same runners. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01VptDWG2fKr2vBnLSJcgzgW --- .github/workflows/ci.yml | 85 ++++++++++++++++++++++++++++++---- .github/workflows/mutation.yml | 7 ++- 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 66da9b468..547d822a5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -278,7 +278,34 @@ jobs: run: | sudo apt-get update -q sudo apt-get install -y ninja-build catch2 - wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} + # Download, check, then execute -- not + # `wget -qO- https://apt.llvm.org/llvm.sh | sudo bash` (morph#681). + # `wget -q` writes no error document, so on an HTTP 4xx/5xx it exits + # 8 having written zero bytes. `bash` then reads an empty script, + # does nothing, and exits 0 -- and GitHub runs `run:` under `bash -e` + # without pipefail, so the pipeline's status is bash's, not wget's. + # The step therefore reported success having installed no compiler, + # and the leg went red several steps later at Configure, naming a + # missing compiler rather than the download that never happened. + # + # Measured against apt.llvm.org itself, on a path that 404s: + # + # $ curl -sSL -o llvm.sh https://apt.llvm.org/does-not-exist.sh + # exit=0 564 bytes of error page + # $ curl -sSL --fail -o llvm.sh https://apt.llvm.org/does-not-exist.sh + # curl: (22) The requested URL returned error: 404 + # exit=22 + # + # Same three lines as the `Install sccache` steps (morph#672), so the + # repository has one download idiom rather than two: `--fail` so the + # download reports its own failure, a file so nothing downstream runs + # when it does, and `test -s` for the 200-with-empty-body case that + # `--fail` cannot see. This is not a retry policy and it does not make + # an apt.llvm.org outage less likely -- it makes the step that failed + # be the step the log names. + curl -sSL --fail -o /tmp/llvm.sh https://apt.llvm.org/llvm.sh + test -s /tmp/llvm.sh + sudo bash /tmp/llvm.sh ${{ env.CLANG_VERSION }} # Keyed by preset alone, not this job's name: gcc-debug/clang-debug's # object files are the same ones linux-qt, ladder-tests, valgrind (for @@ -464,7 +491,12 @@ jobs: run: | sudo apt-get update -q sudo apt-get install -y ninja-build catch2 libsqlite3-dev - wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} + # --fail, a file, and a non-empty check -- never `wget -qO- | sudo + # bash`: see linux-compilers' identical install step for why the piped + # form reported success having installed nothing (morph#681). + curl -sSL --fail -o /tmp/llvm.sh https://apt.llvm.org/llvm.sh + test -s /tmp/llvm.sh + sudo bash /tmp/llvm.sh ${{ env.CLANG_VERSION }} # Keyed by preset alone, matching linux-compilers' cache above: this # matrix's clang-asan/clang-tsan legs share the same preset name (and @@ -627,7 +659,12 @@ jobs: run: | sudo apt-get update -q sudo apt-get install -y ninja-build catch2 libsqlite3-dev - wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} + # --fail, a file, and a non-empty check -- never `wget -qO- | sudo + # bash`: see linux-compilers' identical install step for why the piped + # form reported success having installed nothing (morph#681). + curl -sSL --fail -o /tmp/llvm.sh https://apt.llvm.org/llvm.sh + test -s /tmp/llvm.sh + sudo bash /tmp/llvm.sh ${{ env.CLANG_VERSION }} # examples/common's hand-written GUI/testkit code is real coverage of # morph's client stack (Bridge, backends, QtExecutor, completions -- @@ -846,7 +883,12 @@ jobs: # test run itself stays off-GUI. sudo apt-get install -y ninja-build catch2 libsqlite3-dev \ unixodbc-dev libsqliteodbc libyaml-cpp-dev libzip-dev libgl1-mesa-dev - wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} + # --fail, a file, and a non-empty check -- never `wget -qO- | sudo + # bash`: see linux-compilers' identical install step for why the piped + # form reported success having installed nothing (morph#681). + curl -sSL --fail -o /tmp/llvm.sh https://apt.llvm.org/llvm.sh + test -s /tmp/llvm.sh + sudo bash /tmp/llvm.sh ${{ env.CLANG_VERSION }} # Not the distro's Qt: examples/common/CMakeLists.txt requires 6.5+ # unconditionally and Ubuntu 24.04 still ships 6.4.2 — the same gap @@ -1041,7 +1083,12 @@ jobs: # target installs. sudo apt-get install -y ninja-build catch2 libsqlite3-dev \ unixodbc-dev libsqliteodbc libyaml-cpp-dev libzip-dev libgl1-mesa-dev - wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} + # --fail, a file, and a non-empty check -- never `wget -qO- | sudo + # bash`: see linux-compilers' identical install step for why the piped + # form reported success having installed nothing (morph#681). + curl -sSL --fail -o /tmp/llvm.sh https://apt.llvm.org/llvm.sh + test -s /tmp/llvm.sh + sudo bash /tmp/llvm.sh ${{ env.CLANG_VERSION }} # Not the distro's Qt: examples/common/CMakeLists.txt requires 6.5+ # unconditionally and Ubuntu 24.04 still ships 6.4.2 — the same gap @@ -1775,7 +1822,12 @@ jobs: # same set every other ladder-building Linux job installs. sudo apt-get install -y ninja-build catch2 libsqlite3-dev \ unixodbc-dev libsqliteodbc libyaml-cpp-dev libzip-dev libgl1-mesa-dev - wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} + # --fail, a file, and a non-empty check -- never `wget -qO- | sudo + # bash`: see linux-compilers' identical install step for why the piped + # form reported success having installed nothing (morph#681). + curl -sSL --fail -o /tmp/llvm.sh https://apt.llvm.org/llvm.sh + test -s /tmp/llvm.sh + sudo bash /tmp/llvm.sh ${{ env.CLANG_VERSION }} # Not the distro's Qt: examples/common/CMakeLists.txt requires 6.5+ # unconditionally and Ubuntu 24.04 still ships 6.4.2 — the same gap @@ -2041,7 +2093,12 @@ jobs: sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-15 15 sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-15 15 else - wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} + # --fail, a file, and a non-empty check -- never `wget -qO- | sudo + # bash`: see linux-compilers' identical install step for why the piped + # form reported success having installed nothing (morph#681). + curl -sSL --fail -o /tmp/llvm.sh https://apt.llvm.org/llvm.sh + test -s /tmp/llvm.sh + sudo bash /tmp/llvm.sh ${{ env.CLANG_VERSION }} fi # Not the distro's Qt: MORPH_BUILD_FORMS_QML needs 6.5+ (see the version @@ -2396,7 +2453,12 @@ jobs: - name: Install clang-format ${{ env.CLANG_VERSION }} run: | - wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} + # --fail, a file, and a non-empty check -- never `wget -qO- | sudo + # bash`: see linux-compilers' identical install step for why the piped + # form reported success having installed nothing (morph#681). + curl -sSL --fail -o /tmp/llvm.sh https://apt.llvm.org/llvm.sh + test -s /tmp/llvm.sh + sudo bash /tmp/llvm.sh ${{ env.CLANG_VERSION }} sudo apt-get install -y clang-format-${{ env.CLANG_VERSION }} - name: Check every tracked C++ file against .clang-format @@ -2463,7 +2525,12 @@ jobs: unixodbc-dev libsqliteodbc libyaml-cpp-dev libzip-dev \ libgl1-mesa-dev libxkbcommon-x11-0 libxcb-cursor0 libxcb-icccm4 \ libxcb-keysyms1 libxcb-shape0 libxcb-xinerama0 - wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} + # --fail, a file, and a non-empty check -- never `wget -qO- | sudo + # bash`: see linux-compilers' identical install step for why the piped + # form reported success having installed nothing (morph#681). + curl -sSL --fail -o /tmp/llvm.sh https://apt.llvm.org/llvm.sh + test -s /tmp/llvm.sh + sudo bash /tmp/llvm.sh ${{ env.CLANG_VERSION }} sudo apt-get install -y clang-tidy-${{ env.CLANG_VERSION }} # Here rather than in a lint job of its own because this is the only job diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 03ae0cea2..77e319d4c 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -76,7 +76,12 @@ jobs: run: | sudo apt-get update -q sudo apt-get install -y ninja-build catch2 - wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} + # --fail, a file, and a non-empty check -- never `wget -qO- | sudo + # bash`: see ci.yml's linux-compilers install step for why the piped + # form reported success having installed nothing (morph#681). + curl -sSL --fail -o /tmp/llvm.sh https://apt.llvm.org/llvm.sh + test -s /tmp/llvm.sh + sudo bash /tmp/llvm.sh ${{ env.CLANG_VERSION }} # Not automated inside scripts/mutation.sh itself on purpose (that # script's own header: "a script that downloads a toolchain behind your