chore: setup CI scripts (#6)

* wip: workflows

* wip: fix up issues in ci scripts and fix frontend lint errors

* wip: fix backend lints

* remove unused deps

* wip: build frontend in test.yml

* wip: attempt to improve Rust caching

* wip: testing release

* wip: linear release flow

* wip: check against both package.json versions

* wip: spurious attempt to get Rust caching

* wip: more cache

* merge release and publish jobs; add more caching to release flow

* decouple github releases and npm publishing

* update pack flow

---------

Co-authored-by: couscous <couscous@runner.com>
This commit is contained in:
Gabriel Gordon-Hall
2025-06-27 13:32:32 +01:00
committed by GitHub
parent b25f81504a
commit 340b094c75
33 changed files with 620 additions and 280 deletions

136
.github/workflows/pre-release.yml vendored Normal file
View File

@@ -0,0 +1,136 @@
# To pre-release:
# ```
# git tag -a v0.1.0 -m "Release 0.1.0"
# git push origin v0.1.0
# ```
name: Create GitHub Pre-Release
on:
push:
tags:
- "v*.*.*"
concurrency:
group: release
cancel-in-progress: true
permissions:
contents: write
packages: write
pull-requests: write
env:
NODE_VERSION: 22
PNPM_VERSION: 10.8.1
TAG_REGEX: '^v[0-9]+\.[0-9]+\.[0-9]+$'
jobs:
tag-check:
runs-on: ubuntu-latest
if: github.ref_type == 'tag'
steps:
- uses: actions/checkout@v4
- name: Validate tag matches package.json version
shell: bash
run: |
set -euo pipefail
echo "::group::Tag validation"
# 1. Must be a tag and match the regex
[[ "${GITHUB_REF_TYPE}" == "tag" ]] \
|| { echo "❌ Not a tag push"; exit 1; }
[[ "${GITHUB_REF_NAME}" =~ ${TAG_REGEX} ]] \
|| { echo "❌ Tag '${GITHUB_REF_NAME}' != ${TAG_REGEX}"; exit 1; }
# 2. Extract versions
tag_ver="${GITHUB_REF_NAME#v}"
package_ver="$(node -p "require('./package.json').version")"
cli_package_ver="$(node -p "require('./npx-cli/package.json').version")"
# 3. Compare
[[ "${tag_ver}" == "${package_ver}" ]] \
|| { echo "❌ Tag ${tag_ver} ≠ package.json ${package_ver}"; exit 1; }
# 4. Compare tag with npx-cli package.json
[[ "${tag_ver}" == "${cli_package_ver}" ]] \
|| { echo "❌ Tag ${tag_ver} ≠ npx-cli package.json ${cli_package_ver}"; exit 1; }
echo "✅ Tag and package.json agree (${tag_ver})"
echo "::endgroup::"
create-prerelease:
needs: tag-check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Install dependencies
run: pnpm install
- name: Lint frontend
run: cd frontend && npm run lint
- name: Type check frontend
run: cd frontend && npx tsc --noEmit
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: nightly-2025-05-18
components: rustfmt, clippy
- name: Build frontend
run: npm run frontend:build
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
env:
RUST_CACHE_DEBUG: true
with:
workspaces: "backend"
- name: Checks
run: |
cargo fmt --all -- --check
cargo test --workspace
cargo clippy --all --all-targets --all-features -- -D warnings
- name: Build backend
run: cargo build --release --manifest-path backend/Cargo.toml
- name: Get version from tag
id: get-version
run: echo "version=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT
- name: Zip backend
run: |
mkdir vibe-kanban-${{ github.ref_name }}
mv target/release/vibe-kanban vibe-kanban-${{ github.ref_name }}
mv frontend/dist vibe-kanban-${{ github.ref_name }}
zip -r vibe-kanban-${{ github.ref_name }}.zip vibe-kanban-${{ github.ref_name }}
- name: Code sign
run: echo "pass"
- name: Pack
run: |
mkdir -p npx-cli/dist/linux-x64
mv vibe-kanban-${{ github.ref_name }}.zip npx-cli/dist/linux-x64
cd npx-cli
npm pack
- name: Create GitHub Pre-Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: Pre-release ${{ github.ref_name }}
prerelease: true
generate_release_notes: true
files: |
vibe-kanban-${{ github.ref_name }}.zip
npx-cli/vibe-kanban-*.tgz

114
.github/workflows/publish.yml vendored Normal file
View File

@@ -0,0 +1,114 @@
name: Publish to npm
on:
release:
types: [released]
concurrency:
group: publish
cancel-in-progress: true
permissions:
contents: read
packages: write
env:
NODE_VERSION: 22
PNPM_VERSION: 10.8.1
jobs:
publish:
runs-on: ubuntu-latest
# Only run if this was converted from a pre-release
if: github.event.release.prerelease == false
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.release.tag_name }}
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Configure npm authentication
run: |
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
- name: Download release assets
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
// Get the release assets
const release = await github.rest.repos.getRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: context.payload.release.id
});
// Find the .tgz file
const tgzAsset = release.data.assets.find(asset => asset.name.endsWith('.tgz'));
if (!tgzAsset) {
core.setFailed('No .tgz file found in release assets');
return;
}
// Download the asset
const response = await github.rest.repos.getReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
asset_id: tgzAsset.id,
headers: {
Accept: 'application/octet-stream'
}
});
// Save to npx-cli directory
const filePath = path.join('npx-cli', tgzAsset.name);
fs.writeFileSync(filePath, Buffer.from(response.data));
console.log(`Downloaded ${tgzAsset.name} to ${filePath}`);
// Set output for next step
core.setOutput('package-file', filePath);
core.setOutput('package-name', tgzAsset.name);
- name: Verify package integrity
id: verify
run: |
cd npx-cli
# List files to confirm download
ls -la *.tgz
# Verify the package can be read
npm pack --dry-run || echo "Note: This is expected to show differences since we're using the pre-built package"
# Extract package name from the downloaded file
PACKAGE_FILE=$(ls *.tgz | head -n1)
echo "package-file=$PACKAGE_FILE" >> $GITHUB_OUTPUT
- name: Publish to npm
run: |
cd npx-cli
# Publish the exact same package that was tested
PACKAGE_FILE="${{ steps.verify.outputs.package-file }}"
echo "Publishing $PACKAGE_FILE to npm..."
npm publish "$PACKAGE_FILE"
echo "✅ Successfully published to npm!"
- name: Update release description
uses: actions/github-script@v7
with:
script: |
await github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: context.payload.release.id,
body: context.payload.release.body + '\n\n✅ **Published to npm registry**'
});

57
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,57 @@
name: Test
on:
pull_request:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
env:
CARGO_TERM_COLOR: always
NODE_VERSION: 22
PNPM_VERSION: 10.8.1
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Install dependencies
run: pnpm install
- name: Lint frontend
run: cd frontend && npm run lint
- name: Format check frontend
run: cd frontend && npm run format:check
- name: Type check frontend
run: cd frontend && npx tsc --noEmit
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: nightly-2025-05-18
components: rustfmt, clippy
- name: Build frontend
run: cd frontend && npm run build
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
env:
RUST_CACHE_DEBUG: true
with:
workspaces: "backend"
- name: Checks
run: |
cargo fmt --all -- --check
cargo test --workspace
cargo clippy --all --all-targets --all-features -- -D warnings