I have an azure devops pipeline that publishes output,
pool:
vmImage: 'windows-latest'
steps:
- script: |
dotnet restore
dotnet build --configuration Release
- task: DotNetCoreCLI#2
inputs:
command: publish
arguments: '--configuration Release --output publish_output'
projects: 'MyProject/*.csproj'
publishWebProjects: false
modifyOutputPath: false
zipAfterPublish: false
- task: ArchiveFiles#2
displayName: "Archive files"
inputs:
rootFolderOrFile: "$(System.DefaultWorkingDirectory)/publish_output"
includeRootFolder: false
archiveFile: "$(System.DefaultWorkingDirectory)/myapp.zip"
- task: PublishBuildArtifacts#1
inputs:
PathtoPublish: '$(System.DefaultWorkingDirectory)/myapp.zip'
artifactName: 'myapp'
and this works.
Another release pipeline should use the artifact generated by build,
trigger:
- main
variables:
azureSubscription: MySubscription
appName: myAppName
vmImageName: 'ubuntu-latest'
steps:
- task: DownloadBuildArtifacts#1
inputs:
buildType: 'current'
downloadType: 'single'
artifactName: 'myapp'
downloadPath: '$(Build.ArtifactsDirectory)'
- task: AzureFunctionApp#1 # Add this at the end of your file
inputs:
azureSubscription: $(azureSubscription)
appType: functionApp # default is functionApp
appName: $(appName)
package: $(Build.ArtifactsDirectory)/**/*.zip
but this fails already in the DownloadBuildArtifacts task with error:
##[error]Artifact myapp was not found for build xy.
I can see in the log that the artifact is placed in some folder,
Upload 'D:\a\1\s\myapp.zip' to file container: '#/29596927/myapp'
but there is no info in which location the DownloadBuildArtifacts task is searching for the artifact (at least I did not find it even with analytics enabled in the pipeline run). Should I replace 'Build.ArtifactsDirectory' or is something wrong at another place?
##[error]Artifact myapp was not found for build xy.
From your YAML sample, the cause of the issue is that you need to download the artifacts from Build Pipeline, but in release pipeline, you add the DownloadBuildArtifacts task to download the current release pipeline artifacts.
buildType: 'current'
Since the build artifacts doesn't exist in release pipeline, it will cause the issue.
To solve this issue, you need to modify the DownloadBuildArtifacts task definition to download the build pipeline artifacts.
For example:
steps:
- task: DownloadBuildArtifacts#1
displayName: 'Download Build Artifacts'
inputs:
buildType: specific
project: 'projectname'
pipeline: 'Pipelinename or PipelineID'
artifactName: 'myapp'
downloadPath: '$(Build.ArtifactsDirectory)'
In this case, it will download the artifacts of Build Pipeline.
For more detailed info, you can refer to the doc: DownloadBuildArtifacts#1
You have to define your resources to that other build pipeline before or after the variables:
resources:
pipelines:
- pipeline: referenceNameOfBuildPipeline
source: BuildPipelineName
# similarly, referencing another repo source
repositories:
- repository: referenceNameOfRepo
type: git
name: RepoName
Then you can use the reference name in a download or checkout step:
steps
- checkout: self
- checkout: referenceNameOfRepo
- download: referenceNameOfBuildPipeline
artifact: 'myApp'
displayName: 'Downloading myApp'
- task: ExtractFiles#1
displayName: "Extracting Build Artifacts"
inputs:
archiveFilePatterns: "$(Pipeline.Workspace)/**/myapp.zip"
destinationFolder: '$(Build.BinariesDirectory)'
Related
I have an ASP.NET MVC application (not .NET Core) which I am deploying to an Azure App Service using Azure Devops and a yaml file. It's working fine but I've another console application in the same solution and I want to deploy that as a webjob in the same app service.
I can't find any good help with .NET framework. All the links I found are demonstrating in .NET Core.
Here is my yaml:
trigger:
- master
pool:
vmImage: 'windows-2019'
variables:
solution: '**/*.sln'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
stages:
- stage: Build
displayName: Build and Test Package
jobs:
- job: Build_Test_Publish
displayName: Build_Test_Publish
steps:
- task: NuGetToolInstaller#1
- task: VisualStudioTestPlatformInstaller#1
displayName: 'Install Visual Studio Test Platform'
inputs:
packageFeedSelector: 'nugetOrg'
versionSelector: 'latestStable'
- task: NuGetCommand#2
displayName: 'Restore NuGet packages'
inputs:
command: 'restore'
restoreSolution: '$(solution)'
feedsToUse: 'config'
nugetConfigPath: './'
- task: VSBuild#1
displayName: 'Build Solution'
inputs:
solution: '$(solution)'
msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactStagingDirectory)"'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- task: VSTest#2
displayName: 'Run Unit Tests'
inputs:
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- task: PublishBuildArtifacts#1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop'
publishLocation: 'Container'
- stage: Deploy
displayName: Deploy
jobs:
- deployment: Deploy
displayName: Deploy
environment: 'PROD'
strategy:
runOnce:
deploy:
steps:
- checkout: none
- task: DownloadBuildArtifacts#0
inputs:
buildType: 'current'
downloadType: 'single'
artifactName: 'drop'
downloadPath: '$(System.ArtifactsDirectory)'
- task: AzureRmWebAppDeployment#4
inputs:
ConnectionType: 'AzureRM'
azureSubscription: 'mySubscription'
appType: 'webApp'
WebAppName: 'myWebApp'
packageForLinux: '$(System.ArtifactsDirectory)/**/Web.zip'
To deploy a .NET framework Web job, you need to put it in a specific folder like App_Data/jobs/continuous for continuous Web Jobs and App_Data/jobs/triggered for scheduled or on-demand Web Jobs .
The following script must be added to the .YAML file .
- task: DotNetCoreCLI#2
inputs:
command: 'publish'
publishWebProjects: true
arguments: '--output $(Build.BinariesDirectory)/publish_output'
zipAfterPublish: false
- task: DotNetCoreCLI#2
inputs:
command: 'publish'
publishWebProjects: false
projects: '**/*webjob.csproj'
arguments: '--output $(Build.BinariesDirectory)/publish_output/App_Data/jobs/continuous/YoutubeWebJob'
zipAfterPublish: false
modifyOutputPath: false
The first task will add a the web app the later one will add a web job in this it is a continuous Web job .
refer this tutorial to deploy Web job and webapp together in one pipeline .
refer this documentation on how to deploy .NET framework Web jobs .
Using Azure pipelines, I am trying to build/deploy a Xamarin iOS app that depends on a push notification iOS service extension developed by Airship.
To build an iOS app and a related iOS service extension requires multiple provisioning profiles, one for the app and another for the service extension.
The Azure pipeline build fails, complaining that the service extension provisioning profile does not match the apps provisioning profile.
How do I get an Azure pipeline build to succeed when multiple provisioning profiles are required?
In case it matters, the app is developed using Visual Studio for Mac. I am able to build and run it on a physical test device.
Update #1:
This is the error message we get in the Azure pipeline console. This message is output when trying to build the service extension.
Info.plist : error : Project bundle identifier 'com.orgname.ServiceExtension' does not match specified provisioning profile 'xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx'
(The xxxxx's represent our apps provisioning profile uuid)
Reviewing the Azure code, it looks like there is no way to tell the build step to use multiple provisioning profiles. If I am understanding the code correctly, it looks like the Xamarin iOS Azure pipeline task can only handle a single provProfileUuid value.
Update #2 - The .yml files:
azure-pipelines-prod.yml
variables:
productName: 'OurAppName'
projectBuildNumber: $[counter('', 800)]
versionName: $[format('{0:yyyy}.{0:MM}.{0:dd}', pipeline.startTime)]
name: $(versionName) ($(projectBuildNumber))
jobs:
- template: pipelines/build-ios.yml
parameters:
productionBuild: true
provisioningProfile: 'match_AppStore_com_orgname_appname.mobileprovision'
serviceExtensionProvisioningProfile: 'orgname_appname_service_ext.mobileprovision'
azure-pipeline-build-ios.yml
parameters:
- name: productionBuild
type: boolean
default: false
- name: provisioningProfile
displayName: 'Provisioning Profile'
type: string
- name: serviceExtensionProvisioningProfile
displayName: 'Provisioning Profile for App Extension'
type: string
jobs:
- job: iOS
pool:
vmImage: 'macOS-latest'
variables:
iosRoot: '$(system.defaultworkingdirectory)/$(productName).iOS'
iosProjectPath: '$(iosRoot)/*iOS.csproj'
NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget/packages
buildConfiguration: 'Release'
outputDirectory: '$(build.binariesDirectory)/$(buildConfiguration)'
infoPlist: '$(iosRoot)/Info.plist'
# if not a production build, add the QA build symbol for compiler switches
${{ if eq(parameters.productionBuild, false) }}:
buildArgs: '/p:DefineConstants="QA"'
${{ if eq(parameters.productionBuild, true) }}:
buildArgs: ''
steps:
# restore and run unit tests
- template: unit-tests.yml
# Set build number and version Name
- task: ios-bundle-version#1
displayName: 'Set build number and version Name'
inputs:
sourcePath: '$(infoPlist)'
versionCodeOption: 'buildid'
versionCode: '$(projectBuildNumber)'
versionName: '$(versionName)'
printFile: true
# Install signing certificate
- task: InstallAppleCertificate#2
displayName: 'Install signing certificate'
inputs:
certSecureFile: 'AppleSigningCertificate.p12'
certPwd: '$(ios-cert-key)'
# Install Provisioning Profile
- task: InstallAppleProvisioningProfile#1
displayName: 'Install Provisioning Profile'
inputs:
provProfileSecureFile: ${{ parameters.provisioningProfile }}
# Install App Extension Provisioning Profile
- task: InstallAppleProvisioningProfile#1
displayName: 'Install Provisioning Profile for App Extension'
inputs:
provProfileSecureFile: ${{ parameters.serviceExtensionProvisioningProfile }}
# Build iOS ipa package
- task: XamariniOS#2
displayName: Build iOS ipa package
inputs:
solutionFile: '$(iosProjectPath)'
configuration: '$(buildConfiguration)'
buildForSimulator: false
packageApp: true
signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)'
signingProvisioningProfileID: '$(APPLE_PROV_PROFILE_UUID)'
args: /p:IpaPackageDir="$(Build.ArtifactStagingDirectory)" /p:OutputPath="$(outputDirectory)/iPhone/" /p:RestorePackages=false $(buildArgs)"
# Archive dSYM
- task: ArchiveFiles#2
displayName: 'Archive dSYM'
inputs:
rootFolderOrFile: '$(outputDirectory)/iPhone/$(productName).iOS.app.dSYM'
includeRootFolder: false
archiveType: 'zip'
archiveFile: '$(Build.ArtifactStagingDirectory)/$(productName).iOS.app.dSYM.zip'
replaceExistingArchive: true
# on non-prod builds, make a simulator build
- ${{ if eq(parameters.productionBuild, false) }}:
# Create simulator build
- task: XamariniOS#2
displayName: 'Create simulator build'
inputs:
solutionFile: '$(iosProjectPath)'
configuration: '$(buildConfiguration)'
buildForSimulator: true
packageApp: false
args: /p:OutputPath="$(outputDirectory)/iPhoneSimulator/" /p:RestorePackages=false $(buildArgs)
# Archive Simulator Build
- task: ArchiveFiles#2
displayName: 'Archive Simulator Build'
inputs:
rootFolderOrFile: '$(outputDirectory)/iPhoneSimulator/$(productName).iOS.app'
includeRootFolder: false
archiveType: 'zip'
archiveFile: '$(Build.ArtifactStagingDirectory)/$(productName).iOS.app.zip'
replaceExistingArchive: true
# Archive Simulator dSYM
- task: ArchiveFiles#2
displayName: 'Archive Simulator dSYM'
inputs:
rootFolderOrFile: '$(outputDirectory)/iPhoneSimulator/$(productName).iOS.app.dSYM'
includeRootFolder: false
archiveType: 'zip'
archiveFile: '$(Build.ArtifactStagingDirectory)/$(productName).iOS.app.Simulator.dSYM.zip'
replaceExistingArchive: true
# publish artifacts to pipeline
- task: PublishBuildArtifacts#1
displayName: 'publish artifacts to pipeline'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop'
publishLocation: 'Container'
I have a .NET MVC solution in Visual Studio 2019 that contains 3 projects:
AdminWebApp
SharedCode (which is set as a dependency in both of the other projects in VS)
FrontWebApp
In Azure DevOps Pipelines I want to create separate builds for
AdminWebApp
and
FrontWebApp
which will both contain the
SharedCode
because it contains helpers etc. I want to do it with the YAML way.
Should I create 1 or 2 pipelines (each artifact will be later published to its own Azure App Service)? What is the YAML code to achieve it?
It would really matter on how the management and release cycle looks like. The puristic way would be to redeploy everything every-time. The realistic way would be to group deployment pipelines together when it make sense.
In terms of what to do in the "YAML way". Would look at using YAML templates
The template parameter would at least by the directory of the project to build. This is an example of a .net Core template but will give you an idea of the thought process: For example purposes this YAML file would be called something like build-corewebapp.yml
parameters:
SolutionPath: ''
BuildConfiguration: 'Release'
projectName: ''
DependsOn: []
publish: 'false'
jobs:
- job: Build_${{ parameters.projectName }}
dependsOn: ${{ parameters.DependsOn }}
steps:
- task: DotNetCoreCLI#2
displayName: 'dotnet restore'
inputs:
command: 'restore'
projects: '$(Build.SourcesDirectory)/${{ parameters.SolutionPath }}/${{ parameters.projectName }}**/*.csproj'
- task: DotNetCoreCLI#2
displayName: 'dotnet build'
inputs:
projects: '$(Build.SourcesDirectory)/${{ parameters.SolutionPath }}/${{ parameters.projectName }}**/*.csproj'
arguments: '--configuration ${{ parameters.BuildConfiguration }}'
- task: DotNetCoreCLI#2
displayName: 'dotnet test'
inputs:
command: test
projects: '$(Build.SourcesDirectory)/${{ parameters.SolutionPath }}/${{ parameters.projectName }}.Tests/*.csproj'
arguments: '--configuration ${{ parameters.BuildConfiguration }} --collect "Code coverage" '
- job: Publish_${{ parameters.projectName }}
dependsOn: Build_${{ parameters.projectName }}
condition: and(succeeded(),eq( ${{ parameters.publish }}, 'true'))
steps:
- task: DotNetCoreCLI#2
displayName: 'dotnet publish'
inputs:
command: publish
publishWebProjects: false
projects: '$(Build.SourcesDirectory)/${{ parameters.SolutionPath }}/${{ parameters.projectName }}**/*.csproj'
arguments: '--configuration ${{ parameters.BuildConfiguration }} --output $(build.artifactstagingdirectory)'
zipAfterPublish: True
- task: PublishBuildArtifacts#1
displayName: 'Publish Artifact: drop'
A template would be called by something similar to:
jobs:
- template: build-corewebapp.yml
parameters:
projectName: ${{ variables.appProjectName }}
solutionPath: $(solutionPath)
publish: 'true'
For max re usability I would recommend any kind of build template to exist in a separate repository so it can be used by other repos. This would be setup in your pipeline by referencing the repo similar to:
resources:
repositories:
- repository: repositoryTemplate
type: git
name: ProjectName/YAMLTEMPLATERepoName
The pro to using templates is then updating a task version or changing a build/deployment strategy can be updated and referenced in one place.
You can use conditions to make separate builds, so that you can put all build steps in one pipeline. Here's similar topic.
Simple sample for your build steps:
steps:
- task: PowerShell#2
inputs:
targetType: 'inline'
script: |
$files=$(git diff HEAD HEAD~ --name-only)
$temp=$files -split ' '
$count=$temp.Length
For ($i=0; $i -lt $temp.Length; $i++)
{
$name=$temp[$i]
echo "this is $name file"
if ($name -like "AdminWebApp/*")
{
Write-Host "##vso[task.setvariable variable=RunAdminWebApp]True"
}
if ($name -like "SharedCode/*")
{
Write-Host "##vso[task.setvariable variable=RunSharedCode]True"
}
if ($name -like "FrontWebApp/*")
{
Write-Host "##vso[task.setvariable variable=RunFrontWebApp]True"
}
}
- task: MSBuild#1
inputs:
solution: '**/AdminWebApp.csproj'
msbuildArguments: 'xxx'
condition: or(variables['RunAdminWebApp'], variables['RunSharedCode'])
- task: MSBuild#1
inputs:
solution: '**/FrontWebApp.csproj'
msbuildArguments: 'xxx'
condition: or(variables['RunFrontWebApp'], variables['RunSharedCode'])
- task: PublishBuildArtifacts#1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop'
publishLocation: 'Container'
If any file in your AdminWebApp project changes, then only build the AdminWebApp and SharedCode project.(First build task)
If any file in your FrontWebApp project changes, then only build the FrontWebApp and SharedCode project.(Second build task)
And if the file in SharedCode changes, since the two projects depend on it, both two build tasks will run.
You should specify the msbuild arguments(/t:publish...) so that the build task can generate zip package to deploy. (Otherwise you need to add additional task to zip the output files)
Since you'll get two published zip files once the SharedCode project has changes. Then your release pipeline should at least have two deploy tasks. For you release: One PS task(determine whether the A.zip/B.zip exists and then set custom variables DeployA/DeployB) and two conditional Deploy tasks based of the value of DeployA/DeployB.(Just a suggestion,it's not about your original issue, so I won't talk much about it here...)
My project contains 2 Dockerfiles, one for the backend and one for a mock database. I have a build pipeline in Azure using the following script:
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)'
msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- task: CopyFiles#2
inputs:
SourceFolder: './MyProject'
Contents: '**'
TargetFolder: '$(build.artifactStagingDirectory)'
flattenFolders: true
- task: CopyFiles#2
inputs:
SourceFolder: './MyProject/Database'
Contents: '**'
TargetFolder: '$(build.artifactStagingDirectory)/Database'
flattenFolders: true
- task: ArchiveFiles#2
displayName: "Archive files"
inputs:
rootFolderOrFile: "$(build.artifactStagingDirectory)"
includeRootFolder: true
archiveFile: "$(System.DefaultWorkingDirectory)/build$(Build.BuildId).zip"
- task: PublishBuildArtifacts#1
inputs:
PathtoPublish: '$(build.artifactStagingDirectory)'
ArtifactName: 'backend'
I put 2 CopyFiles steps in there because I have 2 Dockerfiles, one in /MyProject for the backend and one in /MyProject/Database for a mock database. This way I can choose between both Dockerfiles later on in my release pipeline. In the picture below I have one Dockerfile marked in the backend folder and you can see the other Dockerfile in the Database folder.
The problem is that even though I select the Dockerfile placed in the backend folder for the release step, the pipeline uses the Dockerfile for the database. Presumably this is because this is the first Dockerfile it encounters, even though it is located in a subdirectory of what I have specified. How can I make my pipeline use the correct Dockerfile?
Found the problem: setting flattenFolders: true did so that the Dockerfile in the subdirectory overwrote the top-level Dockerfile. By setting it to false I got the complete folder structure and could choose the correct Dockerfile.
I'm getting below warning while building Artifacts on Azure Deops pipeline.
Unable to integrate continuous deployment because publish Artifact for Xamarin iOS project:
[warning]Directory '/Users/vsts/agent/2.152.1/work/16/a' is empty. Nothing will be added to build artifact 'drop'
I'm building this solution for Xamarin.iOS and need to publish it on App Center.
YAML for PublishBuildartifacts
task: PublishBuildArtifacts#1
displayName: 'Publish Artifact: drop'
inputs:
PathtoPublish: '$(build.artifactstagingdirectory)'
condition: succeededOrFailed()
YAML for CopyFiles
steps:
task: CopyFiles#2
displayName: 'Copy Files to: $(build.artifactstagingdirectory)'
inputs:
SourceFolder: '$(system.defaultworkingdirectory)'
Contents: '**/*.ipa'
TargetFolder: '$(build.artifactstagingdirectory)'
CleanTargetFolder: true
condition: succeededOrFailed()
The error caused by your Contents format of CopyFiles task is incorrect. As a folder path, you should not use /, modify it to \.
So change your the Contents as:
Contents: **\*.ipa