Search code examples
azure-devopsmonorepo

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


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 :

  1. What exactly is a build tag and where does it live? Is it somehow linked to an artifact?
  2. The idea is to create one build tag per artifact, right?
  3. I failed to create a build tag, how can I do so?
  4. 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 :

enter image description here

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


Solution

  • 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.

    enter image description here

    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. enter image description here

    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!