From 67934dcb6b7e979b7794daa7063a8cfcfb00b383 Mon Sep 17 00:00:00 2001 From: Yueer <36443462+YueerMoe@users.noreply.github.com> Date: Sat, 7 Feb 2026 03:24:21 +0800 Subject: [PATCH 1/5] =?UTF-8?q?chore(ci):=20=E6=8B=86=E5=88=86=20dev/previ?= =?UTF-8?q?ew/master=20=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/dev.yml | 52 +++++++++++++++ .github/workflows/preview.yml | 118 ++++++++++++++++++++++++++++++++++ .github/workflows/release.yml | 114 ++++++++++++++++++++++++++++++++ .github/workflows/tauri.yml | 72 --------------------- README.md | 15 ++++- 5 files changed, 296 insertions(+), 75 deletions(-) create mode 100644 .github/workflows/dev.yml create mode 100644 .github/workflows/preview.yml create mode 100644 .github/workflows/release.yml delete mode 100644 .github/workflows/tauri.yml diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml new file mode 100644 index 0000000..107202b --- /dev/null +++ b/.github/workflows/dev.yml @@ -0,0 +1,52 @@ +name: Dev CI + +on: + push: + branches: + - dev + workflow_dispatch: + +concurrency: + group: dev-ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ${{ matrix.platform }} + strategy: + fail-fast: false + matrix: + platform: [windows-latest, ubuntu-22.04] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + cache: yarn + cache-dependency-path: yarn.lock + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Cache Rust + uses: swatinem/rust-cache@v2 + with: + workspaces: | + src-tauri -> src-tauri/target + + - name: Install Linux dependencies + if: matrix.platform == 'ubuntu-22.04' + run: | + sudo apt-get update + sudo apt-get install -y libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml new file mode 100644 index 0000000..6d91df3 --- /dev/null +++ b/.github/workflows/preview.yml @@ -0,0 +1,118 @@ +name: Preview Prerelease + +on: + pull_request: + types: [closed] + branches: + - preview + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: preview-prerelease + cancel-in-progress: false + +jobs: + prepare: + if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'preview' && github.event.pull_request.head.ref == 'dev') + runs-on: ubuntu-latest + outputs: + tag_name: ${{ steps.vars.outputs.tag_name }} + app_version: ${{ steps.vars.outputs.app_version }} + + steps: + - name: Checkout (preview) + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: preview + + - name: Configure git + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + - name: Bump version, commit and tag + id: vars + shell: pwsh + run: | + $pkg = Get-Content -Raw package.json | ConvertFrom-Json + $baseVersion = [string]$pkg.version + if ($baseVersion.Contains("-")) { $baseVersion = $baseVersion.Split("-", 2)[0] } + + $shortSha = (git rev-parse --short=7 HEAD).Trim() + $epoch = [int64](Get-Date -AsUTC -UFormat %s) + $hex = ("{0:x}" -f $epoch) + $preVersion = "$baseVersion-pre.$hex.$shortSha" + $tag = "v$preVersion" + + if ((git ls-remote --tags origin "refs/tags/$tag")) { + throw "Tag already exists on origin: $tag" + } + + ./scripts/set-version.ps1 -Version $preVersion + git add package.json src-tauri/tauri.conf.json src-tauri/Cargo.toml + git commit -m "chore(version): 更新版本号为 $preVersion" + git tag $tag + + git push origin preview + git push origin $tag + + "tag_name=$tag" >> $env:GITHUB_OUTPUT + "app_version=$preVersion" >> $env:GITHUB_OUTPUT + + build: + needs: prepare + runs-on: ${{ matrix.platform }} + strategy: + fail-fast: false + matrix: + platform: [windows-latest, ubuntu-22.04] + + steps: + - name: Checkout (tag) + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ needs.prepare.outputs.tag_name }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + cache: yarn + cache-dependency-path: yarn.lock + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Cache Rust + uses: swatinem/rust-cache@v2 + with: + workspaces: | + src-tauri -> src-tauri/target + + - name: Install Linux dependencies + if: matrix.platform == 'ubuntu-22.04' + run: | + sudo apt-get update + sudo apt-get install -y libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf + + - name: Install frontend dependencies + run: yarn install --frozen-lockfile + + - name: Quick web build + run: yarn build + + - name: Build Tauri app and publish prerelease assets + uses: tauri-apps/tauri-action@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + projectPath: . + releaseDraft: false + prerelease: true + tagName: ${{ needs.prepare.outputs.tag_name }} + releaseName: EndCat ${{ needs.prepare.outputs.tag_name }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..0705664 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,114 @@ +name: Release Draft + +on: + pull_request: + types: [closed] + branches: + - master + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: master-release + cancel-in-progress: false + +jobs: + prepare: + if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'master' && github.event.pull_request.head.ref == 'preview') + runs-on: ubuntu-latest + outputs: + tag_name: ${{ steps.vars.outputs.tag_name }} + app_version: ${{ steps.vars.outputs.app_version }} + + steps: + - name: Checkout (master) + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: master + + - name: Configure git + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + - name: Bump version, commit and tag + id: vars + shell: pwsh + run: | + $pkg = Get-Content -Raw package.json | ConvertFrom-Json + $current = [string]$pkg.version + $releaseVersion = $current + if ($releaseVersion.Contains("-")) { $releaseVersion = $releaseVersion.Split("-", 2)[0] } + + $tag = "v$releaseVersion" + if ((git ls-remote --tags origin "refs/tags/$tag")) { + throw "Tag already exists on origin: $tag" + } + + ./scripts/set-version.ps1 -Version $releaseVersion + git add package.json src-tauri/tauri.conf.json src-tauri/Cargo.toml + git commit -m "chore(version): 更新版本号为 $releaseVersion" + git tag $tag + + git push origin master + git push origin $tag + + "tag_name=$tag" >> $env:GITHUB_OUTPUT + "app_version=$releaseVersion" >> $env:GITHUB_OUTPUT + + build: + needs: prepare + runs-on: ${{ matrix.platform }} + strategy: + fail-fast: false + matrix: + platform: [windows-latest, ubuntu-22.04] + + steps: + - name: Checkout (tag) + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ needs.prepare.outputs.tag_name }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + cache: yarn + cache-dependency-path: yarn.lock + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Cache Rust + uses: swatinem/rust-cache@v2 + with: + workspaces: | + src-tauri -> src-tauri/target + + - name: Install Linux dependencies + if: matrix.platform == 'ubuntu-22.04' + run: | + sudo apt-get update + sudo apt-get install -y libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf + + - name: Install frontend dependencies + run: yarn install --frozen-lockfile + + - name: Quick web build + run: yarn build + + - name: Build Tauri app and create draft release + uses: tauri-apps/tauri-action@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + projectPath: . + releaseDraft: true + prerelease: false + tagName: ${{ needs.prepare.outputs.tag_name }} + releaseName: EndCat ${{ needs.prepare.outputs.tag_name }} diff --git a/.github/workflows/tauri.yml b/.github/workflows/tauri.yml deleted file mode 100644 index 4bf0dbc..0000000 --- a/.github/workflows/tauri.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: Tauri Build - -on: - push: - branches: - - main - tags: - - "v*" - pull_request: - -jobs: - build: - runs-on: ${{ matrix.platform }} - strategy: - fail-fast: false - matrix: - platform: [windows-latest, ubuntu-22.04] - - permissions: - contents: write - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 18 - cache: yarn - cache-dependency-path: yarn.lock - - - name: Setup Rust - uses: dtolnay/rust-toolchain@stable - - - name: Cache Rust - uses: swatinem/rust-cache@v2 - with: - workspaces: | - src-tauri -> src-tauri/target - - - name: Install Linux dependencies - if: matrix.platform == 'ubuntu-22.04' - run: | - sudo apt-get update - sudo apt-get install -y libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf - - - name: Install frontend dependencies - run: yarn install --frozen-lockfile - - - name: Quick web build (PR only) - if: github.event_name == 'pull_request' - run: yarn build - - - name: Build Tauri app - uses: tauri-apps/tauri-action@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - projectPath: . - releaseDraft: ${{ startsWith(github.ref, 'refs/tags/') }} - prerelease: false - tagName: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || '' }} - releaseName: ${{ startsWith(github.ref, 'refs/tags/') && format('EndCat {0}', github.ref_name) || '' }} - - - name: Upload bundles - if: always() - uses: actions/upload-artifact@v4 - with: - name: tauri-bundles-${{ matrix.platform }} - path: src-tauri/target/release/bundle/** - retention-days: 7 diff --git a/README.md b/README.md index f8e338c..6b47ca3 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ - Node.js (v18+) - Rust (最新稳定版) - VS Code (推荐) +- Yarn v1(推荐) ### 启动项目 @@ -97,19 +98,27 @@ 2. **安装依赖** ```bash - npm install + yarn ``` 3. **启动开发模式** ```bash - npm run tauri dev + yarn tauri dev ``` 4. **构建生产版本** ```bash - npm run tauri build + yarn tauri build ``` +## 🧩 分支与发布流程 + +- `dev`:push 触发 CI(`.github/workflows/dev.yml`),不发版 +- `preview`:合并 `dev -> preview` 的 PR 后自动创建 Prerelease(版本号:`{version}-pre.{hex_timestamp}.{short_sha}`) +- `master`:合并 `preview -> master` 的 PR 后自动创建 Draft Release(正式版本号) + +> 版本号会同步写入 `package.json`、`src-tauri/tauri.conf.json`、`src-tauri/Cargo.toml`(脚本:`scripts/set-version.ps1`)。 + ## 贡献者
From 2e2d945d56cfc5aaf8f4e7acff55797336b6e074 Mon Sep 17 00:00:00 2001 From: Yueer <36443462+YueerMoe@users.noreply.github.com> Date: Sat, 7 Feb 2026 03:25:56 +0800 Subject: [PATCH 2/5] =?UTF-8?q?chore(version):=20=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7=E8=87=B3=200.2.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/tauri.conf.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index c29bf4a..41d3b3c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "endfield-cat", "private": true, - "version": "0.1.3", + "version": "0.2.0", "type": "module", "scripts": { "dev": "vite", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 0cf8151..41b2e54 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -878,7 +878,7 @@ checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" [[package]] name = "endfield-cat" -version = "0.1.3" +version = "0.2.0" dependencies = [ "futures-util", "reqwest", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 1ce5a29..26495d6 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "endfield-cat" -version = "0.1.3" +version = "0.2.0" description = "A Tauri App" authors = ["you"] edition = "2021" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index cfa2b8d..54d4bff 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "endfield-cat", - "version": "0.1.3", + "version": "0.2.0", "identifier": "org.boxcat.endfield-cat", "build": { "beforeDevCommand": "yarn dev", From df2889e8e618c2cacdbc9da741d475df0cc714c5 Mon Sep 17 00:00:00 2001 From: Yueer <36443462+YueerMoe@users.noreply.github.com> Date: Sat, 7 Feb 2026 03:26:09 +0800 Subject: [PATCH 3/5] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=20gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c555555..6a25e00 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,8 @@ endfield-cat-metadata # Local TLS certs (self-signed) /certs/* -scripts \ No newline at end of file +scripts + +findings.md +progress.md +task_plan.md From fe266d72f66b1e190fcab2fb3127cf9e898d434e Mon Sep 17 00:00:00 2001 From: Yueer <36443462+YueerMoe@users.noreply.github.com> Date: Sat, 7 Feb 2026 03:26:28 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat(updater):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E9=A2=84=E5=8F=91=E5=B8=83=E6=9B=B4=E6=96=B0=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=89=88=E6=9C=AC=E6=AF=94=E8=BE=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 +- src-tauri/src/app_cmd.rs | 5 + src-tauri/src/lib.rs | 1 + src-tauri/src/services/release.rs | 91 +++++++++-- src/api/tauriCommands.ts | 4 + src/components/UpdateDialog.vue | 42 ++++-- src/i18n/locales/en-US.ts | 2 + src/i18n/locales/zh-CN.ts | 2 + src/stores/updater.ts | 242 +++++++++++++++++++----------- yarn.lock | 10 ++ 10 files changed, 292 insertions(+), 111 deletions(-) diff --git a/package.json b/package.json index 41d3b3c..532dd68 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@varlet/ui": "^3.13.1", "echarts": "^5", "pinia": "^3.0.4", + "semver": "^7.7.4", "vue": "^3.5.13", "vue-echarts": "^6", "vue-i18n": "^11.2.8", @@ -23,6 +24,7 @@ }, "devDependencies": { "@tauri-apps/cli": "^2", + "@types/semver": "^7.7.1", "@varlet/import-resolver": "^3.13.1", "@vitejs/plugin-vue": "^5.2.1", "typescript": "~5.6.2", @@ -31,4 +33,4 @@ "vite": "^6.0.3", "vue-tsc": "^2.1.10" } -} \ No newline at end of file +} diff --git a/src-tauri/src/app_cmd.rs b/src-tauri/src/app_cmd.rs index 665fb2d..97e6aed 100644 --- a/src-tauri/src/app_cmd.rs +++ b/src-tauri/src/app_cmd.rs @@ -111,6 +111,11 @@ pub async fn fetch_latest_release(client: State<'_, reqwest::Client>) -> Result< release::fetch_latest_release(&client).await } +#[tauri::command] +pub async fn fetch_latest_prerelease(client: State<'_, reqwest::Client>) -> Result { + release::fetch_latest_prerelease(&client).await +} + #[tauri::command] pub async fn download_and_apply_update( window: tauri::Window, diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 367ee10..4d894b5 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -44,6 +44,7 @@ pub fn run() { app_cmd::fetch_metadata_manifest, app_cmd::check_metadata, app_cmd::fetch_latest_release, + app_cmd::fetch_latest_prerelease, app_cmd::download_and_apply_update, app_cmd::test_github_mirror, hg_api::auth::hg_exchange_user_token, diff --git a/src-tauri/src/services/release.rs b/src-tauri/src/services/release.rs index 52522eb..71ded7a 100644 --- a/src-tauri/src/services/release.rs +++ b/src-tauri/src/services/release.rs @@ -46,19 +46,23 @@ pub async fn fetch_latest_release(client: &reqwest::Client) -> Result Result Err(err.message), } } + +pub async fn fetch_latest_prerelease(client: &reqwest::Client) -> Result { + let url = "https://api.github.com/repos/BoxCatTeam/endfield-cat/releases?per_page=20"; + let resp = client + .get(url) + .header("Accept", "application/vnd.github+json") + .header("User-Agent", "endfield-cat/tauri") + .send() + .await + .map_err(|e| e.to_string())?; + + let status = resp.status(); + if !status.is_success() { + return Err(format!("GitHub API status {}", status)); + } + + let json: serde_json::Value = resp.json().await.map_err(|e| e.to_string())?; + let releases = json.as_array().ok_or("Invalid GitHub response: expected array")?; + + let target = releases.iter().find(|r| { + r.get("draft").and_then(|v| v.as_bool()) == Some(false) + && r.get("prerelease").and_then(|v| v.as_bool()) == Some(true) + }); + + let Some(target) = target else { + return Err("No prerelease found".to_string()); + }; + + let tag_name = target + .get("tag_name") + .or_else(|| target.get("name")) + .and_then(|v| v.as_str()) + .unwrap_or("") + .to_string(); + + if tag_name.is_empty() { + return Err("Missing tag_name in GitHub response".to_string()); + } + + let name = target.get("name").and_then(|v| v.as_str()).map(|s| s.to_string()); + let html_url = target.get("html_url").and_then(|v| v.as_str()).map(|s| s.to_string()); + let body = target.get("body").and_then(|v| v.as_str()).map(|s| s.to_string()); + + let download_url = if cfg!(target_os = "windows") { + target + .get("assets") + .and_then(|v| v.as_array()) + .and_then(|assets| { + assets.iter().find_map(|asset| { + let name = asset.get("name").and_then(|v| v.as_str())?; + if name.ends_with(".exe") { + asset.get("browser_download_url").and_then(|v| v.as_str()).map(|s| s.to_string()) + } else { + None + } + }) + }) + } else { + None + }; + + Ok(LatestRelease { tag_name, name, html_url, download_url, body }) +} diff --git a/src/api/tauriCommands.ts b/src/api/tauriCommands.ts index bc61247..ecd0ddb 100644 --- a/src/api/tauriCommands.ts +++ b/src/api/tauriCommands.ts @@ -39,6 +39,10 @@ export function fetchLatestRelease() { return invoke("fetch_latest_release"); } +export function fetchLatestPrerelease() { + return invoke("fetch_latest_prerelease"); +} + export function downloadAndApplyUpdate(downloadUrl: string) { return invoke("download_and_apply_update", { downloadUrl }); } diff --git a/src/components/UpdateDialog.vue b/src/components/UpdateDialog.vue index 540838a..dda406f 100644 --- a/src/components/UpdateDialog.vue +++ b/src/components/UpdateDialog.vue @@ -1,17 +1,12 @@