Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
106 changes: 92 additions & 14 deletions .azure-pipelines/ci-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pr:
variables:
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
NuGetOrganizationName: 'openapinet'
privateFeedBaseUrl: 'https://microsoftgraph.pkgs.visualstudio.com/0985d294-5762-4bc2-a565-161ef349ca3e/_packaging/GraphDeveloperExperiences_Public'
ProductBinPath: '$(Build.SourcesDirectory)\src\Microsoft.OpenApi\bin\$(BuildConfiguration)'

resources:
Expand Down Expand Up @@ -81,7 +83,7 @@ extends:
<configuration>
<packageSources>
<clear />
<add key="GraphDeveloperExperiences_Public" value="https://microsoftgraph.pkgs.visualstudio.com/0985d294-5762-4bc2-a565-161ef349ca3e/_packaging/GraphDeveloperExperiences_Public/nuget/v3/index.json" />
<add key="GraphDeveloperExperiences_Public" value="$(privateFeedBaseUrl)/nuget/v3/index.json" />
</packageSources>
</configuration>
"@ | Set-Content -Path "$(Build.SourcesDirectory)/nuget.config" -Encoding UTF8
Expand Down Expand Up @@ -205,7 +207,16 @@ extends:
inputs:
targetFolder: $(Build.ArtifactStagingDirectory)/Nugets
sourceFolder: $(Build.ArtifactStagingDirectory)
content: '*.nupkg'
Contents: |
*.nupkg
*.snupkg

- task: CopyFiles@2
displayName: 'Include version-check script in Nugets artifact'
inputs:
SourceFolder: '$(Build.SourcesDirectory)/scripts'
Contents: 'check-nuget-package-published.ps1'
TargetFolder: '$(Build.ArtifactStagingDirectory)/Nugets/scripts'

- stage: deploy
condition: and(contains(variables['Build.SourceBranch'], 'refs/tags/v'), succeeded())
Expand All @@ -232,13 +243,47 @@ extends:
pool:
vmImage: ubuntu-latest
steps:
- task: 1ES.PublishNuget@1
displayName: 'NuGet push'
- task: PowerShell@2
displayName: 'Check whether NuGet package version already published (idempotent)'
inputs:
targetType: filePath
filePath: '$(Pipeline.Workspace)/scripts/check-nuget-package-published.ps1'
arguments: '-PackageId "Microsoft.OpenApi" -PackageDirectory "$(Pipeline.Workspace)" -NuGetServiceIndexUrl "$(privateFeedBaseUrl)/nuget/v3/index.json"'
pwsh: true
env:
FEED_ACCESS_TOKEN: $(System.AccessToken)
- task: CopyFiles@2
displayName: 'Stage OpenAPI NuGet packages for ESRP release'
condition: and(succeeded(), ne(variables['nugetAlreadyPublished'], 'true'))
inputs:
packagesToPush: '$(Pipeline.Workspace)/Microsoft.OpenApi.[0-9]*.nupkg'
packageParentPath: '$(Pipeline.Workspace)'
nuGetFeedType: external
publishFeedCredentials: 'OpenAPI Nuget Connection'
SourceFolder: '$(Pipeline.Workspace)'
Contents: |
Microsoft.OpenApi.*.nupkg
Microsoft.OpenApi.*.snupkg
!Microsoft.OpenApi.YamlReader.*
TargetFolder: '$(Pipeline.Workspace)/nuget-packages/$(NuGetOrganizationName)/openapi'
CleanTargetFolder: true
- task: EsrpRelease@14
displayName: 'ESRP Release - OpenAPI NuGet'
condition: and(succeeded(), ne(variables['nugetAlreadyPublished'], 'true'))
inputs:
connectedservicename: 'Federated DevX ESRP Managed Identity Connection'
usemanagedidentity: false
keyvaultname: 'akv-prod-eastus'
authcertname: 'ReferenceLibraryPrivateCert'
signcertname: 'ReferencePackagePublisherCertificate'
clientid: '65035b7f-7357-4f29-bf25-c5ee5c3949f8'
intent: 'packagedistribution'
contenttype: 'NuGet'
organizationname: '$(NuGetOrganizationName)'
contentsource: 'Folder'
folderlocation: '$(Pipeline.Workspace)/nuget-packages/$(NuGetOrganizationName)/openapi'
waitforreleasecompletion: true
owners: 'christiano@microsoft.com,ramsess@microsoft.com,gavinbarron@microsoft.com,jingjingjia@microsoft.com,peombwa@microsoft.com,treicys@microsoft.com'
approvers: 'christiano@microsoft.com,ramsess@microsoft.com,gavinbarron@microsoft.com,jingjingjia@microsoft.com,peombwa@microsoft.com,treicys@microsoft.com'
serviceendpointurl: 'https://api.esrp.microsoft.com/'
mainpublisher: 'ESRPRELPACMAN'
domaintenantid: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2'

- deployment: deploy_yaml_reader
condition: and(contains(variables['build.SourceBranch'], 'refs/tags/v'), succeeded())
Expand All @@ -257,13 +302,46 @@ extends:
pool:
vmImage: ubuntu-latest
steps:
- task: 1ES.PublishNuget@1
displayName: 'NuGet push'
- task: PowerShell@2
displayName: 'Check whether NuGet package version already published (idempotent)'
inputs:
targetType: filePath
filePath: '$(Pipeline.Workspace)/scripts/check-nuget-package-published.ps1'
arguments: '-PackageId "Microsoft.OpenApi.YamlReader" -PackageDirectory "$(Pipeline.Workspace)" -NuGetServiceIndexUrl "$(privateFeedBaseUrl)/nuget/v3/index.json"'
pwsh: true
env:
FEED_ACCESS_TOKEN: $(System.AccessToken)
- task: CopyFiles@2
displayName: 'Stage YAML reader NuGet packages for ESRP release'
condition: and(succeeded(), ne(variables['nugetAlreadyPublished'], 'true'))
inputs:
SourceFolder: '$(Pipeline.Workspace)'
Contents: |
Microsoft.OpenApi.YamlReader.*.nupkg
Microsoft.OpenApi.YamlReader.*.snupkg
TargetFolder: '$(Pipeline.Workspace)/nuget-packages/$(NuGetOrganizationName)/yaml-reader'
CleanTargetFolder: true
- task: EsrpRelease@14
displayName: 'ESRP Release - YAML reader NuGet'
condition: and(succeeded(), ne(variables['nugetAlreadyPublished'], 'true'))
inputs:
packagesToPush: '$(Pipeline.Workspace)/Microsoft.OpenApi.YamlReader.*.nupkg'
packageParentPath: '$(Pipeline.Workspace)'
nuGetFeedType: external
publishFeedCredentials: 'OpenAPI Nuget Connection'
connectedservicename: 'Federated DevX ESRP Managed Identity Connection'
usemanagedidentity: false
keyvaultname: 'akv-prod-eastus'
authcertname: 'ReferenceLibraryPrivateCert'
signcertname: 'ReferencePackagePublisherCertificate'
clientid: '65035b7f-7357-4f29-bf25-c5ee5c3949f8'
intent: 'packagedistribution'
contenttype: 'NuGet'
organizationname: '$(NuGetOrganizationName)'
contentsource: 'Folder'
folderlocation: '$(Pipeline.Workspace)/nuget-packages/$(NuGetOrganizationName)/yaml-reader'
waitforreleasecompletion: true
owners: 'christiano@microsoft.com,ramsess@microsoft.com,gavinbarron@microsoft.com,jingjingjia@microsoft.com,peombwa@microsoft.com,treicys@microsoft.com'
approvers: 'christiano@microsoft.com,ramsess@microsoft.com,gavinbarron@microsoft.com,jingjingjia@microsoft.com,peombwa@microsoft.com,treicys@microsoft.com'
serviceendpointurl: 'https://api.esrp.microsoft.com/'
mainpublisher: 'ESRPRELPACMAN'
domaintenantid: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2'

- deployment: create_github_release
condition: and(contains(variables['build.SourceBranch'], 'refs/tags/v'), succeeded())
Expand Down
84 changes: 84 additions & 0 deletions scripts/check-nuget-package-published.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

<#
.SYNOPSIS
Checks whether a NuGet artifact's version exists in an authenticated Azure Artifacts feed.
.DESCRIPTION
Resolves the package content endpoint from the private feed's NuGet v3 service index.
Sets nugetAlreadyPublished for the ESRP release steps; only a missing package or version
permits publishing. Feed authentication and other lookup failures fail the step.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$PackageDirectory,
[Parameter(Mandatory = $true)]
[string]$PackageId,
[Parameter(Mandatory = $true)]
[string]$NuGetServiceIndexUrl,
[string]$FeedAccessToken = $env:FEED_ACCESS_TOKEN
)

$ErrorActionPreference = 'Stop'

function Assert-PrivateFeedUrl {
param([string]$Url)

$uri = [uri]$Url
if (-not $uri.IsAbsoluteUri -or $uri.Scheme -ne 'https' -or
($uri.Host -ne 'pkgs.dev.azure.com' -and -not $uri.Host.EndsWith('.pkgs.visualstudio.com'))) {
throw "NuGet lookups must use an HTTPS Azure Artifacts feed: $Url"
}
}

Assert-PrivateFeedUrl -Url $NuGetServiceIndexUrl
if ([string]::IsNullOrWhiteSpace($FeedAccessToken)) {
throw 'FEED_ACCESS_TOKEN is required to query the private NuGet feed.'
}

$packagePattern = '^' + [regex]::Escape($PackageId) + '\.(\d[\w\.\-]*)\.nupkg$'
$packages = @(Get-ChildItem -Path $PackageDirectory -File -Filter "$PackageId.*.nupkg" |
Where-Object { $_.Name -match $packagePattern })
if ($packages.Count -ne 1) {
throw "Expected exactly one $PackageId nupkg to publish; found $($packages.Count)."
}
$version = [regex]::Match($packages[0].Name, $packagePattern, 'IgnoreCase').Groups[1].Value
$id = $PackageId.ToLowerInvariant()
$credentials = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("AzureDevOps:$FeedAccessToken"))
$headers = @{
'Authorization' = "Basic $credentials"
'User-Agent' = 'openapi-azdo-pipeline'
}

$index = Invoke-RestMethod -Uri $NuGetServiceIndexUrl -Headers $headers -MaximumRedirection 0
$resource = $index.resources | Where-Object { $_.'@type' -eq 'PackageBaseAddress/3.0.0' } | Select-Object -First 1
if ([string]::IsNullOrWhiteSpace($resource.'@id')) {
throw "No PackageBaseAddress resource found in the NuGet service index at $NuGetServiceIndexUrl"
}
$uri = "$($resource.'@id'.TrimEnd('/'))/$id/index.json"
Assert-PrivateFeedUrl -Url $uri

try {
$response = Invoke-RestMethod -Uri $uri -Headers $headers -MaximumRedirection 0
if ($null -eq $response.versions) {
throw "No versions returned for NuGet $id by the private feed."
}
$alreadyPublished = $response.versions -contains $version
}
catch {
if ([int]$_.Exception.Response.StatusCode -eq 404) {
$alreadyPublished = $false
}
else {
throw
}
}

if ($alreadyPublished) {
Write-Host "NuGet $id $version already present in the private feed; skipping ESRP release (idempotent re-run)."
}
else {
Write-Host "NuGet $id $version not found in the private feed; will publish via ESRP."
}
Write-Host "##vso[task.setvariable variable=nugetAlreadyPublished]$($alreadyPublished.ToString().ToLowerInvariant())"
Loading