Last active
April 16, 2022 12:37
Build & Deploy SPFx package in multiple environments (Azure DevOps & CLI for Microsoft 365)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: main | |
trigger: | |
branches: | |
include: | |
- main | |
stages: | |
- template: pipelines/stages/build-deploy-spfx-cli-m365.yml | |
parameters: | |
include_tests: false | |
variable_group_uat: 'contoso-UAT' | |
variable_group_prd: 'contoso-PRD' | |
deploy_uat: true | |
deploy_prd: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
parameters: | |
- name: include_tests | |
type: boolean | |
default: true | |
- name: variable_group_uat | |
type: string | |
- name: variable_group_prd | |
type: string | |
- name: deploy_uat | |
type: boolean | |
default: true | |
- name: deploy_prd | |
type: boolean | |
default: true | |
stages: | |
- stage: 'build' | |
jobs: | |
- template: ../jobs/build-spfx.yml | |
parameters: | |
include_tests: false | |
- ${{ if eq(parameters.deploy_uat, true) }}: | |
- stage: 'deploy_uat' | |
displayName: Deploy on UAT | |
dependsOn: [ build ] | |
jobs: | |
- template: ../jobs/deploy-spfx-cli-m365.yml | |
parameters: | |
target_environment: 'UAT' | |
variable_group_name: ${{ parameters.variable_group_uat }} | |
- ${{ if eq(parameters.deploy_prd, true) }}: | |
- stage: 'deploy_prd' | |
displayName: Deploy on PRD | |
dependsOn: [ deploy_uat ] | |
jobs: | |
- template: ../jobs/deploy-spfx-cli-m365.yml | |
parameters: | |
target_environment: 'PRD' | |
variable_group_name: ${{ parameters.variable_group_prd }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# No triggers here, which makes the pipeline not callable except from another pipeline | |
parameters: | |
- name: include_tests | |
type: boolean | |
default: true | |
jobs: | |
- job: build | |
pool: | |
vmImage: 'ubuntu-latest' | |
demands: | |
- npm | |
- node.js | |
variables: | |
npm_config_cache: $(Pipeline.Workspace)/.npm | |
steps: | |
- checkout: self | |
- task: gittools.usegitversion.gitversion-task.UseGitVersion@5 | |
displayName: 'GitVersion' | |
inputs: | |
versionSpec: '5.6.x' | |
- task: NodeTool@0 | |
displayName: 'Use Node 14.x' | |
inputs: | |
versionSpec: 14.x | |
checkLatest: true | |
- script: npm ci | |
displayName: 'npm ci' | |
- task: Gulp@0 | |
displayName: 'Bundle project' | |
inputs: | |
targets: bundle | |
arguments: '--ship' | |
- ${{ if eq(parameters.include_tests, true) }}: | |
- script: npm test | |
displayName: 'npm test' | |
- 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' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# No triggers here, which makes the pipeline not callable except from another pipeline | |
parameters: | |
- name: target_environment | |
type: string | |
- name: variable_group_name | |
type: string | |
jobs: | |
- deployment: deploy | |
displayName: 'Upload & deploy *.sppkg to SharePoint app catalog' | |
pool: | |
vmImage: 'ubuntu-latest' | |
environment: ${{ parameters.target_environment }} | |
variables: | |
- group: ${{ parameters.variable_group_name }} | |
# This is specific to AzDO: it allows to use variables / secrets stored in a "library" | |
# It's very useful with multi-stage pipelines | |
strategy: | |
runOnce: | |
deploy: | |
steps: | |
- download: current | |
artifact: drop | |
patterns: '**/*.sppkg' | |
- pwsh: sudo npm install -g @pnp/cli-microsoft365 | |
displayName: Install CLI for Microsoft365 | |
- task: DownloadSecureFile@1 | |
inputs: | |
secureFile: PnP.SharePoint.AppOnly.pfx | |
displayName: 'Download authentication certificate' | |
name: AppCertificate | |
# Thanks to the AzDO pipeline files management, we can store secure files | |
# Such as a certificate file | |
- pwsh: | | |
m365 login --authType certificate --certificateFile $(AppCertificate.secureFilePath) -p "$(aad_app_password)" --appId $(aad_app_id) --tenant $(aad_tenant_id) | |
displayName: Login to Microsoft 365 | |
- pwsh: | | |
m365 cli config set --key output --value json | |
m365 cli config set --key errorOutput --value stdout | |
displayName: Configuring CLI for Microsoft 365 output error handling | |
- pwsh: | | |
$package = Get-ChildItem -Path $(Pipeline.Workspace)/drop -Recurse -Filter '*.sppkg' | Select Name | Select-Object -First 1 | |
Write-Host "##vso[task.setvariable variable=SpPkgFileName;isOutput=true]$($package.Name)" | |
name: GetSharePointPackage | |
displayName: Get generated *.sppkg filename | |
- ${{ if ne(parameters.target_environment, 'PRD') }}: | |
- pwsh: | | |
$uri = [System.Uri]"$(site_url_uat)" | |
m365 spo set --url $($uri.Scheme + "://" + $uri.Authority) | |
displayName: Set site collection context (${{ parameters.target_environment }}) | |
- pwsh: | | |
m365 spo app add --filePath "$(Pipeline.Workspace)/drop/sharepoint/solution/$(GetSharePointPackage.SpPkgFileName)" --appCatalogUrl $(site_url_uat) --scope sitecollection --overwrite | |
name: SPOPackage | |
displayName: Upload SharePoint package | |
- pwsh: | | |
m365 spo app deploy --name $(GetSharePointPackage.SpPkgFileName) --appCatalogUrl $(site_url_uat) --scope sitecollection | |
displayName: Deploy SharePoint package | |
- ${{ if eq(parameters.target_environment, 'PRD') }}: | |
- pwsh: | | |
$uri = [System.Uri]"$(site_url_prd)" | |
m365 spo set --url $($uri.Scheme + "://" + $uri.Authority) | |
displayName: Set site collection context (${{ parameters.target_environment }}) | |
- pwsh: m365 spo app add --filePath "$(Pipeline.Workspace)/drop/sharepoint/solution/$(GetSharePointPackage.SpPkgFileName)" --appCatalogUrl $(app_catalog_site_url) --scope $(app_catalog_scope) --overwrite | |
displayName: Upload SharePoint package to $(app_catalog_scope) App Catalog | |
- pwsh: m365 spo app deploy --name $(GetSharePointPackage.SpPkgFileName) --appCatalogUrl $(app_catalog_site_url) --scope $(app_catalog_scope) | |
displayName: Deploy SharePoint package |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Abstract
This sample provides a ready-to-use Azure DevOps pipeline that will build an SPFx package, then deploy it on an existing site (in a site collection app catalog) dedicated to test out new features / bug fixes. Then the pipeline will be deployed on the tenant app catalog (or a production site collection app catalog). This sample will use CLI for Microsoft 365 in order to connect to SharePoint Online and deploy the SPFx package. Below the different files description:
azure-pipelines.yml
: the main pipeline that will be triggered as the initiatorbuild-deploy-spfx-cli-m365.yml
: a global CI / CD template, that will call subsequentlybuild-spfx.yml
: CI pipelinedeploy-spfx-cli-m365.yml
: CD pipelineConfiguration
SharePoint sites
For this sample, we'll need two sites:
The app will have to be already installed on both UAT & PRD sites.
Solution
The SPFx solution can be ordered like this:
Environments
The environments will be necessary for approving a pipeline before being run. We'll have to add two environments:
Environments can be configured here: https://dev.azure.com/[ORGANIZATION]/[PROJECT]/_environment.
Approvers
For each environment, we can add an approver by clicking on the three dots located in the upper right of it, then "Approvals and checks" and select "Approvals".
Variable Groups
Variable groups allow to store specific values that can be called when running a pipeline. We'll have to add two variable groups:
Variable groups can be configured here: https://dev.azure.com/[ORGANIZATION]/[PROJECT]/_library?itemType=VariableGroups.
Below the variables used in the pipelines, depending on the context:
aad_app_id
aad_app_password
aad_tenant_id
app_catalog_scope
site_url_uat
app_catalog_site_url
site_url_prd
Secure files
Especially for AzDO, we will use the Secure files feature to store a PFX file in order to login to SharePoint in Application context. In this example, we'll use one PFX file for both testing and production environments:
PnP.SharePoint.AppOnly.pfx
.Secure files can be configured here: https://dev.azure.com/[ORGANIZATION]/[PROJECT]/_library?itemType=SecureFiles.
Stage permissions
During the pipeline run, both CI and CD parts are considered as "Stages". As the UAT and PRD deployments will have to access to environments, secure files and variable groups, we will have to give permission for those stages once.
For each of those, we will have to permit the pipeline to access to them only on the first run. This will be seen on the pipeline run page, as we'll see that the UAT / PR deployments will be pending for approving permissions. More info here.
Azure AD application
As the authentication will be done in app context (not delegated), to be sure to authenticate correctly, the AAD application will have to be configured with the following info:
PnP.SharePoint.AppOnly.pfx
one)