|
| 1 | +--- |
| 2 | +title: Implement Continuous Integration and Continuous deployment using Azure Pipelines (preview) |
| 3 | +description: Streamlining the build and deployment process by automating manual steps. |
| 4 | +ms.date: 12/03/2019 |
| 5 | +ms.prod: sharepoint |
| 6 | +localization_priority: Priority |
| 7 | +--- |
| 8 | +# Implement Continuous Integration and Continuous deployment using Azure Pipelines |
| 9 | +Azure Pipelines is the newer version of the Azure DevOps build and release features. |
| 10 | + |
| 11 | +This article explains the steps involved in setting up your Azure Pipelines environment with Continuous Integration and Continuous Deployment to automate your SharePoint Framework builds, unit tests, and deployment. |
| 12 | + |
| 13 | +> [!NOTE] |
| 14 | +> Azure Multi-stage Pipelines is still in preview and you need to make sure you enable this preview feature for your Azure DevOps organization under __Preview Features__ |
| 15 | +
|
| 16 | +## Chosing between Azure Multi-stage Pipelines (preview) and Azure DevOps builds and releases |
| 17 | +There are currently two approaches available to implement continuous integration, and deployement in Azure DevOps. |
| 18 | +Azure builds and releases is the historic one, featuring a graphical edition experience and storing the definitions in a JSON document hidden from the user. |
| 19 | +Azure multi-stage Pipelines is a newer feature still in preview, is relies on pipeline definitions stored as YAML files on the repository providing transparency, version history and repeatability. |
| 20 | +Both approaches are decribed for the SharePoint Framework: |
| 21 | +- [Azure Build and Release](./implement-ci-cd-with-azure-devops.md) |
| 22 | +- Azure Multi-stage Pipelines (this article) |
| 23 | + |
| 24 | +## Implementing Continuous Integration and Continuous testing |
| 25 | +The continuous integration and continuous testing stage are described by the following YAML template. |
| 26 | +Copy the following content in a new file at the root of the project called __azure-pipelines-build-template.yml__. |
| 27 | +```YAML |
| 28 | +parameters: |
| 29 | + name: '' |
| 30 | +jobs: |
| 31 | + - job: ${{ parameters.name }} |
| 32 | + pool: |
| 33 | + vmImage: 'ubuntu-latest' |
| 34 | + demands: |
| 35 | + - npm |
| 36 | + - node.js |
| 37 | + - java |
| 38 | + variables: |
| 39 | + npm_config_cache: $(Pipeline.Workspace)/.npm |
| 40 | + |
| 41 | + steps: |
| 42 | + - checkout: self |
| 43 | + |
| 44 | + - task: NodeTool@0 |
| 45 | + displayName: 'Use Node 10.x' |
| 46 | + inputs: |
| 47 | + versionSpec: 10.x |
| 48 | + checkLatest: true |
| 49 | + |
| 50 | + - task: CacheBeta@1 |
| 51 | + inputs: |
| 52 | + key: npm | $(Agent.OS) | package-lock.json |
| 53 | + path: $(npm_config_cache) |
| 54 | + cacheHitVar: CACHE_RESTORED |
| 55 | + - script: npm ci |
| 56 | + displayName: 'npm ci' |
| 57 | + |
| 58 | + - task: Gulp@0 |
| 59 | + displayName: 'Bundle project' |
| 60 | + inputs: |
| 61 | + targets: bundle |
| 62 | + arguments: '--ship' |
| 63 | + |
| 64 | + - script: npm test |
| 65 | + displayName: 'npm test' |
| 66 | + |
| 67 | + - task: PublishTestResults@2 |
| 68 | + displayName: Publish test results |
| 69 | + inputs: |
| 70 | + testResultsFormat: JUnit |
| 71 | + testResultsFiles: '**/junit.xml' |
| 72 | + #failTaskOnFailedTests: true #if we want to fail the build on failed unit tests |
| 73 | + |
| 74 | + - task: PublishCodeCoverageResults@1 |
| 75 | + displayName: 'Publish code coverage results' |
| 76 | + inputs: |
| 77 | + codeCoverageTool: Cobertura |
| 78 | + summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/*coverage.xml' |
| 79 | + |
| 80 | + - task: Gulp@0 |
| 81 | + displayName: 'Package Solution' |
| 82 | + inputs: |
| 83 | + targets: 'package-solution' |
| 84 | + arguments: '--ship' |
| 85 | + |
| 86 | + - task: CopyFiles@2 |
| 87 | + displayName: 'Copy Files to: $(Build.ArtifactStagingDirectory)' |
| 88 | + inputs: |
| 89 | + Contents: | |
| 90 | + sharepoint/**/*.sppkg |
| 91 | + TargetFolder: '$(Build.ArtifactStagingDirectory)' |
| 92 | + |
| 93 | + - task: PublishBuildArtifacts@1 |
| 94 | + displayName: 'Publish Artifact: drop' |
| 95 | +``` |
| 96 | +
|
| 97 | +> [!NOTE] |
| 98 | +> You can comment out/remove the _PublishCodeCoverageResults_, _PublishTestResults_ and _npm test_ tasks if you do not have any unit test implement and/or do not want unit tests to run. |
| 99 | +
|
| 100 | +> [!NOTE] |
| 101 | +> You can find the latest version of this file on the [sample](https://github.com/SharePoint/sp-dev-build-extensions/tree/master/samples/azure-devops-ci-cd-spfx) |
| 102 | +
|
| 103 | +## Implementing Continuous Deployment |
| 104 | +The continuous deployment stage is described by the following YAML template. |
| 105 | +Copy the following content in a new file at the root of the project called __azure-pipelines-deploy-template.yml__. |
| 106 | +```YAML |
| 107 | +parameters: |
| 108 | + # unique name of the job |
| 109 | + job_name: deploy_sppkg |
| 110 | + # friendly name of the job |
| 111 | + display_name: Upload & deploy *.sppkg to SharePoint app catalog |
| 112 | + # name of target enviroment deploying to |
| 113 | + target_environment: '' |
| 114 | + # app catalog scope (tenant|sitecollection) |
| 115 | + o365cli_app_catalog_scope: 'tenant' |
| 116 | + variable_group_name: '' |
| 117 | +jobs: |
| 118 | +- deployment: ${{ parameters.job_name }} |
| 119 | + displayName: ${{ parameters.display_name }} |
| 120 | + pool: |
| 121 | + vmImage: 'ubuntu-latest' |
| 122 | + environment: ${{ parameters.target_environment }} |
| 123 | + variables: |
| 124 | + - group: ${{parameters.variable_group_name}} #o365_user_login, o365_user_password, o365_app_catalog_site_url |
| 125 | + strategy: |
| 126 | + runOnce: |
| 127 | + deploy: |
| 128 | + steps: |
| 129 | + - checkout: none |
| 130 | + - download: current |
| 131 | + artifact: drop |
| 132 | + patterns: '**/*.sppkg' |
| 133 | + - script: sudo npm install --global @pnp/office365-cli |
| 134 | + displayName: Install Office365 CLI |
| 135 | + - script: o365 login $(o365_app_catalog_site_url) --authType password --userName $(o365_user_login) --password $(o365_user_password) |
| 136 | + displayName: Login to Office365 |
| 137 | + - script: | |
| 138 | + CMD_GET_SPPKG_NAME=$(find $(Pipeline.Workspace)/drop -name '*.sppkg' -exec basename {} \;) |
| 139 | + echo "##vso[task.setvariable variable=SpPkgFileName;isOutput=true]${CMD_GET_SPPKG_NAME}" |
| 140 | + displayName: Get generated *.sppkg filename |
| 141 | + name: GetSharePointPackage |
| 142 | + - script: o365 spo app add --filePath "$(Pipeline.Workspace)/drop/sharepoint/solution/$(GetSharePointPackage.SpPkgFileName)" --appCatalogUrl $(o365_app_catalog_site_url) --scope ${{ parameters.o365cli_app_catalog_scope }} --overwrite |
| 143 | + displayName: Upload SharePoint package to Site Collection App Catalog |
| 144 | + - script: o365 spo app deploy --name $(GetSharePointPackage.SpPkgFileName) --appCatalogUrl $(o365_app_catalog_site_url) --scope ${{ parameters.o365cli_app_catalog_scope }} |
| 145 | + displayName: Deploy SharePoint package |
| 146 | +``` |
| 147 | +
|
| 148 | +> [!NOTE] |
| 149 | +> You can find the latest version of this file on the [sample](https://github.com/SharePoint/sp-dev-build-extensions/tree/master/samples/azure-devops-ci-cd-spfx) |
| 150 | +
|
| 151 | +## Defining the Pipeline structure |
| 152 | +Now that the build and deploy stages are defined in their respective templates, it needs to be assembled as a Multi-stage pipeline. |
| 153 | +This document will describe the structure of the pipeline as well as the different environments in use. |
| 154 | +Copy the following content in a new file at the root of the project called __azure-pipelines.yml__. |
| 155 | +```YAML |
| 156 | +name: $(TeamProject)_$(BuildDefinitionName)_$(SourceBranchName)_$(Date:yyyyMMdd)$(Rev:.r) |
| 157 | +resources: |
| 158 | +- repo: self |
| 159 | + |
| 160 | +trigger: |
| 161 | + branches: |
| 162 | + include: |
| 163 | + - master |
| 164 | + - develop |
| 165 | + |
| 166 | +stages: |
| 167 | +- stage: build |
| 168 | + displayName: build |
| 169 | + jobs: |
| 170 | + - template: ./azure-pipelines-build-template.yml |
| 171 | + parameters: |
| 172 | + name: 'buildsolution' |
| 173 | +- stage: 'deployqa' |
| 174 | + # uncomment if you want deployments to occur only for a specific branch |
| 175 | + #condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/develop')) |
| 176 | + jobs: |
| 177 | + - template: ./azure-pipelines-deploy-template.yml |
| 178 | + parameters: |
| 179 | + job_name: deploy_solution |
| 180 | + target_environment: 'qa' |
| 181 | + variable_group_name: qa_configuration |
| 182 | +``` |
| 183 | +> [!NOTE] |
| 184 | +> You can find the latest version of this file on the [sample](https://github.com/SharePoint/sp-dev-build-extensions/tree/master/samples/azure-devops-ci-cd-spfx) |
| 185 | +> [!NOTE] |
| 186 | +> You can define multiple environments and by duplicating the __deployqa__ stage and providing different parameters. If you do so, make sure the stage name, the job name, the target environment and the variable group name are unique. |
| 187 | +> [!NOTE] |
| 188 | +> You can conditionnally deploy to different environments leveraging [conditions](https://docs.microsoft.com/en-us/azure/devops/pipelines/process/conditions?view=azure-devops&tabs=yaml) |
| 189 | +
|
| 190 | +## Configuring the credentials for the environments |
| 191 | +Secrets should never be committed to a repository for security reasons. The pipeline described in the previous steps makes use of _variable groups_ to keep configuration values secret. The variable groups need to be created for each environment and the name needs to match what is described in the pipeline definition (here __qa_configuration__). |
| 192 | +To create the variable group, follow these steps: |
| 193 | +1. Sign-in to Azure DevOps, navigate to your project |
| 194 | +1. Under __Pipelines__ select __Library__ |
| 195 | +1. Add a new __Variable Group__ making sure the name matches what is defined in the pipeline definition |
| 196 | +1. Add the following variables to the group and select __Save__ |
| 197 | + - o365_user_login: the user login of a SharePoint tenant administator |
| 198 | + - o365_user_password: the user password of the account |
| 199 | + - o365_app_catalog_site_url: the url of the app catalog site collection |
| 200 | +
|
| 201 | +> [!NOTE] |
| 202 | +> You can select the lockpad icon next to the variable value input to mark it as sensitive and have Azure DevOps hide the value from other users and from the logs. |
0 commit comments