Skip to content

Consolidate backport workflow onto ddev release port-commit - #24470

Merged
Kyle-Neale merged 15 commits into
masterfrom
kyle.neale/backport-via-port-commit
Aug 13, 2026
Merged

Consolidate backport workflow onto ddev release port-commit#24470
Kyle-Neale merged 15 commits into
masterfrom
kyle.neale/backport-via-port-commit

Conversation

@Kyle-Neale

Copy link
Copy Markdown
Contributor

What does this PR do?

Replaces the tibdex/backport action with a ddev release port-commit loop. For each backport/<base> label on a merged PR, the workflow cherry-picks the merged commit onto the release branch and resets per-branch regenerated files — .in-toto and now .deps/ — to the target branch. One tested tool now backs both manual and CI backports.

Motivation

Auto-backports failed when a merged PR touched .deps/: the cherry-pick carried the source branch's resolved lockfiles onto the release branch, producing a broken backport. port-commit already reset .in-toto this way; generalizing that to .deps/ fixes the failure and collapses the CI-only backport path onto the same tool used manually.

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Add qa/required if this PR needs QA validation, or qa/skip-qa if it does not. Exactly one of the two is required.
  • If you need to backport this PR to another branch, you can add the backport/<branch-name> label to the PR and it will automatically open a backport PR once this one is merged

@Kyle-Neale Kyle-Neale added the qa/skip-qa Automatically skip this PR for the next QA label Jul 9, 2026
@datadog-prod-us1-6

datadog-prod-us1-6 Bot commented Jul 9, 2026

Copy link
Copy Markdown

Tests  Code Coverage

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 97.79%
Overall Coverage: 88.60% (+0.18%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 59ec2e5 | Docs | Datadog PR Page | Give us feedback!

@Kyle-Neale
Kyle-Neale marked this pull request as ready for review July 13, 2026 14:00
@Kyle-Neale
Kyle-Neale requested a review from a team as a code owner July 13, 2026 14:00
@Kyle-Neale
Kyle-Neale requested a review from Copilot July 13, 2026 14:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR consolidates the repository’s automated backporting onto the existing ddev release port-commit implementation, replacing the separate tibdex/backport workflow path. It extends port-commit’s “reset regenerated files to target branch” behavior to cover .deps/ in addition to .in-toto, fixing backports that previously broke when lockfiles were involved.

Changes:

  • Extend port-commit conflict auto-resolution and post-cherry-pick reset behavior to include .deps/ alongside .in-toto.
  • Update/expand port-commit tests to cover .deps/ conflict handling and non-interactive confirmation skipping (CI/backport workflow path).
  • Replace the tibdex/backport GitHub Action with a workflow loop that runs ddev --no-interactive release port-commit per backport/<base> label.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
ddev/tests/cli/release/test_port_commit.py Updates tests for generated-file preservation, .deps/ conflict resolution, and non-interactive confirmation behavior.
ddev/src/ddev/cli/release/port_commit.py Updates command help text to include .deps/ preservation.
ddev/src/ddev/cli/release/port_commit_workflow.py Generalizes “reset to target” handling to include .deps/ and refactors confirmation prompting for interactive vs CI runs.
ddev/changelog.d/24470.added Documents the new .deps/ reset behavior in release port-commit.
.github/workflows/backport-pr.yml Replaces tibdex/backport with a ddev release port-commit loop keyed off backport/<base> labels.
.github/chainguard/self.backport.pull-request-target.sts.yaml Updates trust-policy documentation to reflect the new workflow and permissions needs.
Comments suppressed due to low confidence (1)

.github/workflows/backport-pr.yml:24

  • The workflow-level if condition uses contains(github.event.label.name, 'backport'), which will also run this job for unrelated labels that merely include the substring (e.g. no-backport). Since the script already expects backport/<base>, tighten the condition to startsWith(..., 'backport/') to avoid unnecessary privileged runs.
    if: >
      github.event.pull_request.merged
      && (
        github.event.action == 'closed'
        || (
          github.event.action == 'labeled'
          && contains(github.event.label.name, 'backport')
        )
      )

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/backport-pr.yml Outdated
Comment thread .github/workflows/backport-pr.yml Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3ef6c2bdea

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/backport-pr.yml Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread .github/workflows/backport-pr.yml Outdated
Comment thread .github/workflows/backport-pr.yml Outdated

@AAraKKe AAraKKe left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks @Kyle-Neale! Small couple of comments, the biggest one is the god script in the workflow injected into the yaml file.

Comment thread ddev/src/ddev/cli/release/port_commit_workflow.py Outdated
Comment thread ddev/src/ddev/cli/release/port_commit_workflow.py
Comment thread .github/workflows/backport-pr.yml Outdated
Comment thread .github/workflows/backport-pr.yml Outdated
Kyle-Neale and others added 9 commits July 16, 2026 16:48
Replace the tibdex/backport action with a ddev-driven backport that
cherry-picks the merged commit per backport/<base> label and resets
per-branch regenerated files (.in-toto and now .deps/) to the target
branch, so dependency lockfiles don't carry over from the source branch.

- Generalize port-commit's .in-toto handling to a path list covering .deps/.
- Guard the interactive confirm prompts with app.interactive so the tool
  runs unattended in CI.
- Rework backport-pr.yml to loop the backport/* labels and call
  ddev --no-interactive release port-commit per base.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Match `.deps/` with startswith so nested paths (e.g. vendor/foo.deps/) are not
  treated as regenerated; `.in-toto` stays a substring match for its *.in-toto.link files.
- Extract `confirm_or_abort` so the interactive confirmation guard lives in one place
  instead of being duplicated at both prompt sites.
- Rename the preserve-step tests to `generated_files` and parametrize the in-toto/deps reset case.
We already have the merge commit SHA from the triggering event; passing it
directly avoids resolving PR-<n> back through the GitHub API to the same
commit, and drops the dependency on the API's lazily-computed merge_commit_sha.
The backport job's branch push, PR creation, and PR comments all authenticate
with the scoped octo-sts token, so the ambient GITHUB_TOKEN no longer needs
contents/pull-requests write; drop it to read to shrink blast radius under
pull_request_target.

Gate the labeled-event run on startsWith('backport/') instead of
contains('backport') so unrelated labels that merely include the substring
(e.g. no-backport) don't spin up the privileged job.
A backport/<base> label pointing at a branch that does not exist on origin made
the per-base git fetch fail under set -e, aborting the whole step so no other
backport/* label was processed. Guard the fetch: comment, mark the run failed,
and continue to the next base.

When port-commit succeeds but the new PR is not yet listed, gh pr list --jq
'.[0].url' printed the literal 'null', which is non-empty and produced an
'opened: null' comment. Default the jq expression to an empty string so the
comment is skipped instead.
Compress the multi-line inline comments in backport-pr.yml to single lines per
the repo's one-line-comment convention. No behavioral change.
Collapse the three near-identical gh pr comment call sites into a single
comment_pr helper, centralizing the best-effort (|| true) semantics in one
place. No behavioral change.
The open-PR pre-check only detects an OPEN backport PR, so a branch left by a
run that failed before opening the PR (or whose PR was later closed) is not
auto-cleaned and port-commit's push is rejected non-fast-forward. Document the
limitation at the pre-check and, in the failure comment, tell the operator to
delete the stale branch and retry. Manual cleanup is the accepted remedy.
@Kyle-Neale
Kyle-Neale force-pushed the kyle.neale/backport-via-port-commit branch from 3d8949d to 714d920 Compare July 17, 2026 13:09
Move all backport label parsing, per-base looping, idempotency, and error
aggregation into ddev release port-commit --from-pr, backed by unit tests.
Slim backport-pr.yml to a should_run gate job plus a gated backport job, and
use ddev config override in place of the repo-pointing config set calls.
@Kyle-Neale
Kyle-Neale force-pushed the kyle.neale/backport-via-port-commit branch from 714d920 to 8cf1f79 Compare July 17, 2026 13:25
Carry the shared CLI knobs (branch prefix/suffix, labels, no-pr, draft,
verify, dry-run) in a frozen PortOptions instead of threading them through
build_port_plan, resolve_port_plan, and run_backport_from_pr as a repeated
seven-parameter tail.

Replace the stringly-typed per-base result tuple with a BackportStatus
StrEnum and a BackportResult dataclass, so the overall pass/fail check is an
enum comparison rather than a string match. Extract the per-base loop into
_port_to_each_base, collapse target_branch plus its explicit flag into a
single override_base, and drop run_backport_from_pr's token check in favour
of a message override on _resolve_pr.

Add a summary-panel test covering the mixed ported/skipped/failed case and
register the not-found PR mock explicitly.
…nt typing

require_github_user names the get-or-abort contract accurately whether the
returned user is used or discarded.

Document that the existing-backport-PR check filters on head=owner:branch and
therefore relies on the branch being pushed to origin, as PushStep does; a
fork-based push flow would silently stop matching.

Mirror the real client's Literal['open','closed','all'] on the fake's
list_pull_requests state param so test call sites get the same type feedback.
… as planned

An explicit --branch-suffix is shared across every base derived from --from-pr, so all bases resolve to the same head branch. After the first opens a PR, the rest are silently skipped as already-ported. Reject the combination unless --target-branch pins a single base.

Dry-run ports recorded BackportStatus.PORTED even though nothing was pushed, so the summary implied work happened. Add a PLANNED status used only under --dry-run.
…-via-port-commit

# Conflicts:
#	ddev/tests/cli/release/test_port_commit.py
@Kyle-Neale
Kyle-Neale requested a review from AAraKKe August 11, 2026 18:53
@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 11, 2026

Copy link
Copy Markdown

evalya-impact-summary

evalya impact analysis
Impact analysis: RUN-ALL — every test task will run
Trigger:         empty diff (default branch, scheduled run, or shallow-clone fallback)
Test tasks:      0 (all selected)
Publish tasks:   1 (always emitted)
Diff:            empty (no diff information)

Learn more about CI impact filtering

Comment thread .github/workflows/backport-pr.yml
Under pull_request_target the default checkout ref is the PR's base branch.
A PR merged into an older release branch would install a local ddev lacking
--from-pr. Pinning ref: master decouples the ddev version from the target
branch; port-commit still fetches origin/<base> per target for the cherry-pick.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dd-octo-sts

dd-octo-sts Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Validation Report

All 21 validations passed.

Show details
Validation Description Status
agent-reqs Verify check versions match the Agent requirements file
ci Validate CI configuration and code coverage settings
codeowners Validate every integration has a CODEOWNERS entry
config Validate default configuration files against spec.yaml
dep Verify dependency pins are consistent and Agent-compatible
http Validate integrations use the HTTP wrapper correctly
imports Validate check imports do not use deprecated modules
integration-style Validate check code style conventions
jmx-metrics Validate JMX metrics definition files and config
labeler Validate PR labeler config matches integration directories
legacy-signature Validate no integration uses the legacy Agent check signature
license-headers Validate Python files have proper license headers
licenses Validate third-party license attribution list
metadata Validate metadata.csv metric definitions
models Validate configuration data models match spec.yaml
openmetrics Validate OpenMetrics integrations disable the metric limit
package Validate Python package metadata and naming
qa-label Validate the pull request declares whether it needs QA for the next Agent release
readmes Validate README files have required sections
saved-views Validate saved view JSON file structure and fields
version Validate version consistency between package and changelog

View full run

@Kyle-Neale
Kyle-Neale enabled auto-merge August 13, 2026 15:05
@Kyle-Neale
Kyle-Neale added this pull request to the merge queue Aug 13, 2026
Merged via the queue into master with commit 6fd380c Aug 13, 2026
385 checks passed
@Kyle-Neale
Kyle-Neale deleted the kyle.neale/backport-via-port-commit branch August 13, 2026 18:09
@dd-octo-sts dd-octo-sts Bot added this to the 7.83.0 milestone Aug 13, 2026
github-actions Bot pushed a commit that referenced this pull request Aug 13, 2026
* Consolidate backport workflow onto ddev release port-commit

Replace the tibdex/backport action with a ddev-driven backport that
cherry-picks the merged commit per backport/<base> label and resets
per-branch regenerated files (.in-toto and now .deps/) to the target
branch, so dependency lockfiles don't carry over from the source branch.

- Generalize port-commit's .in-toto handling to a path list covering .deps/.
- Guard the interactive confirm prompts with app.interactive so the tool
  runs unattended in CI.
- Rework backport-pr.yml to loop the backport/* labels and call
  ddev --no-interactive release port-commit per base.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Add changelog entry

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Anchor .deps/ match to repo root and extract port-commit confirm helper

- Match `.deps/` with startswith so nested paths (e.g. vendor/foo.deps/) are not
  treated as regenerated; `.in-toto` stays a substring match for its *.in-toto.link files.
- Extract `confirm_or_abort` so the interactive confirmation guard lives in one place
  instead of being duplicated at both prompt sites.
- Rename the preserve-step tests to `generated_files` and parametrize the in-toto/deps reset case.

* Pass merge SHA directly to port-commit in backport workflow

We already have the merge commit SHA from the triggering event; passing it
directly avoids resolving PR-<n> back through the GitHub API to the same
commit, and drops the dependency on the API's lazily-computed merge_commit_sha.

* Minimize ambient token scope and tighten backport label gate

The backport job's branch push, PR creation, and PR comments all authenticate
with the scoped octo-sts token, so the ambient GITHUB_TOKEN no longer needs
contents/pull-requests write; drop it to read to shrink blast radius under
pull_request_target.

Gate the labeled-event run on startsWith('backport/') instead of
contains('backport') so unrelated labels that merely include the substring
(e.g. no-backport) don't spin up the privileged job.

* Guard per-base fetch and empty PR-URL default in backport workflow

A backport/<base> label pointing at a branch that does not exist on origin made
the per-base git fetch fail under set -e, aborting the whole step so no other
backport/* label was processed. Guard the fetch: comment, mark the run failed,
and continue to the next base.

When port-commit succeeds but the new PR is not yet listed, gh pr list --jq
'.[0].url' printed the literal 'null', which is non-empty and produced an
'opened: null' comment. Default the jq expression to an empty string so the
comment is skipped instead.

* Condense backport workflow comments to one line each

Compress the multi-line inline comments in backport-pr.yml to single lines per
the repo's one-line-comment convention. No behavioral change.

* Extract comment_pr helper in backport workflow

Collapse the three near-identical gh pr comment call sites into a single
comment_pr helper, centralizing the best-effort (|| true) semantics in one
place. No behavioral change.

* Document stale backport branch cleanup in workflow

The open-PR pre-check only detects an OPEN backport PR, so a branch left by a
run that failed before opening the PR (or whose PR was later closed) is not
auto-cleaned and port-commit's push is rejected non-fast-forward. Document the
limitation at the pre-check and, in the failure comment, tell the operator to
delete the stale branch and retry. Manual cleanup is the accepted remedy.

* Redesign backport automation around port-commit --from-pr

Move all backport label parsing, per-base looping, idempotency, and error
aggregation into ddev release port-commit --from-pr, backed by unit tests.
Slim backport-pr.yml to a should_run gate job plus a gated backport job, and
use ddev config override in place of the repo-pointing config set calls.

* Group port-commit options and type the backport results

Carry the shared CLI knobs (branch prefix/suffix, labels, no-pr, draft,
verify, dry-run) in a frozen PortOptions instead of threading them through
build_port_plan, resolve_port_plan, and run_backport_from_pr as a repeated
seven-parameter tail.

Replace the stringly-typed per-base result tuple with a BackportStatus
StrEnum and a BackportResult dataclass, so the overall pass/fail check is an
enum comparison rather than a string match. Extract the per-base loop into
_port_to_each_base, collapse target_branch plus its explicit flag into a
single override_base, and drop run_backport_from_pr's token check in favour
of a message override on _resolve_pr.

Add a summary-panel test covering the mixed ported/skipped/failed case and
register the not-found PR mock explicitly.

* Rename check_github_user to require_github_user and tighten fake client typing

require_github_user names the get-or-abort contract accurately whether the
returned user is used or discarded.

Document that the existing-backport-PR check filters on head=owner:branch and
therefore relies on the branch being pushed to origin, as PushStep does; a
fork-based push flow would silently stop matching.

Mirror the real client's Literal['open','closed','all'] on the fake's
list_pull_requests state param so test call sites get the same type feedback.

* Reject --branch-suffix in multi-base --from-pr and mark dry-run ports as planned

An explicit --branch-suffix is shared across every base derived from --from-pr, so all bases resolve to the same head branch. After the first opens a PR, the rest are silently skipped as already-ported. Reject the combination unless --target-branch pins a single base.

Dry-run ports recorded BackportStatus.PORTED even though nothing was pushed, so the summary implied work happened. Add a PLANNED status used only under --dry-run.

* Pin backport workflow checkout to master so ddev has --from-pr

Under pull_request_target the default checkout ref is the PR's base branch.
A PR merged into an older release branch would install a local ddev lacking
--from-pr. Pinning ref: master decouples the ddev version from the target
branch; port-commit still fetches origin/<base> per target for the cherry-pick.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> 6fd380c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants