Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Commit d1068e3

Browse files
authored
Add nuget package pipeline (#13)
1 parent 792041f commit d1068e3

File tree

6 files changed

+290
-29
lines changed

6 files changed

+290
-29
lines changed

.azure-pipelines/powershell/BuildTools.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ function Compress-BuildOutput {
372372
if ($Cleanup) {
373373
foreach ($path in $Source) {
374374
Write-Verbose "Compress-BuildOutput: Cleaning up $path"
375-
Remove-Item $path -Force
375+
Remove-Item $path -Force -Recurse
376376
}
377377
}
378378

.azure-pipelines/release-cli.yaml

Lines changed: 212 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,17 @@ parameters:
4343
type: boolean
4444
default: false
4545
- name: notarizeAfterSign
46-
displayName: Notarize Build Output
46+
displayName: Notarize Build Output (MacOS only)
4747
type: boolean
4848
default: true
4949
- name: simulate
5050
displayName: Simulate operations (faster)
5151
type: boolean
5252
default: false
53+
- name: forceNugetPublish
54+
displayName: Force Publishing the Nuget output
55+
type: boolean
56+
default: false
5357

5458
# test ----------> | build -> | |
5559
# | | sign |
@@ -118,9 +122,10 @@ stages:
118122
- ${{ if ne(parameters.simulate, 'true') }}:
119123
- template: templates/nuget-packages.yaml
120124
parameters:
125+
extraRestoreArgs: -p:PublishReadyToRun=true
121126
vstsFeedName: ${{variables.internalFeed}}
122127

123-
- pwsh: dotnet publish ./src/msgraph-beta-cli.csproj --no-restore --runtime $(rid) --self-contained true --configuration $(buildConfiguration) --output $(outputDir)
128+
- pwsh: dotnet publish ./src/msgraph-beta-cli.csproj -p:PublishSingleFile=true -p:PublishReadyToRun=true --no-restore --runtime $(rid) --self-contained true --configuration $(buildConfiguration) --output $(outputDir)
124129
workingDirectory: $(Build.SourcesDirectory)
125130
condition: and(succeeded(), ne('${{ parameters.simulate }}', 'true'))
126131
displayName: DotNet publish
@@ -207,7 +212,7 @@ stages:
207212
vmImage: windows-latest
208213
dependsOn: [build]
209214
# Only sign binaries if we're building a tag.
210-
condition: and(succeeded(), or(eq('${{ parameters.forceSignOutput }}', 'true'), startsWith(variables['Build.SourceBranch'], 'refs/tags/v')))
215+
condition: and(succeeded(), or(eq('${{ parameters.forceSignOutput }}', 'true'), eq('${{ parameters.forceNugetPublish }}', 'true'), startsWith(variables['Build.SourceBranch'], 'refs/tags/v')))
211216
jobs:
212217
- job: esrpSign
213218
dependsOn: []
@@ -271,6 +276,71 @@ stages:
271276
}
272277
]
273278
inlineNotarizeOperation: ""
279+
nuget:
280+
rid: nuget
281+
vmImage: windows-latest
282+
packageType: "zip"
283+
compressionProgram: "none"
284+
sign: true
285+
forceNugetPublish: ${{ parameters.forceNugetPublish }}
286+
pattern: |
287+
mgc-beta.dll
288+
inlineSignOperation: |
289+
[
290+
{
291+
"keyCode": "CP-230012",
292+
"operationSetCode": "SigntoolSign",
293+
"parameters": [
294+
{
295+
"parameterName": "OpusName",
296+
"parameterValue": "Microsoft"
297+
},
298+
{
299+
"parameterName": "OpusInfo",
300+
"parameterValue": "http://www.microsoft.com"
301+
},
302+
{
303+
"parameterName": "FileDigest",
304+
"parameterValue": "/fd \"SHA256\""
305+
},
306+
{
307+
"parameterName": "PageHash",
308+
"parameterValue": "/NPH"
309+
},
310+
{
311+
"parameterName": "TimeStamp",
312+
"parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
313+
}
314+
],
315+
"toolName": "sign",
316+
"toolVersion": "1.0"
317+
},
318+
{
319+
"keyCode": "CP-230012",
320+
"operationSetCode": "SigntoolVerify",
321+
"parameters": [ ],
322+
"toolName": "sign",
323+
"toolVersion": "1.0"
324+
}
325+
]
326+
inlineNugetSignOperation: |
327+
[
328+
{
329+
"keyCode": "CP-401405",
330+
"operationSetCode": "NuGetSign",
331+
"parameters": [ ],
332+
"toolName": "sign",
333+
"toolVersion": "1.0"
334+
},
335+
{
336+
"keyCode": "CP-401405",
337+
"operationSetCode": "NuGetVerify",
338+
"parameters": [ ],
339+
"toolName": "sign",
340+
"toolVersion": "1.0"
341+
}
342+
]
343+
274344
'MacOS-x64':
275345
rid: osx-x64
276346
vmImage: macOS-11
@@ -304,18 +374,30 @@ stages:
304374
Write-Verbose 'fileNameTemplate = ''$(fileNameTemplate)'''
305375
Write-Verbose 'artifactsDownloadLocation = ''$(artifactsDownloadLocation)'''
306376
Write-Verbose 'sign = ''$(sign)'''
377+
Write-Verbose 'forceNugetPublish = ''$(forceNugetPublish)'''
307378
Write-Verbose 'notarize = ''$(notarize)'''
308379
Write-Verbose 'inlineSignOperation = ''$(inlineSignOperation)'''
309380
Write-Verbose 'inlineNotarizeOperation = ''$(inlineNotarizeOperation)'''
381+
Write-Verbose 'inlineNugetSignOperation = ''$(inlineNugetSignOperation)'''
310382
$rid = '$(rid)'
311383
$shouldSign = '$(sign)'
384+
if ($shouldSign.ToLower() -eq 'true' -and '$(rid)' -eq 'nuget') {
385+
$shouldSign = '$(forceNugetPublish)'
386+
}
312387
$shouldNotarize = '$(notarize)'
313388
$notarizeOp = '$(inlineNotarizeOperation)'
389+
$isNuget = $rid -eq 'nuget'
390+
$isDarwin = $rid.StartsWith('osx')
391+
$workDir = Join-Path -Path '$(artifactsDownloadLocation)' -ChildPath '$(rid)'
392+
$downloadDir = Join-Path -Path $workDir -ChildPath 'build-output-$(rid)'
314393
Write-Host "##vso[task.setvariable variable=RUNTIME_ID]$rid"
394+
Write-Host "##vso[task.setvariable variable=IS_NUGET]$isNuget"
395+
Write-Host "##vso[task.setvariable variable=IS_MACOS]$isDarwin"
315396
Write-Host "##vso[task.setvariable variable=SHOULD_SIGN]$shouldSign"
316397
Write-Host "##vso[task.setvariable variable=SHOULD_NOTARIZE]$shouldNotarize"
317398
Write-Host "##vso[task.setvariable variable=NOTARIZE_OPERATION]$notarizeOp"
318-
Write-Host "##vso[task.setvariable variable=WORKING_DIR]$(artifactsDownloadLocation)/$(rid)"
399+
Write-Host "##vso[task.setvariable variable=WORKING_DIR]$workDir"
400+
Write-Host "##vso[task.setvariable variable=ARTIFACTS_PATH]$downloadDir"
319401
verbosePreference: '$(OUTPUT_PREFERENCE)'
320402
debugPreference: '$(OUTPUT_PREFERENCE)'
321403
informationPreference: '$(OUTPUT_PREFERENCE)'
@@ -326,11 +408,62 @@ stages:
326408

327409
- checkout: self
328410

411+
# Nuget tool doesn't work with multi-stage builds
412+
- task: UseDotNet@2
413+
displayName: 'Use .NET 7'
414+
condition: and(succeeded(), ne('${{ parameters.simulate }}', 'true'), eq(variables['IS_NUGET'], 'true'))
415+
inputs:
416+
version: 7.x
417+
418+
- ${{ if ne(parameters.simulate, 'true') }}:
419+
- template: templates/nuget-packages.yaml
420+
parameters:
421+
vstsFeedName: ${{variables.internalFeed}}
422+
enabled: $(IS_NUGET)
423+
424+
- task: DotNetCoreCLI@2
425+
displayName: "build nuget tool"
426+
inputs:
427+
projects: './src/msgraph-beta-cli.csproj'
428+
arguments: " --no-restore --configuration $(buildConfiguration) --no-incremental"
429+
condition: and(succeeded(), ne('${{ parameters.simulate }}', 'true'), eq(variables['IS_NUGET'], 'true'))
430+
431+
- pwsh: |
432+
New-Item '$(ARTIFACTS_PATH)' -ItemType Directory -Force
433+
echo "Test file" > '$(ARTIFACTS_PATH)/mgc-beta.dll'
434+
echo "Test file2" > '$(ARTIFACTS_PATH)/mgc-beta.txt'
435+
condition: and(succeeded(), eq('${{ parameters.simulate }}', 'true'), eq(variables['IS_NUGET'], 'true'))
436+
displayName: Simulate nuget build
437+
329438
- task: DownloadPipelineArtifact@2
330439
inputs:
331440
patterns: build-output-$(rid)/**/*
332441
path: $(WORKING_DIR)
333-
condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'True'))
442+
condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'True'), ne(variables['IS_NUGET'], 'true'))
443+
444+
- task: PowerShell@2
445+
inputs:
446+
pwsh: true
447+
targetType: inline
448+
script: |
449+
$path = '$(ARTIFACTS_PATH)'
450+
if ('$(IS_NUGET)'.ToLower() -eq 'true' -and ('${{ parameters.simulate }}'.ToLower() -ne 'true')) {
451+
$path = './src/obj/$(buildConfiguration)/net7.0'
452+
}
453+
Write-Verbose "Checking if $path has files"
454+
$hasArtifacts = Test-Path $path/* -PathType Leaf
455+
Write-Verbose "Result $hasArtifacts"
456+
457+
$shouldSign = '$(SHOULD_SIGN)'.ToLower() -eq 'true'
458+
if ($shouldSign) {
459+
$shouldSign = $shouldSign -and $hasArtifacts
460+
}
461+
Write-Host "##vso[task.setvariable variable=SIGN_PATH]$path"
462+
Write-Host "##vso[task.setvariable variable=SHOULD_SIGN]$shouldSign"
463+
verbosePreference: '$(OUTPUT_PREFERENCE)'
464+
debugPreference: '$(OUTPUT_PREFERENCE)'
465+
informationPreference: '$(OUTPUT_PREFERENCE)'
466+
displayName: Check for artifacts
334467

335468
- task: PowerShell@2
336469
inputs:
@@ -344,6 +477,7 @@ stages:
344477
debugPreference: '$(OUTPUT_PREFERENCE)'
345478
informationPreference: '$(OUTPUT_PREFERENCE)'
346479
displayName: Compute zip name
480+
condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'True'), ne(variables['IS_NUGET'], 'true'))
347481

348482
- task: PowerShell@2
349483
inputs:
@@ -352,7 +486,7 @@ stages:
352486
script: |
353487
. $(powershellScriptsDir)/BuildTools.ps1
354488
355-
$downloadDir = Join-Path -Path '$(WORKING_DIR)' -ChildPath 'build-output-$(rid)'
489+
$downloadDir = '$(ARTIFACTS_PATH)'
356490
$extractPath = Join-Path -Path '$(WORKING_DIR)' -ChildPath artifacts
357491
Expand-EsrpArtifacts -SourceDir $downloadDir -OutputDir $extractPath -FileNameTemplate '$(fileNameTemplate)' -BranchOrTagName '$(branchOrTagName)' -RuntimeIdentifier '$(rid)' -PackageType $(packageType) -TarCompression $(compressionProgram) -Cleanup
358492
@@ -362,31 +496,39 @@ stages:
362496
debugPreference: '$(OUTPUT_PREFERENCE)'
363497
informationPreference: '$(OUTPUT_PREFERENCE)'
364498
displayName: Extract archive
365-
condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'True'))
499+
condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'True'), ne(variables['IS_NUGET'], 'True'))
366500

367501
- template: templates/prepare-unsigned-executable-darwin.yaml
368502
parameters:
369503
executablePath: $(ARTIFACTS_PATH)
370504
executableName: mgc-beta
371505
zipName: $(ZIP_NAME)
372506
targetRuntime: $(rid)
507+
enabled: $(IS_MACOS)
373508

374509
- pwsh: |
375510
Write-Host "##vso[task.setvariable variable=ESRP_FILE_PATTERN]$(ZIP_NAME)"
376511
displayName: Compute ESRP filter pattern osx
377-
condition: and(succeeded(), startsWith(variables['RUNTIME_ID'], 'osx'))
512+
condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'True'), eq(variables['IS_MACOS'], 'true'))
378513
379514
- pwsh: |
380515
Write-Host "##vso[task.setvariable variable=ESRP_FILE_PATTERN]$(pattern)"
381-
displayName: Compute ESRP filter pattern Windows
382-
condition: and(succeeded(), startsWith(variables['RUNTIME_ID'], 'win'))
516+
displayName: Compute ESRP filter pattern Windows/Nuget
517+
condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'True'), or(startsWith(variables['RUNTIME_ID'], 'win'), eq(variables['IS_NUGET'], 'true')))
518+
519+
# ESRP needs .NET 6
520+
- task: UseDotNet@2
521+
displayName: 'Change to .NET 6'
522+
condition: and(succeeded(), ne('${{ parameters.simulate }}', 'true'), eq(variables['IS_NUGET'], 'true'))
523+
inputs:
524+
version: 6.x
383525

384526
- task: EsrpCodeSigning@2
385-
displayName: 'ESRP CodeSigning (Sign)'
527+
displayName: 'ESRP CodeSigning (Sign Build output)'
386528
inputs:
387529
# Pipeline validation can't expand service name from matrix variables
388530
ConnectedServiceName: "microsoftgraph ESRP CodeSign DLL and NuGet (AKV)"
389-
FolderPath: $(ARTIFACTS_PATH)
531+
FolderPath: $(SIGN_PATH)
390532
signConfigType: inlineSignParams
391533
UseMinimatch: true
392534
Pattern: $(ESRP_FILE_PATTERN)
@@ -399,14 +541,38 @@ stages:
399541
inputs:
400542
# Pipeline validation can't expand service name from matrix variables
401543
ConnectedServiceName: "microsoftgraph ESRP CodeSign DLL and NuGet (AKV)"
402-
FolderPath: $(ARTIFACTS_PATH)
544+
FolderPath: $(SIGN_PATH)
403545
signConfigType: inlineSignParams
404546
UseMinimatch: true
405547
Pattern: $(ESRP_FILE_PATTERN)
406548
inlineOperation: $(inlineNotarizeOperation)
407549
SessionTimeout: 20
408550
condition: and(succeeded(), ne('${{ parameters.simulate }}', 'true'), gt(length(variables['NOTARIZE_OPERATION']), 0), ne(variables['NOTARIZE_OPERATION'], '$(inlineNotarizeOperation)'), and(eq(variables['SHOULD_SIGN'], 'True'), eq(variables['SHOULD_NOTARIZE'], 'True')))
409551

552+
- pwsh: |
553+
dotnet pack ./src/msgraph-beta-cli.csproj --configuration $(buildConfiguration) --output $(ARTIFACTS_PATH) --no-build --include-symbols --include-source /p:SymbolPackageFormat=snupkg -v d
554+
workingDirectory: $(Build.SourcesDirectory)
555+
displayName: DotNet pack (nuget)
556+
condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'True'), ne('${{ parameters.simulate }}', 'true'), eq(variables['Is_NUGET'], 'true'))
557+
558+
- task: EsrpCodeSigning@2
559+
displayName: 'ESRP CodeSigning (Sign Nuget)'
560+
inputs:
561+
# Pipeline validation can't expand service name from matrix variables
562+
ConnectedServiceName: "microsoftgraph ESRP CodeSign DLL and NuGet (AKV)"
563+
FolderPath: $(ARTIFACTS_PATH)
564+
signConfigType: inlineSignParams
565+
UseMinimatch: true
566+
Pattern: "*.nupkg"
567+
inlineOperation: $(inlineNugetSignOperation)
568+
SessionTimeout: 20
569+
condition: and(succeeded(), ne('${{ parameters.simulate }}', 'true'), eq(variables['SHOULD_SIGN'], 'True'), eq(variables['IS_NUGET'], 'true'))
570+
571+
- pwsh: |
572+
$artifactsPath = '$(ARTIFACTS_PATH)'
573+
Write-Host "##vso[task.setvariable variable=WORKING_DIR]$artifactsPath"
574+
condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'True'), eq(variables['IS_NUGET'], 'true'))
575+
410576
- task: PowerShell@2
411577
displayName: Simulate ESRP
412578
inputs:
@@ -435,7 +601,7 @@ stages:
435601
verbosePreference: '$(OUTPUT_PREFERENCE)'
436602
debugPreference: '$(OUTPUT_PREFERENCE)'
437603
informationPreference: '$(OUTPUT_PREFERENCE)'
438-
condition: and(succeeded(), eq('${{ parameters.simulate }}', 'true'))
604+
condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'True'), eq('${{ parameters.simulate }}', 'true'))
439605

440606
- task: PowerShell@2
441607
inputs:
@@ -478,7 +644,7 @@ stages:
478644
pool:
479645
vmImage: windows-latest
480646
# Only scan binaries if we're building a tag, building main, or building a PR targeting main
481-
condition: and(succeeded(), or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), eq(variables['Build.SourceBranch'], 'refs/heads/main'), eq(variables['System.PullRequest.TargetBranch'], 'main')))
647+
condition: and(succeeded(), or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), eq(variables['Build.SourceBranch'], 'refs/heads/main'), eq(variables['System.PullRequest.TargetBranch'], 'main'), eq('${{ parameters.forceNugetPublish }}', 'true')))
482648
jobs:
483649
- job: scan
484650
displayName: Scanning binaries
@@ -491,11 +657,12 @@ stages:
491657

492658
- stage: upload
493659
dependsOn: [binaryScan, sign]
494-
# Only upload release if we're building a tag.
495-
condition: and(succeeded(), ne('${{ parameters.simulate }}', 'true'), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
660+
condition: and(succeeded(), ne('${{ parameters.simulate }}', 'true'))
496661
jobs:
497-
- job: upload
498-
displayName: Upload binaries
662+
- job: uploadGitHub
663+
displayName: Upload binaries (GitHub)
664+
# Only upload release if we're building a tag.
665+
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
499666
steps:
500667
- checkout: none
501668
- task: DownloadPipelineArtifact@2
@@ -519,3 +686,29 @@ stages:
519686
$(artifactsDownloadLocation)/sign-output-*/*.tar*
520687
$(artifactsDownloadLocation)/sign-output-*/*.zip
521688
isPreRelease: $(IS_PREVIEW)
689+
690+
- deployment: deployNuget
691+
displayName: Deploy Nuget
692+
dependsOn: []
693+
environment: microsoftgraph-nuget-org
694+
condition: and(succeeded(), or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), eq('${{ parameters.forceNugetPublish }}', 'true')))
695+
strategy:
696+
runOnce:
697+
deploy:
698+
pool:
699+
vmImage: ubuntu-latest
700+
steps:
701+
- task: DownloadPipelineArtifact@2
702+
displayName: Download nupkg from artifacts
703+
inputs:
704+
artifact: sign-output-nuget
705+
source: current
706+
path: $(artifactsDownloadLocation)/nuget
707+
- task: NuGetCommand@2
708+
displayName: "NuGet push"
709+
inputs:
710+
command: push
711+
packagesToPush: "$(artifactsDownloadLocation)/nuget/Microsoft.Graph.Beta.Cli.*.nupkg;$(artifactsDownloadLocation)/nuget/Microsoft.Graph.Beta.Cli.*.snupkg;"
712+
nuGetFeedType: external
713+
publishFeedCredentials: "microsoftgraph NuGet connection"
714+

0 commit comments

Comments
 (0)