From 19e5133a96a9b65034eb3d1428666854b005e607 Mon Sep 17 00:00:00 2001 From: Matthew L McPeak Date: Thu, 11 Jun 2026 16:37:40 -0400 Subject: [PATCH] feat: CI --- .dockerignore | 13 + .forgejo/workflows/ci.yml | 100 ++++++++ .../plans/2026-06-11-docs-site-and-docker.md | 222 ++++++++++++++++++ .../2026-06-11-docs-site-and-docker-design.md | 55 +++++ packages/playground/.storybook/main.ts | 2 +- packages/playground/Dockerfile | 12 + packages/playground/stories/Install.mdx | 41 ++++ 7 files changed, 444 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 .forgejo/workflows/ci.yml create mode 100644 docs/superpowers/plans/2026-06-11-docs-site-and-docker.md create mode 100644 docs/superpowers/specs/2026-06-11-docs-site-and-docker-design.md create mode 100644 packages/playground/Dockerfile create mode 100644 packages/playground/stories/Install.mdx diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4411221 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +node_modules +**/node_modules +**/dist +**/storybook-static +**/.storybook-static +.git +docs +.tmp +.bun-cache +.pw-browsers +.pw-libs +.shots +*.log diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml new file mode 100644 index 0000000..42044cc --- /dev/null +++ b/.forgejo/workflows/ci.yml @@ -0,0 +1,100 @@ +name: ci + +on: + push: + tags: + - 'v*' + pull_request: + +jobs: + build: + runs-on: docker + container: oven/bun:1 + steps: + - name: Install git + run: apt-get update && apt-get install -y git nodejs + + - name: Checkout + uses: actions/checkout@v4 + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Audit dependencies + run: bun audit + + - name: Run unit tests + run: bun run test:unit run + + - name: Type check + run: bun run type-check -- --force + + - name: Build + run: bun run build-only + + - name: Upload dist + uses: actions/upload-artifact@v4 + with: + name: dist + path: packages/library/dist + + publish: + needs: build + if: startsWith(github.ref, 'refs/tags/v') + runs-on: docker + container: oven/bun:1 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Download dist + uses: actions/download-artifact@v4 + with: + name: dist + path: packages/library/dist + + - name: Set package version + run: bun pm version "${GITHUB_REF_NAME#v}" --no-git-tag-version + working-directory: packages/library + + - name: Configure registry auth + run: echo "//git.mcpeakdev.com/api/packages/mcpeakdev/npm/:_authToken=${FORGEJO_TOKEN}" > .npmrc + working-directory: packages/library + env: + FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }} + + - name: Publish package + run: bun publish --registry https://git.mcpeakdev.com/api/packages/mcpeakdev/npm/ + working-directory: packages/library + + publish-docs: + needs: build + if: startsWith(github.ref, 'refs/tags/v') + runs-on: docker + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Log in to registry + uses: docker/login-action@v3 + with: + registry: git.mcpeakdev.com + username: ${{ github.actor }} + password: ${{ secrets.FORGEJO_TOKEN }} + + - name: Extract image tag + id: meta + run: echo "tag=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" + + - name: Build and push docs image + uses: docker/build-push-action@v6 + with: + context: . + file: packages/playground/Dockerfile + push: true + tags: | + git.mcpeakdev.com/mcpeakdev/nychthemeron-docs:${{ steps.meta.outputs.tag }} + git.mcpeakdev.com/mcpeakdev/nychthemeron-docs:latest diff --git a/docs/superpowers/plans/2026-06-11-docs-site-and-docker.md b/docs/superpowers/plans/2026-06-11-docs-site-and-docker.md new file mode 100644 index 0000000..b5a1360 --- /dev/null +++ b/docs/superpowers/plans/2026-06-11-docs-site-and-docker.md @@ -0,0 +1,222 @@ +# Docs Site Docker Image + Install Page Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add an Installation page to the Storybook playground, package the playground's static build as a `nychthemeron-docs` Docker image served by nginx, and wire up CI to build/push that image on version tags. + +**Architecture:** A new MDX docs page (`packages/playground/stories/Install.mdx`) documents installing `@nychthemeron/library` via npm/pnpm/yarn/bun from the private Forgejo npm registry. A new multi-stage `packages/playground/Dockerfile` builds the library and Storybook static output with `oven/bun:1`, then copies `storybook-static` into `nginx:alpine`. A root `.dockerignore` keeps the build context lean. A new `publish-docs` job in `.forgejo/workflows/ci.yml`, parallel to `publish`, builds and pushes the image on `v*` tags. + +**Tech Stack:** Storybook 10 (`@storybook/addon-docs`), Vue 3, Bun, Docker (multi-stage, nginx:alpine), Forgejo Actions. + +--- + +### Task 1: Add Installation MDX page + +**Files:** +- Create: `packages/playground/stories/Install.mdx` + +- [ ] **Step 1: Create the MDX file** + +```mdx +import { Meta } from '@storybook/addon-docs/blocks' + + + +# Installation + +`@nychthemeron/library` is published to a private npm registry hosted on +Forgejo. Configure your package manager for the `@nychthemeron` scope, then +install the package. + +## Configure the registry + +Add the following to your project's `.npmrc`: + +``` +@nychthemeron:registry=https://git.mcpeakdev.com/api/packages/mcpeakdev/npm/ +``` + +## npm + +```bash +npm install @nychthemeron/library +``` + +## pnpm + +```bash +pnpm add @nychthemeron/library +``` + +## yarn + +```bash +yarn add @nychthemeron/library +``` + +## bun + +```bash +bun add @nychthemeron/library +``` +``` + +- [ ] **Step 2: Build Storybook and verify the page is included** + +Run: `cd packages/playground && bun run build` + +Expected: Build succeeds with output ending in something like +`Output directory: storybook-static`. Then run: + +`grep -o '"title":"Get Started/Installation"' packages/playground/storybook-static/index.json` + +Expected: prints `"title":"Get Started/Installation"`. + +- [ ] **Step 3: Commit** + +```bash +git add packages/playground/stories/Install.mdx +git commit -m "Add installation docs page to playground" +``` + +--- + +### Task 2: Add root `.dockerignore` + +**Files:** +- Create: `.dockerignore` + +- [ ] **Step 1: Create `.dockerignore`** + +``` +node_modules +**/node_modules +**/dist +**/storybook-static +**/.storybook-static +.git +docs +.tmp +.bun-cache +.pw-browsers +.pw-libs +.shots +*.log +``` + +- [ ] **Step 2: Commit** + +```bash +git add .dockerignore +git commit -m "Add .dockerignore for docs Docker build" +``` + +--- + +### Task 3: Add Dockerfile for the docs site + +**Files:** +- Create: `packages/playground/Dockerfile` + +- [ ] **Step 1: Create the Dockerfile** + +```dockerfile +# syntax=docker/dockerfile:1 + +FROM oven/bun:1 AS build +WORKDIR /app +COPY . . +RUN bun install --frozen-lockfile +RUN cd packages/library && bun run build +RUN cd packages/playground && bun run build + +FROM nginx:alpine AS runtime +COPY --from=build /app/packages/playground/storybook-static /usr/share/nginx/html +EXPOSE 80 +``` + +- [ ] **Step 2: Build and run the image locally** + +Run (from repo root): + +```bash +docker build -t nychthemeron-docs:test -f packages/playground/Dockerfile . +docker run -d --rm --name nychthemeron-docs-test -p 8080:80 nychthemeron-docs:test +sleep 2 +curl -sf http://localhost:8080/ | grep -i storybook +docker stop nychthemeron-docs-test +``` + +Expected: `docker build` completes successfully, the container starts, and +the `curl` output contains a reference to `storybook` (from +`storybook-static/index.html`). + +> If the Docker CLI/daemon isn't available in the current environment (e.g. +> sandboxed dev container), skip running this step here and ask the user to +> run it locally before merging. + +- [ ] **Step 3: Commit** + +```bash +git add packages/playground/Dockerfile +git commit -m "Add Dockerfile for nychthemeron-docs static site" +``` + +--- + +### Task 4: Add `publish-docs` CI job + +**Files:** +- Modify: `.forgejo/workflows/ci.yml` + +- [ ] **Step 1: Add the `publish-docs` job** + +Add this job after the existing `publish` job (same indentation level, +i.e. as a sibling under `jobs:`): + +```yaml + publish-docs: + needs: build + if: startsWith(github.ref, 'refs/tags/v') + runs-on: docker + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Log in to registry + uses: docker/login-action@v3 + with: + registry: git.mcpeakdev.com + username: ${{ github.actor }} + password: ${{ secrets.FORGEJO_TOKEN }} + + - name: Extract image tag + id: meta + run: echo "tag=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" + + - name: Build and push docs image + uses: docker/build-push-action@v6 + with: + context: . + file: packages/playground/Dockerfile + push: true + tags: | + git.mcpeakdev.com/mcpeakdev/nychthemeron-docs:${{ steps.meta.outputs.tag }} + git.mcpeakdev.com/mcpeakdev/nychthemeron-docs:latest +``` + +- [ ] **Step 2: Verify YAML structure** + +Run: `bun run --eval "console.log('ok')"` is not a YAML check — instead, +visually confirm in the file that `publish-docs:` is indented exactly like +`publish:` (4 spaces under `jobs:`), and that all of its child keys +(`needs`, `if`, `runs-on`, `steps`, and each `- name:` step) match the +indentation pattern used by the `publish` job. Confirm there are exactly +three top-level jobs: `build`, `publish`, `publish-docs`. + +- [ ] **Step 3: Commit** + +```bash +git add .forgejo/workflows/ci.yml +git commit -m "Add publish-docs job to build and push nychthemeron-docs image" +``` diff --git a/docs/superpowers/specs/2026-06-11-docs-site-and-docker-design.md b/docs/superpowers/specs/2026-06-11-docs-site-and-docker-design.md new file mode 100644 index 0000000..47fadbc --- /dev/null +++ b/docs/superpowers/specs/2026-06-11-docs-site-and-docker-design.md @@ -0,0 +1,55 @@ +# Docs site (playground) Docker image + install page + +## Goal + +Publish the Storybook playground as a static "docs" site, package it as a +Docker image (`nychthemeron-docs`), and add an Installation page documenting +how to install `@nychthemeron/library` from the private Forgejo npm registry +via npm, pnpm, yarn, and bun. + +## Install page + +- New file: `packages/playground/stories/Install.mdx` +- Storybook addon-docs MDX page (no story export), `Meta` title + `Get Started/Installation` so it sorts near the top of the sidebar. +- Content: + - Heading + short description of the library. + - Registry config snippet (`.npmrc`) showing how to point the scoped + `@nychthemeron` registry at `https://git.mcpeakdev.com/api/packages/mcpeakdev/npm/`. + - Four code blocks showing install commands for `@nychthemeron/library`: + npm, pnpm, yarn, bun. + +## Docker image (`nychthemeron-docs`) + +- New file: `packages/playground/Dockerfile`, multi-stage build: + - **Stage 1 (`oven/bun:1`)**: copy the workspace, `bun install --frozen-lockfile`, + build `@nychthemeron/library` (`cd packages/library && bun run build`), + then build Storybook (`cd packages/playground && bun run build` → + `packages/playground/storybook-static`). + - **Stage 2 (`nginx:alpine`)**: copy `storybook-static` into + `/usr/share/nginx/html`, default nginx config, `EXPOSE 80`. +- Build context is the repo root (so the workspace lockfile and all + packages are available to stage 1). + +## CI changes + +In `.forgejo/workflows/ci.yml`, add a new `publish-docs` job: + +- Parallel to the existing `publish` job (both depend on `build`). +- Gated on `startsWith(github.ref, 'refs/tags/v')`. +- Steps: + 1. Checkout + 2. Log in to `git.mcpeakdev.com` using `docker/login-action` with + `secrets.FORGEJO_TOKEN` (same credential as the library publish job). + 3. Extract version from tag (`${GITHUB_REF_NAME#v}`). + 4. `docker/build-push-action` with context `.`, dockerfile + `packages/playground/Dockerfile`, push `true`, tags: + - `git.mcpeakdev.com/mcpeakdev/nychthemeron-docs:` + - `git.mcpeakdev.com/mcpeakdev/nychthemeron-docs:latest` + +## Out of scope + +- No changes to the existing `build` or `publish` (npm) jobs beyond what's + already in place. +- No SPA routing / custom nginx config — Storybook's static output is + served as-is. diff --git a/packages/playground/.storybook/main.ts b/packages/playground/.storybook/main.ts index 25482a1..a5cb9fe 100644 --- a/packages/playground/.storybook/main.ts +++ b/packages/playground/.storybook/main.ts @@ -3,7 +3,7 @@ import { dirname } from 'node:path' import type { StorybookConfig } from '@storybook/vue3-vite' const config: StorybookConfig = { - stories: ['../stories/**/*.stories.ts'], + stories: ['../stories/**/*.stories.ts', '../stories/**/*.mdx'], addons: [getAbsolutePath('@storybook/addon-links'), getAbsolutePath('@storybook/addon-docs')], framework: { name: getAbsolutePath('@storybook/vue3-vite'), diff --git a/packages/playground/Dockerfile b/packages/playground/Dockerfile new file mode 100644 index 0000000..01ad6bd --- /dev/null +++ b/packages/playground/Dockerfile @@ -0,0 +1,12 @@ +# syntax=docker/dockerfile:1 + +FROM oven/bun:1 AS build +WORKDIR /app +COPY . . +RUN bun install --frozen-lockfile +RUN cd packages/library && bun run build +RUN cd packages/playground && bun run build + +FROM nginx:alpine AS runtime +COPY --from=build /app/packages/playground/storybook-static /usr/share/nginx/html +EXPOSE 80 diff --git a/packages/playground/stories/Install.mdx b/packages/playground/stories/Install.mdx new file mode 100644 index 0000000..dcdd3cd --- /dev/null +++ b/packages/playground/stories/Install.mdx @@ -0,0 +1,41 @@ +import { Meta } from '@storybook/addon-docs/blocks' + + + +# Installation + +`@nychthemeron/library` is published to a private npm registry hosted on +Forgejo. Configure your package manager for the `@nychthemeron` scope, then +install the package. + +## Configure the registry + +Add the following to your project's `.npmrc`: + +``` +@nychthemeron:registry=https://git.mcpeakdev.com/api/packages/mcpeakdev/npm/ +``` + +## npm + +```bash +npm install @nychthemeron/library +``` + +## pnpm + +```bash +pnpm add @nychthemeron/library +``` + +## yarn + +```bash +yarn add @nychthemeron/library +``` + +## bun + +```bash +bun add @nychthemeron/library +```