Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
7a4dbaa
Remove yank job; ESRP doesn't have direct programmatic support for that
danieljurek Sep 22, 2025
840dfd2
Rough changes to Pack-Crates.ps1 to produce .crate files
danieljurek Sep 23, 2025
10d7fec
First cut at ESRP publishing
danieljurek Sep 24, 2025
5776bcc
Use *.crate package pattern, adjust Pack-Crates.ps1 to create package…
danieljurek Sep 24, 2025
4609efe
Extract package information from .crate file
danieljurek Sep 24, 2025
9361718
Syntax
danieljurek Sep 24, 2025
439fb75
Syntax
danieljurek Sep 24, 2025
219b615
Syntax
danieljurek Sep 24, 2025
67cfc1b
Syntax
danieljurek Sep 24, 2025
5f99257
Compress-ReleaseCrate.ps1, wire into archetype-rust-release.yml
danieljurek Sep 24, 2025
26e43bd
Use managed identity
danieljurek Sep 24, 2025
a9bb270
Redundant line
danieljurek Sep 24, 2025
3fb1dff
Deployment scripts must be inline (no checkout)
danieljurek Sep 24, 2025
17492cc
Disable repo tagging to iterate on release, inline compression
danieljurek Sep 24, 2025
29056a6
Create output directory
danieljurek Sep 24, 2025
f8e8b61
:
danieljurek Sep 24, 2025
66b58b2
EsrpRelease@10
danieljurek Sep 24, 2025
f28db0a
Remove redundant keys
danieljurek Sep 24, 2025
8eae845
DomainTenantId
danieljurek Sep 24, 2025
5529ee9
Don't nest in zip?
danieljurek Sep 24, 2025
228f56e
Remove toolchain config
danieljurek Sep 24, 2025
fe40fea
Add KV and signing info
danieljurek Sep 24, 2025
4346cbc
Use ESRPRELPACMANTEST
danieljurek Sep 25, 2025
5a9a328
Check that crate is publishable
danieljurek Sep 25, 2025
5088f09
Pack-Crates.ps1: Remove -PackageInfoDirectory, add -RequireDependenci…
danieljurek Sep 26, 2025
45ee30c
Wire up release intent
danieljurek Sep 26, 2025
6f4ea85
each artifact
danieljurek Sep 26, 2025
8293f62
Parameters
danieljurek Sep 26, 2025
8680b7d
Only specify an environment if not in a test pipeline
danieljurek Sep 26, 2025
056885a
Use environment: none if in TestPipeline
danieljurek Sep 26, 2025
56fb5ed
Remove Environment param
danieljurek Sep 26, 2025
90faf9b
(test) Depend on unreleased core
danieljurek Sep 26, 2025
a0447ec
Remove azure_canary_core's dependency on azure_core
danieljurek Sep 26, 2025
f6ccd4d
Check existence
danieljurek Sep 26, 2025
f70e12b
Naming
danieljurek Sep 26, 2025
bdc03d9
Log file paths
danieljurek Sep 26, 2025
867b1c2
backtick
danieljurek Sep 26, 2025
3aa7bf4
Remove extra logging
danieljurek Sep 26, 2025
922fc54
Test ESRP idempotency
danieljurek Sep 26, 2025
014370f
Remove test step
danieljurek Sep 26, 2025
f342ccd
Update ci.yml files with release parameters
danieljurek Sep 29, 2025
3a697ac
Also require dependency order
danieljurek Sep 29, 2025
68cffcb
Wire up CHANGELOG.md and README.md
danieljurek Sep 29, 2025
4735144
Test: remove package verison updating from release. Should fail Packing.
danieljurek Sep 29, 2025
8f8ebc3
Better testing: turn off TestPipeline
danieljurek Sep 29, 2025
f43a964
Undo test changes
danieljurek Sep 29, 2025
fe472fc
Move RequireDependencies into pack.yml
danieljurek Sep 29, 2025
6423c8d
Move RequireDependencies into pack.yml
danieljurek Sep 29, 2025
247de8e
Pack-Crates.ps1: Use PackageInfoDirectory
danieljurek Sep 29, 2025
726d7ac
-RequireDependencies
danieljurek Sep 29, 2025
5997f54
Syntax
danieljurek Sep 29, 2025
37ea97a
Formatting/cleanup
danieljurek Sep 29, 2025
fe8cf19
cspell: allowCompoundWords: true
danieljurek Sep 29, 2025
20bed97
Remove formatting
danieljurek Sep 29, 2025
debd2f2
Spelling
danieljurek Sep 29, 2025
455288c
Review feedback: No artifacts selected means "just build all artifact…
danieljurek Oct 1, 2025
fa4ab88
convertToJson
danieljurek Oct 1, 2025
da1fda7
Only create the stage if there are artifacts to release
danieljurek Oct 1, 2025
1a298a0
'False'
danieljurek Oct 1, 2025
d3c1de1
More error throwing
danieljurek Oct 1, 2025
da077ef
Review feedback: Don't enable allowCompoundWords, also release_ names…
danieljurek Oct 2, 2025
11ad80d
Fix typespec_macros
danieljurek Oct 2, 2025
8e71351
Artifact ordering for Pack-Crates.ps1
danieljurek Oct 2, 2025
9caec0d
Add support for outputting release order of specified packages
danieljurek Oct 6, 2025
ba0db82
Use artifact ordering from artifacts
danieljurek Oct 7, 2025
db2fb91
Log index
danieljurek Oct 7, 2025
9cfa228
One PR per-release
danieljurek Oct 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 44 additions & 9 deletions eng/pipelines/templates/jobs/pack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,51 @@ jobs:
ServiceDirectory: ${{ parameters.ServiceDirectory }}
PackageInfoDirectory: $(Build.ArtifactStagingDirectory)/PackageInfo

- task: Powershell@2
displayName: "Pack Crates"
condition: and(succeeded(), ne(variables['NoPackagesChanged'],'true'))
inputs:
pwsh: true
filePath: $(Build.SourcesDirectory)/eng/scripts/Pack-Crates.ps1
arguments: >
-OutputPath '$(Build.ArtifactStagingDirectory)'
-PackageInfoDirectory '$(Build.ArtifactStagingDirectory)/PackageInfo'
- ${{ if eq('auto', parameters.ServiceDirectory) }}:
- task: Powershell@2
displayName: "Pack Crates (PR build)"
condition: and(succeeded(), ne(variables['NoPackagesChanged'],'true'))
inputs:
pwsh: true
filePath: $(Build.SourcesDirectory)/eng/scripts/Pack-Crates.ps1
arguments: >
-OutputPath '$(Build.ArtifactStagingDirectory)'
-PackageInfoDirectory '$(Build.ArtifactStagingDirectory)/PackageInfo'

- ${{ else }}:
- pwsh: |
$artifacts = '${{ convertToJson(parameters.Artifacts) }}' | ConvertFrom-Json
$requireDependencies = $true
$artifactsToBuild = $artifacts | Where-Object { $_.releaseInBatch -ne 'False' }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the double negative here?




if (!$artifactsToBuild) {
Write-Host "No packages to release. Building all packages in the service directory with no dependency validation."
$artifactsToBuild = $artifacts
$requireDependencies = $false
}

$packageNames = $artifactsToBuild.name -join ','

Write-Host "##vso[task.setvariable variable=PackageNames]$packageNames"
Write-Host "##vso[task.setvariable variable=RequireDependencies]$requireDependencies"

displayName: Create package list

- task: Powershell@2
displayName: "Pack Crates"
condition: and(succeeded(), ne(variables['NoPackagesChanged'],'true'))
inputs:
pwsh: true
filePath: $(Build.SourcesDirectory)/eng/scripts/Pack-Crates.ps1
arguments: >
-OutputPath '$(Build.ArtifactStagingDirectory)'
-PackageNames $(PackageNames)
-RequireDependencies:$$(RequireDependencies)
-OutBuildOrderFile '$(Build.ArtifactStagingDirectory)/release-order.json'

# TODO: Ensure APIView works given a change to the crates output folder structure
- template: /eng/common/pipelines/templates/steps/publish-1es-artifact.yml
parameters:
ArtifactPath: $(Build.ArtifactStagingDirectory)
Expand Down
210 changes: 109 additions & 101 deletions eng/pipelines/templates/stages/archetype-rust-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,13 @@ parameters:
- name: DevFeedName
type: string
default: 'public/azure-sdk-for-rust'
- name: Environment
type: string
default: 'cratesio'

stages:
- ${{ if eq(variables['System.TeamProject'], 'internal') }}:
- ${{ if in(variables['Build.Reason'], 'Manual', '') }}:
- ${{ each artifact in parameters.Artifacts }}:
- stage: Release_${{artifact.safeName}}
displayName: "Release: ${{artifact.name}}"
- ${{ if gt(length(parameters.Artifacts), 0) }}:
- stage: Release_Batch
displayName: "Releasing: ${{length(parameters.Artifacts)}} crates"
dependsOn: ${{parameters.DependsOn}}
condition: and(succeeded(), ne(variables['SetDevVersion'], 'true'), ne(variables['Skip.Release'], 'true'), ne(variables['Build.Repository.Name'], 'Azure/azure-sdk-for-rust-pr'))
variables:
Expand All @@ -50,16 +47,17 @@ stages:

- template: /eng/common/pipelines/templates/steps/retain-run.yml

- script: |
echo "##vso[build.addbuildtag]${{artifact.name}}"
displayName: Add build tag '${{artifact.name}}'
- ${{ each artifact in parameters.Artifacts }}:
- script: |
echo "##vso[build.addbuildtag]${{artifact.name}}"
displayName: Add build tag '${{artifact.name}}'

- template: /eng/common/pipelines/templates/steps/create-tags-and-git-release.yml
parameters:
ArtifactLocation: $(Pipeline.Workspace)/${{parameters.PipelineArtifactName}}/${{artifact.name}}
PackageRepository: Crates.io
ReleaseSha: $(Build.SourceVersion)
WorkingDirectory: $(Pipeline.Workspace)/_work
- template: /eng/common/pipelines/templates/steps/create-tags-and-git-release.yml
parameters:
ArtifactLocation: $(Pipeline.Workspace)/${{parameters.PipelineArtifactName}}/${{artifact.name}}
PackageRepository: Crates.io
ReleaseSha: $(Build.SourceVersion)
WorkingDirectory: $(Pipeline.Workspace)/_work

- deployment: PublishPackage
displayName: "Publish to Crates.io"
Expand All @@ -71,7 +69,10 @@ stages:
- input: pipelineArtifact # Required, type of the input artifact
artifactName: ${{parameters.PipelineArtifactName}} # Required, name of the pipeline artifact
targetPath: $(Pipeline.Workspace)/drop # Optional, specifies where the artifact is downloaded to
environment: ${{parameters.Environment}}
${{if parameters.TestPipeline}}:
environment: none
${{else}}:
environment: cratesio
# This timeout shouldn't be necessary once we're able to parallelize better. Right now,
# this is here to ensure larger areas (30+) libraries don't time out.
timeoutInMinutes: 120
Expand All @@ -84,33 +85,77 @@ stages:
runOnce:
deploy:
steps:
- template: /eng/pipelines/templates/steps/use-rust.yml@self
parameters:
Toolchain: stable

- pwsh: |
$additionalOwners = @('heaths', 'hallipr')
$token = $env:CARGO_REGISTRY_TOKEN
$crateName = '${{artifact.name}}'

$manifestPath = "$(Pipeline.Workspace)/drop/$crateName/contents/Cargo.toml"
Write-Host "> cargo publish --manifest-path `"$manifestPath`""
cargo publish --manifest-path $manifestPath
if (!$?) {
Write-Error "Failed to publish package: '$crateName'"
exit 1
}

$existingOwners = (cargo owner --list $crateName) -replace " \(.*", ""
$missingOwners = $additionalOwners | Where-Object { $existingOwners -notcontains $_ }

foreach ($owner in $missingOwners) {
Write-Host "> cargo owner --add $owner $crateName"
cargo owner --add $owner $crateName
}
displayName: Publish Crate
env:
CARGO_REGISTRY_TOKEN: $(azure-sdk-cratesio-token)
- pwsh: |
Write-Host "##vso[task.setvariable variable=ArtifactIndex]0"
displayName: Set ArtifactIndex to 0

- ${{ each artifact in parameters.Artifacts }}:
- pwsh: |
# Read artifact release order from release-order.json
# and use ArtifactIndex to select the right one
$index = [int]'$(ArtifactIndex)'
$artifacts = Get-Content '$(Pipeline.Workspace)/drop/release-order.json' | ConvertFrom-Json
if ($index -ge $artifacts.Count) {
Write-Error "ArtifactIndex $index is out of range (0..$($artifacts.Count - 1))"
exit 1
}

$artifactName = $artifacts[$index]
Write-Host "Releasing artifact $artifactName (index $index)"

$artifactRootPath = '$(Pipeline.Workspace)/drop'
$outDir = '$(Pipeline.Workspace)/esrp-release'

if (Test-Path $outDir) {
Write-Host "Cleaning output directory: $outDir"
Remove-Item -Path $outDir -Recurse -Force
}
New-Item -ItemType Directory -Path $outDir -Force | Out-Null

Write-Host "Artifact name: $artifactName"

$packageMetadataPath = "$artifactRootPath/PackageInfo/$artifactName.json"
if (!(Test-Path $packageMetadataPath)) {
Write-Error "Package metadata file not found: $packageMetadataPath"
exit 1
}

$packageMetadata = Get-Content -Raw $packageMetadataPath | ConvertFrom-Json
$packageVersion = $packageMetadata.version
Write-Host "Package version: $packageVersion"

$cratePath = "$artifactRootPath/$artifactName/$artifactName-$packageVersion.crate"
Copy-Item `
-Path $cratePath `
-Destination $outDir
Write-Host "Contents of $outDir"
Get-ChildItem -Path $outDir | ForEach-Object { Write-Host $_.FullName }
displayName: 'Copy crate for ESRP'

- task: EsrpRelease@10
displayName: 'ESRP Release'
inputs:
connectedservicename: 'Azure SDK PME Managed Identity'
ClientId: '5f81938c-2544-4f1f-9251-dd9de5b8a81b'
DomainTenantId: '975f013f-7f24-47e8-a7d3-abc4752bf346'
Usemanagedidentity: true
KeyVaultName: 'kv-azuresdk-codesign'
SignCertName: 'azure-sdk-esrp-release-certificate'
intent: 'packagedistribution'
contenttype: 'Rust'
contentsource: 'Folder'
folderlocation: '$(Pipeline.Workspace)/esrp-release'
waitforreleasecompletion: true
owners: ${{ coalesce(variables['Build.RequestedForEmail'], '[email protected]') }}
approvers: ${{ coalesce(variables['Build.RequestedForEmail'], '[email protected]') }}
serviceendpointurl: 'https://api.esrp.microsoft.com/'
mainpublisher: 'ESRPRELPACMANTEST'

- pwsh: |
$index = [int]'$(ArtifactIndex)' + 1
Write-Host "Setting ArtifactIndex to $index"
Write-Host "##vso[task.setvariable variable=ArtifactIndex]$index"
displayName: Increment ArtifactIndex

- job: UpdatePackageVersion
displayName: "API Review and Package Version Update"
Expand All @@ -130,69 +175,32 @@ stages:
displayName: Download ${{parameters.PipelineArtifactName}} artifact
artifact: ${{parameters.PipelineArtifactName}}

- template: /eng/common/pipelines/templates/steps/create-apireview.yml
parameters:
ArtifactPath: $(Pipeline.Workspace)/${{parameters.PipelineArtifactName}}
Artifacts: ${{parameters.Artifacts}}
ConfigFileDir: $(Pipeline.Workspace)/${{parameters.PipelineArtifactName}}/PackageInfo
MarkPackageAsShipped: true
ArtifactName: ${{parameters.PipelineArtifactName}}
SourceRootPath: $(System.DefaultWorkingDirectory)
PackageName: ${{artifact.name}}

# Apply the version increment to each library, which updates the Cargo.toml and changelog files.
- task: PowerShell@2
displayName: Increment ${{artifact.name}} version
inputs:
targetType: filePath
filePath: $(Build.SourcesDirectory)/eng/scripts/Update-PackageVersion.ps1
arguments: >
-ServiceDirectory '${{parameters.ServiceDirectory}}'
-PackageName '${{artifact.name}}'
- ${{each artifact in parameters.Artifacts }}:
- template: /eng/common/pipelines/templates/steps/create-apireview.yml
parameters:
ArtifactPath: $(Pipeline.Workspace)/${{parameters.PipelineArtifactName}}
Artifacts: ${{parameters.Artifacts}}
ConfigFileDir: $(Pipeline.Workspace)/${{parameters.PipelineArtifactName}}/PackageInfo
MarkPackageAsShipped: true
ArtifactName: ${{parameters.PipelineArtifactName}}
SourceRootPath: $(System.DefaultWorkingDirectory)
PackageName: ${{artifact.name}}

# Apply the version increment to each library, which updates the Cargo.toml and changelog files.
- task: PowerShell@2
displayName: Increment ${{artifact.name}} version
inputs:
targetType: filePath
filePath: $(Build.SourcesDirectory)/eng/scripts/Update-PackageVersion.ps1
arguments: >
-ServiceDirectory '${{parameters.ServiceDirectory}}'
-PackageName '${{artifact.name}}'

- template: /eng/common/pipelines/templates/steps/create-pull-request.yml
parameters:
PRBranchName: increment-package-version-${{parameters.ServiceDirectory}}-$(Build.BuildId)
CommitMsg: "Increment package version after release of ${{ artifact.name }}"
CommitMsg: "Increment package version after release of ${{ join(', ', parameters.Artifacts.*.name) }}"
PRTitle: "Increment versions for ${{parameters.ServiceDirectory}} releases"
CloseAfterOpenForTesting: '${{parameters.TestPipeline}}'
${{ if startsWith(variables['Build.SourceBranch'], 'refs/pull/') }}:
BaseBranchName: main

- ${{ if eq(parameters.TestPipeline, true) }}:
- job: ManualApproval
displayName: "Manual approval"
dependsOn: PublishPackage
condition: ne(variables['Skip.PublishPackage'], 'true')
pool: server
timeoutInMinutes: 120 # 2 hours
steps:
- task: ManualValidation@1
timeoutInMinutes: 60 # 1 hour
inputs:
notifyUsers: '' # Required, but empty string allowed
allowApproversToApproveTheirOwnRuns: true
instructions: "Approve yank of ${{ artifact.name }}"
onTimeout: 'resume'

- job: YankCrates
displayName: "Yank Crates"
dependsOn: ManualApproval
condition: and(succeeded(), ne(variables['Skip.PublishPackage'], 'true'))
steps:
- template: /eng/common/pipelines/templates/steps/sparse-checkout.yml

- download: current
displayName: Download ${{parameters.PipelineArtifactName}} artifact
artifact: ${{parameters.PipelineArtifactName}}

- task: PowerShell@2
displayName: Yank Crates
env:
CARGO_REGISTRY_TOKEN: $(azure-sdk-cratesio-token)
inputs:
targetType: filePath
filePath: $(Build.SourcesDirectory)/eng/scripts/Yank-Crates.ps1
arguments:
-CrateNames '${{artifact.name}}'
-PackageInfoDirectory '$(Pipeline.Workspace)/${{parameters.PipelineArtifactName}}/PackageInfo'
7 changes: 5 additions & 2 deletions eng/pipelines/templates/stages/archetype-sdk-client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ extends:
ServiceDirectory: ${{ parameters.ServiceDirectory }}
PipelineArtifactName: packages
Artifacts: ${{ parameters.Artifacts }}
TestPipeline: ${{ eq(parameters.ServiceDirectory, 'canary') }}
TestPipeline: ${{ eq(parameters.ServiceDirectory, 'canary') }}
TestTimeoutInMinutes: ${{ parameters.TestTimeoutInMinutes }}
TestProxy: ${{ parameters.TestProxy }}
MatrixConfigs:
Expand Down Expand Up @@ -148,6 +148,9 @@ extends:
parameters:
DependsOn: "Build"
ServiceDirectory: ${{ parameters.ServiceDirectory }}
Artifacts: ${{ parameters.Artifacts }}
Artifacts:
- ${{ each artifact in parameters.Artifacts }}:
- ${{ if ne(artifact.releaseInBatch, 'false')}}:
- ${{ artifact }}
TestPipeline: ${{ eq(parameters.ServiceDirectory, 'canary') }}
PipelineArtifactName: packages
27 changes: 22 additions & 5 deletions eng/scripts/Language-Settings.ps1
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
$Language = "rust"
$LanguageDisplayName = "Rust"
$PackageRepository = "crates.io"
$packagePattern = "Cargo.toml"
$packagePattern = "*.crate"
#$MetadataUri = "https://raw.githubusercontent.com/Azure/azure-sdk/main/_data/releases/latest/rust-packages.csv"
$GithubUri = "https://github.com/Azure/azure-sdk-for-rust"
$PackageRepositoryUri = "https://crates.io/crates"
Expand Down Expand Up @@ -139,15 +139,32 @@ function Get-rust-AdditionalValidationPackagesFromPackageSet ($packagesWithChang
return $additionalPackages ?? @()
}

# $GetPackageInfoFromPackageFileFn = "Get-${Language}-PackageInfoFromPackageFile"
function Get-rust-PackageInfoFromPackageFile([IO.FileInfo]$pkg, [string]$workingDirectory) {
#$pkg will be a FileInfo object for the Cargo.toml file in a package artifact directory
$package = cargo read-manifest --manifest-path $pkg.FullName | ConvertFrom-Json
# Create a temporary folder for extraction
$extractionPath = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
New-Item -ItemType Directory -Path $extractionPath | Out-Null

# Extract the .crate file (which is a tarball) to the temporary folder
tar -xvf $pkg.FullName -C $extractionPath
$cargoTomlPath = Join-Path $extractionPath $pkg.BaseName 'Cargo.toml'

Write-Host "Reading package info from $cargoTomlPath"
if (!(Test-Path $cargoTomlPath)) {
$message = "The Cargo.toml file was not found in the package artifact at $cargoTomlPath"
LogError $message
throw $message
}

$package = cargo read-manifest --manifest-path $cargoTomlPath | ConvertFrom-Json

$packageName = $package.name
$packageVersion = $package.version

$changeLogLoc = Get-ChildItem -Path $pkg.DirectoryName -Filter "CHANGELOG.md" | Select-Object -First 1
$readmeContentLoc = Get-ChildItem -Path $pkg.DirectoryName -Filter "README.md" | Select-Object -First 1
$packageAssetPath = Join-Path $extractionPath "$packageName-$packageVersion"

$changeLogLoc = Get-ChildItem -Path $packageAssetPath -Filter "CHANGELOG.md" | Select-Object -First 1
$readmeContentLoc = Get-ChildItem -Path $packageAssetPath -Filter "README.md" | Select-Object -First 1

if ($changeLogLoc) {
$releaseNotes = Get-ChangeLogEntryAsString -ChangeLogLocation $changeLogLoc -VersionString $packageVersion
Expand Down
Loading