pr writer fixes

This commit is contained in:
Arthur Tazhitdinov 2026-02-01 21:56:20 +03:00
parent 9db4408750
commit 6297189e6f
2 changed files with 167 additions and 114 deletions

View File

@ -6,10 +6,13 @@ on:
- opened - opened
- reopened - reopened
- edited - edited
- synchronize
permissions: permissions:
contents: read
statuses: write statuses: write
pull-requests: write pull-requests: write
issues: write
jobs: jobs:
title-check: title-check:
@ -25,11 +28,11 @@ jobs:
id: title_check id: title_check
uses: amannn/action-semantic-pull-request@v6 uses: amannn/action-semantic-pull-request@v6
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ github.token }}
- name: Comment with changelog hint on failure - name: Comment with changelog hint on failure
if: failure() if: failure()
uses: actions/github-script@v7 uses: actions/github-script@v8
with: with:
script: | script: |
const marker = '<!-- pr-title-check -->'; const marker = '<!-- pr-title-check -->';
@ -46,8 +49,11 @@ If this change should appear in release notes, ensure the title reflects the cor
owner: context.repo.owner, owner: context.repo.owner,
repo: context.repo.repo, repo: context.repo.repo,
issue_number: context.issue.number, issue_number: context.issue.number,
per_page: 100,
}); });
const existing = comments.find((comment) => comment.body && comment.body.includes(marker));
const existing = comments.find((comment) => (comment.body || "").includes(marker));
if (existing) { if (existing) {
await github.rest.issues.updateComment({ await github.rest.issues.updateComment({
owner: context.repo.owner, owner: context.repo.owner,
@ -63,3 +69,31 @@ If this change should appear in release notes, ensure the title reflects the cor
body, body,
}); });
} }
- name: Remove failure comment on success
if: success()
uses: actions/github-script@v8
with:
script: |
const marker = '<!-- pr-title-check -->';
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((comment) => (comment.body || "").includes(marker));
if (!existing) {
core.info("No previous PR title failure comment found.");
return;
}
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
});
core.info(`Deleted previous failure comment id=${existing.id}`);

View File

@ -1,111 +1,130 @@
comment_firmware: name: PR writes (label + comment)
runs-on: ubuntu-latest
steps:
- name: Find the matching CI run for this PR SHA
id: find_run
uses: actions/github-script@v8
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const pr = context.payload.pull_request;
const headSha = pr.head.sha;
const { data } = await github.rest.actions.listWorkflowRunsForRepo({ on:
owner, pull_request_target:
repo, types: [opened, synchronize, reopened]
event: "pull_request",
per_page: 50,
});
const run = data.workflow_runs.find(r => r.head_sha === headSha && r.name === "CI (build)"); permissions:
if (!run) core.setFailed(`No matching CI (build) run found for head_sha=${headSha}.`); contents: read
pull-requests: write
issues: write
core.setOutput("run_id", String(run.id)); jobs:
core.setOutput("run_html_url", run.html_url); label:
runs-on: ubuntu-latest
steps:
# Safe: labeler reads files from the base repo by default in pull_request_target context.
# Do NOT checkout PR head.
- uses: actions/labeler@v5
- name: Locate artifact IDs in the CI run comment_firmware:
id: artifacts runs-on: ubuntu-latest
uses: actions/github-script@v8 steps:
with: - name: Find the matching CI run for this PR SHA
script: | id: find_run
const owner = context.repo.owner; uses: actions/github-script@v8
const repo = context.repo.repo; with:
const runId = Number("${{ steps.find_run.outputs.run_id }}"); script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const pr = context.payload.pull_request;
const headSha = pr.head.sha;
const { data } = await github.rest.actions.listWorkflowRunArtifacts({ const { data } = await github.rest.actions.listWorkflowRunsForRepo({
owner, owner,
repo, repo,
run_id: runId, event: "pull_request",
per_page: 100, per_page: 50,
}); });
const artifacts = data.artifacts || []; const run = data.workflow_runs.find(r => r.head_sha === headSha && r.name === "CI (build)");
const fw = artifacts.find(a => a.name === "firmware-bin"); if (!run) core.setFailed(`No matching CI (build) run found for head_sha=${headSha}.`);
const meta = artifacts.find(a => a.name === "build-meta");
if (!meta) core.setFailed("build-meta artifact not found in CI run artifacts."); core.setOutput("run_id", String(run.id));
// firmware-bin is nice-to-have for linking; fail if you want. core.setOutput("run_html_url", run.html_url);
core.setOutput("fw_id", fw ? String(fw.id) : "");
core.setOutput("meta_id", String(meta.id));
- name: Download build-meta artifact zip and extract pio.log - name: Locate artifact IDs in the CI run
id: parse_log id: artifacts
shell: bash uses: actions/github-script@v8
env: with:
OWNER: ${{ github.repository_owner }} script: |
REPO: ${{ github.event.repository.name }} const owner = context.repo.owner;
META_ID: ${{ steps.artifacts.outputs.meta_id }} const repo = context.repo.repo;
GH_TOKEN: ${{ github.token }} const runId = Number("${{ steps.find_run.outputs.run_id }}");
run: |
set -euo pipefail
# Download artifact zip via GitHub API (will redirect to blob storage; -L follows) const { data } = await github.rest.actions.listWorkflowRunArtifacts({
api="https://api.github.com/repos/${OWNER}/${REPO}/actions/artifacts/${META_ID}/zip" owner,
curl -sSL \ repo,
-H "Authorization: Bearer ${GH_TOKEN}" \ run_id: runId,
-H "X-GitHub-Api-Version: 2022-11-28" \ per_page: 100,
-o build-meta.zip \ });
"${api}"
mkdir -p build-meta const artifacts = data.artifacts || [];
unzip -q build-meta.zip -d build-meta const fw = artifacts.find(a => a.name === "firmware-bin");
const meta = artifacts.find(a => a.name === "build-meta");
if [[ ! -f build-meta/pio.log ]]; then if (!meta) core.setFailed("build-meta artifact not found in CI run artifacts.");
echo "pio.log not found inside build-meta artifact" // firmware-bin is nice-to-have for linking; fail if you want.
echo "ram_line=" >> "$GITHUB_OUTPUT" core.setOutput("fw_id", fw ? String(fw.id) : "");
echo "flash_line=" >> "$GITHUB_OUTPUT" core.setOutput("meta_id", String(meta.id));
exit 0
fi
ram_line="$(grep -E "RAM:\s" -m1 build-meta/pio.log || true)" - name: Download build-meta artifact zip and extract pio.log
flash_line="$(grep -E "Flash:\s" -m1 build-meta/pio.log || true)" id: parse_log
shell: bash
env:
OWNER: ${{ github.repository_owner }}
REPO: ${{ github.event.repository.name }}
META_ID: ${{ steps.artifacts.outputs.meta_id }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
echo "ram_line=${ram_line}" >> "$GITHUB_OUTPUT" # Download artifact zip via GitHub API (will redirect to blob storage; -L follows)
echo "flash_line=${flash_line}" >> "$GITHUB_OUTPUT" api="https://api.github.com/repos/${OWNER}/${REPO}/actions/artifacts/${META_ID}/zip"
curl -sSL \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
-o build-meta.zip \
"${api}"
- name: Post/update PR comment with RAM/Flash + artifact links mkdir -p build-meta
uses: actions/github-script@v8 unzip -q build-meta.zip -d build-meta
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const prNumber = context.payload.pull_request.number;
const runId = Number("${{ steps.find_run.outputs.run_id }}"); if [[ ! -f build-meta/pio.log ]]; then
const runUrl = "${{ steps.find_run.outputs.run_html_url }}"; echo "pio.log not found inside build-meta artifact"
echo "ram_line=" >> "$GITHUB_OUTPUT"
echo "flash_line=" >> "$GITHUB_OUTPUT"
exit 0
fi
const marker = '<!-- firmware-stats -->'; ram_line="$(grep -E "RAM:\s" -m1 build-meta/pio.log || true)"
const ram = `${{ steps.parse_log.outputs.ram_line }}`.trim(); flash_line="$(grep -E "Flash:\s" -m1 build-meta/pio.log || true)"
const flash = `${{ steps.parse_log.outputs.flash_line }}`.trim();
const fwId = `${{ steps.artifacts.outputs.fw_id }}`.trim(); echo "ram_line=${ram_line}" >> "$GITHUB_OUTPUT"
const metaId = `${{ steps.artifacts.outputs.meta_id }}`.trim(); echo "flash_line=${flash_line}" >> "$GITHUB_OUTPUT"
const fwUrl = fwId ? `https://github.com/${owner}/${repo}/actions/runs/${runId}/artifacts/${fwId}` : null; - name: Post/update PR comment with RAM/Flash + artifact links
const metaUrl = metaId ? `https://github.com/${owner}/${repo}/actions/runs/${runId}/artifacts/${metaId}` : null; uses: actions/github-script@v8
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const prNumber = context.payload.pull_request.number;
const body = const runId = Number("${{ steps.find_run.outputs.run_id }}");
const runUrl = "${{ steps.find_run.outputs.run_html_url }}";
const marker = '<!-- firmware-stats -->';
const ram = `${{ steps.parse_log.outputs.ram_line }}`.trim();
const flash = `${{ steps.parse_log.outputs.flash_line }}`.trim();
const fwId = `${{ steps.artifacts.outputs.fw_id }}`.trim();
const metaId = `${{ steps.artifacts.outputs.meta_id }}`.trim();
const fwUrl = fwId ? `https://github.com/${owner}/${repo}/actions/runs/${runId}/artifacts/${fwId}` : null;
const metaUrl = metaId ? `https://github.com/${owner}/${repo}/actions/runs/${runId}/artifacts/${metaId}` : null;
const body =
`${marker} `${marker}
**Firmware build stats** **Firmware build stats**
@ -120,26 +139,26 @@ ${flash || "Flash: not found"}
- Build logs: ${metaUrl ? `[build-meta](${metaUrl})` : "artifact not found"} - Build logs: ${metaUrl ? `[build-meta](${metaUrl})` : "artifact not found"}
`; `;
const { data: comments } = await github.rest.issues.listComments({ const { data: comments } = await github.rest.issues.listComments({
owner, owner,
repo, repo,
issue_number: prNumber, issue_number: prNumber,
per_page: 100, per_page: 100,
}); });
const existing = comments.find(c => (c.body || "").includes(marker)); const existing = comments.find(c => (c.body || "").includes(marker));
if (existing) { if (existing) {
await github.rest.issues.updateComment({ await github.rest.issues.updateComment({
owner, owner,
repo, repo,
comment_id: existing.id, comment_id: existing.id,
body, body,
}); });
} else { } else {
await github.rest.issues.createComment({ await github.rest.issues.createComment({
owner, owner,
repo, repo,
issue_number: prNumber, issue_number: prNumber,
body, body,
}); });
} }