How to deploy multiple apps (monorepo) with Azure and NX - azure-devops

I'm using NX tools to manage a monorepo with multiple apps and I'm struggling to understand how to deploy using Azure and release pipelines.
Disclaimer : I'm very new to Azure and devops in general.
My understanding is this :
I create a pipeline (not a release pipeline, just a "regular one" if that make any sense) and plug a yml to it. Also, the pipeline is linked to a repo on Azure Repos, which means that every time I push to this repo, it will trigger the pipeline and run the yaml commands.
On this commands, I run lint, test and builds.
This is what I can do and can understand, the following become more obscure :
The build job is supposed to create an artifact if I'm pusing/merging on master which I can conditioned.
Now I can create a release pipeline which will be trigger when to repo it is linked to will create an artifact. This release pipeline can then send this artifact to an app service which is a slot where an app will live.
Okay, but I'm using a monorepo, which means the build will produce multiple applications and each one of these apps should be deploy to the correct app service.
After some research, I found that the general idea is to create one release pipeline for each app. These release pipelines are all linked to the same monorepo, but they have a filter which is a build tag. The build tag is added while building the apps using the yml file.
So these are basically my understanding of all of this. Now here are the questions :
What exactly is a build tag and where does it live? Is it somehow linked to an artifact?
The idea is to create one build tag per artifact, right?
I failed to create a build tag, how can I do so?
What is the correct way to zip and publish the artifacts?
Here is the yaml I'm using :
jobs:
- job: Lint
steps:
- task: NodeTool#0
inputs:
versionSpec: '12.x'
displayName: 'Install Node.js'
- task: Npm#1
displayName: 'Npm install'
- pwsh: 'npm run nx affected -- --target=lint --parallel --base=origin/master --maxParallel=4'
displayName: 'Running lint'
- job: Test
steps:
- task: NodeTool#0
inputs:
versionSpec: '12.x'
displayName: 'Install Node.js'
- task: Npm#1
displayName: 'npm install'
- pwsh: 'npm run nx affected -- --target=test --parallel --code-coverage --base=origin/master --maxParallel=4'
displayName: 'Running tests'
- job: Build
steps:
- task: NodeTool#0
inputs:
versionSpec: '12.x'
displayName: 'Install Node.js'
- task: Npm#1
displayName: 'npm install'
- pwsh: 'npm run nx affected -- --target=build --parallel --base=origin/master --prod'
displayName: 'Running build'
- pwsh: |
npm run nx affected:apps -- --base=HEAD~1 --head=HEAD | grep -E '( - )(\w|-|\d|_)+' | sed -E 's/ - /##vso[build.addbuildtag]/g'
displayName: 'Adding build tags'
When running this, test, lint and builds are working, but I don't think it adds a build tag, here is the log :
It appears like nothing happens... How can I correctly add the tag and make the release pipeline to be triggered?
I've also found this snippet to zip and publish the artifact, but I don't know if I can use that since in a monorepo we should - I think - create multiple artifacts.
5) So the last question is : how can I create multiple artifacts and is it even the good thing to do?
Many many thanks in advance for the help, I know this is a long boring post and helping a noob can be boring but I'm stuck with this for way to long...

1, You can add tags for a build from the UI page(Build summary page, see below) or using Rest api. It can be used to filter between builds. If your build pipeline generated multiple artifacts, build tags will not be able to filter the artifacts which generated in one build.
2, So you can think about how to separate the build artifacts for each app in your pipeline.
You can use Archive files task to zip your build artifacts and publish using publish build artifacts task.
See below yaml example: I used two archive files task to package the build artifacts for app1 and app2 separately. And save the zipped artifacts in folder $(Build.ArtifactStagingDirectory).
Then the publish build artifacts task will publish the artifacts to azure devops cloud. (Release pipeline will download the artifacts to deploy to your app server)
- task: ArchiveFiles#2
inputs:
rootFolderOrFile: $(system.defaultworkingdirectory)/app1/dist
archiveType: 'zip'
archiveFile: '$(Build.ArtifactStagingDirectory)/app1/dist1.zip'
includeRootFolder: false
enabled: true
- task: ArchiveFiles#2
inputs:
rootFolderOrFile: $(system.defaultworkingdirectory)/app2/dist
archiveType: 'zip'
archiveFile: '$(Build.ArtifactStagingDirectory)/app2/dist2.zip'
includeRootFolder: false
enabled: true
- task: PublishBuildArtifacts#1
inputs:
PathtoPublish: $(Build.ArtifactStagingDirectory)/
artifactName: build
3, Then you can use multiple stages in your release pipeline and use Azure App Service Deploy task. For below example:
In stage one add Azure App Service Deploy task and set the package to $(System.DefaultWorkingDirectory)/**/app1/dist1.zip to deploy app1. And in stage two set it to $(System.DefaultWorkingDirectory)/**/app2/dist2.zip to deploy app2.
Another workaround to deploy multiple apps in monorepo is to create multiple build/release pipeline, one for each app. And in the build pipeline using path filter to let the build pipeline only be triggered when it corresponding app is updated.
trigger:
paths:
include:
- root/app1/*
Hope above helps!

#levi Lu-MSFT answered helped me a ton and is basically how we are doing it, but they didn't really give full yaml code.
The way we have the release pipeline set up is one release pipeline per application, looking at the build tags for the release trigger. We are currently bundling all apps together inside one artifact, so the downside is when an app's main branch is triggered, the release process will download all the apps.
The way I added my build tags dynamically started with this nx command:
npx nx affected:apps --base=origin/main --plain
which prints out a list of apps that have changed. From there, I loop through the apps and create the build tags dynamically.
Here I have two jobs, one that runs on PR's and one that runs on main branch.
trigger:
branches:
include:
- main
pool:
name: My-Pool
demands: Agent.OS -equals Windows_NT
jobs:
- job: NX_AFFECTED_PR
pool:
name: WBOmega-Pool
demands: Agent.OS -equals Windows_NT
condition: eq(variables['Build.Reason'], 'PullRequest')
steps:
- task: Npm#1
displayName: 'npm install'
inputs:
command: 'install'
verbose: true
- powershell: |
npx nx affected:apps --base=origin/main --plain | Tee-Object -Variable output
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12
foreach ($appName in ($output -replace '\s+', ' ').Split()) {
Write-Host "this is the app-name: $appName"
if($appName.Trim() -eq ""){
Write-Host "App name is blank"
} else {
$url="https://dev.azure.com/YOUR_ORG/$(System.TeamProject)/_apis/build/builds/$(build.buildid)/tags/" + $appName + "?api-version=6.0"
Write-Host $url
$result = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Bearer $(System.AccessToken)"} -Method Put
}
}
name: set_build_tags
- powershell: |
npx nx affected --target=build --base=origin/main --parallel --max-parallel=3
name: build
- powershell: |
npx nx affected --target=lint --base=origin/main --parallel --max-parallel=3
name: lint
- powershell: |
npx nx affected --target=test --base=origin/main --parallel --max-parallel=3
name: test
- job: NX_AFFECTED_MAIN
pool:
name: My-Pool
demands: Agent.OS -equals Windows_NT
condition: ne(variables['Build.Reason'], 'PullRequest')
steps:
- checkout: self
persistCredentials: true
- powershell: |
npx nx affected:apps --base=HEAD~1 --plain | Tee-Object -Variable output
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12
foreach ($appName in ($output -replace '\s+', ' ').Split()) {
Write-Host "this is the app-name: $appName"
if($appName.Trim() -eq ""){
Write-Host "App name is blank"
} else {
$url="https://dev.azure.com/YOUR_ORG/$(System.TeamProject)/_apis/build/builds/$(build.buildid)/tags/" + $appName + "?api-version=6.0"
Write-Host $url
$result = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Bearer $(System.AccessToken)"} -Method Put
}
}
name: set_build_tags
- powershell: |
npx nx affected --target=build --base=HEAD~1 --parallel --max-parallel=3
name: build
- powershell: |
npx nx affected --target=lint --base=HEAD~1 --parallel --max-parallel=3
name: lint
- powershell: |
npx nx affected --target=test --base=HEAD~1 --parallel --max-parallel=3
name: test
- task: CopyFiles#2
displayName: 'Copy Files to: $(build.artifactstagingdirectory)\apps\'
inputs:
SourceFolder: '$(Build.SourcesDirectory)\dist\apps\'
TargetFolder: '$(build.artifactstagingdirectory)\apps\'
CleanTargetFolder: true
OverWrite: true
- task: PublishBuildArtifacts#1
displayName: 'Publish Artifact'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)\apps'
ArtifactName: 'Apps'

Related

Question about Azure Devops pipeline question about task conditions

I've been trying to setup an Azure Devops pipeline for testing purposes and i'm struggling to understand why one of my tasks runs the script line despite being skipped.
Here's the pipeline yaml code:
## Example azure-pipelines.yml
## Event (branch to trigger the pipeline execution)
trigger:
branches:
include:
- main
exclude:
- My-branch # Will not run
# Configures pipeline execution on pull requests
pr:
branches:
include:
- main
exclude:
- My-branch # Will not run
# Environment variables created
variables:
- group: my-keys
## OS where the pipeline will run
pool:
vmImage: 'ubuntu-latest'
# List of stages for your application
stages:
- stage: Test
displayName: Application Testing
# List of jobs the pipeline stage will run
jobs:
- job: MyJob
displayName: Install packages and and publishes
variables:
# Sets the environment variable to cache the application packages
npm_config_cache: $(Pipeline.Workspace)/.npm
# List of steps for the job
steps:
- task: NodeTool#0
inputs:
versionSpec: '12.x'
displayName: 'Install Node.js'
- task: Cache#2
displayName: Install and cache packages
inputs:
key: 'npm | "$(Agent.OS)" | package-lock.json'
restoreKeys: |
npm | "$(Agent.OS)"
path: $(npm_config_cache)
- script: npm ci
condition: ne(variables.CACHE_RESTORED, 'true')
- task: Npm#1
displayName: Publish and auto accept
condition: and(succeeded(), eq(variables['build.sourceBranch'], 'refs/heads/main'))
- script: npx my-package --with-token=${my-keys} --auto-publish-changes
- task: Npm#1
displayName: Publish
condition: eq(variables['Build.Reason'], 'PullRequest')
- script: npx my-package --with-token=${my-keys}
- script: echo ${{variables['Build.Reason']}} ${{eq(variables['Build.Reason'], 'PullRequest')}}
A example, for instance when a push is made into the main branch it runs Publish and auto accept followed by the Publish, when it technically should only run the first one. One other thing that i saw was that when a pull request is incoming to one other branch rather than main it shouldn't trigger the script associated to Publish and auto accept but instead jump over that and run only the script in Publish, but instead it runs the scripts in both.
If anyone could provide some help with this i would appreciate it.
Thanks in advance
I think the problem is that you run 4 tasks instead of two
Take a look at NPM task syntax, it has no 'script' parameter
https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/package/npm?view=azure-devops
'script' task that you are using is indeed shortcut of another task 'CmdLine#2'
https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/command-line?view=azure-devops&tabs=yaml
Firstly you run NPM task with specified condition, but it does nothing
task: Npm#1
displayName: Publish and auto accept
condition: and(succeeded(), eq(variables['build.sourceBranch'], 'refs/heads/main'))
Then you run script task without condition(so it will run always), this task does npm stuff
script: npx my-package --with-token=${my-keys} --auto-publish-changes
Then you run again npm task without desired parameters but with conditions
task: Npm#1
displayName: Publish
condition: eq(variables['Build.Reason'], 'PullRequest')
And finally you run fourth task doing stuff, without conditions so it runs always.
script: npx my-package --with-token=${my-keys}
So as to fix this problem, you need to use Npm#1 task with parameters specified in provided documentation. Or just add conditions to your script tasks(CmdLine#2).
I think that below snippet should work
- task: CmdLine#2
displayName: 'Publish and auto accept'
condition: and(succeeded(), eq(variables['build.sourceBranch'], 'refs/heads/main'))
inputs:
script: 'npx my-package --with-token=${my-keys} --auto-publish-changes'
- task: CmdLine#2
displayName: 'Publish'
condition: eq(variables['Build.Reason'], 'PullRequest')
inputs:
script: 'npx my-package --with-token=${my-keys}'

Azure pipeline - unzip artefact, copy one directory into Azure blob store YAML file

I am getting stuck with Azure pipelines.
I have an existing node SPA project that needs built for each environment (TEST and PRODUCTION). This i can do, but need to have a manual step when pushing to PROD. I am using Azure Dev-op pipeline environments with Approval and Checks to mandate this.
The issue is using a 'deploy job' to take an artefact from a previous step I am unable to find the right directory. This is my YAML file have so far:
variables:
# Agent VM image name
vmImageName: 'ubuntu-latest'
trigger:
- master
# Don't run against PRs
pr: none
stages:
- stage: Development
displayName: Devlopment stage
jobs:
- job: install
displayName: Install and test
pool:
vmImage: $(vmImageName)
steps:
- task: NodeTool#0
inputs:
versionSpec: '12.x'
displayName: 'Install Node.js'
- script: |
npm install
displayName: Install node modules
- script: |
npm run build
displayName: 'Build it'
# Build creates a ./dist folder. The contents will need to be copied to blob store
- task: ArchiveFiles#2
inputs:
rootFolderOrFile: '$(Build.BinariesDirectory)'
includeRootFolder: true
archiveType: 'zip'
archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
replaceExistingArchive: true
verbose: true
- deployment: ToDev
environment: development
dependsOn: install
strategy:
runOnce:
deploy:
steps:
- task: DownloadPipelineArtifact#2
inputs:
buildType: 'current'
targetPath: '$(Pipeline.Workspace)'
- task: ExtractFiles#1
inputs:
archiveFilePatterns: '**/*.zip'
cleanDestinationFolder: true
destinationFolder: './cpDist/'
# Somehow within a deploy job retrieve the .zip artefact, unzip, copy the ./dist folder into the blob store
- task: AzureCLI#2
inputs:
azureSubscription: MYTEST-Development
scriptLocation: "inlineScript"
scriptType: "bash"
inlineScript: |
az storage blob upload-batch -d \$web --account-name davey -s dist --connection-string 'DefaultEndpointsProtocol=https;AccountName=davey;AccountKey=xxxxxxx.yyyyyyyyy.zzzzzzzzzz;EndpointSuffix=core.windows.net'
displayName: "Copy build files to Development blob storage davey"
- script: |
pwd
ls
cd cpDist/
pwd
ls -al
displayName: 'list'
- bash: echo "Done"
If you are confused with the folder path, you could add few debug steps to check the location of know system variables to understand what was going on using a powershell script as below:
- task: PowerShell#2
displayName: 'Degug parameters'
inputs:
targetType: Inline
script: |
Write-Host "$(Build.ArtifactStagingDirectory)"
Write-Host "$(System.DefaultWorkingDirectory)"
Write-Host "$(System.ArtifactsDirectory)"
Write-Host "$(Pipeline.Workspace)"
Write-Host "$(System.ArtifactsDirectory)"
You should simply publish the build generated artifacts to drop folder.
Kindly check this official doc -- Artifact selection , in there is explaining that you can define the path which to download the artifacts to with the following task:
steps:
- download: none
- task: DownloadPipelineArtifact#2
displayName: 'Download Build Artifacts'
inputs:
patterns: '**/*.zip'
path: '$(Build.ArtifactStagingDirectory)'
Please be aware that the download happens automatically to $(Pipeline.Workspace), so if you don’t want you deployment to download the files twice, you need to specify the “download: none” in your steps.

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

How to capture and retain the artifact package version for Universal artifacts in azure pipelines for cd

I have this azure devops ci/cd pipeline using yaml. My yaml has two stages CI and CD. My CI stage has one job called BuildandDeploy. The CD stage has one deployment job. I am using universal artifacts to publish and downloading the same. In the CD phase I am using UniversalPackages devops task to download the artifact. The task has a input variable called vstsPackageVersion which is the package version that is shown in universal artifacts. I have known of two other variables that could be used $(Build.BuildId) and $(Build.BuildNumber). As a temporary work around I am hard coding the package version for the universal artifact.
I wasn't able to download the artifact with either of the built-in variables. Since the CI and CD are in the same pipeline, is there any way to store and retrieve the package version of the artifact? Is there a identifier like latest that I could use to get the latest artifact from universal package.
# specific branch build with batching
trigger:
batch: true
branches:
include:
- master
stages:
- stage: CI
jobs:
- job: BuildAndPublish
pool:
vmImage: 'Ubuntu-16.04'
steps:
-
script: |
docker build -t $(dockerId).azurecr.io/$(imageName):$(version) .
docker login -u $(dockerId) -p $(pswd) $(dockerId).azurecr.io
docker push $(dockerId).azurecr.io/$(imageName):$(version)
- task: Bash#3
displayName: Initialize Helm Client - create local repo
inputs:
targetType: 'inline'
script: '
helm init --client-only
'
- task: HelmDeploy#0
displayName: Package helm chart
inputs:
connectionType: 'Kubernetes Service Connection'
command: 'package'
chartPath: 'my-helm-dir'
- task: UniversalPackages#0
displayName: Publish helm package to my-company-artifacts
inputs:
command: 'publish'
publishDirectory: '$(Build.ArtifactStagingDirectory)'
feedsToUsePublish: 'internal'
vstsFeedPublish: '$(my-feed-guid)'
vstsFeedPackagePublish: 'my-artifact-name'
versionOption: patch
packagePublishDescription: 'My helm package descrition'
- stage: CD
jobs:
- deployment: DeployJob
displayName: Deploy Job
pool:
vmImage: Ubuntu-16.04
environment: dev
strategy:
runOnce:
deploy:
steps:
- task: UniversalPackages#0
displayName: 'Universal download'
inputs:
command: download
vstsFeed: '$(my-feed-name)'
vstsFeedPackage: 'my-artifact-name'
vstsPackageVersion: 0.0.32
- task: ExtractFiles#1
displayName: 'Extract files '
inputs:
archiveFilePatterns: '*.tgz'
destinationFolder: 'my-folder'
cleanDestinationFolder: true
The Universal Packages task based on az artifacts universal cli that not support "latest version", but only specific version (by the way, this cli is on preview).
As workaround, you can use the Rest API to retrieve the latest version and set a new variable, then, in the download task use this variable.
For example, add a PowerShell task that get the version number and set the variable:
- powershell: |
$head = #{ Authorization = "Bearer $env:TOKEN" }
$url = "https://feeds.dev.azure.com/{organization}/_apis/packaging/Feeds/{feed-name}/packages/{package-guid}?api-version=5.0-preview.1"
$package = Invoke-RestMethod -Uri $url -Method Get -Headers $head -ContentType application/json
$latestVersion = ($package.versions.Where({ $_.isLatest -eq $True })).version
Write-Host "The latest version is $latestVersion"
Write-Host "##vso[task.setvariable variable=latestVersion]$latestVersion"
env:
TOKEN: $(system.accesstoken)
Now, in the download task use it:
vstsPackageVersion: $(latestVersion)

Azure DevOps test -xml not found after running the Cypress tests

Added a Publish test results task in Azure DevOpsCI/CD pipeline, test were successfull, but after running the test it complaints about ##[warning]No test result files matching **/test-*.xml were found. Could someone please advise on how can we resolve similar problem ?
Publish Test Results task : configuration
Test result format= JUnit
Test results files= **/test-*.xml
Search folder = $(System.DefaultWorkingDirectory)
Test results title = Cypress Test Results
note: I have try adding the search folder path as follows: C:\agent_work\r5\a\drop\ui-tests\cypress
package.json to run the tests
"scripts": {
"test": "cypress run --record --key <key value here>"
}
My directory path in server:
C:\agent_work\r5\a\drop\ui-tests\cypress
My friend, I was facing the same issue on Azure DevOps.
In my case, the folder where the xml files were generated was reports on the root of the repo, that depends on how you got configured Junit on your cypress.json file
So In my case, the solution was changing this on azure-pipelines.yml
testResultsFiles: "results/*.xml"
searchFolder: $(System.DefaultWorkingDirectory)
So that's the entire setup of the testing pipeline
# Node.js
# Build a general Node.js project with npm.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://learn.microsoft.com/azure/devops/pipelines/languages/javascript
trigger:
- master
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool#0
inputs:
versionSpec: '12.x'
displayName: 'Install Node.js'
- script: "npm i"
displayName: "Install project dependencies"
- script: "npm run cy:verify"
displayName: "Cypress Verify"
- script: "source cypress.env" # comment this script to run tests against production
displayName: "Using env variables to change url to test against development branch"
- script: "npm run cy:run-report"
displayName: "Run Cypress Tests"
- task: PublishBuildArtifacts#1
displayName: "Publish Artifact: cypress-azure-devops screenshots"
inputs:
PathtoPublish: cypress/screenshots
ArtifactName: "CypressAzureDevopsTestRunScreenshots"
condition: failed()
- task: PublishTestResults#2
displayName: "Publish Test Results"
condition: succeededOrFailed()
inputs:
testResultsFormat: "JUnit"
testResultsFiles: "results/*.xml"
searchFolder: $(System.DefaultWorkingDirectory)
mergeTestResults: true
testRunTitle: 'Test Results'
continueOnError: true
Saludos desde Argentina 🇦🇷