GitHub Release (Run ID: latest build) #6
This file contains hidden or 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: Publish GitHub Release | |
| run-name: "GitHub Release (Run ID: ${{ inputs.run_id || 'latest build' }})" | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| run_id: | |
| description: "Build workflow run ID (leave empty to use latest)" | |
| required: false | |
| type: string | |
| use_local_storage: | |
| description: "Use local artifact storage" | |
| required: false | |
| type: boolean | |
| default: true | |
| use_self_hosted_runners: | |
| description: "Use self-hosted runners" | |
| required: false | |
| type: boolean | |
| default: true | |
| workflow_call: | |
| inputs: | |
| run_id: | |
| description: "Build workflow run ID (leave empty to use latest)" | |
| required: false | |
| type: string | |
| use_local_storage: | |
| description: "Use local artifact storage" | |
| required: false | |
| type: boolean | |
| default: true | |
| use_self_hosted_runners: | |
| description: "Use self-hosted runners" | |
| required: false | |
| type: boolean | |
| default: true | |
| permissions: | |
| contents: write | |
| actions: read | |
| jobs: | |
| release: | |
| name: Create GitHub Release | |
| runs-on: ${{ inputs.use_self_hosted_runners && fromJson('["self-hosted","Linux"]') || fromJson('["ubuntu-latest"]') }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Generate GitHub App token | |
| id: app-token | |
| uses: actions/create-github-app-token@v3 | |
| with: | |
| client-id: ${{ secrets.BBB_CLIENT_ID }} | |
| private-key: ${{ secrets.BBB_PRIVATE_KEY }} | |
| - name: Validate local storage configuration | |
| uses: ./.github/actions/validate-local-storage | |
| with: | |
| use_local_storage: ${{ inputs.use_local_storage }} | |
| artifact_host: ${{ vars.ARTIFACT_HOST }} | |
| artifact_base_path: ${{ vars.ARTIFACT_BASE_PATH }} | |
| - name: Get Latest Build Run ID | |
| id: get-run-id | |
| uses: ./.github/actions/get-latest-build-run-id | |
| with: | |
| run_id: ${{ inputs.run_id }} | |
| github_token: ${{ github.token }} | |
| - name: Download Server Artifact | |
| uses: ./.github/actions/download-artifact | |
| with: | |
| name: Server | |
| path: ./server-publish | |
| github-token: ${{ github.token }} | |
| artifact-host: ${{ inputs.use_local_storage && vars.ARTIFACT_HOST || '' }} | |
| artifact-base-path: ${{ inputs.use_local_storage && vars.ARTIFACT_BASE_PATH || '' }} | |
| run-id: ${{ steps.get-run-id.outputs.run_id }} | |
| - name: Download docker-compose file | |
| uses: ./.github/actions/download-artifact | |
| with: | |
| name: DockerCompose | |
| path: ./docker-compose-download | |
| github-token: ${{ github.token }} | |
| artifact-host: ${{ inputs.use_local_storage && vars.ARTIFACT_HOST || '' }} | |
| artifact-base-path: ${{ inputs.use_local_storage && vars.ARTIFACT_BASE_PATH || '' }} | |
| run-id: ${{ steps.get-run-id.outputs.run_id }} | |
| - name: Verify Server Payload | |
| uses: ./.github/actions/verify-server-payload | |
| with: | |
| path: ./server-publish | |
| - name: Get Build Metadata | |
| id: metadata | |
| uses: ./.github/actions/get-build-metadata | |
| with: | |
| run-id: ${{ steps.get-run-id.outputs.run_id }} | |
| github-token: ${{ github.token }} | |
| artifact-host: ${{ inputs.use_local_storage && vars.ARTIFACT_HOST || '' }} | |
| artifact-base-path: ${{ inputs.use_local_storage && vars.ARTIFACT_BASE_PATH || '' }} | |
| # The build metadata lists the runtimes the build produced, so the archive set is | |
| # decided by the build rather than by whatever happens to be on disk. Only the | |
| # runtimes that have a release archive are zipped; the rest are reported and skipped. | |
| - name: Prepare Release Artifacts | |
| shell: pwsh | |
| env: | |
| SERVER_RIDS: ${{ steps.metadata.outputs.server_rids }} | |
| PRIMARY_RID: ${{ steps.metadata.outputs.primary_rid }} | |
| RELEASE_VERSION: ${{ steps.metadata.outputs.release_version }} | |
| PRERELEASE: ${{ steps.metadata.outputs.prerelease }} | |
| run: | | |
| $RidLabels = [ordered]@{ | |
| 'linux-x64' = 'linux-amd64' | |
| 'linux-arm64' = 'linux-arm64' | |
| 'win-x64' = 'win-x64' | |
| } | |
| $ArchiveCount = 0 | |
| $Archived = [System.Collections.Generic.List[string]]::new() | |
| foreach ($Rid in $env:SERVER_RIDS.Split(',')) { | |
| if (-not $RidLabels.Contains($Rid)) { | |
| Write-Host "No release archive for '$Rid'; skipping." | |
| continue | |
| } | |
| $RidDirectory = "./server-publish/$Rid" | |
| if (-not (Test-Path -PathType Container $RidDirectory)) { | |
| Write-Warning "'$RidDirectory' is missing from the Server artifact; skipping its archive." | |
| continue | |
| } | |
| $Label = $RidLabels[$Rid] | |
| $Archive = "server-$Label.zip" | |
| Remove-Item -Path $Archive -Force -ErrorAction SilentlyContinue | |
| # Zip from inside the runtime directory so the archive root is the payload root. | |
| Push-Location -Path $RidDirectory | |
| try { | |
| zip -qr "../../$Archive" . | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "zip failed for $Rid with exit code $LASTEXITCODE." | |
| } | |
| } | |
| finally { | |
| Pop-Location | |
| } | |
| $Archived.Add("- ``$Rid`` -> ``$Archive``") | |
| Write-Host "$Archive <- $Rid" | |
| $ArchiveCount++ | |
| } | |
| if ($ArchiveCount -eq 0) { | |
| throw "The Server artifact contains no payload for the runtimes in the build metadata ($env:SERVER_RIDS)." | |
| } | |
| # The primary runtime supplies the release notes and API schemas for the release. | |
| Copy-Item -Path "./server-publish/$env:PRIMARY_RID/ControlR.Web.Server_internal.json" -Destination . -Force | |
| Copy-Item -Path "./server-publish/$env:PRIMARY_RID/ControlR.Web.Server_v1.json" -Destination . -Force | |
| Copy-Item -Path "docker-compose-download/docker-compose.yml" -Destination . -Force | |
| Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "## Release Summary" | |
| Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "**Version:** v$env:RELEASE_VERSION" | |
| Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "**Server Runtimes:**" | |
| Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value $Archived | |
| Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "**Status:** Draft" | |
| Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "**Pre-release:** $env:PRERELEASE" | |
| Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" | |
| Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "⚠️ Release is in DRAFT mode - review and publish when ready" | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| name: v${{ steps.metadata.outputs.release_version }} Release | |
| tag_name: v${{ steps.metadata.outputs.release_version }} | |
| draft: true | |
| prerelease: ${{ steps.metadata.outputs.prerelease == 'true' }} | |
| generate_release_notes: false | |
| body_path: ./server-publish/${{ steps.metadata.outputs.primary_rid }}/wwwroot/downloads/release-notes.md | |
| files: | | |
| server-*.zip | |
| ControlR.Web.Server_internal.json | |
| ControlR.Web.Server_v1.json | |
| docker-compose.yml | |
| env: | |
| GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} | |
| - name: Archive Release Notes | |
| if: ${{ steps.metadata.outputs.prerelease == 'false' }} | |
| shell: pwsh | |
| env: | |
| PRIMARY_RID: ${{ steps.metadata.outputs.primary_rid }} | |
| RELEASE_VERSION: ${{ steps.metadata.outputs.release_version }} | |
| run: | | |
| Copy-Item -Path "./server-publish/$env:PRIMARY_RID/wwwroot/downloads/release-notes.md" ` | |
| -Destination ".release-notes/v$env:RELEASE_VERSION.md" -Force | |
| @' | |
| ## Breaking Changes | |
| None. | |
| ## Enhancements | |
| None. | |
| ## Fixes | |
| None. | |
| ## Removals | |
| None. | |
| ## Internal | |
| None. | |
| '@ | Set-Content -Path .release-notes/current.md -Encoding utf8 | |
| git config user.name "bitbound-bot[bot]" | |
| git config user.email "bitbound-bot[bot]@users.noreply.github.com" | |
| git add .release-notes/ | |
| $Changes = git status --porcelain -- .release-notes/ | |
| if (-not $Changes) { | |
| Write-Host "Release notes are already up to date; nothing to commit." | |
| } | |
| else { | |
| git commit -m "chore: archive release notes for v$env:RELEASE_VERSION" | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "Failed to commit the archived release notes." | |
| } | |
| git push "https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/${{ github.repository }}.git" | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "Failed to push the archived release notes." | |
| } | |
| } |