diff --git a/.woodpecker/ci.yml b/.woodpecker/ci.yml index 2dfe430..e39e5da 100644 --- a/.woodpecker/ci.yml +++ b/.woodpecker/ci.yml @@ -44,18 +44,30 @@ steps: test: image: *node_image + environment: + DATABASE_URL: postgresql://mosaic:mosaic@postgres:5432/mosaic commands: - *enable_pnpm + # Install postgresql-client for pg_isready + - apk add --no-cache postgresql-client + # Wait up to 30s for postgres to be ready + - | + for i in $(seq 1 30); do + pg_isready -h postgres -p 5432 -U mosaic && break + echo "Waiting for postgres ($i/30)..." + sleep 1 + done + # Run migrations (DATABASE_URL is set in environment above) + - pnpm --filter @mosaic/db run db:migrate + # Run all tests - pnpm test depends_on: - typecheck - build: - image: *node_image - commands: - - *enable_pnpm - - pnpm build - depends_on: - - lint - - format - - test +services: + postgres: + image: pgvector/pgvector:pg17 + environment: + POSTGRES_USER: mosaic + POSTGRES_PASSWORD: mosaic + POSTGRES_DB: mosaic diff --git a/.woodpecker/publish.yml b/.woodpecker/publish.yml new file mode 100644 index 0000000..2723893 --- /dev/null +++ b/.woodpecker/publish.yml @@ -0,0 +1,75 @@ +# Docker image build and push — runs only on main branch push/tag +# Completely independent of the CI test pipeline + +variables: + - &node_image 'node:22-alpine' + - &enable_pnpm 'corepack enable' + +when: + - branch: [main] + event: [push, manual, tag] + +steps: + install: + image: *node_image + commands: + - corepack enable + - pnpm install --frozen-lockfile + + build: + image: *node_image + commands: + - *enable_pnpm + - pnpm build + depends_on: + - install + + build-gateway: + image: gcr.io/kaniko-project/executor:debug + environment: + REGISTRY_USER: + from_secret: gitea_username + REGISTRY_PASS: + from_secret: gitea_password + CI_COMMIT_BRANCH: ${CI_COMMIT_BRANCH} + CI_COMMIT_TAG: ${CI_COMMIT_TAG} + CI_COMMIT_SHA: ${CI_COMMIT_SHA} + commands: + - mkdir -p /kaniko/.docker + - echo "{\"auths\":{\"git.mosaicstack.dev\":{\"username\":\"$REGISTRY_USER\",\"password\":\"$REGISTRY_PASS\"}}}" > /kaniko/.docker/config.json + - | + DESTINATIONS="--destination git.mosaicstack.dev/mosaic/mosaic-stack/gateway:sha-${CI_COMMIT_SHA:0:7}" + if [ "$CI_COMMIT_BRANCH" = "main" ]; then + DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaic/mosaic-stack/gateway:latest" + fi + if [ -n "$CI_COMMIT_TAG" ]; then + DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaic/mosaic-stack/gateway:$CI_COMMIT_TAG" + fi + /kaniko/executor --context . --dockerfile docker/gateway.Dockerfile $DESTINATIONS + depends_on: + - build + + build-web: + image: gcr.io/kaniko-project/executor:debug + environment: + REGISTRY_USER: + from_secret: gitea_username + REGISTRY_PASS: + from_secret: gitea_password + CI_COMMIT_BRANCH: ${CI_COMMIT_BRANCH} + CI_COMMIT_TAG: ${CI_COMMIT_TAG} + CI_COMMIT_SHA: ${CI_COMMIT_SHA} + commands: + - mkdir -p /kaniko/.docker + - echo "{\"auths\":{\"git.mosaicstack.dev\":{\"username\":\"$REGISTRY_USER\",\"password\":\"$REGISTRY_PASS\"}}}" > /kaniko/.docker/config.json + - | + DESTINATIONS="--destination git.mosaicstack.dev/mosaic/mosaic-stack/web:sha-${CI_COMMIT_SHA:0:7}" + if [ "$CI_COMMIT_BRANCH" = "main" ]; then + DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaic/mosaic-stack/web:latest" + fi + if [ -n "$CI_COMMIT_TAG" ]; then + DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaic/mosaic-stack/web:$CI_COMMIT_TAG" + fi + /kaniko/executor --context . --dockerfile docker/web.Dockerfile $DESTINATIONS + depends_on: + - build diff --git a/docs/scratchpads/ci-docker-publish-20260330.md b/docs/scratchpads/ci-docker-publish-20260330.md new file mode 100644 index 0000000..b8ee848 --- /dev/null +++ b/docs/scratchpads/ci-docker-publish-20260330.md @@ -0,0 +1,30 @@ +# Scratchpad: CI Docker Publish (2026-03-30) + +- Objective: Add Woodpecker Docker build+push steps for gateway and web images on `main` pushes. +- Scope: `.woodpecker/ci.yml`. +- Constraints: + - Use existing Dockerfiles at `docker/gateway.Dockerfile` and `docker/web.Dockerfile`. + - Publish to `git.mosaicstack.dev` with `from_secret` credentials. + - Tag both `latest` and `${CI_COMMIT_SHA}`. + - Do not run publish steps on pull requests. +- ASSUMPTION: Publishing `latest` is required by the task for registry convenience, even though immutable tags remain the safer deployment reference. +- Findings: + - Existing pipeline already has `build` after `lint`, `format`, and `test`. + - `apps/gateway/package.json` uses `tsc` for `build`; no Prisma dependency or `prisma generate` hook is present. +- Plan: + 1. Patch `.woodpecker/ci.yml` to keep `build` as the quality gate successor and add `publish-gateway` plus `publish-web`. + 2. Validate YAML and run repo quality gates relevant to the change. + 3. Review the diff, then commit/push/PR if validation passes. +- Verification: + - `python3 -c "import yaml; yaml.safe_load(open('.woodpecker/ci.yml'))" && echo "YAML valid"` + - `pnpm lint` + - `pnpm typecheck` + - `pnpm format:check` + - `docker compose up -d` + - `pnpm --filter @mosaic/db db:push` + - `pnpm test` + - `pnpm build` + - Manual review of `.woodpecker/ci.yml` diff: publish steps are main-only, depend on `build`, and use secret-backed registry auth plus dual tags. +- Risks: + - Pipeline behavior beyond YAML validation cannot be fully proven locally; remote Woodpecker execution will be the final situational check after push. + - Repo baseline required two existing `plugins/macp` files to be reformatted before `pnpm format:check` would pass. diff --git a/packages/macp/src/gate-runner.ts b/packages/macp/src/gate-runner.ts index 40c971a..b59f807 100644 --- a/packages/macp/src/gate-runner.ts +++ b/packages/macp/src/gate-runner.ts @@ -43,7 +43,7 @@ export function runShell( let timedOut = false; try { - const result = spawnSync('bash', ['-lc', command], { + const result = spawnSync('sh', ['-c', command], { cwd, timeout: Math.max(1, timeoutSec) * 1000, encoding: 'utf-8',