forked from wso2/identity-apps
-
Notifications
You must be signed in to change notification settings - Fork 0
370 lines (322 loc) · 14 KB
/
sync-prs-to-next.yml
File metadata and controls
370 lines (322 loc) · 14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# This workflow will sync PRs from the master branch to the next branch.
name: 🔄 Sync PRs to next
on:
workflow_run:
workflows: ["💡 PR Merged"]
types: [completed]
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to sync to next branch'
required: true
type: string
permissions:
contents: write
pull-requests: write
env:
BASE_BRANCH: master
TARGET_BRANCH: next
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Skip conditions for PRs (comma-separated arrays)
SKIP_AUTHORS: ""
SKIP_TITLE_PATTERNS: "[Release] [GitHub Action],[skip ci]"
jobs:
sync:
runs-on: ubuntu-latest
if: >
github.repository == 'wso2/identity-apps' &&
(
(github.event_name == 'workflow_run' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success') ||
github.event_name == 'workflow_dispatch'
)
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: 📥 Download PR Number Artifact (for workflow_run)
if: github.event_name == 'workflow_run'
uses: actions/download-artifact@v4
with:
name: pr-number
github-token: ${{ env.GH_TOKEN }}
repository: ${{ github.repository }}
run-id: ${{ github.event.workflow_run.id }}
- name: 🔍 Debug Artifact Contents
if: github.event_name == 'workflow_run'
run: |
echo "=== Current working directory ==="
pwd
echo "=== Contents of current directory ==="
ls -la
echo "=== Looking for pr-number directory ==="
find . -name "pr-number*" -type d
echo "=== Contents of pr-number directory (if exists) ==="
if [ -d "pr-number" ]; then
ls -la pr-number/
echo "=== File contents in pr-number directory ==="
find pr-number/ -type f -exec sh -c 'echo "=== {} ==="; cat "{}"' \;
else
echo "pr-number directory not found"
fi
echo "=== Looking for any PR_NUMBER files ==="
find . -name "*PR_NUMBER*" -o -name "*pr-number*" -o -name "*pr_number*"
- name: Prepare PR_NUMBER file
if: github.event_name == 'workflow_run'
run: |
# Enhanced file extraction with multiple fallback methods
PR_FILE=""
# Method 1: Check common artifact locations
if [ -f "pr-number/PR_NUMBER" ]; then
PR_FILE="pr-number/PR_NUMBER"
echo "Found PR_NUMBER at: pr-number/PR_NUMBER"
elif [ -f "pr-number/pr-number" ]; then
PR_FILE="pr-number/pr-number"
echo "Found pr-number at: pr-number/pr-number"
elif [ -f "PR_NUMBER" ]; then
PR_FILE="PR_NUMBER"
echo "Found PR_NUMBER at root"
else
# Method 2: Search for any file containing PR number
echo "Searching for PR number files..."
FOUND_FILES=$(find . -name "*PR_NUMBER*" -o -name "*pr-number*" -o -name "*pr_number*" | head -5)
if [ -n "$FOUND_FILES" ]; then
echo "Found potential PR files:"
echo "$FOUND_FILES"
# Use the first found file
PR_FILE=$(echo "$FOUND_FILES" | head -1)
echo "Using file: $PR_FILE"
else
echo "❌ No PR_NUMBER file found anywhere in the artifact"
echo "Available files and directories:"
find . -type f | head -20
exit 1
fi
fi
# Extract PR number and store it
if [ -n "$PR_FILE" ] && [ -f "$PR_FILE" ]; then
PR_NUMBER=$(cat "$PR_FILE" | tr -d '\n\r' | tr -d ' ')
if [ -n "$PR_NUMBER" ] && [ "$PR_NUMBER" != "null" ]; then
echo "$PR_NUMBER" > ./PR_NUMBER
echo "✅ Successfully extracted PR number: $PR_NUMBER"
echo "PR_NUMBER_EXTRACTED=$PR_NUMBER" >> $GITHUB_ENV
else
echo "❌ PR file found but contains invalid data: '$PR_NUMBER'"
exit 1
fi
else
echo "❌ PR file not accessible: $PR_FILE"
exit 1
fi
- name: Get merged PR information
id: trigger_info
run: |
# Get PR number based on trigger type
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
PR_NUMBER="${{ github.event.inputs.pr_number }}"
echo "Using manual PR number: $PR_NUMBER"
else
# Get the PR number from the artifact (workflow_run trigger)
PR_NUMBER=$(cat ./PR_NUMBER)
echo "PR Number from artifact: $PR_NUMBER"
fi
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
echo "SYNC_MODE=pr" >> $GITHUB_ENV
# Verify PR exists and is merged
PR_STATE=$(gh pr view $PR_NUMBER --json state -q '.state')
if [[ "$PR_STATE" != "MERGED" ]]; then
echo "Error: PR #$PR_NUMBER is not merged (state: $PR_STATE)"
exit 1
fi
# Get PR details to check if we should skip it
PR_TITLE=$(gh pr view $PR_NUMBER --json title -q '.title')
PR_AUTHOR=$(gh pr view $PR_NUMBER --json author -q '.author.login')
# Check skip conditions using environment variables (support arrays)
SKIP_AUTHORS="${{ env.SKIP_AUTHORS }}"
SKIP_TITLE_PATTERNS="${{ env.SKIP_TITLE_PATTERNS }}"
# Convert comma-separated values to arrays
IFS=',' read -ra AUTHORS_ARRAY <<< "$SKIP_AUTHORS"
IFS=',' read -ra TITLE_PATTERNS_ARRAY <<< "$SKIP_TITLE_PATTERNS"
# Check if PR title matches any skip pattern
SKIP_TITLE=false
for pattern in "${TITLE_PATTERNS_ARRAY[@]}"; do
if [[ "$PR_TITLE" == *"$pattern"* ]]; then
SKIP_TITLE=true
break
fi
done
# If we have skip authors configured, check both author and title
# If no skip authors configured, just check title
SHOULD_SKIP=false
if [[ -n "$SKIP_AUTHORS" && "$SKIP_AUTHORS" != "" ]]; then
# Check if PR author should be skipped
SKIP_AUTHOR=false
for author in "${AUTHORS_ARRAY[@]}"; do
if [[ "$PR_AUTHOR" == "$author" ]]; then
SKIP_AUTHOR=true
break
fi
done
# Skip if both author and title conditions are met
if [[ "$SKIP_AUTHOR" == "true" && "$SKIP_TITLE" == "true" ]]; then
SHOULD_SKIP=true
fi
else
# No specific authors to skip, just check title patterns
if [[ "$SKIP_TITLE" == "true" ]]; then
SHOULD_SKIP=true
fi
fi
# Skip PR if conditions are met (but allow override for manual trigger)
if [[ "$SHOULD_SKIP" == "true" && "${{ github.event_name }}" != "workflow_dispatch" ]]; then
echo "Skipping sync for PR #$PR_NUMBER from $PR_AUTHOR with title: $PR_TITLE"
echo "skip_sync=true" >> $GITHUB_OUTPUT
exit 0
elif [[ "$SHOULD_SKIP" == "true" && "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "⚠️ Warning: PR #$PR_NUMBER matches skip conditions but proceeding due to manual trigger"
fi
echo "skip_sync=false" >> $GITHUB_OUTPUT
# Create unique sync branch name for this PR
SYNC_BRANCH="sync-pr-${PR_NUMBER}-to-next"
echo "SYNC_BRANCH=$SYNC_BRANCH" >> $GITHUB_ENV
echo "Sync branch for PR #$PR_NUMBER: $SYNC_BRANCH"
- name: Set up Git
if: steps.trigger_info.outputs.skip_sync != 'true'
run: |
git config user.name "wso2-iam-bot"
git config user.email "wso2-iam-bot@users.noreply.github.com"
- name: Get PR commits
if: steps.trigger_info.outputs.skip_sync != 'true'
run: |
# Get all commits from this specific PR
COMMITS=$(gh pr view $PR_NUMBER --json commits -q '.commits[].oid' | tr '\n' ' ')
echo "COMMITS_TO_SYNC=$COMMITS" >> $GITHUB_ENV
echo "Commits from PR #$PR_NUMBER: $COMMITS"
- name: Create sync branch
if: steps.trigger_info.outputs.skip_sync != 'true'
run: |
# Validate that SYNC_BRANCH is set
if [ -z "$SYNC_BRANCH" ]; then
echo "Error: SYNC_BRANCH is not set"
exit 1
fi
echo "Creating sync branch: $SYNC_BRANCH"
# Fetch latest from target branch
git fetch origin $TARGET_BRANCH
# Create new sync branch from target
git checkout $TARGET_BRANCH
git checkout -b "$SYNC_BRANCH"
- name: Cherry-pick commits
if: steps.trigger_info.outputs.skip_sync != 'true'
run: |
if [ -z "$COMMITS_TO_SYNC" ]; then
echo "No commits to sync."
exit 0
fi
for commit in $COMMITS_TO_SYNC; do
if [ -z "$commit" ]; then
continue
fi
echo "Cherry-picking commit $commit: $(git log -1 --oneline $commit)"
git cherry-pick $commit || {
echo "Cherry-pick failed for $commit. Attempting to skip..."
git cherry-pick --skip
}
done
- name: Create PR to sync to target branch
if: steps.trigger_info.outputs.skip_sync != 'true'
run: |
# Debug: Show current branch and target branch info
echo "=== Branch Information ==="
echo "Current branch: $(git branch --show-current)"
echo "Target branch: ${{ env.TARGET_BRANCH }}"
echo "Sync branch: $SYNC_BRANCH"
# Ensure we're on the sync branch
git checkout "$SYNC_BRANCH" || {
echo "Failed to checkout sync branch: $SYNC_BRANCH"
exit 1
}
# Check if there are any commits to sync
echo "=== Checking for commits to sync ==="
git log --oneline "${{ env.TARGET_BRANCH }}..HEAD" || echo "No commits found"
COMMITS_ON_BRANCH=$(git log "${{ env.TARGET_BRANCH }}..HEAD" --oneline 2>/dev/null || true)
# Count commits more reliably
COMMIT_COUNT=0
if [ -n "$COMMITS_ON_BRANCH" ]; then
COMMIT_COUNT=$(echo "$COMMITS_ON_BRANCH" | wc -l | tr -d ' ')
fi
echo "Commits found: $COMMIT_COUNT"
echo "Commit details:"
echo "$COMMITS_ON_BRANCH"
if [ "$COMMIT_COUNT" -eq 0 ] || [ -z "$COMMITS_ON_BRANCH" ]; then
echo "✅ No commits to sync. The changes from PR #$PR_NUMBER already exist in ${{ env.TARGET_BRANCH }}."
echo "This is normal if the PR was already synced or if the target branch already contains these changes."
exit 0
fi
# Push the sync branch to remote before creating PR
echo "=== Pushing sync branch to remote ==="
git push origin "$SYNC_BRANCH" --force || {
echo "Failed to push sync branch to remote"
exit 1
}
# Check for existing open PR for this sync branch
EXISTING_PR=$(gh pr list \
--base "${{ env.TARGET_BRANCH }}" \
--head "$SYNC_BRANCH" \
--state open \
--json number \
-q '.[0].number')
# Get PR details for the merged PR
PR_TITLE=$(gh pr view $PR_NUMBER --json title -q '.title')
PR_AUTHOR=$(gh pr view $PR_NUMBER --json author -q '.author.login')
TOTAL_COMMITS=$(echo "$COMMITS_ON_BRANCH" | wc -l | tr -d ' ')
SYNC_TITLE="[Sync][${{ env.BASE_BRANCH }} -> ${{ env.TARGET_BRANCH }}][#${PR_NUMBER}]: $PR_TITLE"
PR_BODY="🤖 **Auto-sync from ${{ env.BASE_BRANCH }}**
This PR automatically syncs the changes from #${PR_NUMBER} to the \`${{ env.TARGET_BRANCH }}\` branch.
**Original PR:** https://github.com/${{ github.repository }}/pull/${PR_NUMBER}
**Author:** @${PR_AUTHOR}
**Total commits:** $TOTAL_COMMITS
**Workflow run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
**Commits:**
\`\`\`
$(git log ${{ env.TARGET_BRANCH }}..HEAD --oneline)
\`\`\`"
if [ -n "$EXISTING_PR" ]; then
echo "✅ PR #$EXISTING_PR already exists for sync branch. Updating with new commits."
gh pr edit $EXISTING_PR --title "$SYNC_TITLE" --body "$PR_BODY" || {
echo "⚠️ Failed to update existing PR, but continuing..."
}
echo "Updated existing PR #$EXISTING_PR with $TOTAL_COMMITS total commits"
else
echo "=== Creating new PR ==="
echo "Base: ${{ env.TARGET_BRANCH }}"
echo "Head: $SYNC_BRANCH"
echo "Title: $SYNC_TITLE"
# Verify branch exists on remote
if ! git ls-remote --heads origin "$SYNC_BRANCH" | grep -q "$SYNC_BRANCH"; then
echo "❌ Sync branch $SYNC_BRANCH does not exist on remote"
exit 1
fi
# Create PR with error handling
NEW_PR=$(gh pr create \
--base "${{ env.TARGET_BRANCH }}" \
--head "$SYNC_BRANCH" \
--title "$SYNC_TITLE" \
--body "$PR_BODY" 2>&1) || {
echo "❌ Failed to create PR:"
echo "$NEW_PR"
# Additional debugging info
echo "=== Additional Debug Info ==="
echo "Available branches:"
git branch -a | grep -E "(next|sync-pr-.*-to-next)" || echo "No matching branches found"
echo "Remote branches:"
git ls-remote --heads origin | grep -E "(next|sync-pr-.*-to-next)" || echo "No matching remote branches"
echo "Commit comparison:"
git log --oneline "${{ env.TARGET_BRANCH }}..HEAD" | head -5 || echo "No commits to show"
exit 1
}
echo "✅ Created new PR: $NEW_PR"
fi