Skip to content

pr-comment: preserve https:// URLs in free /review base_file (#120) #567

pr-comment: preserve https:// URLs in free /review base_file (#120)

pr-comment: preserve https:// URLs in free /review base_file (#120) #567

Workflow file for this run

name: 'Test oasdiff actions'
on:
pull_request:
push:
jobs:
oasdiff_diff:
runs-on: ubuntu-latest
name: Test diff action
steps:
- name: checkout
uses: actions/checkout@v6
- name: Running diff action
id: test_ete
uses: ./diff
with:
base: https://raw.githubusercontent.com/oasdiff/oasdiff/main/data/openapi-test1.yaml
revision: https://raw.githubusercontent.com/oasdiff/oasdiff/main/data/openapi-test3.yaml
format: 'text'
output-to-file: 'diff.txt'
- name: Test diff action output to file
run: |
if [ ! -s diff.txt ]; then
echo "Diff file doesn't exist or is empty"
exit 1
fi
oasdiff_diff_exclude_elements:
runs-on: ubuntu-latest
name: Test diff action with exclude-elements option
steps:
- name: checkout
uses: actions/checkout@v6
- name: Running diff action with exclude-elements option
id: test_exclude_elements
uses: ./diff
with:
base: 'specs/base.yaml'
revision: 'specs/base-exclude-elements.yaml'
format: 'text'
exclude-elements: 'description,title,summary'
- name: Test diff action output
run: |
delimiter=$(cat /proc/sys/kernel/random/uuid | tr -d '-')
output=$(cat <<-$delimiter
${{ steps.test_exclude_elements.outputs.diff }}
$delimiter
)
if [ "$output" != "No changes" ]; then
echo "Expected output 'No changes' but got '$output'" >&2
exit 1
fi
oasdiff_diff_composed:
runs-on: ubuntu-latest
name: Test diff action with composed option
steps:
- name: checkout
uses: actions/checkout@v6
- name: Running diff action with composed option
id: test_composed
uses: ./diff
with:
base: 'specs/glob/base/*.yaml'
revision: 'specs/glob/revision/*.yaml'
format: 'text'
composed: true
- name: Test diff action output
run: |
delimiter=$(cat /proc/sys/kernel/random/uuid | tr -d '-')
output=$(cat <<-$delimiter
${{ steps.test_composed.outputs.diff }}
$delimiter
)
if [[ ! "$output" =~ "Deleted Endpoints: 1" ]]; then
echo "Expected 'Deleted Endpoints: 1' to be modified in diff, instead got '$output'" >&2
exit 1
fi
oasdiff_breaking:
runs-on: ubuntu-latest
name: Test breaking changes
env:
OASDIFF_ACTION_TEST_EXPECTED_OUTPUT: "1 changes: 1 error, 0 warning, 0 info"
steps:
- name: checkout
uses: actions/checkout@v6
- name: Running breaking action
id: test_breaking_changes
uses: ./breaking
with:
base: 'specs/base.yaml'
revision: 'specs/revision-breaking.yaml'
output-to-file: 'breaking.txt'
- name: Test breaking changes action output
run: |
delimiter=$(cat /proc/sys/kernel/random/uuid | tr -d '-')
output=$(cat <<-$delimiter
${{ steps.test_breaking_changes.outputs.breaking }}
$delimiter
)
if [ "$output" != "$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT" ]; then
echo "Expected output '$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT' but got '$output'" >&2
exit 1
fi
- name: Test breaking changes action output to file
run: |
if [ ! -s breaking.txt ]; then
echo "Breaking changes file doesn't exist or is empty"
exit 1
fi
output=$(cat breaking.txt | head -n 1)
if [[ "${output}" != "$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT" ]]; then
echo "Expected output '$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT' but got '${output}'" >&2
exit 1
fi
oasdiff_breaking_fail_on:
runs-on: ubuntu-latest
name: Test fail on breaking changes
env:
OASDIFF_ACTION_TEST_EXPECTED_OUTPUT: "2 changes: 0 error, 2 warning, 0 info"
steps:
- name: checkout
uses: actions/checkout@v6
- name: Running breaking action
id: test_breaking_changes
uses: ./breaking
with:
base: 'specs/base.yaml'
revision: 'specs/revision-breaking-warn.yaml'
output-to-file: 'breaking.txt'
fail-on: 'ERR'
- name: Test breaking changes action output
run: |
delimiter=$(cat /proc/sys/kernel/random/uuid | tr -d '-')
output=$(cat <<-$delimiter
${{ steps.test_breaking_changes.outputs.breaking }}
$delimiter
)
if [ "$output" != "$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT" ]; then
echo "Expected output '$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT' but got '$output'" >&2
exit 1
fi
- name: Test breaking changes action output to file
run: |
if [ ! -s breaking.txt ]; then
echo "Breaking changes file doesn't exist or is empty"
exit 1
fi
output=$(cat breaking.txt | head -n 1)
if [[ "${output}" != "$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT" ]]; then
echo "Expected output '$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT' but got '${output}'" >&2
exit 1
fi
oasdiff_breaking_matching_delimiter_not_found:
runs-on: ubuntu-latest
name: Test breaking action with petsotre to validate no error of unable to process file command 'output' successfully and invalid value and matching delimiter not found
env:
OASDIFF_ACTION_TEST_EXPECTED_OUTPUT: "9 changes: 6 error, 3 warning, 0 info"
steps:
- name: checkout
uses: actions/checkout@v6
- name: Running breaking action with petsotre to validate no error of unable to process file command 'output' successfully and invalid value and matching delimiter not found
id: test_breaking_changes_matching_delimiter_not_found
uses: ./breaking
with:
base: 'specs/petstore-base.yaml'
revision: 'specs/petstore-revision.yaml'
- name: Test breaking changes action output
run: |
delimiter=$(cat /proc/sys/kernel/random/uuid | tr -d '-')
output=$(cat <<-$delimiter
${{ steps.test_breaking_changes_matching_delimiter_not_found.outputs.breaking }}
$delimiter
)
if [ "$output" != "$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT" ]; then
echo "Expected output '$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT' but got '$output'" >&2
exit 1
fi
oasdiff_breaking_composed:
runs-on: ubuntu-latest
name: Test breaking action with composed option
env:
OASDIFF_ACTION_TEST_EXPECTED_OUTPUT: "1 changes: 1 error, 0 warning, 0 info"
steps:
- name: checkout
uses: actions/checkout@v6
- name: Running breaking action with composed option
id: test_breaking_composed
uses: ./breaking
with:
base: 'specs/glob/base/*.yaml'
revision: 'specs/glob/revision/*.yaml'
composed: true
- name: Test breaking action output
run: |
delimiter=$(cat /proc/sys/kernel/random/uuid | tr -d '-')
output=$(cat <<-$delimiter
${{ steps.test_breaking_composed.outputs.breaking }}
$delimiter
)
if [[ ! "$output" =~ "$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT" ]]; then
echo "Expected '$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT', instead got '$output'" >&2
exit 1
fi
oasdiff_breaking_deprecation:
runs-on: ubuntu-latest
name: Test breaking changes with deprecation
steps:
- name: checkout
uses: actions/checkout@v6
- name: Set date for deprecated specs
run: |
# Deprecate Beta in 14 days
sed -ie "s/{{SUNSET_DATE_BETA}}/$(date --date="14 day" "+%Y-%m-%d")/" specs/base-deprecation.yaml
# Deprecate Stable in 21 days
sed -ie "s/{{SUNSET_DATE_STABLE}}/$(date --date="21 day" "+%Y-%m-%d")/" specs/base-deprecation.yaml
- name: Running OpenAPI Spec check breaking action
id: test_breaking_deprecations
uses: ./breaking
with:
base: specs/base.yaml
revision: specs/base-deprecation.yaml
deprecation-days-beta: 14
deprecation-days-stable: 21
oasdiff_changelog:
runs-on: ubuntu-latest
name: Test generation of changelog
env:
OASDIFF_ACTION_TEST_EXPECTED_OUTPUT: "21 changes: 2 error, 4 warning, 15 info"
steps:
- name: checkout
uses: actions/checkout@v6
- name: Running changelog action
id: test_changelog
uses: ./changelog
with:
base: https://raw.githubusercontent.com/oasdiff/oasdiff/main/data/openapi-test1.yaml
revision: https://raw.githubusercontent.com/oasdiff/oasdiff/main/data/openapi-test3.yaml
output-to-file: "changelog.txt"
- name: Test changelog action output
run: |
output=$(echo "${{steps.test_changelog.outputs.changelog}}" | head -n 1)
if [[ "${output}" != "${OASDIFF_ACTION_TEST_EXPECTED_OUTPUT}" ]]; then
echo "Expected output '$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT' but got '${output}'" >&2
exit 1
fi
- name: Test changelog action output to file
run: |
if [ ! -s changelog.txt ]; then
echo "Changelog file doesn't exist or is empty"
exit 1
fi
output=$(cat changelog.txt | head -n 1)
if [[ "${output}" != "${OASDIFF_ACTION_TEST_EXPECTED_OUTPUT}" ]]; then
echo "Expected output '$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT' but got '${output}'" >&2
exit 1
fi
oasdiff_changelog_composed:
runs-on: ubuntu-latest
name: Test changelog action with composed option
steps:
- name: checkout
uses: actions/checkout@v6
- name: Running changelog action with composed option
id: test_changelog_composed
uses: ./changelog
with:
base: 'specs/glob/base/*.yaml'
revision: 'specs/glob/revision/*.yaml'
composed: true
- name: Test changelog action output
run: |
delimiter=$(cat /proc/sys/kernel/random/uuid | tr -d '-')
output=$(cat <<-$delimiter
${{ steps.test_changelog_composed.outputs.changelog }}
$delimiter
)
if [[ ! "$output" =~ "1 changes: 1 error, 0 warning, 0 info" ]]; then
echo "Expected '1 changes: 1 error, 0 warning, 0 info', instead got '$output'" >&2
exit 1
fi
oasdiff_breaking_flatten_allof:
runs-on: ubuntu-latest
name: Test breaking action with flatten-allof option
env:
OASDIFF_ACTION_TEST_EXPECTED_OUTPUT: "1 changes: 1 error, 0 warning, 0 info"
steps:
- name: checkout
uses: actions/checkout@v6
- name: Running breaking action with flatten-allof option
id: test_breaking_flatten_allof
uses: ./breaking
with:
base: 'specs/base-allof.yaml'
revision: 'specs/revision-allof.yaml'
flatten-allof: true
- name: Test breaking action output
run: |
delimiter=$(cat /proc/sys/kernel/random/uuid | tr -d '-')
output=$(cat <<-$delimiter
${{ steps.test_breaking_flatten_allof.outputs.breaking }}
$delimiter
)
if [ "$output" != "$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT" ]; then
echo "Expected output '$OASDIFF_ACTION_TEST_EXPECTED_OUTPUT' but got '$output'" >&2
exit 1
fi
oasdiff_breaking_err_ignore:
runs-on: ubuntu-latest
name: Test breaking action with err-ignore option
steps:
- name: checkout
uses: actions/checkout@v6
- name: Running breaking action with err-ignore option
id: test_breaking_err_ignore
uses: ./breaking
with:
base: 'specs/base.yaml'
revision: 'specs/revision-breaking.yaml'
err-ignore: 'specs/err-ignore.txt'
- name: Test breaking changes are suppressed
run: |
delimiter=$(cat /proc/sys/kernel/random/uuid | tr -d '-')
output=$(cat <<-$delimiter
${{ steps.test_breaking_err_ignore.outputs.breaking }}
$delimiter
)
if [ "$output" != "No breaking changes" ]; then
echo "Expected 'No breaking changes' but got '$output'" >&2
exit 1
fi
# ---------------------------------------------------------------------
# .oasdiff.yaml config-file support — verify all three free actions
# pick up .oasdiff.yaml from the repo root automatically (via the CLI's
# cwd-based config-file lookup; the runner mounts $GITHUB_WORKSPACE as
# the container's WORKDIR).
# ---------------------------------------------------------------------
oasdiff_breaking_yaml_config_fail_on:
runs-on: ubuntu-latest
name: Test breaking action picks up fail-on from .oasdiff.yaml
steps:
- name: checkout
uses: actions/checkout@v6
- name: Drop .oasdiff.yaml at repo root
run: |
cat > .oasdiff.yaml <<EOF
fail-on: ERR
EOF
- name: Running breaking action without fail-on input
id: test_yaml_fail_on
continue-on-error: true
uses: ./breaking
with:
base: 'specs/base.yaml'
revision: 'specs/revision-breaking.yaml'
- name: Assert action failed (.oasdiff.yaml fail-on triggered) and report rendered
run: |
if [ "${{ steps.test_yaml_fail_on.outcome }}" != "failure" ]; then
echo "Expected action to fail because .oasdiff.yaml sets fail-on: ERR and the spec has an ERR-level breaking change. Got outcome: ${{ steps.test_yaml_fail_on.outcome }}" >&2
exit 1
fi
delimiter=$(cat /proc/sys/kernel/random/uuid | tr -d '-')
output=$(cat <<-$delimiter
${{ steps.test_yaml_fail_on.outputs.breaking }}
$delimiter
)
# Even when fail-on triggers, the entrypoint should still render
# the report. Check that the breaking output is non-empty and
# matches the same shape as a normal fail-on-input run.
if [ "$output" != "1 changes: 1 error, 0 warning, 0 info" ]; then
echo "Expected '1 changes: 1 error, 0 warning, 0 info' to be rendered alongside fail-on, got: '$output'" >&2
exit 1
fi
oasdiff_breaking_yaml_config_err_ignore:
runs-on: ubuntu-latest
name: Test breaking action picks up err-ignore from .oasdiff.yaml
steps:
- name: checkout
uses: actions/checkout@v6
- name: Drop .oasdiff.yaml at repo root
run: |
cat > .oasdiff.yaml <<EOF
err-ignore: specs/err-ignore.txt
EOF
- name: Running breaking action without err-ignore input
id: test_yaml_err_ignore
uses: ./breaking
with:
base: 'specs/base.yaml'
revision: 'specs/revision-breaking.yaml'
- name: Assert breaking changes were suppressed by .oasdiff.yaml
run: |
delimiter=$(cat /proc/sys/kernel/random/uuid | tr -d '-')
output=$(cat <<-$delimiter
${{ steps.test_yaml_err_ignore.outputs.breaking }}
$delimiter
)
if [ "$output" != "No breaking changes" ]; then
echo "Expected 'No breaking changes' (err-ignore from .oasdiff.yaml should suppress findings) but got '$output'" >&2
exit 1
fi
oasdiff_changelog_yaml_config_level:
runs-on: ubuntu-latest
name: Test changelog action picks up level from .oasdiff.yaml
steps:
- name: checkout
uses: actions/checkout@v6
- name: Drop .oasdiff.yaml at repo root
run: |
cat > .oasdiff.yaml <<EOF
level: ERR
EOF
- name: Running changelog action without level input
id: test_yaml_level
uses: ./changelog
with:
base: https://raw.githubusercontent.com/oasdiff/oasdiff/main/data/openapi-test1.yaml
revision: https://raw.githubusercontent.com/oasdiff/oasdiff/main/data/openapi-test3.yaml
- name: Assert level filter from .oasdiff.yaml suppressed warning/info findings
run: |
# Without the YAML, the same specs produce "21 changes: 2 error, 4 warning, 15 info".
# With level: ERR in YAML, only the 2 errors should remain.
output=$(echo "${{ steps.test_yaml_level.outputs.changelog }}" | head -n 1)
if [[ "$output" != "2 changes: 2 error, 0 warning, 0 info" ]]; then
echo "Expected '2 changes: 2 error, 0 warning, 0 info' (level: ERR from .oasdiff.yaml) but got '$output'" >&2
exit 1
fi
oasdiff_diff_yaml_config_exclude_elements:
runs-on: ubuntu-latest
name: Test diff action picks up exclude-elements from .oasdiff.yaml
steps:
- name: checkout
uses: actions/checkout@v6
- name: Drop .oasdiff.yaml at repo root
run: |
cat > .oasdiff.yaml <<EOF
exclude-elements:
- description
- title
- summary
format: text
EOF
- name: Running diff action without exclude-elements input
id: test_yaml_exclude_elements
uses: ./diff
with:
base: 'specs/base.yaml'
revision: 'specs/base-exclude-elements.yaml'
- name: Assert diff is empty thanks to exclude-elements from .oasdiff.yaml
run: |
delimiter=$(cat /proc/sys/kernel/random/uuid | tr -d '-')
output=$(cat <<-$delimiter
${{ steps.test_yaml_exclude_elements.outputs.diff }}
$delimiter
)
if [ "$output" != "No changes" ]; then
echo "Expected 'No changes' (exclude-elements from .oasdiff.yaml should filter description/title/summary) but got '$output'" >&2
exit 1
fi
# ---------------------------------------------------------------------
# pr-comment entrypoint: oasdiff exit-code tolerance.
#
# The pr-comment script wraps the oasdiff changelog invocation so a
# non-zero exit (e.g. fail-on triggered from .oasdiff.yaml) does not
# abort the script under set -e. Real failures (no output) still
# abort. These two jobs run pr-comment/entrypoint.sh directly with a
# stubbed oasdiff on PATH so we don't need a Docker image, an
# oasdiff-token, or a reachable oasdiff-service.
# ---------------------------------------------------------------------
pr_comment_tolerates_oasdiff_fail_on:
runs-on: ubuntu-latest
name: Test pr-comment proceeds when oasdiff exits non-zero with output
steps:
- uses: actions/checkout@v6
- name: Stub oasdiff to simulate fail-on triggered
run: |
set -euo pipefail
mkdir -p /tmp/stub
cat > /tmp/stub/oasdiff <<'STUB'
#!/bin/sh
# Simulate fail-on: emit valid JSON, then exit non-zero.
echo '[]'
exit 1
STUB
chmod +x /tmp/stub/oasdiff
# Minimum env the entrypoint reads
mkdir -p /tmp/run
export GITHUB_REF=refs/pull/123/merge
export GITHUB_REPOSITORY=foo/bar
export GITHUB_SHA=deadbeef
export GITHUB_BASE_REF=main
export GITHUB_STEP_SUMMARY=/tmp/run/step-summary
cat > /tmp/run/event.json <<EVT
{"pull_request":{"head":{"sha":"deadbeef"},"base":{"sha":"baadcafe"}}}
EVT
export GITHUB_EVENT_PATH=/tmp/run/event.json
# Run with empty oasdiff_token: the script should reach the
# "No oasdiff-token provided" branch and exit 0. If the fix
# is missing, set -e would abort at the oasdiff invocation
# (exit 1, no notice line).
export PATH=/tmp/stub:$PATH
set +e
out=$(./pr-comment/entrypoint.sh \
'specs/base.yaml' 'specs/revision.yaml' \
'' '' '' '' '' '' 2>&1)
rc=$?
set -e
echo "--- entrypoint output ---"
echo "$out"
echo "--- exit code: $rc ---"
if [ "$rc" -ne 0 ]; then
echo "FAIL: expected exit 0 (script should reach the no-token skip), got $rc" >&2
exit 1
fi
if ! echo "$out" | grep -q "::notice::.*View API changes"; then
echo "FAIL: script aborted before emitting the review-page notice; the oasdiff fail-on tolerance fix is missing" >&2
exit 1
fi
if ! echo "$out" | grep -q "No oasdiff-token provided"; then
echo "FAIL: script aborted before reaching the no-token skip" >&2
exit 1
fi
echo "PASS"
pr_comment_aborts_on_oasdiff_real_failure:
runs-on: ubuntu-latest
name: Test pr-comment aborts when oasdiff exits non-zero with no output
steps:
- uses: actions/checkout@v6
- name: Stub oasdiff to simulate a real failure
run: |
set -euo pipefail
mkdir -p /tmp/stub
cat > /tmp/stub/oasdiff <<'STUB'
#!/bin/sh
# Simulate a real failure: no stdout, non-zero exit.
echo "oasdiff: spec not found" >&2
exit 2
STUB
chmod +x /tmp/stub/oasdiff
mkdir -p /tmp/run
export GITHUB_REF=refs/pull/123/merge
export GITHUB_REPOSITORY=foo/bar
export GITHUB_SHA=deadbeef
export GITHUB_BASE_REF=main
export GITHUB_STEP_SUMMARY=/tmp/run/step-summary
cat > /tmp/run/event.json <<EVT
{"pull_request":{"head":{"sha":"deadbeef"},"base":{"sha":"baadcafe"}}}
EVT
export GITHUB_EVENT_PATH=/tmp/run/event.json
export PATH=/tmp/stub:$PATH
set +e
out=$(./pr-comment/entrypoint.sh \
'specs/base.yaml' 'specs/revision.yaml' \
'' '' '' '' '' '' 2>&1)
rc=$?
set -e
echo "--- entrypoint output ---"
echo "$out"
echo "--- exit code: $rc ---"
if [ "$rc" -ne 2 ]; then
echo "FAIL: expected exit 2 (oasdiff exit propagated), got $rc" >&2
exit 1
fi
if ! echo "$out" | grep -q "ERROR: oasdiff exited 2 with no output"; then
echo "FAIL: expected the explicit no-output error message" >&2
exit 1
fi
if echo "$out" | grep -q "::notice::.*View API changes"; then
echo "FAIL: script proceeded past the oasdiff failure; the early-abort branch is missing" >&2
exit 1
fi
echo "PASS"
pr_comment_handles_large_payload:
runs-on: ubuntu-latest
name: Test pr-comment jq payload survives a multi-MB changes array
# Regression test for the jq argv ARG_MAX limit. Real-world specs can
# produce changelogs in the multi-MB range; the original implementation
# passed `$changes` via `jq --argjson changes "$changes"` which put the
# entire JSON string on jq's command line and exceeded ARG_MAX (typical
# Linux ceiling is 2 MB), surfacing as `jq: Argument list too long` and
# aborting the action right before the service POST. The fix pipes the
# changes payload via stdin instead. This job stubs oasdiff to emit a
# ~4 MB changelog and asserts the entrypoint reaches the no-token skip
# without aborting, which proves the jq invocation processed the
# payload successfully.
steps:
- uses: actions/checkout@v6
- name: Stub oasdiff to emit a multi-MB changelog
run: |
set -euo pipefail
mkdir -p /tmp/stub
# Pre-build a ~2 MB filler string to embed inside two synthetic
# change entries (~4 MB total payload, well above the 2 MB Linux
# ARG_MAX ceiling). dd reads a bounded number of zero bytes and
# exits 0 cleanly, then tr converts to 'a's. We avoid `yes ... |
# head -c N` because `head` closes the pipe and `yes` exits with
# SIGPIPE, which fails under `set -o pipefail`.
dd if=/dev/zero bs=1024 count=2000 status=none | tr '\0' 'a' > /tmp/filler
filler_size=$(wc -c < /tmp/filler)
echo "filler size: ${filler_size} bytes"
cat > /tmp/stub/oasdiff <<'STUB'
#!/bin/sh
# Emit a synthetic JSON changelog totalling >4 MB. printf is a
# POSIX builtin so neither the variable assignment via $(cat ...)
# nor the final printf '%s' "$json" goes through execve.
filler=$(cat /tmp/filler)
printf '[{"id":"big-1","text":"%s","level":3},{"id":"big-2","text":"%s","level":3}]' "$filler" "$filler"
STUB
chmod +x /tmp/stub/oasdiff
mkdir -p /tmp/run
export GITHUB_REF=refs/pull/123/merge
export GITHUB_REPOSITORY=foo/bar
export GITHUB_SHA=deadbeef
export GITHUB_BASE_REF=main
export GITHUB_STEP_SUMMARY=/tmp/run/step-summary
cat > /tmp/run/event.json <<EVT
{"pull_request":{"head":{"sha":"deadbeef"},"base":{"sha":"baadcafe"}}}
EVT
export GITHUB_EVENT_PATH=/tmp/run/event.json
export PATH=/tmp/stub:$PATH
set +e
out=$(./pr-comment/entrypoint.sh \
'specs/base.yaml' 'specs/revision.yaml' \
'' '' '' '' '' '' 2>&1)
rc=$?
set -e
echo "--- entrypoint output (truncated) ---"
echo "$out" | head -c 2000
echo "--- exit code: $rc ---"
if [ "$rc" -ne 0 ]; then
echo "FAIL: expected exit 0 (script should reach the no-token skip after building the JSON payload), got $rc" >&2
echo "If the message contains 'jq: Argument list too long', the regression has returned: \$changes is being passed via argv (--argjson) instead of stdin." >&2
exit 1
fi
if ! echo "$out" | grep -q "::notice::.*View API changes"; then
echo "FAIL: script aborted before emitting the review-page notice" >&2
exit 1
fi
if ! echo "$out" | grep -q "No oasdiff-token provided"; then
echo "FAIL: script aborted before reaching the no-token skip; the jq payload-construction step likely blew up on the multi-MB changes array" >&2
exit 1
fi
echo "PASS"
pr_comment_curl_handles_large_payload:
runs-on: ubuntu-latest
name: Test pr-comment curl POST survives a multi-MB payload
# Companion to pr_comment_handles_large_payload. The previous test
# exercises the jq payload-construction path with an empty
# oasdiff_token, which short-circuits past the curl step. This one
# exercises the curl step itself by providing a non-empty token and
# stubbing both oasdiff (multi-MB changelog source) and curl (verifies
# it received the payload via stdin, not via argv). Catches the
# regression class where `curl -d "$payload"` puts a multi-MB body on
# argv and aborts with `curl: Argument list too long` after the jq
# invocation already succeeded — the same ARG_MAX trap one layer
# down. The fix pipes the payload through stdin via `--data-binary @-`.
steps:
- uses: actions/checkout@v6
- name: Stub oasdiff + curl, run entrypoint with a fake token
run: |
set -euo pipefail
mkdir -p /tmp/stub /tmp/run
# Same filler strategy as the jq test: dd | tr produces a
# ~2 MB string of 'a' characters and exits 0 cleanly under
# pipefail.
dd if=/dev/zero bs=1024 count=2000 status=none | tr '\0' 'a' > /tmp/filler
cat > /tmp/stub/oasdiff <<'STUB'
#!/bin/sh
filler=$(cat /tmp/filler)
printf '[{"id":"big-1","text":"%s","level":3},{"id":"big-2","text":"%s","level":3}]' "$filler" "$filler"
STUB
chmod +x /tmp/stub/oasdiff
# Stub curl: consume the POST body from stdin, record its
# byte count to a side file the assertions below can read,
# and emit the success-response shape the entrypoint expects
# from `-s -w "\n%{http_code}"` (body then a newline then the
# HTTP status code).
cat > /tmp/stub/curl <<'STUB'
#!/bin/sh
body=$(cat)
printf '%s' "$body" | wc -c > /tmp/run/curl-bytes
printf '{"review_token":"stub-token-uuid"}\n200\n'
STUB
chmod +x /tmp/stub/curl
export GITHUB_REF=refs/pull/123/merge
export GITHUB_REPOSITORY=foo/bar
export GITHUB_SHA=deadbeef
export GITHUB_BASE_REF=main
export GITHUB_STEP_SUMMARY=/tmp/run/step-summary
cat > /tmp/run/event.json <<EVT
{"pull_request":{"head":{"sha":"deadbeef"},"base":{"sha":"baadcafe"}}}
EVT
export GITHUB_EVENT_PATH=/tmp/run/event.json
# Note: jq must remain the system jq (not stubbed). PATH puts
# our stubs first; we only override `oasdiff` and `curl`.
export PATH=/tmp/stub:$PATH
set +e
out=$(./pr-comment/entrypoint.sh \
'specs/base.yaml' 'specs/revision.yaml' \
'' '' '' 'stub-oasdiff-token' '' '' 2>&1)
rc=$?
set -e
echo "--- entrypoint output (truncated) ---"
echo "$out" | head -c 2000
echo "--- exit code: $rc ---"
if [ "$rc" -ne 0 ]; then
echo "FAIL: expected exit 0, got $rc" >&2
if echo "$out" | grep -q "curl: Argument list too long"; then
echo "The regression has returned: \$payload is being passed via curl argv (-d) instead of stdin (--data-binary @-)." >&2
fi
exit 1
fi
if [ ! -f /tmp/run/curl-bytes ]; then
echo "FAIL: curl stub was never invoked; script aborted before reaching the POST" >&2
exit 1
fi
curl_bytes=$(cat /tmp/run/curl-bytes | tr -d ' ')
echo "curl received: ${curl_bytes} bytes"
if [ "$curl_bytes" -lt 4000000 ]; then
echo "FAIL: curl stub received only ${curl_bytes} bytes; expected >4 MB (proves payload made it through stdin)" >&2
exit 1
fi
if ! echo "$out" | grep -q "::notice::.*View API changes"; then
echo "FAIL: script aborted before emitting the review-page notice" >&2
exit 1
fi
echo "PASS"
pr_comment_free_review_url_preserves_https_base:
runs-on: ubuntu-latest
name: Test pr-comment free review URL keeps the https:// scheme on URL-style base
# Regression test for a bug surfaced by oasdiff-test/test#59: when the
# workflow passes a raw.githubusercontent.com URL as the base input
# (as the integration-test repo does), the entrypoint's
# base_path=$(echo "$base" | sed 's/.*://')
# stripped the "https:" prefix and left a broken "//raw.github..."
# URL. The free /review page then tried to GET that broken URL and
# rendered "access denied" with no useful diagnostic — because the
# generic access-denied screen masked the real cause (malformed URL).
# The fix passes URL-shaped inputs through unchanged.
steps:
- uses: actions/checkout@v6
- name: Stub oasdiff to a no-changes spec
run: |
set -euo pipefail
mkdir -p /tmp/stub
cat > /tmp/stub/oasdiff <<'STUB'
#!/bin/sh
echo '[]'
STUB
chmod +x /tmp/stub/oasdiff
mkdir -p /tmp/run
export GITHUB_REF=refs/pull/123/merge
export GITHUB_REPOSITORY=oasdiff-test/test
export GITHUB_SHA=deadbeef
export GITHUB_BASE_REF=main
export GITHUB_STEP_SUMMARY=/tmp/run/step-summary
cat > /tmp/run/event.json <<EVT
{"pull_request":{"head":{"sha":"deadbeef"},"base":{"sha":"baadcafe"}}}
EVT
export GITHUB_EVENT_PATH=/tmp/run/event.json
export PATH=/tmp/stub:$PATH
base_url='https://raw.githubusercontent.com/oasdiff-test/test/main/simple.yaml'
out=$(./pr-comment/entrypoint.sh \
"$base_url" 'simple.yaml' \
'' '' '' '' '' '' 2>&1)
echo "--- entrypoint output ---"
echo "$out"
if ! echo "$out" | grep -q "::notice::.*View API changes"; then
echo "FAIL: notice line missing" >&2
exit 1
fi
notice=$(echo "$out" | grep "::notice::.*View API changes")
# The encoded base_file= param must contain the full URL, not the
# stripped "//raw..." form. https:// URL-encodes to https%3A%2F%2F.
if echo "$notice" | grep -q 'base_file=https%3A%2F%2Fraw.githubusercontent.com'; then
echo "PASS: full https://raw... URL preserved in base_file"
elif echo "$notice" | grep -q 'base_file=%2F%2Fraw.githubusercontent.com'; then
echo "FAIL: 'https:' was stripped from base — the strip_ref_prefix URL guard is missing" >&2
echo "notice line: $notice" >&2
exit 1
else
echo "FAIL: base_file= param did not contain the raw.githubusercontent.com host as expected" >&2
echo "notice line: $notice" >&2
exit 1
fi
pr_comment_free_review_url_strips_git_ref_prefix:
runs-on: ubuntu-latest
name: "Test pr-comment free review URL strips origin/main: prefix from git-ref base"
# Companion to pr_comment_free_review_url_preserves_https_base: when
# the base input is git-ref form (origin/main:openapi.yaml), the
# prefix must still be stripped so the /review page receives just the
# path. The previous sed-based implementation handled this correctly;
# this test guards the case-branch refactor against breaking it.
steps:
- uses: actions/checkout@v6
- name: Stub oasdiff to a no-changes spec
run: |
set -euo pipefail
mkdir -p /tmp/stub
cat > /tmp/stub/oasdiff <<'STUB'
#!/bin/sh
echo '[]'
STUB
chmod +x /tmp/stub/oasdiff
mkdir -p /tmp/run
export GITHUB_REF=refs/pull/123/merge
export GITHUB_REPOSITORY=foo/bar
export GITHUB_SHA=deadbeef
export GITHUB_BASE_REF=main
export GITHUB_STEP_SUMMARY=/tmp/run/step-summary
cat > /tmp/run/event.json <<EVT
{"pull_request":{"head":{"sha":"deadbeef"},"base":{"sha":"baadcafe"}}}
EVT
export GITHUB_EVENT_PATH=/tmp/run/event.json
export PATH=/tmp/stub:$PATH
out=$(./pr-comment/entrypoint.sh \
'origin/main:multi-file/openapi.yaml' 'HEAD:multi-file/openapi.yaml' \
'' '' '' '' '' '' 2>&1)
echo "--- entrypoint output ---"
echo "$out"
notice=$(echo "$out" | grep "::notice::.*View API changes")
# base_file should be just "multi-file/openapi.yaml" (URL-encoded slash),
# not the full "origin/main:multi-file/openapi.yaml".
if echo "$notice" | grep -q 'base_file=multi-file%2Fopenapi.yaml'; then
echo "PASS: origin/main: prefix stripped from base"
else
echo "FAIL: base_file= did not have the git-ref prefix stripped" >&2
echo "notice line: $notice" >&2
exit 1
fi