Skip to content

Commit d41fba6

Browse files
authored
Merge pull request #3059 from cmderdev/copilot/improve-vendor-ci-cd-messaging
chore: Auto-merge non-breaking vendor updates with improved messaging
2 parents 27e27ca + c231c38 commit d41fba6

4 files changed

Lines changed: 329 additions & 33 deletions

File tree

.github/workflows/build.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ jobs:
5656
$actualBranchName = $refName
5757
$branchLink = ""
5858
$prLink = ""
59-
59+
6060
# Check if this is a PR merge ref (e.g., "3061/merge")
6161
if ($refName -match '^(\d+)/(merge|head)$') {
6262
$prNumber = $Matches[1]
@@ -196,7 +196,7 @@ jobs:
196196
run: |
197197
# Source utility functions
198198
. scripts/utils.ps1
199-
199+
200200
$summary = @"
201201
202202
### 🗃️ Artifacts
@@ -208,7 +208,7 @@ jobs:
208208
# Get all files from the build directory (excluding directories and hidden files)
209209
if (Test-Path "build") {
210210
$buildFiles = Get-ChildItem -Path "build" -File | Where-Object { -not $_.Name.StartsWith('.') } | Sort-Object Name
211-
211+
212212
foreach ($file in $buildFiles) {
213213
$artifact = $file.Name
214214
$path = $file.FullName

.github/workflows/vendor.yml

Lines changed: 202 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ on:
66
# At 13:37 UTC every day.
77
- cron: '37 13 * * *'
88

9+
concurrency:
10+
group: vendor-update
11+
cancel-in-progress: false
12+
913
defaults:
1014
run:
1115
shell: pwsh
@@ -45,64 +49,226 @@ jobs:
4549
env:
4650
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4751
run: |
48-
$currentVersion = (Get-Content -Raw .\vendor\sources.json | ConvertFrom-Json)
49-
. .\scripts\update.ps1 -verbose
50-
Set-GHVariable -Name COUNT_UPDATED -Value $count
51-
$newVersion = (Get-Content -Raw .\vendor\sources.json | ConvertFrom-Json)
52-
$listUpdated = ""
53-
$updateMessage = "| Name | Old Version | New Version |`n| :--- | ---- | ---- |`n"
54-
foreach ($s in $newVersion) {
55-
$oldVersion = ($currentVersion | Where-Object {$_.name -eq $s.name}).version
56-
if ($s.version -ne $oldVersion) {
57-
$repoUrl = ($repoUrl = $s.Url.Replace("/archive/", "/releases/")).Substring(0, $repoUrl.IndexOf("/releases/")) + "/releases"
58-
$listUpdated += "$($s.name) v$($s.version), "
59-
$updateMessage += "| **[$($s.name)]($repoUrl)** | $oldVersion | **$($s.version)** |`n"
52+
$currentVersion = (Get-Content -Raw .\vendor\sources.json | ConvertFrom-Json)
53+
. .\scripts\update.ps1 -verbose
54+
55+
# Export count of updated packages (update.ps1 is expected to set $count)
56+
if (-not ($count)) { $count = 0 }
57+
Set-GHVariable -Name COUNT_UPDATED -Value $count
58+
59+
$newVersion = (Get-Content -Raw .\vendor\sources.json | ConvertFrom-Json)
60+
# Source utility functions
61+
. scripts/utils.ps1
62+
63+
$listUpdated = ""
64+
$updateMessage = "| Name | Old Version | New Version |`n| :--- | :---: | :---: |`n"
65+
$majorUpdates = @()
66+
$singleDepName = ""
67+
$singleDepOldVersion = ""
68+
$singleDepNewVersion = ""
69+
foreach ($s in $newVersion) {
70+
$oldVersion = ($currentVersion | Where-Object {$_.name -eq $s.name}).version
71+
if ($s.version -ne $oldVersion) {
72+
$repoUrl = ($repoUrl = $s.Url.Replace("/archive/", "/releases/")).Substring(0, $repoUrl.IndexOf("/releases/")) + "/releases"
73+
74+
# Store single dependency info for messages (only if this is the only update)
75+
if ($count -eq 1) {
76+
$singleDepName = $s.name
77+
$singleDepOldVersion = $oldVersion
78+
$singleDepNewVersion = $s.version
79+
}
80+
81+
# Determine change type and emoji using shared function
82+
$result = Get-VersionChangeType -OldVersion $oldVersion -NewVersion $s.version
83+
$changeType = $result.ChangeType
84+
$emoji = $result.Emoji
85+
$isMajor = $result.IsMajor
86+
87+
# Track major updates for changelog section
88+
if ($isMajor) {
89+
$compareUrl = "$repoUrl/compare/v$oldVersion...v$($s.version)"
90+
$majorUpdates += @{
91+
name = $s.name
92+
oldVersion = $oldVersion
93+
newVersion = $s.version
94+
compareUrl = $compareUrl
95+
repoUrl = $repoUrl
96+
}
97+
}
98+
99+
$listUpdated += "$($s.name) v$($s.version), "
100+
$updateMessage += "| $emoji **[$($s.name)]($repoUrl)** | \`$oldVersion\` | **\`$($s.version)\`** |`n"
101+
}
102+
}
103+
104+
if ($count -eq 0) { return }
105+
106+
Set-GHVariable -Name LIST_UPDATED -Value $listUpdated.Trim(', ')
107+
# Set single dependency variables (they will only be used if COUNT_UPDATED is 1)
108+
# Use safe fallback values in case variables weren't set (shouldn't happen but prevents errors)
109+
if ([string]::IsNullOrEmpty($singleDepName) -and $count -eq 1) {
110+
# This shouldn't happen, but if it does, log a warning
111+
Write-Warning "Single dependency name not set despite count being 1"
112+
$singleDepName = "unknown-package"
113+
$singleDepOldVersion = "unknown"
114+
$singleDepNewVersion = "unknown"
115+
} elseif ([string]::IsNullOrEmpty($singleDepName)) {
116+
# For multiple dependencies, set placeholder values (won't be used)
117+
$singleDepName = ""
118+
$singleDepOldVersion = ""
119+
$singleDepNewVersion = ""
60120
}
61-
}
62-
if ($count -eq 0) { return }
63-
Set-GHVariable -Name LIST_UPDATED -Value $listUpdated.Trim(', ')
64121
65-
echo "UPDATE_MESSAGE<<EOF`n$updateMessage`nEOF" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
122+
Set-GHVariable -Name SINGLE_DEP_NAME -Value $singleDepName
123+
Set-GHVariable -Name SINGLE_DEP_OLD_VERSION -Value $singleDepOldVersion
124+
Set-GHVariable -Name SINGLE_DEP_NEW_VERSION -Value $singleDepNewVersion
125+
126+
# Write multiline UPDATE_MESSAGE to GITHUB_ENV
127+
## echo "UPDATE_MESSAGE<<EOF`n$updateMessage`nEOF" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
128+
Add-Content -Path $env:GITHUB_ENV -Value "UPDATE_MESSAGE<<EOF"
129+
Add-Content -Path $env:GITHUB_ENV -Value $updateMessage
130+
Add-Content -Path $env:GITHUB_ENV -Value "EOF"
131+
132+
# Generate major updates changelog section and export
133+
if ($majorUpdates.Count -gt 0) {
134+
$changelogSection = "`n<details>`n<summary>🔥 Major version updates - View changelog</summary>`n`n"
135+
foreach ($update in $majorUpdates) {
136+
$changelogSection += "### [$($update.name)]($($update.repoUrl))`n"
137+
$changelogSection += "**$($update.oldVersion)** → **$($update.newVersion)**`n`n"
138+
$changelogSection += "- [View full changelog]($($update.compareUrl))`n"
139+
$changelogSection += "- [Release notes]($($update.repoUrl)/tag/v$($update.newVersion))`n`n"
140+
}
141+
$changelogSection += "</details>`n"
142+
143+
Add-Content -Path $env:GITHUB_ENV -Value "CHANGELOG_SECTION<<EOF"
144+
Add-Content -Path $env:GITHUB_ENV -Value $changelogSection
145+
Add-Content -Path $env:GITHUB_ENV -Value "EOF"
146+
Add-Content -Path $env:GITHUB_ENV -Value "HAS_BREAKING_CHANGES=True"
147+
} else {
148+
Add-Content -Path $env:GITHUB_ENV -Value "CHANGELOG_SECTION="
149+
Add-Content -Path $env:GITHUB_ENV -Value "HAS_BREAKING_CHANGES=False"
150+
}
66151
67152
- name: Summary - Update check results
68153
shell: pwsh
69154
run: |
70155
$count = [int]$env:COUNT_UPDATED
156+
71157
if ($count -eq 0) {
72158
$summary = @"
73159
### ✅ No Updates Available
74160
75-
All vendor dependencies are up to date.
161+
All vendor dependencies are up to date! 🎉
76162
"@
77163
} else {
78164
$word = if ($count -eq 1) { 'dependency' } else { 'dependencies' }
79165
$summary = @"
80166
### 🔄 Updates Found
81167
82-
**$count** vendor $word updated:
168+
"@
169+
if ($count -eq 1) {
170+
$summary += '📦 **' + $env:SINGLE_DEP_NAME + '** updated from `' + $env:SINGLE_DEP_OLD_VERSION + '` to `' + $env:SINGLE_DEP_NEW_VERSION + '`' + "`n" + "`n"
171+
} else {
172+
$summary += '📦 **' + $count + '** vendor ' + $word + ' updated:' + "`n" + "`n"
173+
}
174+
}
83175
84-
$env:UPDATE_MESSAGE
176+
$summary += $env:UPDATE_MESSAGE + "`n"
85177
86-
"@
178+
# Check if we can auto-merge (only minor/patch changes)
179+
$hasBreaking = $env:HAS_BREAKING_CHANGES -eq 'True'
180+
if ($hasBreaking) {
181+
$summary += '> ⚠️ **Note:** This update contains major version changes that may include breaking changes.'
182+
} else {
183+
$summary += '> ℹ️ **Note:** This update only contains minor or patch changes.'
87184
}
88185
89186
$summary | Add-Content -Path $env:GITHUB_STEP_SUMMARY -Encoding utf8
90187
188+
- name: Auto-merge minor updates
189+
if: env.COUNT_UPDATED > 0 && env.HAS_BREAKING_CHANGES != 'True'
190+
shell: pwsh
191+
run: |
192+
try {
193+
echo "### 🚀 Auto-merging Updates" >> $env:GITHUB_STEP_SUMMARY
194+
echo "" >> $env:GITHUB_STEP_SUMMARY
195+
echo "Attempting to automatically merge non-breaking changes to master..." >> $env:GITHUB_STEP_SUMMARY
196+
197+
git config --global user.name "github-actions[bot]"
198+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
199+
200+
# Commit the changes
201+
git add vendor/sources.json
202+
$commitResult = git commit -m "⬆️ Update dependencies ($env:LIST_UPDATED)"
203+
$commitSuccess = $LASTEXITCODE -eq 0
204+
205+
if ($commitSuccess) {
206+
# Push directly to master
207+
git push origin HEAD:master
208+
$pushSuccess = $LASTEXITCODE -eq 0
209+
210+
if ($pushSuccess) {
211+
echo "" >> $env:GITHUB_STEP_SUMMARY
212+
echo "✅ **Success!** Updates have been automatically merged to master." >> $env:GITHUB_STEP_SUMMARY
213+
echo "" >> $env:GITHUB_STEP_SUMMARY
214+
echo "**Updated dependencies:** $env:LIST_UPDATED" >> $env:GITHUB_STEP_SUMMARY
215+
216+
# Set a flag to skip PR creation
217+
echo "AUTO_MERGED=true" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
218+
} else {
219+
throw "Failed to push to master (exit code: $LASTEXITCODE)"
220+
}
221+
} else {
222+
throw "Failed to commit changes (exit code: $LASTEXITCODE)"
223+
}
224+
} catch {
225+
echo "" >> $env:GITHUB_STEP_SUMMARY
226+
echo "⚠️ **Warning:** Unable to automatically merge updates." >> $env:GITHUB_STEP_SUMMARY
227+
echo "" >> $env:GITHUB_STEP_SUMMARY
228+
echo "**Error:** $($_.Exception.Message)" >> $env:GITHUB_STEP_SUMMARY
229+
echo "" >> $env:GITHUB_STEP_SUMMARY
230+
echo "Falling back to creating a pull request..." >> $env:GITHUB_STEP_SUMMARY
231+
232+
Write-Warning "Failed to auto-merge: $($_.Exception.Message)"
233+
234+
# Only reset if commit was successful but push failed
235+
if ($commitSuccess -and -not $pushSuccess) {
236+
try {
237+
git reset --hard HEAD~1
238+
if ($LASTEXITCODE -ne 0) {
239+
Write-Warning "Failed to reset commit (exit code: $LASTEXITCODE), continuing with PR creation"
240+
}
241+
} catch {
242+
Write-Warning "Failed to reset commit: $($_.Exception.Message), continuing with PR creation"
243+
}
244+
}
245+
246+
# Set flag to create PR instead
247+
echo "AUTO_MERGED=false" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
248+
}
249+
91250
- uses: peter-evans/create-pull-request@v8
92-
if: env.COUNT_UPDATED > 0
251+
if: fromJSON(env.COUNT_UPDATED) > 0 && (env.HAS_BREAKING_CHANGES == 'True' || env.AUTO_MERGED == 'false')
93252
with:
94-
title: 'Updates to `${{ env.COUNT_UPDATED }}` vendored dependencies'
253+
title: ${{ env.COUNT_UPDATED == 1 && format('⬆️ Update {0}', env.LIST_UPDATED) || format('⬆️ Update {0} vendored dependencies', env.COUNT_UPDATED) }}
95254
body: |
96-
### Automatically updated `${{ env.COUNT_UPDATED }}` dependencies:
255+
### ${{ env.COUNT_UPDATED == 1 && format('📦 Updated {0} from `{1}` to `{2}`', env.SINGLE_DEP_NAME, env.SINGLE_DEP_OLD_VERSION, env.SINGLE_DEP_NEW_VERSION) || format('📦 Automatically updated `{0}` dependencies', env.COUNT_UPDATED) }}
256+
97257
${{ env.UPDATE_MESSAGE }}
258+
259+
${{ env.CHANGELOG_SECTION }}
260+
98261
---
99-
Please verify and then **Merge** the pull request to update.
262+
263+
${{ env.HAS_BREAKING_CHANGES == 'True' && '⚠️ **This update contains major version changes that may include breaking changes.**' || 'ℹ️ This update only contains minor or patch changes.' }}
264+
265+
Please verify and then **Merge** the pull request to apply the updates.
100266
commit-message: '⬆️ Update dependencies (${{ env.LIST_UPDATED }})'
101267
branch: update-vendor
102268
base: master
103269

104270
- name: Summary - Pull request created
105-
if: env.COUNT_UPDATED > 0
271+
if: env.COUNT_UPDATED > 0 && (env.HAS_BREAKING_CHANGES == 'True' || env.AUTO_MERGED == 'false')
106272
shell: pwsh
107273
run: |
108274
$summary = @"
@@ -112,9 +278,19 @@ jobs:
112278
113279
**Branch:** ``update-vendor``
114280
115-
**Updated dependencies:** $env:LIST_UPDATED
281+
$(if (-not [string]::IsNullOrEmpty($env:LIST_UPDATED)) { "**Updated dependencies:** $env:LIST_UPDATED" } else { "**Updated dependencies:** " })
116282
283+
"@
284+
285+
if ($env:HAS_BREAKING_CHANGES -eq 'True') {
286+
$summary += "> ⚠️ **Manual review required:** This update contains major version changes."
287+
} else {
288+
$summary += "> ℹ️ **Note:** Auto-merge failed, manual review required."
289+
}
290+
291+
$summary += @"
117292
> Please review and merge the pull request to apply the updates.
293+
118294
"@
119295
120296
$summary | Add-Content -Path $env:GITHUB_STEP_SUMMARY -Encoding utf8

scripts/update.ps1

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ function Fetch-DownloadUrl {
259259
}
260260

261261
$count = 0
262+
$hasBreakingChanges = $false
263+
$updateDetails = @()
262264

263265
# Read the current sources content
264266
$sources = Get-Content $sourcesPath | Out-String | ConvertFrom-Json
@@ -301,6 +303,26 @@ foreach ($s in $sources) {
301303
# }
302304

303305
$count++
306+
307+
# Analyze version change type using shared function
308+
$result = Get-VersionChangeType -OldVersion $s.version -NewVersion $version
309+
$changeType = $result.ChangeType
310+
311+
# Determine if this is a breaking change
312+
if ($changeType -eq "downgrade" -or $changeType -eq "major") {
313+
$hasBreakingChanges = $true
314+
} elseif ($changeType -eq "unknown") {
315+
# If version parsing failed, treat as potentially breaking
316+
$hasBreakingChanges = $true
317+
Write-Verbose "Could not parse version as semantic version for dependency '$($s.name)' (old: '$($s.version)', new: '$version'), treating as potentially breaking"
318+
}
319+
320+
$updateDetails += @{
321+
name = $s.name
322+
oldVersion = $s.version
323+
newVersion = $version
324+
changeType = $changeType
325+
}
304326
}
305327

306328
$s.url = $downloadUrl
@@ -314,12 +336,16 @@ if ($count -eq 0) {
314336
return
315337
}
316338

317-
if ($Env:APPVEYOR -eq 'True') {
318-
Add-AppveyorMessage -Message "Successfully updated $count dependencies." -Category Information
319-
}
320-
339+
# Export update details for GitHub Actions
321340
if ($Env:GITHUB_ACTIONS -eq 'true') {
341+
$updateDetailsJson = $updateDetails | ConvertTo-Json -Compress
342+
Write-Output "UPDATE_DETAILS=$updateDetailsJson" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
343+
Write-Output "HAS_BREAKING_CHANGES=$hasBreakingChanges" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
322344
Write-Output "::notice title=Task Complete::Successfully updated $count dependencies."
323345
}
324346

347+
if ($Env:APPVEYOR -eq 'True') {
348+
Add-AppveyorMessage -Message "Successfully updated $count dependencies." -Category Information
349+
}
350+
325351
Write-Host -ForegroundColor green "Successfully updated $count dependencies."

0 commit comments

Comments
 (0)