csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
6.5 KiB
181 lines
6.5 KiB
name: Output API Diff
|
|
|
|
on:
|
|
issue_comment:
|
|
types: [created]
|
|
|
|
permissions: {}
|
|
|
|
concurrency:
|
|
group: api-diff-${{ github.event.issue.number }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
api-diff:
|
|
name: Output API Diff
|
|
if: >-
|
|
github.event.issue.pull_request
|
|
&& contains(github.event.comment.body, '/api-diff')
|
|
&& contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)
|
|
runs-on: ubuntu-latest
|
|
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
|
|
steps:
|
|
- name: Check maintainer permission
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const { data: permLevel } = await github.rest.repos.getCollaboratorPermissionLevel({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
username: context.payload.comment.user.login,
|
|
});
|
|
const allowed = ['admin', 'maintain', 'write'];
|
|
if (!allowed.includes(permLevel.permission)) {
|
|
core.setFailed(`User @${context.payload.comment.user.login} does not have write access.`);
|
|
}
|
|
|
|
- name: Add reaction to acknowledge command
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
await github.rest.reactions.createForIssueComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
comment_id: context.payload.comment.id,
|
|
content: 'eyes',
|
|
});
|
|
|
|
- name: Get PR branch info
|
|
id: pr
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const { data: pr } = await github.rest.pulls.get({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
pull_number: context.issue.number,
|
|
});
|
|
if (pr.head.repo.full_name !== `${context.repo.owner}/${context.repo.repo}`) {
|
|
core.setFailed('Cannot run /api-diff on fork PRs — would execute untrusted code.');
|
|
return;
|
|
}
|
|
core.setOutput('ref', pr.head.ref);
|
|
core.setOutput('sha', pr.head.sha);
|
|
|
|
- name: Checkout PR branch
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ steps.pr.outputs.sha }}
|
|
submodules: recursive
|
|
|
|
- name: Setup .NET
|
|
uses: actions/setup-dotnet@v4
|
|
with:
|
|
global-json-file: global.json
|
|
|
|
- name: Run OutputApiDiff
|
|
run: dotnet run --project ./nukebuild/_build.csproj -- OutputApiDiff
|
|
|
|
- name: Post API diff as PR comment
|
|
if: always() && steps.pr.outcome == 'success'
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const diffDir = path.join(process.env.GITHUB_WORKSPACE, 'artifacts', 'api-diff', 'markdown');
|
|
const mergedPath = path.join(diffDir, '_diff.md');
|
|
|
|
let body;
|
|
if (fs.existsSync(mergedPath)) {
|
|
let diff = fs.readFileSync(mergedPath, 'utf8').trim();
|
|
if (!diff || diff.toLowerCase().includes('no changes')) {
|
|
body = '### API Diff\n\n✅ No public API changes detected in this PR.';
|
|
} else {
|
|
const MAX_COMMENT_LENGTH = 60000; // GitHub comment limit is 65536
|
|
const header = '### API Diff\n\n';
|
|
const footer = '\n\n---\n_Generated by `/api-diff` command._';
|
|
const budget = MAX_COMMENT_LENGTH - header.length - footer.length;
|
|
|
|
if (diff.length > budget) {
|
|
diff = diff.substring(0, budget) + '\n\n> ⚠️ Output truncated. See the [full workflow run](' +
|
|
`${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` +
|
|
') for complete diff.';
|
|
}
|
|
|
|
body = header + diff + footer;
|
|
}
|
|
} else {
|
|
body = '### API Diff\n\n⚠️ No diff output was produced. Check the [workflow run](' +
|
|
`${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` +
|
|
') for details.';
|
|
}
|
|
|
|
// Collapse into <details> if large
|
|
if (body.length > 2000) {
|
|
const inner = body;
|
|
body = '<details>\n<summary>📋 API Diff (click to expand)</summary>\n\n' + inner + '\n\n</details>';
|
|
}
|
|
|
|
// Update existing bot comment or create a new one
|
|
const marker = '<!-- api-diff-bot -->';
|
|
body = marker + '\n' + body;
|
|
|
|
const { data: comments } = await github.rest.issues.listComments({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: context.issue.number,
|
|
per_page: 100,
|
|
});
|
|
const existing = comments.find(c => c.body?.includes(marker));
|
|
|
|
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,
|
|
});
|
|
}
|
|
|
|
- name: Add success reaction
|
|
if: success()
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
await github.rest.reactions.createForIssueComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
comment_id: context.payload.comment.id,
|
|
content: 'rocket',
|
|
});
|
|
|
|
- name: Report failure
|
|
if: failure()
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
await github.rest.reactions.createForIssueComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
comment_id: context.payload.comment.id,
|
|
content: '-1',
|
|
});
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: context.issue.number,
|
|
body: `❌ \`/api-diff\` failed. [See logs](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}).`,
|
|
});
|
|
|