-
Notifications
You must be signed in to change notification settings - Fork 86
272 lines (224 loc) · 11.3 KB
/
Copy pathsync-main-to-stable.yml
File metadata and controls
272 lines (224 loc) · 11.3 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
# 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
# It runs every 4 hours and can be triggered manually
#
# This workflow uses the built-in GITHUB_TOKEN with the required permissions set below.
name: Sync Main to Stable
on:
schedule:
# Run every 4 hours
- cron: '0 */4 * * *'
workflow_dispatch:
permissions:
contents: write
pull-requests: write
# Configuration: PR Reviewers
# To modify who gets requested to review sync PRs, update the list below with comma-separated or space-separated GitHub usernames
env:
PR_REVIEWERS: "sutaakar"
jobs:
lake-gate:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Configure Git
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: Check for differences between main and stable
id: check-diff
run: |
set -euo pipefail
# Ensure we have the latest refs
git fetch origin main
git fetch origin stable || {
echo "Error: stable branch doesn't exist. Please create the stable branch first."
exit 1
}
# Update local refs to match remote
git checkout main
git reset --hard origin/main
git checkout -B stable origin/stable
# Get commits that are in main but not in stable
NEW_COMMITS=$(git rev-list stable..main --reverse)
if [ -z "$NEW_COMMITS" ]; then
echo "No new commits to cherry-pick"
echo "new_commits=" >> $GITHUB_OUTPUT
echo "runtime_changes=false" >> $GITHUB_OUTPUT
else
echo "Found new commits to cherry-pick:"
echo "$NEW_COMMITS"
# Store commits as a single line with spaces
COMMITS_LINE=$(echo "$NEW_COMMITS" | tr '\n' ' ' | sed 's/ $//')
echo "new_commits=$COMMITS_LINE" >> $GITHUB_OUTPUT
# Get the latest commit hash for PR title
LATEST_COMMIT=$(echo "$NEW_COMMITS" | tail -n1)
LATEST_COMMIT_SHORT=$(git rev-parse --short "$LATEST_COMMIT")
LATEST_COMMIT_MSG=$(git log --format=%s -n 1 "$LATEST_COMMIT")
echo "latest_commit=$LATEST_COMMIT" >> $GITHUB_OUTPUT
echo "latest_commit_short=$LATEST_COMMIT_SHORT" >> $GITHUB_OUTPUT
echo "latest_commit_msg=$LATEST_COMMIT_MSG" >> $GITHUB_OUTPUT
# Check if any commits contain changes to runtime images
RUNTIME_CHANGES=false
for commit in $NEW_COMMITS; do
if git diff-tree --no-commit-id --name-only -r "$commit" | grep -q "^images/runtime/"; then
RUNTIME_CHANGES=true
break
fi
done
echo "runtime_changes=$RUNTIME_CHANGES" >> $GITHUB_OUTPUT
echo "Runtime changes detected: $RUNTIME_CHANGES"
fi
- name: Fast-forward stable branch
id: fast-forward-stable
if: steps.check-diff.outputs.new_commits != '' && steps.check-diff.outputs.runtime_changes == 'false'
run: |
set -euo pipefail
echo "No runtime changes detected. Fast-forwarding stable branch directly."
# Get the latest commit from main
LATEST_COMMIT="${{ steps.check-diff.outputs.latest_commit }}"
LATEST_COMMIT_SHORT="${{ steps.check-diff.outputs.latest_commit_short }}"
COMMIT_COUNT=$(echo "${{ steps.check-diff.outputs.new_commits }}" | wc -w)
echo "Fast-forwarding stable branch to $LATEST_COMMIT_SHORT"
echo "Total commits being synced: $COMMIT_COUNT"
# Update stable branch to point to the same commit as main
git checkout stable
git reset --hard origin/main
git push origin stable
echo "✅ Successfully fast-forwarded stable branch to $LATEST_COMMIT_SHORT"
echo "fast_forward_completed=true" >> $GITHUB_OUTPUT
- name: Check for existing sync PRs
id: check-existing-pr
if: steps.check-diff.outputs.new_commits != '' && steps.check-diff.outputs.runtime_changes == 'true'
run: |
set -euo pipefail
# Look for existing PRs with the lake-gate label
EXISTING_PR_DATA=$(gh pr list --base stable --label "lake-gate" --state open --json number,headRefName,title | jq -r '.[0] // empty')
if [ -n "$EXISTING_PR_DATA" ] && [ "$EXISTING_PR_DATA" != "null" ]; then
EXISTING_PR_NUMBER=$(echo "$EXISTING_PR_DATA" | jq -r '.number')
EXISTING_PR_BRANCH=$(echo "$EXISTING_PR_DATA" | jq -r '.headRefName')
echo "Found existing PR: #$EXISTING_PR_NUMBER (branch: $EXISTING_PR_BRANCH)"
echo "existing_pr_number=$EXISTING_PR_NUMBER" >> $GITHUB_OUTPUT
echo "existing_pr_branch=$EXISTING_PR_BRANCH" >> $GITHUB_OUTPUT
# Check if the existing PR already contains the latest commit
PR_TITLE=$(echo "$EXISTING_PR_DATA" | jq -r '.title')
LATEST_COMMIT_SHORT="${{ steps.check-diff.outputs.latest_commit_short }}"
if echo "$PR_TITLE" | grep -q "$LATEST_COMMIT_SHORT"; then
echo "Existing PR already contains the latest commit"
echo "pr_up_to_date=true" >> $GITHUB_OUTPUT
else
echo "Existing PR is outdated"
echo "pr_up_to_date=false" >> $GITHUB_OUTPUT
fi
else
echo "No existing cherry-pick PR found"
echo "existing_pr_number=" >> $GITHUB_OUTPUT
echo "existing_pr_branch=" >> $GITHUB_OUTPUT
echo "pr_up_to_date=false" >> $GITHUB_OUTPUT
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Close outdated PR and delete branch
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'
run: |
set -euo pipefail
PR_NUMBER="${{ steps.check-existing-pr.outputs.existing_pr_number }}"
BRANCH_NAME="${{ steps.check-existing-pr.outputs.existing_pr_branch }}"
# Safety check: Verify the branch matches automation pattern before closing/deleting
if [[ "$BRANCH_NAME" =~ ^lake-gate- ]]; then
echo "Branch matches automation pattern (lake-gate-*), proceeding with closure and deletion..."
echo "Closing outdated PR #$PR_NUMBER (branch: $BRANCH_NAME)"
gh pr close "$PR_NUMBER" --comment "Closing this PR as newer commits are available. A new PR will be created automatically."
sleep 5 # Brief pause to ensure PR operations complete
# Delete the temporary branch
if [ -n "$BRANCH_NAME" ]; then
echo "Deleting temporary branch: $BRANCH_NAME"
git push origin --delete "$BRANCH_NAME" || {
echo "Warning: Failed to delete branch $BRANCH_NAME (it may have already been deleted)"
}
else
echo "Warning: No branch name found for PR #$PR_NUMBER"
fi
else
echo "Warning: Branch '$BRANCH_NAME' does not match expected automation pattern (lake-gate-*). Skipping closure and deletion to prevent impacting user branches."
echo "PR #$PR_NUMBER will remain open. Manual intervention may be required."
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create sync branch and PR
if: steps.check-diff.outputs.new_commits != '' && steps.check-diff.outputs.runtime_changes == 'true' && steps.check-existing-pr.outputs.pr_up_to_date == 'false'
run: |
set -euo pipefail
# Create a unique branch name with timestamp
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
BRANCH_NAME="lake-gate-$TIMESTAMP"
echo "Creating branch: $BRANCH_NAME from main"
git checkout main
git checkout -b "$BRANCH_NAME"
# Push the branch
git push origin "$BRANCH_NAME"
# Prepare PR body
COMMITS="${{ steps.check-diff.outputs.new_commits }}"
LATEST_COMMIT="${{ steps.check-diff.outputs.latest_commit }}"
LATEST_COMMIT_SHORT="${{ steps.check-diff.outputs.latest_commit_short }}"
COMMIT_COUNT=$(echo "$COMMITS" | wc -w)
RUNTIME_CHANGES="${{ steps.check-diff.outputs.runtime_changes }}"
# Build PR body using here document
PR_BODY=$(cat << EOF
## Automated Sync from main to stable
This PR automatically syncs the \`main\` branch to the \`stable\` branch by creating a temporary branch directly from main.
**Latest commit:** $LATEST_COMMIT_SHORT - ${{ steps.check-diff.outputs.latest_commit_msg }}
**Total commits to sync:** $COMMIT_COUNT
## Merging
**🚫 DO NOT use the GitHub merge button!**
Mergify will automatically approve and fast-forward merge this PR into the \`stable\` branch once all Konflux checks pass.
## Pre-merge Checklist
Before this PR is merged, please ensure the following tasks are completed:
- [ ] **PR checks**: All Konflux checks passed
EOF
)
# Add integration test requirement if runtime images changed
if [ "$RUNTIME_CHANGES" = true ]; then
PR_BODY="$PR_BODY"$'\n'"- [ ] **Integration Tests**: Run Jenkins integration tests on CUDA or ROCm OCP cluster (runtime image changes detected)"
fi
PR_BODY="$PR_BODY"$'\n\n'"### Commits to be synced:"
for commit in $COMMITS; do
COMMIT_SHORT=$(git rev-parse --short "$commit")
COMMIT_MSG=$(git log --format=%s -n 1 "$commit")
PR_BODY="$PR_BODY"$'\n'"- $COMMIT_SHORT: $COMMIT_MSG"
done
PR_BODY="$PR_BODY"$'\n\n'"---"$'\n'"*This PR was created automatically by the sync workflow.*"
# Create the PR
PR_TITLE="Auto sync main to stable (up to $LATEST_COMMIT_SHORT)"
# Normalize PR_REVIEWERS by replacing commas with spaces and create reviewer flags
REVIEWER_FLAGS=""
NORMALIZED_REVIEWERS=$(echo "$PR_REVIEWERS" | tr ',' ' ')
for reviewer in $NORMALIZED_REVIEWERS; do
if [ -n "$reviewer" ]; then
REVIEWER_FLAGS="$REVIEWER_FLAGS --reviewer $reviewer"
fi
done
gh pr create \
--title "$PR_TITLE" \
--body "$PR_BODY" \
--base stable \
--head "$BRANCH_NAME" \
--label "lake-gate" \
$REVIEWER_FLAGS
echo "Created PR: $PR_TITLE"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Summary
run: |
if [ -z "${{ steps.check-diff.outputs.new_commits }}" ]; then
echo "✅ No new commits to sync. Stable branch is up to date."
elif [ "${{ steps.fast-forward-stable.outputs.fast_forward_completed }}" == "true" ]; then
echo "✅ Fast-forward completed. Stable branch updated directly (no runtime changes detected)."
elif [ "${{ steps.check-existing-pr.outputs.pr_up_to_date }}" == "true" ]; then
echo "✅ Existing PR already contains the latest commits. No action needed."
else
echo "✅ Sync process completed. New PR created or existing PR updated (runtime changes detected)."
fi