Skip to content

Release Build and Publish #4

Release Build and Publish

Release Build and Publish #4

Workflow file for this run

name: Release Build and Publish
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
version:
description: "Release version (e.g., v0.5.0)"
required: true
permissions:
contents: write
jobs:
build-release:
strategy:
fail-fast: false
matrix:
include:
- platform: "macos-latest"
args: ""
rust-target: "aarch64-apple-darwin"
sidecar-target: "aarch64-apple-darwin"
slug: "macos-aarch64"
- platform: "ubuntu-22.04"
args: ""
rust-target: "x86_64-unknown-linux-gnu"
sidecar-target: "x86_64-unknown-linux-gnu"
slug: "linux-x86_64"
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: frontend/package-lock.json
- name: Setup Rust
uses: moonrepo/setup-rust@v1
with:
channel: stable
- name: Install dependencies (Ubuntu)
if: matrix.platform == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
file \
libxdo-dev \
libssl-dev \
libayatana-appindicator3-dev \
librsvg2-dev
- name: Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: "./backend -> target"
- name: Install frontend dependencies
working-directory: frontend
run: npm ci
- name: Build backend (linggen-server)
working-directory: backend
run: cargo build --release --bin linggen-server
- name: Build CLI (linggen)
working-directory: linggen-cli
run: cargo build --release
- name: Package CLI and server tarballs
run: |
mkdir -p dist
tar -C linggen-cli/target/release -czf dist/linggen-cli-${{ matrix.slug }}.tar.gz linggen
tar -C backend/target/release -czf dist/linggen-server-${{ matrix.slug }}.tar.gz linggen-server
- name: Setup Tauri sidecar
shell: bash
run: |
SIDECAR_NAME="linggen-server-${{ matrix.sidecar-target }}"
cp "backend/target/release/linggen-server" "frontend/src-tauri/${SIDECAR_NAME}"
chmod +x "frontend/src-tauri/${SIDECAR_NAME}"
echo "Sidecar created: ${SIDECAR_NAME}"
- name: Build Tauri app
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
with:
projectPath: frontend
args: ${{ matrix.args }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: linggen-${{ matrix.platform }}
path: |
frontend/src-tauri/target/*/release/bundle/dmg/*.dmg
frontend/src-tauri/target/*/release/bundle/dmg/*.dmg.tar.gz
frontend/src-tauri/target/*/release/bundle/dmg/*.dmg.tar.gz.sig
frontend/src-tauri/target/release/bundle/deb/*.deb
frontend/src-tauri/target/release/bundle/deb/*.deb.tar.gz
frontend/src-tauri/target/release/bundle/deb/*.deb.tar.gz.sig
frontend/src-tauri/target/release/bundle/appimage/*.AppImage
frontend/src-tauri/target/release/bundle/appimage/*.AppImage.tar.gz
frontend/src-tauri/target/release/bundle/appimage/*.AppImage.tar.gz.sig
dist/*.tar.gz
if-no-files-found: ignore
publish-to-releases-repo:
needs: build-release
runs-on: ubuntu-latest
steps:
- name: Checkout linggen repository
uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Get version
id: version
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
else
echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
fi
- name: List artifacts
run: |
echo "Downloaded artifacts:"
find artifacts -type f
- name: Generate manifests
run: |
set -euo pipefail
VERSION="${{ steps.version.outputs.version }}"
VERSION_NUM="${VERSION#v}"
BASE_URL="https://github.com/linggen/linggen-releases/releases/download/${VERSION}"
DMG=$(find artifacts -name "*.dmg" | head -n 1 || true)
DEB=$(find artifacts -name "*.deb" | head -n 1 || true)
CLI_MAC_ARM64=$(find artifacts -name "linggen-cli-macos-aarch64.tar.gz" | head -n 1 || true)
CLI_LINUX_X64=$(find artifacts -name "linggen-cli-linux-x86_64.tar.gz" | head -n 1 || true)
SRV_MAC_ARM64=$(find artifacts -name "linggen-server-macos-aarch64.tar.gz" | head -n 1 || true)
SRV_LINUX_X64=$(find artifacts -name "linggen-server-linux-x86_64.tar.gz" | head -n 1 || true)
# Validate required artifacts exist
if [ -z "$CLI_MAC_ARM64" ]; then
echo "Error: CLI macOS ARM64 artifact not found" >&2
exit 1
fi
if [ -z "$CLI_LINUX_X64" ]; then
echo "Error: CLI Linux x86_64 artifact not found" >&2
exit 1
fi
if [ -z "$SRV_MAC_ARM64" ]; then
echo "Error: Server macOS ARM64 artifact not found" >&2
exit 1
fi
if [ -z "$SRV_LINUX_X64" ]; then
echo "Error: Server Linux x86_64 artifact not found" >&2
exit 1
fi
DMG_BASENAME=$(basename "$DMG" 2>/dev/null || echo "")
DEB_BASENAME=$(basename "$DEB" 2>/dev/null || echo "")
CLI_MAC_ARM64_BASENAME=$(basename "$CLI_MAC_ARM64")
CLI_LINUX_X64_BASENAME=$(basename "$CLI_LINUX_X64")
SRV_MAC_ARM64_BASENAME=$(basename "$SRV_MAC_ARM64")
SRV_LINUX_X64_BASENAME=$(basename "$SRV_LINUX_X64")
# Generate latest.json only if DMG and DEB exist
if [ -n "$DMG_BASENAME" ] && [ -n "$DEB_BASENAME" ]; then
cat > latest.json << EOF
{
"version": "${VERSION_NUM}",
"notes": "See release notes at https://github.com/linggen/linggen-releases/releases/tag/${VERSION}",
"pub_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"platforms": {
"darwin-universal": {
"signature": "",
"url": "${BASE_URL}/${DMG_BASENAME}"
},
"linux-x86_64": {
"signature": "",
"url": "${BASE_URL}/${DEB_BASENAME}"
}
}
}
EOF
else
echo "Warning: DMG or DEB not found, skipping latest.json generation"
touch latest.json
fi
# Generate manifest.json with all artifacts
{
echo "{"
echo " \"version\": \"${VERSION_NUM}\","
echo " \"artifacts\": {"
echo " \"cli-macos-aarch64\": {\"url\": \"${BASE_URL}/${CLI_MAC_ARM64_BASENAME}\"},"
echo " \"cli-linux-x86_64\": {\"url\": \"${BASE_URL}/${CLI_LINUX_X64_BASENAME}\"},"
echo " \"server-macos-aarch64\": {\"url\": \"${BASE_URL}/${SRV_MAC_ARM64_BASENAME}\"},"
if [ -n "$DMG_BASENAME" ] || [ -n "$DEB_BASENAME" ]; then
echo " \"server-linux-x86_64\": {\"url\": \"${BASE_URL}/${SRV_LINUX_X64_BASENAME}\"},"
else
echo " \"server-linux-x86_64\": {\"url\": \"${BASE_URL}/${SRV_LINUX_X64_BASENAME}\"}"
fi
if [ -n "$DMG_BASENAME" ]; then
if [ -n "$DEB_BASENAME" ]; then
echo " \"app-macos-dmg\": {\"url\": \"${BASE_URL}/${DMG_BASENAME}\"},"
else
echo " \"app-macos-dmg\": {\"url\": \"${BASE_URL}/${DMG_BASENAME}\"}"
fi
fi
if [ -n "$DEB_BASENAME" ]; then
echo " \"app-linux-deb\": {\"url\": \"${BASE_URL}/${DEB_BASENAME}\"}"
fi
echo " }"
echo "}"
} > manifest.json
echo "Generated latest.json:"
cat latest.json
echo "Generated manifest.json:"
cat manifest.json
- name: Checkout linggen-releases repository
uses: actions/checkout@v4
with:
repository: linggen/linggen-releases
token: ${{ secrets.RELEASES_PAT }}
path: linggen-releases
- name: Create release in linggen-releases
env:
GH_TOKEN: ${{ secrets.RELEASES_PAT }}
run: |
set -euo pipefail
VERSION="${{ steps.version.outputs.version }}"
VERSION_NUM="${VERSION#v}"
cd linggen-releases
gh release create "${VERSION}" \
--title "Linggen ${VERSION}" \
--notes "Release ${VERSION} - See main repository for details" \
--draft
# Upload DMG, DEB, AppImage
find ../artifacts -name "*.dmg" -exec gh release upload "${VERSION}" {} \;
find ../artifacts -name "*.deb" -exec gh release upload "${VERSION}" {} \;
find ../artifacts -name "*.AppImage" -exec gh release upload "${VERSION}" {} \;
# Upload server tarballs
find ../artifacts -name "linggen-server-*.tar.gz" -exec gh release upload "${VERSION}" {} \;
# Upload CLI tarballs with base names, versioned names, and latest names
for cli_tarball in ../artifacts/linggen-cli-*.tar.gz; do
if [ -f "$cli_tarball" ]; then
basename_file=$(basename "$cli_tarball")
slug="${basename_file#linggen-cli-}"
slug="${slug%.tar.gz}"
# Upload with base name (linggen-cli-<slug>.tar.gz)
gh release upload "${VERSION}" "$cli_tarball"
# Create and upload versioned name (linggen-cli-<slug>-v<version>.tar.gz)
versioned_name="linggen-cli-${slug}-v${VERSION_NUM}.tar.gz"
cp "$cli_tarball" "/tmp/${versioned_name}"
gh release upload "${VERSION}" "/tmp/${versioned_name}"
# Create and upload latest name (linggen-cli-<slug>-latest.tar.gz)
# The latest release will serve these when using /releases/latest/download/
latest_name="linggen-cli-${slug}-latest.tar.gz"
cp "$cli_tarball" "/tmp/${latest_name}"
gh release upload "${VERSION}" "/tmp/${latest_name}"
fi
done
# Upload manifests
gh release upload "${VERSION}" ../latest.json ../manifest.json
gh release edit "${VERSION}" --draft=false
echo "Release ${VERSION} published successfully!"