dotnet-ado-publish
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesedotnet-ado-publish
dotnet-ado-publish
Publishing pipelines for .NET projects in Azure DevOps: NuGet package push to Azure Artifacts and nuget.org, container image build and push to Azure Container Registry (ACR) using , artifact staging with and , and pipeline artifacts for multi-stage release pipelines.
Docker@2PublishBuildArtifacts@1PublishPipelineArtifact@1Version assumptions: for pack/push operations. for container image builds. for NuGet push to external feeds. (preferred over ).
DotNetCoreCLI@2Docker@2NuGetCommand@2PublishPipelineArtifact@1PublishBuildArtifacts@1针对Azure DevOps中.NET项目的发布管道:将NuGet包推送至Azure Artifacts和nuget.org,使用构建并推送容器镜像至Azure Container Registry (ACR),通过和进行工件暂存,以及为多阶段发布管道提供管道工件支持。
Docker@2PublishBuildArtifacts@1PublishPipelineArtifact@1版本前提:打包/推送操作使用;容器镜像构建使用;推送NuGet包至外部源使用;推荐使用(优于)。
DotNetCoreCLI@2Docker@2NuGetCommand@2PublishPipelineArtifact@1PublishBuildArtifacts@1Scope
适用范围
- NuGet package push to Azure Artifacts and nuget.org
- Container image build and push to ACR using Docker@2
- Artifact staging with PublishPipelineArtifact@1
- Pipeline artifacts for multi-stage release pipelines
- 将NuGet包推送至Azure Artifacts和nuget.org
- 使用Docker@2构建并推送容器镜像至ACR
- 通过PublishPipelineArtifact@1进行工件暂存
- 为多阶段发布管道提供管道工件支持
Out of scope
不适用范围
- Container image authoring (Dockerfile, base image selection) -- see [skill:dotnet-containers]
- Native AOT MSBuild configuration -- see [skill:dotnet-native-aot]
- CLI release pipelines -- see [skill:dotnet-cli-release-pipeline]
- Starter CI templates -- see [skill:dotnet-add-ci]
- GitHub Actions publishing -- see [skill:dotnet-gha-publish]
- ADO-unique features (environments, service connections) -- see [skill:dotnet-ado-unique]
Cross-references: [skill:dotnet-containers] for container image authoring and SDK container properties, [skill:dotnet-native-aot] for AOT publish configuration in CI, [skill:dotnet-cli-release-pipeline] for CLI-specific release automation, [skill:dotnet-add-ci] for starter publish templates.
- 容器镜像编写(Dockerfile、基础镜像选择)——详见[skill:dotnet-containers]
- Native AOT MSBuild配置——详见[skill:dotnet-native-aot]
- CLI发布管道——详见[skill:dotnet-cli-release-pipeline]
- 入门CI模板——详见[skill:dotnet-add-ci]
- GitHub Actions发布——详见[skill:dotnet-gha-publish]
- Azure DevOps独有功能(环境、服务连接)——详见[skill:dotnet-ado-unique]
交叉参考:容器镜像编写和SDK容器属性详见[skill:dotnet-containers],CI中的AOT发布配置详见[skill:dotnet-native-aot],CLI专属发布自动化详见[skill:dotnet-cli-release-pipeline],入门发布模板详见[skill:dotnet-add-ci]。
NuGet Push to Azure Artifacts
推送NuGet包至Azure Artifacts
Push with DotNetCoreCLI@2
DotNetCoreCLI@2使用DotNetCoreCLI@2
推送
DotNetCoreCLI@2yaml
trigger:
tags:
include:
- 'v*'
stages:
- stage: Pack
jobs:
- job: PackJob
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: 'Pack'
inputs:
command: 'pack'
packagesToPack: 'src/**/*.csproj'
configuration: 'Release'
outputDir: '$(Build.ArtifactStagingDirectory)/nupkgs'
versioningScheme: 'byEnvVar'
versionEnvVar: 'PACKAGE_VERSION'
env:
PACKAGE_VERSION: $(Build.SourceBranchName)
- task: PublishPipelineArtifact@1
displayName: 'Upload NuGet packages'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/nupkgs'
artifactName: 'nupkgs'
- stage: PushToFeed
dependsOn: Pack
jobs:
- job: PushJob
pool:
vmImage: 'ubuntu-latest'
steps:
- download: current
artifact: nupkgs
- task: NuGetAuthenticate@1
displayName: 'Authenticate NuGet'
- task: DotNetCoreCLI@2
displayName: 'Push to Azure Artifacts'
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/nupkgs/*.nupkg'
nuGetFeedType: 'internal'
publishVstsFeed: 'MyProject/MyFeed'yaml
trigger:
tags:
include:
- 'v*'
stages:
- stage: Pack
jobs:
- job: PackJob
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: 'Pack'
inputs:
command: 'pack'
packagesToPack: 'src/**/*.csproj'
configuration: 'Release'
outputDir: '$(Build.ArtifactStagingDirectory)/nupkgs'
versioningScheme: 'byEnvVar'
versionEnvVar: 'PACKAGE_VERSION'
env:
PACKAGE_VERSION: $(Build.SourceBranchName)
- task: PublishPipelineArtifact@1
displayName: 'Upload NuGet packages'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/nupkgs'
artifactName: 'nupkgs'
- stage: PushToFeed
dependsOn: Pack
jobs:
- job: PushJob
pool:
vmImage: 'ubuntu-latest'
steps:
- download: current
artifact: nupkgs
- task: NuGetAuthenticate@1
displayName: 'Authenticate NuGet'
- task: DotNetCoreCLI@2
displayName: 'Push to Azure Artifacts'
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/nupkgs/*.nupkg'
nuGetFeedType: 'internal'
publishVstsFeed: 'MyProject/MyFeed'Version from Git Tag
从Git Tag获取版本号
Extract the version from the triggering Git tag using a script step. is a runtime variable, so use a script to parse it rather than compile-time template expressions:
Build.SourceBranchyaml
steps:
- script: |
set -euo pipefail
if [[ "$(Build.SourceBranch)" == refs/tags/v* ]]; then
VERSION="${BUILD_SOURCEBRANCH#refs/tags/v}"
else
VERSION="0.0.0-ci.$(Build.BuildId)"
fi
echo "##vso[task.setvariable variable=packageVersion]$VERSION"
displayName: 'Extract version from tag'
- task: DotNetCoreCLI@2
displayName: 'Pack'
inputs:
command: 'pack'
packagesToPack: 'src/**/*.csproj'
configuration: 'Release'
outputDir: '$(Build.ArtifactStagingDirectory)/nupkgs'
arguments: '-p:Version=$(packageVersion)'通过脚本步骤从触发的Git Tag中提取版本号。是运行时变量,因此需使用脚本来解析,而非编译时模板表达式:
Build.SourceBranchyaml
steps:
- script: |
set -euo pipefail
if [[ "$(Build.SourceBranch)" == refs/tags/v* ]]; then
VERSION="${BUILD_SOURCEBRANCH#refs/tags/v}"
else
VERSION="0.0.0-ci.$(Build.BuildId)"
fi
echo "##vso[task.setvariable variable=packageVersion]$VERSION"
displayName: 'Extract version from tag'
- task: DotNetCoreCLI@2
displayName: 'Pack'
inputs:
command: 'pack'
packagesToPack: 'src/**/*.csproj'
configuration: 'Release'
outputDir: '$(Build.ArtifactStagingDirectory)/nupkgs'
arguments: '-p:Version=$(packageVersion)'NuGet Push to nuget.org
推送NuGet包至nuget.org
Push with NuGetCommand@2
NuGetCommand@2使用NuGetCommand@2
推送
NuGetCommand@2For pushing to external NuGet feeds (nuget.org), use a service connection:
yaml
- task: NuGetCommand@2
displayName: 'Push to nuget.org'
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/nupkgs/*.nupkg'
nuGetFeedType: 'external'
publishFeedCredentials: 'NuGetOrgServiceConnection'The service connection stores the nuget.org API key securely. Create it in Project Settings > Service Connections > NuGet.
推送至外部NuGet源(如nuget.org)时,需使用服务连接:
yaml
- task: NuGetCommand@2
displayName: 'Push to nuget.org'
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/nupkgs/*.nupkg'
nuGetFeedType: 'external'
publishFeedCredentials: 'NuGetOrgServiceConnection'服务连接会安全存储nuget.org的API密钥。可在项目设置 > 服务连接 > NuGet中创建。
Conditional Push (Stable vs Pre-Release)
条件推送(正式版 vs 预发布版)
yaml
- task: NuGetCommand@2
displayName: 'Push to nuget.org (stable only)'
condition: and(succeeded(), not(contains(variables['packageVersion'], '-')))
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/nupkgs/*.nupkg'
nuGetFeedType: 'external'
publishFeedCredentials: 'NuGetOrgServiceConnection'
- task: DotNetCoreCLI@2
displayName: 'Push to Azure Artifacts (all versions)'
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/nupkgs/*.nupkg'
nuGetFeedType: 'internal'
publishVstsFeed: 'MyProject/MyFeed'Pre-release versions (containing like ) go only to Azure Artifacts; stable versions go to both feeds.
-1.2.3-preview.1yaml
- task: NuGetCommand@2
displayName: 'Push to nuget.org (stable only)'
condition: and(succeeded(), not(contains(variables['packageVersion'], '-')))
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/nupkgs/*.nupkg'
nuGetFeedType: 'external'
publishFeedCredentials: 'NuGetOrgServiceConnection'
- task: DotNetCoreCLI@2
displayName: 'Push to Azure Artifacts (all versions)'
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/nupkgs/*.nupkg'
nuGetFeedType: 'internal'
publishVstsFeed: 'MyProject/MyFeed'预发布版本(包含,如)仅推送至Azure Artifacts;正式版本则同时推送至两个源。
-1.2.3-preview.1Skip Duplicate Packages
跳过重复包
yaml
- task: DotNetCoreCLI@2
displayName: 'Push (skip duplicates)'
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/nupkgs/*.nupkg'
nuGetFeedType: 'internal'
publishVstsFeed: 'MyProject/MyFeed'
continueOnError: true # Azure Artifacts returns 409 for duplicatesAzure Artifacts returns HTTP 409 for duplicate package versions. Use for idempotent pipeline reruns, or configure the feed to allow overwriting pre-release versions in Feed Settings.
continueOnError: trueyaml
- task: DotNetCoreCLI@2
displayName: 'Push (skip duplicates)'
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/nupkgs/*.nupkg'
nuGetFeedType: 'internal'
publishVstsFeed: 'MyProject/MyFeed'
continueOnError: true # Azure Artifacts returns 409 for duplicates当包版本重复时,Azure Artifacts会返回HTTP 409状态码。对于支持幂等性的管道重跑,可使用,或在源设置中配置允许覆盖预发布版本。
continueOnError: trueContainer Image Build and Push to ACR
构建并推送容器镜像至ACR
Docker@2
Task
Docker@2Docker@2
任务
Docker@2Build and push a container image to Azure Container Registry. See [skill:dotnet-containers] for Dockerfile authoring guidance:
yaml
stages:
- stage: BuildContainer
jobs:
- job: DockerBuild
pool:
vmImage: 'ubuntu-latest'
steps:
- task: Docker@2
displayName: 'Login to ACR'
inputs:
command: 'login'
containerRegistry: 'MyACRServiceConnection'
- task: Docker@2
displayName: 'Build and push'
inputs:
command: 'buildAndPush'
repository: 'myapp'
containerRegistry: 'MyACRServiceConnection'
dockerfile: 'src/MyApp/Dockerfile'
buildContext: '.'
tags: |
$(Build.BuildId)
latest构建容器镜像并推送至Azure Container Registry。Dockerfile编写指导详见[skill:dotnet-containers]:
yaml
stages:
- stage: BuildContainer
jobs:
- job: DockerBuild
pool:
vmImage: 'ubuntu-latest'
steps:
- task: Docker@2
displayName: 'Login to ACR'
inputs:
command: 'login'
containerRegistry: 'MyACRServiceConnection'
- task: Docker@2
displayName: 'Build and push'
inputs:
command: 'buildAndPush'
repository: 'myapp'
containerRegistry: 'MyACRServiceConnection'
dockerfile: 'src/MyApp/Dockerfile'
buildContext: '.'
tags: |
$(Build.BuildId)
latestTagging Strategy
标签策略
yaml
- task: Docker@2
displayName: 'Build and push with semver tags'
inputs:
command: 'buildAndPush'
repository: 'myapp'
containerRegistry: 'MyACRServiceConnection'
dockerfile: 'src/MyApp/Dockerfile'
buildContext: '.'
tags: |
$(packageVersion)
$(Build.SourceVersion)
latestUse semantic version tags for release images and commit SHA tags for traceability. The tag should only be applied to stable releases.
latestyaml
- task: Docker@2
displayName: 'Build and push with semver tags'
inputs:
command: 'buildAndPush'
repository: 'myapp'
containerRegistry: 'MyACRServiceConnection'
dockerfile: 'src/MyApp/Dockerfile'
buildContext: '.'
tags: |
$(packageVersion)
$(Build.SourceVersion)
latest正式版镜像使用语义化版本标签,为了可追溯性同时使用提交SHA标签。标签仅应应用于正式发布版本。
latestSDK Container Publish (Dockerfile-Free)
SDK容器发布(无需Dockerfile)
Use .NET SDK container publish for projects without a Dockerfile. See [skill:dotnet-containers] for MSBuild configuration:
PublishContaineryaml
- task: Docker@2
displayName: 'Login to ACR'
inputs:
command: 'login'
containerRegistry: 'MyACRServiceConnection'
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '8.0.x'
- script: |
dotnet publish src/MyApp/MyApp.csproj \
-c Release \
-p:PublishProfile=DefaultContainer \
-p:ContainerRegistry=$(ACR_LOGIN_SERVER) \
-p:ContainerRepository=myapp \
-p:ContainerImageTags='"$(packageVersion);latest"'
displayName: 'Publish container via SDK'
env:
ACR_LOGIN_SERVER: $(acrLoginServer)对于没有Dockerfile的项目,可使用.NET SDK容器发布功能。的MSBuild配置详见[skill:dotnet-containers]:
PublishContaineryaml
- task: Docker@2
displayName: 'Login to ACR'
inputs:
command: 'login'
containerRegistry: 'MyACRServiceConnection'
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '8.0.x'
- script: |
dotnet publish src/MyApp/MyApp.csproj \
-c Release \
-p:PublishProfile=DefaultContainer \
-p:ContainerRegistry=$(ACR_LOGIN_SERVER) \
-p:ContainerRepository=myapp \
-p:ContainerImageTags='"$(packageVersion);latest"'
displayName: 'Publish container via SDK'
env:
ACR_LOGIN_SERVER: $(acrLoginServer)Native AOT Container Publish
Native AOT容器发布
Publish a Native AOT binary as a container image. AOT configuration is owned by [skill:dotnet-native-aot]; this shows the CI pipeline step only:
yaml
- script: |
dotnet publish src/MyApp/MyApp.csproj \
-c Release \
-r linux-x64 \
-p:PublishAot=true \
-p:PublishProfile=DefaultContainer \
-p:ContainerRegistry=$(ACR_LOGIN_SERVER) \
-p:ContainerRepository=myapp \
-p:ContainerBaseImage=mcr.microsoft.com/dotnet/runtime-deps:8.0-noble-chiseled \
-p:ContainerImageTags='"$(packageVersion)"'
displayName: 'Publish AOT container'The base image is sufficient for AOT binaries since they include the runtime. See [skill:dotnet-native-aot] for AOT MSBuild properties and [skill:dotnet-containers] for base image selection.
runtime-deps将Native AOT二进制文件发布为容器镜像。AOT配置由[skill:dotnet-native-aot]负责;以下仅展示CI管道步骤:
yaml
- script: |
dotnet publish src/MyApp/MyApp.csproj \
-c Release \
-r linux-x64 \
-p:PublishAot=true \
-p:PublishProfile=DefaultContainer \
-p:ContainerRegistry=$(ACR_LOGIN_SERVER) \
-p:ContainerRepository=myapp \
-p:ContainerBaseImage=mcr.microsoft.com/dotnet/runtime-deps:8.0-noble-chiseled \
-p:ContainerImageTags='"$(packageVersion)"'
displayName: 'Publish AOT container'由于AOT二进制文件已包含运行时,因此使用基础镜像即可。AOT的MSBuild属性详见[skill:dotnet-native-aot],基础镜像选择详见[skill:dotnet-containers]。
runtime-depsArtifact Staging
工件暂存
PublishPipelineArtifact@1
(Recommended)
PublishPipelineArtifact@1PublishPipelineArtifact@1
(推荐)
PublishPipelineArtifact@1Pipeline artifacts are the modern replacement for build artifacts, offering faster upload/download and deduplication:
yaml
steps:
- task: DotNetCoreCLI@2
displayName: 'Publish app'
inputs:
command: 'publish'
projects: 'src/MyApp/MyApp.csproj'
arguments: '-c Release -o $(Build.ArtifactStagingDirectory)/app'
- task: PublishPipelineArtifact@1
displayName: 'Upload app artifact'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/app'
artifactName: 'app'
- task: PublishPipelineArtifact@1
displayName: 'Upload NuGet packages'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/nupkgs'
artifactName: 'nupkgs'管道工件是构建工件的现代替代方案,提供更快的上传/下载速度和重复数据删除功能:
yaml
steps:
- task: DotNetCoreCLI@2
displayName: 'Publish app'
inputs:
command: 'publish'
projects: 'src/MyApp/MyApp.csproj'
arguments: '-c Release -o $(Build.ArtifactStagingDirectory)/app'
- task: PublishPipelineArtifact@1
displayName: 'Upload app artifact'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/app'
artifactName: 'app'
- task: PublishPipelineArtifact@1
displayName: 'Upload NuGet packages'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/nupkgs'
artifactName: 'nupkgs'PublishBuildArtifacts@1
(Legacy)
PublishBuildArtifacts@1PublishBuildArtifacts@1
(旧版)
PublishBuildArtifacts@1Use only when integrating with classic release pipelines that require build artifacts:
yaml
- task: PublishBuildArtifacts@1
displayName: 'Upload build artifact (legacy)'
inputs:
pathToPublish: '$(Build.ArtifactStagingDirectory)/app'
artifactName: 'app'
publishLocation: 'Container'仅在与需要构建工件的经典发布管道集成时使用:
yaml
- task: PublishBuildArtifacts@1
displayName: 'Upload build artifact (legacy)'
inputs:
pathToPublish: '$(Build.ArtifactStagingDirectory)/app'
artifactName: 'app'
publishLocation: 'Container'Downloading Artifacts in Downstream Stages
在下游阶段下载工件
yaml
stages:
- stage: Build
jobs:
- job: BuildJob
steps:
- script: dotnet publish -c Release -o $(Build.ArtifactStagingDirectory)/app
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/app'
artifactName: 'app'
- stage: Deploy
dependsOn: Build
jobs:
- deployment: DeployJob
environment: 'staging'
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: app
- script: echo "Deploying from $(Pipeline.Workspace)/app"The keyword downloads artifacts from the current pipeline run. Use for artifacts from a different pipeline.
download: currentdownload: pipelineNameyaml
stages:
- stage: Build
jobs:
- job: BuildJob
steps:
- script: dotnet publish -c Release -o $(Build.ArtifactStagingDirectory)/app
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/app'
artifactName: 'app'
- stage: Deploy
dependsOn: Build
jobs:
- deployment: DeployJob
environment: 'staging'
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: app
- script: echo "Deploying from $(Pipeline.Workspace)/app"download: currentdownload: pipelineNamePipeline Artifacts for Release Pipelines
发布管道的管道工件
Multi-Stage Release with Artifact Promotion
带有工件晋升的多阶段发布
yaml
trigger:
tags:
include:
- 'v*'
stages:
- stage: Build
jobs:
- job: BuildAndPack
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: 'Build'
inputs:
command: 'build'
projects: 'MyApp.sln'
arguments: '-c Release'
- task: DotNetCoreCLI@2
displayName: 'Publish'
inputs:
command: 'publish'
projects: 'src/MyApp/MyApp.csproj'
arguments: '-c Release -o $(Build.ArtifactStagingDirectory)/app'
- task: DotNetCoreCLI@2
displayName: 'Pack'
inputs:
command: 'pack'
packagesToPack: 'src/MyLibrary/MyLibrary.csproj'
configuration: 'Release'
outputDir: '$(Build.ArtifactStagingDirectory)/nupkgs'
- task: PublishPipelineArtifact@1
displayName: 'Upload app'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/app'
artifactName: 'app'
- task: PublishPipelineArtifact@1
displayName: 'Upload packages'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/nupkgs'
artifactName: 'nupkgs'
- stage: DeployStaging
dependsOn: Build
jobs:
- deployment: DeployStaging
environment: 'staging'
pool:
vmImage: 'ubuntu-latest'
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: app
- script: echo "Deploying to staging from $(Pipeline.Workspace)/app"
- stage: PublishPackages
dependsOn: DeployStaging
jobs:
- job: PushPackages
pool:
vmImage: 'ubuntu-latest'
steps:
- download: current
artifact: nupkgs
- task: NuGetAuthenticate@1
- task: NuGetCommand@2
displayName: 'Push to nuget.org'
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/nupkgs/*.nupkg'
nuGetFeedType: 'external'
publishFeedCredentials: 'NuGetOrgServiceConnection'
- stage: DeployProduction
dependsOn: DeployStaging
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: DeployProduction
environment: 'production'
pool:
vmImage: 'ubuntu-latest'
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: app
- script: echo "Deploying to production from $(Pipeline.Workspace)/app"yaml
trigger:
tags:
include:
- 'v*'
stages:
- stage: Build
jobs:
- job: BuildAndPack
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: 'Build'
inputs:
command: 'build'
projects: 'MyApp.sln'
arguments: '-c Release'
- task: DotNetCoreCLI@2
displayName: 'Publish'
inputs:
command: 'publish'
projects: 'src/MyApp/MyApp.csproj'
arguments: '-c Release -o $(Build.ArtifactStagingDirectory)/app'
- task: DotNetCoreCLI@2
displayName: 'Pack'
inputs:
command: 'pack'
packagesToPack: 'src/MyLibrary/MyLibrary.csproj'
configuration: 'Release'
outputDir: '$(Build.ArtifactStagingDirectory)/nupkgs'
- task: PublishPipelineArtifact@1
displayName: 'Upload app'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/app'
artifactName: 'app'
- task: PublishPipelineArtifact@1
displayName: 'Upload packages'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/nupkgs'
artifactName: 'nupkgs'
- stage: DeployStaging
dependsOn: Build
jobs:
- deployment: DeployStaging
environment: 'staging'
pool:
vmImage: 'ubuntu-latest'
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: app
- script: echo "Deploying to staging from $(Pipeline.Workspace)/app"
- stage: PublishPackages
dependsOn: DeployStaging
jobs:
- job: PushPackages
pool:
vmImage: 'ubuntu-latest'
steps:
- download: current
artifact: nupkgs
- task: NuGetAuthenticate@1
- task: NuGetCommand@2
displayName: 'Push to nuget.org'
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/nupkgs/*.nupkg'
nuGetFeedType: 'external'
publishFeedCredentials: 'NuGetOrgServiceConnection'
- stage: DeployProduction
dependsOn: DeployStaging
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: DeployProduction
environment: 'production'
pool:
vmImage: 'ubuntu-latest'
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: app
- script: echo "Deploying to production from $(Pipeline.Workspace)/app"Cross-Pipeline Artifact Consumption
跨管道工件消费
Consume artifacts from a different pipeline (e.g., a shared build pipeline):
yaml
resources:
pipelines:
- pipeline: buildPipeline
source: 'MyApp-Build'
trigger:
branches:
include:
- main
stages:
- stage: Deploy
jobs:
- deployment: DeployFromBuild
environment: 'staging'
strategy:
runOnce:
deploy:
steps:
- download: buildPipeline
artifact: app
- script: echo "Deploying from $(Pipeline.Workspace)/buildPipeline/app"从其他管道(如共享构建管道)消费工件:
yaml
resources:
pipelines:
- pipeline: buildPipeline
source: 'MyApp-Build'
trigger:
branches:
include:
- main
stages:
- stage: Deploy
jobs:
- deployment: DeployFromBuild
environment: 'staging'
strategy:
runOnce:
deploy:
steps:
- download: buildPipeline
artifact: app
- script: echo "Deploying from $(Pipeline.Workspace)/buildPipeline/app"Agent Gotchas
代理注意事项
- Use over
PublishPipelineArtifact@1-- pipeline artifacts are faster, support deduplication, and work with multi-stage YAML pipelines; build artifacts are legacy and required only for classic release pipelines.PublishBuildArtifacts@1 - Azure Artifacts returns 409 for duplicate package versions -- use for idempotent reruns, or handle duplicates in feed settings by allowing pre-release version overwrites.
continueOnError: true - with
NuGetCommand@2feed type requires a service connection -- do not hardcode API keys in pipeline YAML; create a NuGet service connection in Project Settings that stores the key securely.external - SDK container publish requires Docker on the agent -- with
dotnet publishneeds Docker; hostedPublishProfile=DefaultContaineragents include Docker, but self-hosted agents may not.ubuntu-latest - AOT publish requires matching RID -- must match the agent OS; do not use
dotnet publish -r linux-x64on a Linux agent.-r win-x64 - uses
download: currentnot$(Pipeline.Workspace)-- artifacts downloaded in deployment jobs are at$(Build.ArtifactStagingDirectory), not the staging directory.$(Pipeline.Workspace)/artifactName - Never hardcode registry credentials in pipeline YAML -- use Docker service connections for ACR/DockerHub authentication; service connections store credentials securely and rotate independently.
- Tag triggers require explicit in the trigger section -- tags are not included by default CI triggers; add
tags.includeto trigger on version tags.tags: include: ['v*']
- 优先使用而非
PublishPipelineArtifact@1——管道工件速度更快,支持重复数据删除,适用于多阶段YAML管道;构建工件属于旧版功能,仅在与经典发布管道集成时才需要使用。PublishBuildArtifacts@1 - Azure Artifacts对重复包版本返回409状态码——对于支持幂等性的重跑,可使用,或在源设置中配置允许覆盖预发布版本。
continueOnError: true - 使用推送至外部源需要服务连接——请勿在管道YAML中硬编码API密钥;应在项目设置中创建NuGet服务连接,安全存储密钥。
NuGetCommand@2 - SDK容器发布需要代理上安装Docker——使用的
PublishProfile=DefaultContainer命令依赖Docker;托管的dotnet publish代理已包含Docker,但自托管代理可能未安装。ubuntu-latest - AOT发布需要匹配RID——必须与代理操作系统匹配;请勿在Linux代理上使用
dotnet publish -r linux-x64。-r win-x64 - 使用
download: current而非$(Pipeline.Workspace)——部署作业中下载的工件存储在$(Build.ArtifactStagingDirectory),而非暂存目录。$(Pipeline.Workspace)/artifactName - 切勿在管道YAML中硬编码注册表凭据——应使用Docker服务连接进行ACR/DockerHub认证;服务连接会安全存储凭据并独立轮换。
- Tag触发需要在trigger部分显式设置——默认CI触发器不包含Tag;需添加
tags.include来触发版本Tag对应的管道运行。tags: include: ['v*']