Public Access
Give the runner a node before asking it to run an action
Every job died on its first line: "Cannot find: node in PATH", from actions/checkout. act_runner executes each `uses:` action with node inside the job container, and the image this runner is configured with has none — so nothing in the pipeline had run yet, including the tests the image job gates on. A `run:` step is shell rather than node, so one placed ahead of the first action can fix the job it is in. It installs via apt-get, apk or dnf, whichever is there, and says plainly what to do when none of them is. git goes in alongside, named in the step rather than smuggled into it: checkout shells out to git the moment node has loaded it, so an image thin enough to lack one usually lacks the other, and finding that out separately costs another round trip through CI. The version is warned about, not enforced. Distributions pin nodejs to whatever shipped with the release — Ubuntu 24.04 still serves 18, past end of life and older than these actions declare — but act_runner hands an action whichever node is on PATH regardless of what it asked for, and it generally works. A warning is the right weight for something that explains a later inexplicable failure without being one. Repeated verbatim in all three jobs. It cannot be a local composite action, since that needs the checkout it exists to unblock, and YAML anchors that would deduplicate it are rejected by GitHub's parser. Byte-identical across the three so a diff shows drift. This is still a workaround. The fix is one line of the runner's own config.yaml pointing container.image at an image that ships node, as Gitea's default catthehacker/ubuntu:act-latest does; the step then costs a version check and nothing else. Kept regardless, because a pipeline that silently depends on a runner being configured correctly elsewhere fails confusingly when it is not. Verified by running the step's own script in ubuntu:24.04 and alpine:3.20, which have neither, and node:20-bookworm, which has both: installs where needed, no-ops where not, and warns only on the node 18 that Ubuntu gives. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,67 @@ jobs:
|
|||||||
name: build and test
|
name: build and test
|
||||||
runs-on: [linux]
|
runs-on: [linux]
|
||||||
steps:
|
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/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
|
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
|
||||||
@@ -61,6 +122,50 @@ jobs:
|
|||||||
name: android head
|
name: android head
|
||||||
runs-on: [linux]
|
runs-on: [linux]
|
||||||
steps:
|
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/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
|
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
|
||||||
@@ -114,6 +219,50 @@ jobs:
|
|||||||
needs: [build]
|
needs: [build]
|
||||||
runs-on: [linux]
|
runs-on: [linux]
|
||||||
steps:
|
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/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
# No docker/* actions here, deliberately. The build is single-architecture, so it
|
# No docker/* actions here, deliberately. The build is single-architecture, so it
|
||||||
|
|||||||
Reference in New Issue
Block a user