ci(cd): turbo-кэш, гейты typecheck/lint, таймауты, non-root образ
- .turbo в actions/cache (пересборки shared/db переиспользуются между прогонами) - typecheck в web/api джобах, lint бэкенда в api-джобе - убран пустой turbo test --filter=web (в web нет тестов) - timeout-minutes на все джобы - Dockerfile: USER node + --chown; прекомпрессия статики gzip+brotli на этапе сборки (Traefik не сжимает); compose: chown 1000:1000 data в инструкции
This commit is contained in:
@@ -25,6 +25,7 @@ jobs:
|
|||||||
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') &&
|
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') &&
|
||||||
needs.quality.result == 'success'
|
needs.quality.result == 'success'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 30
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
packages: write
|
packages: write
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
changes:
|
changes:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 5
|
||||||
outputs:
|
outputs:
|
||||||
web: ${{ steps.detect.outputs.web }}
|
web: ${{ steps.detect.outputs.web }}
|
||||||
api: ${{ steps.detect.outputs.api }}
|
api: ${{ steps.detect.outputs.api }}
|
||||||
@@ -148,6 +149,7 @@ jobs:
|
|||||||
needs: [changes]
|
needs: [changes]
|
||||||
if: needs.changes.outputs.web == 'true'
|
if: needs.changes.outputs.web == 'true'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
@@ -163,6 +165,7 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
${{ env.PNPM_STORE_DIR }}
|
${{ env.PNPM_STORE_DIR }}
|
||||||
${{ env.COREPACK_HOME }}
|
${{ env.COREPACK_HOME }}
|
||||||
|
.turbo
|
||||||
node_modules
|
node_modules
|
||||||
apps/web/node_modules
|
apps/web/node_modules
|
||||||
apps/api/node_modules
|
apps/api/node_modules
|
||||||
@@ -172,20 +175,21 @@ jobs:
|
|||||||
key: pnpm-${{ runner.os }}-${{ steps.pnpm-hash.outputs.key }}
|
key: pnpm-${{ runner.os }}-${{ steps.pnpm-hash.outputs.key }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
pnpm-${{ runner.os }}-
|
pnpm-${{ runner.os }}-
|
||||||
- name: pnpm install, lint, test, build
|
- name: pnpm install, lint, typecheck, build
|
||||||
env:
|
env:
|
||||||
PNPM_CACHE_HIT: ${{ steps.pnpm-cache.outputs.cache-hit }}
|
PNPM_CACHE_HIT: ${{ steps.pnpm-cache.outputs.cache-hit }}
|
||||||
run: |
|
run: |
|
||||||
set -euxo pipefail
|
set -euxo pipefail
|
||||||
sh scripts/ci/pnpm-ci.sh
|
sh scripts/ci/pnpm-ci.sh
|
||||||
pnpm --filter web lint
|
pnpm --filter web lint
|
||||||
pnpm exec turbo run test --filter=web
|
pnpm exec turbo run typecheck --filter=web
|
||||||
pnpm exec turbo run build --filter=web
|
pnpm exec turbo run build --filter=web
|
||||||
|
|
||||||
api:
|
api:
|
||||||
needs: [changes]
|
needs: [changes]
|
||||||
if: needs.changes.outputs.api == 'true'
|
if: needs.changes.outputs.api == 'true'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
@@ -201,6 +205,7 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
${{ env.PNPM_STORE_DIR }}
|
${{ env.PNPM_STORE_DIR }}
|
||||||
${{ env.COREPACK_HOME }}
|
${{ env.COREPACK_HOME }}
|
||||||
|
.turbo
|
||||||
node_modules
|
node_modules
|
||||||
apps/web/node_modules
|
apps/web/node_modules
|
||||||
apps/api/node_modules
|
apps/api/node_modules
|
||||||
@@ -210,18 +215,21 @@ jobs:
|
|||||||
key: pnpm-${{ runner.os }}-${{ steps.pnpm-hash.outputs.key }}
|
key: pnpm-${{ runner.os }}-${{ steps.pnpm-hash.outputs.key }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
pnpm-${{ runner.os }}-
|
pnpm-${{ runner.os }}-
|
||||||
- name: pnpm install, test, build
|
- name: pnpm install, lint, test, typecheck, build
|
||||||
env:
|
env:
|
||||||
PNPM_CACHE_HIT: ${{ steps.pnpm-cache.outputs.cache-hit }}
|
PNPM_CACHE_HIT: ${{ steps.pnpm-cache.outputs.cache-hit }}
|
||||||
run: |
|
run: |
|
||||||
set -euxo pipefail
|
set -euxo pipefail
|
||||||
sh scripts/ci/pnpm-ci.sh
|
sh scripts/ci/pnpm-ci.sh
|
||||||
|
pnpm exec turbo run lint --filter=@authportal/api --filter=@authportal/db --filter=@authportal/shared
|
||||||
pnpm exec turbo run test --filter=@authportal/api
|
pnpm exec turbo run test --filter=@authportal/api
|
||||||
|
pnpm exec turbo run typecheck --filter=@authportal/api
|
||||||
pnpm exec turbo run build --filter=@authportal/api
|
pnpm exec turbo run build --filter=@authportal/api
|
||||||
|
|
||||||
commitlint:
|
commitlint:
|
||||||
if: inputs.is_pull_request
|
if: inputs.is_pull_request
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
@@ -262,6 +270,7 @@ jobs:
|
|||||||
needs: [changes]
|
needs: [changes]
|
||||||
if: inputs.is_pull_request && needs.changes.outputs.docker == 'true'
|
if: inputs.is_pull_request && needs.changes.outputs.docker == 'true'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
# On server:
|
# On server:
|
||||||
# mkdir -p /opt/auth-portal/data
|
# mkdir -p /opt/auth-portal/data
|
||||||
|
# chown -R 1000:1000 /opt/auth-portal/data # container runs as non-root "node"
|
||||||
# cp deploy/docker-compose.traefik.yml /opt/auth-portal/docker-compose.yml
|
# cp deploy/docker-compose.traefik.yml /opt/auth-portal/docker-compose.yml
|
||||||
# cp deploy/env.traefik.example /opt/auth-portal/.env # fill secrets
|
# cp deploy/env.traefik.example /opt/auth-portal/.env # fill secrets
|
||||||
# docker login git.shx.one
|
# docker login git.shx.one
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
|
|||||||
pnpm install --frozen-lockfile
|
pnpm install --frozen-lockfile
|
||||||
|
|
||||||
FROM deps AS build
|
FROM deps AS build
|
||||||
|
RUN apk add --no-cache brotli
|
||||||
COPY apps/web apps/web
|
COPY apps/web apps/web
|
||||||
COPY apps/api apps/api
|
COPY apps/api apps/api
|
||||||
COPY packages/ui packages/ui
|
COPY packages/ui packages/ui
|
||||||
@@ -25,6 +26,8 @@ RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
|
|||||||
pnpm turbo build --filter=web --filter=@authportal/api \
|
pnpm turbo build --filter=web --filter=@authportal/api \
|
||||||
&& pnpm --filter @authportal/api deploy --prod /out \
|
&& pnpm --filter @authportal/api deploy --prod /out \
|
||||||
&& cp -r apps/web/dist /out/static \
|
&& cp -r apps/web/dist /out/static \
|
||||||
|
&& find /out/static -type f \( -name '*.js' -o -name '*.css' \) -exec sh -c \
|
||||||
|
'gzip -k9 "$1" && brotli -f -q 11 -o "$1.br" "$1"' _ {} \; \
|
||||||
&& rm -rf /out/src /out/test /out/.turbo \
|
&& rm -rf /out/src /out/test /out/.turbo \
|
||||||
&& rm -rf /out/node_modules/@authportal/db/src /out/node_modules/@authportal/db/scripts /out/node_modules/@authportal/db/.turbo \
|
&& rm -rf /out/node_modules/@authportal/db/src /out/node_modules/@authportal/db/scripts /out/node_modules/@authportal/db/.turbo \
|
||||||
&& rm -rf /out/node_modules/@authportal/shared/src /out/node_modules/@authportal/shared/.turbo \
|
&& rm -rf /out/node_modules/@authportal/shared/src /out/node_modules/@authportal/shared/.turbo \
|
||||||
@@ -32,7 +35,10 @@ RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
|
|||||||
|
|
||||||
FROM ${BASE_NODE} AS runtime
|
FROM ${BASE_NODE} AS runtime
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN apk add --no-cache ca-certificates
|
# Не-root runtime; /data — bind mount с хоста, на сервере нужен
|
||||||
|
# `chown -R 1000:1000 ./data` (см. deploy/docker-compose.traefik.yml).
|
||||||
|
RUN apk add --no-cache ca-certificates \
|
||||||
|
&& mkdir -p /data && chown node:node /data
|
||||||
ARG VERSION=dev
|
ARG VERSION=dev
|
||||||
ARG GIT_SHA=unknown
|
ARG GIT_SHA=unknown
|
||||||
ARG BUILD_TIME=
|
ARG BUILD_TIME=
|
||||||
@@ -43,7 +49,8 @@ ENV NODE_ENV=production \
|
|||||||
APP_VERSION=${VERSION} \
|
APP_VERSION=${VERSION} \
|
||||||
GIT_SHA=${GIT_SHA} \
|
GIT_SHA=${GIT_SHA} \
|
||||||
BUILD_TIME=${BUILD_TIME}
|
BUILD_TIME=${BUILD_TIME}
|
||||||
COPY --from=build /out ./
|
COPY --from=build --chown=node:node /out ./
|
||||||
|
USER node
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
VOLUME ["/data"]
|
VOLUME ["/data"]
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||||||
|
|||||||
Reference in New Issue
Block a user