From ce6e693ea76b3ae8bf58fbb191b862c5e92cd068 Mon Sep 17 00:00:00 2001 From: Light1YT Date: Sat, 27 Jun 2026 16:11:26 +0500 Subject: [PATCH] fix(ci): pin prettier 3.9.0 for codegen check + pre-commit so api-types is byte-stable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit openapi-codegen-check был RED на каждом PR: CI шаг гонял bare `npx prettier` (резолвится в плавающий latest), а committed api-types.ts был отформатирован старым prettier (≤3.6.2, union-типы multi-line). 3.9.0 переносит union-wrapping на single-line → CI-регенерация всегда давала diff → gate падал. Чиним детерминизмом одной версии на обоих путях: - frontend/package.json: добавлен prettier@3.9.0 (exact) в devDependencies + обновлён package-lock.json. - CI openapi-codegen-check: bare `npx prettier` → ./node_modules/.bin/prettier (project-local pinned, не плавает). - .pre-commit-config.yaml: prettier hook additional_dependencies=["prettier@3.9.0"] — тот же движок, что в CI (alpha.8-обёртка байт-в-байт == prettier 3.9.0). - api-types.ts перегенерирован prettier 3.9.0 (union-типы single-line). Backend OpenAPI-схема не менялась — только формат. CI-регенерация теперь байт-в-байт совпадает с committed-файлом и с выводом pre-commit hook. --- .forgejo/workflows/ci.yml | 11 +++++++---- .pre-commit-config.yaml | 9 ++++++++- frontend/package-lock.json | 17 +++++++++++++++++ frontend/package.json | 1 + frontend/src/lib/api-types.ts | 18 ++++++------------ 5 files changed, 39 insertions(+), 17 deletions(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index ff1270b0..48a47220 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -276,14 +276,17 @@ jobs: working-directory: backend run: uv run python -c "import json; from app.main import app; print(json.dumps(app.openapi()))" > /tmp/openapi.json - - name: Regenerate api-types.ts + format (prettier defaults) + - name: Regenerate api-types.ts + format (project-local pinned prettier) working-directory: frontend # 1) openapi-typescript из дампнутого файла (эквивалент `npm run codegen`, - # который читает ту же схему по URL). 2) prettier (defaults, как - # pre-commit hook) → формат совпадает с committed-файлом. + # который читает ту же схему по URL). 2) ./node_modules/.bin/prettier — + # PROJECT-LOCAL, pinned (prettier 3.9.0 в devDependencies). НЕ `npx + # prettier` (тот резолвится в плавающий latest и расходится с pre-commit, + # ломая этот gate). Pre-commit hook гоняет тот же локальный prettier 3.9.0 + # → байт-в-байт идентичный формат. См. .pre-commit-config.yaml. run: | npx openapi-typescript /tmp/openapi.json -o src/lib/api-types.ts - npx prettier --write src/lib/api-types.ts + ./node_modules/.bin/prettier --write src/lib/api-types.ts - name: Assert api-types.ts is up-to-date working-directory: frontend diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 08770073..f085b541 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,10 +30,17 @@ repos: - id: ruff-format files: ^(backend|tradein-mvp/backend)/ - # Frontend — prettier on TS/TSX/JSON + # Frontend — prettier on TS/TSX/JSON. + # additional_dependencies pins the EXACT prettier engine (3.9.0) so this hook + # and CI (`openapi-codegen-check` → ./node_modules/.bin/prettier, also 3.9.0 + # via frontend/package.json) format byte-for-byte identically. Без явного pin + # mirrors-prettier@v4.0.0-alpha.8 тянет CLI-обёртку, а CI `npx prettier` + # плавает в latest → расхождение формата → codegen-gate RED. Меняешь версию + # здесь — синхронно меняй prettier в frontend/package.json + lockfile. - repo: https://github.com/pre-commit/mirrors-prettier rev: v4.0.0-alpha.8 hooks: - id: prettier + additional_dependencies: ["prettier@3.9.0"] files: ^frontend/.*\.(ts|tsx|js|jsx|json|css|md)$ exclude: ^frontend/(node_modules|\.next|package-lock\.json)/ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 82b9b63f..ebe0ca27 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -40,6 +40,7 @@ "jsdom": "^25.0.1", "openapi-typescript": "^7.0.0", "postcss": "^8.4.0", + "prettier": "3.9.0", "tailwindcss": "^4.0.0", "typescript": "5.9.3", "vitest": "^2.1.9" @@ -14055,6 +14056,22 @@ "node": ">=0.10.0" } }, + "node_modules/prettier": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.0.tgz", + "integrity": "sha512-LjIqSIC5VYLzs9WedVmJ2ljNAGnU+DteIClbahu4L/DBeWjZ6iT/k1lAYyu9JUh+1xINxWadaPw/Pl63y/agAw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index e6ef4dc6..1e6c5040 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -45,6 +45,7 @@ "jsdom": "^25.0.1", "openapi-typescript": "^7.0.0", "postcss": "^8.4.0", + "prettier": "3.9.0", "tailwindcss": "^4.0.0", "typescript": "5.9.3", "vitest": "^2.1.9" diff --git a/frontend/src/lib/api-types.ts b/frontend/src/lib/api-types.ts index a8ad8484..8e505843 100644 --- a/frontend/src/lib/api-types.ts +++ b/frontend/src/lib/api-types.ts @@ -2833,8 +2833,7 @@ export interface components { nspd_risk_zones?: components["schemas"]["RiskZone"][] | null; /** Nspd Opportunity Parcels */ nspd_opportunity_parcels?: - | components["schemas"]["OpportunityParcel"][] - | null; + components["schemas"]["OpportunityParcel"][] | null; /** Nspd Red Lines */ nspd_red_lines?: components["schemas"]["RedLine"][] | null; /** Nspd Dump */ @@ -3752,8 +3751,7 @@ export interface components { * @description Категория: competition|permitting|demand|risk|other */ category?: - | ("competition" | "permitting" | "demand" | "risk" | "other") - | null; + ("competition" | "permitting" | "demand" | "risk" | "other") | null; /** * Is Confidential * @description «Непублично» (§7.13): маркировка чувствительной заметки @@ -3846,8 +3844,7 @@ export interface components { body?: string | null; /** Category */ category?: - | ("competition" | "permitting" | "demand" | "risk" | "other") - | null; + ("competition" | "permitting" | "demand" | "risk" | "other") | null; /** Is Confidential */ is_confidential?: boolean | null; /** District */ @@ -4630,12 +4627,10 @@ export interface components { year_built?: number | null; /** House Type */ house_type?: - | ("panel" | "brick" | "monolith" | "monolith_brick" | "other") - | null; + ("panel" | "brick" | "monolith" | "monolith_brick" | "other") | null; /** Repair State */ repair_state?: - | ("needs_repair" | "standard" | "good" | "excellent") - | null; + ("needs_repair" | "standard" | "good" | "excellent") | null; /** Has Balcony */ has_balcony?: boolean | null; }; @@ -7877,8 +7872,7 @@ export interface operations { cad_num?: string | null; /** @description Фильтр по категории */ category?: - | ("competition" | "permitting" | "demand" | "risk" | "other") - | null; + ("competition" | "permitting" | "demand" | "risk" | "other") | null; /** @description Фильтр по пометке «непублично» */ is_confidential?: boolean | null; /** @description Фильтр по автору */