name: Develop on: push: branches: - develop workflow_dispatch: concurrency: group: develop-${{ github.ref }} cancel-in-progress: true permissions: contents: read packages: write env: IMAGE: ghcr.io/vvzvlad/gitmost jobs: # Run the reusable test suite. Together with the e2e jobs below it gates the # publish job (the image push), not the build itself — build runs in parallel. test: uses: ./.github/workflows/test.yml # Runs in parallel with the test/e2e jobs and only warms the buildx cache # (GHA cache, scope develop-amd64). No push happens here — the publish job # below is the only one that pushes the image. build: runs-on: ubuntu-latest timeout-minutes: 30 steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Resolve version id: version run: echo "value=$(git describe --tags --always)" >> "$GITHUB_OUTPUT" - name: Build develop image (warm cache, no push) uses: docker/build-push-action@v6 with: context: . platforms: linux/amd64 build-args: | APP_VERSION=${{ steps.version.outputs.value }} AI_AGENT_ROLES_CATALOG_URL=https://raw.githubusercontent.com/vvzvlad/gitmost/develop/agent-roles-catalog push: false cache-from: type=gha,scope=develop-amd64 cache-to: type=gha,scope=develop-amd64,mode=max,ignore-error=true # The gate: rebuilds from the cache the build job just wrote (near-instant on # a cache hit; worst case — cache eviction — a full rebuild, which matches the # old sequential timing) and pushes :develop only when unit tests AND both # e2e suites AND the build are green. publish: needs: [test, e2e-server, e2e-mcp, build] runs-on: ubuntu-latest timeout-minutes: 30 steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Resolve version id: version run: echo "value=$(git describe --tags --always)" >> "$GITHUB_OUTPUT" - name: Build and push develop image uses: docker/build-push-action@v6 with: context: . platforms: linux/amd64 build-args: | APP_VERSION=${{ steps.version.outputs.value }} AI_AGENT_ROLES_CATALOG_URL=https://raw.githubusercontent.com/vvzvlad/gitmost/develop/agent-roles-catalog push: true tags: ${{ env.IMAGE }}:develop cache-from: type=gha,scope=develop-amd64 # e2e jobs gate the publish (image push), not the build: the :develop image # is pushed only when unit tests AND both e2e suites pass (publish.needs # lists them all). e2e-server: runs-on: ubuntu-latest # Hard cap: the full-AppModule e2e leaks open handles and hung jest to the 6h max. timeout-minutes: 15 env: DATABASE_URL: postgresql://docmost:docmost@localhost:5432/docmost REDIS_URL: redis://localhost:6379 APP_SECRET: ci-e2e-secret-change-me-min-32-characters APP_URL: http://localhost:3000 services: postgres: # via mirror.gcr.io (Docker Hub pull-through cache; avoids Hub anonymous # pull rate-limit that randomly fails on shared GitHub runner IPs). image: mirror.gcr.io/pgvector/pgvector:pg18 env: POSTGRES_DB: docmost POSTGRES_USER: docmost POSTGRES_PASSWORD: docmost ports: - 5432:5432 options: >- --health-cmd "pg_isready -U docmost" --health-interval 5s --health-timeout 5s --health-retries 20 redis: # via mirror.gcr.io (see postgres note above). image: mirror.gcr.io/library/redis:7 ports: - 6379:6379 options: >- --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20 steps: - name: Checkout uses: actions/checkout@v4 - name: Set up pnpm uses: pnpm/action-setup@v4 - name: Set up Node uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm - name: Install dependencies run: pnpm install --frozen-lockfile - name: Build editor-ext run: pnpm --filter @docmost/editor-ext build - name: Run migrations run: pnpm --filter ./apps/server migration:latest - name: Run server e2e run: pnpm --filter ./apps/server test:e2e # Gates the publish too — see the comment above e2e-server. e2e-mcp: runs-on: ubuntu-latest timeout-minutes: 20 env: DATABASE_URL: postgresql://docmost:docmost@localhost:5432/docmost REDIS_URL: redis://localhost:6379 APP_SECRET: ci-e2e-secret-change-me-min-32-characters APP_URL: http://localhost:3000 NODE_ENV: production services: postgres: # via mirror.gcr.io (Docker Hub pull-through cache; avoids Hub anonymous # pull rate-limit that randomly fails on shared GitHub runner IPs). image: mirror.gcr.io/pgvector/pgvector:pg18 env: POSTGRES_DB: docmost POSTGRES_USER: docmost POSTGRES_PASSWORD: docmost ports: - 5432:5432 options: >- --health-cmd "pg_isready -U docmost" --health-interval 5s --health-timeout 5s --health-retries 20 redis: # via mirror.gcr.io (see postgres note above). image: mirror.gcr.io/library/redis:7 ports: - 6379:6379 options: >- --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20 steps: - name: Checkout uses: actions/checkout@v4 - name: Set up pnpm uses: pnpm/action-setup@v4 - name: Set up Node uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm - name: Install dependencies run: pnpm install --frozen-lockfile - name: Build editor-ext run: pnpm --filter @docmost/editor-ext build - name: Build server run: pnpm server:build - name: Build mcp run: pnpm --filter @docmost/mcp build - name: Run migrations run: pnpm --filter ./apps/server migration:latest - name: Start server (prod) # Capture stdout/stderr so a start-up crash (bind error, stack trace, # migration mismatch) is diagnosable; without this the only signal is # the generic health-loop timeout below, ~120s later. run: pnpm --filter ./apps/server start:prod > /tmp/server.log 2>&1 & - name: Wait for server health run: | for i in $(seq 1 60); do if curl -fsS http://localhost:3000/api/health > /dev/null; then echo "Server is healthy" exit 0 fi sleep 2 done echo "Server did not become healthy in time" exit 1 - name: Dump server log on failure if: failure() run: cat /tmp/server.log || true - name: Seed admin run: | curl -fsS -X POST http://localhost:3000/api/auth/setup \ -H "Content-Type: application/json" \ -d '{"name":"E2E","email":"e2e@example.com","password":"E2ePassword123","workspaceName":"E2E"}' - name: Run mcp e2e env: DOCMOST_API_URL: http://localhost:3000/api DOCMOST_EMAIL: e2e@example.com DOCMOST_PASSWORD: E2ePassword123 run: pnpm --filter @docmost/mcp test:e2e