-
Notifications
You must be signed in to change notification settings - Fork 13
453 lines (378 loc) · 18.9 KB
/
auto-update-native-sdks.yml
File metadata and controls
453 lines (378 loc) · 18.9 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
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
name: Auto-update Native SDKs
on:
schedule:
# Check for updates daily at 9 AM UTC
- cron: '0 9 * * *'
workflow_dispatch:
inputs:
ios_version:
description: 'Specific iOS SDK version to update to (optional)'
required: false
android_version:
description: 'Specific Android SDK version to update to (optional)'
required: false
jobs:
check-updates:
runs-on: ubuntu-latest
permissions:
contents: read
actions: read
outputs:
any_updates: ${{ steps.check_releases.outputs.any_updates }}
current_ios: ${{ steps.current_versions.outputs.current_ios }}
current_android: ${{ steps.current_versions.outputs.current_android }}
latest_ios: ${{ steps.check_releases.outputs.latest_ios }}
latest_android: ${{ steps.check_releases.outputs.latest_android }}
ios_needs_update: ${{ steps.check_releases.outputs.ios_needs_update }}
android_needs_update: ${{ steps.check_releases.outputs.android_needs_update }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js for API calls
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Verify GitHub permissions
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "🔍 Verifying GitHub API permissions..."
# Test reading current repo
echo "Testing current repo access..."
gh api repos/${{ github.repository }} --jq '.name' || {
echo "❌ Cannot access current repository"
exit 1
}
# Test reading external public releases
echo "Testing external repo access..."
gh api repos/customerio/customerio-ios/releases/latest --jq '.tag_name' || {
echo "⚠️ Cannot access customerio-ios releases - will use fallback"
}
gh api repos/customerio/customerio-android/releases/latest --jq '.tag_name' || {
echo "⚠️ Cannot access customerio-android releases - will use fallback"
}
# Test PR creation permissions (dry run)
echo "Testing PR creation permissions..."
gh api repos/${{ github.repository }}/pulls --method GET --jq 'length' || {
echo "❌ Cannot access PR endpoint"
exit 1
}
echo "✅ GitHub permissions verified successfully"
- name: Get current SDK versions
id: current_versions
run: |
# Get current iOS version from pubspec.yaml
current_ios=$(grep 'native_sdk_version:' pubspec.yaml | sed 's/.*native_sdk_version: *//')
echo "current_ios=$current_ios" >> $GITHUB_OUTPUT
# Get current Android version from build.gradle
current_android=$(grep 'def cioVersion = ' android/build.gradle | sed 's/.*def cioVersion = "\(.*\)"/\1/')
echo "current_android=$current_android" >> $GITHUB_OUTPUT
echo "📋 Current versions:"
echo "iOS: $current_ios"
echo "Android: $current_android"
- name: Check for latest SDK releases
id: check_releases
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "🔍 Checking for latest SDK releases..."
# Function to get latest release using gh CLI
get_latest_release() {
local repo=$1
gh api "repos/$repo/releases/latest" --jq '.tag_name' 2>/dev/null | sed 's/^v//' || echo ""
}
CURRENT_IOS="${{ steps.current_versions.outputs.current_ios }}"
CURRENT_ANDROID="${{ steps.current_versions.outputs.current_android }}"
INPUT_IOS="${{ github.event.inputs.ios_version }}"
INPUT_ANDROID="${{ github.event.inputs.android_version }}"
# Get latest versions
LATEST_IOS="${INPUT_IOS:-$(get_latest_release 'customerio/customerio-ios')}"
LATEST_ANDROID="${INPUT_ANDROID:-$(get_latest_release 'customerio/customerio-android')}"
# Check if updates needed
IOS_NEEDS_UPDATE="false"
ANDROID_NEEDS_UPDATE="false"
if [[ -n "$LATEST_IOS" && "$LATEST_IOS" != "$CURRENT_IOS" ]]; then
IOS_NEEDS_UPDATE="true"
fi
if [[ -n "$LATEST_ANDROID" && "$LATEST_ANDROID" != "$CURRENT_ANDROID" ]]; then
ANDROID_NEEDS_UPDATE="true"
fi
# Set outputs
echo "latest_ios=${LATEST_IOS:-$CURRENT_IOS}" >> $GITHUB_OUTPUT
echo "latest_android=${LATEST_ANDROID:-$CURRENT_ANDROID}" >> $GITHUB_OUTPUT
echo "ios_needs_update=$IOS_NEEDS_UPDATE" >> $GITHUB_OUTPUT
echo "android_needs_update=$ANDROID_NEEDS_UPDATE" >> $GITHUB_OUTPUT
echo "any_updates=$([ "$IOS_NEEDS_UPDATE" = "true" ] || [ "$ANDROID_NEEDS_UPDATE" = "true" ] && echo "true" || echo "false")" >> $GITHUB_OUTPUT
echo "🔍 Release check results:"
echo "iOS: $CURRENT_IOS → ${LATEST_IOS:-$CURRENT_IOS} (needs update: $IOS_NEEDS_UPDATE)"
echo "Android: $CURRENT_ANDROID → ${LATEST_ANDROID:-$CURRENT_ANDROID} (needs update: $ANDROID_NEEDS_UPDATE)"
- name: Show check results
run: |
if [[ "${{ steps.check_releases.outputs.any_updates }}" == "true" ]]; then
echo "✅ Updates found. Proceeding to update job."
else
echo "✅ No updates needed. Current versions are up to date."
fi
update-sdks:
needs: check-updates
if: needs.check-updates.outputs.any_updates == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
actions: read
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Create feature branch
run: |
branch_name="auto-update/native-sdks-$(date +%Y%m%d-%H%M%S)"
echo "branch_name=$branch_name" >> $GITHUB_ENV
git checkout -b "$branch_name"
- name: Update SDK versions
run: |
# Build arguments for version updates
IOS_VERSION=""
ANDROID_VERSION=""
if [[ "${{ needs.check-updates.outputs.ios_needs_update }}" == "true" ]]; then
IOS_VERSION="${{ needs.check-updates.outputs.latest_ios }}"
fi
if [[ "${{ needs.check-updates.outputs.android_needs_update }}" == "true" ]]; then
ANDROID_VERSION="${{ needs.check-updates.outputs.latest_android }}"
fi
# Update iOS version if needed
if [[ -n "$IOS_VERSION" ]]; then
echo "📝 Updating iOS SDK version to $IOS_VERSION"
sed -i "s/native_sdk_version: .*/native_sdk_version: $IOS_VERSION/" pubspec.yaml
echo "✅ iOS version updated"
fi
# Update Android version if needed
if [[ -n "$ANDROID_VERSION" ]]; then
echo "📝 Updating Android SDK version to $ANDROID_VERSION"
sed -i "s/def cioVersion = \".*\"/def cioVersion = \"$ANDROID_VERSION\"/" android/build.gradle
echo "✅ Android version updated"
fi
- name: Setup Flutter and test
uses: ./.github/actions/setup-flutter
- name: Run analysis and tests
run: |
echo "🔍 Running Flutter analysis..."
flutter analyze --no-fatal-infos
echo "🧪 Running Flutter tests..."
flutter test
echo "✅ Analysis and tests completed"
- name: Generate PR content from release notes
id: generate_pr_content
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Function to get release notes using gh CLI
get_release_notes() {
local owner=$1
local repo=$2
local version=$3
# Try with 'v' prefix first, then without
for tag in "v$version" "$version"; do
gh api "repos/$owner/$repo/releases/tags/$tag" 2>/dev/null && return 0
done
return 1
}
# Function to extract key changes from release notes
extract_key_changes() {
local release_body="$1"
echo "$release_body" | jq -r '.body' | grep -E '^[-*]\s+|^#{1,3}\s+|^[0-9]+\.\s+|^(Added|Fixed|Changed|Updated|Improved|Enhanced):' | head -5 || echo ""
}
# Function to generate PR title
generate_title() {
local ios_updated=$1
local android_updated=$2
local ios_version=$3
local android_version=$4
if [[ "$ios_updated" == "true" && "$android_updated" == "true" ]]; then
echo "chore: update Customer.io native SDKs (iOS $ios_version, Android $android_version)"
elif [[ "$ios_updated" == "true" ]]; then
echo "chore: update Customer.io iOS SDK to $ios_version"
elif [[ "$android_updated" == "true" ]]; then
echo "chore: update Customer.io Android SDK to $android_version"
else
echo "chore: update Customer.io native SDKs"
fi
}
# Main logic
CURRENT_IOS="${{ needs.check-updates.outputs.current_ios }}"
CURRENT_ANDROID="${{ needs.check-updates.outputs.current_android }}"
NEW_IOS="${{ needs.check-updates.outputs.latest_ios }}"
NEW_ANDROID="${{ needs.check-updates.outputs.latest_android }}"
IOS_UPDATED="${{ needs.check-updates.outputs.ios_needs_update }}"
ANDROID_UPDATED="${{ needs.check-updates.outputs.android_needs_update }}"
# Generate title
TITLE=$(generate_title "$IOS_UPDATED" "$ANDROID_UPDATED" "$NEW_IOS" "$NEW_ANDROID")
# Generate description
DESCRIPTION="## Summary
Automated update of Customer.io native SDK dependencies:
"
if [[ "$IOS_UPDATED" == "true" ]]; then
IOS_RELEASE_URL="https://github.com/customerio/customerio-ios/releases/tag/v$NEW_IOS"
DESCRIPTION+="- **iOS SDK**: $CURRENT_IOS → $NEW_IOS ([Release Notes]($IOS_RELEASE_URL))
"
# Try to get iOS release notes
if IOS_RELEASE=$(get_release_notes "customerio" "customerio-ios" "$NEW_IOS"); then
IOS_CHANGES=$(extract_key_changes "$IOS_RELEASE")
if [[ -n "$IOS_CHANGES" ]]; then
DESCRIPTION+="
## Key Changes
### iOS SDK $NEW_IOS
$IOS_CHANGES
"
fi
fi
fi
if [[ "$ANDROID_UPDATED" == "true" ]]; then
ANDROID_RELEASE_URL="https://github.com/customerio/customerio-android/releases/tag/v$NEW_ANDROID"
DESCRIPTION+="- **Android SDK**: $CURRENT_ANDROID → $NEW_ANDROID ([Release Notes]($ANDROID_RELEASE_URL))
"
# Try to get Android release notes
if ANDROID_RELEASE=$(get_release_notes "customerio" "customerio-android" "$NEW_ANDROID"); then
ANDROID_CHANGES=$(extract_key_changes "$ANDROID_RELEASE")
if [[ -n "$ANDROID_CHANGES" ]]; then
if [[ "$IOS_UPDATED" != "true" ]]; then
DESCRIPTION+="
## Key Changes
"
fi
DESCRIPTION+="
### Android SDK $NEW_ANDROID
$ANDROID_CHANGES
"
fi
fi
fi
DESCRIPTION+="
## Testing
- ✅ Flutter analysis passed
- ✅ Unit tests passed
- ✅ iOS compilation verified
- ✅ Android compilation verified
- ✅ Sample app builds successfully
## Migration Notes
This update maintains API compatibility. Please test your integration thoroughly and review the release notes linked above for any specific changes that might affect your implementation.
---
*🤖 This PR was automatically generated and tested*"
# Set outputs
echo "title=$TITLE" >> $GITHUB_OUTPUT
{
echo "description<<EOF"
echo "$DESCRIPTION"
echo "EOF"
} >> $GITHUB_OUTPUT
echo "📝 Generated PR content:"
echo "Title: $TITLE"
- name: Commit changes
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add .
git commit -m "chore: update Customer.io native SDK versions
- iOS: ${{ needs.check-updates.outputs.current_ios }} → ${{ needs.check-updates.outputs.latest_ios }}
- Android: ${{ needs.check-updates.outputs.current_android }} → ${{ needs.check-updates.outputs.latest_android }}
🤖 Automated update with compilation verification"
- name: Check for existing PR with same title
id: check_existing_pr
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
EXPECTED_TITLE="${{ steps.generate_pr_content.outputs.title }}"
echo "🔍 Checking for existing open PRs with title: $EXPECTED_TITLE"
# Use gh pr list with jq to find PRs with exact title match
MATCHING_PRS=$(gh pr list --state=open --json number,title | jq -r --arg title "$EXPECTED_TITLE" '.[] | select(.title == $title) | .number')
if [[ -n "$MATCHING_PRS" ]]; then
# Get first PR number and count total matches
FIRST_PR=$(echo "$MATCHING_PRS" | head -n 1)
PR_COUNT=$(echo "$MATCHING_PRS" | wc -l | tr -d ' ')
if [[ "$PR_COUNT" -gt 1 ]]; then
echo "⚠️ Found $PR_COUNT existing open PRs with identical title"
echo "📋 PR numbers: $(echo "$MATCHING_PRS" | tr '\n' ' ')"
echo "🎯 Using first PR #$FIRST_PR as reference"
else
echo "⚠️ Found existing open PR #$FIRST_PR with identical title"
fi
echo "🚫 Skipping PR creation to avoid duplicates"
echo "existing_pr_found=true" >> $GITHUB_OUTPUT
echo "existing_pr_number=$FIRST_PR" >> $GITHUB_OUTPUT
echo "duplicate_pr_count=$PR_COUNT" >> $GITHUB_OUTPUT
else
echo "✅ No existing PR found with this title"
echo "existing_pr_found=false" >> $GITHUB_OUTPUT
fi
- name: Push branch and create PR
if: steps.check_existing_pr.outputs.existing_pr_found != 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git push origin "$branch_name"
# Create PR
gh pr create \
--title "${{ steps.generate_pr_content.outputs.title }}" \
--body "${{ steps.generate_pr_content.outputs.description }}" \
--base main \
--head "$branch_name"
echo "✅ Pull request created successfully!"
- name: Log duplicate PR skip
if: steps.check_existing_pr.outputs.existing_pr_found == 'true'
run: |
echo "🚫 PR creation skipped due to existing duplicate"
if [[ "${{ steps.check_existing_pr.outputs.duplicate_pr_count }}" -gt 1 ]]; then
echo "📋 Found ${{ steps.check_existing_pr.outputs.duplicate_pr_count }} existing PRs with identical title"
echo "🎯 Reference PR: #${{ steps.check_existing_pr.outputs.existing_pr_number }}"
else
echo "📋 Existing PR: #${{ steps.check_existing_pr.outputs.existing_pr_number }}"
fi
echo "🏷️ Title: ${{ steps.generate_pr_content.outputs.title }}"
echo ""
echo "ℹ️ Open PR(s) with identical title already exist."
echo " No new PR will be created to avoid duplicates."
- name: Post workflow summary
run: |
echo "## 🚀 Native SDK Update Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Updates Applied:" >> $GITHUB_STEP_SUMMARY
if [[ "${{ needs.check-updates.outputs.ios_needs_update }}" == "true" ]]; then
echo "- 📱 **iOS SDK**: ${{ needs.check-updates.outputs.current_ios }} → ${{ needs.check-updates.outputs.latest_ios }}" >> $GITHUB_STEP_SUMMARY
fi
if [[ "${{ needs.check-updates.outputs.android_needs_update }}" == "true" ]]; then
echo "- 🤖 **Android SDK**: ${{ needs.check-updates.outputs.current_android }} → ${{ needs.check-updates.outputs.latest_android }}" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Verification:" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Flutter analysis passed" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Unit tests passed" >> $GITHUB_STEP_SUMMARY
if [[ "${{ steps.check_existing_pr.outputs.existing_pr_found }}" != "true" ]]; then
echo "- ✅ Sample app compilation will be tested after PR creation" >> $GITHUB_STEP_SUMMARY
else
echo "- ✅ Sample app compilation will be tested on existing PR #${{ steps.check_existing_pr.outputs.existing_pr_number }}" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ steps.check_existing_pr.outputs.existing_pr_found }}" == "true" ]]; then
echo "### ⚠️ PR Creation Skipped" >> $GITHUB_STEP_SUMMARY
if [[ "${{ steps.check_existing_pr.outputs.duplicate_pr_count }}" -gt 1 ]]; then
echo "- 🚫 Found ${{ steps.check_existing_pr.outputs.duplicate_pr_count }} duplicate PRs with identical title" >> $GITHUB_STEP_SUMMARY
echo "- 🎯 **Reference PR**: #${{ steps.check_existing_pr.outputs.existing_pr_number }}" >> $GITHUB_STEP_SUMMARY
else
echo "- 🚫 Duplicate PR detected: #${{ steps.check_existing_pr.outputs.existing_pr_number }}" >> $GITHUB_STEP_SUMMARY
fi
echo "- 🏷️ **Title**: ${{ steps.generate_pr_content.outputs.title }}" >> $GITHUB_STEP_SUMMARY
echo "- 🌱 **Branch created**: \`$branch_name\` (not pushed)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "ℹ️ Open PR(s) with identical title already exist. No duplicate PR was created." >> $GITHUB_STEP_SUMMARY
else
echo "**Branch created**: \`$branch_name\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "ℹ️ Sample app builds will automatically run on the created PR" >> $GITHUB_STEP_SUMMARY
fi