mcpField
D
dotnet-ado-publish

dotnet-ado-publish

github.com/wshaddixクラウド・DevOps8667 回インストール35 週間前に更新
リポジトリ

dotnet-ado-publish について

Azure DevOps パイプラインで公開を行う .NET チーム向けのスキルです。NuGet パッケージ、コンテナーイメージ、ビルド成果物を対象に、Azure Artifacts、nuget.org、ACR、多段階リリースの設定を扱います。

主な機能

  1. 01Azure Artifacts への NuGet パッケージ公開
  2. 02nuget.org へのパッケージ公開
  3. 03ACR 向けイメージのビルドとプッシュ
  4. 04パイプライン成果物のステージングと公開
  5. 05ステージ間での成果物の受け渡し

活用シーン

  1. 01Azure DevOps から NuGet パッケージを公開
  2. 02コンテナーイメージを ACR にプッシュ
  3. 03多段階リリースでビルド成果物を受け渡し

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-ado-publish

インストール後、Claude Code で/dotnet-ado-publishを入力して読み込まれたか確認します。

詳細

dotnet-ado-publish

Azure DevOps で .NET プロジェクトのパイプラインを公開します。NuGet パッケージを Azure Artifacts および nuget.org にプッシュし、Docker@2 を使用してコンテナーイメージをビルドして Azure Container Registry(ACR)にプッシュします。また、PublishBuildArtifacts@1 と PublishPipelineArtifact@1 による成果物のステージングや、複数ステージのリリースパイプライン用のパイプライン成果物にも対応します。

バージョンの前提条件: パック/プッシュ操作には DotNetCoreCLI@2 を使用します。コンテナーイメージのビルドには Docker@2 を使用します。外部フィードへの NuGet プッシュには NuGetCommand@2 を使用します。PublishPipelineArtifact@1 を使用します(PublishBuildArtifacts@1 より推奨)。

対象範囲: このスキルは、Azure DevOps からの成果物公開パイプラインを担当します。コンテナーイメージの作成(Dockerfile のベストプラクティス、SDK コンテナーのプロパティ)は [skill:dotnet-containers] が担当します。Native AOT コンパイルの構成は [skill:dotnet-native-aot] が担当します。このスキルでは CI パイプライン構成における AOT のみを扱います。CLI 固有のリリースパイプラインは [skill:dotnet-cli-release-pipeline] が担当します。スターター CI テンプレートは [skill:dotnet-add-ci] が担当します。

対象外: コンテナーイメージの作成(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] を参照してください。ADO 固有の機能(環境、サービス接続)については、[skill:dotnet-ado-unique] を参照してください。

相互参照:[skill:dotnet-containers] ではコンテナーイメージの作成と SDK コンテナーのプロパティ、[skill:dotnet-native-aot] では CI での AOT 公開構成、[skill:dotnet-cli-release-pipeline] では CLI 固有のリリース自動化、[skill:dotnet-add-ci] ではスターター公開テンプレートについて説明しています。


Azure Artifacts への NuGet プッシュ

DotNetCoreCLI@2 によるプッシュ
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'
Git タグからバージョンを取得

スクリプトステップを使用して、トリガーとなった Git タグからバージョンを抽出します。Build.SourceBranch は実行時変数なので、コンパイル時のテンプレート式ではなくスクリプトで解析してください。

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.org への NuGet プッシュ

NuGetCommand@2 によるプッシュ

外部の NuGet フィード(nuget.org)にプッシュする場合は、サービス接続を使用してください。

- task: NuGetCommand@2
  displayName: 'Push to nuget.org'
  inputs:
    command: 'push'
    packagesToPush: '$(Pipeline.Workspace)/nupkgs/*.nupkg'
    nuGetFeedType: 'external'
    publishFeedCredentials: 'NuGetOrgServiceConnection'

サービス接続には、nuget.org の API キーが安全に保存されます。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'

プレリリースバージョン(1.2.3-preview.1 のように - を含むもの)は Azure Artifacts にのみ送信され、安定版は両方のフィードに送信されます。

重複パッケージをスキップする
- 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: true を使用するか、フィード設定でプレリリースバージョンの上書きを許可してください。


ACR へのコンテナーイメージのビルドとプッシュ

Docker@2 タスク

Azure Container Registry にコンテナーイメージをビルドしてプッシュします。Dockerfile の作成方法については、[skill:dotnet-containers] を参照してください。

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

リリースイメージにはセマンティックバージョンタグを使用し、追跡性を確保するにはコミット SHA タグを使用します。latest タグは安定版のリリースにのみ適用してください。

SDK コンテナーの公開(Dockerfile 不要)

Dockerfile を使用しないプロジェクトでは、.NET SDK によるコンテナー公開を使用します。PublishContainer の MSBuild 構成については、[skill:dotnet-containers] を参照してください。

- 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 コンテナーの公開

Native AOT バイナリをコンテナーイメージとして公開します。AOT の構成は [skill:dotnet-native-aot] が担当します。ここでは CI パイプラインのステップのみを示します。

- 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 バイナリにはランタイムが含まれるため、runtime-deps ベースイメージで十分です。AOT の MSBuild プロパティについては [skill:dotnet-native-aot] を、ベースイメージの選択については [skill:dotnet-containers] を参照してください。


成果物のステージング

PublishPipelineArtifact@1(推奨)

パイプライン成果物はビルド成果物に代わる最新の方式であり、アップロード/ダウンロードの高速化と重複排除に対応しています。

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(レガシー)

ビルド成果物を必要とするクラシックリリースパイプラインと統合する場合にのみ使用します。

- 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"

download: current キーワードは、現在のパイプライン実行から成果物をダウンロードします。別のパイプラインの成果物には、download: pipelineName を使用します。


リリースパイプライン向けパイプライン成果物

成果物の昇格を伴うマルチステージリリース
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"
パイプライン間での成果物の利用

別のパイプライン(例:共有ビルドパイプライン)の成果物を利用します。

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"

エージェントに関する注意点

  1. PublishBuildArtifacts@1 より PublishPipelineArtifact@1 を使用する -- パイプライン成果物は高速で、重複排除に対応し、マルチステージ YAML パイプラインで動作します。ビルド成果物はレガシーであり、クラシックリリースパイプラインでのみ必要です。
  2. Azure Artifacts はパッケージバージョンが重複すると 409 を返す -- 冪等な再実行には continueOnError: true を使用するか、フィードの設定でプレリリースバージョンの上書きを許可して重複を処理します。
  3. NuGetCommand@2 でフィードタイプ external を使用するには、サービス接続が必要 -- パイプライン YAML に API キーをハードコードしないでください。Project Settings で NuGet サービス接続を作成し、キーを安全に保管します。
  4. SDK コンテナーの発行にはエージェント上の Docker が必要 -- PublishProfile=DefaultContainer を指定した dotnet publish には Docker が必要です。ホスト型の ubuntu-latest エージェントには Docker が含まれていますが、セルフホスト型エージェントには含まれていない場合があります。
  5. AOT 発行では一致する RID が必要 -- dotnet publish -r linux-x64 はエージェントの OS と一致させる必要があります。Linux エージェントで -r win-x64 を使用しないでください。
  6. download: current は $(Build.ArtifactStagingDirectory) ではなく $(Pipeline.Workspace) を使用する -- デプロイジョブでダウンロードされた成果物は、ステージングディレクトリではなく $(Pipeline.Workspace)/artifactName にあります。
  7. レジストリの認証情報をパイプライン YAML にハードコードしない -- ACR/DockerHub 認証には Docker サービス接続を使用します。サービス接続では認証情報を安全に保管し、個別にローテーションできます。
  8. タグトリガーにはトリガーセクションで明示的な tags.include が必要 -- タグは既定の CI トリガーには含まれません。バージョンタグでトリガーするには、tags: include: ['v*'] を追加します。

コメント