pr-comment: preserve https:// URLs in free /review base_file (#120) #567
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |