Skip to content

Release

Release #81

Workflow file for this run

name: Release
on:
workflow_dispatch:
inputs:
run:
description: 'The Package workflow run to release'
required: true
dry-run:
description: 'If true, the workflow only indicates which artifacts would be uploaded'
required: true
type: boolean
default: true
workflow_call:
inputs:
dispatch:
description: "Marker to indicate that the workflow was dispatched via workflow_call"
type: string
required: false
default: "workflow_call"
dry-run:
description: 'If true, the workflow only indicates which artifacts would be uploaded'
required: true
type: boolean
default: true
concurrency: gateway-release
jobs:
preflight:
name: Preflight
runs-on: ubuntu-latest
outputs:
run: ${{ steps.get-run.outputs.run }}
version: ${{ steps.get-version.outputs.version }}
skip-publishing: ${{ steps.check-release.outputs.skip-publishing }}
steps:
## workflow_dispatch: The run_id is read from the inputs
## workflow_call: The run_id is the current run_id
- name: Get run
id: get-run
shell: pwsh
run: |
if ('${{ github.event.inputs.run }}') {
echo "run=${{ github.event.inputs.run }}" >> $Env:GITHUB_OUTPUT
} else {
echo "run=${{ github.run_id }}" >> $Env:GITHUB_OUTPUT
}
- name: Get dry run
id: get-dry-run
shell: pwsh
run: |
$DryRun = "false"
if ('${{ inputs.dry-run }}') {
$DryRun = "${{ inputs.dry-run }}"
}
if ([System.Convert]::ToBoolean($DryRun)) {
echo "::notice::This is a dry run; publishing will be skipped"
} else {
echo "::warning::This is not a dry run, release will be published!"
}
- name: Download version
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh run download ${{ steps.get-run.outputs.run }} -n version --repo $Env:GITHUB_REPOSITORY
- name: Get version
id: get-version
shell: pwsh
run: |
$Version = Get-Content VERSION -TotalCount 1
echo "version=$Version" >> $Env:GITHUB_OUTPUT
echo "::notice::Releasing artifacts for version $Version from run ${{ steps.get-run.outputs.run }}"
## If we already released this version to GitHub, publishing will be skipped
- name: Check GitHub releases
id: check-release
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
Set-PSDebug -Trace 1
$Output = (gh release list --repo $Env:GITHUB_REPOSITORY) | Out-String
$Releases = ( $Output -split '\r?\n' ).Trim()
$Versions = ForEach($Release in $Releases) {
$Version = ( $Release -Split '\s+' ).Trim()
$Version = $Version.TrimStart("v")
$Version[0]
}
$SkipPublishing = 'false'
if ($Versions -Contains "${{ steps.get-version.outputs.version }}") {
echo "::warning::GitHub already has a release version ${{ steps.get-version.outputs.version }}; publishing will be skipped"
$SkipPublishing = 'true'
}
echo "skip-publishing=$SkipPublishing" >> $Env:GITHUB_OUTPUT
container:
name: Container [${{ matrix.os }} ${{ matrix.base-image }}]
runs-on: ${{ matrix.runner }}
environment: publish-prod
needs: preflight
if: needs.preflight.outputs.skip-publishing == 'false' || ${{ inputs.dry-run }}
strategy:
fail-fast: false
matrix:
arch: [ x86_64 ]
os: [ linux ]
base-image: [ bookworm-slim ]
include:
- os: linux
runner: ubuntu-latest
steps:
- name: Download artifacts
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh run download ${{ needs.preflight.outputs.run }} -n webapp-client -n docker -n devolutions-gateway -n native-libs --repo $Env:GITHUB_REPOSITORY
## workflow_call: The same artifacts persist across the entire run, so the PowerShell/DevolutionsGateway directory will still exist from the CI workflow
- name: Manage artifacts
shell: pwsh
run: Remove-Item -Path (Join-Path devolutions-gateway PowerShell DevolutionsGateway) -Recurse -ErrorAction Ignore
- name: Prepare artifacts
id: prepare-artifacts
shell: pwsh
run: |
Set-PSDebug -Trace 1
$PkgDir = Join-Path docker $Env:RUNNER_OS # RUNNER_OS is camelcase
echo "package-path=$PkgDir" >> $Env:GITHUB_OUTPUT
Write-Host "PkgDir = $PkgDir"
Get-ChildItem -Path "$PkgDir"
$SourceFileName = "DevolutionsGateway_$($Env:RUNNER_OS)_${{ needs.preflight.outputs.version }}_${{ matrix.arch }}"
$TargetFileName = "devolutions-gateway"
Write-Host "SourceFileName = $SourceFileName"
Write-Host "TargetFileName = $TargetFileName"
$SourcePath = Get-ChildItem -Recurse -Filter $SourceFileName -File -Path devolutions-gateway
$TargetPath = Join-Path $PkgDir $TargetFileName
Write-Host "SourcePath = $SourcePath"
Write-Host "TargetPath = $TargetPath"
Copy-Item -Path $SourcePath -Destination $TargetPath
if ($Env:RUNNER_OS -eq "Linux") {
Invoke-Expression "chmod +x $TargetPath"
}
$XmfFileName = "libxmf.so"
$XmfSourcePath = Get-ChildItem -Recurse -Filter $XmfFileName -File -Path native-libs
$XmfTargetPath = Join-Path $PkgDir $XmfFileName
Write-Host "XmfSourcePath = $XmfSourcePath"
Write-Host "XmfTargetPath = $XmfTargetPath"
Copy-Item -Path $XmfSourcePath -Destination $XmfTargetPath
$WebAppArchive = Get-ChildItem -Recurse -Filter "devolutions_gateway_webapp_*.tar.gz" | Select-Object -First 1
$TargetPath = Join-Path $PkgDir "webapp" "client"
Write-Host "WebAppArchive = $WebAppArchive"
Write-Host "TargetPath = $TargetPath"
New-Item -ItemType Directory -Path $TargetPath
tar -xvzf $WebAppArchive.FullName -C $TargetPath --strip-components=1
$PowerShellArchive = Get-ChildItem -Recurse -Filter "DevolutionsGateway-ps-*.tar" | Select-Object -First 1
tar -xvf "$PowerShellArchive" -C "$PkgDir"
- name: Build container
id: build-container
shell: pwsh
working-directory: ${{ steps.prepare-artifacts.outputs.package-path }}
run: |
Set-PSDebug -Trace 1
$ImageName = "devolutions/devolutions-gateway:${{ needs.preflight.outputs.version }}-${{ matrix.base-image }}"
docker build -t "$ImageName" .
echo "image-name=$ImageName" >> $Env:GITHUB_OUTPUT
Get-ChildItem -Recurse
- name: Push container
shell: pwsh
working-directory: ${{ steps.prepare-artifacts.outputs.package-path }}
run: |
Set-PSDebug -Trace 1
echo ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} | docker login -u devolutionsbot --password-stdin
$DockerPushCmd = 'docker push ${{ steps.build-container.outputs.image-name }}'
Write-Host $DockerPushCmd
$DryRun = [System.Convert]::ToBoolean('${{ inputs.dry-run }}')
if (-Not $DryRun) {
Invoke-Expression $DockerPushCmd
}
github-release:
name: GitHub release
runs-on: ubuntu-latest
environment: publish-prod
needs: preflight
if: needs.preflight.outputs.skip-publishing == 'false' || ${{ inputs.dry-run }}
steps:
- name: Configure runner
run: cargo install parse-changelog
- name: Download artifacts
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh run download ${{ needs.preflight.outputs.run }} -n jetsocat -n devolutions-gateway -n devolutions-agent -n webapp-client -n changelog --repo $Env:GITHUB_REPOSITORY
- name: Manage artifacts
shell: pwsh
run: |
# workflow_call: The same artifacts persist across the entire run, so the PowerShell/DevolutionsGateway directory will still exist from the CI workflow
# FIXME: I suspect this line is no longer required.
Remove-Item -Path (Join-Path devolutions-gateway PowerShell DevolutionsGateway) -Recurse -ErrorAction Ignore
# Devolutions Agent on Linux does not have any useful feature yet, so we filter out the Linux artifacts.
Remove-Item -Path (Join-Path devolutions-agent linux) -Recurse -ErrorAction Ignore
# For the PowerShell module, only upload the nupkg.
Remove-Item -Path (Join-Path devolutions-gateway PowerShell DevolutionsGateway-ps-*.tar) -Recurse -ErrorAction Ignore
- name: Create GitHub release
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
Set-PSDebug -Trace 1
$Version = "${{ needs.preflight.outputs.version }}"
$HashPath = 'checksums'
$Files = Get-ChildItem -Recurse -File -Exclude 'CHANGELOG.md', '*.dll' | % { Get-FileHash -Algorithm SHA256 $_.FullName }
$Files | % { "$($_.Hash) $(Split-Path $_.Path -leaf)" } | Out-File -FilePath $HashPath -Append -Encoding ASCII
echo "::group::checksums"
Get-Content $HashPath
echo "::endgroup::"
$ChangesPath = 'changes'
parse-changelog $(Join-Path changelog CHANGELOG.md) $Version | Out-File -Encoding UTF8NoBOM $ChangesPath
echo "::group::changes"
Get-Content $ChangesPath
echo "::endgroup::"
$GhCmd = $(@('gh', 'release', 'create', "v$Version", "--repo", $Env:GITHUB_REPOSITORY, "--notes-file", $ChangesPath, $HashPath) + $Files.Path) -Join ' '
Write-Host $GhCmd
$DryRun = [System.Convert]::ToBoolean('${{ inputs.dry-run }}')
if (-Not $DryRun) {
Invoke-Expression $GhCmd
}
psgallery-release:
name: PowerShell release
runs-on: ubuntu-latest
environment: publish-prod
needs: preflight
if: needs.preflight.outputs.skip-publishing == 'false' || ${{ inputs.dry-run }}
steps:
- name: Download artifacts
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh run download ${{ needs.preflight.outputs.run }} -n devolutions-gateway --repo $Env:GITHUB_REPOSITORY
## workflow_call: The same artifacts persist across the entire run, so the PowerShell/DevolutionsGateway directory will still exist from the CI workflow
- name: Manage artifacts
shell: pwsh
run: Remove-Item -Path (Join-Path PowerShell DevolutionsGateway) -Recurse -ErrorAction Ignore
- name: Install PSResourceGet
shell: pwsh
run: |
Install-PSResource Microsoft.PowerShell.PSResourceGet -Scope CurrentUser -TrustRepository
- name: Publish PowerShell module
shell: pwsh
run: |
$Archive = Get-ChildItem -Recurse -Filter "*-ps-*.tar" -File
Write-Host "Archive = $Archive"
tar -xvf "$Archive" -C './PowerShell'
Get-ChildItem -Path "./PowerShell" -Recurse
$PublishCmd = @('Publish-PSResource', '-Repository', 'PSGallery', '-Path', (Join-Path PowerShell DevolutionsGateway), '-ApiKey', '${{ secrets.PS_GALLERY_NUGET_API_KEY }}')
$DryRun = [System.Convert]::ToBoolean('${{ inputs.dry-run }}')
if ($DryRun) {
$PublishCmd += '-WhatIf'
}
$PublishCmd = $PublishCmd -Join ' '
Write-Host "PublishCmd = $PublishCmd"
try {
Invoke-Expression $PublishCmd
} catch {
if ($_.Exception.Message -ilike "*cannot be published as the current version*is already available in the repository*") {
echo "::warning::PowerShell module not published; this version is already listed on PSGallery"
} else {
Write-Error $_
exit 1
}
}
onedrive-gateway:
name: OneDrive (Devolutions Gateway)
runs-on: ubuntu-latest
needs: preflight
if: needs.preflight.outputs.skip-publishing == 'false' || ${{ inputs.dry-run }}
environment: onedrive-upload # for OneDrive secrets
steps:
- name: Check out Devolutions/actions
uses: actions/checkout@v4
with:
repository: Devolutions/actions
ref: v1
token: ${{ secrets.DEVOLUTIONSBOT_TOKEN }}
path: ./.github/workflows
## Devolutions Toolbox is required for OneDrive uploading
- name: Install Devolutions Toolbox
uses: ./.github/workflows/toolbox-install
with:
github_token: ${{ secrets.DEVOLUTIONSBOT_TOKEN }}
- name: Download artifacts
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh run download ${{ needs.preflight.outputs.run }} -n devolutions-gateway --repo $Env:GITHUB_REPOSITORY
- name: Prepare upload
id: prepare
shell: pwsh
run: |
Set-PSDebug -Trace 1
$destinationFolder = "${{ runner.temp }}/artifacts"
$version="${{ needs.preflight.outputs.version }}"
# Note that ".0" is appended here (required by release tooling downstream)
$versionFull="$version.0"
echo "version=${versionFull}" >> $Env:GITHUB_OUTPUT
echo "files-to-upload=$destinationFolder" >> $Env:GITHUB_OUTPUT
New-Item -Path "$destinationFolder" -ItemType "directory"
Move-Item -Path "./windows/x86_64/DevolutionsGateway-x86_64-${version}.msi" -Destination "$destinationFolder/DevolutionsGateway-x86_64-${versionFull}.msi"
Move-Item -Path "./windows/x86_64/DevolutionsGateway_Windows_${version}_x86_64.pdb" -Destination "$destinationFolder/DevolutionsGateway-x86_64-${versionFull}.pdb"
Move-Item -Path "./linux/x86_64/devolutions-gateway_${version}-1_amd64.deb" -Destination "$destinationFolder/devolutions-gateway_${versionFull}_amd64.deb"
Move-Item -Path "./linux/x86_64/devolutions-gateway_${version}-1_x86_64.rpm" -Destination "$destinationFolder/devolutions-gateway_${versionFull}_x86_64.rpm"
- name: Upload to OneDrive
uses: ./.github/workflows/onedrive-upload
if: (needs.preflight.outputs.skip-publishing == 'false') && (inputs.dry-run == false)
with:
azure_client_id: ${{ secrets.ONEDRIVE_AUTOMATION_CLIENT_ID }}
azure_client_secret: ${{ secrets.ONEDRIVE_AUTOMATION_CLIENT_SECRET }}
conflict_behavior: fail
destination_path: /Gateway/${{ steps.prepare.outputs.version }}
remote: releases
source_path: ${{ steps.prepare.outputs.files-to-upload }}
onedrive-agent:
name: OneDrive (Devolutions Agent)
runs-on: ubuntu-latest
needs: preflight
if: needs.preflight.outputs.skip-publishing == 'false' || ${{ inputs.dry-run }}
environment: onedrive-upload # for OneDrive secrets
steps:
- name: Check out Devolutions/actions
uses: actions/checkout@v4
with:
repository: Devolutions/actions
ref: v1
token: ${{ secrets.DEVOLUTIONSBOT_TOKEN }}
path: ./.github/workflows
## Devolutions Toolbox is required for OneDrive uploading
- name: Install Devolutions Toolbox
uses: ./.github/workflows/toolbox-install
with:
github_token: ${{ secrets.DEVOLUTIONSBOT_TOKEN }}
- name: Download artifacts
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh run download ${{ needs.preflight.outputs.run }} -n devolutions-agent --repo $Env:GITHUB_REPOSITORY
- name: Prepare upload
id: prepare
shell: pwsh
run: |
Set-PSDebug -Trace 1
$destinationFolder = "${{ runner.temp }}/artifacts"
$version="${{ needs.preflight.outputs.version }}"
# Note that ".0" is appended here (required by release tooling downstream)
$versionFull="$version.0"
echo "version=${versionFull}" >> $Env:GITHUB_OUTPUT
echo "files-to-upload=$destinationFolder" >> $Env:GITHUB_OUTPUT
New-Item -Path "$destinationFolder" -ItemType "directory"
Move-Item -Path "./windows/x86_64/DevolutionsAgent-x86_64-${version}.msi" -Destination "$destinationFolder/DevolutionsAgent-x86_64-${versionFull}.msi"
Move-Item -Path "./windows/x86_64/DevolutionsAgent-x86_64-${version}.symbols.zip" -Destination "$destinationFolder/DevolutionsAgent-x86_64-${versionFull}.symbols.zip"
Move-Item -Path "./linux/x86_64/devolutions-agent_${version}-1_amd64.deb" -Destination "$destinationFolder/devolutions-agent_${versionFull}_amd64.deb"
Move-Item -Path "./linux/x86_64/devolutions-agent_${version}-1_x86_64.rpm" -Destination "$destinationFolder/devolutions-agent_${versionFull}_x86_64.rpm"
- name: Upload to OneDrive
uses: ./.github/workflows/onedrive-upload
if: (needs.preflight.outputs.skip-publishing == 'false') && (inputs.dry-run == false)
with:
azure_client_id: ${{ secrets.ONEDRIVE_AUTOMATION_CLIENT_ID }}
azure_client_secret: ${{ secrets.ONEDRIVE_AUTOMATION_CLIENT_SECRET }}
conflict_behavior: fail
destination_path: /Agent/${{ steps.prepare.outputs.version }}
remote: releases
source_path: ${{ steps.prepare.outputs.files-to-upload }}
remove-labels:
name: Remove release-required labels
runs-on: ubuntu-latest
if: needs.preflight.outputs.skip-publishing == 'false' || ${{ inputs.dry-run }}
needs:
- container
- github-release
- psgallery-release
- onedrive-gateway
- onedrive-agent
steps:
- name: Check out ${{ github.repository }}
uses: actions/checkout@v4
- name: Remove labels
shell: pwsh
env:
GITHUB_TOKEN: ${{ github.token }}
run: ./ci/remove-labels.ps1 -Label 'release-required'