Files
professional-website/.woodpecker/web.yml
Jason Woltje 462d938297 feat(scaffold): Next 16 + Payload 3 scaffold with Kaniko CI and Swarm deploy
Initial app scaffold wired end-to-end: Payload 3.82 CMS integrated with Next
16.2 App Router (standalone output), PostgreSQL 17 adapter, Lexical rich text,
Tailwind 3 with Material 3 token palette ported from the stitch technical-
editorial design, self-hosted Space Grotesk + Inter via next/font, and
lucide-react icons. Admin lives at /admin, REST/GraphQL at /api/*, and
/api/health returns build SHA/REV for deploy verification.

Seven collections (Users, Media, Categories, Projects, Posts, Gear,
ContactSubmissions) and six globals (Home, About, Contact, Resume,
Navigation, SEO) model the content outlined in docs/PRD.md.

Multi-stage Dockerfile builds a non-root standalone runner; Woodpecker
pipeline lints, typechecks, builds, audits, builds with Kaniko to
git.mosaicstack.dev, scans with Trivy, and links the package. Swarm
compose mirrors the mosaic-stack-website Traefik entrypoints=web pattern
with www->apex redirect and immutable WEB_IMAGE_TAG.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 21:18:01 -05:00

156 lines
4.3 KiB
YAML

when:
- event: [push, pull_request, manual]
- event: tag
variables:
- &node_image "node:24-alpine"
- &install_deps |
corepack enable
pnpm config set store-dir /tmp/pnpm-store
pnpm install --frozen-lockfile
- &enable_pnpm |
corepack enable
pnpm config set store-dir /tmp/pnpm-store
- &kaniko_setup |
mkdir -p /kaniko/.docker
echo "{\"auths\":{\"git.mosaicstack.dev\":{\"username\":\"$$GITEA_USER\",\"password\":\"$$GITEA_TOKEN\"}}}" > /kaniko/.docker/config.json
steps:
install:
image: *node_image
commands:
- *install_deps
lint:
image: *node_image
commands:
- *enable_pnpm
- pnpm lint
depends_on:
- install
typecheck:
image: *node_image
commands:
- *enable_pnpm
- pnpm typecheck
depends_on:
- install
build:
image: *node_image
environment:
NODE_ENV: "production"
NEXT_PUBLIC_BUILD_SHA: ${CI_COMMIT_SHA:0:8}
NEXT_PUBLIC_BUILD_REV: ${CI_COMMIT_BRANCH:-${CI_COMMIT_TAG}}
commands:
- *enable_pnpm
- pnpm build
depends_on:
- lint
- typecheck
security-audit:
image: *node_image
commands:
- *enable_pnpm
- pnpm audit --prod --audit-level=high || true
depends_on:
- install
docker-build:
image: gcr.io/kaniko-project/executor:debug
environment:
GITEA_USER:
from_secret: gitea_username
GITEA_TOKEN:
from_secret: gitea_token
CI_COMMIT_BRANCH: ${CI_COMMIT_BRANCH}
CI_COMMIT_TAG: ${CI_COMMIT_TAG}
CI_COMMIT_SHA: ${CI_COMMIT_SHA}
commands:
- *kaniko_setup
- |
set -e
IMAGE="git.mosaicstack.dev/jason.woltje/professional-website"
SHORT_SHA="$${CI_COMMIT_SHA:0:8}"
DESTINATIONS="--destination $$IMAGE:sha-$$SHORT_SHA"
if [ -n "$$CI_COMMIT_TAG" ]; then
DESTINATIONS="$$DESTINATIONS --destination $$IMAGE:$$CI_COMMIT_TAG"
fi
if [ "$$CI_COMMIT_BRANCH" = "main" ]; then
DESTINATIONS="$$DESTINATIONS --destination $$IMAGE:latest"
elif [ "$$CI_COMMIT_BRANCH" = "develop" ]; then
DESTINATIONS="$$DESTINATIONS --destination $$IMAGE:dev"
fi
/kaniko/executor \
--context . \
--dockerfile Dockerfile \
--build-arg NEXT_PUBLIC_BUILD_SHA=sha-$$SHORT_SHA \
--build-arg NEXT_PUBLIC_BUILD_REV=$${CI_COMMIT_TAG:-$$CI_COMMIT_BRANCH} \
$$DESTINATIONS
when:
- branch: [main, develop]
event: [push, manual]
- event: tag
depends_on:
- build
- security-audit
security-trivy:
image: aquasec/trivy:latest
environment:
GITEA_USER:
from_secret: gitea_username
GITEA_TOKEN:
from_secret: gitea_token
CI_COMMIT_BRANCH: ${CI_COMMIT_BRANCH}
CI_COMMIT_TAG: ${CI_COMMIT_TAG}
CI_COMMIT_SHA: ${CI_COMMIT_SHA}
commands:
- |
set -e
IMAGE="git.mosaicstack.dev/jason.woltje/professional-website"
if [ -n "$$CI_COMMIT_TAG" ]; then
SCAN_TAG="$$CI_COMMIT_TAG"
else
SCAN_TAG="sha-$${CI_COMMIT_SHA:0:8}"
fi
mkdir -p ~/.docker
echo "{\"auths\":{\"git.mosaicstack.dev\":{\"username\":\"$$GITEA_USER\",\"password\":\"$$GITEA_TOKEN\"}}}" > ~/.docker/config.json
trivy image --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed \
$$IMAGE:$$SCAN_TAG
when:
- branch: [main, develop]
event: [push, manual]
- event: tag
depends_on:
- docker-build
link-package:
image: alpine:3
environment:
GITEA_TOKEN:
from_secret: gitea_token
commands:
- apk add --no-cache curl
- |
set -e
STATUS=$$(curl -s -o /dev/null -w "%{http_code}" -X POST \
-H "Authorization: token $$GITEA_TOKEN" \
"https://git.mosaicstack.dev/api/v1/packages/jason.woltje/container/professional-website/-/link/professional-website")
if [ "$$STATUS" = "201" ] || [ "$$STATUS" = "204" ]; then
echo "Package linked"
elif [ "$$STATUS" = "400" ]; then
echo "Package already linked (OK)"
else
echo "Unexpected response: $$STATUS"
exit 1
fi
when:
- branch: [main, develop]
event: [push, manual]
- event: tag
depends_on:
- security-trivy