From 8c5520249c46e615e9a82283f2e9912658a6abb9 Mon Sep 17 00:00:00 2001 From: Rob Pocklington Date: Fri, 24 Oct 2025 13:22:17 +1100 Subject: [PATCH] feat: shift to another tool supporting OAS 3.1 --- README.md | 2 +- scripts/api-diff/README.md | 13 +-- scripts/api-diff/api-diff.sh | 38 ++----- scripts/api-diff/test-api-diff.sh | 158 ++++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+), 41 deletions(-) create mode 100644 scripts/api-diff/test-api-diff.sh diff --git a/README.md b/README.md index 5ac149356..801f84655 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Once you sign up or login, you can create a new API under your account and impor If you find something missing or incorrect please [open an issue](https://github.com/XeroAPI/Xero-OpenAPI/issues/new) or send us a pull request. ## API Diff Checking -This repository includes automated API diff checking using [oasdiff](https://github.com/oasdiff/oasdiff) to detect breaking changes and modifications to the OpenAPI specifications. +This repository includes automated API diff checking using [openapi-diff](https://github.com/OpenAPITools/openapi-diff) to detect breaking changes and modifications to the OpenAPI specifications. ### Quick Start ```bash diff --git a/scripts/api-diff/README.md b/scripts/api-diff/README.md index 374ed418f..fd09deb11 100644 --- a/scripts/api-diff/README.md +++ b/scripts/api-diff/README.md @@ -1,6 +1,6 @@ # API Diff Scripts -This directory contains scripts for detecting and reporting API changes using [oasdiff](https://github.com/oasdiff/oasdiff). +This directory contains scripts for detecting and reporting API changes using [openapi-diff](https://github.com/OpenAPITools/openapi-diff). ## Files @@ -23,7 +23,7 @@ Main script that compares OpenAPI specifications against the master branch. ``` **Environment Variables:** -- `OASDIFF_DOCKER_IMAGE` - Docker image to use (default: `tufin/oasdiff:latest`) +- `OPENAPI_DIFF_DOCKER_IMAGE` - Docker image to use (default: `openapitools/openapi-diff:latest`) - `BASE_BRANCH` - Branch to compare against (default: `origin/master`) ### `api-diff.test.sh` @@ -58,12 +58,3 @@ The GitHub Actions workflow automatically adjusts its behavior based on branch n - Build will fail if breaking changes are detected This allows developers to explicitly signal when they're working on breaking changes by including `breaking` in their branch name. - -## Known Limitations - -The oasdiff tool has some non-deterministic behavior due to unordered map iteration in Go: -- **Error counts** (breaking changes) are consistent and reliable -- **Warning counts** may vary by ~2-3% between runs on identical inputs -- This is acceptable for CI purposes as breaking change detection remains accurate - -For more details, see the [oasdiff documentation](https://github.com/oasdiff/oasdiff). diff --git a/scripts/api-diff/api-diff.sh b/scripts/api-diff/api-diff.sh index dccc0f467..8c86b97db 100755 --- a/scripts/api-diff/api-diff.sh +++ b/scripts/api-diff/api-diff.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Script to check API diffs using oasdiff +# Script to check API diffs using openapi-diff # Usage: ./scripts/api-diff/api-diff.sh [--fail-on-breaking] [filename.yaml] # Assumes you have Docker installed and the repo is checked out with master branch available @@ -11,7 +11,7 @@ set -o pipefail # Catch errors in pipes cd "$(dirname "$0")/../.." # Configuration -DOCKER_IMAGE="${OASDIFF_DOCKER_IMAGE:-tufin/oasdiff:latest}" +DOCKER_IMAGE="${OPENAPI_DIFF_DOCKER_IMAGE:-openapitools/openapi-diff:latest}" BASE_BRANCH="${BASE_BRANCH:-origin/master}" FAIL_ON_BREAKING=false @@ -112,39 +112,19 @@ for file in $files; do continue fi - # Note: oasdiff has some non-deterministic behavior in change counts due to - # unordered map iteration in Go. Error counts are consistent, but warning - # counts may vary by ~2-3% between runs. This is a known limitation. - - # Run oasdiff changelog - echo "--- Changelog ---" - set +e - CHANGELOG_OUTPUT=$(docker run --rm -v "$(pwd)":/current -v "$TEMP_DIR":/base "$DOCKER_IMAGE" changelog --include-path-params /base/"$file" /current/"$file" 2>&1) - CHANGELOG_EXIT=$? - set -e - - echo "$CHANGELOG_OUTPUT" - - if [ $CHANGELOG_EXIT -eq 0 ]; then - echo "✓ Changelog generated successfully" - else - echo "⚠ Could not generate changelog (exit code: $CHANGELOG_EXIT)" - fi - - # Run breaking changes check - echo "" - echo "--- Breaking changes check ---" + # Run openapi-diff to check for changes and breaking changes + echo "--- API Diff ---" set +e - BREAKING_OUTPUT=$(docker run --rm -v "$(pwd)":/current -v "$TEMP_DIR":/base "$DOCKER_IMAGE" breaking --fail-on ERR --include-path-params /base/"$file" /current/"$file" 2>&1) - BREAKING_EXIT=$? + DIFF_OUTPUT=$(docker run --rm -v "$(pwd)":/current -v "$TEMP_DIR":/base "$DOCKER_IMAGE" /base/"$file" /current/"$file" --fail-on-incompatible 2>&1) + DIFF_EXIT=$? set -e - echo "$BREAKING_OUTPUT" + echo "$DIFF_OUTPUT" - if [ $BREAKING_EXIT -eq 0 ]; then + if [ $DIFF_EXIT -eq 0 ]; then echo "✓ No breaking changes detected" else - echo "⚠ Breaking changes detected (exit code: $BREAKING_EXIT)" + echo "⚠ Breaking changes detected (exit code: $DIFF_EXIT)" BREAKING_CHANGES_FOUND=true FILES_WITH_BREAKING_CHANGES+=("$file") fi diff --git a/scripts/api-diff/test-api-diff.sh b/scripts/api-diff/test-api-diff.sh new file mode 100644 index 000000000..aa5f86082 --- /dev/null +++ b/scripts/api-diff/test-api-diff.sh @@ -0,0 +1,158 @@ +#!/bin/bash + +# Script to check API diffs using openapi-diff +# Usage: ./scripts/api-diff/test-api-diff.sh [--fail-on-breaking] [filename.yaml] +# Assumes you have Docker installed and the repo is checked out with master branch available + +set -e # Exit on error +set -o pipefail # Catch errors in pipes + +# Change to repo root +cd "$(dirname "$0")/../.." + +# Configuration +DOCKER_IMAGE="${OPENAPI_DIFF_DOCKER_IMAGE:-openapitools/openapi-diff:latest}" +BASE_BRANCH="${BASE_BRANCH:-origin/master}" + +FAIL_ON_BREAKING=false +TARGET_FILE="" + +# Parse arguments +for arg in "$@"; do + if [ "$arg" = "--fail-on-breaking" ]; then + FAIL_ON_BREAKING=true + elif [[ "$arg" == *.yaml ]]; then + TARGET_FILE="$arg" + fi +done + +echo "Starting API diff check..." + +# Ensure we're in the repo root +if [ ! -f "xero_accounting.yaml" ]; then + echo "Error: Not in repo root or xero_accounting.yaml not found" + exit 1 +fi + +# Fetch master if not already done +git fetch "${BASE_BRANCH%%/*}" "${BASE_BRANCH##*/}" 2>/dev/null || echo "Warning: Could not fetch ${BASE_BRANCH}" + +# Create temp directory for master branch files (outside repo to avoid overlap with /current mount) +TEMP_DIR=$(mktemp -d) +trap "rm -rf $TEMP_DIR" EXIT + +# Get list of xero*.yaml files (excluding any master_*.yaml files) +if [ -n "$TARGET_FILE" ]; then + # Single file specified + if [ ! -f "$TARGET_FILE" ]; then + echo "Error: File '$TARGET_FILE' not found" + exit 1 + fi + files="$TARGET_FILE" + echo "Running diff for single file: $TARGET_FILE" +else + # All xero*.yaml files + files=$(ls xero*.yaml 2>/dev/null | grep -v "^master_") + if [ -z "$files" ]; then + echo "No xero*.yaml files found" + exit 1 + fi +fi + +BREAKING_CHANGES_FOUND=false +FILES_WITH_BREAKING_CHANGES=() +TOTAL_FILES=0 +PROCESSED_FILES=0 + +echo "========================================" +echo "API Diff Summary" +echo "Using Docker image: $DOCKER_IMAGE" +echo "Base branch: $BASE_BRANCH" +echo "========================================" + +for file in $files; do + TOTAL_FILES=$((TOTAL_FILES + 1)) + echo "" + echo "========== $file ==========" + + # Get the file from master branch + if ! git show "$BASE_BRANCH:$file" > "$TEMP_DIR/$file" 2>/dev/null; then + echo "ℹ️ New file (does not exist in master branch)" + continue + fi + + # Verify the temp file was created + if [ ! -f "$TEMP_DIR/$file" ]; then + echo "❌ Failed to create temp file" + continue + fi + + # Note: openapi-diff provides deterministic results for change detection. + # Both error and warning counts are consistent between runs. + + # Run openapi-diff changelog + echo "--- Changelog ---" + set +e + CHANGELOG_OUTPUT=$(docker run --rm -v "$(pwd)":/current -v "$TEMP_DIR":/base "$DOCKER_IMAGE" changelog --include-path-params /base/"$file" /current/"$file" 2>&1) + CHANGELOG_EXIT=$? + set -e + + echo "$CHANGELOG_OUTPUT" + + if [ $CHANGELOG_EXIT -eq 0 ]; then + echo "✓ Changelog generated successfully" + else + echo "⚠ Could not generate changelog (exit code: $CHANGELOG_EXIT)" + fi + + # Run breaking changes check + echo "" + echo "--- Breaking changes check ---" + set +e + BREAKING_OUTPUT=$(docker run --rm -v "$(pwd)":/current -v "$TEMP_DIR":/base "$DOCKER_IMAGE" breaking --fail-on ERR --include-path-params /base/"$file" /current/"$file" 2>&1) + BREAKING_EXIT=$? + set -e + + echo "$BREAKING_OUTPUT" + + if [ $BREAKING_EXIT -eq 0 ]; then + echo "✓ No breaking changes detected" + else + echo "⚠ Breaking changes detected (exit code: $BREAKING_EXIT)" + BREAKING_CHANGES_FOUND=true + FILES_WITH_BREAKING_CHANGES+=("$file") + fi + + PROCESSED_FILES=$((PROCESSED_FILES + 1)) +done + +echo "" +echo "========================================" +echo "API Diff check completed" +echo "Processed: $PROCESSED_FILES/$TOTAL_FILES files" +echo "========================================" + +# Summary +if [ "$BREAKING_CHANGES_FOUND" = true ]; then + echo "" + echo "❌ Breaking changes detected in the following files:" + for file in "${FILES_WITH_BREAKING_CHANGES[@]}"; do + echo " - $file" + # Output GitHub Actions annotation + if [ -n "$GITHUB_ACTIONS" ]; then + echo "::warning file=${file}::Breaking changes detected in this API spec file" + fi + done + + if [ "$FAIL_ON_BREAKING" = true ]; then + echo "" + echo "Exiting with error due to breaking changes" + exit 1 + else + echo "" + echo "Note: Not failing build (use --fail-on-breaking to fail on breaking changes)" + fi +else + echo "" + echo "✓ No breaking changes detected across all files" +fi \ No newline at end of file