Azure Pipeline - DevOps19 + VS22: Building Solution with two different projects - azure-devops

This post will be a bit longer, as I not only describe my problem, but also show my different attempts to solve the problem.
I have a solution contaning .Net-6-Web-Api-Project (csproj) and a C++/CLI-Wrapper-Project (vcxproj). I have a reference from the C#-Project to the c++-Project. I use DevOps 2019 and VS22 on my local building agent.
I'm not able to successfully run this solution through an Azure DevOps Pipeline using the task DotNetCoreCLI#2, VSBuild#1 or a custom script as a workaround for the MSBuild#1 to publish.
VSBuild
My initial approach was to simply use the VSBuild#1 task. Using this task does not allow the pipeline to start, with the following error:
##[Error 1]
No agent found in pool My_Pool which satisfies the specified demands:
agent.name -equals My_Agend_Unity_1
Cmd
msbuild
visualstudio
Agent.Version -gtVersion 2.153.1
The cause is the compatibility issue between DevOps 2019 and VS2022. The agent does not recognize VS2022 and therefore does not create system capabilities for it. Its the same issue for the MSBuild#1 and why I tried a custom script to work around, because it couldn't find MSBuild.
DotNetCoreCLI
The first error I got was:
error MSB4019: The imported project "C:\Microsoft.Cpp.Default.props" was not found. Confirm that the expression in the Import declaration "\Microsoft.Cpp.Default.props" is correct, and that the file exists on disk.
So I fixed that by adding the env variable to the task:
env:
PATH: 'C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170'
The resulting further error was:
##[error]Error: Unable to locate executable file: 'dotnet'. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also verify the file has a valid extension for an executable file.
So I tried to fix it by using the Task UseDotNet#2, even though it doesn't make sense to me. But at the end I still get an error similar to the first error.:
MSBuild version 17.3.2+561848881 for .NET
C:\agent\_work\2\s\XXX\YYY\CPPWrapper\MyProject.vcxproj : warning NU1503: Skipping restore for project "C:\agent\_work\2\s\XXX\YYY\CPPWrapper\MyProject.vcxproj". The project file may be invalid or missing targets required for restore. [C:\agent\_work\2\s\XXX\YYY\MySolution.sln]
Determining projects to restore...
"C:\agent\_work\2\s\XXX\YYY\DotNet6Project\MyProject.csproj" restored (in "2,4 sec").
C:\agent\_work\2\s\XXX\YYY\CPPWrapper\MyProject.vcxproj(21,3):error MSB4019: The imported project "C:\Microsoft.Cpp.Default.props" was not found. Confirm that the expression in the Import declaration "\Microsoft.Cpp.Default.props" is correct, and that the file exists on disk.
C:\agent\_work\2\s\XXX\YYY\CPPWrapper\MyProject.vcxproj(21,3): error MSB4019: The imported project "C:\Microsoft.Cpp.Default.props" was not found. Confirm that the expression in the Import declaration "\Microsoft.Cpp.Default.props" is correct, and that the file exists on disk.
##[error]Error: The process 'C:\agent\_work\_tool\dotnet\dotnet.exe' failed with exit code 1
##[error]Dotnet command failed with non-zero exit code on the following projects : C:\agent\_work\2\s\XXX\YYY\MySolution.sln
##[section]Finishing: Build & Publish XXX Service - DotNetCoreCLI#2
MSBuild
My last hope then was my custom script that I already use in another pipeline that accesses the same agent and uses MSBuild from VS22. This is the approach I've come furthest with, as it looks like the project builds fine, but then fails because of this error.
(ResolvePackageAssets Target) -> C:\Program Files\dotnet\sdk\7.0.101\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(267,5):
error NETSDK1064: Package "Microsoft.EntityFrameworkCore.Analyzers",
Version 6.0.4, not found. It may have been deleted after the NuGet restore.
Otherwise, the NuGet restore may have been only partially completed due to limitations on the maximum path length.
[C:\agent\_work\2\s\XXX\YYY\DotNet6Project\MyProject.csproj]
How to proceed with it, I do not know right now. I enabled already long paths via Group Policy Editor→Administrative templates→All Settings→Enable Win32 long paths.
My yaml file:
pool:
name: 'My_Pool'
demands:
- agent.name -equals My_Agent
variables:
buildPlatform: 'x64'
buildConfiguration: 'Release'
solution: '$(System.DefaultWorkingDirectory)/XXX/YYY/MySolution.sln'
DotNet6Project: '$(System.DefaultWorkingDirectory)/XXX/YYY/DotNet6Project/MyProject.csproj'
CPPWrapper: '$(System.DefaultWorkingDirectory)/XXX/YYY/CPPWrapper/MyProject.vcxproj'
steps:
- task: NuGetToolInstaller#0
displayName: 'NuGet Tool Installer - NuGetToolInstaller#0'
name: 'NuGetToolInstaller'
inputs:
versionSpec: '>=6.1.0'
- task: NuGetCommand#2
displayName: 'NuGet Restore - NuGetCommand#2'
inputs:
command: 'restore'
restoreSolution: '$(solution)'
noCache: true
- task: BatchScript#1
displayName: 'Run BatchScript to create DLLs, Libs & Header - BatchScript#1'
inputs:
filename: '$(System.DefaultWorkingDirectory)/ICP/ZZZ/build_release.bat'
env:
PATH: 'C:\Program Files\CMake\bin'
- task: PowerShell#2
displayName: 'Run Powershell Script to unpack Packages from BatchScript for ZZZWrapper - PowerShell#2'
inputs:
filePath: '$(System.DefaultWorkingDirectory)/XXX/YYY/CPPWrapper/install_ZZZ_package.ps1'
# Workaround for MSBuild#1
- script: |
#echo off
setlocal enabledelayedexpansion
for /f "usebackq tokens=*" %%i in (`"!ProgramFiles(x86)!\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe`) do (set msbuild_exe=%%i)
"!msbuild_exe!" "$(solution)" /p:Configuration="$(buildConfiguration)" /p:Platform="$(buildPlatform)" /p:PackageLocation="$(build.artifactStagingDirectory)" /t:rebuild
displayName: 'Build - Script'
# ---------- VSBuild ----------------
#- task: VSBuild#1
# inputs:
# solution: '$(solution)'
# msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactStagingDirectory)"'
# platform: '$(buildPlatform)'
# configuration: '$(buildConfiguration)'
# ---------- DotNetCoreCLI ----------
#- task: UseDotNet#2
# inputs:
# packageType: 'sdk'
# version: '6.x'
#- task: DotNetCoreCLI#2
# displayName: 'Build & Publish - DotNetCoreCLI#2'
# inputs:
# command: 'publish'
# publishWebProjects: false
# projects: '$(solution)'
# arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)'
# zipAfterPublish: false
# env:
# PATH: 'C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170'
- task: PublishBuildArtifacts#1
displayName: 'Publish Build Artifacts - PublishBuildArtifacts#1'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'XXXArtifact'
publishLocation: 'Container'

From your yaml file ,I understand you want to build a solution and then publish build artifact. Accroding the error of your described task, I would like to provide suggestions that you can check.
1 VSBuild#1
taskError information: No agent found in pool My_Pool which satisfies the specified demandsThis indicates there are no agents on your machine that meet the demand requirements. You should check whether exists the agent which name is My_Agend_Unity_1 and exists check for Cmd,msbuild,visualstudio,Agent.Version -gtVersion 2.153.1.
See more information refer to doc:pool definition
2  UseDotNet#2
There’s a warning warning NU1503: Skipping restore for project that indicates  the packages required for the project MyProject are not restored correctly. You should edit the affected project to add targets for restore.
Please refer to doc:NuGet Warning NU1503
About the error MSB4019,you should check whether the project path "C:\Microsoft.Cpp.Default.props" exists. Here’s a ticekt  similar to your issue.You can try to this workaround and see if it works.
3 MSBuild
MSBuildAbout error NETSDK1064, this error occurs when the build tools can't find a NuGet package that's needed to build a project. This is typically due to a package restore issue related to warning NU1503 inTask   UseDotNet#2`. You can refer this doc:NETSDK1064: Package not found to take some actions provided to resolve this error.

Related

Azure DevOps: I'm caching nuget packages, but the Build task fails to use the cached packages

I'm using the Cache#2 DevOps task to cache nuget packages from multiple projects:
variables:
NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget/packages
- task: Cache#2
displayName: 'NuGet cache'
inputs:
key: 'nuget | "$(Agent.OS)" | **/packages.lock.json,!**/bin/**,!**/obj/**'
restoreKeys: |
nuget | "$(Agent.OS)"
nuget
path: $(NUGET_PACKAGES)
cacheHitVar: 'CACHE_RESTORED'
- task: NuGetCommand#2
displayName: 'NuGet restore'
condition: ne(variables.CACHE_RESTORED, true)
inputs:
command: 'restore'
restoreSolution: '$(solution)'
- task: VSBuild#1
displayName: 'Build solution'
...
I'm following the documentation here:
https://learn.microsoft.com/en-us/azure/devops/pipelines/artifacts/caching-nuget?view=azure-devops
In the 'NuGet cache' step, if there is a cache, it is restored:
Resolved to: nuget|"Windows_NT"|Gor2Y1OZWvAeaan3RC3GH9D0ldp6z17wm6JB2YUxrS0=
There is a cache hit: `nuget|"Windows_NT"|Gor2Y1OZWvAeaan3RC3GH9D0ldp6z17wm6JB2YUxrS0=`
Path =
Type = tar
Code Page = UTF-8
Characteristics = ASCII
Everything is Ok
Folders: 6022
Files: 8938
Size: 1894324465
Compressed: 7660544
Process exit code: 0
Cache restored.
If there is a cache hit, the 'NuGet restore' task is skipped:
Evaluating: ne(variables['CACHE_RESTORED'], True)
Expanded: ne('true', True)
Result: False
Then comes my problem. The 'Build solution' task fails with thousands of errors like these
##[error]NHO.Core\IdentityServerClientStartup.cs(32,12): Error CS0246: The type or namespace name 'OwinStartupAttribute' could not be found (are you missing a using directive or an assembly reference?)
It cannot resolve references to classes in NuGet packages.
Any idea why this fails? I'm following the documentation exactly, but I don't know if I'm still missing something?
Update: Possible solution/source of error
It seems to be an error in the documentation.
If I run the NuGet restore step normally, without the condition
- task: NuGetCommand#2
displayName: 'NuGet restore'
inputs:
command: 'restore'
restoreSolution: '$(solution)'
it is a lot quicker than normal (20 seconds instead of 2 minutes), so I'm guessing it uses the cache.
The documentation provides only a basic case that all packages and references are stored in .nuget/packages and no assets files are required. In this case, the users can skip the restore task and just perform the cache task.
However, in many other cases, performing a restore task is necessary if using Microsoft-hosted agent. Since most packages are already cached by cache task, the running time of nuget restore task will be significantly reduced.

Disable AzureFileCopy#2 pre job?

I am using Azure Devops Pipelines (YAML).
I have a AzureFileCopy#2 task which copies file from the source into a Storage Account. The Storage Account is created dynamically by an earlier ARM deploy task (the ARM task outputs the SA name which is then parsed into a variable for later consumption).
The AzureFileCopy#2 task works perfectly and copies all the files into the Storage Account. But, I notice in the run that the AzureFileCopy#2 task actually runs twice - once by me and once as a "pre-job". The pre-job of course fails with a warning that it can't reference the Storage Account (because by that stage I haven't created the variable).
Fortunately, it's only a warning but it is rather annoying to have that warning in every run.
I believe that pre-jobs can't be disabled (though I could drop that is a a feature enhancement) so is there a better way of handing this presumably common scenario?
Thanks in advance
EDIT: Obfuscated YAML added:
variables:
My.Configuration: 'Release'
My.SQLProject: 'contoso.api'
My.ARMProject: 'contoso.azure.templates'
My.IntEnvironment: 'i'
My.ResourceGroupNumber: 66
My.ArtifactLocation: 'drop'
# BUILD STAGES ARE HERE
- stage: 'Stage_Deploy'
displayName: 'Stage Deploy'
jobs:
- deployment: 'Job_Deploy'
pool:
vmImage: 'windows-2019'
displayName: 'Job Deploy'
environment: 'env1'
strategy:
runOnce:
deploy:
steps:
- download: none
- task: DownloadPipelineArtifact#2
displayName: 'Download Pipeline Artifacts from Drop'
inputs:
buildType: 'current'
targetPath: '$(Pipeline.Workspace)'
- task: AzureResourceManagerTemplateDeployment#3
displayName: 'ARM Deployment'
inputs:
deploymentScope: 'Resource Group'
azureResourceManagerConnection: 'CONTOSO CONNECTION'
subscriptionId: 'aaaaaaaa-0000-0000-00000-aaaaaaaaaaaaa'
action: 'Create Or Update Resource Group'
resourceGroupName: 'contoso-$(My.IntEnvironment)-eun-core-$(My.ResourceGroupNumber)-rg'
location: 'North Europe'
templateLocation: 'Linked artifact'
csmFile: '$(Pipeline.Workspace)/$(My.ArtifactLocation)/$(My.ARMProject)/azuredeploy.json'
csmParametersFile: '$(Pipeline.Workspace)/$(My.ArtifactLocation)/$(My.ARMProject)/azuredeploy.parameters.json'
overrideParameters: '-environment $(My.IntEnvironment)'
deploymentMode: 'Incremental'
deploymentOutputs: 'ARMOutput'
- task: PowerShell#2
condition: true
displayName: 'Parse ARM Template Outputs'
inputs:
targetType: filePath
filePath: '$(Pipeline.Workspace)/$(My.ArtifactLocation)/$(My.ARMProject)/Parse-ARMOutput.ps1'
arguments: '-ARMOutput ''$(ARMOutput)'''
- task: AzureFileCopy#2
condition: true
displayName: 'Copy Static Web Content to SA'
inputs:
SourcePath: '$(Pipeline.Workspace)/$(My.ArtifactLocation)'
azureSubscription: 'CONTOSO CONNECTION'
Destination: AzureBlob
storage: '$(ARM.AppDataStorageName)'
ContainerName: static
Then, when I run it, the following stages happen:
1. Initialize job
2. Pre-job: Copy Static Web Content to SA
It is this pre-job that, in the debugging shows this:
##[debug]StorageAccountRM=$(ARM.AppDataStorageName)
<other debug lines followed by...>
##[warning]Can\'t find loc string for key: StorageAccountDoesNotExist
Later on the task "Copy Static Web Content to SA" runs as a normal task and it runs fine.
Fortunately, it's only a warning but it is rather annoying to have
that warning in every run. I believe that pre-jobs can't be disabled
(though I could drop that is a a feature enhancement) so is there a
better way of handing this presumably common scenario?
Sorry but I'm afraid it's not supported to disable the warning. The warning occurs because it's by design.
(The source code of AzureFileCopyV2 task causes this behavior.)
More details:
We can find source of that task here. It contains one task.json file in which defines content like this:
"instanceNameFormat": "$(Destination) File Copy",
"prejobexecution": {
"Node": {
"target": "PreJobExecutionAzureFileCopy.js"
}
},
The task.json file describes the build or release task and is what the build/release system uses to render configuration options to the user and to know which scripts to execute at build/release time. Since the task.json has definition like prejobexecution, the predefined pre-job task will do the check about the inputs defined in PreJobExecutionAzureFileCopy.js file. Including the Storage Account.
So this is something by design of the code of AzureFileCopyV2 task, we can't disable the warning in pre-job task. If you do want to resolve that warning, you can consider using AzureFileCopyV1 in which doesn't define the prejobexecution, but this is not recommended. Compared with Version1, Version2 has some improvement and fixes some old issues.

Publishing VS Code extension via Azure DevOps

After reading VSCode Publish Extension docs, I've succeeded to publish a VSCode extension manually with vsce.
I'm wondering if there is a way to publish extensions automatically via Azure DevOps pipelines (build or release) instead of doing it manually.
I've tried to use vsce there but I'm getting an authentication error
Resource not available for anonymous access. Client authentication required.
Using vsce publish -p <access_token> is not possible because the pipeline is public and everyone can see the access token...
So, is there a way to publish a Visual Studio Code extension automatically via Azure DevOps Pipeline or even Travis CI?
You can add the Personal Access Token as a secret variable, then nobody can couldn't see it.
Go to Azure DevOps to your pipeline and click on "Edit", not in the top left click on "Variables":
Now click on the + icon and add the variable, mark the checkbox "Keep this value secret":
Now you can use it in this way: $(PAT), for example:
vsce publish -p $(PAT)
The variable value will not appear in the YAML :)
Is there a way to publish a Visual Studio Code extension automatically
via Azure DevOps Pipeline?
Of course yes!
To have a good experience for CI/CD in Azure Devops, I recommend you store the source code in Azure Devops or Github.
Build \ CI
In build, most of work is update the version which in manifest of VSIX, build\create package. For the version increased, here I use the counter expression feature which supported in VSTS to achieve that:
counter('name', seed)
Use this expression in variable declaration bloc. For detailed and completed build process, refer to my sample YAML code:
trigger:
- '*'
pool:
vmImage: 'windows-2019'
variables:
VersionPatch: $[counter('versioncount', 24)]
solution: '**/*.sln'
BuildPlatform: 'Any CPU'
BuildConfiguration: 'Release'
name: 2.0.$(VersionPatch)
steps:
- task: UseDotNet#2
inputs:
packageType: 'sdk'
version: '3.0.100'
includePreviewVersions: true
- task: NuGetToolInstaller#1
inputs:
versionSpec: 5.1.0
- task: PowerShell#2
displayName: Update version
inputs:
filePath: 'Build\VersionUpdate.ps1'
arguments: '$(Build.BuildNumber)'
pwsh: true
- task: NuGetCommand#2
inputs:
command: 'restore'
- task: DotNetCoreCLI#2
displayName:
inputs:
command: 'restore'
projects: 'tests/**/*.csproj'
vstsFeed: '{My feed ID}'
includeNuGetOrg: false
- task: VSBuild#1
inputs:
solution: '**\*.sln'
maximumCpuCount: true
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
- task: VSTest#2
inputs:
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
- task: CopyFiles#2
inputs:
SourceFolder: '$(Build.SourcesDirectory)'
Contents: |
Build/**
**/*.vsix
**/*.nupkg
README.md
TargetFolder: '$(Build.ArtifactStagingDirectory)'
- task: PublishPipelineArtifact#0
inputs:
artifactName: 'ExtensionDrop'
targetPath: '$(Build.ArtifactStagingDirectory)'
In UpdateVersion.ps1 file:
$VerbosePreference="Continue"
$version = $args[0]
if (!$version) {
$version = "0.0.0"
}
Write-Host "This Version is: $version"
$FullPath = Resolve-Path $PSScriptRoot\..\src\Merlin.Compiler.Vsix\source.vsixmanifest
Write-Host $FullPath
[xml]$content = Get-Content $FullPath
$content.PackageManifest.Metadata.Identity.Version = $version
$content.Save($FullPath)
Release\ CD
After build succeed, set the release pipeline for this repos. In release, use powershell script and VsixPublisher.exe to publish the vsix file.
$PAToken = $args[0]
$VsixPath = "$PSScriptRoot\..\src\Merlin.Compiler.Vsix\bin\Release\Merlin.Compiler.Vsix"
$ManifestPath = "$PSScriptRoot\ExtensionManifest.json"
$Installation = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -format json | ConvertFrom-Json
$Path = $Installation.installationPath
$VsixPublisher = Join-Path -Path $Path -ChildPath "VSSDK\VisualStudioIntegration\Tools\Bin\VsixPublisher.exe" -Resolve
& $VsixPublisher publish -payload $VsixPath -publishManifest $ManifestPath -personalAccessToken $PAToken -ignoreWarnings "VSIXValidatorWarning01,VSIXValidatorWarning02,VSIXValidatorWarning08"
In CD, use VsixPublisher.exe which exist in VS to publish the vsix file.
You can set the PAToken in Variable tab, then set it as secret. Thus it would not be public for others. Here PAT token is a necessary one which could not be replaced by others. And also, when generate the token, need choose All accessible organizations. Or it will cause the permission error.
Further #Shayki's answer there are some more steps because you can't just run vsce publish -p $(PAT).
The vsce should be installed (can be in devDependencies)
Add a "deploy" (or name it as you like) script to the package.json scripts.
"deploy": "vsce publish -p"
Add a "publish" step in the azure-pipeline.yml file. the condition is for running the publish script only on master so Pull Requests will not publish. Also run it only in Linux's build, in case you configured multiple platforms. If you configured only one (for example, windows) replace Linux with that platform
- bash: |
echo ">>> Publish"
yarn deploy $(token)
displayName: Publish
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['Agent.OS'], 'Linux'))
Example azure-pipeline.yml

I have a build pipeline in Azure DevOps for my github repo - where are the binaries?

Here is the (unedited from template) YAML definition of the pipeline:
# .NET Desktop
# Build and run tests for .NET Desktop or Windows classic desktop solutions.
# Add steps that publish symbols, save build artifacts, and more:
# https://learn.microsoft.com/azure/devops/pipelines/apps/windows/dot-net
trigger:
- master
pool:
vmImage: 'windows-latest'
variables:
solution: '**/*.sln'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
steps:
- task: NuGetToolInstaller#1
- task: NuGetCommand#2
inputs:
restoreSolution: '$(solution)'
- task: VSBuild#1
inputs:
solution: '$(solution)'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- task: VSTest#2
inputs:
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
This pipeline triggers when code is pushed to the master branch of my repo as intended - however I can't find the binaries that it built! How do I access them so I can share them with folks? Are the binaries unavailable because some of my unit tests failed, causing the build to fail, or something?
You need to publish those somewhere. It's up to you to choose what to keep at what stage of the pipeline. You can copy files into a directory, or just grab the whole $(Build.SourcesDirectory). You can also instruct the VsBuild task to redirect output to a specific directory by passing in the /p:OutputPath=$(Build.ArtifactStagingDirectory) commandline argument.
You then have a few options:
GitHub Release task - Creates a release in GitHub and associates the files you want to it.
# GitHub Release
# Create, edit, or delete a GitHub release
- task: GitHubRelease#0
inputs:
gitHubConnection:
#repositoryName: '$(Build.Repository.Name)'
#action: 'create' # Options: create, edit, delete
#target: '$(Build.SourceVersion)' # Required when action == Create || Action == Edit
#tagSource: 'auto' # Required when action == Create# Options: auto, manual
#tagPattern: # Optional
#tag: # Required when action == Edit || Action == Delete || TagSource == Manual
#title: # Optional
#releaseNotesSource: 'file' # Optional. Options: file, input
#releaseNotesFile: # Optional
#releaseNotes: # Optional
#assets: '$(Build.ArtifactStagingDirectory)/*' # Optional
#assetUploadMode: 'delete' # Optional. Options: delete, replace
#isDraft: false # Optional
#isPreRelease: false # Optional
#addChangeLog: true # Optional
#compareWith: 'lastFullRelease' # Required when addChangeLog == True. Options: lastFullRelease, lastRelease, lastReleaseByTag
#releaseTag: # Required when compareWith == LastReleaseByTag
Publish Pipeline Artifact (Azure DevOps) - Links the selected files to the build as an artifact. You can download them from the pipeline's summary page in Azure DevOps. Works well in both Build and Release pipelines.
# Publish pipeline artifact
# Publish (upload) a file or directory as a named artifact for the current run
- task: PublishPipelineArtifact#1
inputs:
targetPath: '$(Pipeline.Workspace)'
artifact: 'Output'
Publish Build Artifact (Azure DevOps and TFS) - Similar to Publish Pipeline Artifact, but less efficient in its transfers and specific to build pipelines. Can also publish to a file share instead of an attachment to the pipeline summary.
# Publish build artifacts
# Publish build artifacts to Azure Pipelines or a Windows file share
- task: PublishBuildArtifacts#1
inputs:
#pathtoPublish: '$(Build.ArtifactStagingDirectory)'
#artifactName: 'drop'
#publishLocation: 'Container' # Options: container, filePath
#targetPath: # Required when publishLocation == FilePath
#parallel: false # Optional
#parallelCount: # Optional
You are missing the task of "copy and publish artifact" task. This task will copy the resulting compiled binaries as artifact to be downloaded later.
For more information about this copy and publish artifact, visit the official documentation: https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/copy-and-publish-build-artifacts?view=azure-devops
UPDATE: the copy and publish artifact task is deprecated in Azure DevOps, please use the newest one: https://learn.microsoft.com/en-us/azure/devops/pipelines/artifacts/build-artifacts?view=azure-devops&tabs=yaml
Use this in your YAML: PublishBuildArtifacts#1

Azure Devops : Build a winforms project and copy release files to Azure blob storage

I want to set up CI CD for a winforms project Dot Net Framework 4.5.2 to build the project and then copy the release files to an Azure blob.
When I create a new build pipeline and select my Azure Repo the following YAML is created
# .NET Desktop
# Build and run tests for .NET Desktop or Windows classic desktop solutions.
# Add steps that publish symbols, save build artifacts, and more:
# https://learn.microsoft.com/azure/devops/pipelines/apps/windows/dot-net
trigger:
- master
pool:
vmImage: 'VS2017-Win2016'
variables:
solution: '**/*.sln'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
steps:
- task: NuGetToolInstaller#0
- task: NuGetCommand#2
displayName: 'NuGet restore'
inputs:
restoreSolution: '**\*.sln'
feedsToUse: config
nugetConfigPath: 'NuGet.config'
- task: VSBuild#1
inputs:
solution: '$(solution)'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
The pipeline builds successfully
However I am having trouble setting up the Release pipeline to copy the release files to Azure blob storage.
I created a new release pipeline with an Empty Job.
Then I added an Azure File Copy Task
What do I put as the source ?
When I click the elipse I see I can select a myapp (Build) folder from within a Linked artifacts folder.
I was able to set up the storage and container names , but left the Blob Prefix blank.
When I run the Agent job I get an error on AzureBlob File Copy
(edited)
##[section]Starting: AzureBlob File Copy
==============================================================================
Task : Azure File Copy
Description : Copy files to Azure blob or VM(s)
Version : 2.1.3
Author : Microsoft Corporation
Help : [More Information](https://aka.ms/azurefilecopyreadme)
==============================================================================
##[command]Import-Module -Name C:\Program Files\WindowsPowerShell\Modules\AzureRM\2.1.0\AzureRM.psd1 -Global
##[warning]The names of some imported commands from the module 'AzureRM.Websites' include unapproved verbs that might make them less discoverable. To find the commands with unapproved verbs, run the Import-Module command again with the Verbose parameter. For a list of approved verbs, type Get-Verb.
##[command]Import-Module -Name C:\Program Files\WindowsPowerShell\Modules\AzureRM.Profile\2.1.0\AzureRM.Profile.psm1 -Global
##[command]Add-AzureRMAccount -ServicePrincipal -Tenant *** -Credential System.Management.Automation.PSCredential -EnvironmentName AzureCloud #processScope
##[command] Select-AzureRMSubscription -SubscriptionId blahblah -TenantId ***
Uploading files from source path: 'd:\a\r1\a\_Viv2' to storage account: 'viv' in container: 'viv2' with blob prefix: ''
##[command] & "AzCopy\AzCopy.exe" /Source:"d:\a\r1\a\_Viv2" /Dest:"https://vivapps.blob.core.windows.net/viv2" /#:"d:\a\_temp\n40zblahblah" /XO /Y /SetContentType /Z:"AzCopy" /V:"AzCopy\AzCopyVerbose_20blahblah.log" /S
[2019/02/13 01:26:46][ERROR] Error parsing source location "d:\a\r1\a\_Viv2": Failed to enumerate directory d:\a\r1\a\_Viv2\ with file pattern *. The system cannot find the path specified. (Exception from HRESULT: 0x80070003) For more details, please type "AzCopy /?:Source" or use verbose option /V.
##[error]Upload to container: 'vivj2' in storage account: 'vivapps' with blob prefix: '' failed with error: 'AzCopy.exe exited with non-zero exit code while uploading files to blob storage.' For more info please refer to https://aka.ms/azurefilecopyreadme
##[section]Finishing: AzureBlob File Copy
[Update]
I think the issue must be to do with the Source
looking at the build logs I see path names like "D:\a\1\s\blahblah"
I also see
creating bin\Release
but how do I figure out what I should be putting in the Source property ?
Trying
$(System.DefaultWorkingDirectory)/_Viv2/bin/Release
No joy.
Exception from HRESULT: 0x80070003 means the system cannot find the file specified.
[Update]
The default YAML created does not included a task to publish the build "Artifacts" (Not to be confused with the Project Artifacts )
I tried adding one
- task: PublishBuildArtifacts#1
displayName: 'Publish Artifact: drop'
inputs:
PathtoPublish: '$(build.artifactstagingdirectory)'
artifactName: drop
but the task log says
##[warning]Directory 'D:\a\1\a' is empty. Nothing will be added to build artifact 'drop'
Please have a try to append the copy file and publish Build Artifacts task after VS build task in the build pipeline.
In the build pipeline:
...
- task: VSBuild#1
inputs:
solution: '$(solution)'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- task: CopyFiles#2
displayName: 'Copy Files'
inputs:
SourceFolder: '$(build.sourcesdirectory)'
TargetFolder: '$(build.artifactstagingdirectory)'
- task: PublishBuildArtifacts#1
displayName: 'Publish Artifact: drop'
In the release pipeline:
Azure copy file source should be
$(System.DefaultWorkingDirectory)/{Source alias}/drop/xx/xxx/bin/Release
We could get source alias from this screenshot
After we build successfully then we could choose the source path.
It works correctly on my side, I check it from the release log and azure storage container