| --- |
| name: apidiff |
| on: |
| pull_request: |
| |
| permissions: |
| contents: read |
| |
| jobs: |
| scan_changes: |
| runs-on: ubuntu-latest |
| steps: |
| - uses: actions/checkout@v4 |
| with: |
| ref: main |
| - name: Get main commit |
| id: main |
| run: echo "hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT |
| - uses: actions/checkout@v4 |
| - uses: actions/setup-go@v5 |
| with: |
| go-version: '1.22.x' |
| - name: Get changed directories |
| id: changed_dirs |
| # Ignore changes to the internal and root directories. |
| # Ignore added files with --diff-filter=a. |
| run: | |
| dirs=$(go run ./internal/actions/cmd/changefinder -q --diff-filter=a) |
| if [ -z "$dirs" ] |
| then |
| echo "skip=1" >> $GITHUB_OUTPUT |
| echo "No changes worth diffing!" |
| else |
| for d in $dirs; do list=${list},\"${d}\"; done |
| echo "changed={\"changed\":[${list#,}]}" >> $GITHUB_OUTPUT |
| echo "skip=" >> $GITHUB_OUTPUT |
| fi |
| outputs: |
| changed_dirs: ${{ steps.changed_dirs.outputs.changed }} |
| skip: ${{ steps.changed_dirs.outputs.skip }} |
| apidiff: |
| needs: scan_changes |
| runs-on: ubuntu-latest |
| if: ${{ !needs.scan_changes.outputs.skip && !contains(github.event.pull_request.labels.*.name, 'breaking change allowed') }} |
| continue-on-error: true |
| permissions: |
| pull-requests: write |
| strategy: |
| matrix: ${{ fromJson(needs.scan_changes.outputs.changed_dirs) }} |
| steps: |
| - uses: actions/setup-go@v5 |
| with: |
| go-version: '1.22.x' |
| - name: Install latest apidiff |
| run: go install golang.org/x/exp/cmd/apidiff@latest |
| - uses: actions/checkout@v4 |
| with: |
| ref: main |
| - name: Create baseline |
| id: baseline |
| run: | |
| export CHANGED=${{ matrix.changed }} |
| echo pkg="${CHANGED//\//_}_pkg.main" >> $GITHUB_OUTPUT |
| - name: Create Go package baseline |
| run: cd ${{ matrix.changed }} && apidiff -m -w ${{ steps.baseline.outputs.pkg }} . |
| - name: Upload baseline package data |
| uses: actions/upload-artifact@v4 |
| with: |
| name: ${{ steps.baseline.outputs.pkg }} |
| path: ${{ matrix.changed }}/${{ steps.baseline.outputs.pkg }} |
| retention-days: 1 |
| - uses: actions/checkout@v4 |
| - name: Download baseline package data |
| uses: actions/download-artifact@v4 |
| with: |
| name: ${{ steps.baseline.outputs.pkg }} |
| path: ${{ matrix.changed }} |
| - name: Compare regenerated code to baseline |
| # Only ignore Go interface additions when the PR is from OwlBot as it is |
| # likely a new method added to the gRPC client stub interface, which is |
| # non-breaking. |
| env: |
| PR_HEAD_REF: ${{ github.event.pull_request.head.ref }} |
| run: | |
| cd ${{ matrix.changed }} && apidiff -m -incompatible ${{ steps.baseline.outputs.pkg }} . > diff.txt |
| if [[ "$PR_HEAD_REF" == owl-bot-copy ]]; then |
| sed -i '/: added/d' ./diff.txt |
| fi |
| cat diff.txt && ! [ -s diff.txt ] |
| - name: Add breaking change label |
| if: ${{ failure() && !github.event.pull_request.head.repo.fork }} |
| uses: actions/github-script@v7 |
| with: |
| script: | |
| github.rest.issues.addLabels({ |
| issue_number: ${{ github.event.number }}, |
| owner: context.repo.owner, |
| repo: context.repo.repo, |
| labels: ['breaking change'] |
| }) |