Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: CI

on:
pull_request:
branches: [main]
push:
branches: [main]

env:
CARGO_TERM_COLOR: always

jobs:
frontend-check:
name: Frontend Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: "22" }
- uses: pnpm/action-setup@v4
- run: pnpm install --frozen-lockfile
- run: pnpm turbo run typecheck lint test

check:
name: Cargo Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev
- uses: actions/setup-node@v4
with: { node-version: "22" }
- uses: pnpm/action-setup@v4
- run: pnpm install --frozen-lockfile && pnpm turbo run build --filter=@ltk-forge/app
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo check --all-targets --all-features

test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev
- uses: actions/setup-node@v4
with: { node-version: "22" }
- uses: pnpm/action-setup@v4
- run: pnpm install --frozen-lockfile && pnpm turbo run build --filter=@ltk-forge/app
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo test --all-features

clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev
- uses: actions/setup-node@v4
with: { node-version: "22" }
- uses: pnpm/action-setup@v4
- run: pnpm install --frozen-lockfile && pnpm turbo run build --filter=@ltk-forge/app
- uses: dtolnay/rust-toolchain@stable
with: { components: clippy }
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --all-targets --all-features -- -D warnings

fmt:
name: Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with: { components: rustfmt }
- run: cargo fmt --all -- --check
99 changes: 99 additions & 0 deletions .github/workflows/release-prepare.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: Prepare Release

on:
workflow_dispatch:
inputs:
version:
description: "Version bump: patch, minor, major, or explicit (e.g. 1.2.3)"
required: true
type: string

jobs:
prepare:
name: Create Release PR
runs-on: ubuntu-latest
if: github.repository_owner == 'LeagueToolkit'
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Resolve version
id: version
shell: bash
run: |
INPUT="${{ inputs.version }}"
CURRENT=$(node -p "require('./package.json').version")
IFS='.' read -r MAJ MIN PAT <<< "$CURRENT"

case "$INPUT" in
patch) VERSION="$MAJ.$MIN.$((PAT + 1))" ;;
minor) VERSION="$MAJ.$((MIN + 1)).0" ;;
major) VERSION="$((MAJ + 1)).0.0" ;;
*)
if [[ ! "$INPUT" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
echo "::error::Invalid version: $INPUT (expected patch, minor, major, or semver like 1.2.3)"
exit 1
fi
VERSION="$INPUT"
;;
esac

echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "::notice::Preparing release v$VERSION (current: $CURRENT)"

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable

- name: Bump versions and create PR
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ steps.version.outputs.version }}"
BRANCH="release/v$VERSION"

# Bump root package.json
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg.version = '$VERSION';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
"

# Bump apps/forge/package.json
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('apps/forge/package.json', 'utf8'));
pkg.version = '$VERSION';
fs.writeFileSync('apps/forge/package.json', JSON.stringify(pkg, null, 2) + '\n');
"

# Bump src-tauri/Cargo.toml
sed -i "0,/^version = \".*\"/s//version = \"$VERSION\"/" src-tauri/Cargo.toml

# Bump src-tauri/tauri.conf.json
node -e "
const fs = require('fs');
const conf = JSON.parse(fs.readFileSync('src-tauri/tauri.conf.json', 'utf8'));
conf.version = '$VERSION';
fs.writeFileSync('src-tauri/tauri.conf.json', JSON.stringify(conf, null, 2) + '\n');
"

# Regenerate Cargo.lock
cargo generate-lockfile

git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git checkout -b "$BRANCH"
git add package.json apps/forge/package.json src-tauri/Cargo.toml src-tauri/tauri.conf.json Cargo.lock
git commit -m "chore: release v$VERSION"
git push origin "$BRANCH"

gh pr create \
--title "chore: release v$VERSION" \
--body "Bumps version to **v$VERSION** in \`package.json\`, \`apps/forge/package.json\`, \`src-tauri/Cargo.toml\`, and \`src-tauri/tauri.conf.json\`." \
--base main \
--head "$BRANCH"
171 changes: 171 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
name: Release

on:
pull_request:
types: [closed]
branches: [main]
push:
tags:
- "v*"

env:
CARGO_TERM_COLOR: always

jobs:
release:
name: Build & Release
runs-on: windows-latest
if: >
github.repository_owner == 'LeagueToolkit' && (
github.event_name == 'push' ||
(github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v'))
)
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Resolve version
id: version
shell: bash
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
BRANCH="${{ github.event.pull_request.head.ref }}"
VERSION="${BRANCH#release/v}"
else
TAG="${GITHUB_REF#refs/tags/}"
VERSION="${TAG#v}"
fi

echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag=v$VERSION" >> "$GITHUB_OUTPUT"

if [[ "$VERSION" == *-* ]]; then
echo "prerelease=true" >> "$GITHUB_OUTPUT"
else
echo "prerelease=false" >> "$GITHUB_OUTPUT"
fi

echo "::notice::Releasing v$VERSION"

- name: Create tag
if: github.event_name == 'pull_request'
shell: bash
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag "v${{ steps.version.outputs.version }}"
git push origin "v${{ steps.version.outputs.version }}"

- name: Delete release branch
if: github.event_name == 'pull_request'
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: git push origin --delete "${{ github.event.pull_request.head.ref }}" || true

- name: Validate version consistency
if: github.event_name == 'push'
shell: bash
run: |
CARGO_VERSION=$(sed -n 's/^version = "\(.*\)"/\1/p' src-tauri/Cargo.toml | head -1)
if [ "$CARGO_VERSION" != "${{ steps.version.outputs.version }}" ]; then
echo "::error::Tag version (${{ steps.version.outputs.version }}) does not match Cargo.toml version ($CARGO_VERSION)"
exit 1
fi

- name: Generate changelog
id: changelog
uses: orhun/git-cliff-action@v4
with:
config: cliff.toml
args: --latest --strip header

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"

- uses: pnpm/action-setup@v4

- name: Cache pnpm store
uses: actions/cache@v4
with:
path: ~\AppData\Local\pnpm\store
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: pnpm-

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-pc-windows-msvc

- uses: Swatinem/rust-cache@v2
with:
shared-key: release
cache-on-failure: true

- name: Install trusted-signing-cli
if: env.AZURE_CLIENT_ID != ''
run: cargo install trusted-signing-cli
env:
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}

- name: Locate signtool.exe
if: env.AZURE_CLIENT_ID != ''
id: signtool
shell: pwsh
env:
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
run: |
$signtool = Get-ChildItem -Path "C:\Program Files (x86)\Windows Kits\10\bin" -Recurse -Filter "signtool.exe" |
Where-Object { $_.FullName -like "*\x64\*" } |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1
if (-not $signtool) { throw "signtool.exe not found" }
echo "SIGNTOOL_PATH=$($signtool.FullName)" >> $env:GITHUB_OUTPUT

- name: Install frontend dependencies
run: pnpm install --frozen-lockfile

- name: Build and release
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
SIGNTOOL_PATH: ${{ steps.signtool.outputs.SIGNTOOL_PATH }}
with:
args: --verbose
tagName: ${{ steps.version.outputs.tag }}
releaseName: "LTK Forge v${{ steps.version.outputs.version }}"
releaseBody: ${{ steps.changelog.outputs.content }}
releaseDraft: false
prerelease: ${{ steps.version.outputs.prerelease }}
updaterJsonPreferNsis: true

- name: Update updater release
shell: bash
run: |
TAG="${{ steps.version.outputs.tag }}"

# Download latest.json from the release we just created
gh release download "$TAG" --pattern "latest.json" --dir . --clobber

# Upload to the pinned "updater" release
if gh release view updater &>/dev/null; then
gh release upload updater latest.json --clobber
else
gh release create updater latest.json \
--title "Updater" \
--notes "Auto-updated by CI. Contains the latest updater manifest for in-app updates." \
--latest=false
fi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5 changes: 5 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
Auto-generated from all feature plans. Last updated: 2026-03-06

## Active Technologies

- TypeScript 5.x (frontend), Rust 2021 edition (backend) + Tauri v2, React 19, Vite 6, TanStack Router, Tailwind CSS v4, Zustand, tauri-plugin-{shell,dialog,fs,process} (002-tauri-app-setup)
- N/A (no persistent storage in initial setup) (002-tauri-app-setup)
- TypeScript 5.x (frontend), Rust 2021 edition (backend), YAML (CI workflows) + lefthook (git hooks), @commitlint/cli + @commitlint/config-conventional (commit validation), git-cliff (changelog generation via GitHub Action), Tauri v2 (build/release) (003-commitlint-release-workflow)
- N/A (configuration-only feature) (003-commitlint-release-workflow)

- TypeScript 5.x, targeting ES2022+ + pnpm (workspace management), Turborepo (build orchestration), Three.js + @react-three/fiber (3D rendering), Vitest (testing), tsup (library bundling), ESLint + Prettier (linting/formatting) (001-frontend-monorepo)

Expand All @@ -24,6 +27,8 @@ npm test; npm run lint
TypeScript 5.x, targeting ES2022+: Follow standard conventions

## Recent Changes

- 003-commitlint-release-workflow: Added TypeScript 5.x (frontend), Rust 2021 edition (backend), YAML (CI workflows) + lefthook (git hooks), @commitlint/cli + @commitlint/config-conventional (commit validation), git-cliff (changelog generation via GitHub Action), Tauri v2 (build/release)
- 002-tauri-app-setup: Added TypeScript 5.x (frontend), Rust 2021 edition (backend) + Tauri v2, React 19, Vite 6, TanStack Router, Tailwind CSS v4, Zustand, tauri-plugin-{shell,dialog,fs,process}

- 001-frontend-monorepo: Added TypeScript 5.x, targeting ES2022+ + pnpm (workspace management), Turborepo (build orchestration), Three.js + @react-three/fiber (3D rendering), Vitest (testing), tsup (library bundling), ESLint + Prettier (linting/formatting)
Expand Down
Loading