Skip to content

Commit cff771c

Browse files
committed
add beta track builds
1 parent fd3c41b commit cff771c

10 files changed

Lines changed: 307 additions & 3 deletions

File tree

.github/workflows/release-beta.yml

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
name: Beta Release Build
2+
3+
on:
4+
push:
5+
branches:
6+
- beta
7+
8+
jobs:
9+
release:
10+
permissions:
11+
contents: write
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
include:
16+
- platform: 'macos-latest'
17+
args: '--target aarch64-apple-darwin --features beta'
18+
- platform: 'macos-latest'
19+
args: '--target x86_64-apple-darwin --features beta'
20+
- platform: 'ubuntu-22.04'
21+
args: '--features beta'
22+
- platform: 'windows-latest'
23+
args: '--features beta'
24+
25+
runs-on: ${{ matrix.platform }}
26+
steps:
27+
- uses: actions/checkout@v4
28+
29+
- name: Setup Node.js
30+
uses: actions/setup-node@v4
31+
with:
32+
node-version: 20
33+
34+
- name: Install Rust stable
35+
uses: dtolnay/rust-toolchain@stable
36+
with:
37+
targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
38+
39+
- name: Install dependencies (Ubuntu only)
40+
if: matrix.platform == 'ubuntu-22.04'
41+
run: |
42+
sudo apt-get update
43+
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
44+
45+
- name: Install frontend dependencies
46+
run: yarn install
47+
48+
- name: Get version from package.json
49+
id: version
50+
shell: bash
51+
run: echo "VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
52+
53+
- name: Check signing configuration
54+
shell: bash
55+
run: |
56+
if [ -n "${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}" ]; then
57+
echo "✓ TAURI_SIGNING_PRIVATE_KEY is set (length: ${#TAURI_SIGNING_PRIVATE_KEY})"
58+
else
59+
echo "✗ TAURI_SIGNING_PRIVATE_KEY is NOT set"
60+
fi
61+
if [ -n "${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}" ]; then
62+
echo "✓ TAURI_SIGNING_PRIVATE_KEY_PASSWORD is set"
63+
else
64+
echo "✗ TAURI_SIGNING_PRIVATE_KEY_PASSWORD is NOT set"
65+
fi
66+
env:
67+
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
68+
69+
- uses: tauri-apps/tauri-action@v0
70+
env:
71+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
72+
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
73+
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
74+
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
75+
with:
76+
tagName: v${{ steps.version.outputs.VERSION }}-beta
77+
releaseName: 'Dota Keeper Beta v${{ steps.version.outputs.VERSION }}'
78+
releaseBody: 'Beta pre-release v${{ steps.version.outputs.VERSION }}'
79+
releaseDraft: false
80+
prerelease: true
81+
configPath: src-tauri/tauri.beta.conf.json
82+
args: ${{ matrix.args }}
83+
84+
update-beta-json:
85+
needs: release
86+
runs-on: ubuntu-latest
87+
permissions:
88+
contents: write
89+
steps:
90+
- uses: actions/checkout@v4
91+
with:
92+
ref: main
93+
94+
- name: Get version from package.json
95+
id: version
96+
run: echo "VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
97+
98+
- name: Download and inspect release signatures
99+
env:
100+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
101+
run: |
102+
VERSION="${{ steps.version.outputs.VERSION }}"
103+
TAG="v${VERSION}-beta"
104+
echo "=== Release assets for ${TAG} ==="
105+
gh release view "${TAG}" --json assets --jq '.assets[].name' || echo "Could not list assets"
106+
107+
mkdir -p ./signatures
108+
109+
echo ""
110+
echo "=== Downloading .sig files ==="
111+
gh release download "${TAG}" --pattern "*.sig" --dir ./signatures 2>&1 || \
112+
echo "Warning: gh release download failed or no .sig files found"
113+
114+
echo ""
115+
echo "=== Downloaded signature files ==="
116+
ls -la ./signatures/ 2>/dev/null || echo "No files downloaded"
117+
118+
- name: Update latest-beta.json
119+
env:
120+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
121+
run: |
122+
VERSION="${{ steps.version.outputs.VERSION }}"
123+
TAG="v${VERSION}-beta"
124+
PUB_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
125+
126+
WIN_SIG=""
127+
LINUX_SIG=""
128+
MACOS_X64_SIG=""
129+
MACOS_ARM_SIG=""
130+
131+
for f in ./signatures/*.sig; do
132+
[ -f "$f" ] || continue
133+
name=$(basename "$f")
134+
echo "Classifying: $name"
135+
case "$name" in
136+
*aarch64*) MACOS_ARM_SIG=$(cat "$f"); echo " → macOS ARM" ;;
137+
*amd64*) LINUX_SIG=$(cat "$f"); echo " → Linux x64" ;;
138+
*x64.app.tar.gz.sig) MACOS_X64_SIG=$(cat "$f"); echo " → macOS x64" ;;
139+
*x64*) WIN_SIG=$(cat "$f"); echo " → Windows x64" ;;
140+
*) echo " → unrecognised, skipping" ;;
141+
esac
142+
done
143+
144+
echo ""
145+
echo "Windows sig present: $([ -n "$WIN_SIG" ] && echo yes || echo NO)"
146+
echo "Linux sig present: $([ -n "$LINUX_SIG" ] && echo yes || echo NO)"
147+
echo "macOS x64 sig present: $([ -n "$MACOS_X64_SIG" ] && echo yes || echo NO)"
148+
echo "macOS ARM sig present: $([ -n "$MACOS_ARM_SIG" ] && echo yes || echo NO)"
149+
150+
mkdir -p meta/autoupdate
151+
152+
cat > meta/autoupdate/latest-beta.json << EOF
153+
{
154+
"version": "${VERSION}",
155+
"notes": "Beta release v${VERSION}",
156+
"pub_date": "${PUB_DATE}",
157+
"platforms": {
158+
"windows-x86_64": {
159+
"signature": "${WIN_SIG}",
160+
"url": "https://github.com/stringhandler/dota-keeper/releases/download/${TAG}/Dota.Keeper.Beta_${VERSION}_x64_en-US.msi"
161+
},
162+
"linux-x86_64": {
163+
"signature": "${LINUX_SIG}",
164+
"url": "https://github.com/stringhandler/dota-keeper/releases/download/${TAG}/Dota.Keeper.Beta_${VERSION}_amd64.AppImage.tar.gz"
165+
},
166+
"darwin-x86_64": {
167+
"signature": "${MACOS_X64_SIG}",
168+
"url": "https://github.com/stringhandler/dota-keeper/releases/download/${TAG}/Dota.Keeper.Beta_x64.app.tar.gz"
169+
},
170+
"darwin-aarch64": {
171+
"signature": "${MACOS_ARM_SIG}",
172+
"url": "https://github.com/stringhandler/dota-keeper/releases/download/${TAG}/Dota.Keeper.Beta_aarch64.app.tar.gz"
173+
}
174+
}
175+
}
176+
EOF
177+
178+
echo ""
179+
echo "=== Generated latest-beta.json ==="
180+
cat meta/autoupdate/latest-beta.json
181+
182+
- name: Commit latest-beta.json to main
183+
run: |
184+
git config user.name "github-actions[bot]"
185+
git config user.email "github-actions[bot]@users.noreply.github.com"
186+
git add meta/autoupdate/latest-beta.json
187+
git diff --cached --quiet || git commit -m "chore: update latest-beta.json for v${{ steps.version.outputs.VERSION }}"
188+
git push

meta/autoupdate/latest-beta.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"version": "0.0.0",
3+
"notes": "No beta release yet",
4+
"pub_date": "1970-01-01T00:00:00Z",
5+
"platforms": {}
6+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
https://github.com/stringhandler/dota-keeper/actions/runs/22591700976
2+
3+
4+
yarn run v1.22.22
5+
$ tauri android build --apk --target aarch64
6+
error: a value is required for '--apk <APK>' but none was supplied
7+
[possible values: true, false]
8+
9+
For more information, try '--help'.
10+
error Command failed with exit code 2.
11+
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
12+
Error: Process completed with exit code 2.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Test Guide: Beta Release Channel
2+
3+
## Files Changed
4+
5+
- `src-tauri/tauri.beta.conf.json` — new overlay config
6+
- `src-tauri/Cargo.toml` — added `[features] beta = []`
7+
- `src-tauri/src/database.rs` — beta uses `dota_keeper_beta.db`
8+
- `src-tauri/src/lib.rs` — added `is_beta_build()` Tauri command
9+
- `src/lib/TitleBar.svelte` — shows BETA badge when beta feature is active
10+
- `meta/autoupdate/latest-beta.json` — placeholder manifest
11+
- `.github/workflows/release-beta.yml` — CI workflow for beta releases
12+
13+
## Manual Tests
14+
15+
### 1. Normal dev build — no badge
16+
```
17+
yarn tauri dev
18+
```
19+
- Title bar should show **"Dota Keeper"** only, no BETA badge.
20+
21+
### 2. Beta feature flag — BETA badge appears
22+
```
23+
yarn tauri dev -- -- --features beta
24+
```
25+
Or build with:
26+
```
27+
yarn tauri build -- --features beta --config src-tauri/tauri.beta.conf.json
28+
```
29+
- Title bar should show **"Dota Keeper BETA"** (gold badge next to the title).
30+
- Window title (OS taskbar) should read **"Dota Keeper Beta"**.
31+
32+
### 3. Database isolation
33+
Run stable and beta builds on the same machine and confirm:
34+
- Stable: `%LOCALAPPDATA%/DotaKeeper/dota_keeper.db`
35+
- Beta: `%LOCALAPPDATA%/DotaKeeper/dota_keeper_beta.db`
36+
37+
Each build should open/create its own separate database file.
38+
39+
### 4. Separate app identifier
40+
Install both stable and beta (with `--config`). They should appear as separate
41+
entries in Windows "Apps & Features" — one for `com.volthawk.dota-keeper`,
42+
one for `com.volthawk.dota-keeper-beta`.
43+
44+
### 5. CI workflow (GitHub)
45+
Push a commit to the `beta` branch and confirm:
46+
- `release-beta.yml` workflow triggers (not `release.yml`).
47+
- A GitHub **pre-release** is created tagged `v<version>-beta`.
48+
- `meta/autoupdate/latest-beta.json` is committed back to `main` with platform
49+
URLs pointing to the beta release assets.
File renamed without changes.

src-tauri/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,6 @@ chrono = { version = "0.4", features = ["serde"] }
3636
rand = "0.8"
3737
lazy_static = "1.5"
3838
uuid = { version = "1.11", features = ["v4"] }
39+
40+
[features]
41+
beta = []

src-tauri/src/database.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,8 @@ impl Match {
200200
/// Prefers the globally initialised app-data dir (set during Tauri setup, works on all
201201
/// platforms including mobile). Falls back to `dirs::data_local_dir()` for situations
202202
/// where setup hasn't run yet (e.g. unit tests).
203-
/// Dev builds use `dota_keeper_dev.db`; release builds use `dota_keeper.db`.
203+
/// Dev builds use `dota_keeper_dev.db`; beta builds use `dota_keeper_beta.db`;
204+
/// release builds use `dota_keeper.db`.
204205
fn get_db_path() -> Option<PathBuf> {
205206
let mut base = match DB_DIR.get() {
206207
Some(dir) => dir.clone(),
@@ -214,7 +215,10 @@ fn get_db_path() -> Option<PathBuf> {
214215
#[cfg(debug_assertions)]
215216
base.push("dota_keeper_dev.db");
216217

217-
#[cfg(not(debug_assertions))]
218+
#[cfg(all(not(debug_assertions), feature = "beta"))]
219+
base.push("dota_keeper_beta.db");
220+
221+
#[cfg(all(not(debug_assertions), not(feature = "beta")))]
218222
base.push("dota_keeper.db");
219223

220224
Some(base)

src-tauri/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,12 @@ fn get_goal_histogram_data(goal_id: i64) -> Result<Vec<MatchDataPoint>, String>
10021002
get_goal_match_data(&conn, goal_id)
10031003
}
10041004

1005+
/// Returns true when this binary was compiled with the `beta` feature flag.
1006+
#[tauri::command]
1007+
fn is_beta_build() -> bool {
1008+
cfg!(feature = "beta")
1009+
}
1010+
10051011
/// Get the path to the database folder
10061012
#[tauri::command]
10071013
fn get_database_folder_path() -> Result<String, String> {
@@ -1783,6 +1789,7 @@ pub fn run() {
17831789
get_hero_goal_suggestion,
17841790
refresh_hero_goal_suggestion,
17851791
parse_match,
1792+
is_beta_build,
17861793
get_database_folder_path,
17871794
open_database_folder,
17881795
get_last_hits_analysis_data,

src-tauri/tauri.beta.conf.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"productName": "Dota Keeper Beta",
3+
"identifier": "com.volthawk.dota-keeper-beta",
4+
"plugins": {
5+
"updater": {
6+
"endpoints": [
7+
"https://raw.githubusercontent.com/stringhandler/dota-keeper/main/meta/autoupdate/latest-beta.json"
8+
]
9+
}
10+
}
11+
}

src/lib/TitleBar.svelte

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
<script>
22
import { getCurrentWindow } from '@tauri-apps/api/window';
3+
import { invoke } from '@tauri-apps/api/core';
4+
import { onMount } from 'svelte';
35
46
const appWindow = getCurrentWindow();
57
8+
let isBeta = false;
9+
10+
onMount(async () => {
11+
isBeta = await invoke('is_beta_build');
12+
});
13+
614
async function minimize() {
715
await appWindow.minimize();
816
}
@@ -17,7 +25,10 @@
1725
</script>
1826

1927
<div class="titlebar" data-tauri-drag-region role="banner">
20-
<span class="titlebar-title" data-tauri-drag-region>Dota Keeper</span>
28+
<span class="titlebar-title" data-tauri-drag-region>
29+
Dota Keeper
30+
{#if isBeta}<span class="beta-badge">BETA</span>{/if}
31+
</span>
2132
<div class="titlebar-buttons">
2233
<button class="tb-btn" onclick={minimize} title="Minimize" aria-label="Minimize">
2334
<svg width="10" height="1" viewBox="0 0 10 1"><rect width="10" height="1" fill="currentColor"/></svg>
@@ -58,6 +69,19 @@
5869
pointer-events: none;
5970
}
6071
72+
.beta-badge {
73+
font-size: 9px;
74+
font-weight: 700;
75+
letter-spacing: 1px;
76+
color: #1a1a1a;
77+
background: var(--gold-dim);
78+
padding: 1px 5px;
79+
border-radius: 2px;
80+
margin-left: 8px;
81+
vertical-align: middle;
82+
pointer-events: none;
83+
}
84+
6185
.titlebar-buttons {
6286
display: flex;
6387
gap: 0;

0 commit comments

Comments
 (0)