Skip to content

test(connection selection): Fix the test on developer machines #2493

test(connection selection): Fix the test on developer machines

test(connection selection): Fix the test on developer machines #2493

Workflow file for this run

name: Windows Installer
on:
release:
types: [published]
workflow_dispatch:
push:
paths:
- '**/*.py' # Watch for changes in any Python files
concurrency:
group: ci-${{github.workflow}}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build:
runs-on: 'windows-latest'
strategy:
matrix:
python-version: ['3.13']
outputs:
hashes: ${{ steps.hash.outputs.hashes }}
permissions:
contents: write
id-token: write
steps:
# step-security/harden-runner does not (yet) run on windows, so do not use it
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
# https://docs.astral.sh/uv/guides/integration/github/
- name: Install uv and set the python version
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
with:
python-version: ${{ matrix.python-version }}
activate-environment: true
- name: Install dependencies
run: |
uv pip install .[win_dist]
- name: Restore Inno Setup installer from cache
id: cache-innosetup
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: installer.exe
key: innosetup-6.5.4-exe
- name: Download Inno Setup installer
if: steps.cache-innosetup.outputs.cache-hit != 'true'
run: curl -L -o installer.exe http://files.jrsoftware.org/is/6/innosetup-6.5.4.exe
- name: Install Inno Setup
run: |
Start-Process -FilePath ./installer.exe -ArgumentList '/VERYSILENT','/ALLUSERS','/DIR=inst' -Wait -NoNewWindow
- name: Validate Inno Setup installation
run: |
if (-not (Test-Path "$env:GITHUB_WORKSPACE\inst\ISCC.exe")) {
Get-ChildItem inst -Recurse -ErrorAction SilentlyContinue | Format-List FullName, Length
throw 'Inno Setup compiler not found at inst\\ISCC.exe. Ensure the installer step completed successfully.'
}
- name: List installed software versions
run: |
python -m pip list
- name: Prepare installer
run: |
cd ardupilot_methodic_configurator
copy ..\\windows\\ardupilot_methodic_configurator.spec
pyinstaller --clean ardupilot_methodic_configurator.spec
del ardupilot_methodic_configurator.spec
- name: Write the git commit hash to file
run: |
$hash = git rev-parse HEAD
$hash = $hash.Trim()
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllText("git_hash.txt", $hash, $utf8NoBom)
- name: Verify git hash file
run: |
Write-Host "Git hash file content:"
$bytes = [System.IO.File]::ReadAllBytes("git_hash.txt")
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
Write-Host "::warning::File contains UTF-8 BOM"
} else {
Write-Host "File has no BOM (good)"
}
Get-Content -Raw git_hash.txt
- name: Debug GitHub token and permissions
run: |
Write-Host "Checking GitHub token and permissions"
# Don't print the actual token, just check if it exists
if ([string]::IsNullOrEmpty("${{ secrets.GITHUB_TOKEN }}")) {
Write-Host "::warning::GITHUB_TOKEN is empty or not accessible"
} else {
Write-Host "GITHUB_TOKEN is available"
}
# Check if running in fork (which may have limited permissions)
if ("${{ github.repository }}" -ne "${{ github.repository_owner }}/${{ github.event.repository.name }}") {
Write-Host "::warning::Running in a fork which may have limited permissions"
}
- name: Restore ChineseSimplified.isl from cache
id: cache-chinese-isl
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: ChineseSimplified.isl
key: chinese-simplified-isl-6.5
- name: Download ChineseSimplified.isl
if: steps.cache-chinese-isl.outputs.cache-hit != 'true'
run: |
curl -L -o ChineseSimplified.isl https://raw.githubusercontent.com/jrsoftware/issrc/refs/heads/main/Files/Languages/Unofficial/ChineseSimplified.isl
- name: Build installer
run: |
New-Item -ItemType Directory -Force -Path "inst\Languages"
Copy-Item "ChineseSimplified.isl" -Destination "inst\Languages\ChineseSimplified.isl"
cd windows
$env:VERSION=$(python return_version.py)
Start-Process -FilePath "..\inst\ISCC.exe" -ArgumentList "/dMyAppVersion=$env:VERSION", "ardupilot_methodic_configurator.iss" -Wait -NoNewWindow
Get-ChildItem Output
# https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md
- name: Generate hashes
id: hash
shell: bash
run: |
cd windows/Output
# Generate SHA256 hashes in the format expected by SLSA (sha256sum format)
sha256sum *.exe > checksums.txt
echo "hashes=$(cat checksums.txt | base64 -w0)" >> "$GITHUB_OUTPUT"
- name: Upload build artifacts
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: windows-installer
path: windows/Output/*.exe
retention-days: 7
# Generate SLSA provenance using the official generic workflow
# provenance:
# needs: [build]
# permissions:
# actions: read # To read the workflow path
# id-token: write # To sign the provenance
# contents: write # To add assets to a release
# uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@4876e96b8268fd8b7b8d8574718d06c0d0426d40 # latest commit
# with:
# base64-subjects: "${{ needs.build.outputs.hashes }}"
# upload-assets: ${{ startsWith(github.ref, 'refs/tags/v') }} # Only upload to releases for v* tags
# continue-on-error: false # Explicit error handling - fail fast for security issues
# Release job that depends on provenance generation
release:
# needs: [build, provenance]
needs: [build]
runs-on: windows-latest
if: startsWith(github.ref, 'refs/tags/v') || github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Download build artifacts
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: windows-installer
path: release-artifacts
- name: Rename installer for pre-release
if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
shell: pwsh
run: |
$files = Get-ChildItem release-artifacts\*.exe
foreach ($file in $files) {
$newName = $file.Name -replace '_setup_.*\.exe$', '_setup_latest_pre_release.exe'
Rename-Item $file.FullName $newName
Write-Host "Renamed $($file.Name) to $newName"
}
- name: Generate categorized release notes
id: release_notes
shell: pwsh
run: |
# Determine if this is a pre-release or stable release
$isPreRelease = "${{ github.ref }}" -eq "refs/heads/${{ github.event.repository.default_branch }}"
$isStableRelease = "${{ github.ref }}" -like "refs/tags/v*"
try {
if ($isPreRelease) {
# For pre-releases, compare against latest stable release
Write-Host "Fetching latest stable release..."
Write-Host "GitHub token available: $($env:GH_TOKEN -ne $null -and $env:GH_TOKEN -ne '')"
Write-Host "Repository: ${{ github.repository }}"
# Try multiple approaches to fetch releases
$releases = $null
# First try with gh CLI
try {
$releases = gh release list --repo "${{ github.repository }}" --limit 50 --json tagName,isPrerelease 2>$null
if ($LASTEXITCODE -ne 0) {
# Capture stderr for logging
$ghError = gh release list --repo "${{ github.repository }}" --limit 50 --json tagName,isPrerelease 1>$null 2>&1
Write-Host "gh CLI failed with exit code: $LASTEXITCODE"
Write-Host "gh CLI stderr: $ghError"
$releases = $null
}
}
catch {
Write-Host "gh CLI exception: $($_.Exception.Message)"
$releases = $null
}
# Fallback to REST API if gh CLI fails
if (-not $releases) {
Write-Host "Trying REST API fallback..."
try {
$releases = gh api "repos/${{ github.repository }}/releases?per_page=50" --jq '[.[] | {tagName: .tag_name, isPrerelease: .prerelease}]' | ConvertFrom-Json
}
catch {
Write-Host "REST API also failed: $($_.Exception.Message)"
}
}
if (-not $releases) {
Write-Host "All methods failed to fetch releases, using fallback"
$fallbackNotes = @"
**⚠️ This is an unstable development build. Use at your own risk!**
### Recent Changes:
Unable to fetch detailed change log. This build contains the latest development changes.
---
**Build Info:**
- Commit: [${{ github.sha }}](https://github.com/${{ github.repository }}/commit/${{ github.sha }})
- Build: #${{ github.run_number }}
- Date: $((Get-Date).ToUniversalTime().ToString('yyyy-MM-dd HH:mm:ss')) UTC
**Full Changelog**: https://github.com/${{ github.repository }}/commits/${{ github.event.repository.default_branch }}
"@
"notes<<EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
$fallbackNotes | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
return
}
$releaseList = $releases | ConvertFrom-Json
$latestStable = $releaseList | Where-Object { $_.tagName -like "v*" } | Select-Object -First 1
if ($latestStable -and $latestStable.tagName) {
$compareFrom = $latestStable.tagName
$releaseType = "pre-release"
$releaseWarning = "**⚠️ This is an unstable development build. Use at your own risk!**"
Write-Host "Pre-release: Comparing against latest stable release: $compareFrom"
} else {
$compareFrom = ""
Write-Host "No stable release found for comparison"
}
} elseif ($isStableRelease) {
# For stable releases, compare against previous stable release
Write-Host "Fetching previous releases..."
Write-Host "Repository: ${{ github.repository }}"
# Try multiple approaches to fetch releases
$releases = $null
# First try with gh CLI
try {
$releases = gh release list --repo "${{ github.repository }}" --limit 50 --json tagName 2>$null
if ($LASTEXITCODE -ne 0) {
$errorOutput = gh release list --repo "${{ github.repository }}" --limit 50 --json tagName 2>&1
Write-Host "gh CLI failed with exit code: $LASTEXITCODE"
Write-Host "gh CLI error output: $errorOutput"
$releases = $null
}
}
catch {
Write-Host "gh CLI exception: $($_.Exception.Message)"
$releases = $null
}
# Fallback to REST API if gh CLI fails
if (-not $releases) {
Write-Host "Trying REST API fallback..."
try {
$releases = gh api "repos/${{ github.repository }}/releases?per_page=50" --jq '[.[] | {tagName: .tag_name}]' | ConvertFrom-Json
}
catch {
Write-Host "REST API also failed: $($_.Exception.Message)"
}
}
if (-not $releases) {
Write-Host "All methods failed to fetch releases, using fallback"
$currentVersion = "${{ github.ref }}" -replace "refs/tags/", ""
$fallbackNotes = @"
## πŸŽ‰ Stable Release
### Release ${currentVersion}:
Unable to fetch detailed change log. Please refer to the commit history for changes.
---
**Release Info:**
- Version: ${currentVersion}
- Date: $((Get-Date).ToUniversalTime().ToString('yyyy-MM-dd HH:mm:ss')) UTC
**Full Changelog**: https://github.com/${{ github.repository }}/commits/${currentVersion}
"@
"notes<<EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
$fallbackNotes | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
return
}
$allReleases = $releases | ConvertFrom-Json
$currentTag = "${{ github.ref }}" -replace "refs/tags/", ""
$previousRelease = $allReleases | Where-Object { $_.tagName -ne $currentTag -and $_.tagName -like "v*" } | Select-Object -First 1
if ($previousRelease -and $previousRelease.tagName) {
$compareFrom = $previousRelease.tagName
$releaseType = "stable"
$releaseWarning = ""
Write-Host "Stable release: Comparing against previous release: $compareFrom"
} else {
$compareFrom = ""
Write-Host "No previous release found for comparison"
}
} else {
Write-Host "Neither pre-release nor stable release, skipping"
"notes<<EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
return
}
}
catch {
Write-Host "Error during release detection: $($_.Exception.Message). Using auto-generated notes."
"notes<<EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
return
}
if ($compareFrom) {
try {
# Get commits since comparison point with error handling
Write-Host "Fetching commits from $compareFrom to ${{ github.sha }}"
$commits = gh api "repos/${{ github.repository }}/compare/$compareFrom...${{ github.sha }}" --jq '.commits[] | {message: .commit.message, sha: .sha, author: .commit.author.name, url: .html_url}' 2>$null
if (-not $commits) {
Write-Host "No commits found or API call failed, falling back to auto-generated notes"
"notes<<EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
return
}
$commitList = $commits | ConvertFrom-Json
if (-not $commitList -or $commitList.Count -eq 0) {
Write-Host "No commits to process"
"notes<<EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
return
}
}
catch {
Write-Host "Error fetching commits: $($_.Exception.Message). Using auto-generated notes."
"notes<<EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
return
}
# Initialize grouped commits using ArrayList for better performance
$grouped = @{
'feat' = New-Object System.Collections.ArrayList
'fix' = New-Object System.Collections.ArrayList
'docs' = New-Object System.Collections.ArrayList
'style' = New-Object System.Collections.ArrayList
'refactor' = New-Object System.Collections.ArrayList
'perf' = New-Object System.Collections.ArrayList
'test' = New-Object System.Collections.ArrayList
'build' = New-Object System.Collections.ArrayList
'ci' = New-Object System.Collections.ArrayList
'chore' = New-Object System.Collections.ArrayList
'revert' = New-Object System.Collections.ArrayList
'other' = New-Object System.Collections.ArrayList
}
foreach ($commit in $commitList) {
# Input validation
if (-not $commit.message -or -not $commit.sha -or -not $commit.url) {
Write-Host "Skipping invalid commit object"
continue
}
$message = ($commit.message -split "`n" | Select-Object -First 1).Trim()
# Safe substring operation
$shortSha = if ($commit.sha.Length -ge 7) {
$commit.sha.Substring(0, 7)
} else {
$commit.sha
}
$commitUrl = $commit.url
# Sanitize message to prevent markdown injection
$sanitizedMessage = $message -replace '[<>&"]', '' -replace '\[', '\\[' -replace '\]', '\\]' -replace '`', '\\`'
# Parse conventional commit format
if ($sanitizedMessage -match '^(\w+)(\(.+\))?\s*!?\s*:\s*(.+)$') {
$type = $matches[1].ToLower()
$scope = if ($matches[2]) { ($matches[2] -replace '[()]', '') + ": " } else { "" }
$description = $matches[3].Trim()
# Limit description length (accounting for scope)
$maxLength = 100 - $scope.Length
if ($description.Length -gt $maxLength) {
if ($maxLength - 3 -gt 0) {
$description = $description.Substring(0, $maxLength - 3) + "..."
} else {
$description = "..."
}
}
$formattedDescription = $scope + $description
if ($grouped.ContainsKey($type)) {
$null = $grouped[$type].Add("- $formattedDescription ([$shortSha]($commitUrl))")
} else {
$null = $grouped['other'].Add("- $formattedDescription ([$shortSha]($commitUrl))")
}
} else {
# Non-conventional commit
$truncatedMessage = if ($sanitizedMessage.Length -gt 100) {
$sanitizedMessage.Substring(0, 97) + "..."
} else {
$sanitizedMessage
}
$null = $grouped['other'].Add("- $truncatedMessage ([$shortSha]($commitUrl))")
}
}
# Build categorized release notes
$sections = @()
# Define section mappings with emojis
$sectionMap = @{
'feat' = @{ title = 'πŸš€ New Features'; items = $grouped['feat'] }
'fix' = @{ title = 'πŸ› Bug Fixes'; items = $grouped['fix'] }
'docs' = @{ title = 'πŸ“š Documentation'; items = $grouped['docs'] }
'perf' = @{ title = '⚑ Performance'; items = $grouped['perf'] }
'refactor' = @{ title = '♻️ Code Refactoring'; items = $grouped['refactor'] }
'style' = @{ title = 'πŸ’Ž Style Changes'; items = $grouped['style'] }
'test' = @{ title = 'πŸ§ͺ Tests'; items = $grouped['test'] }
'build' = @{ title = 'πŸ“¦ Build System'; items = $grouped['build'] }
'ci' = @{ title = 'βš™οΈ CI/CD'; items = $grouped['ci'] }
'chore' = @{ title = 'πŸ”§ Maintenance'; items = $grouped['chore'] }
'revert' = @{ title = 'βͺ Reverts'; items = $grouped['revert'] }
'other' = @{ title = 'πŸ“‹ Other Changes'; items = $grouped['other'] }
}
# Process sections in a defined order for consistency
$orderedKeys = @('feat', 'fix', 'perf', 'refactor', 'docs', 'style', 'test', 'build', 'ci', 'chore', 'revert', 'other')
foreach ($key in $orderedKeys) {
if ($sectionMap.ContainsKey($key) -and $sectionMap[$key].items.Count -gt 0) {
$sections += ""
$sections += "### $($sectionMap[$key].title)"
$sections += ""
$sections += $sectionMap[$key].items.ToArray()
}
}
$changesSummary = if ($sections.Count -gt 0) { $sections -join "`n" } else { "No changes found." }
# Build release notes based on release type
if ($isPreRelease) {
$fullNotes = @"
${releaseWarning}
### Changes since last stable release (${compareFrom}):
${changesSummary}
---
**Build Info:**
- Commit: [${{ github.sha }}](https://github.com/${{ github.repository }}/commit/${{ github.sha }})
- Build: #${{ github.run_number }}
- Date: $((Get-Date).ToUniversalTime().ToString('yyyy-MM-dd HH:mm:ss')) UTC
**Full Changelog**: https://github.com/${{ github.repository }}/compare/${compareFrom}...${{ github.sha }}
"@
} else {
$currentVersion = "${{ github.ref }}" -replace "refs/tags/", ""
$fullNotes = @"
### Changes since previous release (${compareFrom}):
${changesSummary}
---
**Release Info:**
- Version: ${currentVersion}
- Date: $((Get-Date).ToUniversalTime().ToString('yyyy-MM-dd HH:mm:ss')) UTC
**Full Changelog**: https://github.com/${{ github.repository }}/compare/${compareFrom}...${currentVersion}
"@
}
# Output the notes for next step (properly handle multiline)
"notes<<EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
$fullNotes | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
} else {
Write-Host "No comparison point found, using auto-generated notes"
"notes<<EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Check for stable tags on current commit
id: check_tags
shell: pwsh
run: |
try {
$tags = gh api "repos/${{ github.repository }}/tags" --jq '[.[] | select(.name | startswith("v")) | select(.commit.sha == "${{ github.sha }}") | .name]'
$tagList = $tags | ConvertFrom-Json
if ($tagList -and $tagList.Count -gt 0) {
Write-Host "Found stable tags: $($tagList -join ', ')"
"has_stable_tag=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
} else {
Write-Host "No stable tags found on this commit"
"has_stable_tag=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
}
} catch {
Write-Host "Error checking tags: $($_.Exception.Message)"
"has_stable_tag=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Debug Pre Release Condition
shell: pwsh
run: |
$formatted = "refs/heads/${{ github.event.repository.default_branch }}"
Write-Host "github.ref == format('refs/heads/{{0}}', github.event.repository.default_branch):"
if ("${{ github.ref }}" -eq $formatted) { Write-Host 'true' } else { Write-Host 'false' }
Write-Host "steps.check_tags.outputs.has_stable_tag == 'false':"
if ("${{ steps.check_tags.outputs.has_stable_tag }}" -eq 'false') { Write-Host 'true' } else { Write-Host 'false' }
Write-Host "github.ref == 'refs/heads/master' && steps.check_tags.outputs.has_stable_tag == 'false':"
if (("${{ github.ref }}" -eq $formatted) -and ("${{ steps.check_tags.outputs.has_stable_tag }}" -eq 'false')) { Write-Host 'true' } else { Write-Host 'false' }
- name: Delete previous Pre Release
if: startsWith(github.ref, 'refs/tags/v') || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && steps.check_tags.outputs.has_stable_tag == 'false')
run: |
gh release delete latest-development-build --cleanup-tag
if ($LASTEXITCODE -eq 0) {
Write-Host "Successfully deleted previous release"
} else {
Write-Host "Release not found or failed to delete, continuing..."
}
$LASTEXITCODE = 0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Pre Release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && steps.check_tags.outputs.has_stable_tag == 'false'
with:
tag_name: "latest-development-build"
prerelease: true
name: "🚧 Development Build 🚧"
files: release-artifacts/*
body: ${{ steps.release_notes.outputs.notes || '' }}
generate_release_notes: ${{ steps.release_notes.outputs.notes == '' }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
if: startsWith(github.ref, 'refs/tags/v')
with:
prerelease: false
files: release-artifacts/*
body: ${{ steps.release_notes.outputs.notes || '' }}
generate_release_notes: ${{ steps.release_notes.outputs.notes == '' }}
token: ${{ secrets.GITHUB_TOKEN }}
make_latest: true