From d7aa84f01573347205d74bb5f9c794a44d0d239f Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Tue, 7 Oct 2025 13:51:29 +0400 Subject: [PATCH] ci: add API diff workflow (#9600) Co-authored-by: knqyf263 --- .github/workflows/apidiff.yaml | 126 +++++++++++++++++++++++++++++++++ go.mod | 2 +- go.sum | 4 +- misc/triage/labels.yaml | 5 +- 4 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/apidiff.yaml diff --git a/.github/workflows/apidiff.yaml b/.github/workflows/apidiff.yaml new file mode 100644 index 0000000000..e3537bbbc8 --- /dev/null +++ b/.github/workflows/apidiff.yaml @@ -0,0 +1,126 @@ +name: API Diff Check + +on: + pull_request: + types: [opened, synchronize] + paths: + - 'pkg/**/*.go' + - 'rpc/**/*.go' + +permissions: + contents: read + pull-requests: write + issues: write + +jobs: + apidiff: + runs-on: ubuntu-24.04 + name: API Diff Check + steps: + - name: Checkout + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + - name: Set up Go + uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 + with: + go-version-file: go.mod + cache: false + + # Ensure the base commit exists locally when checkout uses depth=1 (default). + - name: Fetch base commit + run: | + BASE_REF="${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }}" + if [ -n "$BASE_REF" ]; then + git fetch --depth=1 origin "$BASE_REF" + fi + + # NOTE: go-apidiff is not managed in go.mod because installing it via `go get -tool` + # would cause `mage tool:install` to attempt building it on Windows, which currently + # fails due to platform-specific issues. + - name: Run go-apidiff + id: apidiff + continue-on-error: true + uses: joelanford/go-apidiff@60c4206be8f84348ebda2a3e0c3ac9cb54b8f685 # v0.8.3 + with: + version: v0.8.3 + + - name: Add apidiff label + if: ${{ steps.apidiff.outputs.semver-type == 'major' }} + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + script: | + const label = 'apidiff'; + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: [label], + }); + + - name: Comment API diff + if: ${{ steps.apidiff.outputs.semver-type == 'major' }} + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + env: + APIDIFF_OUTPUT: ${{ steps.apidiff.outputs.output }} + SEMVER_TYPE: ${{ steps.apidiff.outputs.semver-type }} + with: + script: | + const header = '## 📊 API Changes Detected'; + const diff = process.env.APIDIFF_OUTPUT.trim(); + const semver = process.env.SEMVER_TYPE || 'unknown'; + const body = [ + header, + '', + `Semver impact: \`${semver}\``, + '', + '```', + diff, + '```', + ].join('\n'); + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + const existing = comments.find(comment => + comment.user.type === 'Bot' && + comment.body.startsWith(header), + ); + + if (existing) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body, + }); + } + + # Attempt to request the premium reviewers; needs org-scoped token because GITHUB_TOKEN lacks read:org. + - name: Request trivy-premium review + if: ${{ steps.apidiff.outputs.semver-type == 'major' }} + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + github-token: ${{ secrets.ORG_REPO_TOKEN }} + script: | + try { + await github.rest.pulls.requestReviewers({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + team_reviewers: ['trivy-premium'], + }); + console.log('Requested review from aquasecurity/trivy-premium team'); + } catch (error) { + core.error(`Failed to request trivy-premium reviewers: ${error.message}`); + throw error; + } diff --git a/go.mod b/go.mod index 8682ce2edc..642f642fbf 100644 --- a/go.mod +++ b/go.mod @@ -153,7 +153,7 @@ require ( cloud.google.com/go/storage v1.55.0 // indirect connectrpc.com/connect v1.18.1 // indirect connectrpc.com/otelconnect v0.7.2 // indirect - dario.cat/mergo v1.0.1 // indirect + dario.cat/mergo v1.0.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect diff --git a/go.sum b/go.sum index 9e838ca398..9905bc01ab 100644 --- a/go.sum +++ b/go.sum @@ -55,8 +55,8 @@ cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e h1:GwCVItFUPxw cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e/go.mod h1:ApHceQLLwcOkCEXM1+DyCXTHEJhNGDpJ2kmV6axsx24= cuelang.org/go v0.8.1 h1:VFYsxIFSPY5KgSaH1jQ2GxHOrbu6Ga3kEI70yCZwnOg= cuelang.org/go v0.8.1/go.mod h1:CoDbYolfMms4BhWUlhD+t5ORnihR7wvjcfgyO9lL5FI= -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= diff --git a/misc/triage/labels.yaml b/misc/triage/labels.yaml index 77bd5997ff..e353cceb2a 100644 --- a/misc/triage/labels.yaml +++ b/misc/triage/labels.yaml @@ -143,4 +143,7 @@ labels: # automation - name: autoready color: 1d76db - description: Automatically mark PR as ready for review when all checks pass \ No newline at end of file + description: Automatically mark PR as ready for review when all checks pass +- name: apidiff + color: ededed + description: Indicates Go API changes relevant to library consumers (CLI compatibility may be unaffected)