From 73b9c760ffe1a7504e6637389852a88fd99bdffe Mon Sep 17 00:00:00 2001 From: WJG Date: Wed, 20 Nov 2024 23:32:59 +0800 Subject: [PATCH] feat: build app workflow --- .github/workflows/build-app.yaml | 144 +++++++++++++++++++++++++++++++ scripts/dist.js | 62 +++++++++++++ src/pages/Mirror.tsx | 7 +- 3 files changed, 208 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/build-app.yaml create mode 100644 scripts/dist.js diff --git a/.github/workflows/build-app.yaml b/.github/workflows/build-app.yaml new file mode 100644 index 0000000..909da89 --- /dev/null +++ b/.github/workflows/build-app.yaml @@ -0,0 +1,144 @@ +name: Build and Release MagicMirror +on: + workflow_dispatch: + +jobs: + build-for-macos: + name: macOS + permissions: + contents: write + strategy: + fail-fast: false + matrix: + include: + - target: universal-apple-darwin + build: macos + os: macos-latest + arch: universal + - target: aarch64-apple-darwin + build: macos + os: macos-latest + arch: aarch64 + - target: x86_64-apple-darwin + build: macos + os: macos-latest + arch: x86_64 + + runs-on: ${{ matrix.os }} + steps: + - name: Setup PNPM + uses: pnpm/action-setup@v3 + with: + version: 8.5.1 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + cache-dependency-path: "**/pnpm-lock.yaml" + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + targets: ${{ matrix.arch == 'universal' && 'aarch64-apple-darwin,x86_64-apple-darwin' || matrix.target }} + - name: Setup Rust Cache + uses: swatinem/rust-cache@v2 + with: + workspaces: "src-tauri/${{ matrix.target }} -> target" + - name: Build APP + run: | + pnpm install + VERSION=$(node -p "require('./package.json').version") + CI=false pnpm tauri build -c "{\"version\":\"$VERSION\"}" -t ${{ matrix.target }} + APP_NAME=MagicMirror_$VERSION_${{ matrix.build }}_${{ matrix.arch }} + node scripts/dist.js ${{ matrix.target }} $APP_NAME + - name: Upload App + uses: actions/upload-artifact@v4 + with: + name: app_${{ matrix.build }}_${{ matrix.arch }} + path: dist/MagicMirror_* + + build-for-windows: + name: Windows + permissions: + contents: write + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-pc-windows-msvc + build: windows + os: windows-latest + arch: x86_64 + - target: aarch64-pc-windows-msvc + build: windows + os: windows-latest + arch: aarch64 + + runs-on: ${{ matrix.os }} + steps: + - name: Setup PNPM + uses: pnpm/action-setup@v3 + with: + version: 8.5.1 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + cache-dependency-path: "**/pnpm-lock.yaml" + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + targets: ${{ matrix.target }} + - name: Setup Rust Cache + uses: swatinem/rust-cache@v2 + with: + workspaces: "src-tauri/${{ matrix.target }} -> target" + - name: Build APP + run: | + pnpm install + $VERSION = $(node -p "require('./package.json').version") + pnpm tauri build -c '{\"version\":\"$VERSION\"}' -t ${{ matrix.target }} --bundles nsis + node scripts/dist.js ${{ matrix.target }} $APP_NAME + - name: Upload App + uses: actions/upload-artifact@v4 + with: + name: app_${{ matrix.build }}_${{ matrix.arch }} + path: dist/MagicMirror_* + + release: + name: Release + needs: [build-for-macos, build-for-windows] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Download Artifacts + uses: actions/download-artifact@v4 + with: + pattern: app_* + path: dist + merge-multiple: true + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + - name: Check Version + id: version + run: | + VERSION=$(node -p "require('./package.json').version") + echo "version=$VERSION" >> $GITHUB_OUTPUT + - name: Release MagicMirror v${{ steps.version.outputs.version }} + uses: ncipollo/release-action@v1 + with: + allowUpdates: true + token: ${{ secrets.GITHUB_TOKEN }} + name: MagicMirror v${{ steps.version.outputs.version }} + tag: v${{ steps.version.outputs.version }} + draft: true + prerelease: false + makeLatest: latest + removeArtifacts: true + artifacts: dist/* diff --git a/scripts/dist.js b/scripts/dist.js new file mode 100644 index 0000000..6e3acc8 --- /dev/null +++ b/scripts/dist.js @@ -0,0 +1,62 @@ +#!/usr/bin/env node + +import fs from "fs/promises"; +import { existsSync, mkdirSync } from "fs"; +import path from "path"; + +const getFiles = async (dir) => { + try { + const files = await fs.readdir(dir); + return files; + } catch (err) { + console.error(`Error reading directory ${dir}:`, err); + return []; + } +}; + +const copyFile = async (from, to) => { + if (!existsSync(from)) { + console.error(`Source file does not exist: ${from}`); + return false; + } + + const dirname = path.dirname(to); + if (!existsSync(dirname)) { + mkdirSync(dirname, { recursive: true }); + } + + await fs.copyFile(from, to).catch(() => null); +}; + +async function main() { + const args = process.argv.slice(2); + const [target, appName] = args; + const bundleDir = path.resolve(`src-tauri/target/${target}/release/bundle`); + let outputs = {}; + switch (process.platform) { + case "darwin": + outputs = { + dmg: [".dmg"], + }; + break; + case "win32": + outputs = { + nsis: [".exe"], + }; + } + for (const dir in outputs) { + const files = await getFiles(path.join(bundleDir, dir)); + for (const filename of files) { + const suffix = outputs[dir].find((e) => filename.endsWith(e)); + if (suffix) { + await copyFile( + path.join(bundleDir, dir, filename), + path.join("dist", appName + suffix) + ); + console.log(`✅ ${appName + suffix}`); + } + } + } +} + +main(); diff --git a/src/pages/Mirror.tsx b/src/pages/Mirror.tsx index 01ae676..7d19985 100644 --- a/src/pages/Mirror.tsx +++ b/src/pages/Mirror.tsx @@ -2,6 +2,7 @@ import { useDragDrop } from "@/hooks/useDragDrop"; import { useSwapFace } from "@/hooks/useSwapFace"; import { convertFileSrc } from "@tauri-apps/api/core"; import { exit } from "@tauri-apps/plugin-process"; +import { open } from "@tauri-apps/plugin-shell"; import { useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; @@ -11,8 +12,6 @@ import iconMenu from "@/assets/images/menu.webp"; import background from "@/assets/images/mirror-bg.svg"; import mirrorInput from "@/assets/images/mirror-input.webp"; import mirrorMe from "@/assets/images/mirror-me.webp"; -import { open } from "@tauri-apps/plugin-shell"; -import { getCurrentWindow } from "@tauri-apps/api/window"; interface Asset { path: string; @@ -127,9 +126,7 @@ export function MirrorPage() { )}
open(t("aboutLink"))}>{t("About")}
-
getCurrentWindow().close()}> - {t("Quit")} -
+
exit(0)}>{t("Quit")}