Add Kaniko-based Docker build step for the coordinator service,
push to git.mosaicstack.dev/mosaic/stack-coordinator, and include
it in the link-packages step.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Build step now depends on lint, typecheck, test, and security-audit so
Docker images cannot be pushed when quality gates fail. Also corrects
docker-compose.prod.yml image names to match pipeline (stack-api, stack-web,
stack-postgres) and replaces hardcoded :latest with ${IMAGE_TAG:-latest}.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Without set -e, if an individual link_package call fails, the script
continues silently. Only the last call's exit code determined the step
result — masking earlier failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Addresses timing issue where packages aren't immediately queryable via
API after being pushed to the registry.
Changes:
- Initial 10-second delay for package indexing
- Retry logic: 3 attempts with 5-second delays
- Only retries on 404 (not found) errors
- Returns success on 201/204 (linked) or 400 (already linked)
- Better logging shows attempt progress
This fixes the race condition where link-packages ran before packages
were indexed in Gitea's registry API.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Woodpecker interprets $ as variable substitution in YAML, so we need to
use $$ to escape it and pass a literal $ to the shell script.
Changed from a for loop to explicit function calls with escaped variables:
- Use $$ instead of $ for all shell variables
- Function-based approach for cleaner variable passing
- Each package explicitly called: link_package "stack-api" etc.
This fixes the variable expansion issue where ${package} was empty,
resulting in URLs like "container//-/link/stack" (double slash).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Gitea package link API returns 201 (Created) on successful linking,
not 204 (No Content) as we were checking for. Updated the link-packages
step to accept both 201 and 204 as success.
Also added visual indicators (✅/❌) to make link status clearer in logs.
Diagnostic output showed all 5 packages successfully linked with 201:
- stack-api: 201 (linked)
- stack-web: 201 (linked)
- stack-postgres: 201 (linked)
- stack-openbao: 201 (linked)
- stack-orchestrator: 201 (linked)
Subsequent runs return 400 "invalid argument" which means already linked.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The link endpoint uses POST (not PUT) and returns 400 when already
linked. Handle both 204 (linked) and 400 (already linked) as success.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Link all Docker container packages to the mosaic/stack repository
using Gitea's package API. This makes packages visible on the
repository page and shows which repo they came from.
API endpoint: /packages/{owner}/container/{name}/-/link/{repo_name}
Links created for:
- mosaic/api
- mosaic/web
- mosaic/postgres
- mosaic/openbao
- mosaic/orchestrator
Each package will now show up in the repository's packages tab.
Add missing Docker image builds for swarm deployment.
Changes:
- Added docker-build-openbao step to .woodpecker.yml
- Added docker-build-orchestrator step to .woodpecker.yml
- Updated docker-compose.swarm.yml to use registry images
(git.mosaicstack.dev/mosaic/*)
- Added IMAGE_TAG variable support for versioned deployments
- Updated deploy-swarm.sh to support both registry and local images
Image tagging strategy:
- All commits: SHA tag (e.g., 658ec077)
- main branch: latest + SHA
- develop branch: dev + SHA
- git tags: version tag + SHA
Registry images:
- git.mosaicstack.dev/mosaic/postgres
- git.mosaicstack.dev/mosaic/openbao
- git.mosaicstack.dev/mosaic/api
- git.mosaicstack.dev/mosaic/orchestrator
- git.mosaicstack.dev/mosaic/web
Deployment modes:
- IMAGE_TAG=latest (default, use registry latest)
- IMAGE_TAG=dev (use registry dev tag)
- IMAGE_TAG=local (use local builds via build-images.sh)
Woodpecker CI doesn't allow tmpfs due to trust level restrictions.
The service is ephemeral anyway - data is auto-cleaned after each pipeline run.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added PostgreSQL 17 service to Woodpecker CI to support integration tests:
**Changes:**
- PostgreSQL 17 Alpine service with test database
- New prisma-migrate step runs migrations before tests
- DATABASE_URL environment variable in test step
- Data stored in tmpfs for speed and auto-cleanup
**Impact:**
- Integration tests (job-events.performance.spec.ts, fulltext-search.spec.ts) now run in CI
- All 1953 tests pass (including 14 integration tests)
- No more skipped DB-dependent tests
**Aligns with "no workarounds" principle** - maintains full test coverage instead of skipping integration tests.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Remove || true from lint and test steps to enforce quality gates.
Tests and linting must pass for builds to succeed.
This prevents regressions from being merged to develop.
docker:dind requires privileged mode and a running daemon.
Kaniko builds containers without needing Docker daemon:
- Runs unprivileged
- Reads credentials from /kaniko/.docker/config.json
- Designed for CI environments like Woodpecker
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The buildx plugin's credential handling doesn't work properly with
Harbor. The docker-auth-test step proved that standard docker login
works, so we switch to:
- docker:dind image
- Manual docker login before build
- Standard docker build and docker push
This bypasses buildx's separate credential store issue.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added a docker-auth-test step that:
- Shows credential lengths (for debugging)
- Tests docker login directly with Harbor
This will help identify if the issue is with secrets injection
or with how buildx handles authentication.
Reverted to woodpeckerci/plugin-docker-buildx since plugins/docker
requires server-side WOODPECKER_PLUGINS_PRIVILEGED config.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The repo setting should NOT include the registry prefix - the
registry setting handles that separately.
Changed repo: reg.mosaicstack.dev/mosaic/api -> repo: mosaic/api
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The woodpeckerci/plugin-docker-buildx plugin was failing with
"insufficient_scope: authorization failed" when pushing to Harbor,
even though the same credentials worked locally.
Switched to the standard plugins/docker which uses traditional
docker login authentication that may work better with Harbor.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The docker-buildx plugin automatically prepends registry to repo,
so having the full URL caused doubled paths:
reg.mosaicstack.dev/reg.mosaicstack.dev/mosaic/api
Changed from: repo: reg.mosaicstack.dev/mosaic/api
Changed to: repo: mosaic/api
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add docker-build-api, docker-build-web, docker-build-postgres steps
- Images pushed to reg.diversecanvas.com/mosaic/* on main/develop
- Create docker-compose.prod.yml for production deployments
- Add .env.prod.example with production configuration
Requires Harbor secrets in Woodpecker:
- harbor_username
- harbor_password
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Removed redundant prisma:generate commands from typecheck, test, and
build steps. The dedicated prisma-generate step already generates the
client, and all subsequent steps depend on it and share node_modules.
Multiple concurrent generation attempts were causing ENOENT errors
during file rename operations:
Error: ENOENT: no such file or directory, rename
'.../libquery_engine-linux-musl-openssl-3.0.x.so.node.tmp33'
This fix ensures Prisma client is generated exactly once per pipeline
run, eliminating the race condition.
Refs #CI-woodpecker
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changed CI pipeline to install dependencies only once in the install step.
All subsequent steps now reuse the installed node_modules instead of
reinstalling, which prevents ENOENT errors from concurrent pnpm lock file
operations.
- Only 'install' step runs 'pnpm install --frozen-lockfile'
- All other steps use 'corepack enable' and reuse existing dependencies
- Fixes ENOENT chown errors on lock.yaml temporary files
Refs #CI-woodpecker
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixes CI pipeline failures caused by missing Prisma Client generation and TypeScript type safety issues. Added Prisma generation step to CI pipeline, installed missing type dependencies, and resolved 40+ exactOptionalPropertyTypes violations across service layer.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>