Add Github workflow to automatically create uplift PRs#792
Add Github workflow to automatically create uplift PRs#792jonathanmendez wants to merge 22 commits intomozilla:enterprise-mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an “Auto Uplift” GitHub Actions workflow intended to automatically create uplift PRs to enterprise-beta and/or enterprise-release when PRs are merged into enterprise-main and carry uplift labels.
Changes:
- Introduces
.github/workflows/uplift.ymltriggered on merged PRs toenterprise-main. - Detects
uplift-to-beta/uplift-to-releaselabels and cherry-picks merged changes onto the corresponding branch. - Opens uplift PRs via
peter-evans/create-pull-request@v6with a generated commit summary.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| PARENTS=$(git rev-list --parents -n 1 $SHA) | ||
| COUNT=$(echo $PARENTS | wc -w) | ||
|
|
||
| APPLIED=0 | ||
|
|
||
| if [ "$COUNT" -eq 3 ]; then | ||
| echo "Merge commit → multi-commit mode" | ||
|
|
||
| COMMITS=$(git log --reverse --no-merges --pretty=format:"%H" $SHA^1..$SHA^2) | ||
|
|
||
| for commit in $COMMITS; do | ||
| SHORT=$(git rev-parse --short $commit) | ||
| MSG=$(git log -1 --pretty=format:"%s" $commit) | ||
| LINK="$REPO_URL/commit/$commit" | ||
|
|
||
| if git branch -r --contains $commit | grep -q "origin/$TARGET"; then | ||
| echo "- [$SHORT]($LINK) $MSG (already in branch)" >> $SUMMARY_FILE | ||
| continue | ||
| fi | ||
|
|
||
| set +e | ||
| git cherry-pick -x -X theirs $commit | ||
| STATUS=$? | ||
| set -e | ||
|
|
||
| if [ $STATUS -ne 0 ]; then | ||
| # Check if it's an empty cherry-pick | ||
| if git diff --cached --quiet && git diff --quiet; then | ||
| echo "Empty cherry-pick for $commit → skipping" | ||
|
|
||
| git cherry-pick --skip | ||
|
|
||
| echo "- [$SHORT]($LINK) $MSG (already applied)" >> $SUMMARY_FILE | ||
| continue | ||
| fi | ||
|
|
||
| git add -A | ||
| git commit -m "Cherry-pick $commit with conflicts" | ||
| echo "- [$SHORT]($LINK) $MSG (⚠️ conflict)" >> $SUMMARY_FILE | ||
| else | ||
| echo "- [$SHORT]($LINK) $MSG" >> $SUMMARY_FILE | ||
| fi | ||
|
|
||
| APPLIED=1 | ||
| done | ||
|
|
||
| else | ||
| echo "Single commit mode" | ||
|
|
||
| SHORT=$(git rev-parse --short $SHA) | ||
| MSG=$(git log -1 --pretty=format:"%s" $SHA) | ||
| LINK="$REPO_URL/commit/$SHA" | ||
|
|
||
| set +e | ||
| git cherry-pick -x -X theirs $SHA | ||
| STATUS=$? |
There was a problem hiding this comment.
The script assumes that any non-merge merge_commit_sha implies a single-commit uplift, but for GitHub’s “rebase and merge” (and sometimes other non-merge merge strategies), the PR may have multiple commits and merge_commit_sha will only reference the last one. In that case this workflow would uplift only one commit and silently miss the rest. Consider deriving the commit list from the PR (e.g., via gh pr view --json commits / GitHub API) and cherry-picking all PR commits (or the single squash commit when applicable) rather than branching on parent count of merge_commit_sha.
There was a problem hiding this comment.
@lissyx I wonder if we should disallow the 'rebase and merge' strategy (for general reasons, not just for this). AFAIK we don't use it and wouldn't want to use it?
There was a problem hiding this comment.
rebase and merge is mostly what i always do manually :'( :'(
There was a problem hiding this comment.
Well I'm only talking about the PR completion action, not any manual rebasing/merging. And I haven't put a lot of thought into "we shouldn't use the rebase-and-merge PR completion", I just know that we've previously said among ourselves to use merge if our commit history is good or squash if not, so I thought we'd implicitly ruled it out.
There was a problem hiding this comment.
I haven't found a way to detect when the merge was done with squash vs rebase-and-merge. If we think it makes sense to remove rebase-and-merge as a PR merge strategy, then this workflow can work as-is. Otherwise I'll just have to leave a warning comment or something to go manually check if the original PR was merged via rebase-and-merge and tell the reviewers to abandon the created uplift PR and do it manually.
| env: | ||
| MERGE_SHA: ${{ github.event.pull_request.merge_commit_sha }} | ||
| PR_NUMBER: ${{ github.event.pull_request.number }} | ||
| PR_TITLE: ${{ github.event.pull_request.title }} | ||
| REPO_URL: https://github.com/${{ github.repository }} |
There was a problem hiding this comment.
I am not sure it is worth duplicating those
| cat << 'EOF' > uplift.sh | ||
| set -e | ||
|
|
||
| TARGET=$1 | ||
| SHA=$2 | ||
|
|
||
| BRANCH="uplift-${TARGET}-${SHA}" | ||
| SUMMARY_FILE=summary.txt | ||
|
|
||
| echo "---- Uplifting to $TARGET ----" | ||
|
|
||
| git fetch origin $TARGET | ||
|
|
||
| # Skip entire operation if merge commit already in branch | ||
| if git branch -r --contains $SHA | grep -q "origin/$TARGET"; then | ||
| echo "Already fully present in $TARGET" | ||
| echo "summary=Already present, nothing to uplift." >> $GITHUB_OUTPUT | ||
| echo "branch=" >> $GITHUB_OUTPUT | ||
| exit 0 | ||
| fi | ||
|
|
||
| # Avoid duplicate branch | ||
| if git ls-remote --heads origin $BRANCH | grep -q $BRANCH; then | ||
| echo "Branch already exists, skipping" | ||
| echo "summary=Uplift branch already exists." >> $GITHUB_OUTPUT | ||
| echo "branch=" >> $GITHUB_OUTPUT | ||
| exit 0 | ||
| fi | ||
|
|
||
| git checkout -b $BRANCH origin/$TARGET | ||
|
|
||
| touch $SUMMARY_FILE | ||
|
|
||
| PARENTS=$(git rev-list --parents -n 1 $SHA) | ||
| COUNT=$(echo $PARENTS | wc -w) | ||
|
|
||
| APPLIED=0 | ||
|
|
||
| if [ "$COUNT" -eq 3 ]; then | ||
| echo "Merge commit → multi-commit mode" | ||
|
|
||
| COMMITS=$(git log --reverse --no-merges --pretty=format:"%H" $SHA^1..$SHA^2) | ||
|
|
||
| for commit in $COMMITS; do | ||
| SHORT=$(git rev-parse --short $commit) | ||
| MSG=$(git log -1 --pretty=format:"%s" $commit) | ||
| LINK="$REPO_URL/commit/$commit" | ||
|
|
||
| if git branch -r --contains $commit | grep -q "origin/$TARGET"; then | ||
| echo "- [$SHORT]($LINK) $MSG (already in branch)" >> $SUMMARY_FILE | ||
| continue | ||
| fi | ||
|
|
||
| set +e | ||
| git cherry-pick -x $commit | ||
| STATUS=$? | ||
| set -e | ||
|
|
||
| if [ $STATUS -ne 0 ]; then | ||
| # Check if it's an empty cherry-pick | ||
| if git diff --cached --quiet && git diff --quiet; then | ||
| echo "Empty cherry-pick for $commit → skipping" | ||
|
|
||
| git cherry-pick --skip | ||
|
|
||
| echo "- [$SHORT]($LINK) $MSG (already applied)" >> $SUMMARY_FILE | ||
| continue | ||
| fi | ||
|
|
||
| git add -A | ||
| git cherry-pick --continue | ||
| echo "- [$SHORT]($LINK) $MSG (⚠️ conflict)" >> $SUMMARY_FILE | ||
| else | ||
| echo "- [$SHORT]($LINK) $MSG" >> $SUMMARY_FILE | ||
| fi | ||
|
|
||
| APPLIED=1 | ||
| done | ||
|
|
||
| else | ||
| echo "Single commit mode" | ||
|
|
||
| SHORT=$(git rev-parse --short $SHA) | ||
| MSG=$(git log -1 --pretty=format:"%s" $SHA) | ||
| LINK="$REPO_URL/commit/$SHA" | ||
|
|
||
| set +e | ||
| git cherry-pick -x $SHA | ||
| STATUS=$? | ||
| set -e | ||
|
|
||
| if [ $STATUS -ne 0 ]; then | ||
| git add -A | ||
| git cherry-pick --continue | ||
| echo "- [$SHORT]($LINK) $MSG (⚠️ conflict)" >> $SUMMARY_FILE | ||
| else | ||
| echo "- [$SHORT]($LINK) $MSG" >> $SUMMARY_FILE | ||
| fi | ||
|
|
||
| APPLIED=1 | ||
| fi | ||
|
|
||
| if [ "$APPLIED" -eq 0 ]; then | ||
| echo "No new commits applied" | ||
| echo "summary=All commits already exist in $TARGET." >> $GITHUB_OUTPUT | ||
| echo "branch=" >> $GITHUB_OUTPUT | ||
| exit 0 | ||
| fi | ||
|
|
||
| git push origin $BRANCH | ||
|
|
||
| echo "branch=$BRANCH" >> $GITHUB_OUTPUT | ||
|
|
||
| DELIM="GITHUB_OUTPUT_$(uuidgen)" | ||
| echo "summary<<$DELIM" >> $GITHUB_OUTPUT | ||
| cat $SUMMARY_FILE >> $GITHUB_OUTPUT | ||
| echo "$DELIM" >> $GITHUB_OUTPUT |
There was a problem hiding this comment.
This should be a file in the repo, and not on the action, would make it easier to review as well
There was a problem hiding this comment.
I intentionally avoided making a script because it is generally seen as a security vulnerability when using on: pull_request_target that executes with privilege. The idea of the security vulnerability is that while the existing/committed version of the workflow will be what runs (even if the PR contains changes to it), having the workflow call a script could in theory run a (maliciously) modified version of the script in the PR.
It may be enough mitigation that I am only running this code when the PR is closed and merged, but I guess I'll let the github admins weigh in on that.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
…icts Co-authored-by: Copilot <copilot@github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # | ||
| # Crucially, no external code is loaded or run as part of this workflow. | ||
| # | ||
| # [0] https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_target:~:text=Warning-,Running,websitehttps://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_target:~:text=Warning-,Running,website |
There was a problem hiding this comment.
The reference link in this comment looks malformed (it contains websitehttps://...). This makes the warning harder to follow; please replace it with the correct GitHub Docs URL (the same one referenced in the text).
| # [0] https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_target:~:text=Warning-,Running,websitehttps://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_target:~:text=Warning-,Running,website | |
| # [0] https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_target |
Description
Bugzilla: Bug-TODO
Adds a workflow that:
uplift-to-betaoruplift-to-releaseare present in the PR and if the PR's target branch is one we would uplift from (enterprise-mainfor beta or release, andenterprise-betafor release)enterprise-beta/enterprise-releasebranch(es) and creates uplift PR(s)Testing
TODO??