Skip to content

Commit 2d70c03

Browse files
committed
[ci] post alpha branch sync
1 parent e22d2dc commit 2d70c03

File tree

2 files changed

+398
-0
lines changed

2 files changed

+398
-0
lines changed

.github/workflows/on-pr-merge.yml

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

0 commit comments

Comments
 (0)