Skip to content

Commit 32e1005

Browse files
Address PR review: version override, per-extension registry, manifest fix, usage validation
- Add set-extension-version-cd.yml to build and cross-build jobs so binaries get the daily version suffix (not just release artifacts) - Switch from shared registry-daily.json to per-extension entries (daily-registry-entries/{id}.json) to avoid race condition when multiple extension pipelines run concurrently - Make _manifest removal unconditional before conditional blocks - Add usage to required fields validation in registry script - Document YAML regex parsing limitation in code comment Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 9736f32 commit 32e1005

5 files changed

Lines changed: 52 additions & 80 deletions

File tree

eng/pipelines/templates/jobs/build-azd-extension.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ jobs:
4040

4141
- template: /eng/pipelines/templates/steps/setup-go.yml
4242

43+
- template: /eng/pipelines/templates/steps/set-extension-version-cd.yml
44+
parameters:
45+
AzdExtensionDirectory: ${{ parameters.AzdExtensionDirectory }}
46+
4347
- task: PowerShell@2
4448
inputs:
4549
pwsh: true

eng/pipelines/templates/jobs/cross-build-azd-extension.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ jobs:
4949
parameters:
5050
Condition: false
5151

52+
- template: /eng/pipelines/templates/steps/set-extension-version-cd.yml
53+
parameters:
54+
AzdExtensionDirectory: ${{ parameters.AzdExtensionDirectory }}
55+
5256
- task: PowerShell@2
5357
displayName: Set extension version variable
5458
inputs:

eng/pipelines/templates/steps/publish-extension.yml

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ parameters:
1515
default: true
1616

1717
steps:
18+
# Remove _manifest folder unconditionally before upload/release
19+
- pwsh: |
20+
if (Test-Path release/_manifest) {
21+
Remove-Item -Path release/_manifest -Recurse -Force
22+
}
23+
Write-Host "Release:"
24+
Get-ChildItem -Recurse release/ | Select-Object -Property Length,FullName
25+
displayName: Remove _manifest folder
26+
1827
- ${{ if and(eq(parameters.CreateGitHubRelease, true), ne(parameters.TagPrefix, ''), ne(parameters.TagVersion, '')) }}:
1928
# This step must run first because a duplicated tag means we don't need to
2029
# continue with any of the subsequent steps.
@@ -44,12 +53,6 @@ steps:
4453
env:
4554
GH_TOKEN: $(azuresdk-github-pat)
4655
47-
- pwsh: |
48-
Remove-Item -Path release/_manifest -Recurse -Force
49-
Write-Host "Release:"
50-
Get-ChildItem -Recurse release/ | Select-Object -Property Length,FullName
51-
displayName: Remove _manifest folder
52-
5356
- pwsh: |
5457
$version = "${{ parameters.TagVersion }}"
5558
$createArgs = @(
@@ -70,15 +73,6 @@ steps:
7073
env:
7174
GH_TOKEN: $(azuresdk-github-pat)
7275
73-
- ${{ if eq(parameters.CreateGitHubRelease, false) }}:
74-
- pwsh: |
75-
if (Test-Path release/_manifest) {
76-
Remove-Item -Path release/_manifest -Recurse -Force
77-
}
78-
Write-Host "Release:"
79-
Get-ChildItem -Recurse release/ | Select-Object -Property Length,FullName
80-
displayName: Remove _manifest folder
81-
8276
- task: AzurePowerShell@5
8377
displayName: Upload release to storage account
8478
inputs:

eng/pipelines/templates/steps/update-extension-daily-registry.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ parameters:
66

77
steps:
88
- task: AzurePowerShell@5
9-
displayName: Update daily registry
9+
displayName: Upload per-extension daily registry entry
1010
inputs:
1111
azureSubscription: 'Azure SDK Artifacts'
1212
azurePowerShellVersion: LatestVersion
@@ -15,15 +15,15 @@ steps:
1515
Inline: |
1616
$storageHost = "$(publish-storage-static-host)"
1717
$dailyBaseUrl = "$storageHost/azd/extensions/${{ parameters.SanitizedExtensionId }}/daily"
18-
$registryBlobPath = "$(publish-storage-location)/`$web/azd/extensions/registry-daily.json"
18+
$entryBlobPath = "$(publish-storage-location)/`$web/azd/extensions/daily-registry-entries/${{ parameters.AzdExtensionId }}.json"
1919
$templatePath = "$(Build.SourcesDirectory)/eng/pipelines/templates/json/extension-registry-daily-template.json"
2020
2121
& "$(Build.SourcesDirectory)/eng/scripts/Update-ExtensionDailyRegistry.ps1" `
2222
-SanitizedExtensionId "${{ parameters.SanitizedExtensionId }}" `
2323
-AzdExtensionId "${{ parameters.AzdExtensionId }}" `
2424
-Version "$(EXT_VERSION)" `
2525
-StorageBaseUrl $dailyBaseUrl `
26-
-RegistryBlobPath $registryBlobPath `
26+
-RegistryEntryBlobPath $entryBlobPath `
2727
-TemplatePath $templatePath
2828
env:
2929
AZCOPY_AUTO_LOGIN_TYPE: 'PSCRED'

eng/scripts/Update-ExtensionDailyRegistry.ps1

Lines changed: 32 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
<#
22
.SYNOPSIS
3-
Updates registry-daily.json on Azure Storage with the current extension's daily build entry.
3+
Writes a per-extension daily registry entry to Azure Storage.
44
55
.DESCRIPTION
66
1. Computes checksums from signed release artifacts
77
2. Reads extension.yaml for metadata (id, namespace, displayName, etc.)
88
3. Loads the JSON template, replaces placeholders with actual values
9-
4. Downloads existing registry-daily.json from storage (or creates empty)
10-
5. Merges the new entry and uploads back
9+
4. Uploads the entry as a standalone per-extension JSON blob
10+
11+
Each extension writes its own file to avoid race conditions when multiple
12+
extension pipelines run concurrently. A separate unification script
13+
(Build-UnifiedDailyRegistry.ps1) combines all per-extension entries into
14+
the final registry-daily.json.
1115
1216
.PARAMETER SanitizedExtensionId
1317
Hyphenated extension id (e.g. azure-ai-agents)
@@ -21,8 +25,9 @@
2125
.PARAMETER StorageBaseUrl
2226
Static storage host URL for daily artifacts
2327
24-
.PARAMETER RegistryBlobPath
25-
Full blob path for registry-daily.json
28+
.PARAMETER RegistryEntryBlobPath
29+
Full blob path for the per-extension entry JSON
30+
(e.g. .../azd/extensions/daily-registry-entries/azure.ai.agents.json)
2631
2732
.PARAMETER ReleasePath
2833
Path to the signed release artifacts
@@ -39,7 +44,7 @@ param(
3944
[Parameter(Mandatory)] [string] $AzdExtensionId,
4045
[Parameter(Mandatory)] [string] $Version,
4146
[Parameter(Mandatory)] [string] $StorageBaseUrl,
42-
[Parameter(Mandatory)] [string] $RegistryBlobPath,
47+
[Parameter(Mandatory)] [string] $RegistryEntryBlobPath,
4348
[Parameter(Mandatory)] [string] $TemplatePath,
4449
[string] $ReleasePath = "release",
4550
[string] $MetadataPath = "release-metadata"
@@ -91,9 +96,12 @@ if ($missingArtifacts.Count -gt 0) {
9196
exit 1
9297
}
9398

94-
# Read extension.yaml for metadata
95-
# Simple line-by-line parsing for top-level scalar fields, capabilities list,
96-
# and providers list. Sufficient for the known extension.yaml schema.
99+
# Read extension.yaml for metadata.
100+
# Uses simple line-by-line regex parsing — handles top-level scalar fields,
101+
# capabilities list, and providers list. This is intentionally not a full YAML
102+
# parser. It works for the known extension.yaml schema where all values are
103+
# single-line scalars or simple lists. If extension.yaml grows multi-line
104+
# values or complex nesting, switch to powershell-yaml.
97105
$extYaml = Get-Content $extYamlPath -Raw
98106
$extMeta = @{}
99107
foreach ($line in $extYaml -split "`n") {
@@ -132,7 +140,7 @@ foreach ($line in $extYaml -split "`n") {
132140
if ($currentProvider) { $providers += $currentProvider }
133141

134142
# Validate required fields were parsed
135-
$requiredFields = @('namespace', 'displayName', 'description')
143+
$requiredFields = @('namespace', 'displayName', 'description', 'usage')
136144
foreach ($field in $requiredFields) {
137145
if (-not $extMeta[$field] -or $extMeta[$field] -eq '') {
138146
Write-Error "Required field '$field' missing or empty in extension.yaml"
@@ -144,6 +152,7 @@ Write-Host "Parsed extension metadata:"
144152
Write-Host " namespace: $($extMeta.namespace)"
145153
Write-Host " displayName: $($extMeta.displayName)"
146154
Write-Host " description: $($extMeta.description)"
155+
Write-Host " usage: $($extMeta.usage)"
147156
Write-Host " capabilities: $($capabilities -join ', ')"
148157
Write-Host " providers: $($providers.Count)"
149158

@@ -152,7 +161,7 @@ $template = Get-Content $TemplatePath -Raw
152161
$replacements = @{
153162
'${EXT_VERSION}' = $Version
154163
'${REQUIRED_AZD_VERSION}' = if ($extMeta.requiredAzdVersion) { $extMeta.requiredAzdVersion } else { "" }
155-
'${USAGE}' = if ($extMeta.usage) { $extMeta.usage } else { "" }
164+
'${USAGE}' = $extMeta.usage
156165
'${SANITIZED_ID}' = $SanitizedExtensionId
157166
'${STORAGE_BASE_URL}' = $StorageBaseUrl
158167
'${CHECKSUM_DARWIN_AMD64}' = $checksums["DARWIN_AMD64"]
@@ -175,7 +184,7 @@ if ($providers.Count -gt 0) {
175184
$versionEntry | Add-Member -NotePropertyName "providers" -NotePropertyValue $providers
176185
}
177186

178-
# Build the full extension entry
187+
# Build the per-extension entry
179188
$extEntry = [ordered]@{
180189
id = $AzdExtensionId
181190
namespace = $extMeta.namespace
@@ -184,64 +193,25 @@ $extEntry = [ordered]@{
184193
versions = @($versionEntry)
185194
}
186195

187-
# Download existing registry or create empty
188-
# Use ErrorActionPreference Continue for azcopy since "not found" is expected on first run
189-
$registryFile = "registry-daily.json"
190-
$prevErrorPref = $ErrorActionPreference
191-
$ErrorActionPreference = 'Continue'
192-
$azcopyOutput = azcopy copy $RegistryBlobPath $registryFile 2>&1
193-
$azcopyExitCode = $LASTEXITCODE
194-
$ErrorActionPreference = $prevErrorPref
195-
196-
if ($azcopyExitCode -ne 0) {
197-
# Check if this is a "not found" (expected) vs an actual error
198-
$outputStr = $azcopyOutput | Out-String
199-
if ($outputStr -match "BlobNotFound|404|does not exist") {
200-
Write-Host "No existing registry found, creating new one"
201-
} else {
202-
Write-Warning "azcopy download failed (exit code $azcopyExitCode), creating new registry"
203-
Write-Warning $outputStr
204-
}
205-
[ordered]@{ extensions = @() } | ConvertTo-Json -Depth 10 | Set-Content $registryFile
206-
}
207-
208-
$registry = Get-Content $registryFile -Raw | ConvertFrom-Json -Depth 20
209-
210-
# Merge: replace existing extension entry or add new
211-
$found = $false
212-
for ($i = 0; $i -lt $registry.extensions.Count; $i++) {
213-
if ($registry.extensions[$i].id -eq $AzdExtensionId) {
214-
$registry.extensions[$i] = $extEntry
215-
$found = $true
216-
Write-Host "Updated existing entry for $AzdExtensionId"
217-
break
218-
}
219-
}
220-
if (-not $found) {
221-
$registry.extensions += $extEntry
222-
Write-Host "Added new entry for $AzdExtensionId"
223-
}
224-
225-
# Write registry and validate JSON round-trip before uploading
226-
$registryJson = $registry | ConvertTo-Json -Depth 20
227-
$registryJson | Set-Content $registryFile -Encoding utf8
196+
# Write per-extension entry and validate JSON
197+
$entryFile = "$AzdExtensionId.json"
198+
$extEntry | ConvertTo-Json -Depth 20 | Set-Content $entryFile -Encoding utf8
228199

229-
# Validate the output is valid JSON
230200
try {
231-
$null = Get-Content $registryFile -Raw | ConvertFrom-Json -Depth 20
201+
$null = Get-Content $entryFile -Raw | ConvertFrom-Json -Depth 20
232202
} catch {
233-
Write-Error "Generated registry JSON is invalid: $_"
203+
Write-Error "Generated entry JSON is invalid: $_"
234204
exit 1
235205
}
236206

237-
Write-Host "Registry contents:"
238-
Get-Content $registryFile
207+
Write-Host "Extension entry:"
208+
Get-Content $entryFile
239209

240-
# Upload to storage
241-
azcopy copy $registryFile $RegistryBlobPath --overwrite=true
210+
# Upload per-extension entry to storage
211+
azcopy copy $entryFile $RegistryEntryBlobPath --overwrite=true
242212
if ($LASTEXITCODE -ne 0) {
243-
Write-Error "Failed to upload registry to $RegistryBlobPath (exit code $LASTEXITCODE)"
213+
Write-Error "Failed to upload entry to $RegistryEntryBlobPath (exit code $LASTEXITCODE)"
244214
exit 1
245215
}
246216

247-
Write-Host "Registry uploaded to $RegistryBlobPath"
217+
Write-Host "Entry uploaded to $RegistryEntryBlobPath"

0 commit comments

Comments
 (0)