-
Notifications
You must be signed in to change notification settings - Fork 316
Add Manual OneBranch Release Stage & Publish Support (Internal/Public) #3761
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| ################################################################################# | ||
| # Licensed to the .NET Foundation under one or more agreements. # | ||
| # The .NET Foundation licenses this file to you under the MIT license. # | ||
| # See the LICENSE file in the project root for more information. # | ||
| ################################################################################# | ||
| parameters: | ||
| - name: approvalAliases | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should be documenting all parameters. Nothing fancy, just a sentence or two about what a parameter does. |
||
| type: string | ||
| default: '[ADO.Net]\\SqlClient Admins' | ||
|
|
||
| - name: publishDestination | ||
| type: string | ||
|
|
||
| - name: dryRun | ||
| type: boolean | ||
|
|
||
| - name: isPreview | ||
| type: boolean | ||
|
|
||
| - name: publishSymbols | ||
| type: boolean | ||
|
|
||
| - name: nugetPackageVersion | ||
| type: string | ||
|
|
||
| - name: product | ||
| type: string | ||
|
|
||
| jobs: | ||
| - job: AwaitApproval | ||
| displayName: 'Await Release Approval' | ||
| pool: server | ||
| steps: | ||
| - task: ManualValidation@0 | ||
| displayName: 'Manual Approval' | ||
| timeoutInMinutes: 4320 # 3 days | ||
| inputs: | ||
| notifyUsers: ${{ parameters.approvalAliases }} | ||
| instructions: | | ||
| Release Checklist: | ||
| * Destination: ${{ parameters.publishDestination }} | ||
| * Preview build: ${{ parameters.isPreview }} | ||
| * Dry run: ${{ parameters.dryRun }} | ||
| * Symbols: ${{ parameters.publishSymbols }} | ||
| * NuGet package version: ${{ parameters.nugetPackageVersion }} | ||
| * Product: ${{ parameters.product }} | ||
| Approve to continue or Reject to abort. | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,65 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ################################################################################# | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Licensed to the .NET Foundation under one or more agreements. # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # The .NET Foundation licenses this file to you under the MIT license. # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # See the LICENSE file in the project root for more information. # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ################################################################################# | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parameters: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: publishDestination | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: dryRun | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: boolean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: internalFeedSource | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: publicNuGetSource | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: publishSymbols | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: boolean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: packageFolderName | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: nugetPackageVersion | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: product | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - job: PublishPackages | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displayName: 'Publish Packages' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dependsOn: AwaitApproval | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should the approval step just live in this file? Is approval really a general task? It seems pretty specific to publishing packages. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| condition: succeeded() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pool: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vmImage: 'ubuntu-latest' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - task: DownloadPipelineArtifact@2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displayName: 'Download Signed Packages' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inputs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| buildType: current | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| artifactName: ${{ parameters.packageFolderName }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| targetPath: $(Pipeline.Workspace)/release/packages | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - script: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it also be helpful to list the contents of |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "NuGet Package Version: ${{ parameters.nugetPackageVersion }}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displayName: 'Echo NuGet Package Version' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - ${{ if ne(parameters.publishDestination, 'Public') }}: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - template: ../steps/publish-internal-feed-step.yml | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parameters: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dryRun: ${{ parameters.dryRun }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| internalFeedSource: ${{ parameters.internalFeedSource }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cheenamalhotra marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| packagesGlob: $(System.DefaultWorkingDirectory)/_dotnet-sqlclient-Official/drop_buildMDS_build_signed_package/*.nupkg | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For future consideration: We need to pick nicer names for these artifacts :) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - ${{ if eq(parameters.publishDestination, 'Public') }}: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer I would probably swap this to be: |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - template: ../steps/publish-public-nuget-step.yml | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parameters: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dryRun: ${{ parameters.dryRun }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| publicNuGetSource: ${{ parameters.publicNuGetSource }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cheenamalhotra marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| packagesGlob: $(System.DefaultWorkingDirectory)/_dotnet-sqlclient-Official/drop_buildMDS_build_signed_package/*.nupkg | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+53
to
+59
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| packagesGlob: $(System.DefaultWorkingDirectory)/_dotnet-sqlclient-Official/drop_buildMDS_build_signed_package/*.nupkg | |
| - ${{ if eq(parameters.publishDestination, 'Public') }}: | |
| - template: ../steps/publish-public-nuget-step.yml | |
| parameters: | |
| dryRun: ${{ parameters.dryRun }} | |
| publicNuGetSource: ${{ parameters.publicNuGetSource }} | |
| packagesGlob: $(System.DefaultWorkingDirectory)/_dotnet-sqlclient-Official/drop_buildMDS_build_signed_package/*.nupkg | |
| packagesGlob: $(Pipeline.Workspace)/release/packages/*.nupkg | |
| - ${{ if eq(parameters.publishDestination, 'Public') }}: | |
| - template: ../steps/publish-public-nuget-step.yml | |
| parameters: | |
| dryRun: ${{ parameters.dryRun }} | |
| publicNuGetSource: ${{ parameters.publicNuGetSource }} | |
| packagesGlob: $(Pipeline.Workspace)/release/packages/*.nupkg |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hardcoded artifact path $(System.DefaultWorkingDirectory)/_dotnet-sqlclient-Official/drop_buildMDS_build_signed_package/*.nupkg contains 'MDS' in the path but is used for all product types (MDS, MSS, AKV). This will fail when publishing MSS or AKV packages. The path should either be parameterized based on the product type or use the downloaded artifact location from line 44: $(Pipeline.Workspace)/release/packages/*.nupkg.
| packagesGlob: $(System.DefaultWorkingDirectory)/_dotnet-sqlclient-Official/drop_buildMDS_build_signed_package/*.nupkg | |
| - ${{ if eq(parameters.publishDestination, 'Public') }}: | |
| - template: ../steps/publish-public-nuget-step.yml | |
| parameters: | |
| dryRun: ${{ parameters.dryRun }} | |
| publicNuGetSource: ${{ parameters.publicNuGetSource }} | |
| packagesGlob: $(System.DefaultWorkingDirectory)/_dotnet-sqlclient-Official/drop_buildMDS_build_signed_package/*.nupkg | |
| packagesGlob: $(Pipeline.Workspace)/release/packages/*.nupkg | |
| - ${{ if eq(parameters.publishDestination, 'Public') }}: | |
| - template: ../steps/publish-public-nuget-step.yml | |
| parameters: | |
| dryRun: ${{ parameters.dryRun }} | |
| publicNuGetSource: ${{ parameters.publicNuGetSource }} | |
| packagesGlob: $(Pipeline.Workspace)/release/packages/*.nupkg |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The condition ne(parameters.dryRun, true) should use eq(parameters.dryRun, false) for consistency with other conditionals in the codebase, or the double-negative logic could be simplified. Additionally, this condition prevents symbol publishing during dry runs, but the individual steps within publish-symbols-step.yml already have their own conditions. Consider whether this outer condition is necessary or if it should be documented why symbols aren't published during dry runs.
| - ${{ if and(parameters.publishSymbols, ne(parameters.dryRun, true)) }}: | |
| # Only publish symbols if requested and not a dry run | |
| - ${{ if and(parameters.publishSymbols, eq(parameters.dryRun, false)) }}: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| ################################################################################# | ||
| # Licensed to the .NET Foundation under one or more agreements. # | ||
| # The .NET Foundation licenses this file to you under the MIT license. # | ||
| # See the LICENSE file in the project root for more information. # | ||
| ################################################################################# | ||
| parameters: | ||
| - name: runRelease | ||
| type: boolean | ||
| default: false | ||
|
|
||
| - name: publishDestination | ||
| type: string | ||
|
|
||
| - name: dryRun | ||
| type: boolean | ||
| default: false | ||
|
|
||
| - name: approvalAliases | ||
| type: string | ||
|
|
||
| - name: internalFeedSource | ||
| type: string | ||
|
|
||
| - name: publicNuGetSource | ||
| type: string | ||
|
|
||
| - name: publishSymbols | ||
| type: boolean | ||
| default: false | ||
|
|
||
| - name: isPreview | ||
| type: boolean | ||
|
|
||
| - name: product | ||
| type: string | ||
|
|
||
| - name: nugetPackageVersion | ||
| type: string | ||
|
|
||
| - name: packageFolderName | ||
| type: string | ||
|
|
||
| stages: | ||
| - stage: releaseMDS | ||
| displayName: 'Release (Manual)' | ||
| condition: and(succeeded(), eq(variables['Build.Reason'],'Manual'), eq(${{ parameters.runRelease }}, true)) | ||
| jobs: | ||
| - template: ../jobs/approval-job.yml | ||
| parameters: | ||
| approvalAliases: ${{ parameters.approvalAliases }} | ||
| publishDestination: ${{ parameters.publishDestination }} | ||
| dryRun: ${{ parameters.dryRun }} | ||
| isPreview: ${{ parameters.isPreview }} | ||
| publishSymbols: ${{ parameters.publishSymbols }} | ||
| nugetPackageVersion: ${{ parameters.nugetPackageVersion }} | ||
| product: ${{ parameters.product }} | ||
| - template: ../jobs/publish-packages-job.yml | ||
| parameters: | ||
| publishDestination: ${{ parameters.publishDestination }} | ||
| dryRun: ${{ parameters.dryRun }} | ||
| internalFeedSource: ${{ parameters.internalFeedSource }} | ||
| publicNuGetSource: ${{ parameters.publicNuGetSource }} | ||
| publishSymbols: ${{ parameters.publishSymbols }} | ||
| packageFolderName: ${{ parameters.packageFolderName }} | ||
| nugetPackageVersion: ${{ parameters.nugetPackageVersion }} | ||
| product: ${{ parameters.product }} |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,46 @@ | ||||||||||||||||||||||
| ################################################################################# | ||||||||||||||||||||||
| # Licensed to the .NET Foundation under one or more agreements. # | ||||||||||||||||||||||
| # The .NET Foundation licenses this file to you under the MIT license. # | ||||||||||||||||||||||
| # See the LICENSE file in the project root for more information. # | ||||||||||||||||||||||
| ################################################################################# | ||||||||||||||||||||||
| parameters: | ||||||||||||||||||||||
| - name: dryRun | ||||||||||||||||||||||
| type: boolean | ||||||||||||||||||||||
|
||||||||||||||||||||||
| type: boolean | |
| type: boolean | |
| default: false |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default value for packagesGlob is hardcoded to an MDS-specific path $(System.DefaultWorkingDirectory)/_dotnet-sqlclient-Official/drop_buildMDS_build_signed_package/*.nupkg. This should not have a default value with 'MDS' hardcoded, as this template is intended to be reusable for all product types (MDS, MSS, AKV). Consider removing the default or making it generic.
| default: '$(System.DefaultWorkingDirectory)/_dotnet-sqlclient-Official/drop_buildMDS_build_signed_package/*.nupkg' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we start putting these elaborate PowerShell scripts into files so we can:
- Read them easily (syntax highlighting etc).
- Run them (i.e. to test that they work).
- Version them separately from the pipeline files.
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message references ${{ parameters.publicNuGetSource }} but this parameter doesn't exist in this template. It should reference ${{ parameters.internalFeedSource }} instead to correctly show which feed is being targeted.
| echo "[DRY RUN] Listing packages targeted for push to: ${{ parameters.publicNuGetSource }}" | |
| echo "[DRY RUN] Listing packages targeted for push to: ${{ parameters.internalFeedSource }}" |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The find command is incorrectly used here. The first argument should be a directory path, not a glob pattern. This will fail when the script tries to execute. Consider using: find "$(dirname '${{ parameters.packagesGlob }}')" -type f -name "$(basename '${{ parameters.packagesGlob }}')" or a simpler approach with shell globbing like for f in ${{ parameters.packagesGlob }}; do.
| for f in $(find "${{ parameters.packagesGlob }}" -name "*.nupkg"); do | |
| for f in ${{ parameters.packagesGlob }}; do |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dry run logic only prints files but doesn't skip the actual push operation. When dryRun is true, the script should exit after listing files, or the push loop (lines 40-43) should be conditionally executed only when dryRun is false. Currently, packages will be pushed even in dry run mode.
| for f in $(find "${{ parameters.packagesGlob }}" -name "*.nupkg"); do | |
| echo "Push $f" | |
| dotnet nuget push --source "$SRC" --api-key az "$f" | |
| done | |
| if [ "${{ parameters.dryRun }}" != "true" ]; then | |
| for f in $(find "${{ parameters.packagesGlob }}" -name "*.nupkg"); do | |
| echo "Push $f" | |
| dotnet nuget push --source "$SRC" --api-key az "$f" | |
| done | |
| fi |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,52 @@ | ||||||||
| ################################################################################# | ||||||||
| # Licensed to the .NET Foundation under one or more agreements. # | ||||||||
| # The .NET Foundation licenses this file to you under the MIT license. # | ||||||||
| # See the LICENSE file in the project root for more information. # | ||||||||
| ################################################################################# | ||||||||
| parameters: | ||||||||
| - name: dryRun | ||||||||
| type: boolean | ||||||||
|
||||||||
| type: boolean | |
| type: boolean | |
| default: false |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default value for packagesGlob is hardcoded to an MDS-specific path $(System.DefaultWorkingDirectory)/_dotnet-sqlclient-Official/drop_buildMDS_build_signed_package/*.nupkg. This should not have a default value with 'MDS' hardcoded, as this template is intended to be reusable for all product types (MDS, MSS, AKV). Consider removing the default or making it generic.
| default: '$(System.DefaultWorkingDirectory)/_dotnet-sqlclient-Official/drop_buildMDS_build_signed_package/*.nupkg' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be surprised if the images we use don't have NuGet installed already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We seem to have two "jobs" directories, and it's not clear which jobs belong where. Just food for thought as we re-write the pipelines. It's hard to tell which files are used by which pipelines when they're all smushed into the same tree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I apologize for this. I made the new folders to separate the new (and model) pipelines from the old ones. For new (and properly built) pipelines, put stuff in eng/pipelines/jobs. Old stuff stays in eng/pipelines/common/templates/jobs.