diff --git a/.github/actions/dashboard-build/action.yml b/.github/actions/dashboard-build/action.yml new file mode 100644 index 0000000..60f6f36 --- /dev/null +++ b/.github/actions/dashboard-build/action.yml @@ -0,0 +1,45 @@ +name: Build dashboard +description: >- + Sets up Node and pnpm, installs dashboard dependencies, generates the + TanStack Router tree, and runs the Vite production build. Output is + written to `py_src/taskito/static/dashboard/` for packaging into the + Python wheel. + +runs: + using: composite + steps: + - name: Set up pnpm + uses: pnpm/action-setup@v6 + with: + version: "10.30.3" + + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + node-version: "22" + cache: pnpm + cache-dependency-path: dashboard/pnpm-lock.yaml + + - name: Install dashboard dependencies + shell: bash + working-directory: dashboard + run: pnpm install --frozen-lockfile + + - name: Generate TanStack Router tree + shell: bash + working-directory: dashboard + run: pnpm exec tsr generate + + - name: Vite production build + shell: bash + working-directory: dashboard + run: pnpm exec vite build + + - name: Verify build output + shell: bash + run: | + set -euo pipefail + if [ ! -f py_src/taskito/static/dashboard/index.html ]; then + echo "::error::Dashboard build did not produce py_src/taskito/static/dashboard/index.html" + exit 1 + fi diff --git a/.github/workflows/dashboard.yml b/.github/workflows/dashboard.yml index d652702..a450069 100644 --- a/.github/workflows/dashboard.yml +++ b/.github/workflows/dashboard.yml @@ -6,47 +6,29 @@ on: paths: - "dashboard/**" - ".github/workflows/dashboard.yml" + - ".github/actions/dashboard-build/**" pull_request: branches: [master] paths: - "dashboard/**" - ".github/workflows/dashboard.yml" + - ".github/actions/dashboard-build/**" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -defaults: - run: - working-directory: dashboard - jobs: ci: name: lint · typecheck · test · build runs-on: ubuntu-latest timeout-minutes: 10 + defaults: + run: + working-directory: dashboard steps: - uses: actions/checkout@v6 - - - name: Set up pnpm - uses: pnpm/action-setup@v6 - with: - version: "10.30.3" - - - name: Set up Node.js - uses: actions/setup-node@v6 - with: - node-version: "22" - cache: "pnpm" - cache-dependency-path: dashboard/pnpm-lock.yaml - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Generate route tree - # TanStack Router's file-based tree is a build artifact; tsc needs - # it to resolve route imports. - run: pnpm exec tsr generate + - uses: ./.github/actions/dashboard-build - name: Biome (lint + format) run: pnpm exec biome ci src/ @@ -57,11 +39,9 @@ jobs: - name: Unit tests (vitest) run: pnpm exec vitest run - - name: Build - run: pnpm exec vite build - - name: Bundle size summary if: always() + working-directory: ${{ github.workspace }} run: | set -e { @@ -69,10 +49,10 @@ jobs: echo echo "| File | Size | Gzipped |" echo "|------|-----:|--------:|" - find ../py_src/taskito/static/dashboard -type f \( -name "*.js" -o -name "*.css" -o -name "*.html" \) | sort | while read -r f; do + find py_src/taskito/static/dashboard -type f \( -name "*.js" -o -name "*.css" -o -name "*.html" \) | sort | while read -r f; do raw=$(stat -c%s "$f") gz=$(gzip -c "$f" | wc -c) - printf "| \`%s\` | %s | %s |\n" "${f#../py_src/taskito/static/dashboard/}" "$(numfmt --to=iec --suffix=B "$raw")" "$(numfmt --to=iec --suffix=B "$gz")" + printf "| \`%s\` | %s | %s |\n" "${f#py_src/taskito/static/dashboard/}" "$(numfmt --to=iec --suffix=B "$raw")" "$(numfmt --to=iec --suffix=B "$gz")" done } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 047b21c..9db78f3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -8,7 +8,24 @@ permissions: contents: read jobs: + build-dashboard: + name: Build dashboard assets + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - uses: ./.github/actions/dashboard-build + + - name: Upload dashboard artifact + uses: actions/upload-artifact@v7 + with: + name: dashboard-dist + path: py_src/taskito/static/dashboard + if-no-files-found: error + retention-days: 1 + build-wheels-linux: + needs: build-dashboard runs-on: ${{ matrix.os }} strategy: matrix: @@ -20,6 +37,16 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Download dashboard assets + uses: actions/download-artifact@v8 + with: + name: dashboard-dist + path: py_src/taskito/static/dashboard + + - name: Verify dashboard assets present + shell: bash + run: test -f py_src/taskito/static/dashboard/index.html + - name: Build wheels uses: PyO3/maturin-action@v1 with: @@ -34,8 +61,10 @@ jobs: with: name: wheels-linux-${{ matrix.target }} path: dist/*.whl + if-no-files-found: error build-wheels-musllinux: + needs: build-dashboard runs-on: ${{ matrix.os }} strategy: matrix: @@ -47,6 +76,16 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Download dashboard assets + uses: actions/download-artifact@v8 + with: + name: dashboard-dist + path: py_src/taskito/static/dashboard + + - name: Verify dashboard assets present + shell: bash + run: test -f py_src/taskito/static/dashboard/index.html + - name: Build wheels uses: PyO3/maturin-action@v1 with: @@ -61,8 +100,10 @@ jobs: with: name: wheels-musllinux-${{ matrix.target }} path: dist/*.whl + if-no-files-found: error build-wheels-macos: + needs: build-dashboard runs-on: macos-latest strategy: matrix: @@ -72,6 +113,16 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Download dashboard assets + uses: actions/download-artifact@v8 + with: + name: dashboard-dist + path: py_src/taskito/static/dashboard + + - name: Verify dashboard assets present + shell: bash + run: test -f py_src/taskito/static/dashboard/index.html + - name: Set up Python 3.10 uses: actions/setup-python@v6 with: @@ -103,8 +154,10 @@ jobs: with: name: wheels-macos-${{ matrix.target }} path: dist/*.whl + if-no-files-found: error build-wheels-windows: + needs: build-dashboard runs-on: windows-latest strategy: matrix: @@ -113,6 +166,16 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Download dashboard assets + uses: actions/download-artifact@v8 + with: + name: dashboard-dist + path: py_src/taskito/static/dashboard + + - name: Verify dashboard assets present + shell: bash + run: test -f py_src/taskito/static/dashboard/index.html + - name: Set up Python 3.10 uses: actions/setup-python@v6 with: @@ -144,12 +207,24 @@ jobs: with: name: wheels-windows-${{ matrix.target }} path: dist/*.whl + if-no-files-found: error build-sdist: + needs: build-dashboard runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + - name: Download dashboard assets + uses: actions/download-artifact@v8 + with: + name: dashboard-dist + path: py_src/taskito/static/dashboard + + - name: Verify dashboard assets present + shell: bash + run: test -f py_src/taskito/static/dashboard/index.html + - name: Build sdist uses: PyO3/maturin-action@v1 with: @@ -161,6 +236,7 @@ jobs: with: name: sdist path: dist/*.tar.gz + if-no-files-found: error publish: needs: [build-wheels-linux, build-wheels-musllinux, build-wheels-macos, build-wheels-windows, build-sdist] @@ -169,9 +245,10 @@ jobs: permissions: id-token: write steps: - - name: Download all artifacts + - name: Download wheel and sdist artifacts uses: actions/download-artifact@v8 with: + pattern: "{wheels-*,sdist}" path: dist merge-multiple: true diff --git a/crates/taskito-async/Cargo.toml b/crates/taskito-async/Cargo.toml index fa20139..da71bd9 100644 --- a/crates/taskito-async/Cargo.toml +++ b/crates/taskito-async/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "taskito-async" -version = "0.12.0" +version = "0.12.1" edition = "2021" [dependencies] diff --git a/crates/taskito-core/Cargo.toml b/crates/taskito-core/Cargo.toml index c9982eb..b763243 100644 --- a/crates/taskito-core/Cargo.toml +++ b/crates/taskito-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "taskito-core" -version = "0.12.0" +version = "0.12.1" edition = "2021" [features] diff --git a/crates/taskito-python/Cargo.toml b/crates/taskito-python/Cargo.toml index 07b1563..17b455b 100644 --- a/crates/taskito-python/Cargo.toml +++ b/crates/taskito-python/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "taskito-python" -version = "0.12.0" +version = "0.12.1" edition = "2021" [features] diff --git a/crates/taskito-workflows/Cargo.toml b/crates/taskito-workflows/Cargo.toml index 3883fe9..9a57557 100644 --- a/crates/taskito-workflows/Cargo.toml +++ b/crates/taskito-workflows/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "taskito-workflows" -version = "0.12.0" +version = "0.12.1" edition = "2021" [dependencies] diff --git a/docs/content/docs/more/changelog.mdx b/docs/content/docs/more/changelog.mdx index c3f60d7..a8a9ccc 100644 --- a/docs/content/docs/more/changelog.mdx +++ b/docs/content/docs/more/changelog.mdx @@ -5,6 +5,18 @@ description: "Release history for taskito — every notable change, fix, and fea All notable changes to taskito are documented here. +## 0.12.1 + +### Fixed + +- **PyPI wheels and sdist now bundle the compiled dashboard.** A regression in 0.12.0 shipped wheels with an empty `taskito/static/` directory because the release pipeline ran `maturin build` without first building the dashboard frontend. End users hit `Dashboard assets not bundled` when running `taskito dashboard`. The release pipeline now builds the dashboard once in a dedicated job, distributes it to every wheel/sdist job as a build artifact, and verifies `static/dashboard/index.html` is present before each `maturin build` invocation — preventing the regression class entirely. + +### Internal + +- **`.github/actions/dashboard-build/`** — composite action centralizing pnpm/Node toolchain versions and the dashboard build steps. Consumed by both `publish.yml` (release) and `dashboard.yml` (CI), so the assets shipped in a wheel are produced by the exact same build path that CI tests on every PR. + +--- + ## 0.12.0 ### Added diff --git a/py_src/taskito/__init__.py b/py_src/taskito/__init__.py index caa29dd..baa36d1 100644 --- a/py_src/taskito/__init__.py +++ b/py_src/taskito/__init__.py @@ -99,4 +99,4 @@ __version__ = _get_version("taskito") except PackageNotFoundError: - __version__ = "0.12.0" + __version__ = "0.12.1" diff --git a/pyproject.toml b/pyproject.toml index 72fd3f7..8307412 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "taskito" -version = "0.12.0" +version = "0.12.1" description = "Rust-powered task queue for Python. No broker required." requires-python = ">=3.10" license = { file = "LICENSE" } @@ -50,6 +50,12 @@ manifest-path = "crates/taskito-python/Cargo.toml" python-source = "py_src" module-name = "taskito._taskito" features = ["extension-module", "postgres", "redis", "workflows"] +# Maturin's `python-source` only auto-packages Python sources (`.py`, `.pyi`, +# `py.typed`). The compiled dashboard SPA must be opted in explicitly so it +# ships in both the wheel and the sdist. +include = [ + { path = "py_src/taskito/static/dashboard/**/*", format = ["wheel", "sdist"] }, +] [project.scripts] taskito = "taskito.cli:main"