diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d83f64..37f42fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,67 @@ jobs: name: build and test runs-on: [linux] steps: + # act_runner runs every `uses:` action with node inside the job container, and this + # runner's image has none — the run died on the first line of actions/checkout with + # "Cannot find: node in PATH". A `run:` step is shell rather than node, so this one + # can go first and unblock the rest. + # + # This is a workaround and the real fix is one line of the runner's own config.yaml: + # point container.image at an image that ships node, the way Gitea's default + # catthehacker/ubuntu:act-latest does. Kept anyway, because a pipeline that depends + # on a runner being configured correctly somewhere else fails confusingly when it is + # not, and because it costs nothing on a runner that is. + # + # git as well as node, and said in the step name rather than smuggled in: checkout + # shells out to git the moment node has loaded it, so an image thin enough to lack + # one usually lacks the other, and learning that costs a whole second CI round trip. + # + # Repeated verbatim in all three jobs, which is not laziness. It cannot be a local + # composite action — that would need the checkout it exists to unblock — and YAML + # anchors, which would deduplicate it, are rejected by GitHub's parser and would make + # this file portable to nothing. Change one copy, change all three. + - name: ensure node and git + run: | + set -eu + SUDO="" + [ "$(id -u)" -eq 0 ] || SUDO="sudo" + + missing="" + command -v node >/dev/null 2>&1 || missing="$missing nodejs" + command -v git >/dev/null 2>&1 || missing="$missing git" + + if [ -z "$missing" ]; then + echo "node $(node --version), git $(git --version)" + exit 0 + fi + + echo "Installing:$missing" + if command -v apt-get >/dev/null 2>&1; then + $SUDO apt-get update -qq + $SUDO apt-get install -y --no-install-recommends $missing + elif command -v apk >/dev/null 2>&1; then + $SUDO apk add --no-cache $missing + elif command -v dnf >/dev/null 2>&1; then + $SUDO dnf install -y $missing + else + echo "No apt-get, apk or dnf here, so node cannot be installed from inside the" >&2 + echo "job. Point the runner's container.image at something that ships node." >&2 + exit 1 + fi + echo "node $(node --version), git $(git --version)" + + # Warned about rather than failed on. Distributions pin their nodejs package to + # the release they shipped with — Ubuntu 24.04 still serves 18, which is past end + # of life and older than the runtime these actions declare. It generally runs + # them anyway, since act_runner uses whichever node is on PATH regardless of what + # the action asked for, so this is a note for when one of them misbehaves in a + # way that makes no sense, not a reason to stop a build that is probably fine. + major="$(node --version | sed 's/^v//; s/\..*//')" + if [ "$major" -lt 20 ]; then + echo "::warning::node $major is older than the runtime these actions target;" \ + "give the runner an image with node 20 or newer if actions misbehave." + fi + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 @@ -61,6 +122,50 @@ jobs: name: android head runs-on: [linux] steps: + # Duplicated from the build job; see the comment there for why it cannot be factored + # out. Any change here has to be made in all three. + - name: ensure node and git + run: | + set -eu + SUDO="" + [ "$(id -u)" -eq 0 ] || SUDO="sudo" + + missing="" + command -v node >/dev/null 2>&1 || missing="$missing nodejs" + command -v git >/dev/null 2>&1 || missing="$missing git" + + if [ -z "$missing" ]; then + echo "node $(node --version), git $(git --version)" + exit 0 + fi + + echo "Installing:$missing" + if command -v apt-get >/dev/null 2>&1; then + $SUDO apt-get update -qq + $SUDO apt-get install -y --no-install-recommends $missing + elif command -v apk >/dev/null 2>&1; then + $SUDO apk add --no-cache $missing + elif command -v dnf >/dev/null 2>&1; then + $SUDO dnf install -y $missing + else + echo "No apt-get, apk or dnf here, so node cannot be installed from inside the" >&2 + echo "job. Point the runner's container.image at something that ships node." >&2 + exit 1 + fi + echo "node $(node --version), git $(git --version)" + + # Warned about rather than failed on. Distributions pin their nodejs package to + # the release they shipped with — Ubuntu 24.04 still serves 18, which is past end + # of life and older than the runtime these actions declare. It generally runs + # them anyway, since act_runner uses whichever node is on PATH regardless of what + # the action asked for, so this is a note for when one of them misbehaves in a + # way that makes no sense, not a reason to stop a build that is probably fine. + major="$(node --version | sed 's/^v//; s/\..*//')" + if [ "$major" -lt 20 ]; then + echo "::warning::node $major is older than the runtime these actions target;" \ + "give the runner an image with node 20 or newer if actions misbehave." + fi + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 @@ -114,6 +219,50 @@ jobs: needs: [build] runs-on: [linux] steps: + # Duplicated from the build job; see the comment there for why it cannot be factored + # out. Any change here has to be made in all three. + - name: ensure node and git + run: | + set -eu + SUDO="" + [ "$(id -u)" -eq 0 ] || SUDO="sudo" + + missing="" + command -v node >/dev/null 2>&1 || missing="$missing nodejs" + command -v git >/dev/null 2>&1 || missing="$missing git" + + if [ -z "$missing" ]; then + echo "node $(node --version), git $(git --version)" + exit 0 + fi + + echo "Installing:$missing" + if command -v apt-get >/dev/null 2>&1; then + $SUDO apt-get update -qq + $SUDO apt-get install -y --no-install-recommends $missing + elif command -v apk >/dev/null 2>&1; then + $SUDO apk add --no-cache $missing + elif command -v dnf >/dev/null 2>&1; then + $SUDO dnf install -y $missing + else + echo "No apt-get, apk or dnf here, so node cannot be installed from inside the" >&2 + echo "job. Point the runner's container.image at something that ships node." >&2 + exit 1 + fi + echo "node $(node --version), git $(git --version)" + + # Warned about rather than failed on. Distributions pin their nodejs package to + # the release they shipped with — Ubuntu 24.04 still serves 18, which is past end + # of life and older than the runtime these actions declare. It generally runs + # them anyway, since act_runner uses whichever node is on PATH regardless of what + # the action asked for, so this is a note for when one of them misbehaves in a + # way that makes no sense, not a reason to stop a build that is probably fine. + major="$(node --version | sed 's/^v//; s/\..*//')" + if [ "$major" -lt 20 ]; then + echo "::warning::node $major is older than the runtime these actions target;" \ + "give the runner an image with node 20 or newer if actions misbehave." + fi + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 # No docker/* actions here, deliberately. The build is single-architecture, so it