Implement Continuous Integration and Continuous deployment using Azure Pipelines
Azure Pipelines is the newer version of the Azure DevOps build and release features.
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.
Choosing between Azure Multi-stage Pipelines and Azure DevOps builds and releases
There are currently two approaches available to implement continuous integration, and deployment in Azure DevOps. 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.
Azure multi-stage Pipelines relies on pipeline definitions stored as YAML files on the repository providing transparency, version history, and repeatability. Both approaches are described for the SharePoint Framework:
- Azure Build and Release
- Azure Multi-stage Pipelines (this article)
Implementing Continuous Integration and Continuous testing
The continuous integration and continuous testing stage are described by the following YAML template. Copy the following content in a new file at the root of the project called azure-pipelines-build-template.yml.
parameters:
name: ''
jobs:
- job: ${{ parameters.name }}
pool:
vmImage: 'ubuntu-latest'
demands:
- npm
- node.js
- java
variables:
npm_config_cache: $(Pipeline.Workspace)/.npm
steps:
- checkout: self
- task: NodeTool@0
displayName: 'Use Node 10.x'
inputs:
versionSpec: 10.x
checkLatest: true
- task: CacheBeta@1
inputs:
key: npm | $(Agent.OS) | package-lock.json
path: $(npm_config_cache)
cacheHitVar: CACHE_RESTORED
- script: npm ci
displayName: 'npm ci'
- task: Gulp@0
displayName: 'Bundle project'
inputs:
targets: bundle
arguments: '--ship'
- script: npm test
displayName: 'npm test'
- task: PublishTestResults@2
displayName: Publish test results
inputs:
testResultsFormat: JUnit
testResultsFiles: '**/junit.xml'
#failTaskOnFailedTests: true #if we want to fail the build on failed unit tests
- task: PublishCodeCoverageResults@1
displayName: 'Publish code coverage results'
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/*coverage.xml'
- task: Gulp@0
displayName: 'Package Solution'
inputs:
targets: 'package-solution'
arguments: '--ship'
- task: CopyFiles@2
displayName: 'Copy Files to: $(Build.ArtifactStagingDirectory)'
inputs:
Contents: |
sharepoint/**/*.sppkg
TargetFolder: '$(Build.ArtifactStagingDirectory)'
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: drop'
Note
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.
Note
You can find the latest version of this file on the sample
Implementing Continuous Deployment
The continuous deployment stage is described by the following YAML template. Copy the following content in a new file at the root of the project called azure-pipelines-deploy-template.yml.
parameters:
# unique name of the job
job_name: deploy_sppkg
# friendly name of the job
display_name: Upload & deploy *.sppkg to SharePoint app catalog
# name of target environment deploying to
target_environment: ''
# app catalog scope (tenant|sitecollection)
m365cli_app_catalog_scope: 'tenant'
variable_group_name: ''
jobs:
- deployment: ${{ parameters.job_name }}
displayName: ${{ parameters.display_name }}
pool:
vmImage: 'ubuntu-latest'
environment: ${{ parameters.target_environment }}
variables:
- group: ${{parameters.variable_group_name}} #m365_user_login, m365_user_password, m365_app_catalog_site_url
strategy:
runOnce:
deploy:
steps:
- checkout: none
- download: current
artifact: drop
patterns: '**/*.sppkg'
- script: sudo npm install --global @pnp/cli-microsoft365
displayName: Install CLI for Microsoft365
- script: m365 login $(m365_app_catalog_site_url) --authType password --userName $(m365_user_login) --password $(m365_user_password)
displayName: Login to Microsoft 365
- script: |
CMD_GET_SPPKG_NAME=$(find $(Pipeline.Workspace)/drop -name '*.sppkg' -exec basename {} \;)
echo "##vso[task.setvariable variable=SpPkgFileName;isOutput=true]${CMD_GET_SPPKG_NAME}"
displayName: Get generated *.sppkg filename
name: GetSharePointPackage
- script: m365 spo app add --filePath "$(Pipeline.Workspace)/drop/sharepoint/solution/$(GetSharePointPackage.SpPkgFileName)" --appCatalogUrl $(m365_app_catalog_site_url) --scope ${{ parameters.m365cli_app_catalog_scope }} --overwrite
displayName: Upload SharePoint package to Site Collection App Catalog
- script: m365 spo app deploy --name $(GetSharePointPackage.SpPkgFileName) --appCatalogUrl $(m365_app_catalog_site_url) --scope ${{ parameters.m365cli_app_catalog_scope }}
displayName: Deploy SharePoint package
Note
You can find the latest version of this file on the sample
Defining the Pipeline structure
Now that the build and deploy stages are defined in their respective templates, it needs to be assembled as a Multi-stage pipeline. This document will describe the structure of the pipeline as well as the different environments in use. Copy the following content in a new file at the root of the project called azure-pipelines.yml.
name: $(TeamProject)_$(BuildDefinitionName)_$(SourceBranchName)_$(Date:yyyyMMdd)$(Rev:.r)
resources:
- repo: self
trigger:
branches:
include:
- master
- develop
stages:
- stage: build
displayName: build
jobs:
- template: ./azure-pipelines-build-template.yml
parameters:
name: 'buildsolution'
- stage: 'deployqa'
# uncomment if you want deployments to occur only for a specific branch
#condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/develop'))
jobs:
- template: ./azure-pipelines-deploy-template.yml
parameters:
job_name: deploy_solution
target_environment: 'qa'
variable_group_name: qa_configuration
Note
You can find the latest version of this file on the sample
Note
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.
Note
You can conditionally deploy to different environments leveraging conditions
Configuring the credentials for the environments
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). To create the variable group, follow these steps:
- Sign-in to Azure DevOps, navigate to your project
- Under Pipelines select Library
- Add a new Variable Group making sure the name matches what is defined in the pipeline definition
- Add the following variables to the group and select Save
- m365_user_login: the user login of a SharePoint tenant administrator
- m365_user_password: the user password of the account
- m365_app_catalog_site_url: the url of the app catalog site collection
Note
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.
Feedback
https://aka.ms/ContentUserFeedback.
Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see:Submit and view feedback for