diff --git a/.dockerignore b/.dockerignore index 4d8429b6dc..414b991945 100644 --- a/.dockerignore +++ b/.dockerignore @@ -9,7 +9,7 @@ # dependencies -node_modules +**/node_modules .pnp .pnp.js diff --git a/.github/actions/get-image-tag/action.yml b/.github/actions/get-image-tag/action.yml index b9fc3e565b..e064623046 100644 --- a/.github/actions/get-image-tag/action.yml +++ b/.github/actions/get-image-tag/action.yml @@ -31,6 +31,11 @@ runs: sha=$(echo ${{ github.sha }} | head -c7) ts=$(date +%s) tag=${env}-${sha}-${ts} + elif [[ "${{ github.ref_name }}" == re2-*-* ]]; then + env=$(echo ${{ github.ref_name }} | cut -d- -f2) + sha=$(echo ${{ github.sha }} | head -c7) + ts=$(date +%s) + tag=${env}-${sha}-${ts} elif [[ "${{ github.ref_name }}" == v.docker.* ]]; then version="${GITHUB_REF_NAME#v.docker.}" tag="v${version}" diff --git a/.github/workflows/publish-worker-re2.yml b/.github/workflows/publish-worker-re2.yml new file mode 100644 index 0000000000..1f2b316afe --- /dev/null +++ b/.github/workflows/publish-worker-re2.yml @@ -0,0 +1,95 @@ +name: "⚒️ Publish Worker RE2" + +on: + workflow_call: + inputs: + image_tag: + description: The image tag to publish + type: string + required: false + default: "" + push: + tags: + - "re2-test-*" + - "re2-prod-*" + +permissions: + packages: write + contents: read + +jobs: + check-branch: + runs-on: ubuntu-latest + steps: + - name: Fail if re2-prod-* is pushed from a non-main branch + if: startsWith(github.ref_name, 're2-prod-') && github.base_ref != 'main' + run: | + echo "🚫 re2-prod-* tags can only be pushed from the main branch." + exit 1 + build: + needs: check-branch + strategy: + matrix: + package: [supervisor] + runs-on: ubuntu-latest + env: + DOCKER_BUILDKIT: "1" + steps: + - name: ⬇️ Checkout git repo + uses: actions/checkout@v4 + + - name: 📦 Get image repo + id: get_repository + run: | + if [[ "${{ matrix.package }}" == *-provider ]]; then + provider_type=$(echo "${{ matrix.package }}" | cut -d- -f1) + repo=provider/${provider_type} + else + repo="${{ matrix.package }}" + fi + echo "repo=${repo}" >> "$GITHUB_OUTPUT" + + - id: get_tag + uses: ./.github/actions/get-image-tag + with: + tag: ${{ inputs.image_tag }} + + - name: 🐋 Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # ..to avoid rate limits when pulling images + - name: 🐳 Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: 🚢 Build Container Image + run: | + docker build -t infra_image -f ./apps/${{ matrix.package }}/Containerfile . + + # ..to push image + - name: 🐙 Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: 🐙 Push to GitHub Container Registry + run: | + docker tag infra_image "$REGISTRY/$REPOSITORY:$IMAGE_TAG" + docker push "$REGISTRY/$REPOSITORY:$IMAGE_TAG" + env: + REGISTRY: ghcr.io/triggerdotdev + REPOSITORY: ${{ steps.get_repository.outputs.repo }} + IMAGE_TAG: ${{ steps.get_tag.outputs.tag }} + + - name: 🐙 Push 'v3' tag to GitHub Container Registry + if: steps.get_tag.outputs.is_semver == 'true' + run: | + docker tag infra_image "$REGISTRY/$REPOSITORY:v3" + docker push "$REGISTRY/$REPOSITORY:v3" + env: + REGISTRY: ghcr.io/triggerdotdev + REPOSITORY: ${{ steps.get_repository.outputs.repo }} diff --git a/apps/supervisor/Containerfile b/apps/supervisor/Containerfile new file mode 100644 index 0000000000..3e7fbd3781 --- /dev/null +++ b/apps/supervisor/Containerfile @@ -0,0 +1,63 @@ +FROM node:22-alpine@sha256:9bef0ef1e268f60627da9ba7d7605e8831d5b56ad07487d24d1aa386336d1944 AS node-22-alpine + +WORKDIR /app + +FROM node-22-alpine AS pruner + +COPY --chown=node:node . . +RUN npx -q turbo@1.10.9 prune --scope=supervisor --docker +RUN find . -name "node_modules" -type d -prune -exec rm -rf '{}' + + +FROM node-22-alpine AS base + +RUN apk add --no-cache dumb-init + +COPY --chown=node:node .gitignore .gitignore +COPY --from=pruner --chown=node:node /app/out/json/ . +COPY --from=pruner --chown=node:node /app/out/pnpm-lock.yaml ./pnpm-lock.yaml +COPY --from=pruner --chown=node:node /app/out/pnpm-workspace.yaml ./pnpm-workspace.yaml + +FROM base AS dev-deps +RUN corepack enable +ENV NODE_ENV development + +RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm fetch --no-frozen-lockfile +RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm install --ignore-scripts --no-frozen-lockfile + +FROM base AS prod-deps +RUN corepack enable +ENV NODE_ENV production + +RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm install --prod --no-frozen-lockfile + +COPY --from=pruner --chown=node:node /app/internal-packages/database/prisma/schema.prisma /app/internal-packages/database/prisma/schema.prisma + +ENV NPM_CONFIG_IGNORE_WORKSPACE_ROOT_CHECK true +RUN pnpx prisma@5.4.1 generate --schema /app/internal-packages/database/prisma/schema.prisma + +FROM base AS builder +RUN corepack enable + +COPY --from=pruner --chown=node:node /app/out/full/ . +COPY --from=dev-deps --chown=node:node /app/ . +COPY --chown=node:node turbo.json turbo.json +COPY --chown=node:node .configs/tsconfig.base.json .configs/tsconfig.base.json +COPY --chown=node:node scripts/updateVersion.ts scripts/updateVersion.ts + +RUN pnpm run generate && \ + pnpm run -r --filter supervisor... build + +FROM base AS runner + +RUN corepack enable +ENV NODE_ENV production + +COPY --from=pruner --chown=node:node /app/out/full/ . +COPY --from=prod-deps --chown=node:node /app . +COPY --from=builder --chown=node:node /app/apps/supervisor ./apps/supervisor + +EXPOSE 8000 + +USER node + +CMD [ "/usr/bin/dumb-init", "--", "pnpm", "run", "--filter", "supervisor", "start"] diff --git a/apps/supervisor/package.json b/apps/supervisor/package.json index af25633177..3718e6514d 100644 --- a/apps/supervisor/package.json +++ b/apps/supervisor/package.json @@ -5,6 +5,7 @@ "main": "dist/index.js", "type": "module", "scripts": { + "build": "tsc", "dev": "tsx --experimental-sqlite --require dotenv/config --watch src/index.ts", "start": "node --experimental-sqlite dist/index.js", "typecheck": "tsc --noEmit"