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>
This commit is contained in:
155
.woodpecker/web.yml
Normal file
155
.woodpecker/web.yml
Normal file
@@ -0,0 +1,155 @@
|
||||
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
|
||||
Reference in New Issue
Block a user