Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
version: 2

updates:
# Actions are pinned to commit SHAs and the linters by image digest, which
# is what stops a moved tag changing what runs here. It is also what stops
# them updating on their own.
# The one action here is first-party and stays on a major tag deliberately:
# GitHub owns both the tag and the content a SHA would pin, so pinning moves
# trust from GitHub to GitHub. This entry is what keeps that tag current.
#
# The two linters ARE pinned, by image digest, because they are third party.
# They sit inside `run: docker run ...` blocks, which this ecosystem does not
# read, so those move by hand.
- package-ecosystem: github-actions
directory: /
schedule:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```

## Buy us a coffee?

If you feel like buying us a coffee (or a beer?), donations are welcome:
Expand Down
19 changes: 9 additions & 10 deletions commit-branch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ set -euo pipefail
# called as x="$(f)" keeps running after a failure instead of aborting.
shopt -s inherit_errexit

WORKDIR="${1:?usage: commit-branch.sh <workdir> <branch> <message>}"
BRANCH="${2:?usage: commit-branch.sh <workdir> <branch> <message>}"
MESSAGE="${3:?usage: commit-branch.sh <workdir> <branch> <message> [pathspec ...]}"
USAGE="usage: commit-branch.sh <workdir> <branch> <message> [pathspec ...]"
WORKDIR="${1:?$USAGE}"
BRANCH="${2:?$USAGE}"
MESSAGE="${3:?$USAGE}"
shift 3
PATHSPEC=("$@")

Expand All @@ -56,12 +57,10 @@ if ! git rev-parse --git-dir >/dev/null 2>&1; then
exit 1
fi

# Stage so git decides what changed, not a directory walk.
if [ "${#PATHSPEC[@]}" -gt 0 ]; then
git add -A -- "${PATHSPEC[@]}"
else
git add -A
fi
# Stage so git decides what changed, not a directory walk. An empty PATHSPEC
# expands to nothing, which after -- means exactly what passing no pathspec
# means; both diffs below already rely on that.
git add -A -- "${PATHSPEC[@]}"
# The oid of the commit this makes, for a caller that has to name it. Without
# it a caller can only ask GitHub to resolve the branch by name afterwards, and
# that is a race: a workflow dispatched seconds after this mutation can still
Expand All @@ -76,7 +75,7 @@ emit_sha() { # oid
printf 'sha=%s\n' "$1" >> "$GITHUB_OUTPUT"
}

if git diff --cached --quiet HEAD -- "${PATHSPEC[@]}" 2>/dev/null; then
if git diff --cached --quiet HEAD -- "${PATHSPEC[@]}"; then
log "nothing changed on $BRANCH"
emit_sha ""
exit 0
Expand Down
9 changes: 7 additions & 2 deletions tests/lint-action.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ body="$(mktemp)"
trap 'rm -f "$body"' EXIT

python3 - "$body" <<'PY'
import sys, yaml
import re, sys, yaml

class Strict(yaml.SafeLoader):
pass
Expand Down Expand Up @@ -51,9 +51,14 @@ assert step["shell"] == "bash", "run: without shell: bash is a load-time error"
# Compared on the env VALUES, not the names: an input is free to arrive under
# a different variable (token -> GITHUB_TOKEN), so matching names would report
# a gap that is not there.
# Matched on a word boundary. A plain substring test let an input whose name
# is a prefix of another's ("path" against a piped "pathspec") report as
# covered while never reaching the step -- the check passing on work it did
# not do, which is the one thing it exists to catch.
declared = set(doc["inputs"])
piped = " ".join(str(v) for v in step.get("env", {}).values())
missing = {name for name in declared if f"inputs.{name}" not in piped}
referenced = set(re.findall(r"inputs\.([A-Za-z0-9_-]+)", piped))
missing = declared - referenced
assert not missing, f"inputs never passed to the step: {sorted(missing)}"

# Expressions belong in env:, never in the run body, so a value containing
Expand Down
16 changes: 9 additions & 7 deletions tests/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,14 @@ fail=0
# Each group runs in a subshell, so a counter variable incremented inside one
# never reaches this scope. The tally goes through a file instead, which is
# the only way the assertion-count guard below can see anything at all.
# One scratch root for the whole suite, exported as TMPDIR so every mktemp
# below lands inside it. Three of the six groups cleaned up after themselves
# and three did not, and a group exiting early leaked whatever its own
# trailing rm would have removed.
TMPROOT="$(mktemp -d)"
export TMPDIR="$TMPROOT"
TALLY="$(mktemp)"
trap 'rm -f "$TALLY"' EXIT
trap 'rm -rf "$TMPROOT"' EXIT

ok() { printf ' ok %s\n' "$1"; echo ok >> "$TALLY"; }
no() { printf ' FAIL %s\n %s\n' "$1" "$2"; echo no >> "$TALLY"; fail=$((fail + 1)); }
Expand Down Expand Up @@ -60,7 +66,6 @@ echo "the signed-commit payload describes every change, deletions included"
mkdir -p "$work/bin"
cat > "$work/bin/curl" <<FAKE
#!/bin/sh
for a in "\$@"; do case "\$a" in --data@*) ;; esac; done
prev=""
for a in "\$@"; do
case "\$prev" in --data) cp "\${a#@}" "$work/payload.json" ;; esac
Expand All @@ -70,7 +75,7 @@ echo '{"data":{"createCommitOnBranch":{"commit":{"oid":"deadbeefdeadbeef","signa
FAKE
chmod +x "$work/bin/curl"

PATH="$work/bin:$PATH" "$ROOT/commit-branch.sh" "$repo" archive "test" >/dev/null 2>&1 || true
PATH="$work/bin:$PATH" "$ROOT/commit-branch.sh" "$repo" archive "test" >/dev/null 2>&1

if [ ! -f "$work/payload.json" ]; then
no "the payload is built" "no payload captured"
Expand Down Expand Up @@ -113,7 +118,7 @@ done
echo '{"data":{"createCommitOnBranch":{"commit":{"oid":"cafebabecafebabe","signature":{"isValid":true,"state":"VALID"}}}}}'
FAKE
chmod +x "$work/bin/curl"
PATH="$work/bin:$PATH" "$ROOT/commit-branch.sh" "$repo" master "cuts" png/ >/dev/null 2>&1 || true
PATH="$work/bin:$PATH" "$ROOT/commit-branch.sh" "$repo" master "cuts" png/ >/dev/null 2>&1

if [ ! -f "$work/payload.json" ]; then
no "a pathspec-scoped commit is built" "no payload captured"
Expand Down Expand Up @@ -182,7 +187,6 @@ FAKE
*) no "and it is labelled as the failure it is" "got [$out]" ;;
esac

cd /; rm -rf "$work"
exit $((fail > 0))
) || fail=$((fail + 1))

Expand Down Expand Up @@ -224,7 +228,6 @@ FAKE
>/dev/null 2>&1 && rc=0 || rc=$?
eq "an unset GITHUB_OUTPUT is not a failure" "0" "${rc:-1}"

cd /; rm -rf "$work"
exit $((fail > 0))
) || fail=$((fail + 1))

Expand Down Expand Up @@ -256,7 +259,6 @@ FAKE
# caller that tagged this would be naming an unsigned commit.
eq "and nothing is handed to the caller" "" "$(cat "$out")"

cd /; rm -rf "$work"
exit $((fail > 0))
) || fail=$((fail + 1))

Expand Down