How to Publish a ClickOnce application with Azure DevOps Pipeline on different environments? - azure-devops

I try for several days now to publish my ClickOnce application with Azure DevOps Pipeline. Before going in detail here is what I would like to do from my release view:
I started with one artifact and 2 release stage modifying the config.deploy file with staging variables during my Staging stage and modifying the config.deploy file with production variables during my Production stage. Deployment was working fine but installation of application was not working because of hash check system.
So I decided to create 2 builds with 2 artifacts. I renamed the classic drop by a drop_staging during my first build and drop_production for my second build. I was hoping the build system (MSBuild) was able to select the correct app.Debug.config then app.Release.config file during the build and publish process.
Here is my build definition
Here is my build arguments
/target:publish
/p:ApplicationVersion=$(Build.BuildNumber)
/p:PublishURL=http://app-staging.example.com/
/p:UpdateEnabled=true
/p:UpdateMode=Foreground
/p:ProductName="App Staging"
/p:OutputPath="$(build.ArtifactStagingDirectory)\Publish\\"
Configuration is set to Staging for first build then on Production for second build. I have, of course, a Staging and Production build definition in visual Studio. I have an app.config with app.Staging.config and app.Production.config in my project.
I cannot simply add a task to transform my config file after the build because I will not respect the hash. I should find a way to say to my build to use the correct XML transformation config file. I don't see any other solution or maybe applying this transformation before the build? Is it possible? What are your solutions?

finally I could solve this by adding a file transform before my build.
In case you need more help here is my YAML detail for transformation
steps:
- task: FileTransform#1
displayName: 'File Transform: '
inputs:
folderPath: App.Example
enableXmlTransform: true
xmlTransformationRules: '-transform **\*.Staging.config -xml **\*.config'
fileType: xml
#Your build pipeline references the ‘BuildPlatform’ variable, which you’ve selected to be settable at queue time. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab, and then select the option to make it settable at queue time. See https://go.microsoft.com/fwlink/?linkid=865971
steps:
- task: VSBuild#1
displayName: 'Build solution'
inputs:
solution: Example.sln
msbuildArgs: '/target:publish /p:ApplicationVersion=$(Build.BuildNumber) /p:PublishURL=http://staging.example.com/ /p:UpdateEnabled=true /p:UpdateMode=Foreground /p:ProductName="App Staging" /p:OutputPath="$(build.ArtifactStagingDirectory)\Publish\\"'
platform: '$(BuildPlatform)'
configuration: Staging

To add to the build solution stage, you can use your visual studio Publish profile as shown below on the msbuildArgs. Please note this doesn't do the version incrementation for you
- task: VSBuild#1
displayName: 'Publish Project'
inputs:
solution: '$(projectSolution)'
msbuildArgs: '/target:publish /p:ApplicationRevision=$(applicationRevision) /p:PublishProfile="Application/PublishProfiles/HerbalPublishProfile.pubxml" /p:PublishDir="$(build.ArtifactStagingDirectory)\Publish\\"'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
msbuildArchitecture: x64

Related

Single WCF project will not create build artifact under YAML Azure DevOps Build Pipeline

Our build pipeline includes a YML template that is used to build all of our WCF services and Web applications. For all of the WCF services but one, it works like a charm. For this one WCF service, however, the following output is generated in the build logs during the Publish Artifact stage:
##[warning]Directory 'D:\azagent\A2_work\1381\a' is empty. Nothing will be added to build artifact 'drop'.
Our Build stage invokes a separate YML file which includes the following to build and publish the project:
- task: VSBuild#1
displayName: "Build ${{ parameters.solution}}"
inputs:
solution: ${{ parameters.solution }}
msbuildArgs: >
/p:DeployOnBuild=true
/p:WebPublishMethod=Package
/p:PackageAsSingleFile=true
/p:SkipInvalidConfigurations=true
/p:IgnoreDeployManagedRuntimeVersion=true
/p:PackageLocation="$(build.ArtifactStagingDirectory)"
platform: ${{ parameters.buildPlatform }}
configuration: ${{ parameters.buildConfiguration }}
- task: PublishBuildArtifacts#1
displayName: "Publish Build Artifact"
inputs:
PathtoPublish: "$(Build.ArtifactStagingDirectory)"
ArtifactName: "drop"
publishLocation: "Container"
As stated earlier, this works perfectly for all other WCF projects, and generates a build artifact. However, for the problematic WCF Service, no build artifact is generated. What we've observed is that no ZIP file is created in the D:\azagent\A2_work\1381\a folder (theoretically, Build.ArtifactStagingDirectory).
I have tried numerous recommended solutions to resolve this issue, all to no effect.
Adding a CopyFiles#2 task between the VSBuild#1 task and the PublishBuildArtifacts#1 task did place the files in the Build.ArtifactStagingDirectory, but they were not in a ZIP file. Further, the deployment task (later in the pipeline) failed because no ZIP file was present in the drop folder.
Adding /p:OutDir=$(Build.ArtfactStagingDirectory) did seem to produce some sort of artifact, but the deployment task still failed, claiming it could not find the ZIP file in the drop folder.
I created a test repo that contained only the WCF project (as it's normally contained in a solution containing it and a Web application) and ran the pipeline against that repo. No build artifact was created.
Ultimately, nothing I do seems to be able to get this project to generate a build artifact.
What am I missing here? What further information can I provide that will help you to help me resolve this issue?
According to Microsoft's Developer Community, this has been a known issue since August of 2019. WCF services built using a YAML pipeline do not produce build artifacts. Consequently, they cannot be deployed via YAML pipelines.
As of this date, there is neither a fix nor a workaround available from Microsoft.

Azure DevOps Pipeline is not copying or deploying all my projects

I need some help to create my build pipeline.
At Build solution step I do a classic build with no MSBuild arguments. But in my solution file I have many projects. One of them is the API and 3 of them are 3 clients applications, one winform, one clickonce and one web client.
When I build localy with Visual Studio from a clean solution during the build Visual Studio properly create all bin folder, release or debug subfolder and publish sub folder for related publishable projects.
When I do the same with the MSBuild from Azure DevOps Pipeline I don't know what happens. The logs seems ok but when I copy then publish my artifact I get only few project.
Here is my YAML
#Your build pipeline references an undefined variable named ‘Parameters.solution’. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab. See https://go.microsoft.com/fwlink/?linkid=865972
#Your build pipeline references the ‘BuildPlatform’ variable, which you’ve selected to be settable at queue time. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab, and then select the option to make it settable at queue time. See https://go.microsoft.com/fwlink/?linkid=865971
#Your build pipeline references the ‘BuildConfiguration’ variable, which you’ve selected to be settable at queue time. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab, and then select the option to make it settable at queue time. See https://go.microsoft.com/fwlink/?linkid=865971
steps:
- task: VSBuild#1
displayName: 'Build solution *****.sln'
inputs:
solution: '$(Parameters.solution)'
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
#Your build pipeline references the ‘BuildConfiguration’ variable, which you’ve selected to be settable at queue time. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab, and then select the option to make it settable at queue time. See https://go.microsoft.com/fwlink/?linkid=865971
steps:
- task: CopyFiles#2
displayName: 'Copy Files to: $(build.ArtifactStagingDirectory)'
inputs:
SourceFolder: '$(system.DefaultWorkingDirectory)'
Contents: '**\bin\$(BuildConfiguration)\**'
TargetFolder: '$(build.ArtifactStagingDirectory)'
#Your build pipeline references an undefined variable named ‘Parameters.ArtifactName’. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab. See https://go.microsoft.com/fwlink/?linkid=865972
steps:
- task: PublishBuildArtifacts#1
displayName: 'Publish Artifact: drop'
inputs:
PathtoPublish: '$(build.ArtifactStagingDirectory)'
ArtifactName: '$(Parameters.ArtifactName)'
condition: succeededOrFailed()

Skeleton for a CI/CD pipeline as YAML definition

I'm trying to to create a yaml definition file for a simple CI/CD pipeline in Azure DevOps.
My pipeline should look like this:
Is it possible to define the whole workflow in one definition file with different stages and jobs?
How can I determine which project (which GIT sub-path has triggered the build) has changed to proceed with project A/B workflow?
The first workflow with project A seems feasible for me. I can run the sc command together with runsas or psexec to start/stop the service and use a copy file task. But how can I initiate to publish the ASP.NET web application to a local directory (as I would do with VS->Publish->Local Folder)?
After that I guess it's the easiest way to make use of scripts to replace content, install npm packages to minify and bundle js/css files and upload these to a ftp server. Or any better/easier ideas?
If you guys can support me by creating an initial yaml definition just for the workflow without the details of the tasks I would really appreciate that. Maybe I get a more clear vision if you can answer my questions above.
At the moment I have a very simple initial build file:
# ASP.NET
# Build and test ASP.NET projects.
# Add steps that publish symbols, save build artifacts, deploy, and more:
# https://learn.microsoft.com/azure/devops/pipelines/apps/aspnet/build-aspnet-4
trigger:
- master # for a productive deployment after manual approval
- develop # for a automatic test deployment
pool:
vmImage: 'windows-latest'
variables:
solution: '**/*.sln'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
steps:
- task: NuGetToolInstaller#0
- task: NuGetCommand#2
inputs:
restoreSolution: '$(solution)'
feedsToUse: 'select'
vstsFeed: 'tpcemedia'
- 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)'
No, releases are not yet possible in yaml. You can have build stages\jobs, but it makes no sense to use them in such a simple case
Yaml has a path-trigger filter, just configure a build per application. no need to complicate the build with conditions. do something like this:
build1:
trigger:
paths:
include: src/proj1/*
build2:
trigger:
paths:
include: src/proj2/*
Better to separate release and build, this way your release agent will be directly on the server and would be able to restart service locally without the need to have network access (and its more secure). It would also pull the artifacts generated by the build agent "for free".
Why use ftp, just use "publish artifacts" step(s), much easier.

Azure DevOps release pipeline: Angular and .NET Core application

We're trying to release an Angular 7 / .NET Core application into Azure using the DevOps release pipelines. I have my build setup to create the .NET and Angular builds as separate artifacts which you can see in the screen shots below (under the Package or Folder box).
From what I've read it seems that you need to create two separate release tasks to deploy the builds to the web app. However the second build seems to be overriding the first which is causing the API not to start.
Does anyone know of a way to ensure the deployments in a given stage simply appends the changes rather than replacing them? Or is there something else I am missing here?
My recommendation would be to implement the following pattern for your pipeline:
'ng build --prod' the angular app in it's own job, and add the artifacts to your pipeline
'dotnet publish' the dotnet core api in it's own job, running in parallel with the angular job, and add the artifacts to your pipeline
Append the Angular and Dotnet Core artifacts together into a new artifact. This serves as your final package to deploy
Deploy the final package
You're missing step 3, so you'd want something like the following logic defined in YAML, where you create a new zip that represents your actual deployed bits in your pipeline. Then release that artifact, since it is the representation of what you have running on your instances.
- job: CreateReleaseArtifact
displayName: 'Package for shared-hosting of angular app and web api'
pool:
vmImage: windows-2019
dependsOn:
- BuildNetcore
- BuildAngularApp
condition: succeeded()
steps:
- checkout: none
- download: current
- task: CopyFiles#2
displayName: 'Copy WebApi Files'
inputs:
SourceFolder: $(Pipeline.Workspace)/api
Contents: '**/*'
TargetFolder: $(Pipeline.Workspace)/package
includeRootFolder: false
- task: CopyFiles#2
displayName: 'Copy Angular Files'
inputs:
SourceFolder: $(Pipeline.Workspace)/webapp
Contents: 'wwwroot/**'
TargetFolder: $(Pipeline.Workspace)/package
includeRootFolder: true
OverWrite: true
- publish: $(Pipeline.Workspace)/package
artifact: package
Does anyone know of a way to ensure the deployments in a given stage simply appends the changes rather than replacing them?
Based on my experience, in your case, after deploy the API or Angular 7, then I you could use the Kudu zip API to upload another one to the Azure WebApp.
You could use the Powershell task to do that. For more inforamtion about powershell demo code, you could refer to this link.
If creating another WebApp is acceptable, you could add a new WebApp and use the same service plan (no extral cost). Then you could deploy them separately.

How do I automate unpacking the zip deployed via devops?

I want to set up CI/CD for a .NETCore2 api project with an Azure repository.
I want the release to be deployed to a folder on my Windows computer c:\mywebapi
I have set up a build pipeline to do the build and a release pipeline to do the deploy.
However the files land on my computer as C:\agent_work\rX\a\myrelease\drop\WebApp.Zip of the target machine.
Where X is the release number.
How do I automate the last step of unpacking the zip to c:\mywebapi folder ?
Here is the build Yaml
resources:
- repo: self
queue:
name: Hosted VS2017
demands:
- msbuild
- visualstudio
- vstest
#Your build pipeline references an undefined variable named ‘Parameters.solution’. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab. See https://go.microsoft.com/fwlink/?linkid=865972
#Your build pipeline references an undefined variable named ‘Parameters.solution’. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab. See https://go.microsoft.com/fwlink/?linkid=865972
#Your build pipeline references the ‘BuildPlatform’ variable, which you’ve selected to be settable at queue time. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab, and then select the option to make it settable at queue time. See https://go.microsoft.com/fwlink/?linkid=865971
#Your build pipeline references the ‘BuildConfiguration’ variable, which you’ve selected to be settable at queue time. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab, and then select the option to make it settable at queue time. See https://go.microsoft.com/fwlink/?linkid=865971
#Your build pipeline references the ‘BuildConfiguration’ variable, which you’ve selected to be settable at queue time. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab, and then select the option to make it settable at queue time. See https://go.microsoft.com/fwlink/?linkid=865971
#Your build pipeline references the ‘BuildPlatform’ variable, which you’ve selected to be settable at queue time. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab, and then select the option to make it settable at queue time. See https://go.microsoft.com/fwlink/?linkid=865971
#Your build pipeline references the ‘BuildConfiguration’ variable, which you’ve selected to be settable at queue time. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab, and then select the option to make it settable at queue time. See https://go.microsoft.com/fwlink/?linkid=865971
#Your build pipeline references an undefined variable named ‘Parameters.ArtifactName’. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab. See https://go.microsoft.com/fwlink/?linkid=865972
steps:
- task: NuGetToolInstaller#0
displayName: 'Use NuGet 4.4.1'
inputs:
versionSpec: 4.4.1
- task: NuGetCommand#2
displayName: 'NuGet restore'
inputs:
restoreSolution: '$(Parameters.solution)'
- task: VSBuild#1
displayName: 'Build solution'
inputs:
solution: '$(Parameters.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: VSTest#2
displayName: 'Test Assemblies'
inputs:
testAssemblyVer2: |
**\$(BuildConfiguration)\*test*.dll
!**\obj\**
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
- task: PublishSymbols#2
displayName: 'Publish symbols path'
inputs:
SearchPattern: '**\bin\**\*.pdb'
PublishSymbols: false
continueOnError: true
- task: PublishBuildArtifacts#1
displayName: 'Publish Artifact'
inputs:
PathtoPublish: '$(build.artifactstagingdirectory)'
ArtifactName: '$(Parameters.ArtifactName)'
If you just need to unpack the zip file to a specific folder (c:\mywebapi here), then you can use the Extract Files task in build pipeline, release pipeline is not necessary. (Reference below screenshot, unpack to \\172.17.16.147\TestShare\0927 in below sample)
Make sure your build service account has the correct permission
(read and write) to access the specific folder (c:\mywebapi in
your scenario).
Add a Copy Files task to copy the WebApp.Zip file to
$(Build.SourcesDirectory)
Add a Extract Files task to unzip the file
UPDATE:
Well, by default during the build it only generate a zip file and publish Artifact as the deploy source.
To deploy the application to a target machine or website you need to create a release pipeline and link the artifact source, then use IIS Web App Deploy task to deploy it. If you want to deploy as an Virtual Application, then you also need to provide the Virtual Application name...