mirror of
https://github.com/doolijb/serene-pub.git
synced 2026-07-20 13:13:27 +00:00
329 lines
15 KiB
YAML
329 lines
15 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- "v*.*.*"
|
|
- "v*.*.*-dev"
|
|
- "v*.*.*-alpha"
|
|
- "v*.*.*-beta"
|
|
- "v*.*.*-pr-*"
|
|
- "v*.*.*-rc-*"
|
|
|
|
jobs:
|
|
build-and-release:
|
|
strategy:
|
|
matrix:
|
|
include:
|
|
- target: linux-x64
|
|
os: ubuntu-latest
|
|
# - target: linux-arm64
|
|
# os: ubuntu-latest
|
|
# NOTE: GitHub-hosted runners don't offer native
|
|
# linux-arm64 hardware, and there's no cross-compile
|
|
# setup here (no QEMU, no npm_config_arch/--target_arch
|
|
# overrides) — `npm install` on an x64 ubuntu-latest
|
|
# runner resolves x64-arch native optional deps (eg.
|
|
# sharp, a transitive dep of @huggingface/transformers,
|
|
# which src/lib/server/embedding/ actually imports) and
|
|
# bundles them into a zip labeled "linux-arm64",
|
|
# producing an artifact that's broken on real arm64
|
|
# hardware. Disabled until real cross-compilation is
|
|
# set up.
|
|
# - target: linux-ppc64
|
|
# os: ubuntu-latest
|
|
# NOTE: same cross-arch issue as linux-arm64 above.
|
|
# - target: linux-arm
|
|
# os: ubuntu-latest
|
|
# NOTE: Node.js does not provide armv7l builds
|
|
- target: macos-x64
|
|
# NOT macos-latest: GitHub's "-latest" label now points
|
|
# to Apple Silicon (macos-15, arm64) — building the
|
|
# x64 target there would resolve x64-labeled but
|
|
# actually-arm64 native optional deps (eg. sharp, a
|
|
# transitive dep of @huggingface/transformers) via
|
|
# npm's platform/arch-matching install logic, silently
|
|
# shipping an arm64 binary inside a "macos-x64" zip
|
|
# that would fail to load on real Intel Macs.
|
|
# NOT macos-latest-large either — that's a paid
|
|
# "larger runner" (GitHub Team/Enterprise only,
|
|
# triggered a billing requirement when tried).
|
|
# macos-15-intel is the plain, free-tier Intel runner
|
|
# that matches macos-latest's current OS version
|
|
# (macOS 15) — just x64 instead of arm64, no paid plan
|
|
# needed.
|
|
os: macos-15-intel
|
|
- target: macos-arm64
|
|
os: macos-latest
|
|
- target: windows-x64
|
|
os: windows-latest
|
|
# - target: windows-arm64
|
|
# os: windows-latest
|
|
# NOTE: same cross-arch native-dependency issue as
|
|
# linux-arm64 above — windows-latest is x64, and there's
|
|
# no cross-compile setup, so this would ship an x64
|
|
# sharp binary inside a "windows-arm64" zip. Disabled
|
|
# until real cross-compilation is set up.
|
|
runs-on: ${{ matrix.os }}
|
|
env:
|
|
NODE_OPTIONS: "--max-old-space-size=4096"
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Generate release title
|
|
id: release_title
|
|
shell: bash
|
|
run: |
|
|
TAG="${{ github.ref_name }}"
|
|
VERSION="${TAG#v}" # Remove 'v' prefix
|
|
|
|
# Extract base version and suffix
|
|
if [[ "$VERSION" =~ ^([0-9]+\.[0-9]+\.[0-9]+)(-(.+))?$ ]]; then
|
|
BASE_VERSION="${BASH_REMATCH[1]}"
|
|
SUFFIX="${BASH_REMATCH[3]}"
|
|
|
|
if [ -z "$SUFFIX" ]; then
|
|
# No suffix - formal release
|
|
TITLE="$BASE_VERSION Release"
|
|
IS_PRERELEASE="false"
|
|
RUN_TESTS="true"
|
|
elif [ "$SUFFIX" = "dev" ]; then
|
|
# Development release
|
|
TITLE="$BASE_VERSION Development Release"
|
|
IS_PRERELEASE="true"
|
|
RUN_TESTS="false"
|
|
elif [ "$SUFFIX" = "alpha" ]; then
|
|
# Alpha release
|
|
TITLE="$BASE_VERSION Alpha Release"
|
|
IS_PRERELEASE="true"
|
|
RUN_TESTS="true"
|
|
elif [ "$SUFFIX" = "beta" ]; then
|
|
# Beta release (not a pre-release)
|
|
TITLE="$BASE_VERSION Beta Release"
|
|
IS_PRERELEASE="false"
|
|
RUN_TESTS="true"
|
|
elif [[ "$SUFFIX" =~ ^pr-([0-9]+)$ ]]; then
|
|
# Pre-release build - these are the tag pattern currently
|
|
# shipped as real releases, so run the full test suite
|
|
# just like any other release.
|
|
PR_NUM="${BASH_REMATCH[1]}"
|
|
TITLE="$BASE_VERSION Pre-Release Build $PR_NUM"
|
|
IS_PRERELEASE="true"
|
|
RUN_TESTS="true"
|
|
elif [[ "$SUFFIX" =~ ^rc-([0-9]+)$ ]]; then
|
|
# Release candidate
|
|
RC_NUM="${BASH_REMATCH[1]}"
|
|
TITLE="$BASE_VERSION Release Candidate $RC_NUM"
|
|
IS_PRERELEASE="true"
|
|
RUN_TESTS="true"
|
|
else
|
|
# Unknown suffix
|
|
TITLE="$VERSION"
|
|
IS_PRERELEASE="true"
|
|
RUN_TESTS="false"
|
|
fi
|
|
else
|
|
# Invalid version format
|
|
TITLE="$VERSION"
|
|
IS_PRERELEASE="true"
|
|
RUN_TESTS="false"
|
|
fi
|
|
|
|
echo "title=$TITLE" >> $GITHUB_OUTPUT
|
|
echo "is_prerelease=$IS_PRERELEASE" >> $GITHUB_OUTPUT
|
|
echo "run_tests=$RUN_TESTS" >> $GITHUB_OUTPUT
|
|
echo "base_version=$BASE_VERSION" >> $GITHUB_OUTPUT
|
|
echo "Release Title: $TITLE"
|
|
echo "Is Pre-release: $IS_PRERELEASE"
|
|
echo "Run Tests: $RUN_TESTS"
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: "24"
|
|
|
|
- name: Install dependencies
|
|
shell: bash
|
|
run: |
|
|
node -e "const fs = require('fs'); try { fs.unlinkSync('package-lock.json'); } catch (e) { /* ignore */ }"
|
|
for i in 1 2 3; do npm install --fetch-retries=5 --fetch-retry-mintimeout=20000 --fetch-retry-maxtimeout=120000 && break || sleep 15; done
|
|
|
|
- name: Prepare SvelteKit
|
|
run: npx @sveltejs/kit sync
|
|
|
|
- name: Run typecheck
|
|
# Non-blocking: the codebase currently carries a large pre-existing
|
|
# type-error backlog (see project history) that predates this gate.
|
|
# Errors still surface in the log for visibility; revisit making
|
|
# this blocking again once the backlog is cleared.
|
|
continue-on-error: true
|
|
run: npm run check
|
|
|
|
- name: Run tests
|
|
if: steps.release_title.outputs.run_tests == 'true'
|
|
run: npm test
|
|
|
|
- name: Build app
|
|
run: npm run build
|
|
|
|
- name: Create platform-specific executables and icons
|
|
run: node scripts/create-executables.js
|
|
|
|
- name: Prepare production dependencies
|
|
shell: bash
|
|
run: |
|
|
# Install production dependencies
|
|
npm install --production
|
|
npm rebuild
|
|
|
|
# Clean node_modules with modclean, preserving license files
|
|
npx modclean --run --patterns="default:safe,default:caution,default:danger" --ignore="**/LICENSE,**/COPYING,**/NOTICE,**/README*,**/COPYRIGHT,**/AUTHORS,**/CONTRIBUTORS"
|
|
|
|
- name: Download Node.js runtime for target platform
|
|
shell: bash
|
|
run: |
|
|
echo "Downloading Node.js for ${{ matrix.target }}..."
|
|
mkdir -p temp-node
|
|
cd temp-node
|
|
|
|
case "${{ matrix.target }}" in
|
|
linux-x64)
|
|
NODE_URL="https://nodejs.org/dist/v24.18.0/node-v24.18.0-linux-x64.tar.xz"
|
|
curl -L -o node.tar.xz "$NODE_URL" || { echo "Failed to download"; exit 1; }
|
|
tar -xf node.tar.xz
|
|
cp node-v24.18.0-linux-x64/bin/node ../node
|
|
;;
|
|
linux-arm64)
|
|
NODE_URL="https://nodejs.org/dist/v24.18.0/node-v24.18.0-linux-arm64.tar.xz"
|
|
curl -L -o node.tar.xz "$NODE_URL" || { echo "Failed to download"; exit 1; }
|
|
tar -xf node.tar.xz
|
|
cp node-v24.18.0-linux-arm64/bin/node ../node
|
|
;;
|
|
linux-ppc64)
|
|
NODE_URL="https://nodejs.org/dist/v24.18.0/node-v24.18.0-linux-ppc64le.tar.xz"
|
|
curl -L -o node.tar.xz "$NODE_URL" || { echo "Failed to download"; exit 1; }
|
|
tar -xf node.tar.xz
|
|
cp node-v24.18.0-linux-ppc64le/bin/node ../node
|
|
;;
|
|
macos-x64)
|
|
NODE_URL="https://nodejs.org/dist/v24.18.0/node-v24.18.0-darwin-x64.tar.gz"
|
|
curl -L -o node.tar.gz "$NODE_URL" || { echo "Failed to download"; exit 1; }
|
|
tar -xzf node.tar.gz
|
|
cp node-v24.18.0-darwin-x64/bin/node ../node
|
|
;;
|
|
macos-arm64)
|
|
NODE_URL="https://nodejs.org/dist/v24.18.0/node-v24.18.0-darwin-arm64.tar.gz"
|
|
curl -L -o node.tar.gz "$NODE_URL" || { echo "Failed to download"; exit 1; }
|
|
tar -xzf node.tar.gz
|
|
cp node-v24.18.0-darwin-arm64/bin/node ../node
|
|
;;
|
|
windows-x64)
|
|
NODE_URL="https://nodejs.org/dist/v24.18.0/node-v24.18.0-win-x64.zip"
|
|
curl -L -o node.zip "$NODE_URL" || { echo "Failed to download"; exit 1; }
|
|
unzip -q node.zip
|
|
cp node-v24.18.0-win-x64/node.exe ../node.exe
|
|
;;
|
|
windows-arm64)
|
|
NODE_URL="https://nodejs.org/dist/v24.18.0/node-v24.18.0-win-arm64.zip"
|
|
curl -L -o node.zip "$NODE_URL" || { echo "Failed to download"; exit 1; }
|
|
unzip -q node.zip
|
|
cp node-v24.18.0-win-arm64/node.exe ../node.exe
|
|
;;
|
|
esac
|
|
|
|
cd ..
|
|
rm -rf temp-node
|
|
|
|
# Verify the Node.js binary was downloaded
|
|
if [[ "${{ matrix.target }}" == windows-* ]]; then
|
|
if [ ! -f "node.exe" ]; then
|
|
echo "ERROR: Failed to download node.exe"
|
|
exit 1
|
|
fi
|
|
echo "Downloaded node.exe ($(du -h node.exe | cut -f1))"
|
|
else
|
|
if [ ! -f "node" ]; then
|
|
echo "ERROR: Failed to download node binary"
|
|
exit 1
|
|
fi
|
|
chmod +x node
|
|
echo "Downloaded node binary ($(du -h node | cut -f1))"
|
|
fi
|
|
|
|
- name: Bundle for ${{ matrix.target }}
|
|
run: node scripts/bundle-dist.js ${{ matrix.target }}
|
|
|
|
- name: Create production environment example
|
|
shell: bash
|
|
run: |
|
|
cd dist
|
|
DIST_DIR=$(ls -d serene-pub-*-${{ matrix.target }} 2>/dev/null | head -1)
|
|
if [ -z "$DIST_DIR" ]; then
|
|
echo "Error: No directory found matching serene-pub-*-${{ matrix.target }}"
|
|
ls -la
|
|
exit 1
|
|
fi
|
|
cat > "$DIST_DIR/.env.example" << EOF
|
|
# Serene Pub ${{ steps.release_title.outputs.base_version }} - Production Configuration
|
|
# Copy this file to .env in the same directory to customize settings
|
|
|
|
# ===========================================
|
|
# APPLICATION DATA DIRECTORY
|
|
# ===========================================
|
|
# Override default data directory location
|
|
# Default: OS-appropriate directory (~/.local/share/SerenePub on Linux, %APPDATA%/SerenePub on Windows, ~/Library/Application Support/SerenePub on macOS)
|
|
# Example for custom location:
|
|
# SERENE_PUB_DATA_DIR=/path/to/custom/data
|
|
|
|
# ===========================================
|
|
# SERVER CONFIGURATION
|
|
# ===========================================
|
|
# WebSocket server port
|
|
# Default: 3001
|
|
# SOCKETS_PORT=3001
|
|
|
|
# HTTP server port (main application)
|
|
# Default: 3000
|
|
# PORT=3000
|
|
|
|
# Disable automatic browser opening
|
|
# Default: Opens browser automatically on startup
|
|
# Set to 1 to disable auto-open
|
|
# SERENE_AUTO_OPEN=1
|
|
EOF
|
|
|
|
- name: Zip dist directory (Windows)
|
|
if: runner.os == 'Windows'
|
|
shell: pwsh
|
|
run: |
|
|
cd dist
|
|
$distDir = Get-ChildItem -Directory -Name "serene-pub-*-${{ matrix.target }}" | Select-Object -First 1
|
|
if (-not $distDir) {
|
|
Write-Error "No directory found matching serene-pub-*-${{ matrix.target }}"
|
|
Get-ChildItem
|
|
exit 1
|
|
}
|
|
Compress-Archive -Path $distDir -DestinationPath "../serene-pub-${{ github.ref_name }}-${{ matrix.target }}.zip"
|
|
|
|
- name: Zip dist directory (Unix)
|
|
if: runner.os != 'Windows'
|
|
shell: bash
|
|
run: |
|
|
cd dist
|
|
DIST_DIR=$(ls -d serene-pub-*-${{ matrix.target }} 2>/dev/null | head -1)
|
|
if [ -z "$DIST_DIR" ]; then
|
|
echo "Error: No directory found matching serene-pub-*-${{ matrix.target }}"
|
|
ls -la
|
|
exit 1
|
|
fi
|
|
zip -r "../serene-pub-${{ github.ref_name }}-${{ matrix.target }}.zip" "$DIST_DIR"
|
|
|
|
- name: Upload release assets
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
name: ${{ steps.release_title.outputs.title }}
|
|
files: serene-pub-*.zip
|
|
prerelease: ${{ steps.release_title.outputs.is_prerelease }}
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|