一键导入
dotnet-ado-publish
Publishing .NET artifacts from Azure DevOps. NuGet push, containers to ACR, pipeline artifacts.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Publishing .NET artifacts from Azure DevOps. NuGet push, containers to ACR, pipeline artifacts.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Guidelines for writing TUnit tests in .NET, including setup, assertions, async testing, and best practices. Use when writing unit tests with TUnit framework, setting up TUnit in a .NET project, or migrating from other test frameworks to TUnit.
Hosted services, background jobs, outbox patterns, and graceful shutdown handling for ASP.NET Core applications. Includes patterns for reliable job processing, distributed systems, and lifecycle management. Use when implementing background processing in ASP.NET Core applications, handling outbox patterns for reliable message delivery, or managing graceful service shutdown.
Design stable, compatible public APIs using extend-only design principles. Manage API compatibility, wire compatibility, versioning, naming conventions, parameter ordering, and return types for NuGet packages and distributed systems. Use when designing public APIs for NuGet packages or libraries, making changes to existing public APIs, planning wire format changes for distributed systems, or reviewing pull requests for breaking changes.
Write modern, high-performance C# code using records, pattern matching, value objects, async/await, Span<T>/Memory<T>, and best-practice API design patterns. Emphasizes functional-style programming with C# 12+ features. Use when writing new C# code or refactoring existing code, designing public APIs for libraries or services, optimizing performance-critical code paths, or building async/await-heavy applications.
Choosing the right concurrency abstraction in .NET - from async/await for I/O to Channels for producer/consumer to Akka.NET for stateful entity management. Covers both high-level abstractions and low-level synchronization primitives. Use when deciding how to handle concurrent operations in .NET, evaluating whether to use async/await, Channels, or Akka.NET, or managing state across multiple concurrent entities.
Design .NET types for performance. Covers struct vs class decision matrix, sealed by default, readonly structs, ref struct and Span/Memory selection, FrozenDictionary, ValueTask, and collection return types. Use when designing new types and APIs, reviewing code for performance issues, choosing between class, struct, and record, or working with collections and enumerables.
| name | dotnet-ado-publish |
| description | Publishing .NET artifacts from Azure DevOps. NuGet push, containers to ACR, pipeline artifacts. |
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 Docker@2, artifact staging with PublishBuildArtifacts@1 and PublishPipelineArtifact@1, and pipeline artifacts for multi-stage release pipelines.
Version assumptions: DotNetCoreCLI@2 for pack/push operations. Docker@2 for container image builds. NuGetCommand@2 for NuGet push to external feeds. PublishPipelineArtifact@1 (preferred over PublishBuildArtifacts@1).
Scope boundary: This skill owns artifact publishing pipelines from Azure DevOps. Container image authoring (Dockerfile best practices, SDK container properties) is owned by [skill:dotnet-containers]. Native AOT compilation configuration is owned by [skill:dotnet-native-aot] -- this skill references AOT for CI pipeline configuration only. CLI-specific release pipelines are owned by [skill:dotnet-cli-release-pipeline]. Starter CI templates are owned by [skill:dotnet-add-ci].
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.
DotNetCoreCLI@2trigger:
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'
Extract the version from the triggering Git tag using a script step. Build.SourceBranch is a runtime variable, so use a script to parse it rather than compile-time template expressions:
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)'
NuGetCommand@2For pushing to external NuGet feeds (nuget.org), use a service connection:
- 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.
- 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 1.2.3-preview.1) go only to Azure Artifacts; stable versions go to both feeds.
- 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 returns HTTP 409 for duplicate package versions. Use continueOnError: true for idempotent pipeline reruns, or configure the feed to allow overwriting pre-release versions in Feed Settings.
Docker@2 TaskBuild and push a container image to Azure Container Registry. See [skill:dotnet-containers] for Dockerfile authoring guidance:
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
- 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
Use semantic version tags for release images and commit SHA tags for traceability. The latest tag should only be applied to stable releases.
Use .NET SDK container publish for projects without a Dockerfile. See [skill:dotnet-containers] for PublishContainer MSBuild configuration:
- 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)
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:
- 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 runtime-deps 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.
PublishPipelineArtifact@1 (Recommended)Pipeline artifacts are the modern replacement for build artifacts, offering faster upload/download and deduplication:
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)Use only when integrating with classic release pipelines that require build artifacts:
- task: PublishBuildArtifacts@1
displayName: 'Upload build artifact (legacy)'
inputs:
pathToPublish: '$(Build.ArtifactStagingDirectory)/app'
artifactName: 'app'
publishLocation: 'Container'
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 download: current keyword downloads artifacts from the current pipeline run. Use download: pipelineName for artifacts from a different pipeline.
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"
Consume artifacts from a different pipeline (e.g., a shared build pipeline):
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"
PublishPipelineArtifact@1 over PublishBuildArtifacts@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.continueOnError: true for idempotent reruns, or handle duplicates in feed settings by allowing pre-release version overwrites.NuGetCommand@2 with external feed 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.dotnet publish with PublishProfile=DefaultContainer needs Docker; hosted ubuntu-latest agents include Docker, but self-hosted agents may not.dotnet publish -r linux-x64 must match the agent OS; do not use -r win-x64 on a Linux agent.download: current uses $(Pipeline.Workspace) not $(Build.ArtifactStagingDirectory) -- artifacts downloaded in deployment jobs are at $(Pipeline.Workspace)/artifactName, not the staging directory.tags.include in the trigger section -- tags are not included by default CI triggers; add tags: include: ['v*'] to trigger on version tags.