Files
stack/packages/mosaic/framework/tools/git/test-pr-review-gitea-comment.sh
jason.woltje 344d86a635
All checks were successful
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
fix(#812 follow-up): normalize detect-platform.sh host-match port comparison by scheme (#859)
2026-07-20 10:13:29 +00:00

329 lines
12 KiB
Bash

#!/usr/bin/env bash
# Regression harness for durable Gitea PR review comments (#812) and for the
# approve/reject `--comment` flag removal (#835). The `tea` stub below rejects
# any `-comment`/`--comment` flag on `pr approve`/`pr reject` exactly like real
# `tea` v0.11.1 does ("flag provided but not defined: -comment"), so this
# harness fails RED against the pre-#835 wrapper (which passed that flag) and
# only passes once the wrapper routes the review body through the durable
# comment REST API instead.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WORK_DIR="${MOSAIC_TEST_WORK_DIR:-$PWD/.mosaic-test-work/pr-review-gitea-comment}"
REPO_DIR="$WORK_DIR/repo"
BIN_DIR="$WORK_DIR/bin"
TEA_LOG="$WORK_DIR/tea.log"
CURL_LOG="$WORK_DIR/curl.log"
OUTPUT_FILE="$WORK_DIR/output.log"
CREDENTIALS_FILE="$WORK_DIR/credentials.json"
cleanup() {
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
mkdir -p "$REPO_DIR" "$BIN_DIR"
git -C "$REPO_DIR" init -q
git -C "$REPO_DIR" remote add origin https://git.mosaicstack.dev/mosaicstack/stack.git
write_credentials() {
local configured_url="$1"
CONFIGURED_GITEA_URL="$configured_url" python3 - "$CREDENTIALS_FILE" <<'PY'
import json
import os
import sys
with open(sys.argv[1], "w", encoding="utf-8") as credentials:
json.dump({
"gitea": {
"mosaicstack": {
"url": os.environ["CONFIGURED_GITEA_URL"],
"token": "test-only-placeholder",
}
}
}, credentials)
PY
}
cat > "$BIN_DIR/tea" <<'SH'
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' "$*" >> "$PR_REVIEW_TEA_LOG"
if [[ "$*" == "login list --output json" ]]; then
printf '%s\n' '[{"name":"mosaicstack","url":"https://git.mosaicstack.dev"}]'
exit 0
fi
# tea v0.11.1 defines no --comment/-comment flag on `pr approve` or `pr
# reject`; it fails closed with this exact message and a nonzero exit. Any
# regression that reintroduces the flag on those subcommands must hit this
# branch and fail RED (#835).
if [[ "$*" == *" -comment "* || "$*" == *" --comment "* || "$*" == *" -comment" || "$*" == *" --comment" ]]; then
echo "flag provided but not defined: -comment" >&2
exit 1
fi
case "${PR_REVIEW_TEST_MODE:-}" in
approve)
[[ "$*" == "pr approve 123 --repo mosaicstack/stack --login mosaicstack" ]] || exit 90
;;
request-changes)
[[ "$*" == "pr reject 123 --repo mosaicstack/stack --login mosaicstack" ]] || exit 91
;;
legacy-fallback|comment-success|http-success|prefix-success|subpath-success|port-success|scp-ssh-success|url-ssh-success|ssh-transport-port-success|explicit-default-port-success|write-transport-failure|write-http-failure|readback-failure)
if [[ "$*" == pr\ comment* ]]; then
# tea v0.11.1 treats the nonexistent subcommand as `tea pr list` and exits 0.
printf '%s\n' 'INDEX TITLE STATE'
exit 0
fi
echo "Unexpected tea command: $*" >&2
exit 92
;;
*)
exit 95
;;
esac
SH
chmod +x "$BIN_DIR/tea"
cat > "$BIN_DIR/curl" <<'SH'
#!/usr/bin/env bash
set -euo pipefail
output_file=""
method="GET"
payload=""
url=""
while [[ $# -gt 0 ]]; do
case "$1" in
-o)
output_file="$2"
shift 2
;;
-w|-H)
shift 2
;;
-X)
method="$2"
shift 2
;;
-d|--data)
payload="$2"
shift 2
;;
-s|-S|-sS)
shift
;;
http://*|https://*)
url="$1"
shift
;;
*)
shift
;;
esac
done
printf '%s %s\n' "$method" "$url" >> "$PR_REVIEW_CURL_LOG"
write_response() {
local status="$1" body="$2"
[[ -n "$output_file" ]] || exit 96
printf '%s' "$body" > "$output_file"
printf '%s' "$status"
}
case "${PR_REVIEW_TEST_MODE:-}" in
legacy-fallback|write-transport-failure)
echo "simulated transport failure" >&2
exit 7
;;
write-http-failure)
write_response 500 '{"message":"simulated rejection"}'
;;
approve|request-changes|comment-success|http-success|prefix-success|subpath-success|port-success|scp-ssh-success|url-ssh-success|ssh-transport-port-success|explicit-default-port-success|readback-failure)
if [[ "$method" == "POST" && "$url" == "$PR_REVIEW_EXPECTED_API_BASE/issues/123/comments" ]]; then
PR_REVIEW_PAYLOAD="$payload" python3 - <<'PY'
import json
import os
assert json.loads(os.environ["PR_REVIEW_PAYLOAD"]) == {"body": os.environ["PR_REVIEW_EXPECTED_BODY"]}
PY
response=$(python3 - <<'PY'
import json
import os
print(json.dumps({"id": 456, "body": os.environ["PR_REVIEW_EXPECTED_BODY"]}))
PY
)
write_response 201 "$response"
elif [[ "$method" == "GET" && "$url" == "$PR_REVIEW_EXPECTED_API_BASE/issues/comments/456" ]]; then
if [[ "$PR_REVIEW_TEST_MODE" == "readback-failure" ]]; then
body="different-body"
else
body="$PR_REVIEW_EXPECTED_BODY"
fi
response=$(PR_REVIEW_BODY="$body" python3 - <<'PY'
import json
import os
print(json.dumps({
"id": 456,
"body": os.environ["PR_REVIEW_BODY"],
"issue_url": os.environ["PR_REVIEW_EXPECTED_API_BASE"] + "/issues/123",
}))
PY
)
write_response 200 "$response"
else
echo "Unexpected curl request: $method $url" >&2
exit 97
fi
;;
*)
exit 98
;;
esac
SH
chmod +x "$BIN_DIR/curl"
run_review() {
local mode="$1" action="$2" comment="${3:-}"
local configured_url="${4:-https://git.mosaicstack.dev}"
local remote_url="${5:-https://git.mosaicstack.dev/mosaicstack/stack.git}"
local expected_repo="${6:-mosaicstack/stack}"
local expected_api_base="${configured_url%/}/api/v1/repos/$expected_repo"
git -C "$REPO_DIR" remote set-url origin "$remote_url"
write_credentials "$configured_url"
: > "$TEA_LOG"
: > "$CURL_LOG"
: > "$OUTPUT_FILE"
(
cd "$REPO_DIR"
PATH="$BIN_DIR:$PATH" \
MOSAIC_CREDENTIALS_FILE="$CREDENTIALS_FILE" \
PR_REVIEW_TEA_LOG="$TEA_LOG" \
PR_REVIEW_CURL_LOG="$CURL_LOG" \
PR_REVIEW_TEST_MODE="$mode" \
PR_REVIEW_EXPECTED_BODY="$comment" \
PR_REVIEW_EXPECTED_API_BASE="$expected_api_base" \
"$SCRIPT_DIR/pr-review.sh" -n 123 -a "$action" ${comment:+-c "$comment"}
) > "$OUTPUT_FILE" 2>&1
}
run_review approve approve
grep -q '^pr approve 123 --repo mosaicstack/stack --login mosaicstack$' "$TEA_LOG"
grep -q 'Approved Gitea PR #123' "$OUTPUT_FILE"
if grep -q 'comment' "$TEA_LOG"; then
echo "Plain approve (no review body) unexpectedly touched comment persistence" >&2
exit 1
fi
# #835: tea v0.11.1 defines no --comment/-comment flag on `pr approve`. A
# review body supplied alongside approve must be routed through the durable
# comment REST API instead of being passed to `tea` directly.
run_review approve approve approve-note
grep -q '^pr approve 123 --repo mosaicstack/stack --login mosaicstack$' "$TEA_LOG"
grep -q 'Approved Gitea PR #123' "$OUTPUT_FILE"
grep -q '^POST https://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack/issues/123/comments$' "$CURL_LOG"
grep -q '^GET https://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack/issues/comments/456$' "$CURL_LOG"
grep -q 'Added and verified review comment on Gitea PR #123 (comment ID 456)' "$OUTPUT_FILE"
# #835: same for `pr reject` (request-changes), where a comment is required.
run_review request-changes request-changes changes-required
grep -q '^pr reject 123 --repo mosaicstack/stack --login mosaicstack$' "$TEA_LOG"
grep -q 'Requested changes on Gitea PR #123' "$OUTPUT_FILE"
grep -q '^POST https://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack/issues/123/comments$' "$CURL_LOG"
grep -q '^GET https://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack/issues/comments/456$' "$CURL_LOG"
grep -q 'Added and verified review comment on Gitea PR #123 (comment ID 456)' "$OUTPUT_FILE"
if run_review legacy-fallback comment durable-body; then
echo "The old nonexistent tea pr comment fallback returned success" >&2
cat "$OUTPUT_FILE" >&2
exit 1
fi
if grep -q '^pr comment ' "$TEA_LOG"; then
echo "Wrapper invoked unsupported tea pr comment" >&2
exit 1
fi
if grep -q 'Added comment to Gitea PR' "$OUTPUT_FILE"; then
echo "Wrapper reported success without durable persistence" >&2
exit 1
fi
complex_body=$'durable "body"\n-- marker'
run_review comment-success comment "$complex_body"
grep -q '^POST https://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack/issues/123/comments$' "$CURL_LOG"
grep -q '^GET https://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack/issues/comments/456$' "$CURL_LOG"
grep -q 'Added and verified comment on Gitea PR #123' "$OUTPUT_FILE"
if [[ -s "$TEA_LOG" ]]; then
echo "REST comment path unexpectedly invoked tea" >&2
cat "$TEA_LOG" >&2
exit 1
fi
run_review http-success comment durable-body http://git.mosaicstack.dev
grep -q '^POST http://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack/issues/123/comments$' "$CURL_LOG"
grep -q '^GET http://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack/issues/comments/456$' "$CURL_LOG"
run_review prefix-success comment durable-body https://git.mosaicstack.dev/gitea/
grep -q '^POST https://git.mosaicstack.dev/gitea/api/v1/repos/mosaicstack/stack/issues/123/comments$' "$CURL_LOG"
grep -q '^GET https://git.mosaicstack.dev/gitea/api/v1/repos/mosaicstack/stack/issues/comments/456$' "$CURL_LOG"
run_review subpath-success comment durable-body https://git.example/gitea https://git.example/gitea/owner/repo.git owner/repo
grep -q '^POST https://git.example/gitea/api/v1/repos/owner/repo/issues/123/comments$' "$CURL_LOG"
grep -q '^GET https://git.example/gitea/api/v1/repos/owner/repo/issues/comments/456$' "$CURL_LOG"
if grep -q '/repos/gitea/owner/repo/' "$CURL_LOG"; then
echo "Configured Gitea path prefix leaked into the repository slug" >&2
exit 1
fi
run_review port-success comment durable-body http://git.example:3000 http://git.example:3000/owner/repo.git owner/repo
grep -q '^POST http://git.example:3000/api/v1/repos/owner/repo/issues/123/comments$' "$CURL_LOG"
grep -q '^GET http://git.example:3000/api/v1/repos/owner/repo/issues/comments/456$' "$CURL_LOG"
run_review scp-ssh-success comment durable-body https://git.example git@git.example:owner/repo.git owner/repo
grep -q '^POST https://git.example/api/v1/repos/owner/repo/issues/123/comments$' "$CURL_LOG"
run_review url-ssh-success comment durable-body https://git.example ssh://git@git.example/owner/repo.git owner/repo
grep -q '^POST https://git.example/api/v1/repos/owner/repo/issues/123/comments$' "$CURL_LOG"
# #850 (follow-up to #812): an SSH remote's transport port (e.g. `ssh://
# git@host:2222/...`) must NOT be compared against the configured HTTP(S) API
# URL's port -- they identify unrelated properties (SSH daemon port vs. HTTP(S)
# provider port) of the same Gitea host. Before the fix, host-match required
# the configured URL to carry the identical port, so this failed closed even
# though both remote and configured URL name the same host.
run_review ssh-transport-port-success comment durable-body https://git.example ssh://git@git.example:2222/owner/repo.git owner/repo
grep -q '^POST https://git.example/api/v1/repos/owner/repo/issues/123/comments$' "$CURL_LOG"
# #850 (follow-up to #812): an explicit default HTTP(S) port on the remote
# (`https://host:443/...`) must be treated as equal to an implicit
# (portless) configured URL on BOTH sides -- the pre-fix comparison only
# normalized the default port when the REMOTE side was portless, so the
# inverse (explicit remote, implicit configured) form failed closed.
run_review explicit-default-port-success comment durable-body https://git.example https://git.example:443/owner/repo.git owner/repo
grep -q '^POST https://git.example/api/v1/repos/owner/repo/issues/123/comments$' "$CURL_LOG"
if run_review write-transport-failure comment durable-body; then
echo "Expected provider transport failure to return nonzero" >&2
exit 1
fi
if run_review write-http-failure comment durable-body; then
echo "Expected non-201 provider write to return nonzero" >&2
exit 1
fi
if run_review readback-failure comment durable-body; then
echo "Expected mismatched provider read-back to return nonzero" >&2
exit 1
fi
if grep -q 'Added and verified comment' "$OUTPUT_FILE"; then
echo "Read-back mismatch reported durable success" >&2
exit 1
fi
echo "pr-review.sh durable Gitea comment regression passed"