Initial Commit
This commit is contained in:
186
tests/test_next_steps.sh
Executable file
186
tests/test_next_steps.sh
Executable file
@@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# scripts/next_steps.sh contract (operator-first scaffold):
|
||||
# 1. Default manifest is operator_setup_steps.json; default recipe is
|
||||
# operator-setup. Steps are read from the manifest; no hardcoding.
|
||||
# 2. --manifest contributor_setup_steps.json --recipe contributor-setup
|
||||
# swaps to the contributor dev-env bootstrap without changing the
|
||||
# runner logic.
|
||||
# 3. Missing manifest prints [warn] and references the orchestrator README.
|
||||
# 4. Flags (--headless, --yes, --skip-optional, --only) forward verbatim
|
||||
# to whichever recipe is selected.
|
||||
# 5. --run mode execs `just <recipe>` in the orchestrator cwd.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd "$(dirname "$0")" && pwd -P)"
|
||||
root="$(cd "$here/.." && pwd -P)"
|
||||
|
||||
pass=0
|
||||
fail=0
|
||||
assert() {
|
||||
local msg="$1"; shift
|
||||
if "$@"; then
|
||||
printf '[ok] %s\n' "$msg"; pass=$((pass + 1))
|
||||
else
|
||||
printf '[FAIL] %s\n' "$msg"; fail=$((fail + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
tmp="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
|
||||
# --- Sandbox ---------------------------------------------------------
|
||||
export FORGE_GITEA_URL="http://127.0.0.1:1"
|
||||
export FORGE_GITEA_ORG="x"
|
||||
export FORGE_GITEA_USERNAME="sandbox"
|
||||
export FORGE_ORCHESTRATOR_REPO_URL="http://127.0.0.1:1/x/forge-stack-orchestrator.git"
|
||||
export FORGE_WORKSPACE_ROOT="$tmp/workspace"
|
||||
unset FORGE_ORCHESTRATOR_BRANCH FSDGG_AUTH_STORE_PATH FSDGG_RUNTIME_DIR
|
||||
|
||||
mkdir -p "$tmp/workspace" "$tmp/fakebin"
|
||||
mkdir -p "$tmp/welcome/scripts"
|
||||
cp "$root/scripts/common.sh" "$tmp/welcome/scripts/"
|
||||
cp "$root/scripts/next_steps.sh" "$tmp/welcome/scripts/"
|
||||
touch "$tmp/welcome/Justfile"
|
||||
|
||||
cat >"$tmp/welcome/.env" <<EOF
|
||||
FORGE_GITEA_URL=$FORGE_GITEA_URL
|
||||
FORGE_GITEA_ORG=$FORGE_GITEA_ORG
|
||||
FORGE_GITEA_USERNAME=$FORGE_GITEA_USERNAME
|
||||
FORGE_ORCHESTRATOR_REPO_URL=$FORGE_ORCHESTRATOR_REPO_URL
|
||||
FORGE_WORKSPACE_ROOT=$FORGE_WORKSPACE_ROOT
|
||||
EOF
|
||||
|
||||
mkdir -p "$tmp/workspace/forge-stack-orchestrator/.git"
|
||||
mkdir -p "$tmp/workspace/forge-stack-orchestrator/scripts"
|
||||
|
||||
# --- Shared manifest fixtures ---------------------------------------
|
||||
# Fixture step ids / commands are deliberately generic. The runner is
|
||||
# manifest-agnostic; the real manifests live in the (private) orchestrator.
|
||||
cat >"$tmp/workspace/forge-stack-orchestrator/scripts/operator_setup_steps.json" <<'JSON'
|
||||
{
|
||||
"schema_version": 1,
|
||||
"description": "Operator manifest under test.",
|
||||
"steps": [
|
||||
{"id": "op-step-a", "title": "Operator step A", "cmd": ["bash", "-c", "true"], "desc": "Operator A desc."},
|
||||
{"id": "op-step-b", "title": "Operator step B", "cmd": ["bash", "-c", "true"], "desc": "Operator B desc."},
|
||||
{"id": "op-step-c", "title": "Operator step C", "cmd": ["bash", "-c", "true"], "desc": "Operator C desc.", "optional": true}
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
cat >"$tmp/workspace/forge-stack-orchestrator/scripts/contributor_setup_steps.json" <<'JSON'
|
||||
{
|
||||
"schema_version": 1,
|
||||
"steps": [
|
||||
{"id": "cstep-a", "title": "Contributor A", "cmd": ["bash", "-c", "true"], "desc": "Contributor A."},
|
||||
{"id": "cstep-b", "title": "Contributor B", "cmd": ["bash", "-c", "true"], "desc": "Contributor B."}
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
# --- Case 1: default (no args) renders the OPERATOR plan ------------
|
||||
set +e
|
||||
bash -c "cd '$tmp/welcome' && bash scripts/next_steps.sh" \
|
||||
>"$tmp/default.out" 2>"$tmp/default.err"
|
||||
rc=$?
|
||||
set -e
|
||||
assert 'default: exits 0 when operator manifest present' bash -c "[ $rc -eq 0 ]"
|
||||
assert 'default: operator_setup_steps.json is the source' \
|
||||
grep -qF 'operator_setup_steps.json' "$tmp/default.err"
|
||||
assert 'default: emits id: op-step-a from operator manifest' \
|
||||
grep -qF 'id: op-step-a' "$tmp/default.err"
|
||||
assert 'default: emits id: op-step-b from operator manifest' \
|
||||
grep -qF 'id: op-step-b' "$tmp/default.err"
|
||||
assert 'default: optional flag shown on third step' \
|
||||
grep -qE '\(3/3\) Operator step C' "$tmp/default.err"
|
||||
assert 'default: does NOT leak contributor ids into the operator plan' \
|
||||
bash -c "! grep -qF 'id: cstep-a' '$tmp/default.err'"
|
||||
assert 'default: "Execute via" pointer uses operator-setup recipe' \
|
||||
grep -qE 'just run-next-steps --manifest operator_setup_steps.json --recipe operator-setup' "$tmp/default.err"
|
||||
|
||||
# --- Case 2: explicit contributor manifest works unchanged ----------
|
||||
set +e
|
||||
bash -c "cd '$tmp/welcome' && bash scripts/next_steps.sh --manifest contributor_setup_steps.json --recipe contributor-setup" \
|
||||
>"$tmp/contrib.out" 2>"$tmp/contrib.err"
|
||||
rc=$?
|
||||
set -e
|
||||
assert 'contrib override: exits 0' bash -c "[ $rc -eq 0 ]"
|
||||
assert 'contrib override: manifest path mentions contributor_setup_steps.json' \
|
||||
grep -qF 'contributor_setup_steps.json' "$tmp/contrib.err"
|
||||
assert 'contrib override: emits contributor step ids' \
|
||||
grep -qF 'id: cstep-a' "$tmp/contrib.err"
|
||||
assert 'contrib override: operator ids do NOT appear' \
|
||||
bash -c "! grep -qF 'id: op-step-a' '$tmp/contrib.err'"
|
||||
|
||||
# --- Case 3: missing operator manifest warns ------------------------
|
||||
mv "$tmp/workspace/forge-stack-orchestrator/scripts/operator_setup_steps.json" \
|
||||
"$tmp/workspace/forge-stack-orchestrator/scripts/operator_setup_steps.json.bak"
|
||||
set +e
|
||||
bash -c "cd '$tmp/welcome' && bash scripts/next_steps.sh" \
|
||||
>"$tmp/missing.out" 2>"$tmp/missing.err"
|
||||
rc=$?
|
||||
set -e
|
||||
mv "$tmp/workspace/forge-stack-orchestrator/scripts/operator_setup_steps.json.bak" \
|
||||
"$tmp/workspace/forge-stack-orchestrator/scripts/operator_setup_steps.json"
|
||||
assert 'missing operator manifest: exits non-zero' bash -c "[ $rc -ne 0 ]"
|
||||
assert 'missing operator manifest: warns via [warn]' \
|
||||
grep -qE '\[warn\]' "$tmp/missing.err"
|
||||
assert 'missing operator manifest: points at the orchestrator README' \
|
||||
grep -qF 'README.md' "$tmp/missing.err"
|
||||
|
||||
# --- Case 4: --run delegates to `just operator-setup` ---------------
|
||||
cat >"$tmp/fakebin/just" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
printf '%s\0' "\$@" > "$tmp/just.argv.nul"
|
||||
pwd > "$tmp/just.cwd"
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x "$tmp/fakebin/just"
|
||||
|
||||
set +e
|
||||
PATH="$tmp/fakebin:$PATH" bash -c "cd '$tmp/welcome' && bash scripts/next_steps.sh --run --headless --skip-optional --only op-step-a" \
|
||||
>"$tmp/run.out" 2>"$tmp/run.err"
|
||||
rc=$?
|
||||
set -e
|
||||
assert '--run: exits 0 on success' bash -c "[ $rc -eq 0 ]"
|
||||
assert '--run: invokes just' test -f "$tmp/just.argv.nul"
|
||||
assert '--run: cwd is the orchestrator checkout' \
|
||||
bash -c "[ \"\$(cat '$tmp/just.cwd')\" = '$tmp/workspace/forge-stack-orchestrator' ]"
|
||||
|
||||
tr '\0' '\n' <"$tmp/just.argv.nul" >"$tmp/just.argv"
|
||||
assert '--run: first arg is "operator-setup" (the default)' \
|
||||
grep -qxF 'operator-setup' "$tmp/just.argv"
|
||||
assert '--run: forwards --headless' \
|
||||
grep -qxF -- '--headless' "$tmp/just.argv"
|
||||
assert '--run: forwards --skip-optional' \
|
||||
grep -qxF -- '--skip-optional' "$tmp/just.argv"
|
||||
assert '--run: forwards --only op-step-a' \
|
||||
bash -c "grep -qxF -- '--only' '$tmp/just.argv' && grep -qxF -- 'op-step-a' '$tmp/just.argv'"
|
||||
|
||||
# --- Case 5: --run --recipe contributor-setup swaps the recipe ------
|
||||
set +e
|
||||
PATH="$tmp/fakebin:$PATH" bash -c "cd '$tmp/welcome' && bash scripts/next_steps.sh --run --manifest contributor_setup_steps.json --recipe contributor-setup --yes" \
|
||||
>"$tmp/run-contrib.out" 2>"$tmp/run-contrib.err"
|
||||
rc=$?
|
||||
set -e
|
||||
assert '--run --recipe contributor-setup: exits 0' bash -c "[ $rc -eq 0 ]"
|
||||
tr '\0' '\n' <"$tmp/just.argv.nul" >"$tmp/just.argv.contrib"
|
||||
assert '--run --recipe contributor-setup: first arg is contributor-setup' \
|
||||
grep -qxF 'contributor-setup' "$tmp/just.argv.contrib"
|
||||
assert '--run --recipe contributor-setup: forwards --yes' \
|
||||
grep -qxF -- '--yes' "$tmp/just.argv.contrib"
|
||||
|
||||
# --- Case 6: next_steps.sh rejects unknown args ---------------------
|
||||
set +e
|
||||
bash -c "cd '$tmp/welcome' && bash scripts/next_steps.sh --bogus" \
|
||||
>"$tmp/bogus.out" 2>"$tmp/bogus.err"
|
||||
rc=$?
|
||||
set -e
|
||||
assert 'unknown arg: exits non-zero' bash -c "[ $rc -ne 0 ]"
|
||||
assert 'unknown arg: prints an error' \
|
||||
grep -qE '\[err\] +unexpected argument' "$tmp/bogus.err"
|
||||
|
||||
printf '\n%d pass / %d fail\n' "$pass" "$fail"
|
||||
[ "$fail" -eq 0 ]
|
||||
Reference in New Issue
Block a user