Skip to content

[ci] Added automated backport workflow#346

Merged
nemesifier merged 2 commits intoopenwisp:masterfrom
atif09:feature/backport-workflow
Mar 4, 2026
Merged

[ci] Added automated backport workflow#346
nemesifier merged 2 commits intoopenwisp:masterfrom
atif09:feature/backport-workflow

Conversation

@atif09
Copy link
Copy Markdown
Contributor

@atif09 atif09 commented Feb 22, 2026

Checklist

  • I have read the OpenWISP Contributing Guidelines.
  • I have manually tested the changes proposed in this pull request.
  • I have written new test cases for new code and/or updated existing tests for changes to existing code.
  • I have updated the documentation.

Reference to Existing Issue

openwisp/openwisp-utils#501

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 22, 2026

📝 Walkthrough

Walkthrough

Adds a new GitHub Actions workflow at .github/workflows/backport.yml named "Backport fixes to stable branch". It defines two triggers: a push-based job that runs on pushes to master and passes commit_sha to a reusable backport workflow, and a comment-based job that runs on qualifying issue comments (merged PR, author association MEMBER/OWNER, comment starting with /backport) and passes pr_number and comment_body. Both jobs invoke the reusable workflow in openwisp/openwisp-utils and supply required secrets and permissions.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer
  participant Repo as Repository (.github/workflows/backport.yml)
  participant GH as GitHub Actions
  participant Reusable as openwisp/openwisp-utils reusable workflow

  opt Push-triggered backport
    Dev->>Repo: Push to master (commit)
    GH->>Repo: Detect push -> run backport-on-push
    Repo->>Reusable: Invoke reusable-backport (input: commit_sha, secrets)
    Reusable->>GH: Execute backport steps (uses provided secrets)
    GH->>Repo: Report result / update status
  end

  opt Comment-triggered backport
    Dev->>Repo: Comment "/backport" on merged PR
    GH->>Repo: Detect issue_comment -> run backport-on-comment
    Repo->>Reusable: Invoke reusable-backport (inputs: pr_number, comment_body, secrets)
    Reusable->>GH: Execute backport steps (uses provided secrets)
    GH->>Repo: Report result / update status
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description includes a checklist with some items completed, but lacks detailed description of changes and reference to issue is incomplete. Complete the 'Description of Changes' section explaining the backport workflow and its purpose, and provide proper issue reference format (Closes #).
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding an automated backport workflow to CI.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d93c0ad and dcb0048.

📒 Files selected for processing (1)
  • .github/workflows/backport.yml
🔇 Additional comments (1)
.github/workflows/backport.yml (1)

3-7: The reusable workflow already handles non-backport pushes gracefully. The reusable-backport.yml workflow reads the commit message for a [backport: branches] label and only executes the backport job if backport targets are explicitly specified. Commits to master/main without this label will cause the parse job to output an empty branches list, which prevents the backport job from running due to its conditional check. Non-backport commits therefore do not trigger spurious PR creation.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/backport.yml:
- Line 35: The workflow guard currently checks contains(fromJSON('["MEMBER",
"OWNER"]'), github.event.comment.author_association) and therefore excludes
repository collaborators; if collaborators with write access should be allowed
to trigger backports, update that array to include "COLLABORATOR" (i.e., add
"COLLABORATOR" to the fromJSON array in the contains(...) check in backport.yml)
so the condition permits MEMBER, OWNER, and COLLABORATOR associations.
- Around line 11-13: The concurrency group currently uses github.ref which is
identical across push and issue_comment events and causes unrelated runs to
serialize; update the concurrency.group value (the concurrency: group setting)
to include the event name and a per-request identifier so runs for different
PRs/issues can run in parallel—for example use an expression combining
github.event_name and a coalesced identifier like ${{
github.event.pull_request.number || github.event.issue.number || github.sha }}
(keep cancel-in-progress: false or adjust as desired) so concurrency.group
becomes something like backport-${{ github.workflow }}-${{ github.event_name
}}-${{ github.event.pull_request.number || github.event.issue.number ||
github.sha }} referencing the symbols concurrency.group, cancel-in-progress,
github.ref, github.event.pull_request.number, github.event.issue.number,
github.sha, and github.event_name.
- Line 22: Replace the mutable branch reference for the reusable workflow with a
full commit SHA: locate the two occurrences of "uses:
openwisp/openwisp-utils/.github/workflows/reusable-backport.yml@master" and
replace "@master" with the current full-length commit SHA for
openwisp/openwisp-utils (you can obtain it via `gh api
repos/openwisp/openwisp-utils/commits/master --jq '.sha'`), updating both
instances so the workflow is pinned to that exact commit SHA.

Comment on lines +11 to +13
concurrency:
group: backport-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Concurrency group key collapses all runs into one queue.

github.ref for issue_comment events is always the default branch. That is the same value the push trigger produces when a commit lands on master/main, so every run — push-triggered or comment-triggered, regardless of which PR is being backported — shares a single concurrency group. With cancel-in-progress: false they all queue sequentially, meaning two concurrent /backport requests on unrelated PRs (e.g. targeting different stable branches) unnecessarily block each other.

Scope the key more narrowly so unrelated runs can proceed in parallel:

🔧 Proposed fix
 concurrency:
-  group: backport-${{ github.workflow }}-${{ github.ref }}
+  group: >-
+    ${{ github.event_name == 'issue_comment'
+        && format('backport-comment-{0}', github.event.issue.number)
+        || format('backport-push-{0}', github.sha) }}
   cancel-in-progress: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
concurrency:
group: backport-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
concurrency:
group: >-
${{ github.event_name == 'issue_comment'
&& format('backport-comment-{0}', github.event.issue.number)
|| format('backport-push-{0}', github.sha) }}
cancel-in-progress: false
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/backport.yml around lines 11 - 13, The concurrency group
currently uses github.ref which is identical across push and issue_comment
events and causes unrelated runs to serialize; update the concurrency.group
value (the concurrency: group setting) to include the event name and a
per-request identifier so runs for different PRs/issues can run in parallel—for
example use an expression combining github.event_name and a coalesced identifier
like ${{ github.event.pull_request.number || github.event.issue.number ||
github.sha }} (keep cancel-in-progress: false or adjust as desired) so
concurrency.group becomes something like backport-${{ github.workflow }}-${{
github.event_name }}-${{ github.event.pull_request.number ||
github.event.issue.number || github.sha }} referencing the symbols
concurrency.group, cancel-in-progress, github.ref,
github.event.pull_request.number, github.event.issue.number, github.sha, and
github.event_name.

jobs:
backport-on-push:
if: github.event_name == 'push'
uses: openwisp/openwisp-utils/.github/workflows/reusable-backport.yml@master
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Pin the external reusable workflow to a commit SHA, not the mutable @master branch.

"Pinning an action to a full-length commit SHA is currently the only way to use an action as an immutable release." A tag (or branch name) can be moved or deleted if a bad actor gains access to the upstream repository, and the same principles apply to third-party reusable workflows. Additionally, when re-running a workflow that uses a reusable workflow and the reference is not a SHA, re-running all jobs will use the reusable workflow from the specified reference at that point in time, making reruns non-deterministic.

🔧 Proposed fix (apply to both lines 22 and 37)
-    uses: openwisp/openwisp-utils/.github/workflows/reusable-backport.yml@master
+    uses: openwisp/openwisp-utils/.github/workflows/reusable-backport.yml@<full-commit-sha> # `@master` as of <date>

Retrieve the current SHA with:

gh api repos/openwisp/openwisp-utils/commits/master --jq '.sha'

Also applies to: 37-37

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/backport.yml at line 22, Replace the mutable branch
reference for the reusable workflow with a full commit SHA: locate the two
occurrences of "uses:
openwisp/openwisp-utils/.github/workflows/reusable-backport.yml@master" and
replace "@master" with the current full-length commit SHA for
openwisp/openwisp-utils (you can obtain it via `gh api
repos/openwisp/openwisp-utils/commits/master --jq '.sha'`), updating both
instances so the workflow is pinned to that exact commit SHA.

github.event.issue.pull_request &&
github.event.issue.pull_request.merged_at != null &&
github.event.issue.state == 'closed' &&
contains(fromJSON('["MEMBER", "OWNER"]'), github.event.comment.author_association) &&
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider whether COLLABORATOR should be included in the author association check.

The guard currently restricts comment-triggered backports to MEMBER and OWNER. Repository collaborators with explicit write access (COLLABORATOR association) are excluded. If outside contributors with write access should be able to trigger backports, add "COLLABORATOR" to the list.

🔧 Proposed fix (if collaborators should be allowed)
-      contains(fromJSON('["MEMBER", "OWNER"]'), github.event.comment.author_association) &&
+      contains(fromJSON('["MEMBER", "OWNER", "COLLABORATOR"]'), github.event.comment.author_association) &&
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
contains(fromJSON('["MEMBER", "OWNER"]'), github.event.comment.author_association) &&
contains(fromJSON('["MEMBER", "OWNER", "COLLABORATOR"]'), github.event.comment.author_association) &&
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/backport.yml at line 35, The workflow guard currently
checks contains(fromJSON('["MEMBER", "OWNER"]'),
github.event.comment.author_association) and therefore excludes repository
collaborators; if collaborators with write access should be allowed to trigger
backports, update that array to include "COLLABORATOR" (i.e., add "COLLABORATOR"
to the fromJSON array in the contains(...) check in backport.yml) so the
condition permits MEMBER, OWNER, and COLLABORATOR associations.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
.github/workflows/backport.yml (2)

21-21: ⚠️ Potential issue | 🟠 Major

Pin reusable workflow to a full commit SHA.

Both uses entries reference mutable @master, which is non-deterministic on reruns and weaker from a supply-chain perspective.

🔧 Proposed fix
-    uses: openwisp/openwisp-utils/.github/workflows/reusable-backport.yml@master
+    uses: openwisp/openwisp-utils/.github/workflows/reusable-backport.yml@<full-commit-sha>
...
-    uses: openwisp/openwisp-utils/.github/workflows/reusable-backport.yml@master
+    uses: openwisp/openwisp-utils/.github/workflows/reusable-backport.yml@<full-commit-sha>
#!/bin/bash
# Fetch current SHA of openwisp-utils master (read-only verification)
gh api repos/openwisp/openwisp-utils/commits/master --jq '.sha'

Also applies to: 36-36

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/backport.yml at line 21, The workflow uses a mutable ref
("uses: openwisp/openwisp-utils/.github/workflows/reusable-backport.yml@master")
which must be pinned to an immutable full commit SHA; update every "uses:
openwisp/openwisp-utils/.github/workflows/reusable-backport.yml@master"
occurrence (including the second occurrence referenced in the comment) to the
corresponding full commit SHA for openwisp-utils master (you can obtain it via
GitHub API/gh cli) and replace the `@master` suffix with @<full-sha> so the
reusable workflow is pinned.

11-12: ⚠️ Potential issue | 🟠 Major

Scope concurrency per request, not per branch ref.

Using github.ref here causes unrelated runs to queue behind each other (same ref for push to master and issue_comment workflows). Use event + per-request identifier to avoid unnecessary serialization.

🔧 Proposed fix
 concurrency:
-  group: backport-${{ github.workflow }}-${{ github.ref }}
+  group: backport-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.issue.number || github.sha }}
   cancel-in-progress: false
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/backport.yml around lines 11 - 12, The workflow
concurrency group uses github.ref which serializes unrelated runs; change the
group to scope by workflow + event/run id instead — replace github.ref with
github.event_name and a per-request identifier such as github.run_id (e.g., use
group values built from github.workflow, github.event_name and github.run_id) so
each request is isolated; update the group key where "group:" is defined and
remove the reference to github.ref.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/backport.yml:
- Line 32: Remove the invalid condition reference to
github.event.issue.pull_request.merged_at from the issue_comment trigger in the
workflow (the check github.event.issue.pull_request.merged_at != null) because
merged_at is not present in issue_comment payloads; instead, call the reusable
workflow as-is on issue_comment and move merged-state verification into the
reusable workflow by querying the Pull Requests API for the PR number (from
github.event.issue.pull_request.url or related fields) and confirming merged
status before performing backport logic.

---

Duplicate comments:
In @.github/workflows/backport.yml:
- Line 21: The workflow uses a mutable ref ("uses:
openwisp/openwisp-utils/.github/workflows/reusable-backport.yml@master") which
must be pinned to an immutable full commit SHA; update every "uses:
openwisp/openwisp-utils/.github/workflows/reusable-backport.yml@master"
occurrence (including the second occurrence referenced in the comment) to the
corresponding full commit SHA for openwisp-utils master (you can obtain it via
GitHub API/gh cli) and replace the `@master` suffix with @<full-sha> so the
reusable workflow is pinned.
- Around line 11-12: The workflow concurrency group uses github.ref which
serializes unrelated runs; change the group to scope by workflow + event/run id
instead — replace github.ref with github.event_name and a per-request identifier
such as github.run_id (e.g., use group values built from github.workflow,
github.event_name and github.run_id) so each request is isolated; update the
group key where "group:" is defined and remove the reference to github.ref.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dcb0048 and 6657c12.

📒 Files selected for processing (1)
  • .github/workflows/backport.yml

if: >
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.issue.pull_request.merged_at != null &&
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

GitHub Actions issue_comment event payload github.event.issue.pull_request merged_at field documentation

💡 Result:

In an issue_comment workflow run, github.event is the webhook payload, and the issue object is the same “issue (or PR-as-issue)” shape you get from the Issues API. GitHub’s Actions docs note you can detect PR comments with github.event.issue.pull_request (it’s present for PRs, absent for issues). [1]

However, for issue_comment, github.event.issue.pull_request is only a link object (e.g., url, html_url, diff_url, patch_url) and does not include PR fields like merged_at. This is shown in the Issues API example response where pull_request contains only those URLs. [2]

To get merged_at, you must fetch the PR itself (e.g., via the Pull Requests API using the URL in github.event.issue.pull_request.url) or at least check merged status via the dedicated endpoint (GET /repos/{owner}/{repo}/pulls/{pull_number}/merge). [3]

Sources
[1] https://docs.github.com/actions/learn-github-actions/events-that-trigger-workflows
[2] https://docs.github.com/en/rest/issues/issues
[3] https://docs.github.com/en/rest/pulls/pulls


Remove merged_at check from trigger—this field does not exist in issue_comment payloads.

In issue_comment events, github.event.issue.pull_request contains only link metadata (url, html_url, diff_url, patch_url). The merged_at field is not present, making the current guard ineffective. Move merged status verification into the reusable workflow using the Pull Requests API.

🔧 Proposed fix
       github.event_name == 'issue_comment' &&
       github.event.issue.pull_request &&
-      github.event.issue.pull_request.merged_at != null &&
       github.event.issue.state == 'closed' &&
       contains(fromJSON('["MEMBER", "OWNER"]'), github.event.comment.author_association) &&
       startsWith(github.event.comment.body, '/backport')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
github.event.issue.pull_request.merged_at != null &&
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.issue.state == 'closed' &&
contains(fromJSON('["MEMBER", "OWNER"]'), github.event.comment.author_association) &&
startsWith(github.event.comment.body, '/backport')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/backport.yml at line 32, Remove the invalid condition
reference to github.event.issue.pull_request.merged_at from the issue_comment
trigger in the workflow (the check github.event.issue.pull_request.merged_at !=
null) because merged_at is not present in issue_comment payloads; instead, call
the reusable workflow as-is on issue_comment and move merged-state verification
into the reusable workflow by querying the Pull Requests API for the PR number
(from github.event.issue.pull_request.url or related fields) and confirming
merged status before performing backport logic.

@nemesifier nemesifier merged commit 3629c3f into openwisp:master Mar 4, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants