Skip to content

Create release

Create release #5

Workflow file for this run

name: Create release
# Workflow 2 of 2: runs build.yml for a fresh set of executables, renames
# them to their final release filenames, and publishes a new GitHub Release
# with each file uploaded as its own asset — same as every existing release,
# so Update.exe's per-file SHA256 check keeps working. Refuses to run if the
# tag already exists, so it can never overwrite a past release.
#
# Multi-line release notes don't fit well in the "Run workflow" web form
# (it's a single-line box); use the gh CLI for those, e.g.:
# gh workflow run release.yml -f version=v2.8 -f release_notes="$(cat notes.md)"
on:
workflow_dispatch:
inputs:
version:
description: "Tag/version to release, e.g. v2.8"
required: true
release_notes:
description: "Release notes (markdown, shown on the release page)"
required: true
prerelease:
description: "Mark as a pre-release"
type: boolean
required: false
default: false
permissions:
contents: write
jobs:
build:
uses: ./.github/workflows/build.yml
with:
version: ${{ inputs.version }}
release:
needs: build
# Self-hosted, same as build.yml's Linux leg. Needs `git` on PATH for the
# tag check below (actions/checkout itself can fall back to the REST API
# without it, but this job's own script can't).
runs-on: [self-hosted, Linux]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Refuse to overwrite an existing tag/release
run: |
if git rev-parse "refs/tags/${{ inputs.version }}" >/dev/null 2>&1; then
echo "::error::Tag ${{ inputs.version }} already exists. Refusing to overwrite an existing release."
exit 1
fi
- name: Download all build artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
pattern: "*-${{ inputs.version }}"
# find, not a hardcoded nested path: upload-artifact's exact internal
# layout for a single-file `path:` has shifted across versions, so this
# locates each binary by name inside its artifact folder instead of
# assuming where under it it landed. The Linux binaries also get
# renamed here: inside the artifact they're just "Text2Pen" etc. (see
# build.yml), but a release holds x86_64 and arm64 side by side, so
# the uploaded asset name has to disambiguate — matches
# backend/paths.py's release_asset_name(), which is what Update.py and
# Installer.py use to pick the right one back up.
- name: Lay out release assets with their final names
run: |
set -euo pipefail
mkdir -p release
copy_asset() {
local artifact_dir="artifacts/$1"
local src_filename="$2"
local dest_filename="$3"
local found
found=$(find "$artifact_dir" -type f -name "$src_filename" | head -n1)
if [ -z "$found" ]; then
echo "::error::Could not find $src_filename in $artifact_dir"
exit 1
fi
cp "$found" "release/$dest_filename"
}
for name in Text2Pen Update Installer; do
copy_asset "$name-windows-${{ inputs.version }}" "$name.exe" "$name.exe"
copy_asset "$name-linux-x86_64-${{ inputs.version }}" "$name" "$name-linux-x86_64"
copy_asset "$name-linux-arm64-${{ inputs.version }}" "$name" "$name-linux-arm64"
done
chmod +x release/*-linux-x86_64 release/*-linux-arm64
ls -la release/
- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.version }}
name: ${{ inputs.version }}
body: ${{ inputs.release_notes }}
prerelease: ${{ inputs.prerelease }}
files: release/*