AI OnAI Off
You're using the Deployment API correct? As there's a requirement now to do so for the new infrastructure. I should imagine it should just be the same process as before.
FYI there's extensions in Azure DevOps by EpiNova that can help make it easier https://www.epinova.se/en/folg-med/blog/2020/epinova-dxp-deployment-part-1-introduction/
Following on from what Scott added and with the help of Epinova, I put togeather the following for a CICD pipeline, utilises DirectDeploy to Integration and than slot swaps for pre-prod and prod
# Pipeline to deploy to Integration DXP environment using Azure App Service Deploy task
# -----------------------------
# Set the pipeline build number format
name: $(Build.DefinitionName)_$(SourceBranchName)_$(Date:yyyyMMdd)$(Rev:.r)
trigger:
branches:
include:
- master
paths:
include:
- src/Content
pool:
vmImage: 'windows-2019'
variables:
- name: buildConfiguration
value: 'Release'
- name: workingDirectory
value: '$(Build.SourcesDirectory)/src/Content'
- name: sourcePath
value: '$(Agent.TempDirectory)/SitePackageContent'
- name: artifact.Name
value: "Optimizely CMS DXP Package"
- name: archiveName
value: 'optimizely.cms.app.$(Build.BuildId).nupkg'
- group: Optimizely-common-vars
stages:
- stage: CI
jobs:
- job: CI
displayName: 'Build & package'
steps:
- script: dotnet restore ./ProjectName.sln
displayName: Restore
workingDirectory: $(workingDirectory)
- script: dotnet build ./ProjectName.sln --configuration $(buildConfiguration)
displayName: Build
workingDirectory: $(workingDirectory)
- script: dotnet publish ./ProjectName.Cms --configuration $(buildConfiguration) --output $(sourcePath)
displayName: Publish Optimizely CMS Artifact
workingDirectory: $(workingDirectory)
- task: ArchiveFiles@2
displayName: "Archive Files"
inputs:
rootFolderOrFile: '$(sourcePath)'
includeRootFolder: false
archiveType: 'zip'
archiveFile: '$(Build.ArtifactStagingDirectory)/$(archiveName)'
replaceExistingArchive: true
- publish: '$(Build.ArtifactStagingDirectory)/$(archiveName)'
artifact: $(artifact.Name)
- task: PowerShell@2
displayName: 'Upload package to DXP'
env:
# Map secret variable
API_SECRET: $(ApiSecret)
inputs:
targetType: 'inline'
script: |
$env:PSModulePath = "C:\Modules\azurerm_6.13.1;" + $env:PSModulePath
if (-not (Get-Module -Name EpiCloud -ListAvailable)) {
Install-Module EpiCloud -Scope CurrentUser -Force
}
Connect-EpiCloud -ClientKey $(ApiKey) -ClientSecret $env:API_SECRET -ProjectId $(ProjectId)
$packagePath = "$(Build.ArtifactStagingDirectory)/$(archiveName)"
$saslink = Get-EpiDeploymentPackageLocation
Add-EpiDeploymentPackage -SasUrl $saslink -Path $packagePath
- stage: Optimizely_CMS_Integration
jobs:
# Add a Deployment job.
# Artifacts are automatically downloaded in deployment jobs. To disable use -download: none
- deployment: DeployApp
displayName: 'Deploy to Integration'
variables:
# Explicitly set the EnvironmentName variable in multi-stage YAML to ensure environment config transform is applied automatically
Release.EnvironmentName: 'Optimizely_CMS_Integration'
# Creates an environment if it doesn't exist
environment: 'Optimizely_CMS_Integration'
strategy:
runOnce:
deploy:
steps:
- download: none
- task: PowerShell@2
displayName: 'Deploy to Integration'
env:
API_SECRET: $(ApiSecret)
inputs:
targetType: 'inline'
script: |
if (-not (Get-Module -Name EpiCloud -ListAvailable)) {
Install-Module EpiCloud -Scope CurrentUser -Force
}
Connect-EpiCloud -ClientKey $(ApiKey) -ClientSecret $env:API_SECRET -ProjectId $(ProjectId)
$packageName = "$(archiveName)"
echo "Starting deployment using package $packageName"
$params = @{
DeploymentPackage = $packageName
TargetEnvironment = 'Integration'
UseMaintenancePage = $false
DirectDeploy = $true
Wait = $true
}
$deploy = Start-EpiDeployment @params
echo "DeploymentId - $($deploy.id)"
echo "##vso[task.setvariable variable=deploymentId;]$($deploy.id)"
- stage: Optimizely_CMS_PreProduction
jobs:
# Add a Deployment job.
# Artifacts are automatically downloaded in deployment jobs. To disable use -download: none
- deployment: DeployApp
displayName: 'Deploy to Preproduction'
# Creates an environment if it doesn’t exist
environment: 'Optimizely_CMS_PreProduction'
strategy:
runOnce:
deploy:
steps:
- download: none
- task: PowerShell@2
displayName: 'Deploy to slot'
env:
API_SECRET: $(ApiSecret)
inputs:
targetType: 'inline'
script: |
if (-not (Get-Module -Name EpiCloud -ListAvailable)) {
Install-Module EpiCloud -Scope CurrentUser -Force
}
Connect-EpiCloud -ClientKey $(ApiKey) -ClientSecret $env:API_SECRET -ProjectId $(ProjectId)
$packageName = "$(archiveName)"
echo "Starting deployment using package $packageName"
$params = @{
DeploymentPackage = $packageName
TargetEnvironment = 'Preproduction'
UseMaintenancePage = $(UseMaintenancePage)
Wait = $true
}
$deploy = Start-EpiDeployment @params
echo "DeploymentId - $($deploy.id)"
echo "##vso[task.setvariable variable=deploymentId;]$($deploy.id)"
- task: PowerShell@2
displayName: 'Validate slot'
env:
API_SECRET: $(ApiSecret)
inputs:
targetType: 'inline'
script: |
Connect-EpiCloud -ClientKey $(ApiKey) -ClientSecret $env:API_SECRET -ProjectId $(ProjectId)
$deploy = Get-EpiDeployment -Id $env:DeploymentId
if ($deploy.status -eq 'AwaitingVerification'){
$response = Invoke-WebRequest -Uri $deploy.validationLinks[0]
if ($response.StatusCode -ne 200){
echo "Smoke test of slot url failed"
exit 1
}
}
- task: PowerShell@2
displayName: 'Reset'
env:
API_SECRET: $(ApiSecret)
condition: failed()
inputs:
targetType: 'inline'
script: |
Connect-EpiCloud -ClientKey $(ApiKey) -ClientSecret $env:API_SECRET -ProjectId $(ProjectId)
Reset-EpiDeployment -Id $env:DeploymentId -Wait
- task: PowerShell@2
displayName: 'Complete deployment'
env:
API_SECRET: $(ApiSecret)
inputs:
targetType: 'inline'
script: |
Connect-EpiCloud -ClientKey $(ApiKey) -ClientSecret $env:API_SECRET -ProjectId $(ProjectId)
Complete-EpiDeployment -Id $env:DeploymentId -Wait
# Run performance tests
- stage: Optimizely_CMS_Production
jobs:
# Add a Deployment job.
# Artifacts are automatically downloaded in deployment jobs. To disable use -download: none
- deployment: DeployApp
displayName: 'Deploy to Production'
# Creates an environment if it doesn’t exist
environment: 'Optimizely_CMS_Production'
strategy:
runOnce:
deploy:
steps:
- download: none
- task: PowerShell@2
displayName: 'Deploy to slot'
env:
API_SECRET: $(ApiSecret)
inputs:
targetType: 'inline'
script: |
if (-not (Get-Module -Name EpiCloud -ListAvailable)) {
Install-Module EpiCloud -Scope CurrentUser -Force
}
Connect-EpiCloud -ClientKey $(ApiKey) -ClientSecret $env:API_SECRET -ProjectId $(ProjectId)
$packageName = "$(archiveName)"
echo "Starting deployment using package $packageName"
$params = @{
DeploymentPackage = $packageName
TargetEnvironment = 'Production'
UseMaintenancePage = $(UseMaintenancePage)
Wait = $true
}
$deploy = Start-EpiDeployment @params
echo "DeploymentId - $($deploy.id)"
echo "##vso[task.setvariable variable=deploymentId;]$($deploy.id)"
- task: PowerShell@2
displayName: 'Validate slot'
env:
API_SECRET: $(ApiSecret)
inputs:
targetType: 'inline'
script: |
Connect-EpiCloud -ClientKey $(ApiKey) -ClientSecret $env:API_SECRET -ProjectId $(ProjectId)
$deploy = Get-EpiDeployment -Id $env:DeploymentId
if ($deploy.status -eq 'AwaitingVerification'){
$response = Invoke-WebRequest -Uri $deploy.validationLinks[0]
if ($response.StatusCode -ne 200){
echo "Smoke test of slot url failed"
exit 1
}
}
- task: PowerShell@2
displayName: 'Reset'
env:
API_SECRET: $(ApiSecret)
condition: failed()
inputs:
targetType: 'inline'
script: |
Connect-EpiCloud -ClientKey $(ApiKey) -ClientSecret $env:API_SECRET -ProjectId $(ProjectId)
Reset-EpiDeployment -Id $env:DeploymentId -Wait
- task: PowerShell@2
displayName: 'Complete deployment'
env:
API_SECRET: $(ApiSecret)
inputs:
targetType: 'inline'
script: |
Connect-EpiCloud -ClientKey $(ApiKey) -ClientSecret $env:API_SECRET -ProjectId $(ProjectId)
Complete-EpiDeployment -Id $env:DeploymentId -Wait
And the following variables
Project Structure
Epinova have an updated blog post for CMS 12.
https://www.epinova.no/folg-med/blogg/2021/epinova-dxp-deployment-extension-for-azure-devops--version-2/
I'm trying to set up a build pipeline (using yaml) for CMS 12 (.NET 5) in Azure DevOps and need some assistance. Does anyone have a working example or a guide for doing this? There are plenty of guides for older CMS versions (.NET Framework) but I'm not able to find any that covers the .NET 5 version.