mirror of
https://github.com/goauthentik/authentik
synced 2026-04-27 18:07:15 +02:00
267 lines
10 KiB
YAML
267 lines
10 KiB
YAML
name: "Cherry-picker"
|
|
description: "Cherry-pick PRs based on their labels"
|
|
|
|
inputs:
|
|
token:
|
|
description: "GitHub Token"
|
|
required: true
|
|
git_user:
|
|
description: "Git user for pushing the cherry-pick PR"
|
|
required: true
|
|
git_user_email:
|
|
description: "Git user email for pushing the cherry-pick PR"
|
|
required: true
|
|
|
|
runs:
|
|
using: "composite"
|
|
steps:
|
|
- name: Check if workflow should run
|
|
id: should_run
|
|
shell: bash
|
|
env:
|
|
GITHUB_TOKEN: ${{ inputs.token }}
|
|
run: |
|
|
set -e -o pipefail
|
|
# For issues events, check if it's actually a PR
|
|
if [ "${{ github.event_name }}" = "issues" ]; then
|
|
# Check if this issue is actually a PR
|
|
PR_DATA=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.issue.number }} 2>/dev/null || echo "null")
|
|
if [ "$PR_DATA" = "null" ]; then
|
|
echo "should_run=false" >> $GITHUB_OUTPUT
|
|
echo "reason=not_a_pr" >> $GITHUB_OUTPUT
|
|
echo "This is an issue, not a PR. Skipping."
|
|
exit 0
|
|
fi
|
|
|
|
# Get PR data
|
|
PR_MERGED=$(echo "$PR_DATA" | jq -r '.merged')
|
|
PR_NUMBER="${{ github.event.issue.number }}"
|
|
MERGE_COMMIT_SHA=$(echo "$PR_DATA" | jq -r '.merge_commit_sha')
|
|
|
|
# Check if it's a backport label
|
|
LABEL_NAME="${{ github.event.label.name }}"
|
|
if [[ "$LABEL_NAME" =~ ^backport/(.+)$ ]]; then
|
|
if [ "$PR_MERGED" = "true" ]; then
|
|
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
echo "reason=label_added_to_merged_pr" >> $GITHUB_OUTPUT
|
|
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
|
|
echo "merge_commit_sha=$MERGE_COMMIT_SHA" >> $GITHUB_OUTPUT
|
|
exit 0
|
|
else
|
|
echo "should_run=false" >> $GITHUB_OUTPUT
|
|
echo "reason=label_added_to_open_pr" >> $GITHUB_OUTPUT
|
|
echo "Backport label added to open PR. Will run after PR is merged."
|
|
exit 0
|
|
fi
|
|
else
|
|
echo "should_run=false" >> $GITHUB_OUTPUT
|
|
echo "reason=non_backport_label" >> $GITHUB_OUTPUT
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
# For pull_request and pull_request_target events
|
|
PR_NUMBER="${{ github.event.pull_request.number }}"
|
|
MERGE_COMMIT_SHA="${{ github.event.pull_request.merge_commit_sha }}"
|
|
|
|
# Case 1: PR was just merged (closed + merged = true)
|
|
if [ "${{ github.event.action }}" = "closed" ] && [ "${{ github.event.pull_request.merged }}" = "true" ]; then
|
|
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
echo "reason=pr_merged" >> $GITHUB_OUTPUT
|
|
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
|
|
echo "merge_commit_sha=$MERGE_COMMIT_SHA" >> $GITHUB_OUTPUT
|
|
exit 0
|
|
fi
|
|
|
|
# Case 2: Label was added
|
|
if [ "${{ github.event.action }}" = "labeled" ]; then
|
|
LABEL_NAME="${{ github.event.label.name }}"
|
|
# Check if it's a backport label
|
|
if [[ "$LABEL_NAME" =~ ^backport/(.+)$ ]]; then
|
|
# Check if PR is already merged
|
|
if [ "${{ github.event.pull_request.merged }}" = "true" ]; then
|
|
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
echo "reason=label_added_to_merged_pr" >> $GITHUB_OUTPUT
|
|
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
|
|
echo "merge_commit_sha=$MERGE_COMMIT_SHA" >> $GITHUB_OUTPUT
|
|
exit 0
|
|
else
|
|
echo "should_run=false" >> $GITHUB_OUTPUT
|
|
echo "reason=label_added_to_open_pr" >> $GITHUB_OUTPUT
|
|
echo "Backport label added to open PR. Will run after PR is merged."
|
|
exit 0
|
|
fi
|
|
else
|
|
echo "should_run=false" >> $GITHUB_OUTPUT
|
|
echo "reason=non_backport_label" >> $GITHUB_OUTPUT
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
echo "should_run=false" >> $GITHUB_OUTPUT
|
|
echo "reason=unknown" >> $GITHUB_OUTPUT
|
|
- name: Configure Git
|
|
if: steps.should_run.outputs.should_run == 'true'
|
|
shell: bash
|
|
env:
|
|
user: ${{ inputs.git_user }}
|
|
email: ${{ inputs.git_user_email }}
|
|
run: |
|
|
git config --global user.name "${user}"
|
|
git config --global user.email "${email}"
|
|
- name: Get PR details and extract backport labels
|
|
if: steps.should_run.outputs.should_run == 'true'
|
|
id: pr_details
|
|
shell: bash
|
|
env:
|
|
GITHUB_TOKEN: ${{ inputs.token }}
|
|
PR_NUMBER: ${{ steps.should_run.outputs.pr_number }}
|
|
REASON: ${{ steps.should_run.outputs.reason }}
|
|
run: |
|
|
set -e -o pipefail
|
|
|
|
# Determine which labels to process
|
|
if [ "${REASON}" = "label_added_to_merged_pr" ]; then
|
|
# Only process the specific label that was just added
|
|
if [ "${{ github.event_name }}" = "issues" ]; then
|
|
LABEL_NAME="${{ github.event.label.name }}"
|
|
else
|
|
LABEL_NAME="${{ github.event.label.name }}"
|
|
fi
|
|
|
|
if [[ "$LABEL_NAME" =~ ^backport/(.+)$ ]]; then
|
|
echo "labels=$LABEL_NAME" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "Label $LABEL_NAME does not match backport pattern"
|
|
echo "labels=" >> $GITHUB_OUTPUT
|
|
fi
|
|
else
|
|
# PR was just merged, process all backport labels
|
|
LABELS=$(gh pr view $PR_NUMBER --json labels --jq '.labels[].name' | grep '^backport/' | tr '\n' ' ' || true)
|
|
echo "labels=$LABELS" >> $GITHUB_OUTPUT
|
|
fi
|
|
- name: Cherry-pick to target branches
|
|
if: steps.should_run.outputs.should_run == 'true' && steps.pr_details.outputs.labels != ''
|
|
shell: bash
|
|
env:
|
|
GITHUB_TOKEN: ${{ inputs.token }}
|
|
PR_NUMBER: '${{ steps.should_run.outputs.pr_number }}'
|
|
COMMIT_SHA: '${{ steps.should_run.outputs.merge_commit_sha }}'
|
|
PR_TITLE: ${{ github.event.pull_request.title }}
|
|
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
|
|
LABELS: '${{ steps.pr_details.outputs.labels }}'
|
|
run: |
|
|
set -e -o pipefail
|
|
|
|
echo "Processing PR #$PR_NUMBER (reason: ${{ steps.should_run.outputs.reason }})"
|
|
echo "Found backport labels: $LABELS"
|
|
|
|
# Process each backport label
|
|
for label in $LABELS; do
|
|
if [[ "$label" =~ ^backport/(.+)$ ]]; then
|
|
TARGET_BRANCH="${BASH_REMATCH[1]}"
|
|
echo "Processing backport to branch: $TARGET_BRANCH"
|
|
|
|
# Check if target branch exists
|
|
if ! git ls-remote --heads origin "$TARGET_BRANCH" | grep -q "$TARGET_BRANCH"; then
|
|
echo "❌ Target branch $TARGET_BRANCH does not exist, skipping"
|
|
|
|
# Comment on the original PR about the missing branch
|
|
gh pr comment $PR_NUMBER --body "⚠️ Cannot backport to \`$TARGET_BRANCH\`: branch does not exist."
|
|
continue
|
|
fi
|
|
|
|
# Create a unique branch name for the cherry-pick
|
|
CHERRY_PICK_BRANCH="cherry-pick/${PR_NUMBER}-to-${TARGET_BRANCH}"
|
|
|
|
# Check if a cherry-pick PR already exists
|
|
EXISTING_PR=$(gh pr list --head "$CHERRY_PICK_BRANCH" --json number --jq '.[0].number' 2>/dev/null || echo "")
|
|
if [ -n "$EXISTING_PR" ]; then
|
|
echo "⚠️ Cherry-pick PR already exists: #$EXISTING_PR"
|
|
gh pr comment $PR_NUMBER --body "Cherry-pick to \`$TARGET_BRANCH\` already exists: #$EXISTING_PR"
|
|
continue
|
|
fi
|
|
|
|
# Fetch and checkout target branch
|
|
git fetch origin "$TARGET_BRANCH"
|
|
git checkout -b "$CHERRY_PICK_BRANCH" "origin/$TARGET_BRANCH"
|
|
|
|
# Attempt cherry-pick
|
|
if git cherry-pick "$COMMIT_SHA"; then
|
|
echo "✅ Cherry-pick successful for $TARGET_BRANCH"
|
|
|
|
# Push the cherry-pick branch
|
|
git push origin "$CHERRY_PICK_BRANCH"
|
|
|
|
# Create PR for the cherry-pick
|
|
CHERRY_PICK_TITLE="$PR_TITLE (cherry-pick #$PR_NUMBER to $TARGET_BRANCH)"
|
|
CHERRY_PICK_BODY="Cherry-pick of #$PR_NUMBER to \`$TARGET_BRANCH\` branch.
|
|
|
|
**Original PR:** #$PR_NUMBER
|
|
**Original Author:** @$PR_AUTHOR
|
|
**Cherry-picked commit:** $COMMIT_SHA"
|
|
|
|
NEW_PR=$(gh pr create \
|
|
--title "$CHERRY_PICK_TITLE" \
|
|
--body "$CHERRY_PICK_BODY" \
|
|
--base "$TARGET_BRANCH" \
|
|
--head "$CHERRY_PICK_BRANCH" \
|
|
--label "cherry-pick")
|
|
|
|
# Assign the PR to the original author
|
|
gh pr edit "$NEW_PR" --add-assignee "$PR_AUTHOR" || true
|
|
|
|
echo "✅ Created cherry-pick PR $NEW_PR for $TARGET_BRANCH"
|
|
|
|
# Comment on original PR
|
|
gh pr comment $PR_NUMBER --body "🍒 Cherry-pick to \`$TARGET_BRANCH\` created: $NEW_PR"
|
|
|
|
else
|
|
echo "⚠️ Cherry-pick failed for $TARGET_BRANCH, creating conflict resolution PR"
|
|
|
|
# Add conflicted files and commit
|
|
git add .
|
|
git commit -m "Cherry-pick #$PR_NUMBER to $TARGET_BRANCH (with conflicts)
|
|
|
|
This cherry-pick has conflicts that need manual resolution.
|
|
|
|
Original PR: #$PR_NUMBER
|
|
Original commit: $COMMIT_SHA"
|
|
|
|
# Push the branch with conflicts
|
|
git push origin "$CHERRY_PICK_BRANCH"
|
|
|
|
# Create PR with conflict notice
|
|
CONFLICT_TITLE="$PR_TITLE (cherry-pick #$PR_NUMBER to $TARGET_BRANCH)"
|
|
CONFLICT_BODY="⚠️ **This cherry-pick has conflicts that require manual resolution.**
|
|
|
|
Cherry-pick of #$PR_NUMBER to \`$TARGET_BRANCH\` branch.
|
|
|
|
**Original PR:** #$PR_NUMBER
|
|
**Original Author:** @$PR_AUTHOR
|
|
**Cherry-picked commit:** $COMMIT_SHA
|
|
|
|
**Please resolve the conflicts in this PR before merging.**"
|
|
|
|
NEW_PR=$(gh pr create \
|
|
--title "$CONFLICT_TITLE" \
|
|
--body "$CONFLICT_BODY" \
|
|
--base "$TARGET_BRANCH" \
|
|
--head "$CHERRY_PICK_BRANCH" \
|
|
--label "cherry-pick")
|
|
|
|
# Assign the PR to the original author
|
|
gh pr edit "$NEW_PR" --add-assignee "$PR_AUTHOR" || true
|
|
|
|
echo "⚠️ Created conflict resolution PR $NEW_PR for $TARGET_BRANCH"
|
|
|
|
# Comment on original PR
|
|
gh pr comment $PR_NUMBER --body "⚠️ Cherry-pick to \`$TARGET_BRANCH\` has conflicts: $NEW_PR"
|
|
fi
|
|
|
|
# Clean up - go back to main branch
|
|
git checkout main
|
|
git branch -D "$CHERRY_PICK_BRANCH" 2>/dev/null || true
|
|
fi
|
|
done
|