From fa0bd230b4e8852a4bd5eecc76fe5e88cde4f7b6 Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Fri, 25 Jul 2025 19:21:25 +0100 Subject: [PATCH 01/23] Beginnings of a Cloud CI/CD v2 Flow implementation --- .../APIv2/Add-DeploymentArtifact.ps1 | 128 ++++++++++++++++++ .github/powershell/APIv2/Apply-Patch.ps1 | 90 ++++++++++++ .github/powershell/APIv2/Get-ChangesById.ps1 | 104 ++++++++++++++ .../powershell/APIv2/Get-LatestDeployment.ps1 | 105 ++++++++++++++ .github/powershell/APIv2/Start-Deployment.ps1 | 125 +++++++++++++++++ .../APIv2/Test-DeploymentStatus.ps1 | 111 +++++++++++++++ .github/workflows/jobs/cloud-artifact.yml | 59 ++++++++ .github/workflows/jobs/cloud-deployment.yml | 82 +++++++++++ .github/workflows/jobs/cloud-preflight.yml | 62 +++++++++ .github/workflows/jobs/cloud-sync.yml | 124 +++++++++++++++++ .github/workflows/main-v2.yml | 58 ++++++++ 11 files changed, 1048 insertions(+) create mode 100644 .github/powershell/APIv2/Add-DeploymentArtifact.ps1 create mode 100644 .github/powershell/APIv2/Apply-Patch.ps1 create mode 100644 .github/powershell/APIv2/Get-ChangesById.ps1 create mode 100644 .github/powershell/APIv2/Get-LatestDeployment.ps1 create mode 100644 .github/powershell/APIv2/Start-Deployment.ps1 create mode 100644 .github/powershell/APIv2/Test-DeploymentStatus.ps1 create mode 100644 .github/workflows/jobs/cloud-artifact.yml create mode 100644 .github/workflows/jobs/cloud-deployment.yml create mode 100644 .github/workflows/jobs/cloud-preflight.yml create mode 100644 .github/workflows/jobs/cloud-sync.yml create mode 100644 .github/workflows/main-v2.yml diff --git a/.github/powershell/APIv2/Add-DeploymentArtifact.ps1 b/.github/powershell/APIv2/Add-DeploymentArtifact.ps1 new file mode 100644 index 0000000..86741c9 --- /dev/null +++ b/.github/powershell/APIv2/Add-DeploymentArtifact.ps1 @@ -0,0 +1,128 @@ +param( + [Parameter(Position=0)] + [string] + $ProjectId, + + [Parameter(Position=1)] + [string] + $ApiKey, + + [Parameter(Position=2)] + [string] + $FilePath, + + [Parameter(Position=3)] + [string] + $Description = $null, + + [Parameter(Position=4)] + [string] + $Version = $null, + + [Parameter(Position=5)] + [string] + $PipelineVendor, ## GITHUB or AZUREDEVOPS + + [Parameter(Position=6)] + [string] + $BaseUrl = "https://api.cloud.umbraco.com" +) + +### Endpoint docs +# https://docs.umbraco.com/umbraco-cloud/set-up/project-settings/umbraco-cicd/umbracocloudapi/todo-v2 +# +$url = "$BaseUrl/v2/projects/$ProjectId/deployments/artifacts" + +# test if file is present +if (-not $FilePath) { + Write-Host "FilePath is empty" + exit 1 +} + +if (-not (Test-Path -Path $FilePath -PathType Leaf)) { + Write-Host "FilePath does not contain a file" + exit 1 +} +# end test + +$Headers = @{ + 'accept' = 'application/json' + 'Content-Type' = 'multipart/form-data' + 'Umbraco-Cloud-Api-Key' = $ApiKey +} +$contentType = 'application/zip' + +$multipartContent = [System.Net.Http.MultipartFormDataContent]::new() + +$fileStream = [System.IO.FileStream]::new($filePath, [System.IO.FileMode]::Open) +$fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new('form-data') +$fileHeader.Name = 'file' +$fileHeader.FileName = Split-Path -leaf $filePath +$fileContent = [System.Net.Http.StreamContent]::new($fileStream) +$fileContent.Headers.ContentDisposition = $fileHeader +$fileContent.Headers.ContentType = [System.Net.Http.Headers.MediaTypeHeaderValue]::Parse($contentType) + +$multipartContent.Add($fileContent) + +$stringHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data") +$stringHeader.Name = "description" +$StringContent = [System.Net.Http.StringContent]::new($Description) +$StringContent.Headers.ContentDisposition = $stringHeader +$multipartContent.Add($stringContent) + +$stringHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data") +$stringHeader.Name = "version" +$StringContent = [System.Net.Http.StringContent]::new($Version) +$StringContent.Headers.ContentDisposition = $stringHeader +$multipartContent.Add($stringContent) + + +try { + $response = Invoke-WebRequest -Body $multipartContent -Headers $Headers -Method 'POST' -Uri $url + if ($response.StatusCode -ne 200) + { + Write-Host "---Response Start---" + Write-Host $response + Write-Host "---Response End---" + Write-Host "Unexpected response - see above" + exit 1 + } + + $responseJson = $response.Content | ConvertFrom-Json + $artifactId = $responseJson.artifactId + + switch ($PipelineVendor) { + "GITHUB" { + "artifactId=$($artifactId)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append + } + "AZUREDEVOPS" { + Write-Host "##vso[task.setvariable variable=artifactId;isOutput=true]$($artifactId)" + } + "TESTRUN" { + Write-Host $PipelineVendor + } + Default { + Write-Host "Please use one of the supported Pipeline Vendors or enhance script to fit your needs" + Write-Host "Currently supported are: GITHUB and AZUREDEVOPS" + Exit 1 + } + } + + Write-Host "Artifact uploaded - Artifact Id: $($artifactId)" + Write-Host "--- Upload Response ---" + Write-Output $responseJson + + exit 0 +} +catch +{ + Write-Host "---Error---" + Write-Host $_.Exception.Message + if ($null -ne $_.Exception.Response) { + $responseStream = $_.Exception.Response.GetResponseStream() + $reader = New-Object System.IO.StreamReader($responseStream) + $responseBody = $reader.ReadToEnd() + Write-Host "Response Body: $responseBody" + } + exit 1 +} \ No newline at end of file diff --git a/.github/powershell/APIv2/Apply-Patch.ps1 b/.github/powershell/APIv2/Apply-Patch.ps1 new file mode 100644 index 0000000..f26ba28 --- /dev/null +++ b/.github/powershell/APIv2/Apply-Patch.ps1 @@ -0,0 +1,90 @@ +param ( + [Parameter(Position=0)] + [string] + $PatchFile, + + [Parameter(Position=1)] + [string] + $LatestDeploymentId, + + [Parameter(Position=3)] + [string] + $PipelineVendor, + + [Parameter(Position=3)] + [string] + $GitUserName, + + [Parameter(Position=4)] + [string] + $GitUserEmail +) + +git config user.name $GitUserName +git config user.email $GitUserEmail + +If ($PipelineVendor -eq "AZUREDEVOPS"){ + # we need to checkout the specific branch to be able to commit bad to repo in Azure DevOps + git checkout $env:BUILD_SOURCEBRANCHNAME +} + +Write-Host "Testing the patch - errors might show up, and that is okay" +Write-Host "==========================================================" +# Check if the patch has been applied already, skip if it has +git apply $PatchFile --reverse --ignore-space-change --ignore-whitespace --check +If ($LASTEXITCODE -eq 0) { + Write-Host "Patch already applied === concluding the apply patch part" + Exit 0 +} Else { + Write-Host "Patch not applied yet" +} + +Write-Host "Checking if patch can be applied..." +# Check if the patch can be applied +git apply $PatchFile --ignore-space-change --ignore-whitespace --check +If ($LASTEXITCODE -eq 0) { + Write-Host "Patch needed, trying to apply now" + Write-Host "=================================" + git apply $PatchFile --ignore-space-change --ignore-whitespace + + switch ($PipelineVendor) { + "GITHUB" { + git add * + git commit -m "Adding cloud changes since deployment $LatestDeploymentId [skip ci]" + git push + $updatedSha = git rev-parse HEAD + + # Record the new sha for the deploy + "updatedSha=$($updatedSha)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append + } + "AZUREDEVOPS" { + git add --all + git commit -m "Adding cloud changes since deployment $LatestDeploymentId [skip ci]" + git push --set-upstream origin $env:BUILD_SOURCEBRANCHNAME + + # Record the new sha for the deploy + $updatedSha = git rev-parse HEAD + Write-Host "##vso[task.setvariable variable=updatedSha;isOutput=true]$($updatedSha)" + } + "TESTRUN" { + Write-Host $PipelineVendor + } + Default { + Write-Host "Please use one of the supported Pipeline Vendors or enhance script to fit your needs" + Write-Host "Currently supported are: GITHUB and AZUREDEVOPS" + Exit 1 + } + } + + Write-Host "Changes are applied successfully" + Write-Host "" + Write-Host "Updated SHA: $updatedSha" + Exit 0 +} Else { + Write-Host "" + Write-Host "Patch cannot be applied - please check the output below for the problematic parts" + Write-Host "=================================================================================" + Write-Host "" + git apply -v --reject $PatchFile --ignore-space-change --ignore-whitespace --check + Exit 1 +} \ No newline at end of file diff --git a/.github/powershell/APIv2/Get-ChangesById.ps1 b/.github/powershell/APIv2/Get-ChangesById.ps1 new file mode 100644 index 0000000..89e06b8 --- /dev/null +++ b/.github/powershell/APIv2/Get-ChangesById.ps1 @@ -0,0 +1,104 @@ +# Set variables +param( + [Parameter(Position=0)] + [string] + $ProjectId, + + [Parameter(Position=1)] + [string] + $ApiKey, + + [Parameter(Position=2)] + [string] + $DeploymentId, + + [Parameter(Position=3)] + [string] + $TargetEnvironmentAlias, + + [Parameter(Position=4)] + [string] + $DownloadFolder, + + [Parameter(Position=5)] + [string] + $PipelineVendor, ## GITHUB or AZUREDEVOPS + + [Parameter(Position=6)] + [string] + $BaseUrl = "https://api.cloud.umbraco.com" +) + +### Endpoint docs +# https://docs.umbraco.com/umbraco-cloud/set-up/project-settings/umbraco-cicd/umbracocloudapi/todo-v2 +# +$ChangeUrl = "$BaseUrl/v2/projects/$ProjectId/deployments/$DeploymentId/diff?targetEnvironmentAlias=$TargetEnvironmentAlias" + +$Headers = @{ + 'Umbraco-Cloud-Api-Key' = $ApiKey + 'Content-Type' = 'application/json' +} + +if ($GetDiffDeploymentId -eq '') { + Write-Host "I need a DeploymentId of an older deployment to download a git-patch" + Exit 1; +} + +# ensure folder exists +if (!(Test-Path $DownloadFolder -PathType Container)) { + Write-Host "Creting folder $($DownloadFolder)" + New-Item -ItemType Directory -Force -Path $DownloadFolder +} + +try { + $Response = Invoke-WebRequest -URI $ChangeUrl -Headers $Headers + $StatusCode = $Response.StatusCode + + switch ($StatusCode){ + "204" { + Write-Host "No Changes - You can continue" + $remoteChanges = "no" + } + "200" { + Write-Host "Changes detected" + $Response | Select-Object -ExpandProperty Content | Out-File "$DownloadFolder/git-patch.diff" + $remoteChanges = "yes" + } + Default { + Write-Host "---Response Start---" + Write-Host $Response + Write-Host "---Response End---" + Write-Host "Unexpected response - see above" + exit 1 + } + } + + switch ($PipelineVendor) { + "GITHUB" { + "remoteChanges=$($remoteChanges)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append + } + "AZUREDEVOPS" { + Write-Host "##vso[task.setvariable variable=remoteChanges;isOutput=true]$($remoteChanges)" + } + "TESTRUN" { + Write-Host $PipelineVendor + } + Default { + Write-Host "Please use one of the supported Pipeline Vendors or enhance script to fit your needs" + Write-Host "Currently supported are: GITHUB and AZUREDEVOPS" + Exit 1 + } + } + Exit 0 +} +catch { + Write-Host "---Error---" + Write-Host $_.Exception.Message + if ($null -ne $_.Exception.Response) { + $responseStream = $_.Exception.Response.GetResponseStream() + $reader = New-Object System.IO.StreamReader($responseStream) + $responseBody = $reader.ReadToEnd() + Write-Host "Response Body: $responseBody" + } + exit 1 +} \ No newline at end of file diff --git a/.github/powershell/APIv2/Get-LatestDeployment.ps1 b/.github/powershell/APIv2/Get-LatestDeployment.ps1 new file mode 100644 index 0000000..188823b --- /dev/null +++ b/.github/powershell/APIv2/Get-LatestDeployment.ps1 @@ -0,0 +1,105 @@ +# Set variables +param( + [Parameter(Position=0)] + [string] + $ProjectId, + + [Parameter(Position=1)] + [string] + $ApiKey, + + [Parameter(Position=2)] + [string] + $TargetEnvironmentAlias, + + [Parameter(Position=3)] + [string] + $PipelineVendor, ## GITHUB or AZUREDEVOPS + + [Parameter(Position=4)] + [string] + $BaseUrl = "https://api.cloud.umbraco.com" +) + +### Endpoint docs +# https://docs.umbraco.com/umbraco-cloud/set-up/project-settings/umbraco-cicd/umbracocloudapi/todo-v2 +# +# We want the Id of the latest deployment that created changes to cloud +# Filter deployments +$Skip = 0 +$Take = 1 +# Exclude cloud null deployments +$IncludeNullDeployments = $False + + +$DeploymentUrl = "$BaseUrl/v2/projects/$ProjectId/deployments?skip=$Skip&take=$Take&includenulldeployments=$IncludeNullDeployments&targetEnvironmentAlias=$TargetEnvironmentAlias" + +$Headers = @{ + 'Umbraco-Cloud-Api-Key' = $ApiKey + 'Content-Type' = 'application/json' +} + +# Actually calling the endpoint +try{ + $Response = Invoke-WebRequest -URI $DeploymentUrl -Headers $Headers + + if ($Response.StatusCode -eq 200) { + + $JsonResponse = ConvertFrom-Json $([String]::new($Response.Content)) + + $latestDeploymentId = '' + + if ($JsonResponse.data.Count -gt 0){ + + $latestDeploymentId = $JsonResponse.data[0].id + } + + ## Write the latest deployment id to the pipelines variables for use in a later step + switch ($PipelineVendor) { + "GITHUB" { + "latestDeploymentId=$($latestDeploymentId)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append + } + "AZUREDEVOPS" { + Write-Host "##vso[task.setvariable variable=latestDeploymentId;isOutput=true]$($latestDeploymentId)" + Write-Host "##vso[task.setvariable variable=latestDeploymentId]$($latestDeploymentId)" + + } + "TESTRUN" { + Write-Host $PipelineVendor + } + Default { + Write-Host "Please use one of the supported Pipeline Vendors or enhance script to fit your needs" + Write-Host "Currently supported are: GITHUB and AZUREDEVOPS" + Exit 1 + } + } + + if ($latestDeploymentId -eq '') { + Write-Host "No latest CICD Flow Deployments found" + Write-Host "----------------------------------------------------------------------------------------" + Write-Host "This is usually because you have yet to make changes to cloud through the CICD endpoints" + } + else { + Write-Host "Latest CICD Flow Deployment:" + Write-Host "$($latestDeploymentId)" + } + exit 0 + } + ## Let errors bubble forward + Write-Host "---Response Start---" + Write-Host $Response + Write-Host "---Response End---" + Write-Host "Unexpected response - see above" + exit 1 +} +catch { + Write-Host "---Error---" + Write-Host $_.Exception.Message + if ($null -ne $_.Exception.Response) { + $responseStream = $_.Exception.Response.GetResponseStream() + $reader = New-Object System.IO.StreamReader($responseStream) + $responseBody = $reader.ReadToEnd() + Write-Host "Response Body: $responseBody" + } + exit 1 +} \ No newline at end of file diff --git a/.github/powershell/APIv2/Start-Deployment.ps1 b/.github/powershell/APIv2/Start-Deployment.ps1 new file mode 100644 index 0000000..fba2dbe --- /dev/null +++ b/.github/powershell/APIv2/Start-Deployment.ps1 @@ -0,0 +1,125 @@ +param( + [Parameter(Position=0)] + [string] + $ProjectId, + + [Parameter(Position=1)] + [string] + $ApiKey, + + [Parameter(Position=2)] + [string] + $ArtifactId, + + [Parameter(Position=3)] + [string] + $TargetEnvironmentAlias, + + [Parameter(Position=4)] + [string] + $CommitMessage = "", + + [Parameter(Position=5)] + [bool] + $NoBuildAndRestore = $false, + + [Parameter(Position=6)] + [bool] + $SkipVersionCheck = $false, + + [Parameter(Position=7)] + [string] + $PipelineVendor, ## GITHUB or AZUREDEVOPS + + [Parameter(Position=8)] + [string] + $BaseUrl = "https://api.cloud.umbraco.com" +) + +### Endpoint docs +# https://docs.umbraco.com/umbraco-cloud/set-up/project-settings/umbraco-cicd/umbracocloudapi/todo-v2 +# +$url = "$BaseUrl/v2/projects/$ProjectId/deployments" + +$headers = @{ + 'Umbraco-Cloud-Api-Key' = $ApiKey + 'Content-Type' = 'application/json' +} + +$requestBody = @{ + 'targetEnvironmentAlias' = $TargetEnvironmentAlias + 'artifactId' = $ArtifactId + 'commitMessage' = $CommitMessage + 'noBuildAndRestore' = $NoBuildAndRestore + 'skipVersionCheck' = $SkipVersionCheck +} | ConvertTo-Json + +try { + Write-Host "Requesting start Deployment at $url with Request:" + $requestBody | Write-Output + + $response = Invoke-RestMethod -URI $url -Headers $headers -Method POST -Body $requestBody + $deploymentId = $response.deploymentId + + Write-Host "--- --- ---" + Write-Host "Response:" + $response | ConvertTo-Json -Depth 10 | Write-Output + + switch ($PipelineVendor) { + "GITHUB" { + "deploymentId=$($deploymentId)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append + } + "AZUREDEVOPS" { + Write-Host "##vso[task.setvariable variable=deploymentId;isOutput=true]$($deploymentId)" + } + "TESTRUN" { + Write-Host $PipelineVendor + } + Default { + Write-Host "Please use one of the supported Pipeline Vendors or enhance script to fit your needs" + Write-Host "Currently supported are: GITHUB and AZUREDEVOPS" + Exit 1 + } + } + + Write-Host "--- --- ---" + Write-Host "Deployment Created Successfully => $($deploymentId)" + exit 0 + + Write-Host "---Response Start---" + Write-Host $response + Write-Host "---Response End---" + Write-Host "Unexpected response - see above" + exit 1 +} +catch { + Write-Host "---Error---" + Write-Host $_.Exception.Message + + if ($_.Exception.Response -is [System.Net.HttpWebResponse]) { + $responseStream = $_.Exception.Response.GetResponseStream() + if ($null -ne $responseStream) { + $reader = New-Object System.IO.StreamReader($responseStream) + try { + $responseBody = $reader.ReadToEnd() + Write-Host "Response Body: $responseBody" + } + finally { + $reader.Dispose() + } + } + } + else { + + try { + $details = $_.ErrorDetails.ToString() | ConvertFrom-Json + $details | Format-List + } + catch { + Write-Host "Could not parse ErrorDetails as JSON." + } + + } + + exit 1 +} \ No newline at end of file diff --git a/.github/powershell/APIv2/Test-DeploymentStatus.ps1 b/.github/powershell/APIv2/Test-DeploymentStatus.ps1 new file mode 100644 index 0000000..e1f5b2e --- /dev/null +++ b/.github/powershell/APIv2/Test-DeploymentStatus.ps1 @@ -0,0 +1,111 @@ +param( + [Parameter(Position=0)] + [string] + $ProjectId, + + [Parameter(Position=1)] + [string] + $ApiKey, + + [Parameter(Position=2)] + [string] + $DeploymentId, + + [Parameter(Position=3)] + [int] + $TimeoutSeconds = 1200, + + [Parameter(Position=4)] + [string] + $BaseUrl = "https://api.cloud.umbraco.com" +) + +### Endpoint docs +# https://docs.umbraco.com/umbraco-cloud/set-up/project-settings/umbraco-cicd/umbracocloudapi/todo-v2 +# +$BaseStatusUrl = "$BaseUrl/v2/projects/$ProjectId/deployments/$DeploymentId" + +$timer = [Diagnostics.Stopwatch]::StartNew() + +$headers = @{ + 'Umbraco-Cloud-Api-Key' = $ApiKey + 'Content-Type' = 'application/json' +} + +function Request-Deployment-Status ([INT]$run){ + Write-Host "=====> Requesting Status - Run number $run" + try { + $response = Invoke-WebRequest -URI $url -Headers $headers -Method Get + + if ($response.StatusCode -eq 200) { + $jsonResponse = ConvertFrom-Json $([String]::new($response.Content)) + + Write-Host "DeploymentStatus: '$($jsonResponse.deploymentState)'" + + foreach ($item in $jsonResponse.deploymentStatusMessages){ + Write-Host "$($item.timestampUtc): $($item.message)" + } + + return $jsonResponse + } + } + catch + { + Write-Host "---Error---" + Write-Host $_.Exception.Message + if ($null -ne $_.Exception.Response) { + $responseStream = $_.Exception.Response.GetResponseStream() + $reader = New-Object System.IO.StreamReader($responseStream) + $responseBody = $reader.ReadToEnd() + Write-Host "Response Body: $responseBody" + } + exit 1 + } +} + +$run = 1 +$url = $BaseStatusUrl + +$statusesBeforeCompleted = ("Pending", "InProgress", "Queued") +Write-Host "Getting Status for Deployment: $($DeploymentId)" +do { + + $deploymentResponse = Request-Deployment-Status($run) + $run++ + + # Handle timeout + if ($timer.Elapsed.TotalSeconds -gt $TimeoutSeconds){ + throw "Timeout was reached" + } + + # Dont write if Deployment was finished + if ($statusesBeforeCompleted -contains $deploymentResponse.deploymentState){ + $sleepValue = 25 + Write-Host "=====> Still Deploying - sleeping for $sleepValue seconds" + Start-Sleep -Seconds $sleepValue + $LastModifiedUtc = $deploymentResponse.modifiedUtc.ToString("o") + $url = "$BaseStatusUrl\?lastModifiedUtc=$($LastModifiedUtc)" + } + +} while ( + $statusesBeforeCompleted -contains $deploymentResponse.deploymentState +) + +$timer.Stop() + +# Successfully deployed to cloud +if ($deploymentResponse.deploymentState -eq 'Completed'){ + Write-Host "Deployment completed successfully" + exit 0 +} + +# Deployment has failed +if ($deploymentResponse.deploymentState -eq 'Failed'){ + Write-Host "Deployment Failed" + exit 1 +} + +# Unexpected deployment status - considered a fail +Write-Host "Unexpected status: $deploymentResponse.deploymentState" +exit 1 + diff --git a/.github/workflows/jobs/cloud-artifact.yml b/.github/workflows/jobs/cloud-artifact.yml new file mode 100644 index 0000000..7a92add --- /dev/null +++ b/.github/workflows/jobs/cloud-artifact.yml @@ -0,0 +1,59 @@ +name: Prepare and Upload Artifact + +on: + workflow_call: + inputs: + newSha: + required: false + type: string + secrets: + projectId: + required: true + umbracoCloudApiKey: + required: true + outputs: + artifactId: + description: 'The Id of the uploaded artifact' + value: ${{ jobs.prepareDeployment.outputs.artifactId }} + +jobs: + prepareDeployment: + name: Prepare Artifact to cloud + runs-on: ubuntu-latest + outputs: + artifactId: ${{ steps.upload-artifact.outputs.artifactId }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.newSha }} + + # switch the gitignore files so cloud does not ignore the build frontend assets + # zip everything, except what is defined in the 'cloud.zipignore' + - name: Prepare Cloud Git Ignore and Zip Source Code + run: | + echo "switching .gitignore with cloud.gitignore" + cp cloud.gitignore .gitignore + echo "Packing artifact for upload" + zip -r sources.zip . -x@cloud.zipignore + shell: bash + + # store artifact for easy debug if needed + # - name: Store artifact in pipeline + # uses: actions/upload-artifact@v4 + # with: + # name: source-artifact + # path: ${{GITHUB.WORKSPACE}}/sources.zip + # retention-days: 1 + + # Upload your zipped artifact + - name: Post Zipped Artifact + id: upload-artifact + shell: pwsh + run: > + ${{GITHUB.WORKSPACE}}/.github/powershell/APIv2/Add-DeploymentArtifact.ps1 + -ProjectId ${{ secrets.projectId }} + -ApiKey ${{ secrets.umbracoCloudApiKey }} + -FilePath ${{ GITHUB.WORKSPACE }}/sources.zip + -Description "Artifact for ${{github.run_number}}" + -Version "${{github.run_number}}" + -PipelineVendor GITHUB \ No newline at end of file diff --git a/.github/workflows/jobs/cloud-deployment.yml b/.github/workflows/jobs/cloud-deployment.yml new file mode 100644 index 0000000..8253fa8 --- /dev/null +++ b/.github/workflows/jobs/cloud-deployment.yml @@ -0,0 +1,82 @@ +name: Deploy To Cloud + +on: + workflow_dispatch: + inputs: + artifactId: + required: false + type: string + targetEnvironmentAlias: + description: 'The target environment alias to deploy to' + required: true + type: string + + workflow_call: + inputs: + artifactId: + required: true + type: string + targetEnvironmentAlias: + description: 'The target environment alias to deploy to' + required: true + type: string + noBuildAndRestore: + description: 'Skip build and restore steps' + required: false + type: number + default: 0 + skipVersionCheck: + description: 'Skip version check' + required: false + type: number + default: 0 + + secrets: + projectId: + required: true + umbracoCloudApiKey: + required: true + +jobs: + startDeployment: + name: Start Deployment + runs-on: ubuntu-latest + outputs: + runningDeploymentId: ${{ steps.requestStartDeployment.outputs.deploymentId }} + steps: + - uses: actions/checkout@v4 + + # Request to prepare a deployment + # - sets the commit message to be used in cloud + # - supplies you with a deploymentId to be used in the rest of the process + - name: Request Start Deployment + id: requestStartDeployment + shell: pwsh + run: > + ${{GITHUB.WORKSPACE}}/.github/powershell/APIv2/Start-Deployment.ps1 + -ProjectId ${{ secrets.projectId }} + -ApiKey ${{ secrets.umbracoCloudApiKey }} + -ArtifactId ${{ inputs.artifactId }} + -TargetEnvironmentAlias ${{ inputs.targetEnvironmentAlias }} + -CommitMessage "Run number ${{github.run_number}}" + -NoBuildAndRestore ${{ inputs.noBuildAndRestore }} + -SkipVersionCheck ${{ inputs.skipVersionCheck }} + -PipelineVendor GITHUB + + awaitDeploymentFinished: + name: Await deployment to finish + runs-on: ubuntu-latest + needs: startDeployment + steps: + - uses: actions/checkout@v4 + + # Poll until deployment finishes + - name: Wait for deployment completed + shell: pwsh + env: + runningDeploymentId: ${{ needs.startDeployment.outputs.runningDeploymentId }} + run: > + ${{GITHUB.WORKSPACE}}/.github/powershell/APIv2/Test-DeploymentStatus.ps1 + -ProjectId ${{ secrets.projectId }} + -ApiKey ${{ secrets.umbracoCloudApiKey }} + -DeploymentId ${{ env.runningDeploymentId }} \ No newline at end of file diff --git a/.github/workflows/jobs/cloud-preflight.yml b/.github/workflows/jobs/cloud-preflight.yml new file mode 100644 index 0000000..895c10a --- /dev/null +++ b/.github/workflows/jobs/cloud-preflight.yml @@ -0,0 +1,62 @@ +name: Umbraco Cloud Preflight + +on: + workflow_call: + inputs: + pathToWebsite: + required: false + type: string + csprojFile: + required: false + type: string + + secrets: + umbracoCloudJson: + required: true + deployLicenseKey: + required: true + formsLicenseKey: + required: true + +obs: + prepareForDeployment: + name: Prepare Source for Deployment + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # Enable/disable package references in .csproj + - name: Update csproj + working-directory: ${{ inputs.pathToWebsite }} + shell: pwsh + run: | + $content = Get-Content '${{ inputs.csprojFile }}' -Raw + + # Enable Umbraco.Cloud.Cms (uncomment) + $content = $content -replace '(?s)', '' + + # Enable Umbraco.Deploy.Cloud (uncomment) + $content = $content -replace '(?s)', '' + + # Disable Umbraco.Deploy.OnPrem (comment out) + $content = $content -replace '(?s)]*Include="Umbraco\.Deploy\.OnPrem")(?=[^>]*Version="([^"]*)")[^>]*/?>', '' + + Set-Content '${{ inputs.csprojFile }}' $content + + # Create umbraco-cloud.json file from Secret + - name: Umbraco Cloud Json + working-directory: ${{ inputs.pathToWebsite }} + shell: pwsh + run: set-content 'umbraco-cloud.json' -value '${{ secrets.umbracoCloudJson }}' + + # Create Deploy license key file from Secret + - name: Deploy License Key + working-directory: "${{ inputs.pathToWebsite }}/umbraco/Licenses" + shell: pwsh + run: set-content 'umbracoDeploy.lic' -value '${{ secrets.deployLicenseKey }}' + + # Create Forms license key file from Secret + - name: Forms License Key + working-directory: "${{ inputs.pathToWebsite }}/umbraco/Licenses" + shell: pwsh + run: set-content 'umbracoForms.lic' -value '${{ secrets.formsLicenseKey }}' \ No newline at end of file diff --git a/.github/workflows/jobs/cloud-sync.yml b/.github/workflows/jobs/cloud-sync.yml new file mode 100644 index 0000000..a052048 --- /dev/null +++ b/.github/workflows/jobs/cloud-sync.yml @@ -0,0 +1,124 @@ +name: Umbraco Cloud Sync + +on: + workflow_call: + outputs: + newSha: + description: 'The new SHA hash if there was a patch' + value: ${{ jobs.applyRemoteChanges.outputs.newSha }} + inputs: + targetEnvironmentAlias: + description: 'The target environment alias to sync with' + required: true + type: string + secrets: + projectId: + required: true + umbracoCloudApiKey: + required: true + +jobs: + preflight: + name: Check Cloud for changes + runs-on: ubuntu-latest + steps: + # Gets the latest CICD Flow deployment to target Environment if there are any + # Will write "latestDeploymentId" to pipeline variables, value can be an uuid or empty string + - uses: actions/checkout@v4 + - name: Get Latest Deployment + id: latest-deployment + shell: pwsh + run: > + ${{GITHUB.WORKSPACE}}/.github/powershell/APIv2/Get-LatestDeployment.ps1 + -ProjectId ${{ secrets.projectId }} + -ApiKey ${{ secrets.umbracoCloudApiKey }} + -TargetEnvironmentAlias ${{ inputs.targetEnvironmentAlias }} + -PipelineVendor GITHUB + outputs: + latestDeploymentId: ${{ steps.latest-deployment.outputs.latestDeploymentId }} + + checkForChanges: + name: Check if there are changes since latest deployment + needs: preflight + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + # Download git-patch file based on changes since latest deployment to target Environment + # Will write "remoteChanges" to pipeline variables, value can be "yes" or "no" + # When "remoteChanges" is yes, there will also be downloaded a patch-file to the path you specified in -DownloadFolder parameter + - name: Fetch Changes From Cloud + env: + latestDeploymentId: ${{ needs.preflight.outputs.latestDeploymentId }} + if: ${{ env.latestDeploymentId != '' }} + id: latest-changes + shell: pwsh + run: > + ${{GITHUB.WORKSPACE}}/.github/powershell/APIv2/Get-ChangesById.ps1 + -ProjectId ${{ secrets.projectId }} + -ApiKey ${{ secrets.umbracoCloudApiKey }} + -DeploymentId ${{ env.latestDeploymentId }} + -TargetEnvironmentAlias ${{ inputs.targetEnvironmentAlias }} + -DownloadFolder ${{GITHUB.WORKSPACE}}/patch + -PipelineVendor GITHUB + + - name: See diff content if any + if: ${{ steps.latest-changes.outputs.remoteChanges == 'yes' }} + shell: pwsh + run: get-content ${{ GITHUB.WORKSPACE }}/patch/git-patch.diff + + - name: Store diff before applying + if: ${{ steps.latest-changes.outputs.remoteChanges == 'yes' }} + uses: actions/upload-artifact@v4 + with: + name: git-patch + path: ${{ GITHUB.WORKSPACE }}/patch/git-patch.diff + retention-days: 1 + outputs: + remoteChanges: ${{ steps.latest-changes.outputs.remoteChanges }} + + applyRemoteChanges: + name: Apply remote changes + needs: [preflight, checkForChanges] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + env: + remoteChanges: ${{ needs.checkForChanges.outputs.remoteChanges }} + if: ${{ env.remoteChanges == 'yes' }} + with: + fetch-depth: 0 + + - name: Get stored diff + env: + remoteChanges: ${{ needs.checkForChanges.outputs.remoteChanges }} + if: ${{ env.remoteChanges == 'yes' }} + uses: actions/download-artifact@v4 + with: + name: git-patch + path: ${{ GITHUB.WORKSPACE }}/patch + + # Using plain git to try an push changes back to local repo + # Depending on your setup you may need to change settings and permissions to better fit your needs + # This targets the same branch as the pipeline was triggered on. + + ## You can change the gitName and gitEmail to whatever you want, this will show up in you git history on + ## changes coming from Umbraco Cloud + + - name: Applying git patch to branch + id: update-bundle + env: + remoteChanges: ${{ needs.checkForChanges.outputs.remoteChanges }} + latestDeploymentId: ${{ needs.preflight.outputs.latestDeploymentId }} + gitName: github-actions + gitEmail: github-actions@github.com + if: ${{ env.remoteChanges == 'yes' }} + shell: pwsh + run: > + ${{GITHUB.WORKSPACE}}/.github/powershell/APIv2/Apply-Patch.ps1 + -PatchFile ${{ GITHUB.WORKSPACE }}/patch/git-patch.diff + -LatestDeploymentId ${{ env.latestDeploymentId }} + -PipelineVendor GITHUB + -GitUserName ${{ env.gitName }} + -GitUserEmail ${{ env.gitEmail }} + outputs: + newSha: ${{ steps.update-bundle.outputs.updatedSha }} diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml new file mode 100644 index 0000000..f2f3f04 --- /dev/null +++ b/.github/workflows/main-v2.yml @@ -0,0 +1,58 @@ +name: pipeline # You can add your own name for the pipeline here + +# Trigger when committing to main branch +on: + push: + branches: + - main + workflow_dispatch: # Allow manual triggering of the workflow + +jobs: + + # Get changes from cloud + # cloud-sync: + # name: "Umbraco Cloud Sync" + # uses: ./.github/workflows/jobs/cloud-sync.yml + # secrets: + # projectId: ${{ secrets.PROJECT_ID }} + # umbracoCloudApiKey: ${{ secrets.UMBRACO_CLOUD_API_KEY }} + # with: + # targetEnvironmentAlias: ${{ vars.TARGET_ENVIRONMENT_ALIAS }} + + # Prepare source code ready for deployment + cloud-preflight: + name: "Prepare Source for Deployment" + uses: ./.github/workflows/jobs/cloud-preflight.yml + with: + pathToWebsite: "src/OpenSourceTest.Site" + csprojFile: "OpenSourceTest.Site.csproj" + secrets: + umbracoCloudJson: ${{ secrets.UMBRACO_CLOUD_JSON }} + deployLicenseKey: ${{ secrets.DEPLOY_LICENSE_KEY }} + formsLicenseKey: ${{ secrets.FORMS_LICENSE_KEY }} + + # Pack and upload the deployment Artifact + cloud-artifact: + name: "Prepare and Upload Artifact" + uses: ./.github/workflows/jobs/cloud-artifact.yml + needs: cloud-preflight + secrets: + projectId: ${{ secrets.PROJECT_ID }} + umbracoCloudApiKey: ${{ secrets.UMBRACO_CLOUD_API_KEY }} + + # Deploy to Umbraco Cloud + # #### + # you can edit the variables noBuildAndRestore and skipVersionCheck + # use 0 for false and 1 for true + cloud-deployment: + name: "Deploy to Cloud" + needs: cloud-artifact + uses: ./.github/workflows/jobs/cloud-deployment.yml + with: + artifactId: ${{ needs.cloud-artifact.outputs.artifactId }} + targetEnvironmentAlias: ${{ vars.TARGET_ENVIRONMENT_ALIAS }} + noBuildAndRestore: 0 + skipVersionCheck: 0 + secrets: + projectId: ${{ secrets.PROJECT_ID }} + umbracoCloudApiKey: ${{ secrets.UMBRACO_CLOUD_API_KEY }} \ No newline at end of file From e00235df9fdc950f775a958987205bf3efe40999 Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Sat, 26 Jul 2025 13:22:11 +0100 Subject: [PATCH 02/23] Use predeploy instead of preflight --- .../jobs/{cloud-preflight.yml => cloud-predeploy.yml} | 0 .github/workflows/main-v2.yml | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename .github/workflows/jobs/{cloud-preflight.yml => cloud-predeploy.yml} (100%) diff --git a/.github/workflows/jobs/cloud-preflight.yml b/.github/workflows/jobs/cloud-predeploy.yml similarity index 100% rename from .github/workflows/jobs/cloud-preflight.yml rename to .github/workflows/jobs/cloud-predeploy.yml diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index f2f3f04..28f8849 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -20,9 +20,9 @@ jobs: # targetEnvironmentAlias: ${{ vars.TARGET_ENVIRONMENT_ALIAS }} # Prepare source code ready for deployment - cloud-preflight: + cloud-predeploy: name: "Prepare Source for Deployment" - uses: ./.github/workflows/jobs/cloud-preflight.yml + uses: ./.github/workflows/jobs/cloud-predeploy.yml with: pathToWebsite: "src/OpenSourceTest.Site" csprojFile: "OpenSourceTest.Site.csproj" @@ -35,7 +35,7 @@ jobs: cloud-artifact: name: "Prepare and Upload Artifact" uses: ./.github/workflows/jobs/cloud-artifact.yml - needs: cloud-preflight + needs: cloud-predeploy secrets: projectId: ${{ secrets.PROJECT_ID }} umbracoCloudApiKey: ${{ secrets.UMBRACO_CLOUD_API_KEY }} From e47d02316cff5f2f62a904b689170dde648c53ba Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Mon, 28 Jul 2025 16:47:47 +0100 Subject: [PATCH 03/23] Remove old scripts --- .../APIv1/Add-DeploymentPackage.ps1 | 63 --------- .github/powershell/APIv1/New-Deployment.ps1 | 79 ----------- .github/powershell/APIv1/Start-Deployment.ps1 | 53 ------- .../APIv1/Test-DeploymentStatus.ps1 | 95 ------------- .github/workflows/main.yml | 26 ---- .github/workflows/package-and-deploy.yml | 130 ------------------ .github/workflows/test-matt.yml | 33 ----- 7 files changed, 479 deletions(-) delete mode 100644 .github/powershell/APIv1/Add-DeploymentPackage.ps1 delete mode 100644 .github/powershell/APIv1/New-Deployment.ps1 delete mode 100644 .github/powershell/APIv1/Start-Deployment.ps1 delete mode 100644 .github/powershell/APIv1/Test-DeploymentStatus.ps1 delete mode 100644 .github/workflows/main.yml delete mode 100644 .github/workflows/package-and-deploy.yml delete mode 100644 .github/workflows/test-matt.yml diff --git a/.github/powershell/APIv1/Add-DeploymentPackage.ps1 b/.github/powershell/APIv1/Add-DeploymentPackage.ps1 deleted file mode 100644 index e312746..0000000 --- a/.github/powershell/APIv1/Add-DeploymentPackage.ps1 +++ /dev/null @@ -1,63 +0,0 @@ -param( - [Parameter(Position=0)] - [string] - $ProjectId, - - [Parameter(Position=1)] - [string] - $DeploymentId, - - [Parameter(Position=2)] - [string] - $ApiKey, - - [Parameter(Position=3)] - [string] - $FilePath, - - [Parameter(Position=4)] - [string] - $BaseUrl = "https://api.cloud.umbraco.com" -) - -### Endpoint docs -# https://docs.umbraco.com/umbraco-cloud/set-up/project-settings/umbraco-cicd/umbracocloudapi#upload-zip-source-file -# -$url = "$BaseUrl/v1/projects/$ProjectId/deployments/$DeploymentId/package" - -$fieldName = 'file' -$contentType = 'application/zip' -$umbracoHeader = @{ 'Umbraco-Cloud-Api-Key' = $ApiKey } - - -$fileStream = [System.IO.FileStream]::new($filePath, [System.IO.FileMode]::Open) -$fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new('form-data') -$fileHeader.Name = $fieldName -$fileHeader.FileName = Split-Path -leaf $filePath -$fileContent = [System.Net.Http.StreamContent]::new($fileStream) -$fileContent.Headers.ContentDisposition = $fileHeader -$fileContent.Headers.ContentType = [System.Net.Http.Headers.MediaTypeHeaderValue]::Parse($contentType) - -$multipartContent = [System.Net.Http.MultipartFormDataContent]::new() -$multipartContent.Add($fileContent) - -try { - $response = Invoke-WebRequest -Body $multipartContent -Headers $umbracoHeader -Method 'POST' -Uri $url - if ($response.StatusCode -ne 202) - { - Write-Host "---Response Start---" - Write-Host $response - Write-Host "---Response End---" - Write-Host "Unexpected response - see above" - exit 1 - } - - Write-Host $response.Content | ConvertTo-Json - exit 0 -} -catch -{ - Write-Host "---Error---" - Write-Host $_ - exit 1 -} \ No newline at end of file diff --git a/.github/powershell/APIv1/New-Deployment.ps1 b/.github/powershell/APIv1/New-Deployment.ps1 deleted file mode 100644 index d6e0991..0000000 --- a/.github/powershell/APIv1/New-Deployment.ps1 +++ /dev/null @@ -1,79 +0,0 @@ -param( - [Parameter(Position=0)] - [string] - $ProjectId, - - [Parameter(Position=1)] - [string] - $ApiKey, - - [Parameter(Position=2)] - [string] - $CommitMessage, - - [Parameter(Position=3)] - [string] - $PipelineVendor, ## GITHUB or AZUREDEVOPS - - [Parameter(Position=4)] - [string] - $BaseUrl = "https://api.cloud.umbraco.com" -) - -### Endpoint docs -# https://docs.umbraco.com/umbraco-cloud/set-up/project-settings/umbraco-cicd/umbracocloudapi#create-the-deployment -# - -$url = "$BaseUrl/v1/projects/$ProjectId/deployments" - -$headers = @{ - 'Umbraco-Cloud-Api-Key' = $ApiKey - 'Content-Type' = 'application/json' -} - -$body = @{ - 'commitMessage' = $CommitMessage -} | ConvertTo-Json - -Write-Host "Posting to $url with commit message: $CommitMessage" -try { - $response = Invoke-RestMethod -URI $url -Headers $headers -Method POST -Body $body - $status = $response.deploymentState - $deploymentId = $response.deploymentId - - if ($status -eq "Created") { - - Write-Host $response.updateMessage - - switch ($PipelineVendor) { - "GITHUB" { - "deploymentId=$($deploymentId)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append - } - "AZUREDEVOPS" { - Write-Host "##vso[task.setvariable variable=deploymentId;]$($deploymentId)" - } - "TESTRUN" { - Write-Host $PipelineVendor - } - Default { - Write-Host "Please use one of the supported Pipeline Vendors or enhance script to fit your needs" - Write-Host "Currently supported are: GITHUB and AZUREDEVOPS" - Exit 1 - } - } - - Write-Host "Deployment Created Successfully => $($deploymentId)" - exit 0 - } - - Write-Host "---Response Start---" - Write-Host $response - Write-Host "---Response End---" - Write-Host "Unexpected response - see above" - exit 1 -} -catch { - Write-Host "---Error---" - Write-Host $_ - exit 1 -} diff --git a/.github/powershell/APIv1/Start-Deployment.ps1 b/.github/powershell/APIv1/Start-Deployment.ps1 deleted file mode 100644 index 80fc675..0000000 --- a/.github/powershell/APIv1/Start-Deployment.ps1 +++ /dev/null @@ -1,53 +0,0 @@ -param( - [Parameter(Position=0)] - [string] - $ProjectId, - - [Parameter(Position=1)] - [string] - $DeploymentId, - - [Parameter(Position=2)] - [string] - $ApiKey, - - [Parameter(Position=3)] - [string] - $BaseUrl = "https://api.cloud.umbraco.com" -) - -### Endpoint docs -# https://docs.umbraco.com/umbraco-cloud/set-up/project-settings/umbraco-cicd/umbracocloudapi#start-deployment -# -$url = "$BaseUrl/v1/projects/$ProjectId/deployments/$DeploymentId" - -$headers = @{ - 'Umbraco-Cloud-Api-Key' = $ApiKey - 'Content-Type' = 'application/json' -} - -$requestBody = @{ - 'deploymentState' = 'Queued' -} | ConvertTo-Json - -try { - Write-Host "Requesting start Deployment at $url" - $response = Invoke-RestMethod -URI $url -Headers $headers -Method PATCH -Body $requestBody - $status = $response.deploymentState - - if ($status -eq "Queued") { - Write-Host $Response.updateMessage - exit 0 - } - - Write-Host "---Response Start---" - Write-Host $response - Write-Host "---Response End---" - Write-Host "Unexpected response - see above" - exit 1 -} -catch { - Write-Host "---Error---" - Write-Host $_ - exit 1 -} \ No newline at end of file diff --git a/.github/powershell/APIv1/Test-DeploymentStatus.ps1 b/.github/powershell/APIv1/Test-DeploymentStatus.ps1 deleted file mode 100644 index 21387a0..0000000 --- a/.github/powershell/APIv1/Test-DeploymentStatus.ps1 +++ /dev/null @@ -1,95 +0,0 @@ -param( - [Parameter(Position=0)] - [string] - $ProjectId, - - [Parameter(Position=1)] - [string] - $DeploymentId, - - [Parameter(Position=2)] - [string] - $ApiKey, - - [Parameter(Position=3)] - [int] - $TimeoutSeconds = 1200, - - [Parameter(Position=4)] - [string] - $BaseUrl = "https://api.cloud.umbraco.com" -) - -### Endpoint docs -# https://docs.umbraco.com/umbraco-cloud/set-up/project-settings/umbraco-cicd/umbracocloudapi#get-deployment-status -# -$url = "$BaseUrl/v1/projects/$ProjectId/deployments/$DeploymentId" - -$timer = [Diagnostics.Stopwatch]::StartNew() - -$headers = @{ - 'Umbraco-Cloud-Api-Key' = $ApiKey - 'Content-Type' = 'application/json' -} - -function Request-Deployment-Status ([INT]$run){ - Write-Host "=====> Requesting Status - Run number $run" - try { - $response = Invoke-WebRequest -URI $url -Headers $headers - if ($response.StatusCode -eq 200) { - - $jsonResponse = ConvertFrom-Json $([String]::new($response.Content)) - - Write-Host $jsonResponse.updateMessage - return $jsonResponse.deploymentState - } - } - catch - { - Write-Host "---Error---" - Write-Host $_ - exit 1 - } -} - -$run = 1 - -$statusesBeforeCompleted = ("Pending", "InProgress", "Queued") - -do { - $deploymentStatus = Request-Deployment-Status($run) - $run++ - - # Handle timeout - if ($timer.Elapsed.TotalSeconds -gt $TimeoutSeconds){ - throw "Timeout was reached" - } - - # Dont write if Deployment was finished - if ($statusesBeforeCompleted -contains $deploymentStatus){ - Write-Host "=====> Still Deploying - sleeping for 15 seconds" - Start-Sleep -Seconds 15 - } - -} while ( - $statusesBeforeCompleted -contains $deploymentStatus -) - -$timer.Stop() - -# Successfully deployed to cloud -if ($deploymentStatus -eq 'Completed'){ - Write-Host "Deployment completed successfully" - exit 0 -} - -# Deployment has failed -if ($deploymentStatus -eq 'Failed'){ - Write-Host "Deployment Failed" - exit 1 -} - -# Unexpected deployment status - considered a fail -Write-Host "Unexpected status: $deploymentStatus" -exit 1 - diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 69b01c3..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: pipeline - -# Trigger when committing to main branch -on: - push: - branches: - - main - workflow_dispatch: # Allow manual triggering of the workflow - -jobs: - - # Intentionally NOT syncing from Cloud as all patches/updates etc being done manually on GitHub repo - - # Package and Deploy to Umbraco Cloud (without saving the artifact as contains sensitive data) - cloud-deployment: - name: "Deploy to Cloud" - uses: ./.github/workflows/package-and-deploy.yml - secrets: - projectId: ${{ secrets.PROJECT_ID }} - umbracoCloudApiKey: ${{ secrets.UMBRACO_CLOUD_API_KEY }} - umbracoCloudJson: ${{ secrets.UMBRACO_CLOUD_JSON }} - deployLicenseKey: ${{ secrets.DEPLOY_LICENSE_KEY }} - formsLicenseKey: ${{ secrets.FORMS_LICENSE_KEY }} - with: - pathToWebsite: "src/OpenSourceTest.Site" - csprojFile: "OpenSourceTest.Site.csproj" \ No newline at end of file diff --git a/.github/workflows/package-and-deploy.yml b/.github/workflows/package-and-deploy.yml deleted file mode 100644 index ab009de..0000000 --- a/.github/workflows/package-and-deploy.yml +++ /dev/null @@ -1,130 +0,0 @@ -name: Deploy To Cloud - -on: - workflow_call: - inputs: - pathToWebsite: - required: true - type: string - csprojFile: - required: true - type: string - - secrets: - projectId: - required: true - umbracoCloudApiKey: - required: true - umbracoCloudJson: - required: true - deployLicenseKey: - required: true - formsLicenseKey: - required: true - -jobs: - - # Do as one job as don't want save the 'real' deployment as an artifact (contains sensitive data) - prepAndDoDeployment: - name: Prep And Do Deployment - runs-on: ubuntu-latest - outputs: - runningDeploymentId: ${{ steps.deployment-meta.outputs.deploymentId }} - steps: - - uses: actions/checkout@v4 - - # Enable/disable package references in .csproj - - name: Update csproj - working-directory: ${{ inputs.pathToWebsite }} - shell: pwsh - run: | - $content = Get-Content '${{ inputs.csprojFile }}' -Raw - - # Enable Umbraco.Cloud.Cms (uncomment) - $content = $content -replace '(?s)', '' - - # Enable Umbraco.Deploy.Cloud (uncomment) - $content = $content -replace '(?s)', '' - - # Disable Umbraco.Deploy.OnPrem (comment out) - $content = $content -replace '(?s)]*/?>', '' - - Set-Content '${{ inputs.csprojFile }}' $content - - # Create umbraco-cloud.json file from Secret - - name: Umbraco Cloud Json - working-directory: ${{ inputs.pathToWebsite }} - shell: pwsh - run: set-content 'umbraco-cloud.json' -value '${{ secrets.umbracoCloudJson }}' - - # Create Deploy license key file from Secret - - name: Deploy License Key - working-directory: "${{ inputs.pathToWebsite }}/umbraco/Licenses" - shell: pwsh - run: set-content 'umbracoDeploy.lic' -value '${{ secrets.deployLicenseKey }}' - - # Create Forms license key file from Secret - - name: Forms License Key - working-directory: "${{ inputs.pathToWebsite }}/umbraco/Licenses" - shell: pwsh - run: set-content 'umbracoForms.lic' -value '${{ secrets.formsLicenseKey }}' - - # switch the gitignore files so cloud does not ignore the build frontend assets - - name: Prepare Cloud Git Ignore - run: cp cloud.gitignore .gitignore - shell: bash - - # zip everything, except what is defined in the 'cloud.zipignore' - - name: Zip Source Code - run: zip -r sources.zip . -x@cloud.zipignore - shell: bash - - # Request to prepare a deployment - # - sets the commit message to be used in cloud - # - supplies you with a deploymentId to be used in the rest of the process - - name: Create Deployment Meta - id: deployment-meta - shell: pwsh - run: > - ${{GITHUB.WORKSPACE}}/.github/powershell/APIv1/New-Deployment.ps1 - -ProjectId ${{ secrets.projectId }} - -ApiKey ${{ secrets.umbracoCloudApiKey }} - -CommitMessage "Run number ${{github.run_number}}" - -PipelineVendor GITHUB - - # Upload your zip file - - name: Post Zip - shell: pwsh - run: > - ${{GITHUB.WORKSPACE}}/.github/powershell/APIv1/Add-DeploymentPackage.ps1 - -ProjectId ${{ secrets.projectId }} - -DeploymentId ${{ steps.deployment-meta.outputs.deploymentId }} - -ApiKey ${{ secrets.umbracoCloudApiKey }} - -FilePath sources.zip - - # Request to start the deployment process in cloud - - name: Request Start Deployment - shell: pwsh - run: > - ${{GITHUB.WORKSPACE}}/.github/powershell/APIv1/Start-Deployment.ps1 - -ProjectId ${{ secrets.projectId }} - -DeploymentId ${{ steps.deployment-meta.outputs.deploymentId }} - -ApiKey ${{ secrets.umbracoCloudApiKey }} - - awaitDeploymentFinished: - name: Await deployment to finish - runs-on: ubuntu-latest - needs: prepAndDoDeployment - steps: - - uses: actions/checkout@v4 - - # Poll until deployment finishes - - name: Wait for deployment completed - shell: pwsh - env: - runningDeploymentId: ${{ needs.prepAndDoDeployment.outputs.runningDeploymentId }} - run: > - ${{GITHUB.WORKSPACE}}/.github/powershell/APIv1/Test-DeploymentStatus.ps1 - -ProjectId ${{ secrets.projectId }} - -DeploymentId ${{ env.runningDeploymentId }} - -ApiKey ${{ secrets.umbracoCloudApiKey }} diff --git a/.github/workflows/test-matt.yml b/.github/workflows/test-matt.yml deleted file mode 100644 index 26ad72b..0000000 --- a/.github/workflows/test-matt.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: test-matt - -# Trigger manually only -on: - workflow_dispatch: # Allow manual triggering of the workflow - -jobs: - - justCsproj: - name: Test csproj - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - # Enable/disable package references in .csproj - - name: Update csproj - working-directory: "src/OpenSourceTest.Site" - shell: pwsh - run: | - $content = Get-Content 'OpenSourceTest.Site.csproj' -Raw - - # Enable Umbraco.Cloud.Cms (uncomment) - $content = $content -replace '(?s)', '' - - # Enable Umbraco.Deploy.Cloud (uncomment) - $content = $content -replace '(?s)', '' - - # Disable Umbraco.Deploy.OnPrem (comment out) - $content = $content -replace '(?s)]*/?>', '' - - Set-Content 'OpenSourceTest.Site.csproj' $content - - echo $content \ No newline at end of file From 8fdaddcb06b6ca40531855d0ed011054be9a53ea Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Mon, 28 Jul 2025 16:48:10 +0100 Subject: [PATCH 04/23] Support running from v2 api branch --- .github/workflows/main-v2.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index 28f8849..2f63c06 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -5,6 +5,7 @@ on: push: branches: - main + - v2-api workflow_dispatch: # Allow manual triggering of the workflow jobs: From 241439e902f373ed10367cb31221db30ecb72fe6 Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Mon, 28 Jul 2025 16:50:17 +0100 Subject: [PATCH 05/23] Workflows must be in root workflows folder --- .github/workflows/{jobs => }/cloud-artifact.yml | 0 .github/workflows/{jobs => }/cloud-deployment.yml | 0 .github/workflows/{jobs => }/cloud-predeploy.yml | 0 .github/workflows/{jobs => }/cloud-sync.yml | 0 .github/workflows/main-v2.yml | 8 ++++---- 5 files changed, 4 insertions(+), 4 deletions(-) rename .github/workflows/{jobs => }/cloud-artifact.yml (100%) rename .github/workflows/{jobs => }/cloud-deployment.yml (100%) rename .github/workflows/{jobs => }/cloud-predeploy.yml (100%) rename .github/workflows/{jobs => }/cloud-sync.yml (100%) diff --git a/.github/workflows/jobs/cloud-artifact.yml b/.github/workflows/cloud-artifact.yml similarity index 100% rename from .github/workflows/jobs/cloud-artifact.yml rename to .github/workflows/cloud-artifact.yml diff --git a/.github/workflows/jobs/cloud-deployment.yml b/.github/workflows/cloud-deployment.yml similarity index 100% rename from .github/workflows/jobs/cloud-deployment.yml rename to .github/workflows/cloud-deployment.yml diff --git a/.github/workflows/jobs/cloud-predeploy.yml b/.github/workflows/cloud-predeploy.yml similarity index 100% rename from .github/workflows/jobs/cloud-predeploy.yml rename to .github/workflows/cloud-predeploy.yml diff --git a/.github/workflows/jobs/cloud-sync.yml b/.github/workflows/cloud-sync.yml similarity index 100% rename from .github/workflows/jobs/cloud-sync.yml rename to .github/workflows/cloud-sync.yml diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index 2f63c06..75dfce7 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -13,7 +13,7 @@ jobs: # Get changes from cloud # cloud-sync: # name: "Umbraco Cloud Sync" - # uses: ./.github/workflows/jobs/cloud-sync.yml + # uses: ./.github/workflows/cloud-sync.yml # secrets: # projectId: ${{ secrets.PROJECT_ID }} # umbracoCloudApiKey: ${{ secrets.UMBRACO_CLOUD_API_KEY }} @@ -23,7 +23,7 @@ jobs: # Prepare source code ready for deployment cloud-predeploy: name: "Prepare Source for Deployment" - uses: ./.github/workflows/jobs/cloud-predeploy.yml + uses: ./.github/workflows/cloud-predeploy.yml with: pathToWebsite: "src/OpenSourceTest.Site" csprojFile: "OpenSourceTest.Site.csproj" @@ -35,7 +35,7 @@ jobs: # Pack and upload the deployment Artifact cloud-artifact: name: "Prepare and Upload Artifact" - uses: ./.github/workflows/jobs/cloud-artifact.yml + uses: ./.github/workflows/cloud-artifact.yml needs: cloud-predeploy secrets: projectId: ${{ secrets.PROJECT_ID }} @@ -48,7 +48,7 @@ jobs: cloud-deployment: name: "Deploy to Cloud" needs: cloud-artifact - uses: ./.github/workflows/jobs/cloud-deployment.yml + uses: ./.github/workflows/cloud-deployment.yml with: artifactId: ${{ needs.cloud-artifact.outputs.artifactId }} targetEnvironmentAlias: ${{ vars.TARGET_ENVIRONMENT_ALIAS }} From 80db38a1a396fbd2ff47b698e88b7f1e3ccbadb0 Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Mon, 28 Jul 2025 16:51:30 +0100 Subject: [PATCH 06/23] Fixed error in yaml --- .github/workflows/cloud-predeploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cloud-predeploy.yml b/.github/workflows/cloud-predeploy.yml index 895c10a..e7b9577 100644 --- a/.github/workflows/cloud-predeploy.yml +++ b/.github/workflows/cloud-predeploy.yml @@ -18,7 +18,7 @@ on: formsLicenseKey: required: true -obs: +jobs: prepareForDeployment: name: Prepare Source for Deployment runs-on: ubuntu-latest From 21c00cfce8098885db71c169e37f1ad17f290613 Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Mon, 28 Jul 2025 17:08:33 +0100 Subject: [PATCH 07/23] Choose environment based on branch --- .github/workflows/main-v2.yml | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index 75dfce7..67452c2 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -1,14 +1,26 @@ -name: pipeline # You can add your own name for the pipeline here +name: pipeline -# Trigger when committing to main branch on: push: branches: - main - v2-api - workflow_dispatch: # Allow manual triggering of the workflow + workflow_dispatch: jobs: + set-env: + runs-on: ubuntu-latest + outputs: + targetEnv: ${{ steps.set-env-main.outputs.value || steps.set-env-staging.outputs.value }} + steps: + - name: Set ENV for main + id: set-env-main + if: github.ref == 'refs/heads/main' + run: echo "value=live" >> $GITHUB_OUTPUT + - name: Set ENV for v2-api + id: set-env-staging + if: github.ref == 'refs/heads/v2-api' + run: echo "value=stage" >> $GITHUB_OUTPUT # Get changes from cloud # cloud-sync: @@ -18,11 +30,12 @@ jobs: # projectId: ${{ secrets.PROJECT_ID }} # umbracoCloudApiKey: ${{ secrets.UMBRACO_CLOUD_API_KEY }} # with: - # targetEnvironmentAlias: ${{ vars.TARGET_ENVIRONMENT_ALIAS }} + # targetEnvironmentAlias: ${{ env.TARGET_ENVIRONMENT_ALIAS }} # Prepare source code ready for deployment cloud-predeploy: name: "Prepare Source for Deployment" + needs: set-env uses: ./.github/workflows/cloud-predeploy.yml with: pathToWebsite: "src/OpenSourceTest.Site" @@ -35,25 +48,20 @@ jobs: # Pack and upload the deployment Artifact cloud-artifact: name: "Prepare and Upload Artifact" - uses: ./.github/workflows/cloud-artifact.yml needs: cloud-predeploy + uses: ./.github/workflows/cloud-artifact.yml secrets: projectId: ${{ secrets.PROJECT_ID }} umbracoCloudApiKey: ${{ secrets.UMBRACO_CLOUD_API_KEY }} # Deploy to Umbraco Cloud - # #### - # you can edit the variables noBuildAndRestore and skipVersionCheck - # use 0 for false and 1 for true cloud-deployment: name: "Deploy to Cloud" - needs: cloud-artifact + needs: [set-env, cloud-artifact] uses: ./.github/workflows/cloud-deployment.yml with: artifactId: ${{ needs.cloud-artifact.outputs.artifactId }} - targetEnvironmentAlias: ${{ vars.TARGET_ENVIRONMENT_ALIAS }} - noBuildAndRestore: 0 - skipVersionCheck: 0 + targetEnvironmentAlias: ${{ needs.set-env.outputs.targetEnv }} secrets: projectId: ${{ secrets.PROJECT_ID }} umbracoCloudApiKey: ${{ secrets.UMBRACO_CLOUD_API_KEY }} \ No newline at end of file From d2808b2b6011a9d4f8839e422007cf68329b3b4a Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Mon, 28 Jul 2025 17:19:39 +0100 Subject: [PATCH 08/23] Give set-env a name --- .github/workflows/main-v2.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index 67452c2..7783e79 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -9,6 +9,7 @@ on: jobs: set-env: + name: "Set Target Environment from Branch" runs-on: ubuntu-latest outputs: targetEnv: ${{ steps.set-env-main.outputs.value || steps.set-env-staging.outputs.value }} From 051b1a5cdae115e4c908d158da690f5edb51131f Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Mon, 28 Jul 2025 17:34:45 +0100 Subject: [PATCH 09/23] Combine predeploy into artifact step --- .github/workflows/cloud-artifact.yml | 48 +++++++++++++++++++++ .github/workflows/cloud-predeploy.yml | 62 --------------------------- .github/workflows/main-v2.yml | 21 +++------ 3 files changed, 55 insertions(+), 76 deletions(-) delete mode 100644 .github/workflows/cloud-predeploy.yml diff --git a/.github/workflows/cloud-artifact.yml b/.github/workflows/cloud-artifact.yml index 7a92add..e33ec08 100644 --- a/.github/workflows/cloud-artifact.yml +++ b/.github/workflows/cloud-artifact.yml @@ -6,11 +6,23 @@ on: newSha: required: false type: string + pathToWebsite: + required: false + type: string + csprojFile: + required: false + type: string secrets: projectId: required: true umbracoCloudApiKey: required: true + umbracoCloudJson: + required: true + deployLicenseKey: + required: true + formsLicenseKey: + required: true outputs: artifactId: description: 'The Id of the uploaded artifact' @@ -27,6 +39,42 @@ jobs: with: ref: ${{ inputs.newSha }} + # Enable/disable package references in .csproj + - name: Update csproj + working-directory: ${{ inputs.pathToWebsite }} + shell: pwsh + run: | + $content = Get-Content '${{ inputs.csprojFile }}' -Raw + + # Enable Umbraco.Cloud.Cms (uncomment) + $content = $content -replace '(?s)', '' + + # Enable Umbraco.Deploy.Cloud (uncomment) + $content = $content -replace '(?s)', '' + + # Disable Umbraco.Deploy.OnPrem (comment out) + $content = $content -replace '(?s)]*Include="Umbraco\.Deploy\.OnPrem")(?=[^>]*Version="([^"]*)")[^>]*/?>', '' + + Set-Content '${{ inputs.csprojFile }}' $content + + # Create umbraco-cloud.json file from Secret + - name: Umbraco Cloud Json + working-directory: ${{ inputs.pathToWebsite }} + shell: pwsh + run: set-content 'umbraco-cloud.json' -value '${{ secrets.umbracoCloudJson }}' + + # Create Deploy license key file from Secret + - name: Deploy License Key + working-directory: "${{ inputs.pathToWebsite }}/umbraco/Licenses" + shell: pwsh + run: set-content 'umbracoDeploy.lic' -value '${{ secrets.deployLicenseKey }}' + + # Create Forms license key file from Secret + - name: Forms License Key + working-directory: "${{ inputs.pathToWebsite }}/umbraco/Licenses" + shell: pwsh + run: set-content 'umbracoForms.lic' -value '${{ secrets.formsLicenseKey }}' + # switch the gitignore files so cloud does not ignore the build frontend assets # zip everything, except what is defined in the 'cloud.zipignore' - name: Prepare Cloud Git Ignore and Zip Source Code diff --git a/.github/workflows/cloud-predeploy.yml b/.github/workflows/cloud-predeploy.yml deleted file mode 100644 index e7b9577..0000000 --- a/.github/workflows/cloud-predeploy.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Umbraco Cloud Preflight - -on: - workflow_call: - inputs: - pathToWebsite: - required: false - type: string - csprojFile: - required: false - type: string - - secrets: - umbracoCloudJson: - required: true - deployLicenseKey: - required: true - formsLicenseKey: - required: true - -jobs: - prepareForDeployment: - name: Prepare Source for Deployment - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - # Enable/disable package references in .csproj - - name: Update csproj - working-directory: ${{ inputs.pathToWebsite }} - shell: pwsh - run: | - $content = Get-Content '${{ inputs.csprojFile }}' -Raw - - # Enable Umbraco.Cloud.Cms (uncomment) - $content = $content -replace '(?s)', '' - - # Enable Umbraco.Deploy.Cloud (uncomment) - $content = $content -replace '(?s)', '' - - # Disable Umbraco.Deploy.OnPrem (comment out) - $content = $content -replace '(?s)]*Include="Umbraco\.Deploy\.OnPrem")(?=[^>]*Version="([^"]*)")[^>]*/?>', '' - - Set-Content '${{ inputs.csprojFile }}' $content - - # Create umbraco-cloud.json file from Secret - - name: Umbraco Cloud Json - working-directory: ${{ inputs.pathToWebsite }} - shell: pwsh - run: set-content 'umbraco-cloud.json' -value '${{ secrets.umbracoCloudJson }}' - - # Create Deploy license key file from Secret - - name: Deploy License Key - working-directory: "${{ inputs.pathToWebsite }}/umbraco/Licenses" - shell: pwsh - run: set-content 'umbracoDeploy.lic' -value '${{ secrets.deployLicenseKey }}' - - # Create Forms license key file from Secret - - name: Forms License Key - working-directory: "${{ inputs.pathToWebsite }}/umbraco/Licenses" - shell: pwsh - run: set-content 'umbracoForms.lic' -value '${{ secrets.formsLicenseKey }}' \ No newline at end of file diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index 7783e79..03c8767 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -33,27 +33,20 @@ jobs: # with: # targetEnvironmentAlias: ${{ env.TARGET_ENVIRONMENT_ALIAS }} - # Prepare source code ready for deployment - cloud-predeploy: - name: "Prepare Source for Deployment" - needs: set-env - uses: ./.github/workflows/cloud-predeploy.yml - with: - pathToWebsite: "src/OpenSourceTest.Site" - csprojFile: "OpenSourceTest.Site.csproj" - secrets: - umbracoCloudJson: ${{ secrets.UMBRACO_CLOUD_JSON }} - deployLicenseKey: ${{ secrets.DEPLOY_LICENSE_KEY }} - formsLicenseKey: ${{ secrets.FORMS_LICENSE_KEY }} - # Pack and upload the deployment Artifact cloud-artifact: name: "Prepare and Upload Artifact" - needs: cloud-predeploy + needs: [set-env] uses: ./.github/workflows/cloud-artifact.yml + with: + pathToWebsite: "src/OpenSourceTest.Site" + csprojFile: "OpenSourceTest.Site.csproj" secrets: projectId: ${{ secrets.PROJECT_ID }} umbracoCloudApiKey: ${{ secrets.UMBRACO_CLOUD_API_KEY }} + umbracoCloudJson: ${{ secrets.UMBRACO_CLOUD_JSON }} + deployLicenseKey: ${{ secrets.DEPLOY_LICENSE_KEY }} + formsLicenseKey: ${{ secrets.FORMS_LICENSE_KEY }} # Deploy to Umbraco Cloud cloud-deployment: From c93388baa686dc6dd398e41c9178e3148c18b2ae Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Mon, 28 Jul 2025 17:42:49 +0100 Subject: [PATCH 10/23] Force push --- .github/workflows/main-v2.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index 03c8767..f3568fd 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -5,7 +5,7 @@ on: branches: - main - v2-api - workflow_dispatch: + workflow_dispatch: jobs: set-env: From 787231f1a6255c77a3598a9ace447ca87802eead Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Mon, 28 Jul 2025 19:07:21 +0100 Subject: [PATCH 11/23] force push --- .github/workflows/main-v2.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index f3568fd..03c8767 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -5,7 +5,7 @@ on: branches: - main - v2-api - workflow_dispatch: + workflow_dispatch: jobs: set-env: From 55e8af7b562a9ccb6ec85703dda7d6889e2621ee Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Mon, 28 Jul 2025 19:20:41 +0100 Subject: [PATCH 12/23] Force deploy --- .github/workflows/main-v2.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index 03c8767..f3568fd 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -5,7 +5,7 @@ on: branches: - main - v2-api - workflow_dispatch: + workflow_dispatch: jobs: set-env: From 933097fcdfb235aa18efc7e253aa5fd0897a1483 Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Mon, 28 Jul 2025 19:30:02 +0100 Subject: [PATCH 13/23] Force some file changes --- src/OpenSourceTest.Site/Views/master.cshtml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/OpenSourceTest.Site/Views/master.cshtml b/src/OpenSourceTest.Site/Views/master.cshtml index 0418616..55d128a 100644 --- a/src/OpenSourceTest.Site/Views/master.cshtml +++ b/src/OpenSourceTest.Site/Views/master.cshtml @@ -10,6 +10,7 @@ @RenderBody() - +
+ From f1cf02bf4ed947743f867285a92f8a3cfe89532e Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Mon, 28 Jul 2025 19:41:01 +0100 Subject: [PATCH 14/23] Don't copy umbraco cloud json --- .github/workflows/cloud-artifact.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cloud-artifact.yml b/.github/workflows/cloud-artifact.yml index e33ec08..7d48453 100644 --- a/.github/workflows/cloud-artifact.yml +++ b/.github/workflows/cloud-artifact.yml @@ -58,10 +58,10 @@ jobs: Set-Content '${{ inputs.csprojFile }}' $content # Create umbraco-cloud.json file from Secret - - name: Umbraco Cloud Json - working-directory: ${{ inputs.pathToWebsite }} - shell: pwsh - run: set-content 'umbraco-cloud.json' -value '${{ secrets.umbracoCloudJson }}' + # - name: Umbraco Cloud Json + # working-directory: ${{ inputs.pathToWebsite }} + # shell: pwsh + # run: set-content 'umbraco-cloud.json' -value '${{ secrets.umbracoCloudJson }}' # Create Deploy license key file from Secret - name: Deploy License Key From 3186e6934bb8bc4c70672db20b3ea3c3e4285356 Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Mon, 28 Jul 2025 19:47:55 +0100 Subject: [PATCH 15/23] Add umbraco cloud json back in --- .github/workflows/cloud-artifact.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cloud-artifact.yml b/.github/workflows/cloud-artifact.yml index 7d48453..e33ec08 100644 --- a/.github/workflows/cloud-artifact.yml +++ b/.github/workflows/cloud-artifact.yml @@ -58,10 +58,10 @@ jobs: Set-Content '${{ inputs.csprojFile }}' $content # Create umbraco-cloud.json file from Secret - # - name: Umbraco Cloud Json - # working-directory: ${{ inputs.pathToWebsite }} - # shell: pwsh - # run: set-content 'umbraco-cloud.json' -value '${{ secrets.umbracoCloudJson }}' + - name: Umbraco Cloud Json + working-directory: ${{ inputs.pathToWebsite }} + shell: pwsh + run: set-content 'umbraco-cloud.json' -value '${{ secrets.umbracoCloudJson }}' # Create Deploy license key file from Secret - name: Deploy License Key From 4b77d69296b120d8dac1bcf0917d28a52564f72a Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Tue, 29 Jul 2025 17:00:54 +0100 Subject: [PATCH 16/23] Update script to run following desired process --- .github/workflows/main-v2.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index f3568fd..751cd64 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -5,6 +5,8 @@ on: branches: - main - v2-api + tags: + - live workflow_dispatch: jobs: @@ -12,15 +14,15 @@ jobs: name: "Set Target Environment from Branch" runs-on: ubuntu-latest outputs: - targetEnv: ${{ steps.set-env-main.outputs.value || steps.set-env-staging.outputs.value }} + targetEnv: ${{ steps.set-env-live.outputs.value || steps.set-env-stage.outputs.value }} steps: - - name: Set ENV for main - id: set-env-main - if: github.ref == 'refs/heads/main' + - name: Set ENV for live tag + id: set-env-live + if: startsWith(github.ref, 'refs/tags/live') run: echo "value=live" >> $GITHUB_OUTPUT - - name: Set ENV for v2-api - id: set-env-staging - if: github.ref == 'refs/heads/v2-api' + - name: Set ENV for all other occasions (default to stage) + id: set-env-stage + if: ${{ !startsWith(github.ref, 'refs/tags/live') }} run: echo "value=stage" >> $GITHUB_OUTPUT # Get changes from cloud From 8e1c43268394d624fdd331485386760531d2c320 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 30 Jul 2025 11:01:25 +0200 Subject: [PATCH 17/23] Apply changes for building frontend files --- .github/workflows/cloud-artifact.yml | 20 ++++++++++++++++++-- .github/workflows/main-v2.yml | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cloud-artifact.yml b/.github/workflows/cloud-artifact.yml index e33ec08..cadddae 100644 --- a/.github/workflows/cloud-artifact.yml +++ b/.github/workflows/cloud-artifact.yml @@ -76,11 +76,27 @@ jobs: run: set-content 'umbracoForms.lic' -value '${{ secrets.formsLicenseKey }}' # switch the gitignore files so cloud does not ignore the build frontend assets + - name: Prepare Cloud Git Ignore + run: cp cloud.gitignore .gitignore + shell: bash + + # Setup Node.js for frontend build + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.x' + cache: 'npm' + cache-dependency-path: '${{ inputs.pathToFrontendClient }}/package-lock.json' + + # build the frontend assets + - name: Build frontend assets + working-directory: ${{ inputs.pathToFrontendClient }} + run: npm ci && npm run build --if-present + shell: bash + # zip everything, except what is defined in the 'cloud.zipignore' - name: Prepare Cloud Git Ignore and Zip Source Code run: | - echo "switching .gitignore with cloud.gitignore" - cp cloud.gitignore .gitignore echo "Packing artifact for upload" zip -r sources.zip . -x@cloud.zipignore shell: bash diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index 751cd64..85f24a4 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -43,6 +43,7 @@ jobs: with: pathToWebsite: "src/OpenSourceTest.Site" csprojFile: "OpenSourceTest.Site.csproj" + pathToFrontendClient: "src/OpenSourceTest.MyExtension/Client" secrets: projectId: ${{ secrets.PROJECT_ID }} umbracoCloudApiKey: ${{ secrets.UMBRACO_CLOUD_API_KEY }} From 42dbf0eb895a8d9725d17b7e3559e47b9405ab98 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 30 Jul 2025 11:02:37 +0200 Subject: [PATCH 18/23] Forgot to define new variable --- .github/workflows/cloud-artifact.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/cloud-artifact.yml b/.github/workflows/cloud-artifact.yml index cadddae..c034b0c 100644 --- a/.github/workflows/cloud-artifact.yml +++ b/.github/workflows/cloud-artifact.yml @@ -9,6 +9,9 @@ on: pathToWebsite: required: false type: string + pathToFrontendClient: + required: false + type: string csprojFile: required: false type: string From 87ae090fd5dd87bb100a76f2bdd7484fb614d738 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 30 Jul 2025 11:18:23 +0200 Subject: [PATCH 19/23] What if.. including that extra project is the problem? --- src/OpenSourceTest.Site/OpenSourceTest.Site.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenSourceTest.Site/OpenSourceTest.Site.csproj b/src/OpenSourceTest.Site/OpenSourceTest.Site.csproj index 69c7611..9688a29 100644 --- a/src/OpenSourceTest.Site/OpenSourceTest.Site.csproj +++ b/src/OpenSourceTest.Site/OpenSourceTest.Site.csproj @@ -20,7 +20,7 @@ - + From 0e491e06fd86b2bb1277ef5f6d59e514b28565a3 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 30 Jul 2025 11:27:03 +0200 Subject: [PATCH 20/23] Revert "What if.. including that extra project is the problem?" This reverts commit 87ae090fd5dd87bb100a76f2bdd7484fb614d738. --- src/OpenSourceTest.Site/OpenSourceTest.Site.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenSourceTest.Site/OpenSourceTest.Site.csproj b/src/OpenSourceTest.Site/OpenSourceTest.Site.csproj index 9688a29..69c7611 100644 --- a/src/OpenSourceTest.Site/OpenSourceTest.Site.csproj +++ b/src/OpenSourceTest.Site/OpenSourceTest.Site.csproj @@ -20,7 +20,7 @@ - + From 64de615169b6cf8708a9a19adc0ac8d113761b23 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 30 Jul 2025 11:29:35 +0200 Subject: [PATCH 21/23] Detect release and publish to live if one exists --- .github/workflows/main-v2.yml | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index 85f24a4..7afdf61 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -5,10 +5,28 @@ on: branches: - main - v2-api - tags: - - live + release: + types: [published] workflow_dispatch: +jobs: + set-env: + name: "Set Target Environment from Release or Branch" + runs-on: ubuntu-latest + outputs: + targetEnv: ${{ steps.set-env.outputs.environment }} + steps: + - name: Set environment based on trigger + id: set-env + run: | + if [ "${{ github.event_name }}" = "release" ]; then + echo "Release published - deploying to live" + echo "environment=live" >> $GITHUB_OUTPUT + else + echo "Push to main or manual trigger - deploying to stage" + echo "environment=stage" >> $GITHUB_OUTPUT + fi + jobs: set-env: name: "Set Target Environment from Branch" From 0e63a9eb3746cf11d9c8b00929e11685d87fe062 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 30 Jul 2025 11:32:07 +0200 Subject: [PATCH 22/23] forgot to remove duplicate set-env --- .github/workflows/main-v2.yml | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index 7afdf61..9a08e1b 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -27,32 +27,6 @@ jobs: echo "environment=stage" >> $GITHUB_OUTPUT fi -jobs: - set-env: - name: "Set Target Environment from Branch" - runs-on: ubuntu-latest - outputs: - targetEnv: ${{ steps.set-env-live.outputs.value || steps.set-env-stage.outputs.value }} - steps: - - name: Set ENV for live tag - id: set-env-live - if: startsWith(github.ref, 'refs/tags/live') - run: echo "value=live" >> $GITHUB_OUTPUT - - name: Set ENV for all other occasions (default to stage) - id: set-env-stage - if: ${{ !startsWith(github.ref, 'refs/tags/live') }} - run: echo "value=stage" >> $GITHUB_OUTPUT - - # Get changes from cloud - # cloud-sync: - # name: "Umbraco Cloud Sync" - # uses: ./.github/workflows/cloud-sync.yml - # secrets: - # projectId: ${{ secrets.PROJECT_ID }} - # umbracoCloudApiKey: ${{ secrets.UMBRACO_CLOUD_API_KEY }} - # with: - # targetEnvironmentAlias: ${{ env.TARGET_ENVIRONMENT_ALIAS }} - # Pack and upload the deployment Artifact cloud-artifact: name: "Prepare and Upload Artifact" From 6693041c79469dac26175a6f613c7a91de9c884b Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 30 Jul 2025 11:41:38 +0200 Subject: [PATCH 23/23] Clean up --- .github/workflows/cloud-artifact.yml | 10 +--------- .github/workflows/main-v2.yml | 1 - 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/workflows/cloud-artifact.yml b/.github/workflows/cloud-artifact.yml index c034b0c..bc97816 100644 --- a/.github/workflows/cloud-artifact.yml +++ b/.github/workflows/cloud-artifact.yml @@ -98,20 +98,12 @@ jobs: shell: bash # zip everything, except what is defined in the 'cloud.zipignore' - - name: Prepare Cloud Git Ignore and Zip Source Code + - name: Zip Source Code run: | echo "Packing artifact for upload" zip -r sources.zip . -x@cloud.zipignore shell: bash - # store artifact for easy debug if needed - # - name: Store artifact in pipeline - # uses: actions/upload-artifact@v4 - # with: - # name: source-artifact - # path: ${{GITHUB.WORKSPACE}}/sources.zip - # retention-days: 1 - # Upload your zipped artifact - name: Post Zipped Artifact id: upload-artifact diff --git a/.github/workflows/main-v2.yml b/.github/workflows/main-v2.yml index 9a08e1b..3b1a780 100644 --- a/.github/workflows/main-v2.yml +++ b/.github/workflows/main-v2.yml @@ -4,7 +4,6 @@ on: push: branches: - main - - v2-api release: types: [published] workflow_dispatch: