diff --git a/.gitea/README.md b/.gitea/README.md index a4f298e..864d0cb 100644 --- a/.gitea/README.md +++ b/.gitea/README.md @@ -14,7 +14,11 @@ Job **changes** вычисляет флаги по путям в diff. Полн На **pull request** — **commitlint**. При изменении `deploy/docker/**` — job **docker-check** (`bake --print`, bake без `--push` если есть доступ к registry). -Кэш зависимостей: `actions/cache` с ключом `sha256sum` lockfile (`go.sum` / `pnpm-lock.yaml`). `hashFiles` в Gitea не используем. +Кэш зависимостей — нативный `actions/cache` (cache server act_runner), ключ `sha256sum` lockfile (не `hashFiles`). Пути **абсолютные** (`$HOME/.pnpm-store`, `go env GOMODCACHE` / `GOCACHE`): тильда `~` на Gitea часто не раскрывается и даёт вечный miss. + +Кэшируется целиком: pnpm store + `node_modules` + corepack; Go modules + GOCACHE + `golangci-lint` в `GOBIN`. При hit: `pnpm install --offline`, `go mod download` без сети. `setup-go cache:` и `golangci-lint-action` не используем — они завязаны на `hashFiles`. + +Если restore пишет `connect ECONNREFUSED` / `cache server not configured` — на runner включите cache server (см. ниже). Иначе каждый job снова качает пакеты (~минуты). Runner: `ubuntu-latest`, **bird2** из apt, Docker для **docker-check** (PR) и **publish** (CD). @@ -58,3 +62,21 @@ docker pull git.shx.one/myuser/evobgp-api:1.2.3 ``` См. [deploy/docker/README.md](../deploy/docker/README.md), [docs/quickstart.md](../docs/quickstart.md). + +## act_runner: cache server + +`actions/cache` ходит в **встроенный cache server** runner (не GitHub `type=gha`). Кэш локален для этого runner. + +В `config.yaml` runner: + +```yaml +cache: + enabled: true + dir: "" # по умолчанию $HOME/.cache/actcache + host: "" # IP, доступный из job-контейнера (не 0.0.0.0) + port: 8088 +``` + +Если runner в Docker, а jobs — отдельные контейнеры: пробросьте порт и задайте `host` (LAN IP хоста) или `external_server: "http://:8088/"`. Иначе restore — timeout/ECONNREFUSED и пакеты качаются снова. + +Не делайте `docker system prune -a` по cron: сотрётся и Docker-кэш FROM, и пользы от `cleanup: false` у buildx не будет. diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/cd.yaml index aa73da0..c9015fc 100644 --- a/.gitea/workflows/cd.yaml +++ b/.gitea/workflows/cd.yaml @@ -39,18 +39,26 @@ jobs: - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: "22" - - name: Enable pnpm via corepack - run: corepack enable + - name: Export cache paths + run: sh scripts/ci/export-cache-env.sh - id: pnpm-hash run: echo "key=$(sha256sum pnpm-lock.yaml | awk '{print $1}')" >> "$GITHUB_OUTPUT" - - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + - id: pnpm-cache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: - path: ~/.local/share/pnpm/store + path: | + ${{ env.PNPM_STORE_DIR }} + ${{ env.COREPACK_HOME }} + node_modules + apps/web/node_modules + packages/ui/node_modules key: pnpm-${{ runner.os }}-${{ steps.pnpm-hash.outputs.key }} restore-keys: | pnpm-${{ runner.os }}- - name: Install release tooling - run: pnpm install --frozen-lockfile + env: + PNPM_CACHE_HIT: ${{ steps.pnpm-cache.outputs.cache-hit }} + run: sh scripts/ci/pnpm-ci.sh - name: Verify releasable commit messages run: pnpm exec node scripts/commit/verify-release-commits.mjs - name: Semantic release diff --git a/.gitea/workflows/quality.yaml b/.gitea/workflows/quality.yaml index db8bbcc..30e32be 100644 --- a/.gitea/workflows/quality.yaml +++ b/.gitea/workflows/quality.yaml @@ -183,20 +183,28 @@ jobs: - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: "22" - - name: Enable pnpm via corepack - run: corepack enable + - name: Export cache paths + run: sh scripts/ci/export-cache-env.sh - id: pnpm-hash run: echo "key=$(sha256sum pnpm-lock.yaml | awk '{print $1}')" >> "$GITHUB_OUTPUT" - - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + - id: pnpm-cache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: - path: ~/.local/share/pnpm/store + path: | + ${{ env.PNPM_STORE_DIR }} + ${{ env.COREPACK_HOME }} + node_modules + apps/web/node_modules + packages/ui/node_modules key: pnpm-${{ runner.os }}-${{ steps.pnpm-hash.outputs.key }} restore-keys: | pnpm-${{ runner.os }}- - name: pnpm install, Redocly, codegen check + env: + PNPM_CACHE_HIT: ${{ steps.pnpm-cache.outputs.cache-hit }} run: | set -euxo pipefail - pnpm install --frozen-lockfile + sh scripts/ci/pnpm-ci.sh pnpm exec redocly lint docs/openapi.yaml chmod +x scripts/check-openapi-gen.sh sh scripts/check-openapi-gen.sh @@ -210,20 +218,28 @@ jobs: - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: "22" - - name: Enable pnpm via corepack - run: corepack enable + - name: Export cache paths + run: sh scripts/ci/export-cache-env.sh - id: pnpm-hash run: echo "key=$(sha256sum pnpm-lock.yaml | awk '{print $1}')" >> "$GITHUB_OUTPUT" - - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + - id: pnpm-cache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: - path: ~/.local/share/pnpm/store + path: | + ${{ env.PNPM_STORE_DIR }} + ${{ env.COREPACK_HOME }} + node_modules + apps/web/node_modules + packages/ui/node_modules key: pnpm-${{ runner.os }}-${{ steps.pnpm-hash.outputs.key }} restore-keys: | pnpm-${{ runner.os }}- - name: pnpm install, typecheck, lint, test, build + env: + PNPM_CACHE_HIT: ${{ steps.pnpm-cache.outputs.cache-hit }} run: | set -euxo pipefail - pnpm install --frozen-lockfile + sh scripts/ci/pnpm-ci.sh pnpm --filter @evobgp/web run typecheck pnpm --filter @evobgp/web run lint pnpm --filter @evobgp/web run test @@ -239,17 +255,29 @@ jobs: with: go-version: "1.24" cache: false + - name: Export cache paths + run: sh scripts/ci/export-cache-env.sh - id: go-hash run: echo "key=$(sha256sum go.sum | awk '{print $1}')" >> "$GITHUB_OUTPUT" - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: | - ~/go/pkg/mod - ~/.cache/go-build - key: go-${{ runner.os }}-${{ steps.go-hash.outputs.key }} + ${{ env.GOMODCACHE }} + ${{ env.GOCACHE }} + ${{ env.GOBIN }} + ${{ env.GOLANGCI_LINT_CACHE }} + key: go-${{ runner.os }}-1.24-gl1.64.8-${{ steps.go-hash.outputs.key }} restore-keys: | - go-${{ runner.os }}- + go-${{ runner.os }}-1.24-gl1.64.8- + go-${{ runner.os }}-1.24- + - name: Download modules + env: + GOMODCACHE: ${{ env.GOMODCACHE }} + GOCACHE: ${{ env.GOCACHE }} + run: go mod download - name: Vet + env: + GOFLAGS: -mod=readonly run: go vet ./... - name: Lint httpapi (ERR-01 / ARCH-01) run: sh scripts/lint-httpapi.sh @@ -258,13 +286,20 @@ jobs: - name: Validate remote speaker compose run: sh scripts/validate-remote-speaker-compose.sh - name: golangci-lint - uses: golangci/golangci-lint-action@55c2c1448f86e01eaae002a5a3a9624417608d84 # v6.5.2 - with: - version: v1.64.8 - skip-cache: true + env: + GOLANGCI_LINT_VERSION: v1.64.8 + run: sh scripts/ci/golangci-lint.sh - name: Test + env: + GOFLAGS: -mod=readonly + GOMODCACHE: ${{ env.GOMODCACHE }} + GOCACHE: ${{ env.GOCACHE }} run: go test ./... -race -count=1 - name: Build all commands + env: + GOFLAGS: -mod=readonly + GOMODCACHE: ${{ env.GOMODCACHE }} + GOCACHE: ${{ env.GOCACHE }} run: | set -euxo pipefail out="${RUNNER_TEMP}/evobgp-bin" @@ -321,13 +356,19 @@ jobs: - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: "22" - - name: Enable pnpm via corepack - run: corepack enable + - name: Export cache paths + run: sh scripts/ci/export-cache-env.sh - id: pnpm-hash run: echo "key=$(sha256sum pnpm-lock.yaml | awk '{print $1}')" >> "$GITHUB_OUTPUT" - - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + - id: pnpm-cache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: - path: ~/.local/share/pnpm/store + path: | + ${{ env.PNPM_STORE_DIR }} + ${{ env.COREPACK_HOME }} + node_modules + apps/web/node_modules + packages/ui/node_modules key: pnpm-${{ runner.os }}-${{ steps.pnpm-hash.outputs.key }} restore-keys: | pnpm-${{ runner.os }}- @@ -335,9 +376,10 @@ jobs: env: BASE_SHA: ${{ inputs.base_sha }} HEAD_SHA: ${{ inputs.head_sha }} + PNPM_CACHE_HIT: ${{ steps.pnpm-cache.outputs.cache-hit }} run: | set -euxo pipefail - pnpm install --frozen-lockfile + sh scripts/ci/pnpm-ci.sh pnpm exec commitlint --from "$BASE_SHA" --to "$HEAD_SHA" docker-check: diff --git a/scripts/ci/export-cache-env.sh b/scripts/ci/export-cache-env.sh new file mode 100644 index 0000000..22dbebc --- /dev/null +++ b/scripts/ci/export-cache-env.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env sh +# Абсолютные пути для actions/cache: на act_runner «~» часто не раскрывается → cache miss. +set -eu +: "${GITHUB_ENV:?GITHUB_ENV required (Gitea/GitHub Actions)}" + +HOME_DIR="${HOME:-}" +if [ -z "$HOME_DIR" ]; then + HOME_DIR="$(getent passwd "$(id -u)" 2>/dev/null | cut -d: -f6 || true)" +fi +HOME_DIR="${HOME_DIR:-/root}" + +if command -v go >/dev/null 2>&1; then + GOMODCACHE="$(go env GOMODCACHE)" + GOCACHE="$(go env GOCACHE)" + GOPATH="$(go env GOPATH)" +else + GOMODCACHE="${HOME_DIR}/go/pkg/mod" + GOCACHE="${HOME_DIR}/.cache/go-build" + GOPATH="${HOME_DIR}/go" +fi + +PNPM_STORE_DIR="${HOME_DIR}/.pnpm-store" +COREPACK_HOME="${HOME_DIR}/.cache/node/corepack" +GOBIN="${GOPATH}/bin" +GOLANGCI_LINT_CACHE="${HOME_DIR}/.cache/golangci-lint" + +mkdir -p "$PNPM_STORE_DIR" "$COREPACK_HOME" "$GOMODCACHE" "$GOCACHE" "$GOBIN" "$GOLANGCI_LINT_CACHE" + +{ + echo "HOME_DIR=${HOME_DIR}" + echo "PNPM_STORE_DIR=${PNPM_STORE_DIR}" + echo "COREPACK_HOME=${COREPACK_HOME}" + echo "GOMODCACHE=${GOMODCACHE}" + echo "GOCACHE=${GOCACHE}" + echo "GOPATH=${GOPATH}" + echo "GOBIN=${GOBIN}" + echo "GOLANGCI_LINT_CACHE=${GOLANGCI_LINT_CACHE}" +} >> "$GITHUB_ENV" + +echo "cache-env HOME_DIR=${HOME_DIR}" +echo "cache-env PNPM_STORE_DIR=${PNPM_STORE_DIR}" +echo "cache-env GOMODCACHE=${GOMODCACHE}" +echo "cache-env GOCACHE=${GOCACHE}" +echo "cache-env GOBIN=${GOBIN}" diff --git a/scripts/ci/golangci-lint.sh b/scripts/ci/golangci-lint.sh new file mode 100644 index 0000000..4197b84 --- /dev/null +++ b/scripts/ci/golangci-lint.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env sh +# Бинарь golangci-lint в GOBIN (кэш actions/cache), без goinstall и без hashFiles. +set -eu +VER="${GOLANGCI_LINT_VERSION:-v1.64.8}" +: "${GOBIN:?GOBIN required — run scripts/ci/export-cache-env.sh after setup-go}" + +mkdir -p "$GOBIN" +export PATH="${GOBIN}:${PATH}" +if [ -n "${GOLANGCI_LINT_CACHE:-}" ]; then + mkdir -p "$GOLANGCI_LINT_CACHE" + export GOLANGCI_LINT_CACHE +fi + +if [ ! -x "${GOBIN}/golangci-lint" ]; then + echo "install golangci-lint ${VER} -> ${GOBIN}" + curl -sSfL "https://raw.githubusercontent.com/golangci/golangci-lint/${VER}/install.sh" \ + | sh -s -- -b "$GOBIN" "$VER" +fi +golangci-lint version +golangci-lint run diff --git a/scripts/ci/pnpm-ci.sh b/scripts/ci/pnpm-ci.sh new file mode 100644 index 0000000..959faaf --- /dev/null +++ b/scripts/ci/pnpm-ci.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env sh +# pnpm install из кэша Gitea (store + node_modules). Без повторного download при hit. +set -eu +: "${PNPM_STORE_DIR:?PNPM_STORE_DIR required — run scripts/ci/export-cache-env.sh first}" + +export COREPACK_HOME="${COREPACK_HOME:-${HOME:-/root}/.cache/node/corepack}" +mkdir -p "$PNPM_STORE_DIR" "$COREPACK_HOME" +corepack enable +pnpm config set store-dir "$PNPM_STORE_DIR" + +echo "pnpm store: $(pnpm store path)" +echo "PNPM_CACHE_HIT=${PNPM_CACHE_HIT:-}" + +if [ "${PNPM_CACHE_HIT:-}" = "true" ]; then + if pnpm install --frozen-lockfile --offline; then + echo "pnpm install --offline (cache hit)" + exit 0 + fi + echo "offline install failed — prefer-offline" +fi +pnpm install --frozen-lockfile --prefer-offline