Skip to content

fix: accept string request field in stripeEventSchema #794

fix: accept string request field in stripeEventSchema

fix: accept string request field in stripeEventSchema #794

Workflow file for this run

name: CI
on:
pull_request:
push:
branches: [main, dev, v2]
workflow_dispatch:
permissions:
packages: write
contents: write
env:
STRIPE_NPM_REGISTRY: https://npm.pkg.github.com
jobs:
# ---------------------------------------------------------------------------
# Changes — skip Docker/publish jobs when only docs/ changed
# ---------------------------------------------------------------------------
changes:
name: Detect code changes
runs-on: ubuntu-24.04-arm
outputs:
code: ${{ steps.filter.outputs.code }}
steps:
- uses: actions/checkout@v5
- uses: dorny/paths-filter@v4
id: filter
with:
filters: |
code:
- '**'
- '!docs/**'
# ---------------------------------------------------------------------------
# Test — lint, build, unit & integration tests
# ---------------------------------------------------------------------------
test:
name: Lint, build & test
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v5
- name: Start services
run: docker compose up -d --wait
- name: Install pnpm
uses: pnpm/action-setup@v5
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version-file: ./.nvmrc
cache: pnpm
- name: Set up .env file
run: |
touch packages/source-stripe/.env
echo DATABASE_URL='postgres://postgres:postgres@localhost:55432/postgres?sslmode=disable&search_path=stripe' >> packages/source-stripe/.env
echo NODE_ENV=dev >> packages/source-stripe/.env
echo STRIPE_SECRET_KEY=sk_test_ >> packages/source-stripe/.env
echo STRIPE_WEBHOOK_SECRET=whsec_ >> packages/source-stripe/.env
echo SCHEMA=stripe >> packages/source-stripe/.env
echo PORT=8080 >> packages/source-stripe/.env
echo API_KEY=api_key_test >> packages/source-stripe/.env
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Formatting checks
run: pnpm format:check
continue-on-error: true
- name: Lint
run: pnpm lint
- name: Build
run: pnpm build
- name: Check deprecated paths are up to date
run: |
cd packages/openapi
bundled=$(ls oas/*.json | grep -v manifest.json | grep -v index.html)
[ "$(echo "$bundled" | wc -l)" -eq 1 ] || { echo "Expected 1 bundled spec"; exit 1; }
version=$(basename "$bundled" .json)
grep -q "DEPRECATED_PATHS_BUNDLED_VERSION = '${version}'" src/deprecatedPaths.ts \
|| { echo "deprecatedPaths.ts is stale (bundled spec is ${version}). Fix: node packages/openapi/scripts/generate-versions.mjs"; exit 1; }
- name: Check generated OpenAPI files
run: ./scripts/generate-openapi.sh --check
env:
STRIPE_API_KEY: 'sk_test_placeholder'
- name: Ensure all shell tests are wired up
run: |
missing=()
for f in e2e/*.test.sh; do
name=$(basename "$f")
if ! grep -rq "$name" .github/workflows/; then
missing+=("$f")
fi
done
if [ ${#missing[@]} -gt 0 ]; then
printf 'Not referenced in any workflow: %s\n' "${missing[@]}"
exit 1
fi
- name: Initialize DB schema
run: |
docker run --rm \
--network="host" \
-e PGPASSWORD=postgres \
postgres:18 \
psql -h localhost -p 55432 -U postgres -d postgres -c 'create schema if not exists "stripe";'
- name: stripe-mock smoke test
run: bash e2e/stripe-mock.test.sh
- name: Tests
run: pnpm --filter '!@stripe/sync-e2e' test
env:
DATABASE_URL: 'postgres://postgres:postgres@localhost:55432/postgres?sslmode=disable&search_path=stripe'
POSTGRES_URL: 'postgres://postgres:postgres@localhost:55432/postgres'
STRIPE_MOCK_URL: 'http://localhost:12111'
STRIPE_API_KEY: ${{ secrets.STRIPE_API_KEY }}
GOOGLE_CLIENT_ID: ${{ vars.GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
GOOGLE_REFRESH_TOKEN: ${{ secrets.GOOGLE_REFRESH_TOKEN }}
GOOGLE_SPREADSHEET_ID: ${{ vars.GOOGLE_SPREADSHEET_ID }}
- name: Disconnect & time-limit tests (Node)
run: |
pnpm --filter @stripe/sync-e2e exec vitest run test-disconnect.test.ts
env:
DISCONNECT_TEST_NODE: '1'
SKIP_SETUP: '1'
- name: Install Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Disconnect & time-limit tests (Bun)
run: |
pnpm --filter @stripe/sync-e2e exec vitest run test-disconnect.test.ts
env:
DISCONNECT_TEST_BUN: '1'
SKIP_SETUP: '1'
- name: Connector loading test
run: bash e2e/connector-loading.test.sh
- name: ESBUILD binary path test
run: bash e2e/esbuild-binary-path.test.sh
- name: Skipped test warnings
if: always()
run: '[ -f /tmp/vitest-skip-warnings.txt ] && cat /tmp/vitest-skip-warnings.txt || true'
# ---------------------------------------------------------------------------
# mitmweb — proxy intercept smoke test (curl, Node, Bun → httpbin.org)
# ---------------------------------------------------------------------------
mitmweb:
name: mitmweb proxy intercept test
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v5
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version-file: ./.nvmrc
- name: Install Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Install mitmproxy
run: pip3 install --quiet mitmproxy
- name: Run mitmweb intercept test
run: bash scripts/mitmweb-env.test.sh
- name: Stop mitmweb
if: always()
run: pkill -f mitmweb || true
# ---------------------------------------------------------------------------
# Publish npm — publish @stripe/* packages to GitHub Packages
# ---------------------------------------------------------------------------
publish_npm:
name: Publish npm packages
needs: [changes]
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v5
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version-file: ./.nvmrc
cache: pnpm
- name: Install dependencies & build
run: pnpm install --frozen-lockfile && pnpm build
- name: Publish to GitHub Packages
run: |
echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> .npmrc
./scripts/publish-packages.sh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ---------------------------------------------------------------------------
# Publish npmjs.org — auto-publish when version changes
# ---------------------------------------------------------------------------
publish_npmjs:
name: Publish to npmjs.org
needs: [test, publish_npm, changes]
if: >-
github.event_name == 'push'
&& needs.changes.outputs.code == 'true'
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v5
- name: Check if version changed
id: version-check
run: |
LOCAL_VERSION=$(jq -r .version apps/engine/package.json)
NPM_VERSION=$(npm view @stripe/sync-engine version \
--registry https://registry.npmjs.org 2>/dev/null || echo "0.0.0")
echo "local=$LOCAL_VERSION" >> "$GITHUB_OUTPUT"
echo "npm=$NPM_VERSION" >> "$GITHUB_OUTPUT"
if [ "$LOCAL_VERSION" = "$NPM_VERSION" ]; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "Version unchanged: $LOCAL_VERSION"
elif [ "$(printf '%s\n%s\n' "$LOCAL_VERSION" "$NPM_VERSION" | sort -V | tail -n1)" = "$LOCAL_VERSION" ]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "Version increased: npm=$NPM_VERSION -> local=$LOCAL_VERSION"
else
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "::notice::Skipping npmjs publish because local version $LOCAL_VERSION is older than npmjs version $NPM_VERSION"
fi
- name: Install pnpm
if: steps.version-check.outputs.changed == 'true'
uses: pnpm/action-setup@v5
- name: Set up Node
if: steps.version-check.outputs.changed == 'true'
uses: actions/setup-node@v6
with:
node-version-file: ./.nvmrc
cache: pnpm
- name: Install dependencies & build
if: steps.version-check.outputs.changed == 'true'
run: pnpm install --frozen-lockfile && pnpm build
- name: Publish to npmjs.org
if: steps.version-check.outputs.changed == 'true'
run: bash scripts/promote-to-npmjs.sh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_REPO_OWNER: ${{ github.repository_owner }}
GITHUB_REPO_NAME: ${{ github.event.repository.name }}
RELEASE_VERSION: ${{ steps.version-check.outputs.local }}
- name: Create GitHub Release
if: steps.version-check.outputs.changed == 'true'
run: |
VERSION="${{ steps.version-check.outputs.local }}"
# Extract changelog section for this version
BODY=$(sed -n "/^## v${VERSION}/,/^## v/{ /^## v${VERSION}/d; /^## v/d; p; }" CHANGELOG.md 2>/dev/null | head -100 || true)
gh release create "v${VERSION}" \
--title "v${VERSION}" \
--notes "${BODY:-Release v${VERSION}}" \
--target "${{ github.sha }}" || echo "::warning::GitHub Release creation skipped (tag may not exist or release already exists)"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ---------------------------------------------------------------------------
# Build arm64 — native arm build with BuildKit registry cache
# ---------------------------------------------------------------------------
build:
name: Build Docker (arm64)
needs: [changes]
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v5
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version-file: ./.nvmrc
cache: pnpm
- name: Install dependencies & build
run: pnpm install --frozen-lockfile && pnpm build
- name: Login to ghcr.io
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/setup-buildx-action@v3
- name: Build and push Docker images (arm64)
run: |
BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
COMMIT_URL="${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}"
docker buildx build \
--platform linux/arm64 \
--build-arg GIT_COMMIT=${{ github.sha }} \
--build-arg BUILD_DATE="${BUILD_DATE}" \
--build-arg COMMIT_URL="${COMMIT_URL}" \
--cache-from type=registry,ref=ghcr.io/${{ github.repository }}:cache-arm64 \
--cache-to type=registry,ref=ghcr.io/${{ github.repository }}:cache-arm64,mode=max \
--target engine \
--tag ghcr.io/${{ github.repository }}:${{ github.sha }}-arm64 \
--push \
.
docker buildx build \
--platform linux/arm64 \
--build-arg GIT_COMMIT=${{ github.sha }} \
--build-arg BUILD_DATE="${BUILD_DATE}" \
--build-arg COMMIT_URL="${COMMIT_URL}" \
--cache-from type=registry,ref=ghcr.io/${{ github.repository }}-service:cache-arm64 \
--cache-to type=registry,ref=ghcr.io/${{ github.repository }}-service:cache-arm64,mode=max \
--target service \
--tag ghcr.io/${{ github.repository }}-service:${{ github.sha }}-arm64 \
--push \
.
# ---------------------------------------------------------------------------
# Build amd64 — native x86 build in parallel with arm64 [push only]
# ---------------------------------------------------------------------------
build_amd64:
name: Build Docker (amd64)
needs: [changes]
if: ${{ github.event_name == 'push' && needs.changes.outputs.code == 'true' }}
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v5
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version-file: ./.nvmrc
cache: pnpm
- name: Install dependencies & build
run: pnpm install --frozen-lockfile && pnpm build
- name: Login to ghcr.io
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/setup-buildx-action@v3
- name: Build and push Docker images (amd64)
run: |
BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
COMMIT_URL="${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}"
docker buildx build \
--platform linux/amd64 \
--build-arg GIT_COMMIT=${{ github.sha }} \
--build-arg BUILD_DATE="${BUILD_DATE}" \
--build-arg COMMIT_URL="${COMMIT_URL}" \
--cache-from type=registry,ref=ghcr.io/${{ github.repository }}:cache-amd64 \
--cache-to type=registry,ref=ghcr.io/${{ github.repository }}:cache-amd64,mode=max \
--target engine \
--tag ghcr.io/${{ github.repository }}:${{ github.sha }}-amd64 \
--push \
.
docker buildx build \
--platform linux/amd64 \
--build-arg GIT_COMMIT=${{ github.sha }} \
--build-arg BUILD_DATE="${BUILD_DATE}" \
--build-arg COMMIT_URL="${COMMIT_URL}" \
--cache-from type=registry,ref=ghcr.io/${{ github.repository }}-service:cache-amd64 \
--cache-to type=registry,ref=ghcr.io/${{ github.repository }}-service:cache-amd64,mode=max \
--target service \
--tag ghcr.io/${{ github.repository }}-service:${{ github.sha }}-amd64 \
--push \
.
# ---------------------------------------------------------------------------
# Merge — combine arm64 + amd64 into a single multi-arch manifest [push only]
# ---------------------------------------------------------------------------
build_manifest:
name: Merge multi-arch manifest
needs: [build, build_amd64]
if: ${{ github.event_name == 'push' }}
runs-on: ubuntu-24.04-arm
steps:
- name: Login to ghcr.io
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create and push multi-arch manifests
run: |
TAG="${GITHUB_REF_NAME//\//-}"
docker buildx imagetools create \
--tag ghcr.io/${{ github.repository }}:${{ github.sha }} \
--tag ghcr.io/${{ github.repository }}:${TAG} \
ghcr.io/${{ github.repository }}:${{ github.sha }}-amd64 \
ghcr.io/${{ github.repository }}:${{ github.sha }}-arm64
docker buildx imagetools create \
--tag ghcr.io/${{ github.repository }}-service:${{ github.sha }} \
--tag ghcr.io/${{ github.repository }}-service:${TAG} \
ghcr.io/${{ github.repository }}-service:${{ github.sha }}-amd64 \
ghcr.io/${{ github.repository }}-service:${{ github.sha }}-arm64
- name: Docker smoke test
run: |
docker run -d --name smoke -p 3000:3000 ghcr.io/${{ github.repository }}:${{ github.sha }}
trap 'docker rm -f smoke 2>/dev/null || true' EXIT
for i in $(seq 1 30); do
body=$(curl -sf http://localhost:3000/health 2>/dev/null || true)
if echo "$body" | grep -q '"ok":true'; then
echo "health check passed: $body"
exit 0
fi
sleep 1
done
echo "health check timed out"
docker logs smoke
exit 1
# ---------------------------------------------------------------------------
# E2E Docker — Docker image smoke + engine tests (runs on every push/PR)
# ---------------------------------------------------------------------------
e2e_docker:
name: E2E Docker
needs: build
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v5
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version-file: ./.nvmrc
cache: pnpm
- name: Install dependencies & build
run: pnpm install --frozen-lockfile && pnpm build
- name: Start Postgres with SSL
run: |
docker run -d --name ci-postgres \
-e POSTGRES_PASSWORD=postgres \
-p 55432:5432 \
postgres:18 \
-c ssl=on \
-c ssl_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem \
-c ssl_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
for i in $(seq 1 30); do
docker exec ci-postgres pg_isready -U postgres && break || sleep 2
done
- name: Login to ghcr.io
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker tests
run: |
IMAGE="ghcr.io/${{ github.repository }}:${{ github.sha }}-arm64"
docker pull "$IMAGE"
if [ -n "${STRIPE_API_KEY:-}" ]; then
bash e2e/docker.test.sh "$IMAGE"
else
echo "::warning::Docker e2e skipped — STRIPE_API_KEY not available. Running smoke only."
docker run --rm "$IMAGE" --version
fi
env:
STRIPE_API_KEY: ${{ secrets.STRIPE_API_KEY }}
POSTGRES_URL: 'postgres://postgres:postgres@localhost:55432/postgres'
GOOGLE_CLIENT_ID: ${{ vars.GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
GOOGLE_REFRESH_TOKEN: ${{ secrets.GOOGLE_REFRESH_TOKEN }}
GOOGLE_SPREADSHEET_ID: ${{ vars.GOOGLE_SPREADSHEET_ID }}
- name: Disconnect & time-limit tests (Docker)
run: |
pnpm --filter @stripe/sync-e2e exec vitest run test-disconnect.test.ts
env:
DISCONNECT_TEST_DOCKER: '1'
DISCONNECT_TEST_DOCKER_HOST_NETWORK: '1'
ENGINE_IMAGE: 'ghcr.io/${{ github.repository }}:${{ github.sha }}-arm64'
- name: Smokescreen proxy e2e
run: |
if [ -z "${STRIPE_API_KEY:-}" ]; then
echo "::warning::smokescreen.test.sh skipped — STRIPE_API_KEY not available"
exit 0
fi
bash e2e/smokescreen.test.sh
env:
STRIPE_API_KEY: ${{ secrets.STRIPE_API_KEY }}
ENGINE_IMAGE: 'ghcr.io/${{ github.repository }}:${{ github.sha }}-arm64'
- name: Publish test
run: |
if [ -z "${STRIPE_NPM_REGISTRY:-}" ]; then
echo "::warning::publish.test.sh skipped — STRIPE_NPM_REGISTRY not set"
exit 0
fi
bash e2e/publish.test.sh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ---------------------------------------------------------------------------
# E2E Stripe — Stripe API + Temporal integration tests (runs on every push/PR)
# ---------------------------------------------------------------------------
e2e_stripe:
name: E2E Stripe
runs-on: ubuntu-24.04-arm
services:
temporal-db:
image: postgres:16-alpine
env:
POSTGRES_USER: temporal
POSTGRES_PASSWORD: temporal
options: >-
--health-cmd "pg_isready -U temporal"
--health-interval 5s
--health-timeout 3s
--health-retries 5
temporal:
image: temporalio/auto-setup:latest
env:
DB: postgres12
DB_PORT: 5432
POSTGRES_USER: temporal
POSTGRES_PWD: temporal
POSTGRES_SEEDS: temporal-db
ports:
- 7233:7233
steps:
- uses: actions/checkout@v5
- name: Start Postgres with SSL
run: |
docker run -d --name ci-postgres \
-e POSTGRES_PASSWORD=postgres \
-p 55432:5432 \
postgres:18 \
-c ssl=on \
-c ssl_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem \
-c ssl_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
for i in $(seq 1 30); do
docker exec ci-postgres pg_isready -U postgres && break || sleep 2
done
- name: Install pnpm
uses: pnpm/action-setup@v5
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version-file: ./.nvmrc
cache: pnpm
- name: Install dependencies & build
run: pnpm install --frozen-lockfile && pnpm build
- name: E2E vitest tests
run: |
if [ -z "${STRIPE_API_KEY:-}" ]; then
echo "::warning::E2E tests skipped — STRIPE_API_KEY not available (fork PR?)"
exit 0
fi
pnpm --filter @stripe/sync-e2e exec vitest run \
--exclude 'service-docker.test.ts' \
--exclude 'test-server-all-api.test.ts' \
--exclude 'test-server-sync.test.ts' \
--exclude 'test-sync-e2e.test.ts' \
--exclude 'test-sync-engine.test.ts' \
--exclude 'test-e2e-network.test.ts' \
--exclude 'test-disconnect.test.ts' # ↑ run in dedicated Docker / main jobs
env:
STRIPE_API_KEY: ${{ secrets.STRIPE_API_KEY }}
POSTGRES_URL: 'postgres://postgres:postgres@localhost:55432/postgres'
TEMPORAL_ADDRESS: 'localhost:7233'
- name: Skipped test warnings
if: always()
run: '[ -f /tmp/vitest-skip-warnings.txt ] && cat /tmp/vitest-skip-warnings.txt || true'
# ---------------------------------------------------------------------------
# E2E Test Server — test-server suites that need Docker Compose infrastructure
# ---------------------------------------------------------------------------
e2e_test_server:
name: E2E Test Server
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v5
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version-file: ./.nvmrc
cache: pnpm
- name: Install dependencies & build
run: pnpm install --frozen-lockfile && pnpm build
- name: Start Docker Compose stack
run: |
docker compose -f compose.yml -f compose.dev.yml -f e2e/compose.e2e.yml \
up --build -d --wait temporal engine service worker
- name: Test server suites (parallel)
run: |
pnpm --filter @stripe/sync-e2e exec vitest run \
test-server-all-api.test.ts \
test-server-sync.test.ts \
test-sync-e2e.test.ts \
test-sync-engine.test.ts
env:
SKIP_SETUP: '1'
GH_TOKEN: ${{ github.token }}
GITHUB_TOKEN: ${{ github.token }}
- name: Network interruption tests (pauses containers)
run: |
pnpm --filter @stripe/sync-e2e exec vitest run \
test-e2e-network.test.ts
env:
SKIP_SETUP: '1'
- name: Skipped test warnings
if: always()
run: '[ -f /tmp/vitest-skip-warnings.txt ] && cat /tmp/vitest-skip-warnings.txt || true'
# ---------------------------------------------------------------------------
# E2E Service — service + worker Docker containers end-to-end (every push/PR)
# ---------------------------------------------------------------------------
e2e_service:
name: E2E Service Docker
needs: build
runs-on: ubuntu-24.04-arm
services:
temporal-db:
image: postgres:16-alpine
env:
POSTGRES_USER: temporal
POSTGRES_PASSWORD: temporal
options: >-
--health-cmd "pg_isready -U temporal"
--health-interval 5s
--health-timeout 3s
--health-retries 5
temporal:
image: temporalio/auto-setup:latest
env:
DB: postgres12
DB_PORT: 5432
POSTGRES_USER: temporal
POSTGRES_PWD: temporal
POSTGRES_SEEDS: temporal-db
ports:
- 7233:7233
steps:
- uses: actions/checkout@v5
- name: Start Postgres with SSL
run: |
docker run -d --name ci-postgres \
-e POSTGRES_PASSWORD=postgres \
-p 55432:5432 \
postgres:18 \
-c ssl=on \
-c ssl_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem \
-c ssl_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
for i in $(seq 1 30); do
docker exec ci-postgres pg_isready -U postgres && break || sleep 2
done
- name: Start stripe-mock
run: |
docker run -d --name ci-stripe-mock -p 12111:12111 stripe/stripe-mock:latest
for i in $(seq 1 20); do
if nc -z localhost 12111 2>/dev/null; then
echo "stripe-mock ready after ${i}s"
break
fi
sleep 0.5
done
nc -z localhost 12111 || (echo "stripe-mock failed to start"; exit 1)
- name: Login to ghcr.io
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Install pnpm
uses: pnpm/action-setup@v5
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version-file: ./.nvmrc
cache: pnpm
- name: Pull images and install dependencies in parallel
run: |
ENGINE_IMAGE="ghcr.io/${{ github.repository }}:${{ github.sha }}-arm64"
SERVICE_IMAGE="ghcr.io/${{ github.repository }}-service:${{ github.sha }}-arm64"
docker pull "$ENGINE_IMAGE" &
docker pull "$SERVICE_IMAGE" &
pnpm install --frozen-lockfile && pnpm build
wait
env:
ENGINE_IMAGE: ${{ github.repository }}
SERVICE_IMAGE: ${{ github.repository }}-service
- name: Wait for Temporal to be ready
run: |
echo "Waiting for Temporal gRPC on localhost:7233..."
for i in $(seq 1 90); do
if nc -z 127.0.0.1 7233 2>/dev/null; then
echo "Temporal port open after ${i}s"
break
fi
sleep 1
done
nc -z 127.0.0.1 7233 || (echo "Temporal never became ready"; exit 1)
# Sleep to allow schema migration + namespace creation to complete after port opens
sleep 20
- name: Start service containers
run: |
ENGINE_IMAGE="ghcr.io/${{ github.repository }}:${{ github.sha }}-arm64"
SERVICE_IMAGE="ghcr.io/${{ github.repository }}-service:${{ github.sha }}-arm64"
docker run -d --name ci-engine --network=host \
-e PORT=3000 \
"$ENGINE_IMAGE"
docker volume create ci-pipeline-data
docker run -d --name ci-service --network=host \
-v ci-pipeline-data:/data \
"$SERVICE_IMAGE" \
serve --temporal-address localhost:7233 --port 4020 --data-dir /data
docker run -d --name ci-worker --network=host \
-v ci-pipeline-data:/data \
"$SERVICE_IMAGE" \
worker --temporal-address localhost:7233 --engine-url http://localhost:3000 --data-dir /data
# Wait for service API health
for i in $(seq 1 60); do
if curl -sf http://localhost:4020/health > /dev/null 2>&1; then
echo "Service healthy after ${i}s"
break
fi
sleep 1
done
curl -sf http://localhost:4020/health || (echo "Service failed to start"; docker logs ci-service; exit 1)
# Verify worker is still running (crashes immediately on misconfiguration)
sleep 3
if ! docker inspect ci-worker --format='{{.State.Running}}' | grep -q true; then
echo "Worker container exited unexpectedly:"
docker logs ci-worker 2>&1 | tail -30
exit 1
fi
echo "Worker is running"
- name: Service Docker e2e
run: |
if [ -z "${STRIPE_API_KEY:-}" ]; then
echo "::warning::service-docker.test.ts skipped — STRIPE_API_KEY not available"
exit 0
fi
pnpm --filter @stripe/sync-e2e exec vitest run service-docker.test.ts
env:
STRIPE_API_KEY: ${{ secrets.STRIPE_API_KEY }}
POSTGRES_URL: 'postgres://postgres:postgres@localhost:55432/postgres'
POSTGRES_CONTAINER_URL: 'postgresql://postgres:postgres@localhost:55432/postgres'
STRIPE_MOCK_URL: 'http://localhost:12111'
SERVICE_DOCKER_E2E: '1'
SKIP_SETUP: '1'
- name: Dump container logs
if: always()
run: |
for name in ci-engine ci-service ci-worker; do
echo "=== $name ==="
docker logs "$name" 2>&1 | tail -100 || true
done
- name: Stop service containers
if: always()
run: docker rm -f ci-engine ci-service ci-worker ci-stripe-mock 2>/dev/null || true
- name: Skipped test warnings
if: always()
run: '[ -f /tmp/vitest-skip-warnings.txt ] && cat /tmp/vitest-skip-warnings.txt || true'
# ---------------------------------------------------------------------------
# Docker Hub — promote the built GHCR image to Docker Hub tags
# ---------------------------------------------------------------------------
publish_dockerhub:
name: Publish Docker Hub
needs: [build_manifest]
if: ${{ github.event_name == 'push' }}
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v5
with:
sparse-checkout: scripts/promote-to-dockerhub.sh
- name: Login to ghcr.io
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN_SYNC_ENGINE }}
- name: Sanitize ref name for Docker tag
id: tag
run: echo "name=${GITHUB_REF_NAME//\//-}" >> "$GITHUB_OUTPUT"
- name: Promote built image to Docker Hub
run: bash scripts/promote-to-dockerhub.sh
env:
GHCR_IMAGE: ghcr.io/${{ github.repository }}:${{ github.sha }}
DOCKERHUB_TAGS: ${{ steps.tag.outputs.name }}${{ github.ref_name == 'main' && ' latest' || '' }}