name: Release on: push: tags: - 'v*' concurrency: group: release-${{ github.ref }} cancel-in-progress: false permissions: contents: write jobs: quality-gate: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: submodules: true - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: 1.3.5 - name: Cache dependencies uses: actions/cache@v4 with: path: | ~/.bun/install/cache node_modules key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }} restore-keys: | ${{ runner.os }}-bun- - name: Install dependencies run: bun install --frozen-lockfile - name: Test suite (source) run: bun run test:fast - name: Launcher smoke suite (source) run: bun run test:launcher:smoke:src - name: Upload launcher smoke artifacts (on failure) if: failure() uses: actions/upload-artifact@v4 with: name: launcher-smoke path: .tmp/launcher-smoke/** if-no-files-found: ignore - name: Build (bundle) run: bun run build - name: Dist smoke suite run: bun run test:smoke:dist build-linux: needs: [quality-gate] runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: submodules: true - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: 1.3.5 - name: Cache dependencies uses: actions/cache@v4 with: path: | ~/.bun/install/cache node_modules vendor/texthooker-ui/node_modules key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock', 'vendor/texthooker-ui/package.json') }} restore-keys: | ${{ runner.os }}-bun- - name: Install dependencies run: bun install --frozen-lockfile - name: Build texthooker-ui run: | cd vendor/texthooker-ui bun install bun run build - name: Build AppImage run: bun run build:appimage env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Build unversioned AppImage run: | shopt -s nullglob appimages=(release/SubMiner-*.AppImage) if [ "${#appimages[@]}" -eq 0 ]; then echo "No versioned AppImage found to create unversioned artifact." ls -la release exit 1 fi cp "${appimages[0]}" release/SubMiner.AppImage - name: Upload AppImage artifact uses: actions/upload-artifact@v4 with: name: appimage path: release/*.AppImage build-macos: needs: [quality-gate] runs-on: macos-latest steps: - name: Checkout uses: actions/checkout@v4 with: submodules: true - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: 1.3.5 - name: Cache dependencies uses: actions/cache@v4 with: path: | ~/.bun/install/cache node_modules vendor/texthooker-ui/node_modules key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock', 'vendor/texthooker-ui/package.json') }} restore-keys: | ${{ runner.os }}-bun- - name: Validate macOS signing/notarization secrets run: | missing=0 for name in CSC_LINK CSC_KEY_PASSWORD APPLE_ID APPLE_APP_SPECIFIC_PASSWORD APPLE_TEAM_ID; do if [ -z "${!name}" ]; then echo "Missing required secret: $name" missing=1 fi done if [ "$missing" -ne 0 ]; then echo "Set all required macOS signing/notarization secrets and rerun." exit 1 fi env: CSC_LINK: ${{ secrets.CSC_LINK }} CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - name: Install dependencies run: bun install --frozen-lockfile - name: Build texthooker-ui run: | cd vendor/texthooker-ui bun install bun run build - name: Build signed + notarized macOS artifacts run: bun run build:mac env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} CSC_LINK: ${{ secrets.CSC_LINK }} CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - name: Upload macOS artifacts uses: actions/upload-artifact@v4 with: name: macos path: | release/*.dmg release/*.zip release: needs: [build-linux, build-macos] runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Download AppImage uses: actions/download-artifact@v4 with: name: appimage path: release - name: Download macOS artifacts uses: actions/download-artifact@v4 with: name: macos path: release - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: 1.3.5 - name: Build Bun subminer wrapper run: make build-launcher - name: Verify Bun subminer wrapper run: dist/launcher/subminer --help >/dev/null - name: Enforce generated launcher workflow run: bash scripts/verify-generated-launcher.sh - name: Package optional assets bundle run: | tar -czf "release/subminer-assets.tar.gz" \ config.example.jsonc \ plugin/subminer.lua \ plugin/subminer.conf \ assets/themes/subminer.rasi - name: Generate checksums run: | shopt -s nullglob files=(release/*.AppImage release/*.dmg release/*.zip release/*.tar.gz dist/launcher/subminer) if [ "${#files[@]}" -eq 0 ]; then echo "No release artifacts found for checksum generation." exit 1 fi sha256sum "${files[@]}" > release/SHA256SUMS.txt - name: Get version from tag id: version run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - name: Generate changelog id: changelog run: | PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") if [ -n "$PREV_TAG" ]; then CHANGES=$(git log --pretty=format:"- %s" ${PREV_TAG}..HEAD) else COMMIT_COUNT=$(git rev-list --count HEAD) if [ "$COMMIT_COUNT" -gt 10 ]; then CHANGES=$(git log --pretty=format:"- %s" HEAD~10..HEAD) else CHANGES=$(git log --pretty=format:"- %s") fi fi echo "CHANGES<> $GITHUB_OUTPUT echo "$CHANGES" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT - name: Create Release uses: softprops/action-gh-release@v2 with: name: ${{ steps.version.outputs.VERSION }} body: | ## Changes ${{ steps.changelog.outputs.CHANGES }} ## Installation ### AppImage (Recommended) 1. Download the AppImage below 2. Make it executable: `chmod +x SubMiner.AppImage` 3. Run: `./SubMiner.AppImage` ### macOS 1. Download `subminer-*.dmg` 2. Open the DMG and drag `SubMiner.app` into `/Applications` 3. If needed, use the ZIP artifact as an alternative ### Manual Installation See the [README](https://github.com/${{ github.repository }}#installation) for manual installation instructions. ### Optional Assets (config example + mpv plugin + rofi theme) 1. Download `subminer-assets.tar.gz` 2. Extract and copy `config.example.jsonc` to `~/.config/SubMiner/config.jsonc` 3. Copy `plugin/subminer.lua` to `~/.config/mpv/scripts/` 4. Copy `plugin/subminer.conf` to `~/.config/mpv/script-opts/` 5. Copy `assets/themes/subminer.rasi` to: - Linux: `~/.local/share/SubMiner/themes/subminer.rasi` - macOS: `~/Library/Application Support/SubMiner/themes/subminer.rasi` Note: the `subminer` wrapper script uses Bun (`#!/usr/bin/env bun`), so `bun` must be installed and on `PATH`. files: | release/*.AppImage release/*.dmg release/*.zip release/*.tar.gz release/SHA256SUMS.txt dist/launcher/subminer draft: false prerelease: false