From 6ea7d53a491d6c3b5e43acbcae16cb22def01506 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Mon, 12 Jan 2026 22:42:09 +0000 Subject: [PATCH] Migrate to using taskfiles --- .github/workflows/check.yml | 7 +- .github/workflows/deploy-docs.yml | 7 +- .github/workflows/e2e.yml | 17 ++-- .github/workflows/publish-plugin.yml | 18 ++-- CLAUDE.md | 132 ++++++++++++++++--------- Taskfile.yml | 96 ++++++++++++++++++ scripts/build-docs.sh | 14 --- scripts/build-sync-server-binaries.sh | 44 --------- scripts/bump-version.sh | 50 ---------- scripts/check.sh | 63 ------------ scripts/clean-up.sh | 4 - scripts/e2e.sh | 98 ------------------- scripts/update-api-types.sh | 18 ---- scripts/utils/check-node.sh | 11 --- scripts/utils/wait-for-server.sh | 24 ----- taskfiles/database.yml | 25 +++++ taskfiles/docs.yml | 35 +++++++ taskfiles/e2e.yml | 134 ++++++++++++++++++++++++++ taskfiles/frontend.yml | 41 ++++++++ taskfiles/release.yml | 44 +++++++++ taskfiles/rust.yml | 73 ++++++++++++++ 21 files changed, 564 insertions(+), 391 deletions(-) create mode 100644 Taskfile.yml delete mode 100755 scripts/build-docs.sh delete mode 100755 scripts/build-sync-server-binaries.sh delete mode 100755 scripts/bump-version.sh delete mode 100755 scripts/check.sh delete mode 100755 scripts/clean-up.sh delete mode 100755 scripts/e2e.sh delete mode 100755 scripts/update-api-types.sh delete mode 100755 scripts/utils/check-node.sh delete mode 100755 scripts/utils/wait-for-server.sh create mode 100644 taskfiles/database.yml create mode 100644 taskfiles/docs.yml create mode 100644 taskfiles/e2e.yml create mode 100644 taskfiles/frontend.yml create mode 100644 taskfiles/release.yml create mode 100644 taskfiles/rust.yml diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index fc1b1c99..b6ff4921 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -32,5 +32,10 @@ jobs: toolchain: "1.92.0" components: clippy, rustfmt + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + - name: Lint & test - run: scripts/check.sh + run: task check diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index bb25e463..d39f0c00 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -34,11 +34,16 @@ jobs: node-version: "25.x" check-latest: true + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + - name: Setup Pages uses: actions/configure-pages@v4 - name: Build docs - run: scripts/build-docs.sh + run: task docs:check - name: Upload artifact uses: actions/upload-pages-artifact@v3 diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 98dbfc1f..917dab69 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -37,12 +37,13 @@ jobs: toolchain: "1.92.0" components: clippy, rustfmt - - name: Setup rust - run: | - which sqlx || cargo install sqlx-cli - cd sync-server - sqlx database create --database-url sqlite://db.sqlite3 - sqlx migrate run --source src/app_state/database/migrations --database-url sqlite://db.sqlite3 + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + + - name: Setup database + run: task db:setup - name: E2E tests run: | @@ -51,7 +52,7 @@ jobs: SERVER_PID=$! cd .. - scripts/e2e.sh 8 + task e2e -- 8 EXIT_CODE=$? kill $SERVER_PID 2>/dev/null || true @@ -69,4 +70,4 @@ jobs: - name: Cleanup if: always() - run: scripts/clean-up.sh + run: task clean diff --git a/.github/workflows/publish-plugin.yml b/.github/workflows/publish-plugin.yml index 452bc601..421dee5b 100644 --- a/.github/workflows/publish-plugin.yml +++ b/.github/workflows/publish-plugin.yml @@ -22,25 +22,27 @@ jobs: node-version: "25.x" check-latest: true - - name: Build plugin - run: | - cd frontend - npm ci - npm run build - - name: Setup Rust toolchain uses: dtolnay/rust-toolchain@stable with: toolchain: "1.92.0" components: clippy, rustfmt + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + - name: Install cross-compilation tools run: | apt update apt install -y gcc-aarch64-linux-gnu musl-tools gcc-mingw-w64-x86-64 - - name: Build Linux and Windows binaries - run: ./scripts/build-sync-server-binaries.sh + - name: Build frontend + run: task frontend:build + + - name: Build binaries + run: task release:build-binaries - name: Create release env: diff --git a/CLAUDE.md b/CLAUDE.md index 323681d9..ef5ea994 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,8 +49,24 @@ The sync-client builds two separate bundles: ## Development Commands +This project uses [Taskfile](https://taskfile.dev/) for task automation. Run `task --list` to see all available tasks. + ### Initial Setup +**Taskfile:** + +```bash +# Install Task (https://taskfile.dev/installation/) +# macOS +brew install go-task + +# Linux +sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin + +# Or via npm +npm install -g @go-task/cli +``` + **Node.js (requires version 25):** ```bash @@ -71,60 +87,89 @@ cargo install sqlx-cli cargo-machete cargo-edit cargo-insta **Frontend:** ```bash -cd frontend -npm install +task frontend:install ``` -### Server Development +### Common Tasks (Taskfile) + +```bash +task check # Full CI check (lint, test, format). Run before pushing. +task check:fix # Same as above but auto-fixes issues +task e2e -- 8 # E2E tests with 8 concurrent clients +task clean # Clean logs and database files +task update-api-types # Update TypeScript bindings from Rust types +task release:bump -- patch # Bump version (patch|minor|major) +``` + +### Server Tasks + +```bash +task rust:run # Start development server +task rust:test # Run all Rust tests +task rust:clippy # Lint Rust code +task rust:clippy-fix # Auto-fix clippy warnings +task rust:fmt # Format Rust code +task rust:fmt-check # Check Rust formatting +task rust:machete # Detect unused dependencies +``` + +### Frontend Tasks + +```bash +task frontend:dev # Start development mode +task frontend:build # Build all workspaces +task frontend:test # Run all frontend tests +task frontend:lint # Lint and format TypeScript +``` + +### Database Tasks + +```bash +task db:setup # Create and migrate database +task db:reset # Reset database (delete and recreate) +task db:prepare # Prepare SQLx offline data +task db:add-migration NAME= # Add new migration +``` + +### Documentation Tasks + +```bash +task docs:check # Build and check documentation +task docs:dev # Start documentation dev server +``` + +### Direct Commands (Alternative) + +If you prefer not to use Taskfile, these commands work directly: + +**Server:** ```bash cd sync-server cargo run config-e2e.yml # Start development server cargo test --verbose # Run all Rust tests -cargo test # Run specific test -cargo clippy --all-targets --all-features # Lint Rust code -cargo clippy --all-targets --all-features --fix --allow-dirty --allow-staged # Auto-fix clippy warnings -cargo fmt --all -- --check # Check Rust formatting -cargo fmt --all # Auto-format Rust code -cargo machete --with-metadata # Detect unused dependencies +cargo clippy --all-targets --all-features # Lint +cargo fmt --all # Format ``` -### Frontend Development +**Frontend:** ```bash cd frontend -npm run dev # Start development mode (watches sync-client and obsidian-plugin) +npm run dev # Development mode npm run build # Build all workspaces -npm run build -w sync-client # Build specific workspace -npm run test # Run all tests across all workspaces -npm run test -w sync-client # Run tests for specific workspace -npm run lint # Lint and format TypeScript code with ESLint + Prettier +npm run test # Run tests +npm run lint # Lint and format ``` -### Database Operations +**Database:** ```bash cd sync-server -# Create/reset database for development -rm -rf db.sqlite* sqlx database create --database-url sqlite://db.sqlite3 sqlx migrate run --source src/app_state/database/migrations --database-url sqlite://db.sqlite3 -cargo sqlx prepare --workspace - -# Add new migration -sqlx migrate add --source src/app_state/database/migrations -sqlx migrate run --source src/app_state/database/migrations --database-url sqlite://db.sqlite3 ``` -### Project Scripts - -- `scripts/check.sh`: Full CI check (builds, lints, tests both server and frontend). **Run before pushing.** -- `scripts/check.sh --fix`: Same as above but auto-fixes linting and formatting issues -- `scripts/e2e.sh`: End-to-end testing (e.g., `scripts/e2e.sh 8` for 8 concurrent clients) -- `scripts/clean-up.sh`: Clean logs and database files -- `scripts/bump-version.sh patch`: Publish new version (options: patch, minor, major) -- `scripts/update-api-types.sh`: Update TypeScript bindings from Rust types (uses ts-rs) - ## Code Structure ### Workspace Configuration @@ -141,7 +186,7 @@ The frontend uses npm workspaces with four packages: Rust structs generate TypeScript types via ts-rs crate: 1. Rust structs annotated with `#[derive(TS)]` export to `sync-server/bindings/` -2. Run `scripts/update-api-types.sh` to copy bindings to `frontend/sync-client/src/services/types/` +2. Run `task update-api-types` to copy bindings to `frontend/sync-client/src/services/types/` 3. Frontend imports these types for type-safe API communication ### Important Implementation Details @@ -156,25 +201,18 @@ Rust structs generate TypeScript types via ts-rs crate: ### Running Tests -**Server:** - ```bash -cargo test --verbose # All tests -cargo test # Specific test +task rust:test # All Rust tests +task frontend:test # All frontend tests +task e2e -- 8 # E2E with 8 concurrent clients +task clean # Clean up after tests ``` -**Frontend:** +Or use direct commands: ```bash -npm run test # All workspaces -npm run test -w sync-client # Specific workspace -``` - -**E2E:** - -```bash -scripts/e2e.sh 8 # 8 concurrent clients -scripts/clean-up.sh # Clean up after tests +cd sync-server && cargo test --verbose # Rust tests +cd frontend && npm run test # Frontend tests ``` ### Test Structure diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 00000000..0d7a1f1e --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,96 @@ +version: "3" + +vars: + NODE_VERSION: "25" + +includes: + rust: + taskfile: ./taskfiles/rust.yml + dir: ./sync-server + frontend: + taskfile: ./taskfiles/frontend.yml + dir: ./frontend + db: + taskfile: ./taskfiles/database.yml + dir: ./sync-server + e2e: + taskfile: ./taskfiles/e2e.yml + docs: + taskfile: ./taskfiles/docs.yml + dir: ./docs + release: + taskfile: ./taskfiles/release.yml + +tasks: + check: + desc: Run all checks (lint, test, format) + cmds: + - task: check-node + - task: db:setup + - task: rust:test + - task: rust:lint + - task: update-api-types + - task: frontend:install + - task: frontend:build + - task: frontend:test + - task: frontend:lint + - task: format + - task: check-clean + + check:fix: + desc: Run all checks with auto-fix enabled + cmds: + - task: check-node + - task: db:setup + - task: rust:test + - task: rust:lint-fix + - task: update-api-types + - task: frontend:install + - task: frontend:build + - task: frontend:test + - task: frontend:lint + - task: format + + check-node: + internal: true + silent: true + preconditions: + - sh: node -v | grep -q "^v{{.NODE_VERSION}}" + msg: "Node.js {{.NODE_VERSION}} required (found: $(node -v))" + cmds: + - echo "Node.js {{.NODE_VERSION}} confirmed" + + check-clean: + internal: true + preconditions: + - sh: test -z "$(git status --porcelain)" + msg: | + Working directory not clean after linting: + $(git status --porcelain) + + format: + desc: Format all files with Prettier + dir: "{{.ROOT_DIR}}" + cmds: + - npx -C frontend prettier --write "**/*.{ts,js,json,md,yml,yaml}" + + update-api-types: + desc: Update TypeScript bindings from Rust types + cmds: + - rm -rf sync-server/bindings + - task: rust:export-bindings + - cp -r sync-server/bindings/* frontend/sync-client/src/services/types/ + - cd frontend && npm run lint + - task: format + + clean: + desc: Clean up logs and databases + cmds: + - rm -rf sync-server/databases logs + + e2e: + desc: Run E2E tests (usage - task e2e -- 8) + cmds: + - task: e2e:run + vars: + PROCESS_COUNT: "{{.CLI_ARGS}}" diff --git a/scripts/build-docs.sh b/scripts/build-docs.sh deleted file mode 100755 index c87144a9..00000000 --- a/scripts/build-docs.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -set -e - -./scripts/utils/check-node.sh - -cd docs - -npm ci -npm run format:check -npm run spell:check -npm run build - -cd - diff --git a/scripts/build-sync-server-binaries.sh b/scripts/build-sync-server-binaries.sh deleted file mode 100755 index 8d690935..00000000 --- a/scripts/build-sync-server-binaries.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -set -e - -cd "$(dirname "$0")/../sync-server" - -# Setup database -sqlx database create --database-url sqlite://db.sqlite3 2>/dev/null || true -sqlx migrate run --source src/app_state/database/migrations --database-url sqlite://db.sqlite3 - -targets=${@:-"x86_64-unknown-linux-gnu x86_64-unknown-linux-musl aarch64-unknown-linux-gnu x86_64-pc-windows-gnu"} - -mkdir -p artifacts -rm -f artifacts/sync-server-* - - -for target in $targets; do - echo "Building $target..." - - # Set linkers for cross-compilation - case "$target" in - aarch64-unknown-linux-gnu) - export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc ;; - x86_64-unknown-linux-musl) - export CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER=musl-gcc ;; - x86_64-pc-windows-gnu) - export CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=x86_64-w64-mingw32-gcc ;; - esac - - rustup target add "$target" 2>/dev/null || true - - cargo build --release --target "$target" - ext="" - [[ "$target" == *windows* ]] && ext=".exe" - - name="sync-server-${target//-/_}$ext" - name="${name//x86_64_unknown_linux_gnu/linux-x86_64}" - name="${name//x86_64_unknown_linux_musl/linux-x86_64-musl}" - name="${name//aarch64_unknown_linux_gnu/linux-aarch64}" - name="${name//x86_64_pc_windows_gnu/windows-x86_64}" - - cp "target/$target/release/sync_server$ext" "artifacts/$name" - echo "✓ Built $name" -done diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh deleted file mode 100755 index bea3d982..00000000 --- a/scripts/bump-version.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -set -e - -if [[ -z $1 ]]; then - echo "Usage: $0 {patch|minor|major}" - exit 1 -fi - -if [[ $1 =~ ^(patch|minor|major)$ ]]; then - echo "Creating a new '$1' version" -else - echo "Invalid argument: $1" - echo "Usage: $0 {patch|minor|major}" - exit 1 -fi - -cargo install cargo-edit --force - -if [[ -n $(git status --porcelain) ]]; then - echo "Your working directory is not clean. Please commit or stash your changes before proceeding." - exit 1 -else - echo "Your working directory is clean." -fi - -echo "Bumping sync-server versions" -cd sync-server -cargo set-version --bump $1 - -echo "Bumping frontend versions" -cd ../frontend -npm version $1 --workspaces -cd .. - -cp frontend/obsidian-plugin/manifest.json manifest.json # for BRAT, otherwise it wouldn't update - -# Format all files across the project (frontend and backend) -npx -C frontend prettier --write "**/*.{ts,js,json,md,yml,yaml}" - -# Commit and tag -git add . -TAG=$(node -p "require('./frontend/obsidian-plugin/package.json').version") -git commit -m "Bump versions to $TAG" - -git push -echo "Tagging $TAG" -git tag -a $TAG -m "Release $TAG" -git push origin $TAG -echo "Done" diff --git a/scripts/check.sh b/scripts/check.sh deleted file mode 100755 index 2ee0dd62..00000000 --- a/scripts/check.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env bash - -set -e - -FIX_MODE=false -if [[ "$1" == "--fix" ]]; then - FIX_MODE=true - echo "Running in fix mode - will automatically fix linting and formatting issues" -fi - -./scripts/utils/check-node.sh - -echo "Running checks in sync-server" - -cd sync-server -which sqlx || cargo install sqlx-cli -sqlx database create --database-url sqlite://db.sqlite3 -sqlx migrate run --source src/app_state/database/migrations --database-url sqlite://db.sqlite3 - -cargo test --verbose - -if [[ "$FIX_MODE" == true ]]; then - cargo clippy --all-targets --all-features --fix --allow-dirty --allow-staged - cargo fmt --all -else - cargo clippy --all-targets --all-features - cargo fmt --all -- --check -fi - -which cargo-machete || cargo install cargo-machete -cargo machete --with-metadata - -cd .. -scripts/update-api-types.sh # this will dirty up the git state if not up-to-date - -echo "Running checks in frontend" -cd frontend - -if [[ "$FIX_MODE" == true ]]; then - npm install -else - npm ci -fi - -cd .. - -cd frontend -npm run build -npm run test -npm run lint -cd .. - -# Format all files across the project (frontend and backend) -# Prettier respects .gitignore by default -npx -C frontend prettier --write "**/*.{ts,js,json,md,yml,yaml}" - -if [[ "$FIX_MODE" == false ]] && [[ $(git status --porcelain) ]]; then - git status --porcelain - echo "Failing CI because the working directory is not clean after linting" - exit 1 -fi - -echo "Success" diff --git a/scripts/clean-up.sh b/scripts/clean-up.sh deleted file mode 100755 index 4dfbf4a0..00000000 --- a/scripts/clean-up.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -rm -rf sync-server/databases -rm -rf logs diff --git a/scripts/e2e.sh b/scripts/e2e.sh deleted file mode 100755 index d0e23260..00000000 --- a/scripts/e2e.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/bash - -set -e -set -o pipefail - -NO_COLOR=1 -FORCE_COLOR=0 - -./scripts/utils/check-node.sh - -# Check if the argument is provided -if [ $# -eq 0 ]; then - echo "Usage: $0 " - exit 1 -fi - -# Get the number of processes from the first argument -process_count=$1 - -mkdir -p logs - -cd frontend -npm ci -npm run build - -../scripts/utils/wait-for-server.sh - -pids=() -for i in $(seq 1 $process_count); do - # Create a named pipe for this process - pipe="/tmp/vaultlink_pipe_$$_$i" - mkfifo "$pipe" - - # Start the node process writing to the pipe - node test-client/dist/cli.js > "$pipe" 2>&1 & - pid=$! - pids+=($pid) - echo "Started process $i with PID: $pid" - - # Read from pipe, prefix with PID - (sed "s/^/[PID $pid] /" < "$pipe" > "../logs/log_${i}.log"; rm "$pipe") & -done - -cd .. - -print_failed_log() { - for i in $(seq 1 $process_count); do - if [ -n "${pids[$i-1]}" ] && ! kill -0 ${pids[$i-1]} 2>/dev/null; then - # Get the exit code of the process - wait ${pids[$i-1]} - exit_code=$? - - # Only consider non-zero exit codes as failures - if [ $exit_code -ne 0 ]; then - echo "----- Log for process ${pids[$i-1]} (log_${i}.log) -----" - cat "$(pwd)/logs/log_${i}.log" - echo "Process ${pids[$i-1]} failed with exit code $exit_code. Log file: $(pwd)/logs/log_${i}.log" - return 0 - else - echo "Process ${pids[$i-1]} completed successfully with exit code 0" - # Mark this PID as processed by setting it to empty - pids[$i-1]="" - fi - fi - done - return 1 -} - -echo "Monitoring $process_count processes" - -# Monitor processes -while true; do - if print_failed_log; then - # Kill remaining processes - for pid in "${pids[@]}"; do - if [ -n "$pid" ]; then - kill $pid 2>/dev/null || true - fi - done - exit 1 - fi - - # Check if all processes have completed - all_done=true - for pid in "${pids[@]}"; do - if [ -n "$pid" ] && kill -0 $pid 2>/dev/null; then - all_done=false - break - fi - done - - if $all_done; then - echo "All processes completed successfully" - exit 0 - fi - - sleep 0.2 -done diff --git a/scripts/update-api-types.sh b/scripts/update-api-types.sh deleted file mode 100755 index 36ca100d..00000000 --- a/scripts/update-api-types.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -set -e - -rm -rf sync-server/bindings - -cd sync-server -cargo test export_bindings -cd - - -cp -r sync-server/bindings/* frontend/sync-client/src/services/types/ - -cd frontend -npm run lint -cd .. - -# Format all files across the project (frontend and backend) -npx -C frontend prettier --write "**/*.{ts,js,json,md,yml,yaml}" diff --git a/scripts/utils/check-node.sh b/scripts/utils/check-node.sh deleted file mode 100755 index d93f2f27..00000000 --- a/scripts/utils/check-node.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -set -e - -TARGET_NODE_VERSION=25 - -node_version=$(node -v | sed 's/^v\([0-9]*\).*/\1/') -if [ "$node_version" != "$TARGET_NODE_VERSION" ]; then - echo "Error: This script requires Node.js version $TARGET_NODE_VERSION, found: $node_version" - exit 1 -fi diff --git a/scripts/utils/wait-for-server.sh b/scripts/utils/wait-for-server.sh deleted file mode 100755 index 7824c405..00000000 --- a/scripts/utils/wait-for-server.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -set -e - -SERVER_URL="http://localhost:3000" -MAX_RETRIES=30 -RETRY_INTERVAL_IN_SECONDS=5 - -echo "Waiting for $SERVER_URL to become available..." -count=0 -while [ $count -lt $MAX_RETRIES ]; do - if curl -s -f -o /dev/null $SERVER_URL; then - echo "$SERVER_URL is now available!" - break - fi - echo "Attempt $(($count+1))/$MAX_RETRIES: $SERVER_URL not available yet, retrying in ${RETRY_INTERVAL_IN_SECONDS}s..." - sleep $RETRY_INTERVAL_IN_SECONDS - count=$(($count+1)) -done - -if [ $count -eq $MAX_RETRIES ]; then - echo "Error: $SERVER_URL did not become available after $MAX_RETRIES attempts." - exit 1 -fi diff --git a/taskfiles/database.yml b/taskfiles/database.yml new file mode 100644 index 00000000..3ed4f6d1 --- /dev/null +++ b/taskfiles/database.yml @@ -0,0 +1,25 @@ +version: "3" + +vars: + DATABASE_URL: "sqlite://db.sqlite3" + MIGRATIONS_PATH: "src/app_state/database/migrations" + +tasks: + setup: + desc: Create and migrate database + sources: + - "{{.MIGRATIONS_PATH}}/**/*.sql" + generates: + - "db.sqlite3" + cmds: + - which sqlx || cargo install sqlx-cli + - sqlx database create --database-url {{.DATABASE_URL}} 2>/dev/null || true + - sqlx migrate run --source {{.MIGRATIONS_PATH}} --database-url {{.DATABASE_URL}} + - cargo sqlx prepare --workspace + + add-migration: + desc: Add a new migration + requires: + vars: [NAME] + cmds: + - sqlx migrate add --source {{.MIGRATIONS_PATH}} {{.NAME}} diff --git a/taskfiles/docs.yml b/taskfiles/docs.yml new file mode 100644 index 00000000..06351b5e --- /dev/null +++ b/taskfiles/docs.yml @@ -0,0 +1,35 @@ +version: "3" + +tasks: + install: + desc: Install docs dependencies + run: once + cmds: + - npm ci + + build: + desc: Build documentation + deps: [install] + cmds: + - npm run build + + lint: + desc: Check formatting and spelling + deps: [install] + cmds: + - npm run format:check + - npm run spell:check + + check: + desc: Run all documentation checks + cmds: + - task: :check-node + - task: install + - task: lint + - task: build + + dev: + desc: Start documentation dev server + deps: [install] + cmds: + - npm run dev diff --git a/taskfiles/e2e.yml b/taskfiles/e2e.yml new file mode 100644 index 00000000..5e38e45a --- /dev/null +++ b/taskfiles/e2e.yml @@ -0,0 +1,134 @@ +version: "3" + +vars: + SERVER_URL: "http://localhost:3000" + MAX_RETRIES: 30 + RETRY_INTERVAL: 5 + LOG_DIR: "{{.ROOT_DIR}}/logs" + +tasks: + run: + desc: Run E2E tests with specified number of processes + summary: | + Runs multiple concurrent test clients against the sync server. + Each client performs random file operations to test synchronization. + + Usage: task e2e -- + Example: task e2e -- 8 + deps: [prepare] + requires: + vars: [PROCESS_COUNT] + preconditions: + - sh: test "{{.PROCESS_COUNT}}" -ge 1 2>/dev/null + msg: "PROCESS_COUNT must be a positive integer (got: {{.PROCESS_COUNT}})" + dir: "{{.ROOT_DIR}}" + env: + NO_COLOR: "1" + FORCE_COLOR: "0" + cmds: + - task: wait-for-server + - task: setup-logs + - defer: { task: cleanup-pipes } + - task: spawn-clients + + prepare: + desc: Build frontend for E2E tests + internal: true + dir: "{{.ROOT_DIR}}" + cmds: + - task: :check-node + - task: :frontend:build + + wait-for-server: + desc: Wait for server to become available + internal: true + silent: true + cmds: + - for: { var: ATTEMPTS, split: "\n" } + cmd: | + if curl -s -f -o /dev/null {{.SERVER_URL}}; then + echo "Server available at {{.SERVER_URL}}" + exit 0 + fi + echo "Attempt {{.ITEM}}/{{.MAX_RETRIES}}: waiting {{.RETRY_INTERVAL}}s..." + sleep {{.RETRY_INTERVAL}} + if [ "{{.ITEM}}" = "{{.MAX_RETRIES}}" ]; then + echo "Error: Server not available after {{.MAX_RETRIES}} attempts" + exit 1 + fi + vars: + ATTEMPTS: + sh: seq 1 {{.MAX_RETRIES}} + + setup-logs: + internal: true + status: + - test -d {{.LOG_DIR}} + cmds: + - mkdir -p {{.LOG_DIR}} + + cleanup-pipes: + internal: true + cmds: + - rm -f /tmp/vaultlink_pipe_* 2>/dev/null || true + + spawn-clients: + internal: true + dir: "{{.ROOT_DIR}}/frontend" + set: [errexit, pipefail] + cmds: + - | + pids=() + + # Start all client processes + for i in $(seq 1 {{.PROCESS_COUNT}}); do + pipe="/tmp/vaultlink_pipe_$$_$i" + mkfifo "$pipe" + node test-client/dist/cli.js > "$pipe" 2>&1 & + pid=$! + pids+=($pid) + echo "Started client $i (PID: $pid)" + (sed "s/^/[PID $pid] /" < "$pipe" > "{{.LOG_DIR}}/log_${i}.log"; rm "$pipe") & + done + + echo "Monitoring {{.PROCESS_COUNT}} client processes..." + + # Monitor loop + while true; do + # Check for failures + for i in $(seq 1 {{.PROCESS_COUNT}}); do + idx=$((i-1)) + pid=${pids[$idx]} + [ -z "$pid" ] && continue + + if ! kill -0 $pid 2>/dev/null; then + wait $pid + code=$? + if [ $code -ne 0 ]; then + echo "Client $i (PID $pid) failed with exit code $code" + echo "===== Log: {{.LOG_DIR}}/log_${i}.log =====" + cat "{{.LOG_DIR}}/log_${i}.log" + # Kill remaining processes + for p in "${pids[@]}"; do + [ -n "$p" ] && kill $p 2>/dev/null || true + done + exit 1 + fi + echo "Client $i (PID $pid) completed successfully" + pids[$idx]="" + fi + done + + # Check if all done + all_done=true + for pid in "${pids[@]}"; do + [ -n "$pid" ] && kill -0 $pid 2>/dev/null && all_done=false && break + done + + if $all_done; then + echo "All {{.PROCESS_COUNT}} clients completed successfully" + exit 0 + fi + + sleep 0.2 + done diff --git a/taskfiles/frontend.yml b/taskfiles/frontend.yml new file mode 100644 index 00000000..7c0e5280 --- /dev/null +++ b/taskfiles/frontend.yml @@ -0,0 +1,41 @@ +version: "3" + +tasks: + install: + desc: Install frontend dependencies + run: once + cmds: + - npm ci + + build: + desc: Build all frontend workspaces + deps: [install] + cmds: + - npm run build + + test: + desc: Run all frontend tests + cmds: + - npm run test + + lint: + desc: Lint and format TypeScript code + cmds: + - npm run lint + + dev: + desc: Start development mode + cmds: + - npm run dev + + workspace: + desc: Run npm script in specific workspace + summary: | + Run any npm script in a specific workspace. + + Usage: task frontend:workspace WORKSPACE= SCRIPT=