diff --git a/.changeset/fix-nightly-css-dts-docker.md b/.changeset/fix-nightly-css-dts-docker.md new file mode 100644 index 0000000000..a1eb0d8763 --- /dev/null +++ b/.changeset/fix-nightly-css-dts-docker.md @@ -0,0 +1,9 @@ +--- +'@hyperdx/app': patch +--- + +Copy `css.d.ts` into the Docker build stage so the app image compiles. The +TypeScript 6 upgrade added ambient `declare module '*.css'` declarations in +`css.d.ts` to satisfy TS2882 for side-effect stylesheet imports, but the +Dockerfiles only copied `mdx.d.ts`, so `next build` failed inside the +container. diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 0000000000..3a4ff8e591 --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,146 @@ +name: Docker Build +# Verifies the release Docker images actually build on PRs, without pushing. +# A source-level type check (`make ci-lint`) cannot catch build failures that +# only surface inside the image — e.g. a declaration file that exists in the +# repo but was never COPYed into the Docker build stage. Each image is built +# only when files that affect it change, so unrelated PRs stay fast. +on: + pull_request: + branches: [main] + workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +permissions: + contents: read +jobs: + # OTel Collector image (Go build via OCB) — docker/otel-collector/Dockerfile. + otel-collector-image: + name: Build OTel Collector Image + runs-on: ubuntu-24.04 + timeout-minutes: 25 + steps: + - name: Checkout + uses: actions/checkout@v6 + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v47.0.6 + with: + files: | + docker/otel-collector/** + packages/otel-collector/** + - name: Setup Docker Buildx + if: steps.changed-files.outputs.any_changed == 'true' + uses: docker/setup-buildx-action@v3 + - name: Build (no push) + if: steps.changed-files.outputs.any_changed == 'true' + uses: docker/build-push-action@v6 + with: + context: . + file: ./docker/otel-collector/Dockerfile + target: prod + platforms: linux/amd64 + push: false + cache-from: | + type=gha,scope=otel-collector-nightly-amd64 + type=gha,scope=docker-build-pr-otel-collector + cache-to: type=gha,mode=max,scope=docker-build-pr-otel-collector + + # App/prod image (API + App + common-utils Node build) — docker/hyperdx target prod. + # This is the image the nightly css.d.ts failure surfaced in; the same builder + # stage backs the all-in-one targets below. + app-image: + name: Build App Image + runs-on: ubuntu-24.04 + timeout-minutes: 25 + steps: + - name: Checkout + uses: actions/checkout@v6 + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v47.0.6 + with: + files: | + packages/api/** + packages/app/** + packages/common-utils/** + docker/hyperdx/** + package.json + yarn.lock + .yarn/** + tsconfig.base.json + nx.json + - name: Setup Docker Buildx + if: steps.changed-files.outputs.any_changed == 'true' + uses: docker/setup-buildx-action@v3 + - name: Build (no push) + if: steps.changed-files.outputs.any_changed == 'true' + uses: docker/build-push-action@v6 + with: + context: . + file: ./docker/hyperdx/Dockerfile + target: prod + platforms: linux/amd64 + push: false + build-contexts: | + hyperdx=./docker/hyperdx + api=./packages/api + app=./packages/app + build-args: | + CODE_VERSION=pr-${{ github.event.pull_request.number }} + cache-from: | + type=gha,scope=app-nightly-amd64 + type=gha,scope=docker-build-pr-app + cache-to: type=gha,mode=max,scope=docker-build-pr-app + + # All-in-one image (adds ClickHouse, MongoDB, OTel Collector to the app build) + # — docker/hyperdx target all-in-one-auth. Building the auth target also + # exercises the shared all-in-one-base, so no-auth need not be built + # separately. + # + # This target's base does `COPY --from=prod /app /app`, so it already + # rebuilds the entire App/prod image. To avoid duplicating that ~8-minute + # Node build on every app change, this job is gated ONLY on the incremental + # bundling inputs (ClickHouse / OTel / the shared Dockerfile) — NOT on + # api/app/common-utils/deps. Those are covered by the App Image job above, + # and they can't break the bundling layers, which only COPY the prod output. + all-in-one-image: + name: Build All-in-One Image + runs-on: ubuntu-24.04 + timeout-minutes: 40 + steps: + - name: Checkout + uses: actions/checkout@v6 + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v47.0.6 + with: + files: | + packages/otel-collector/** + docker/hyperdx/** + docker/clickhouse/** + docker/otel-collector/** + - name: Setup Docker Buildx + if: steps.changed-files.outputs.any_changed == 'true' + uses: docker/setup-buildx-action@v3 + - name: Build (no push) + if: steps.changed-files.outputs.any_changed == 'true' + uses: docker/build-push-action@v6 + with: + context: . + file: ./docker/hyperdx/Dockerfile + target: all-in-one-auth + platforms: linux/amd64 + push: false + build-contexts: | + clickhouse=./docker/clickhouse + otel-collector=./docker/otel-collector + hyperdx=./docker/hyperdx + api=./packages/api + app=./packages/app + build-args: | + CODE_VERSION=pr-${{ github.event.pull_request.number }} + cache-from: | + type=gha,scope=all-in-one-nightly-amd64 + type=gha,scope=docker-build-pr-all-in-one + cache-to: type=gha,mode=max,scope=docker-build-pr-all-in-one diff --git a/docker/hyperdx/Dockerfile b/docker/hyperdx/Dockerfile index fdf8bd696e..bb1e2bb1df 100644 --- a/docker/hyperdx/Dockerfile +++ b/docker/hyperdx/Dockerfile @@ -52,7 +52,7 @@ COPY .yarnrc.yml yarn.lock package.json nx.json .prettierrc .prettierignore ./ts # full source is copied in the build stages that need it. COPY ./packages/common-utils/package.json ./packages/common-utils/package.json COPY ./packages/api/jest.config.js ./packages/api/tsconfig.json ./packages/api/tsconfig.build.json ./packages/api/package.json ./packages/api/ -COPY ./packages/app/jest.config.js ./packages/app/tsconfig.json ./packages/app/tsconfig.build.json ./packages/app/package.json ./packages/app/next.config.mjs ./packages/app/mdx.d.ts ./packages/app/eslint.config.mjs ./packages/app/ +COPY ./packages/app/jest.config.js ./packages/app/tsconfig.json ./packages/app/tsconfig.build.json ./packages/app/package.json ./packages/app/next.config.mjs ./packages/app/mdx.d.ts ./packages/app/css.d.ts ./packages/app/eslint.config.mjs ./packages/app/ # Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. RUN apk add --no-cache libc6-compat diff --git a/packages/api/src/tasks/checkAlerts/index.ts b/packages/api/src/tasks/checkAlerts/index.ts index 82f15525df..96606dcaa8 100644 --- a/packages/api/src/tasks/checkAlerts/index.ts +++ b/packages/api/src/tasks/checkAlerts/index.ts @@ -330,7 +330,7 @@ export const getScheduledWindowStart = ( * that history fetched up-front (see getConsecutiveWindowHistories) lines up * exactly with the window processAlert evaluates. */ -export const getAlertWindowStart = (alert: IAlert, now: Date): Date => { +const getAlertWindowStart = (alert: IAlert, now: Date): Date => { const windowSizeInMins = ms(alert.interval) / 60000; const scheduleStartAt = normalizeScheduleStartAt({ alertId: alert.id, diff --git a/packages/app/Dockerfile b/packages/app/Dockerfile index 56edc5f284..eafc9c923f 100644 --- a/packages/app/Dockerfile +++ b/packages/app/Dockerfile @@ -9,7 +9,7 @@ COPY .yarnrc.yml yarn.lock package.json nx.json .prettierrc .prettierignore ./ts # Only copy package.json for workspace resolution during yarn install; # full source is copied in the build stages that need it. COPY ./packages/common-utils/package.json ./packages/common-utils/package.json -COPY ./packages/app/jest.config.js ./packages/app/tsconfig.json ./packages/app/tsconfig.build.json ./packages/app/package.json ./packages/app/next.config.mjs ./packages/app/mdx.d.ts ./packages/app/eslint.config.mjs ./packages/app/ +COPY ./packages/app/jest.config.js ./packages/app/tsconfig.json ./packages/app/tsconfig.build.json ./packages/app/package.json ./packages/app/next.config.mjs ./packages/app/mdx.d.ts ./packages/app/css.d.ts ./packages/app/eslint.config.mjs ./packages/app/ RUN --mount=type=cache,target=/root/.yarn/berry/cache,id=yarn-cache \ yarn install --mode=skip-build && yarn cache clean