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)
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
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 = @ {}
99107foreach ($line in $extYaml -split " `n " ) {
@@ -132,7 +140,7 @@ foreach ($line in $extYaml -split "`n") {
132140if ($currentProvider ) { $providers += $currentProvider }
133141
134142# Validate required fields were parsed
135- $requiredFields = @ (' namespace' , ' displayName' , ' description' )
143+ $requiredFields = @ (' namespace' , ' displayName' , ' description' , ' usage ' )
136144foreach ($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:"
144152Write-Host " namespace: $ ( $extMeta.namespace ) "
145153Write-Host " displayName: $ ( $extMeta.displayName ) "
146154Write-Host " description: $ ( $extMeta.description ) "
155+ Write-Host " usage: $ ( $extMeta.usage ) "
147156Write-Host " capabilities: $ ( $capabilities -join ' , ' ) "
148157Write-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
230200try {
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
242212if ($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