Skip to content

Conversation

@ekjotmultani
Copy link
Member

@ekjotmultani ekjotmultani commented Jun 3, 2025

Issue #, if available:

Description of changes:

Introduced the aft generate api-report command to AFT. This command uses dart_apitool from @bmw-tech to create snapshots of our package's dart level API surfaces, and a change report for these. Developers must now always use this AFT command to generate these files for each package (just running the command as is once here works) on every Pull Request that is expected to merge into main.

This PR also includes a workflow for checking that these change reports are actually updated according to the changes on the PR branch, and a workflow for requiring additional approvals when an API change actually occurs (as shown by the lovely bot in this thread).

Overall this change to our development flow will enforce that developers are always aware of API changes to help us get the right eyes on it and to help with versioning.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@github-actions
Copy link

github-actions bot commented Jun 3, 2025

⚠️ This PR contains API changes and requires careful review. Please ensure these changes are intentional and backward compatible where possible.

@github-actions
Copy link

github-actions bot commented Jun 3, 2025

⚠️ This PR contains API changes and requires careful review. Please ensure these changes are intentional and backward compatible where possible.

@github-actions
Copy link

github-actions bot commented Jun 3, 2025

⚠️ This PR contains API changes and requires careful review. Please ensure these changes are intentional and backward compatible where possible.

@github-actions
Copy link

github-actions bot commented Jun 3, 2025

⚠️ This PR contains API changes and requires careful review. Please ensure these changes are intentional and backward compatible where possible.

@github-actions
Copy link

github-actions bot commented Jun 3, 2025

⚠️ This PR contains API changes and requires careful review. Please ensure these changes are intentional and backward compatible where possible.

@github-actions
Copy link

github-actions bot commented Jun 3, 2025

⚠️ This PR contains API changes and requires careful review. Please ensure these changes are intentional and backward compatible where possible.

@github-actions
Copy link

github-actions bot commented Jun 3, 2025

⚠️ This PR contains API changes and requires careful review. Please ensure these changes are intentional and backward compatible where possible.

@github-actions
Copy link

github-actions bot commented Jun 3, 2025

⚠️ This PR contains API changes and requires careful review. Please ensure these changes are intentional and backward compatible where possible.

@github-actions
Copy link

github-actions bot commented Jun 4, 2025

⚠️ This PR contains API changes and requires careful review. Please ensure these changes are intentional and backward compatible where possible.

@github-actions
Copy link

github-actions bot commented Jun 4, 2025

⚠️ This PR contains API changes and requires careful review. Please ensure these changes are intentional and backward compatible where possible.

@github-actions
Copy link

github-actions bot commented Jun 5, 2025

⚠️ This PR contains API changes and requires careful review. Please ensure these changes are intentional and backward compatible where possible.

…and look specifically for the text that tells us if anything changed
@github-actions
Copy link

github-actions bot commented Jun 5, 2025

⚠️ This PR contains API changes and requires careful review. Please ensure these changes are intentional and backward compatible where possible.

Copy link
Member

@tyllark tyllark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the AFT ReadMe to reference this new command.

Comment on lines +12 to +78
name: Label API Changes
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Check for API changes
id: check-api-changes
run: |
# Check for changes in API JSON files
API_JSON_CHANGES=$(git diff --name-only origin/main...HEAD | grep -E 'packages/aft/api_reports/.*\.api\.json' || true)

if [[ -n "$API_JSON_CHANGES" ]]; then
echo "API_CHANGES_DETECTED=true" >> $GITHUB_ENV
echo "API changes detected in the following files:"
echo "$API_JSON_CHANGES"
else
echo "API_CHANGES_DETECTED=false" >> $GITHUB_ENV
echo "No API changes detected."
fi

- name: Add API changes label
if: env.API_CHANGES_DETECTED == 'true'
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ['api-changes']
})

- name: Comment on PR
if: env.API_CHANGES_DETECTED == 'true'
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
// Check if we already commented about API changes
const commentMarker = '⚠️ This PR contains API changes';
const { data: comments } = await github.rest.issues.listComments({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo
});

// Look for an existing comment with our marker
const apiChangeComment = comments.find(comment =>
comment.body.includes(commentMarker) &&
comment.user.login === 'github-actions[bot]'
);

// Only create a comment if we haven't already
if (!apiChangeComment) {
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '⚠️ This PR contains API changes and requires careful review. Please ensure these changes are intentional and backward compatible where possible.'
});
} else {
console.log('API changes comment already exists, skipping comment creation');
} No newline at end of file

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI 1 day ago

In general, this problem is fixed by explicitly adding a permissions block to the workflow (at the root or per job) so that the GITHUB_TOKEN has only the minimal scopes needed. This prevents the token from inheriting potentially broad repository or organization defaults.

For this specific workflow, the job needs:

  • To check out code and run git diffcontents: read
  • To add a label to the pull request → this uses issues.addLabels on a PR, which is allowed via pull-requests: write (or issues: write as labels live on the issue/PR). Using pull-requests: write is a clear fit for PR-centric operations.
  • To create a comment on the pull request → also covered by pull-requests: write.

No other scopes (like contents: write, actions, checks, etc.) are required. The safest minimal fix is to add a permissions block under the label-api-changes job (or at the root; job-level is enough here) with:

permissions:
  contents: read
  pull-requests: write

This change should be inserted directly under the job definition (label-api-changes: / name: Label API Changes region) in .github/workflows/api-report-approval.yaml. No imports or additional methods are required, as this is purely YAML configuration for GitHub Actions.

Suggested changeset 1
.github/workflows/api-report-approval.yaml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/api-report-approval.yaml b/.github/workflows/api-report-approval.yaml
--- a/.github/workflows/api-report-approval.yaml
+++ b/.github/workflows/api-report-approval.yaml
@@ -11,6 +11,9 @@
   label-api-changes:
     name: Label API Changes
     runs-on: ubuntu-latest
+    permissions:
+      contents: read
+      pull-requests: write
     steps:
       - name: Checkout code
         uses: actions/checkout@v3
EOF
@@ -11,6 +11,9 @@
label-api-changes:
name: Label API Changes
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v3
Copilot is powered by AI and may make mistakes. Always verify output.
Comment on lines +15 to +115
name: Check API Reports
runs-on: ubuntu-latest
steps:
- name: Git Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
cache: true
channel: 'stable'
flutter-version: '3.32.4'

- name: Setup aft
run: flutter pub global activate -spath packages/aft

- name: Bootstrap
id: bootstrap
timeout-minutes: 20
run: aft bootstrap --fail-fast --include=aft --verbose

- name: Install dart_apitool
run: flutter pub global activate dart_apitool

- name: Generate API reports
run: aft generate api-report

- name: Check for changes in API reports
id: check-changes
run: |
# Debug: Print git status
echo "=== DEBUG: Git status ==="
git status --porcelain

# Check API JSON files for changes
API_JSON_CHANGES=$(git status --porcelain | grep 'packages/aft/api_reports/.*\.api\.json' || true)

if [[ -n "$API_JSON_CHANGES" ]]; then
echo "API report files have changes. Checking if they are actual API changes..."
git diff --name-only | grep -E 'packages/aft/api_reports/.*\.api\.json'

ACTUAL_API_CHANGES=false

# Compare API interfaces using sets instead of text diff
# We're comparing the PR's committed API reports vs freshly generated ones
for file in $(git diff --name-only | grep -E 'packages/aft/api_reports/.*\.api\.json'); do
echo "=== Checking API changes in: $file ==="

# Get the version from the PR (what developer committed)
git show HEAD:"$file" | jq -r '.interfaceDeclarations[] | tostring' > /tmp/pr_interfaces.txt 2>/dev/null || touch /tmp/pr_interfaces.txt

# Get the freshly generated version (what CI just created)
jq -r '.interfaceDeclarations[] | tostring' "$file" > /tmp/generated_interfaces.txt

# Compare the interface sets
if ! cmp -s /tmp/pr_interfaces.txt /tmp/generated_interfaces.txt; then
echo "=== ACTUAL API CHANGES DETECTED in: $file ==="
echo "The API report in your PR doesn't match the current code. Please run 'aft generate api-report' and commit the changes."
echo "Full diff for debugging:"
git diff "$file"
ACTUAL_API_CHANGES=true
else
echo "API report is up-to-date for: $file"
fi

rm -f /tmp/pr_interfaces.txt /tmp/generated_interfaces.txt
done

if [[ "$ACTUAL_API_CHANGES" == "true" ]]; then
echo "ERROR: API report files are not up-to-date. Please run 'aft generate api-report' and commit the changes."
exit 1
else
echo "All API reports are up-to-date (detected only ordering differences)."
fi
else
echo "API report files are up-to-date."
fi

- name: Check if API reports are included in PR
run: |
# Get the list of changed files in the PR
CHANGED_FILES=$(git diff --name-only origin/main...HEAD)

# Check if any Dart files were modified
DART_FILES=$(echo "$CHANGED_FILES" | grep -E '\.dart$' || true)
if [[ -z "$DART_FILES" ]]; then
echo "No Dart files were modified, skipping API report check."
exit 0
fi

# Check if API report files are included
API_REPORTS=$(echo "$CHANGED_FILES" | grep -E 'packages/aft/api_reports/.*\.api\.json' || true)
if [[ -z "$API_REPORTS" ]]; then
echo "Error: API report files are not included in this PR."
echo "Please run 'aft generate api-report' and commit the changes."
exit 1
fi

echo "API report files are included in the PR."

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI 1 day ago

In general, fix this by explicitly defining a permissions: block to scope down the GITHUB_TOKEN to only what this workflow needs. Since this job only checks out code and runs local tools and git commands, it needs only read access to repository contents (and no write permissions, and no access to other scopes like issues, pull-requests, etc.).

The best minimal change without altering functionality is to add a permissions: block at the workflow root (top-level, alongside name: and on:) so it applies to all jobs. Given current usage, contents: read is sufficient. No steps in the job push commits, create releases, comment on PRs, or otherwise call GitHub APIs in a way that needs broader scopes.

Concretely:

  • Edit .github/workflows/api-report-check.yaml.
  • Insert a permissions: block after the name: API Report Check line (line 1 in the snippet) and before the on: block.
  • Set it to:
    permissions:
      contents: read

No additional imports, methods, or definitions are needed since this is purely YAML configuration.

Suggested changeset 1
.github/workflows/api-report-check.yaml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/api-report-check.yaml b/.github/workflows/api-report-check.yaml
--- a/.github/workflows/api-report-check.yaml
+++ b/.github/workflows/api-report-check.yaml
@@ -1,5 +1,8 @@
 name: API Report Check
 
+permissions:
+  contents: read
+
 on:
   pull_request:
     branches:
EOF
@@ -1,5 +1,8 @@
name: API Report Check

permissions:
contents: read

on:
pull_request:
branches:
Copilot is powered by AI and may make mistakes. Always verify output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants