Skip to content

Commit c4d9186

Browse files
sutaakaropenshift-merge-bot[bot]
authored andcommitted
Synchronize changes from main to stable branch
1 parent 025ee15 commit c4d9186

File tree

2 files changed

+394
-0
lines changed

2 files changed

+394
-0
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# This workflow handles "/approve" comments on PRs with "lake-gate" label
2+
# It performs a fast-forward merge of the stable branch to point to the same commit as the temporary branch
3+
#
4+
# This workflow uses the built-in GITHUB_TOKEN with the required permissions set below.
5+
6+
name: Approve Lake Gate PR
7+
8+
on:
9+
issue_comment:
10+
types: [created]
11+
12+
permissions:
13+
contents: write
14+
pull-requests: write
15+
16+
jobs:
17+
approve-lake-gate:
18+
runs-on: ubuntu-latest
19+
if: github.event.issue.pull_request && contains(github.event.comment.body, '/approve') && contains(github.event.issue.labels.*.name, 'lake-gate') && github.event.comment.author_association == 'OWNER'
20+
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v4
24+
with:
25+
fetch-depth: 0
26+
token: ${{ secrets.GITHUB_TOKEN }}
27+
28+
- name: Configure Git
29+
run: |
30+
git config --global user.name "github-actions[bot]"
31+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
32+
33+
- name: Get PR details and perform fast-forward merge
34+
run: |
35+
set -euo pipefail
36+
PR_NUMBER="${{ github.event.issue.number }}"
37+
38+
# Get PR details
39+
PR_DATA=$(gh pr view "$PR_NUMBER" --json headRefName,baseRefName)
40+
HEAD_BRANCH=$(echo "$PR_DATA" | jq -r '.headRefName')
41+
BASE_BRANCH=$(echo "$PR_DATA" | jq -r '.baseRefName')
42+
43+
echo "PR #$PR_NUMBER details:"
44+
echo " Head branch: $HEAD_BRANCH"
45+
echo " Base branch: $BASE_BRANCH"
46+
47+
# Ensure we're working with the stable branch as base
48+
if [ "$BASE_BRANCH" != "stable" ]; then
49+
echo "Error: PR base branch is not 'stable'. Expected 'stable', got '$BASE_BRANCH'"
50+
exit 1
51+
fi
52+
53+
# Fetch all refs
54+
git fetch origin
55+
56+
# Switch to and update stable branch
57+
git switch stable
58+
git reset --hard origin/stable
59+
60+
# Switch to the temporary branch from the PR
61+
git switch "$HEAD_BRANCH"
62+
git reset --hard origin/"$HEAD_BRANCH"
63+
64+
# Get the commit that the temporary branch points to
65+
TEMP_BRANCH_COMMIT=$(git rev-parse HEAD)
66+
echo "Temporary branch commit: $TEMP_BRANCH_COMMIT"
67+
68+
# Switch back to stable and perform fast-forward merge
69+
git switch stable
70+
71+
# Check if we can fast-forward merge
72+
if git merge-base --is-ancestor stable "$TEMP_BRANCH_COMMIT"; then
73+
echo "Performing fast-forward merge of stable to $TEMP_BRANCH_COMMIT"
74+
git reset --hard "$TEMP_BRANCH_COMMIT"
75+
76+
# Push the updated stable branch
77+
git push origin stable
78+
79+
echo "✅ Successfully fast-forwarded stable branch to commit $TEMP_BRANCH_COMMIT"
80+
81+
# Wait a moment for GitHub to process the push
82+
sleep 2
83+
84+
# Check PR status and close if still open
85+
PR_STATE=$(gh pr view "$PR_NUMBER" --json state --jq '.state')
86+
if [ "$PR_STATE" = "OPEN" ]; then
87+
echo "PR is still open, closing it manually..."
88+
gh pr close "$PR_NUMBER" --comment "✅ Approved and merged! The stable branch has been fast-forwarded to point to the same commit as this temporary branch."
89+
else
90+
echo "PR was automatically closed by GitHub (state: $PR_STATE)"
91+
# Add a comment to the already-closed PR
92+
gh pr comment "$PR_NUMBER" --body "✅ Approved and merged! The stable branch has been fast-forwarded to point to the same commit as this temporary branch."
93+
fi
94+
95+
# Clean up the temporary branch after some delay
96+
sleep 5 # Brief pause to ensure PR operations complete
97+
echo "Cleaning up temporary branch: $HEAD_BRANCH"
98+
99+
# Guard: Only delete branches that match the expected lake-gate pattern
100+
if [[ "$HEAD_BRANCH" =~ ^lake-gate- ]]; then
101+
echo "Branch matches lake-gate pattern, proceeding with deletion..."
102+
git push origin --delete "$HEAD_BRANCH" || {
103+
echo "Warning: Failed to delete branch $HEAD_BRANCH (it may have already been deleted)"
104+
}
105+
else
106+
echo "Warning: Branch '$HEAD_BRANCH' does not match expected lake-gate pattern (lake-gate-*). Skipping deletion to prevent accidental removal of non-lake-gate branches."
107+
fi
108+
109+
else
110+
echo "Error: Cannot fast-forward merge. The stable branch is not an ancestor of the temporary branch commit."
111+
gh pr comment "$PR_NUMBER" --body "❌ Cannot approve: Fast-forward merge is not possible. The stable branch is not an ancestor of the temporary branch. Please rebase or recreate the PR."
112+
exit 1
113+
fi
114+
env:
115+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
116+
117+
- name: Summary
118+
run: |
119+
echo "✅ Lake-gate PR approved and merged successfully via fast-forward merge."
Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
# This workflow automatically creates a temporary branch from main to sync with stable branch, for image related changes creates a PR with "lake-gate" label for verification
2+
# It runs every 4 hours and can be triggered manually
3+
#
4+
# This workflow uses the built-in GITHUB_TOKEN with the required permissions set below.
5+
6+
name: Sync Main to Stable
7+
8+
on:
9+
schedule:
10+
# Run every 4 hours
11+
- cron: '0 */4 * * *'
12+
workflow_dispatch:
13+
14+
permissions:
15+
contents: write
16+
pull-requests: write
17+
18+
# Configuration: PR Reviewers
19+
# To modify who gets requested to review sync PRs, update the list below with comma-separated or space-separated GitHub usernames
20+
env:
21+
PR_REVIEWERS: "sutaakar"
22+
23+
jobs:
24+
lake-gate:
25+
runs-on: ubuntu-latest
26+
27+
steps:
28+
- name: Checkout repository
29+
uses: actions/checkout@v4
30+
with:
31+
fetch-depth: 0
32+
token: ${{ secrets.GITHUB_TOKEN }}
33+
34+
- name: Configure Git
35+
run: |
36+
git config --global user.name "github-actions[bot]"
37+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
38+
39+
- name: Check for differences between main and stable
40+
id: check-diff
41+
run: |
42+
set -euo pipefail
43+
# Ensure we have the latest refs
44+
git fetch origin main
45+
git fetch origin stable || {
46+
echo "Error: stable branch doesn't exist. Please create the stable branch first."
47+
exit 1
48+
}
49+
50+
# Update local refs to match remote
51+
git checkout main
52+
git reset --hard origin/main
53+
git checkout -B stable origin/stable
54+
55+
# Get commits that are in main but not in stable
56+
NEW_COMMITS=$(git rev-list stable..main --reverse)
57+
58+
if [ -z "$NEW_COMMITS" ]; then
59+
echo "No new commits to cherry-pick"
60+
echo "new_commits=" >> $GITHUB_OUTPUT
61+
echo "runtime_changes=false" >> $GITHUB_OUTPUT
62+
else
63+
echo "Found new commits to cherry-pick:"
64+
echo "$NEW_COMMITS"
65+
# Store commits as a single line with spaces
66+
COMMITS_LINE=$(echo "$NEW_COMMITS" | tr '\n' ' ' | sed 's/ $//')
67+
echo "new_commits=$COMMITS_LINE" >> $GITHUB_OUTPUT
68+
69+
# Get the latest commit hash for PR title
70+
LATEST_COMMIT=$(echo "$NEW_COMMITS" | tail -n1)
71+
LATEST_COMMIT_SHORT=$(git rev-parse --short "$LATEST_COMMIT")
72+
LATEST_COMMIT_MSG=$(git log --format=%s -n 1 "$LATEST_COMMIT")
73+
echo "latest_commit=$LATEST_COMMIT" >> $GITHUB_OUTPUT
74+
echo "latest_commit_short=$LATEST_COMMIT_SHORT" >> $GITHUB_OUTPUT
75+
echo "latest_commit_msg=$LATEST_COMMIT_MSG" >> $GITHUB_OUTPUT
76+
77+
# Check if any commits contain changes to runtime images
78+
RUNTIME_CHANGES=false
79+
for commit in $NEW_COMMITS; do
80+
if git diff-tree --no-commit-id --name-only -r "$commit" | grep -q "^images/runtime/"; then
81+
RUNTIME_CHANGES=true
82+
break
83+
fi
84+
done
85+
echo "runtime_changes=$RUNTIME_CHANGES" >> $GITHUB_OUTPUT
86+
echo "Runtime changes detected: $RUNTIME_CHANGES"
87+
fi
88+
89+
- name: Fast-forward stable branch
90+
id: fast-forward-stable
91+
if: steps.check-diff.outputs.new_commits != '' && steps.check-diff.outputs.runtime_changes == 'false'
92+
run: |
93+
set -euo pipefail
94+
echo "No runtime changes detected. Fast-forwarding stable branch directly."
95+
96+
# Get the latest commit from main
97+
LATEST_COMMIT="${{ steps.check-diff.outputs.latest_commit }}"
98+
LATEST_COMMIT_SHORT="${{ steps.check-diff.outputs.latest_commit_short }}"
99+
COMMIT_COUNT=$(echo "${{ steps.check-diff.outputs.new_commits }}" | wc -w)
100+
101+
echo "Fast-forwarding stable branch to $LATEST_COMMIT_SHORT"
102+
echo "Total commits being synced: $COMMIT_COUNT"
103+
104+
# Update stable branch to point to the same commit as main
105+
git checkout stable
106+
git reset --hard origin/main
107+
git push origin stable
108+
109+
echo "✅ Successfully fast-forwarded stable branch to $LATEST_COMMIT_SHORT"
110+
echo "fast_forward_completed=true" >> $GITHUB_OUTPUT
111+
112+
- name: Check for existing sync PRs
113+
id: check-existing-pr
114+
if: steps.check-diff.outputs.new_commits != '' && steps.check-diff.outputs.runtime_changes == 'true'
115+
run: |
116+
set -euo pipefail
117+
# Look for existing PRs with the lake-gate label
118+
EXISTING_PR_DATA=$(gh pr list --base stable --label "lake-gate" --state open --json number,headRefName,title | jq -r '.[0] // empty')
119+
120+
if [ -n "$EXISTING_PR_DATA" ] && [ "$EXISTING_PR_DATA" != "null" ]; then
121+
EXISTING_PR_NUMBER=$(echo "$EXISTING_PR_DATA" | jq -r '.number')
122+
EXISTING_PR_BRANCH=$(echo "$EXISTING_PR_DATA" | jq -r '.headRefName')
123+
echo "Found existing PR: #$EXISTING_PR_NUMBER (branch: $EXISTING_PR_BRANCH)"
124+
echo "existing_pr_number=$EXISTING_PR_NUMBER" >> $GITHUB_OUTPUT
125+
echo "existing_pr_branch=$EXISTING_PR_BRANCH" >> $GITHUB_OUTPUT
126+
127+
# Check if the existing PR already contains the latest commit
128+
PR_TITLE=$(echo "$EXISTING_PR_DATA" | jq -r '.title')
129+
LATEST_COMMIT_SHORT="${{ steps.check-diff.outputs.latest_commit_short }}"
130+
131+
if echo "$PR_TITLE" | grep -q "$LATEST_COMMIT_SHORT"; then
132+
echo "Existing PR already contains the latest commit"
133+
echo "pr_up_to_date=true" >> $GITHUB_OUTPUT
134+
else
135+
echo "Existing PR is outdated"
136+
echo "pr_up_to_date=false" >> $GITHUB_OUTPUT
137+
fi
138+
else
139+
echo "No existing cherry-pick PR found"
140+
echo "existing_pr_number=" >> $GITHUB_OUTPUT
141+
echo "existing_pr_branch=" >> $GITHUB_OUTPUT
142+
echo "pr_up_to_date=false" >> $GITHUB_OUTPUT
143+
fi
144+
env:
145+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
146+
147+
- name: Close outdated PR and delete branch
148+
if: steps.check-diff.outputs.new_commits != '' && steps.check-diff.outputs.runtime_changes == 'true' && steps.check-existing-pr.outputs.existing_pr_number != '' && steps.check-existing-pr.outputs.pr_up_to_date == 'false'
149+
run: |
150+
set -euo pipefail
151+
PR_NUMBER="${{ steps.check-existing-pr.outputs.existing_pr_number }}"
152+
BRANCH_NAME="${{ steps.check-existing-pr.outputs.existing_pr_branch }}"
153+
154+
# Safety check: Verify the branch matches automation pattern before closing/deleting
155+
if [[ "$BRANCH_NAME" =~ ^lake-gate- ]]; then
156+
echo "Branch matches automation pattern (lake-gate-*), proceeding with closure and deletion..."
157+
echo "Closing outdated PR #$PR_NUMBER (branch: $BRANCH_NAME)"
158+
gh pr close "$PR_NUMBER" --comment "Closing this PR as newer commits are available. A new PR will be created automatically."
159+
160+
sleep 5 # Brief pause to ensure PR operations complete
161+
162+
# Delete the temporary branch
163+
if [ -n "$BRANCH_NAME" ]; then
164+
echo "Deleting temporary branch: $BRANCH_NAME"
165+
git push origin --delete "$BRANCH_NAME" || {
166+
echo "Warning: Failed to delete branch $BRANCH_NAME (it may have already been deleted)"
167+
}
168+
else
169+
echo "Warning: No branch name found for PR #$PR_NUMBER"
170+
fi
171+
else
172+
echo "Warning: Branch '$BRANCH_NAME' does not match expected automation pattern (lake-gate-*). Skipping closure and deletion to prevent impacting user branches."
173+
echo "PR #$PR_NUMBER will remain open. Manual intervention may be required."
174+
fi
175+
env:
176+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
177+
178+
- name: Create sync branch and PR
179+
if: steps.check-diff.outputs.new_commits != '' && steps.check-diff.outputs.runtime_changes == 'true' && steps.check-existing-pr.outputs.pr_up_to_date == 'false'
180+
run: |
181+
set -euo pipefail
182+
# Create a unique branch name with timestamp
183+
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
184+
BRANCH_NAME="lake-gate-$TIMESTAMP"
185+
186+
echo "Creating branch: $BRANCH_NAME from main"
187+
git checkout main
188+
git checkout -b "$BRANCH_NAME"
189+
190+
# Push the branch
191+
git push origin "$BRANCH_NAME"
192+
193+
# Prepare PR body
194+
COMMITS="${{ steps.check-diff.outputs.new_commits }}"
195+
LATEST_COMMIT="${{ steps.check-diff.outputs.latest_commit }}"
196+
LATEST_COMMIT_SHORT="${{ steps.check-diff.outputs.latest_commit_short }}"
197+
COMMIT_COUNT=$(echo "$COMMITS" | wc -w)
198+
RUNTIME_CHANGES="${{ steps.check-diff.outputs.runtime_changes }}"
199+
200+
# Build PR body using here document
201+
PR_BODY=$(cat << EOF
202+
## Automated Sync from main to stable
203+
204+
This PR automatically syncs the \`main\` branch to the \`stable\` branch by creating a temporary branch directly from main.
205+
206+
**Latest commit:** $LATEST_COMMIT_SHORT - ${{ steps.check-diff.outputs.latest_commit_msg }}
207+
**Total commits to sync:** $COMMIT_COUNT
208+
209+
## ⚠️ IMPORTANT: How to Merge
210+
211+
**🚫 DO NOT use the GitHub merge button!**
212+
213+
Once all checks are complete, comment **\`/approve\`** on this PR to automatically fast-forward merge the stable branch to point to the same commit as this temporary branch.
214+
215+
**Only use the \`/approve\` command - the GitHub merge button will not work correctly for this automated sync process.**
216+
217+
## Pre-merge Checklist
218+
219+
Before approving this PR, please ensure the following tasks are completed:
220+
221+
- [ ] **PR checks**: PR checks passed
222+
EOF
223+
)
224+
225+
# Add integration test requirement if runtime images changed
226+
if [ "$RUNTIME_CHANGES" = true ]; then
227+
PR_BODY="$PR_BODY"$'\n'"- [ ] **Integration Tests**: Run Jenkins integration tests on CUDA or ROCm OCP cluster (runtime image changes detected)"
228+
fi
229+
230+
PR_BODY="$PR_BODY"$'\n\n'"### Commits to be synced:"
231+
232+
for commit in $COMMITS; do
233+
COMMIT_SHORT=$(git rev-parse --short "$commit")
234+
COMMIT_MSG=$(git log --format=%s -n 1 "$commit")
235+
PR_BODY="$PR_BODY"$'\n'"- $COMMIT_SHORT: $COMMIT_MSG"
236+
done
237+
238+
PR_BODY="$PR_BODY"$'\n\n'"---"$'\n'"*This PR was created automatically by the sync workflow.*"
239+
240+
# Create the PR
241+
PR_TITLE="Auto sync main to stable (up to $LATEST_COMMIT_SHORT)"
242+
243+
# Normalize PR_REVIEWERS by replacing commas with spaces and create reviewer flags
244+
REVIEWER_FLAGS=""
245+
NORMALIZED_REVIEWERS=$(echo "$PR_REVIEWERS" | tr ',' ' ')
246+
for reviewer in $NORMALIZED_REVIEWERS; do
247+
if [ -n "$reviewer" ]; then
248+
REVIEWER_FLAGS="$REVIEWER_FLAGS --reviewer $reviewer"
249+
fi
250+
done
251+
252+
gh pr create \
253+
--title "$PR_TITLE" \
254+
--body "$PR_BODY" \
255+
--base stable \
256+
--head "$BRANCH_NAME" \
257+
--label "lake-gate" \
258+
$REVIEWER_FLAGS \
259+
--draft
260+
261+
echo "Created PR: $PR_TITLE"
262+
env:
263+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
264+
265+
- name: Summary
266+
run: |
267+
if [ -z "${{ steps.check-diff.outputs.new_commits }}" ]; then
268+
echo "✅ No new commits to sync. Stable branch is up to date."
269+
elif [ "${{ steps.fast-forward-stable.outputs.fast_forward_completed }}" == "true" ]; then
270+
echo "✅ Fast-forward completed. Stable branch updated directly (no runtime changes detected)."
271+
elif [ "${{ steps.check-existing-pr.outputs.pr_up_to_date }}" == "true" ]; then
272+
echo "✅ Existing PR already contains the latest commits. No action needed."
273+
else
274+
echo "✅ Sync process completed. New PR created or existing PR updated (runtime changes detected)."
275+
fi

0 commit comments

Comments
 (0)