/deploy-spfx-pnp-powershell.yml Secret
Created
April 19, 2022 22:00
Build & Deploy SPFx package in an ephemeral site before production (GitHub Actions & PnP PowerShell)
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: deploy with pnp powershell | |
on: | |
workflow_call: | |
inputs: | |
environment_name: | |
description: 'Target environment to deploy to' | |
required: true | |
type: string | |
site_url_prd: | |
description: 'SharePoint PRD site URL' | |
required: true | |
type: string | |
site_list_prd: | |
description: 'SharePoint PRD list relative URL ("Lists/MyList")' | |
default: "" | |
required: false | |
type: string | |
site_copy_owner: | |
description: 'SharePoint copy site owner to be' | |
default: "" | |
required: false | |
type: string | |
webpart_name: | |
description: 'SPFx WebPart name to add to test page' | |
default: "" | |
required: false | |
type: string | |
site_to_remove: | |
description: 'SharePoint copy site url to remove' | |
default: "" | |
required: false | |
type: string | |
app_catalog_site_url: | |
description: 'SharePoint app catalog site URL (tenant or site collection)' | |
default: "" | |
required: false | |
type: string | |
app_catalog_scope: | |
description: 'Indicates the PRD app catalog scope (tenant or site collection)' | |
default: "" | |
required: false | |
type: string | |
outputs: | |
site_to_remove: | |
description: 'SharePoint copy site url to remove' | |
value: ${{ jobs.deploy.outputs.site_copy_url }} | |
secrets: | |
AAD_APP_ID: | |
required: true | |
AAD_APP_PASSWORD: | |
required: true | |
AAD_APP_ENCODED_CERTIFICATE: | |
required: true | |
AAD_TENANT_ID: | |
required: true | |
jobs: | |
deploy: | |
runs-on: windows-2022 | |
environment: ${{ inputs.environment_name }} | |
outputs: | |
site_copy_url: ${{ steps.step_site_copy.outputs.url }} | |
steps: | |
- name: Download artifact from build job | |
uses: actions/download-artifact@v2 | |
- name: Installing PnP.PowerShell Module | |
shell: pwsh | |
run: Install-Module -Name "PnP.PowerShell" -Force | |
- name: Get generated *.sppkg filename | |
id: package | |
shell: pwsh | |
run: | | |
$package = Get-ChildItem -Path artifact -Recurse -Filter '*.sppkg' | Select Name | Select-Object -First 1 | |
echo "::set-output name=name::$($package.Name)" | |
- name: Connecting to Production site and get site template | |
if: ${{ inputs.environment_name != 'PRD' }} | |
shell: pwsh | |
run: | | |
$securePassword = ConvertTo-SecureString "${{ secrets.AAD_APP_PASSWORD }}" -AsPlainText -Force | |
Connect-PnPOnline -Url ${{ inputs.site_url_prd }} -CertificateBase64Encoded ${{ secrets.AAD_APP_ENCODED_CERTIFICATE }} -CertificatePassword $securePassword -ClientId ${{ secrets.AAD_APP_ID }} -Tenant ${{ secrets.AAD_TENANT_ID }} | |
Get-PnPSiteTemplate -Out template.pnp | |
Add-PnPDataRowsToSiteTemplate -Path template.pnp -List "${{ inputs.site_list_prd }}" | |
- name: Create ${{ inputs.environment_name }} site copy | |
if: ${{ inputs.environment_name != 'PRD' }} | |
id: step_site_copy | |
shell: pwsh | |
run: | | |
$securePassword = ConvertTo-SecureString "${{ secrets.AAD_APP_PASSWORD }}" -AsPlainText -Force | |
Connect-PnPOnline -Url ${{ inputs.site_url_prd }} -CertificateBase64Encoded ${{ secrets.AAD_APP_ENCODED_CERTIFICATE }} -CertificatePassword $securePassword -ClientId ${{ secrets.AAD_APP_ID }} -Tenant ${{ secrets.AAD_TENANT_ID }} | |
$web = Get-PnPWeb | |
$siteName = "$($web.Title)" + [guid]::NewGuid().Guid | |
$uri = [System.Uri]"${{ inputs.site_url_prd }}" | |
$siteUrl = $uri.Scheme + "://" + $uri.Authority + "/sites/" + $siteName | |
$site = New-PnPSite -Type CommunicationSite -Title $siteName -Url $siteUrl -Owner "${{ inputs.site_copy_owner }}" -Wait | |
Write-Host "::set-output name=url::$site" | |
Write-Host $site | |
- name: Apply PRD site template to ${{ inputs.environment_name }} site copy | |
if: ${{ inputs.environment_name != 'PRD' }} | |
shell: pwsh | |
run: | | |
$securePassword = ConvertTo-SecureString "${{ secrets.AAD_APP_PASSWORD }}" -AsPlainText -Force | |
Connect-PnPOnline -Url ${{ steps.step_site_copy.outputs.url }} -CertificateBase64Encoded ${{ secrets.AAD_APP_ENCODED_CERTIFICATE }} -CertificatePassword $securePassword -ClientId ${{ secrets.AAD_APP_ID }} -Tenant ${{ secrets.AAD_TENANT_ID }} | |
$applyTemplateHasFailed = $false | |
try { | |
Invoke-PnPSiteTemplate -Path template.pnp -ClearNavigation | |
} | |
catch { | |
Write-Host $_.Exception.Message -ForegroundColor Yellow | |
$applyTemplateHasFailed = $_.Exception.Message -Match "HttpClient.Timeout" | |
} | |
finally { | |
if ($applyTemplateHasFailed -eq $true) { | |
Write-Host "Retrying to apply PRD site template (after 30 seconds delay)" | |
Start-Sleep -Seconds 30 | |
Invoke-PnPSiteTemplate -Path template.pnp -ClearNavigation | |
} | |
} | |
- name: Enable Site Collection App Catalog, upload SharePoint package, deploy it and add it to the site | |
if: ${{ inputs.environment_name != 'PRD' }} | |
shell: pwsh | |
run: | | |
$uploadHasFailed = $false | |
try { | |
$securePassword = ConvertTo-SecureString "${{ secrets.AAD_APP_PASSWORD }}" -AsPlainText -Force | |
Connect-PnPOnline -Url ${{ steps.step_site_copy.outputs.url }} -CertificateBase64Encoded ${{ secrets.AAD_APP_ENCODED_CERTIFICATE }} -CertificatePassword $securePassword -ClientId ${{ secrets.AAD_APP_ID }} -Tenant ${{ secrets.AAD_TENANT_ID }} | |
Add-PnPSiteCollectionAppCatalog | |
Add-PnPApp -Path "artifact/${{ steps.package.outputs.name }}" -Scope Site -Publish | |
} | |
catch { | |
Write-Host $_.Exception.Message -ForegroundColor Yellow | |
Write-Host "Retrying by removing and re-enabling the site collection app catalog, then the package (after 30 seconds delay)" | |
$uploadHasFailed = $true | |
} | |
finally { | |
if ($uploadHasFailed -eq $true) { | |
Remove-PnPSiteCollectionAppCatalog -Site ${{ steps.step_site_copy.outputs.url }} | |
Add-PnPSiteCollectionAppCatalog | |
Start-Sleep -Seconds 30 | |
Add-PnPApp -Path "artifact/${{ steps.package.outputs.name }}" -Scope Site -Publish -Overwrite | |
} | |
} | |
# Enabling the site collection app catalog or deploying a solution on it can fail, as the site has just been created | |
# We prevent this failure, by waiting and retrying those actions | |
- name: Add an article page and the WebPart (if exists) | |
if: ${{ inputs.environment_name != 'PRD' }} | |
shell: pwsh | |
run: | | |
$webPartHasFailed = $false | |
if ('${{ inputs.webpart_name }}' -ne '') { | |
try { | |
$securePassword = ConvertTo-SecureString "${{ secrets.AAD_APP_PASSWORD }}" -AsPlainText -Force | |
Connect-PnPOnline -Url ${{ steps.step_site_copy.outputs.url }} -CertificateBase64Encoded ${{ secrets.AAD_APP_ENCODED_CERTIFICATE }} -CertificatePassword $securePassword -ClientId ${{ secrets.AAD_APP_ID }} -Tenant ${{ secrets.AAD_TENANT_ID }} | |
Add-PnPPage -Name "TestSPFx" | |
Add-PnPPageWebPart -Page "TestSPFx" -Component "${{ inputs.webpart_name }}" | |
} | |
catch { | |
Write-Host $_.Exception.Message -ForegroundColor Yellow | |
Write-Host "Retrying the WebPart addition after 30 seconds delay" | |
$webPartHasFailed = $true | |
Start-Sleep -Seconds 30 | |
} | |
finally { | |
if ($webPartHasFailed -eq $true) { | |
Add-PnPPageWebPart -Page "TestSPFx" -Component "${{ inputs.webpart_name }}" | |
} | |
} | |
} | |
# Here again, adding a page with the WebPart ont it can fail, as the site has just been created | |
# We prevent this failure, by waiting and retrying those actions | |
- name: Upload SharePoint package to ${{ inputs.app_catalog_scope }} App Catalog (PRD) | |
if: ${{ inputs.environment_name == 'PRD' }} | |
run: | | |
$securePassword = ConvertTo-SecureString "${{ secrets.AAD_APP_PASSWORD }}" -AsPlainText -Force | |
Connect-PnPOnline -Url ${{ inputs.site_url_prd }} -CertificateBase64Encoded ${{ secrets.AAD_APP_ENCODED_CERTIFICATE }} -CertificatePassword $securePassword -ClientId ${{ secrets.AAD_APP_ID }} -Tenant ${{ secrets.AAD_TENANT_ID }} | |
Add-PnPApp -Path "artifact/${{ steps.package.outputs.name }}" -Scope ${{ inputs.app_catalog_scope }} -Publish -Overwrite | |
- name: Remove site copy (PRD) | |
if: ${{ inputs.environment_name == 'PRD' && inputs.site_to_remove != '' }} | |
run: | | |
$securePassword = ConvertTo-SecureString "${{ secrets.AAD_APP_PASSWORD }}" -AsPlainText -Force | |
Connect-PnPOnline -Url ${{ inputs.site_url_prd }} -CertificateBase64Encoded ${{ secrets.AAD_APP_ENCODED_CERTIFICATE }} -CertificatePassword $securePassword -ClientId ${{ secrets.AAD_APP_ID }} -Tenant ${{ secrets.AAD_TENANT_ID }} | |
Remove-PnPTenantSite -Url ${{ inputs.site_to_remove }} -SkipRecyclebin -Force |
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 | |
on: | |
push: | |
branches: | |
- main | |
workflow_dispatch: # Can be triggered manually | |
jobs: | |
build: | |
uses: michaelmaillot/helloworld-copysite/.github/workflows/build-spfx.yml@main | |
deploy_uat: | |
needs: build | |
uses: michaelmaillot/helloworld-copysite/.github/workflows/deploy-spfx-pnp-powershell-copy.yml@main | |
with: | |
environment_name: UAT | |
site_url_prd: https://onepointdev365.sharepoint.com/sites/CommSite | |
site_list_prd: "Lists/EmployeeOnboarding" | |
site_copy_owner: michael.maillot@onepointdev365.onmicrosoft.com | |
webpart_name: "HelloWorld" | |
secrets: | |
AAD_APP_ID: ${{ secrets.AAD_APP_ID }} | |
AAD_APP_PASSWORD: ${{ secrets.AAD_APP_PASSWORD }} | |
AAD_APP_ENCODED_CERTIFICATE: ${{ secrets.AAD_APP_ENCODED_CERTIFICATE }} | |
AAD_TENANT_ID: ${{ secrets.AAD_TENANT_ID }} | |
deploy_prd: | |
needs: deploy_uat | |
uses: michaelmaillot/helloworld-copysite/.github/workflows/deploy-spfx-pnp-powershell-copy.yml@main | |
with: | |
environment_name: PRD | |
site_url_prd: https://onepointdev365.sharepoint.com/sites/CommSite | |
app_catalog_scope: tenant | |
site_to_remove: "${{ needs.deploy_uat.outputs.site_to_remove }}" | |
secrets: | |
AAD_APP_ID: ${{ secrets.AAD_APP_ID }} | |
AAD_APP_PASSWORD: ${{ secrets.AAD_APP_PASSWORD }} | |
AAD_APP_ENCODED_CERTIFICATE: ${{ secrets.AAD_APP_ENCODED_CERTIFICATE }} | |
AAD_TENANT_ID: ${{ secrets.AAD_TENANT_ID }} |
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 GitHub Action workflow that will build an SPFx package, then create an testing site, based on a template from the production site, on which the package will be deployed (in a site collection app catalog) dedicated to test out new features / bug fixes, with a testing page. Then the pipeline will be deployed on the tenant app catalog (or a production site collection app catalog), and finally remove the testing site. This sample will use PnP PowerShell in order to connect to SharePoint Online and deploy the SPFx package, using the Provisioning Engine. Below the different files description:
main.yml
: the main pipeline that will be triggered as the initiatorbuild-spfx.yml
: CI pipelinedeploy-spfx-pnp-powershell.yml
: CD pipelineConfiguration
SharePoint site
For this sample, we'll need one site for production stage, this can use a tenant app catalog or a site collection one (in this case, it will have to be enabled first).
For this sample, the production site has to be a Communication one.
The app will have to be already installed on PRD site.
Solution
The SPFx solution can be ordered like this:
Environments
The environments will be necessary for approving a pipeline before being run. You'll have to add two environments:
Environments can be configured here: https://github.com/[ORGANIZATION]/[PROJECT]/settings/environments.
/!\ Beware that in order to use multiple environments, your repo has to be public or your subscription has to be a Pro one.
Approvers
For each environment, you can add an approver by enabling the checkbox marked "Required reviewers", then adding at least one reviewer account then click on "Save protection rules".
Environment secrets
Environment secrets can be configured here: https://github.com/[ORGANIZATION]/[PROJECT]/settings/environments/[ENVIRONMENT_ID]/edit.
Below the secrets used in the workflows:
AAD_APP_ID
AAD_APP_PASSWORD
AAD_APP_ENCODED_CERTIFICATE
AAD_TENANT_ID
CD Workflow parameters
Below the parameters used in the
deploy-spfx-pnp-powershell.yml
workflow, depending on the environment:environment_name
site_list_prd
webpart_name
site_url_prd
app_catalog_scope
app_catalog_site_url