Skip to content

feat: enhance release workflow with version tagging and signature upl… #7

feat: enhance release workflow with version tagging and signature upl…

feat: enhance release workflow with version tagging and signature upl… #7

Workflow file for this run

name: Release
on:
push:
tags:
- 'v*.*.*' # Trigger on version tags like v1.0.0
workflow_dispatch:
inputs:
version:
description: 'Version to release (e.g., 1.0.0)'
required: true
type: string
env:
CARGO_TERM_COLOR: always
jobs:
# Job to create or validate version tag
prepare-release:
runs-on: ubuntu-latest
permissions:
contents: write # Allow creating releases and pushing commits
pull-requests: write # Allow creating PRs
outputs:
version: ${{ steps.get_version.outputs.version }}
upload_url: ${{ steps.create_release.outputs.upload_url }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.PAT_TOKEN }}
- name: Get version from tag or input
id: get_version
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
VERSION="${{ github.event.inputs.version }}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "tag=v${VERSION}" >> $GITHUB_OUTPUT
else
VERSION=${GITHUB_REF#refs/tags/v}
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
fi
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Update version in all files
run: |
VERSION="${{ steps.get_version.outputs.version }}"
# Update package.json
cd apps/desktop
npm version $VERSION --no-git-tag-version --allow-same-version
# Update tauri.conf.json
sed -i "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" src-tauri/tauri.conf.json
# Update Cargo.toml
sed -i "s/^version = \".*\"/version = \"$VERSION\"/" src-tauri/Cargo.toml
# Update Cargo.lock
cd src-tauri
cargo update --package meet-scribe --precise $VERSION 2>/dev/null || cargo generate-lockfile
cd ../..
- name: Commit version bump
if: github.event_name == 'workflow_dispatch'
run: |
VERSION="${{ steps.get_version.outputs.version }}"
TAG="${{ steps.get_version.outputs.tag }}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Check if there are any changes to commit
if git diff --quiet apps/desktop/package.json apps/desktop/package-lock.json apps/desktop/src-tauri/tauri.conf.json apps/desktop/src-tauri/Cargo.toml apps/desktop/src-tauri/Cargo.lock; then
echo "No version changes detected, skipping commit"
else
# Commit version changes
git add apps/desktop/package.json apps/desktop/package-lock.json apps/desktop/src-tauri/tauri.conf.json apps/desktop/src-tauri/Cargo.toml apps/desktop/src-tauri/Cargo.lock
git commit -m "chore: bump version to ${VERSION}"
git push origin main
fi
# Create and push tag (only if it doesn't exist)
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "Tag $TAG already exists, skipping tag creation"
else
git tag "$TAG"
git push origin "$TAG"
fi
- name: Create GitHub Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
with:
tag_name: ${{ steps.get_version.outputs.tag }}
release_name: Release ${{ steps.get_version.outputs.tag }}
draft: false
prerelease: false
body: |
## Meet Scribe ${{ steps.get_version.outputs.version }}
### Downloads
- **Windows**: `meet-scribe_${{ steps.get_version.outputs.version }}_x64_en-US.msi`
- **Linux**: `meet-scribe_${{ steps.get_version.outputs.version }}_amd64.deb` or `meet-scribe_${{ steps.get_version.outputs.version }}_amd64.AppImage`
### Installation
**Windows:**
1. Download the `.msi` installer
2. Double-click to install
3. Follow the installation wizard
**Linux (Debian/Ubuntu):**
```bash
sudo dpkg -i meet-scribe_${{ steps.get_version.outputs.version }}_amd64.deb
```
**Linux (AppImage):**
```bash
chmod +x meet-scribe_${{ steps.get_version.outputs.version }}_amd64.AppImage
./meet-scribe_${{ steps.get_version.outputs.version }}_amd64.AppImage
```
### Changes
See [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md) for details.
# Build for Windows
build-windows:
needs: prepare-release
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ needs.prepare-release.outputs.tag || github.ref }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: apps/desktop/package-lock.json
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-pc-windows-msvc
- name: Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: apps/desktop/src-tauri
- name: Install dependencies
run: |
cd apps/desktop
npm ci
- name: Build frontend
run: |
cd apps/desktop
npm run build
- name: Build Tauri app
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
run: |
cd apps/desktop
npm run tauri build
- name: List build artifacts
run: |
cd apps/desktop/src-tauri/target/release/bundle
dir /s /b
- name: Upload Windows MSI
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
with:
upload_url: ${{ needs.prepare-release.outputs.upload_url }}
asset_path: apps/desktop/src-tauri/target/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi
asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi
asset_content_type: application/x-msi
- name: Upload Windows MSI Signature
if: hashFiles('apps/desktop/src-tauri/target/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi.sig') != ''
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
with:
upload_url: ${{ needs.prepare-release.outputs.upload_url }}
asset_path: apps/desktop/src-tauri/target/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi.sig
asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi.sig
asset_content_type: text/plain
- name: Save Windows signature as artifact
if: hashFiles('apps/desktop/src-tauri/target/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi.sig') != ''
uses: actions/upload-artifact@v4
with:
name: windows-sig
path: apps/desktop/src-tauri/target/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi.sig
retention-days: 1
- name: Upload Windows MSI (alternative path)
if: failure()
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
with:
upload_url: ${{ needs.prepare-release.outputs.upload_url }}
asset_path: apps/desktop/src-tauri/target/release/bundle/msi/Meet Scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi
asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi
asset_content_type: application/x-msi
# Build for Linux
build-linux:
needs: prepare-release
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ needs.prepare-release.outputs.tag || github.ref }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: apps/desktop/package-lock.json
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: apps/desktop/src-tauri
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
libssl-dev \
libgtk-3-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
libpulse-dev
- name: Install dependencies
run: |
cd apps/desktop
npm ci
- name: Build frontend
run: |
cd apps/desktop
npm run build
- name: Build Tauri app
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
run: |
cd apps/desktop
npm run tauri build
- name: List build artifacts
run: |
echo "Checking if bundle directory exists..."
if [ -d "apps/desktop/src-tauri/target/release/bundle" ]; then
echo "Bundle directory found, listing contents:"
cd apps/desktop/src-tauri/target/release/bundle
ls -lR
else
echo "Bundle directory not found! Listing target directory:"
ls -lR apps/desktop/src-tauri/target/ || echo "Target directory doesn't exist"
fi
- name: Upload Linux DEB
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
with:
upload_url: ${{ needs.prepare-release.outputs.upload_url }}
asset_path: apps/desktop/src-tauri/target/release/bundle/deb/meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.deb
asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.deb
asset_content_type: application/vnd.debian.binary-package
- name: Upload Linux AppImage
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
with:
upload_url: ${{ needs.prepare-release.outputs.upload_url }}
asset_path: apps/desktop/src-tauri/target/release/bundle/appimage/meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.AppImage
asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.AppImage
asset_content_type: application/octet-stream
- name: Upload Linux AppImage Signature
if: hashFiles('apps/desktop/src-tauri/target/release/bundle/appimage/meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.AppImage.sig') != ''
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
with:
upload_url: ${{ needs.prepare-release.outputs.upload_url }}
asset_path: apps/desktop/src-tauri/target/release/bundle/appimage/meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.AppImage.sig
asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.AppImage.sig
asset_content_type: text/plain
- name: Save Linux signature as artifact
if: hashFiles('apps/desktop/src-tauri/target/release/bundle/appimage/meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.AppImage.sig') != ''
uses: actions/upload-artifact@v4
with:
name: linux-sig
path: apps/desktop/src-tauri/target/release/bundle/appimage/meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.AppImage.sig
retention-days: 1
# Generate and upload updater manifest
create-updater-manifest:
needs: [prepare-release, build-windows, build-linux]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download Windows signature
uses: actions/download-artifact@v4
continue-on-error: true
with:
name: windows-sig
path: ./sigs
- name: Download Linux signature
uses: actions/download-artifact@v4
continue-on-error: true
with:
name: linux-sig
path: ./sigs
- name: Generate and upload latest.json
env:
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
run: |
VERSION="${{ needs.prepare-release.outputs.version }}"
TAG="${{ needs.prepare-release.outputs.tag }}"
REPO="${{ github.repository }}"
# Read signature files if they exist
WINDOWS_SIG=""
LINUX_SIG=""
if [ -f "./sigs/meet-scribe_${VERSION}_x64_en-US.msi.sig" ]; then
WINDOWS_SIG=$(cat "./sigs/meet-scribe_${VERSION}_x64_en-US.msi.sig")
echo "Found Windows signature"
else
echo "No Windows signature found (signing may not be configured)"
fi
if [ -f "./sigs/meet-scribe_${VERSION}_amd64.AppImage.sig" ]; then
LINUX_SIG=$(cat "./sigs/meet-scribe_${VERSION}_amd64.AppImage.sig")
echo "Found Linux signature"
else
echo "No Linux signature found (signing may not be configured)"
fi
# Create the updater manifest JSON
cat > latest.json << EOF
{
"version": "$TAG",
"notes": "See full release notes at https://github.com/$REPO/releases/tag/$TAG",
"pub_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"platforms": {
"windows-x86_64": {
"signature": "$WINDOWS_SIG",
"url": "https://github.com/$REPO/releases/download/$TAG/meet-scribe_${VERSION}_x64_en-US.msi"
},
"linux-x86_64": {
"signature": "$LINUX_SIG",
"url": "https://github.com/$REPO/releases/download/$TAG/meet-scribe_${VERSION}_amd64.AppImage"
}
}
}
EOF
echo "Generated latest.json:"
cat latest.json
# Upload to release
UPLOAD_URL="${{ needs.prepare-release.outputs.upload_url }}"
UPLOAD_URL="${UPLOAD_URL%\{*}" # Remove the {?name,label} template part
curl -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @latest.json \
"${UPLOAD_URL}?name=latest.json"