chore: bump to version 1.3.1 #76
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release App | |
| on: | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - 'packages/app/package.json' | |
| - 'packages/app/CHANGELOG.md' | |
| workflow_dispatch: | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: flo0806/dm-hero | |
| jobs: | |
| check: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| should_release: ${{ steps.check.outputs.should_release }} | |
| version: ${{ steps.version.outputs.version }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Get version | |
| id: version | |
| run: | | |
| VERSION=$(node -p "require('./packages/app/package.json').version") | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "App version: $VERSION" | |
| - name: Check if release exists | |
| id: check | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| # Check if tag already exists on remote | |
| if git ls-remote --tags origin | grep -q "refs/tags/v${VERSION}$"; then | |
| echo "Tag v${VERSION} already exists - skipping release" | |
| echo "should_release=false" >> $GITHUB_OUTPUT | |
| else | |
| echo "Tag v${VERSION} does not exist - will create release" | |
| echo "should_release=true" >> $GITHUB_OUTPUT | |
| fi | |
| build-docker-amd64: | |
| needs: check | |
| if: needs.check.outputs.should_release == 'true' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push Docker image (amd64) | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| push: true | |
| tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.check.outputs.version }}-amd64 | |
| cache-from: type=gha,scope=amd64 | |
| cache-to: type=gha,mode=max,scope=amd64 | |
| platforms: linux/amd64 | |
| provenance: false | |
| build-docker-arm64: | |
| needs: check | |
| if: needs.check.outputs.should_release == 'true' | |
| runs-on: ubuntu-24.04-arm | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push Docker image (arm64) | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| push: true | |
| tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.check.outputs.version }}-arm64 | |
| cache-from: type=gha,scope=arm64 | |
| cache-to: type=gha,mode=max,scope=arm64 | |
| platforms: linux/arm64 | |
| provenance: false | |
| create-docker-manifest: | |
| needs: [check, build-docker-amd64, build-docker-arm64] | |
| if: needs.check.outputs.should_release == 'true' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create and push multi-arch manifest | |
| run: | | |
| VERSION="${{ needs.check.outputs.version }}" | |
| IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" | |
| # Create manifest for version tag (--amend allows manifest lists as sources) | |
| docker manifest create --amend ${IMAGE}:${VERSION} \ | |
| ${IMAGE}:${VERSION}-amd64 \ | |
| ${IMAGE}:${VERSION}-arm64 | |
| docker manifest push ${IMAGE}:${VERSION} | |
| # Create manifest for latest tag | |
| docker manifest create --amend ${IMAGE}:latest \ | |
| ${IMAGE}:${VERSION}-amd64 \ | |
| ${IMAGE}:${VERSION}-arm64 | |
| docker manifest push ${IMAGE}:latest | |
| echo "✅ Multi-arch manifest pushed for ${IMAGE}:${VERSION} and ${IMAGE}:latest" | |
| build-electron-windows: | |
| needs: check | |
| if: needs.check.outputs.should_release == 'true' | |
| runs-on: windows-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10 | |
| - name: Install dependencies | |
| run: pnpm install | |
| - name: Build Nuxt | |
| run: pnpm --filter @dm-hero/app build | |
| - name: Rebuild better-sqlite3 for Electron | |
| run: pnpm --filter @dm-hero/app electron:rebuild | |
| - name: Build Electron app | |
| working-directory: packages/app | |
| run: pnpm exec electron-builder --win | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dm-hero-windows | |
| path: | | |
| packages/app/dist-electron/*.zip | |
| packages/app/dist-electron/*.exe | |
| packages/app/dist-electron/latest.yml | |
| if-no-files-found: warn | |
| build-electron-linux: | |
| needs: check | |
| if: needs.check.outputs.should_release == 'true' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10 | |
| - name: Install dependencies | |
| run: pnpm install | |
| - name: Build Nuxt | |
| run: pnpm --filter @dm-hero/app build | |
| - name: Rebuild better-sqlite3 for Electron | |
| run: pnpm --filter @dm-hero/app electron:rebuild | |
| - name: Build Electron app | |
| working-directory: packages/app | |
| run: pnpm exec electron-builder --linux | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dm-hero-linux | |
| path: | | |
| packages/app/dist-electron/*.AppImage | |
| packages/app/dist-electron/latest-linux.yml | |
| if-no-files-found: warn | |
| # ============================================================================ | |
| # MACOS BUILD (signed + notarized, both architectures) | |
| # ============================================================================ | |
| build-electron-macos: | |
| needs: check | |
| if: needs.check.outputs.should_release == 'true' | |
| runs-on: macos-latest | |
| permissions: | |
| contents: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| arch: [x64, arm64] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10 | |
| - name: Install dependencies | |
| run: pnpm install | |
| - name: Build Nuxt | |
| run: pnpm --filter @dm-hero/app build | |
| - name: Install and copy sharp binaries for ${{ matrix.arch }} | |
| run: | | |
| cd packages/app | |
| mkdir -p .output/server/node_modules/@img | |
| if [ "${{ matrix.arch }}" = "x64" ]; then | |
| echo "=== Cross-compiling for x64 on arm64 host ===" | |
| # Use npm to force-install x64 binaries (pnpm skips wrong-platform packages) | |
| npm pack @img/sharp-darwin-x64 --pack-destination /tmp | |
| npm pack @img/sharp-libvips-darwin-x64 --pack-destination /tmp | |
| # Extract directly to .output (npm pack creates img-<name>-<version>.tgz) | |
| mkdir -p .output/server/node_modules/@img/sharp-darwin-x64 | |
| mkdir -p .output/server/node_modules/@img/sharp-libvips-darwin-x64 | |
| tar -xzf /tmp/img-sharp-darwin-x64-*.tgz -C .output/server/node_modules/@img/sharp-darwin-x64 --strip-components=1 | |
| tar -xzf /tmp/img-sharp-libvips-darwin-x64-*.tgz -C .output/server/node_modules/@img/sharp-libvips-darwin-x64 --strip-components=1 | |
| else | |
| echo "=== Native arm64 build ===" | |
| # For arm64, packages are already installed by pnpm - just copy them | |
| for pkg in sharp-darwin-arm64 sharp-libvips-darwin-arm64; do | |
| src=$(find ../../node_modules/.pnpm -type d -name "$pkg" -path "*/@img/$pkg" 2>/dev/null | head -1) | |
| if [ -n "$src" ] && [ -d "$src" ]; then | |
| echo "Copying $pkg from $src" | |
| cp -r "$src" .output/server/node_modules/@img/ | |
| else | |
| echo "Warning: $pkg not found in pnpm store" | |
| fi | |
| done | |
| fi | |
| echo "=== @img contents ===" | |
| ls -la .output/server/node_modules/@img/ | |
| - name: Rebuild better-sqlite3 for Electron (${{ matrix.arch }}) | |
| run: | | |
| cd packages/app | |
| npm_config_arch=${{ matrix.arch }} node scripts/electron-rebuild.js | |
| env: | |
| npm_config_arch: ${{ matrix.arch }} | |
| - name: Build Electron app (Signed + Notarized) | |
| working-directory: packages/app | |
| run: pnpm exec electron-builder --mac --${{ matrix.arch }} | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }} | |
| CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| - name: Rename latest-mac.yml with arch suffix | |
| run: | | |
| cd packages/app/dist-electron | |
| if [ -f "latest-mac.yml" ]; then | |
| mv latest-mac.yml latest-mac-${{ matrix.arch }}.yml | |
| echo "Renamed to latest-mac-${{ matrix.arch }}.yml" | |
| cat latest-mac-${{ matrix.arch }}.yml | |
| fi | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dm-hero-macos-${{ matrix.arch }} | |
| path: | | |
| packages/app/dist-electron/*.dmg | |
| packages/app/dist-electron/latest-mac-${{ matrix.arch }}.yml | |
| if-no-files-found: warn | |
| # ============================================================================ | |
| # MERGE MAC LATEST YML (combines arm64 + x64 for auto-update) | |
| # ============================================================================ | |
| merge-mac-latest-yml: | |
| needs: [check, build-electron-macos] | |
| if: needs.check.outputs.should_release == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download macOS arm64 artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dm-hero-macos-arm64 | |
| path: ./mac-arm64 | |
| - name: Download macOS x64 artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dm-hero-macos-x64 | |
| path: ./mac-x64 | |
| - name: Merge latest-mac.yml files | |
| run: | | |
| # Install js-yaml for parsing | |
| npm install js-yaml | |
| node << 'EOF' | |
| const fs = require('fs'); | |
| const yaml = require('js-yaml'); | |
| // Read both yml files | |
| const arm64Yml = yaml.load(fs.readFileSync('./mac-arm64/latest-mac-arm64.yml', 'utf8')); | |
| const x64Yml = yaml.load(fs.readFileSync('./mac-x64/latest-mac-x64.yml', 'utf8')); | |
| console.log('=== arm64 yml ==='); | |
| console.log(JSON.stringify(arm64Yml, null, 2)); | |
| console.log('=== x64 yml ==='); | |
| console.log(JSON.stringify(x64Yml, null, 2)); | |
| // Create merged yml with both architectures | |
| const merged = { | |
| version: arm64Yml.version, | |
| files: [ | |
| // arm64 file(s) | |
| ...(arm64Yml.files || [{ url: arm64Yml.path, sha512: arm64Yml.sha512, size: arm64Yml.size }]).map(f => ({ | |
| ...f, | |
| arch: 'arm64' | |
| })), | |
| // x64 file(s) | |
| ...(x64Yml.files || [{ url: x64Yml.path, sha512: x64Yml.sha512, size: x64Yml.size }]).map(f => ({ | |
| ...f, | |
| arch: 'x64' | |
| })) | |
| ], | |
| releaseDate: arm64Yml.releaseDate || new Date().toISOString() | |
| }; | |
| // Write merged file | |
| const output = yaml.dump(merged, { lineWidth: -1 }); | |
| fs.writeFileSync('./latest-mac.yml', output); | |
| console.log('=== Merged latest-mac.yml ==='); | |
| console.log(output); | |
| EOF | |
| - name: Upload merged latest-mac.yml | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dm-hero-macos-latest | |
| path: ./latest-mac.yml | |
| create-release: | |
| needs: [check, create-docker-manifest, build-electron-windows, build-electron-linux, merge-mac-latest-yml] | |
| if: needs.check.outputs.should_release == 'true' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Download Windows artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dm-hero-windows | |
| path: ./artifacts | |
| - name: Download Linux artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dm-hero-linux | |
| path: ./artifacts | |
| - name: Download macOS arm64 artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dm-hero-macos-arm64 | |
| path: ./artifacts | |
| - name: Download macOS x64 artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dm-hero-macos-x64 | |
| path: ./artifacts | |
| - name: Download merged macOS latest yml | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dm-hero-macos-latest | |
| path: ./artifacts | |
| - name: Clean up arch-specific yml files (keep only merged) | |
| run: | | |
| rm -f ./artifacts/latest-mac-arm64.yml ./artifacts/latest-mac-x64.yml | |
| echo "=== Final artifacts ===" | |
| ls -la ./artifacts/ | |
| - name: Read changelog | |
| id: changelog | |
| run: | | |
| # Extract the latest changelog entry | |
| CHANGELOG=$(sed -n '/^## /,/^## /p' packages/app/CHANGELOG.md | sed '$ d' | tail -n +2) | |
| echo "changelog<<EOF" >> $GITHUB_OUTPUT | |
| echo "$CHANGELOG" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v${{ needs.check.outputs.version }} | |
| name: DM Hero v${{ needs.check.outputs.version }} | |
| body: ${{ steps.changelog.outputs.changelog }} | |
| files: ./artifacts/* | |
| draft: false | |
| prerelease: ${{ contains(needs.check.outputs.version, 'alpha') || contains(needs.check.outputs.version, 'beta') }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |