Skip to content

gtbuchanan/tooling

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

69 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@gtbuchanan/tooling

Shared build configuration monorepo for JavaScript/TypeScript projects.

Packages

Package Description
@gtbuchanan/cli Shared build CLI (gtb)
@gtbuchanan/eslint-config Shared ESLint configuration
@gtbuchanan/markdownlint-config Shared markdownlint configuration
@gtbuchanan/oxfmt-config Shared oxfmt configuration
@gtbuchanan/oxlint-config Shared oxlint configuration
@gtbuchanan/tsconfig Shared TypeScript base configuration
@gtbuchanan/vitest-config Shared Vitest configuration

Reusable Workflows

All workflows are reusable via workflow_call. Consuming repos create thin wrappers that delegate to this repo's workflows:

# .github/workflows/ci.yml
on:
  pull_request:
    branches: [main]
jobs:
  ci:
    uses: gtbuchanan/tooling/.github/workflows/ci.yml@main

Each workflow follows this same pattern — only the filename and trigger differ:

Workflow Trigger Description
ci.yml PR Build + e2e + optional slow tests
cd.yml Push to main CI + changesets version + publish (OIDC)
changeset-check.yml PR Verify changeset exists
pre-commit.yml PR Run prek hooks on changed files
pre-commit-seed.yml Push to main Warm prek cache for PR builds

Coverage

CI automatically uploads coverage to Codecov via a per-package turbo task. The workflow installs the Codecov CLI and runs coverage:codecov:upload per package. Turbo caches uploads based on coverage content — unchanged packages are skipped and Codecov carries forward their last known data.

Add a CODECOV_TOKEN repository secret and pass it through workflow_call:

jobs:
  ci:
    uses: gtbuchanan/tooling/.github/workflows/ci.yml@main
    secrets:
      CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

To customize coverage targets, add a codecov.yml to your repo root.

Drift risk: The Codecov job uses continue-on-error so upload failures never block PRs. Flags use carryforward: true because Codecov treats missing flags as 0% coverage, which would cause false failures on PRs that only touch a subset of packages. The tradeoff is that a failed upload carries forward stale data. In practice this self-corrects: cd.yml re-runs CI on merge to main, uploading fresh coverage. Drift only persists if that upload also fails — re-run the main workflow to correct it.

Repos customize behavior through Turborepo task graphs generated by gtb turbo:init. Per-package scripts delegate to gtb leaf commands, and consumers can replace script values to customize individual tools. ci.yml also accepts workflow inputs (run-e2e, run-slow-tests) for toggling test tiers. See the CLI package for available commands.

Build pipeline conventions

Turborepo manages task orchestration. The task graph is defined in turbo.json (generated by gtb turbo:init) and declares dependencies between leaf tasks:

typecheck:ts ─┬─ lint:eslint  ─┐
              ├─ lint:oxlint  ─┤ lint ─┐
              └─ test:vitest:fast ─────┤ check ─┬─ compile:ts → pack
                                       │        ├─ test:vitest:slow
                                       │        └─ test:vitest:e2e
                                       └────────────────── build

Turbo resolves the graph, caches results, and runs tasks in parallel where dependencies allow.

The build:ci task produces two outputs:

  • packages/*/dist/source/ — publishable contents per package
  • dist/packages/*.tgz — tarballs for e2e tests

Consumer customization:

  • Consumers replace the values of generated package.json scripts to override individual tools. There is no hook system — turbo:init generates the scripts, and consumers edit them directly.
  • publishConfig.directory — Set to dist/source for packages that need a clean publish directory. The pack command generates package.json and .npmignore there automatically.

CD requires:

  • release GitHub environment with npm trusted publishing (OIDC)
  • A GitHub App with contents: write and pull-requests: write permissions installed on the repo (so changeset PRs trigger checks)
  • Repo variable APP_ID and repo secret APP_PRIVATE_KEY from the App
  • @changesets/cli as a devDependency

Development

pnpm install
pnpm build

Scripts

Top-level scripts delegate to Turborepo:

  • pnpm check — Typecheck, lint, and test:fast (use during development)
  • pnpm build — Full pipeline: check + test:slow + pack + test:e2e
  • pnpm build:ci — CI pipeline: check + pack (slow/e2e run as separate jobs)

Turbo tasks can also be run individually:

  • turbo run typecheck:ts — TypeScript type-checking
  • turbo run lint — oxlint + ESLint (aggregate)
  • turbo run test:vitest:fast — Fast source tests only
  • turbo run test:vitest:slow — Slow source tests only (tagged slow)

All commands go through Turbo for caching:

  • pnpm pack — Pack tarballs (per-package pack:npm via Turbo)
  • pnpm test:e2e — E2E tests (Turbo cache restores tarballs)

Consumer setup

Run gtb turbo:init to generate turbo.json and per-package scripts from project discovery. Use --force to overwrite existing scripts. Run gtb turbo:check to verify generated config hasn't drifted.

See the CLI package for all available commands.

Versioning

Uses changesets for per-package versioning. Every PR requires a changeset — CI enforces this.

  • pnpm exec changeset — declare which packages changed and the bump type
  • pnpm exec changeset --empty — for PRs that don't need a version bump (CI changes, docs, etc.)

About

Shared tooling/build configuration monorepo

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors