Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 98 additions & 3 deletions .github/workflows/abi-report.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Publishes the result of the "abi" workflow (abi.yaml) on the pull request:
# one sticky comment with the per-library ABI verdicts and the
# "ABI compatible" / "ABI break" label.
# one sticky comment with the per-library ABI verdicts, the
# "ABI compatible" / "ABI break" label, and the backport candidate labels.
#
# This is a separate workflow because abi.yaml builds and diffs the pull
# request's own code. For pull requests from forks GitHub therefore runs it
Expand All @@ -11,7 +11,7 @@
# report artifacts the abi run uploaded and posts what they say.
#
# The pass/fail check on the pull request still comes from abi.yaml; this
# workflow only adds the comment and the label. It only starts firing once it
# workflow only adds the comment and the labels. It only starts firing once it
# exists on the default branch, and a first-time contributor's abi run still
# needs a maintainer's approval before anything is published.
#
Expand All @@ -32,3 +32,98 @@ jobs:
issues: write # label
actions: read # download the abi run's report artifacts
uses: fujitatomoya/ros2-abi-action/.github/workflows/report.yml@v1

# Backport candidate labels (https://github.com/ros2/rclcpp/issues/2555).
#
# Bug fixes should reach the supported released distributions, and the main
# reason they are missed is that nobody can tell at a glance whether a change
# is ABI compatible. Once the report job has published the verdict, this job
# adds one "backport-<distro>" label per distribution downstream of the PR's
# target branch when every library is ABI compatible, and removes them when
# it is not. The labels are a hint for maintainers, not a decision: the
# backport itself is still started by hand (@Mergifyio backport <distro>),
# and the backport PR gets its own strict ABI check on the release branch.
#
# A label a maintainer removed by hand is not added again on later pushes,
# so "this is a feature, do not backport" sticks.
#
# This runs from the workflow_run token of this repository, so pull requests
# from forks are labelled too.
backport-label:
needs: report
# The report job leaves both outputs empty when it published nothing (no
# verdict artifacts, or the PR already moved past the checked commit).
if: needs.report.outputs.verdict != '' && needs.report.outputs.pr-number != ''
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # labels
issues: write # labels
env:
VERDICT: ${{ needs.report.outputs.verdict }}
PR_NUMBER: ${{ needs.report.outputs.pr-number }}
# Distributions newest first; a PR targeting one of them is a backport
# candidate for every distribution listed after it. Keep in sync with
# the branches in abi.yaml.
DISTROS: rolling lyrical kilted jazzy humble
LABEL_PREFIX: backport-
steps:
# No checkout: nothing from the pull request is executed here.
- name: Reconcile backport labels
uses: actions/github-script@v7
with:
script: |
const { owner, repo } = context.repo;
const prNumber = Number(process.env.PR_NUMBER);
const verdict = process.env.VERDICT;
const distros = process.env.DISTROS.trim().split(/\s+/);
const prefix = process.env.LABEL_PREFIX;
const compatible = (verdict === 'compatible' || verdict === 'additions-only');

const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
const base = pr.base.ref;
const idx = distros.indexOf(base);
if (idx < 0) {
core.notice(`#${prNumber} targets ${base}, which is not a distribution branch; no backport labels.`);
return;
}
const downstream = distros.slice(idx + 1).map((d) => prefix + d);
if (downstream.length === 0) {
core.notice(`#${prNumber} targets ${base}, the oldest supported distribution; nothing to backport to.`);
return;
}

const present = new Set(pr.labels.map((l) => l.name));
const all = distros.map((d) => prefix + d);

if (!compatible) {
// Mirror the "ABI compatible" label: gone on incompatible / error.
for (const name of all.filter((n) => present.has(n))) {
await github.rest.issues.removeLabel({ owner, repo, issue_number: prNumber, name });
core.info(`Removed label: ${name} (verdict: ${verdict})`);
}
return;
}

// Labels a person removed stay removed. Labels this workflow adds
// and removes show up as github-actions[bot] in the timeline.
const events = await github.paginate(github.rest.issues.listEventsForTimeline, {
owner, repo, issue_number: prNumber, per_page: 100,
});
const removedByHand = new Set(
events
.filter((e) => e.event === 'unlabeled' && e.actor && e.actor.login !== 'github-actions[bot]')
.map((e) => e.label && e.label.name),
);

const toAdd = downstream.filter((n) => !present.has(n) && !removedByHand.has(n));
for (const n of downstream.filter((n) => removedByHand.has(n) && !present.has(n))) {
core.info(`Skipped label: ${n} (removed by a maintainer)`);
}
if (toAdd.length) {
// Missing labels are created on the fly by this endpoint.
await github.rest.issues.addLabels({ owner, repo, issue_number: prNumber, labels: toAdd });
core.info(`Added labels: ${toAdd.join(', ')} (verdict: ${verdict}, base: ${base})`);
} else {
core.info(`Backport labels already up to date on #${prNumber}.`);
}
13 changes: 7 additions & 6 deletions .github/workflows/abi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@
# 6. surfaces the verdict as a pass/fail check and uploads one report bundle
# (abidiff report + verdict.json) per library.
#
# The sticky PR comment and the "ABI compatible" / "ABI break" labels are NOT
# posted from here (publish: workflow-run). Most rclcpp pull requests come from
# forks, and on pull_request events from a fork GitHub gives this workflow a
# read-only token regardless of the permissions requested below, so any write
# to the PR would fail. abi-report.yaml runs on workflow_run once this workflow
# completes and publishes the comment and labels with a token that may write.
# The sticky PR comment, the "ABI compatible" / "ABI break" labels and the
# "backport-<distro>" candidate labels are NOT posted from here
# (publish: workflow-run). Most rclcpp pull requests come from forks, and on
# pull_request events from a fork GitHub gives this workflow a read-only token
# regardless of the permissions requested below, so any write to the PR would
# fail. abi-report.yaml runs on workflow_run once this workflow completes and
# publishes the comment and labels with a token that may write.
#
# Paired changes in other repositories (e.g. an rcl PR this PR depends on) are
# declared by the PR author in the PR description and applied to the PR side
Expand Down
Loading