CI #6
7 changed files with 444 additions and 1 deletions
13
.dockerignore
Normal file
13
.dockerignore
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
node_modules
|
||||||
|
**/node_modules
|
||||||
|
**/dist
|
||||||
|
**/storybook-static
|
||||||
|
**/.storybook-static
|
||||||
|
.git
|
||||||
|
docs
|
||||||
|
.tmp
|
||||||
|
.bun-cache
|
||||||
|
.pw-browsers
|
||||||
|
.pw-libs
|
||||||
|
.shots
|
||||||
|
*.log
|
||||||
100
.forgejo/workflows/ci.yml
Normal file
100
.forgejo/workflows/ci.yml
Normal file
|
|
@ -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
|
||||||
222
docs/superpowers/plans/2026-06-11-docs-site-and-docker.md
Normal file
222
docs/superpowers/plans/2026-06-11-docs-site-and-docker.md
Normal file
|
|
@ -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'
|
||||||
|
|
||||||
|
<Meta title="Get Started/Installation" />
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
```
|
||||||
|
|
@ -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:<version>`
|
||||||
|
- `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.
|
||||||
|
|
@ -3,7 +3,7 @@ import { dirname } from 'node:path'
|
||||||
import type { StorybookConfig } from '@storybook/vue3-vite'
|
import type { StorybookConfig } from '@storybook/vue3-vite'
|
||||||
|
|
||||||
const config: StorybookConfig = {
|
const config: StorybookConfig = {
|
||||||
stories: ['../stories/**/*.stories.ts'],
|
stories: ['../stories/**/*.stories.ts', '../stories/**/*.mdx'],
|
||||||
addons: [getAbsolutePath('@storybook/addon-links'), getAbsolutePath('@storybook/addon-docs')],
|
addons: [getAbsolutePath('@storybook/addon-links'), getAbsolutePath('@storybook/addon-docs')],
|
||||||
framework: {
|
framework: {
|
||||||
name: getAbsolutePath('@storybook/vue3-vite'),
|
name: getAbsolutePath('@storybook/vue3-vite'),
|
||||||
|
|
|
||||||
12
packages/playground/Dockerfile
Normal file
12
packages/playground/Dockerfile
Normal file
|
|
@ -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
|
||||||
41
packages/playground/stories/Install.mdx
Normal file
41
packages/playground/stories/Install.mdx
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { Meta } from '@storybook/addon-docs/blocks'
|
||||||
|
|
||||||
|
<Meta title="Get Started/Installation" />
|
||||||
|
|
||||||
|
# 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
|
||||||
|
```
|
||||||
Loading…
Reference in a new issue