create-projx 1.6.0 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -19
- package/dist/{baseline-72Z7TC2E.js → baseline-KTCFW2FK.js} +2 -2
- package/dist/{chunk-G74HYIE4.js → chunk-D33FXCNT.js} +16 -7
- package/dist/{chunk-FTHX7ILT.js → chunk-LTIJPVRZ.js} +21 -4
- package/dist/index.js +3 -3
- package/dist/{utils-OOY5OZDX.js → utils-VY5BBJBQ.js} +3 -1
- package/package.json +8 -9
- package/src/templates/README.md.ejs +1 -1
- package/src/templates/ci.yml.ejs +24 -7
- package/src/templates/pre-commit.ejs +2 -1
package/README.md
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
**Go from blank folder to production-ready project in 30 seconds.** Backend-only API, AI/ML app, mobile, full-stack, infra setup — pick what you need and get it wired with auth, database, Docker, CI/CD, hooks, and tests. All optional. All yours.
|
|
9
9
|
|
|
10
|
+

|
|
11
|
+
|
|
10
12
|
```bash
|
|
11
13
|
npx create-projx my-app
|
|
12
14
|
```
|
|
@@ -175,27 +177,35 @@ Your custom files (controllers, pages, middleware) are never deleted. Files you
|
|
|
175
177
|
|
|
176
178
|
### Skip Files
|
|
177
179
|
|
|
178
|
-
|
|
180
|
+
Common user-owned files are **default-skipped** automatically — template updates won't touch them:
|
|
181
|
+
|
|
182
|
+
| Scope | Default skips |
|
|
183
|
+
|-------|---------------|
|
|
184
|
+
| Root (`.projx`) | `docker-compose.yml`, `docker-compose.dev.yml`, `README.md`, `.githooks/pre-commit`, `.github/workflows/ci.yml`, `setup.sh` |
|
|
185
|
+
| fastapi | `pyproject.toml` |
|
|
186
|
+
| fastify / frontend / e2e | `package.json` |
|
|
187
|
+
| mobile | `pubspec.yaml` |
|
|
188
|
+
|
|
189
|
+
Defaults are applied once on first `update` and saved to the `skip` array. To skip additional files, add them to `skip` in `.projx` (root-level) or `.projx-component` (per-component):
|
|
179
190
|
|
|
180
191
|
```json
|
|
192
|
+
// .projx — root skip
|
|
181
193
|
{
|
|
182
|
-
"
|
|
183
|
-
"
|
|
184
|
-
"skip": ["src/**", "tests/**"]
|
|
194
|
+
"version": "x.y.z",
|
|
195
|
+
"skip": ["docker-compose.yml", "README.md", "my-custom-config.yml"]
|
|
185
196
|
}
|
|
186
197
|
```
|
|
187
198
|
|
|
188
|
-
To skip root-level files (docker-compose, README), add `skip` to `.projx`:
|
|
189
|
-
|
|
190
199
|
```json
|
|
200
|
+
// fastapi/.projx-component — component skip
|
|
191
201
|
{
|
|
192
|
-
"
|
|
193
|
-
"
|
|
194
|
-
"skip": ["
|
|
202
|
+
"component": "fastapi",
|
|
203
|
+
"origin": "init",
|
|
204
|
+
"skip": ["pyproject.toml", "src/custom_middleware.py"]
|
|
195
205
|
}
|
|
196
206
|
```
|
|
197
207
|
|
|
198
|
-
|
|
208
|
+
To opt back in to updates for a skipped file, use `npx create-projx unpin <file>`.
|
|
199
209
|
|
|
200
210
|
## Options
|
|
201
211
|
|
|
@@ -274,14 +284,14 @@ When both `fastapi` and `fastify` exist, the entity generates in the **primary b
|
|
|
274
284
|
|
|
275
285
|
Override with `--ai` (fastapi) or `--backend` (fastify).
|
|
276
286
|
|
|
277
|
-
| Component | Generated
|
|
278
|
-
| ------------------------- |
|
|
279
|
-
| Primary backend (fastapi) | `src/entities/<name>/_model.py` + `tests/test_<name>_entity.py` — model + 11 CRUD/auth tests
|
|
280
|
-
| Primary backend (fastify) | `src/modules/<name>/schemas.ts` + `index.ts` + Prisma model + `tests/modules/<name>.test.ts`
|
|
281
|
-
| `frontend` | `src/types/<name>.ts` — TypeScript interface + Create/Update variants
|
|
282
|
-
| `mobile` | `lib/entities/<name>/model.dart` — Dart class with fromJson/toJson/copyWith
|
|
287
|
+
| Component | Generated |
|
|
288
|
+
| ------------------------- | -------------------------------------------------------------------------------------------- |
|
|
289
|
+
| Primary backend (fastapi) | `src/entities/<name>/_model.py` + `tests/test_<name>_entity.py` — model + 11 CRUD/auth tests |
|
|
290
|
+
| Primary backend (fastify) | `src/modules/<name>/schemas.ts` + `index.ts` + Prisma model + `tests/modules/<name>.test.ts` |
|
|
291
|
+
| `frontend` | `src/types/<name>.ts` — TypeScript interface + Create/Update variants |
|
|
292
|
+
| `mobile` | `lib/entities/<name>/model.dart` — Dart class with fromJson/toJson/copyWith |
|
|
283
293
|
|
|
284
|
-
**Tests included**: every `gen entity` writes a working integration test file alongside the model — 11 tests for FastAPI (extending `BaseEntityApiTest`), 11 tests for Fastify (via `describeCrudEntity`). Both run against a real database (Postgres
|
|
294
|
+
**Tests included**: every `gen entity` writes a working integration test file alongside the model — 11 tests for FastAPI (extending `BaseEntityApiTest`), 11 tests for Fastify (via `describeCrudEntity`). Both run against a real database (Postgres). New entities ship green from day one — no scrambling to bolt on tests at go-live.
|
|
285
295
|
|
|
286
296
|
No migrations — run `alembic revision --autogenerate` or `prisma migrate dev` (via your package manager) when ready.
|
|
287
297
|
|
|
@@ -343,6 +353,8 @@ The core idea: define a data model, get everything else for free.
|
|
|
343
353
|
|
|
344
354
|
**Backend** — Drop a model file. The registry auto-discovers it and generates CRUD routes, schemas, pagination, filtering, sorting, search, FK expansion, and OpenAPI docs.
|
|
345
355
|
|
|
356
|
+
**Field privacy** — Sensitive columns (`password_hash`, `secret`, `api_key`, `mfa_secret`, etc.) are automatically stripped from API responses and `/_meta` via a built-in baseline. Add project-specific hidden fields per entity (`__hidden_fields__` in FastAPI, `hiddenFields` in Fastify). Mark entire entities as `__private__` / `private: true` to hide them from the API entirely — no routes registered, not listed in `/_meta`. The `/_meta` endpoint requires authentication on both backends.
|
|
357
|
+
|
|
346
358
|
**Frontend** — Fetches metadata from `GET /api/v1/_meta`, renders table + form UI automatically. Customize with overrides.
|
|
347
359
|
|
|
348
360
|
**Mobile** — Same metadata endpoint, generates list/detail/form screens. Offline-first with local DB and sync queue.
|
|
@@ -361,8 +373,8 @@ The CLI lives in `cli/`. Templates are the root-level component directories (`fa
|
|
|
361
373
|
|
|
362
374
|
```bash
|
|
363
375
|
cd cli
|
|
364
|
-
|
|
365
|
-
|
|
376
|
+
pnpm test # run tests
|
|
377
|
+
pnpm build # build CLI
|
|
366
378
|
```
|
|
367
379
|
|
|
368
380
|
## Try it now
|
|
@@ -6,19 +6,20 @@ import {
|
|
|
6
6
|
readComponentMarker,
|
|
7
7
|
readProjxConfig,
|
|
8
8
|
render,
|
|
9
|
+
renderEjsInDir,
|
|
9
10
|
replaceInDir,
|
|
10
11
|
replaceInFile,
|
|
11
12
|
sharedTemplateDir,
|
|
12
13
|
toSnake,
|
|
13
14
|
upsertComponentMarker,
|
|
14
15
|
writeProjxConfig
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-LTIJPVRZ.js";
|
|
16
17
|
|
|
17
18
|
// src/baseline.ts
|
|
18
19
|
import { existsSync, writeFileSync, unlinkSync } from "fs";
|
|
19
|
-
import { chmod, mkdir, writeFile, rm, readFile as readFile2 } from "fs/promises";
|
|
20
|
+
import { chmod, mkdir, writeFile, rm, readFile as readFile2, copyFile } from "fs/promises";
|
|
20
21
|
import { execSync } from "child_process";
|
|
21
|
-
import { join as join2 } from "path";
|
|
22
|
+
import { join as join2, dirname } from "path";
|
|
22
23
|
import { tmpdir } from "os";
|
|
23
24
|
|
|
24
25
|
// src/generators/index.ts
|
|
@@ -106,7 +107,7 @@ function buildDisplayNames(paths) {
|
|
|
106
107
|
}
|
|
107
108
|
var BASELINE_REF = "refs/projx/baseline";
|
|
108
109
|
async function migrateComponentMarkers(cwd, components, componentPaths, applyDefaults) {
|
|
109
|
-
const { readComponentMarker: readComponentMarker2, writeComponentMarker } = await import("./utils-
|
|
110
|
+
const { readComponentMarker: readComponentMarker2, writeComponentMarker } = await import("./utils-VY5BBJBQ.js");
|
|
110
111
|
for (const component of components) {
|
|
111
112
|
const dir = componentPaths[component];
|
|
112
113
|
const markerDir = join2(cwd, dir);
|
|
@@ -259,7 +260,12 @@ async function tryThreeWayMerge(cwd, templateDir, baselineRef, componentPaths) {
|
|
|
259
260
|
if (file === ".projx") continue;
|
|
260
261
|
if (file.endsWith("/.projx-component") || file === ".projx-component") continue;
|
|
261
262
|
const oursPath = join2(cwd, file);
|
|
262
|
-
if (!existsSync(oursPath))
|
|
263
|
+
if (!existsSync(oursPath)) {
|
|
264
|
+
await mkdir(dirname(oursPath), { recursive: true });
|
|
265
|
+
await copyFile(join2(templateDir, file), oursPath);
|
|
266
|
+
merged.push(file);
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
263
269
|
const baseContent = lookupBaseContent(cwd, baselineRef, file, pathFallbacks);
|
|
264
270
|
if (baseContent === null) continue;
|
|
265
271
|
let theirsContent;
|
|
@@ -324,8 +330,10 @@ async function removeSkippedFiles(dir, skipPatterns, realDir) {
|
|
|
324
330
|
const rel = full.slice(base.length + 1);
|
|
325
331
|
if (entry.isDirectory()) {
|
|
326
332
|
await walk(full, base);
|
|
327
|
-
} else if (entry.name !== ".projx-component"
|
|
328
|
-
|
|
333
|
+
} else if (entry.name !== ".projx-component") {
|
|
334
|
+
const targetRel = rel.endsWith(".ejs") ? rel.slice(0, -".ejs".length) : rel;
|
|
335
|
+
if (!matchesSkip(targetRel, skipPatterns) && !matchesSkip(rel, skipPatterns)) continue;
|
|
336
|
+
if (realDir && !existsSync(join2(realDir, targetRel))) continue;
|
|
329
337
|
await unlink(full);
|
|
330
338
|
}
|
|
331
339
|
}
|
|
@@ -358,6 +366,7 @@ async function writeTemplateToDir(dest, repoDir, components, componentPaths, var
|
|
|
358
366
|
await cp(srcDir, outDir, { recursive: true, force: true });
|
|
359
367
|
}
|
|
360
368
|
await rm(tmpDir, { recursive: true, force: true });
|
|
369
|
+
await renderEjsInDir(outDir, vars);
|
|
361
370
|
await upsertComponentMarker(join2(dest, targetDir), component, skipPatterns.length > 0 ? skipPatterns : void 0);
|
|
362
371
|
}
|
|
363
372
|
if (!vars.pathsUpper) {
|
|
@@ -19,13 +19,13 @@ var PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
|
|
|
19
19
|
function pmCommands(pm) {
|
|
20
20
|
switch (pm) {
|
|
21
21
|
case "npm":
|
|
22
|
-
return { name: "npm", install: "npm install", ci: "npm ci", run: "npm run", exec: "npx", dlx: "npx", lockfile: "package-lock.json", prismaExec: "npx prisma", runDev: "npm run dev" };
|
|
22
|
+
return { name: "npm", install: "npm install", ci: "npm ci", run: "npm run", exec: "npx", dlx: "npx", lockfile: "package-lock.json", prismaExec: "npx prisma", runDev: "npm run dev", audit: "npm audit --omit=dev" };
|
|
23
23
|
case "pnpm":
|
|
24
|
-
return { name: "pnpm", install: "pnpm install", ci: "pnpm install --frozen-lockfile", run: "pnpm", exec: "pnpm exec", dlx: "pnpm dlx", lockfile: "pnpm-lock.yaml", prismaExec: "pnpm prisma", runDev: "pnpm dev" };
|
|
24
|
+
return { name: "pnpm", install: "pnpm install", ci: "pnpm install --frozen-lockfile", run: "pnpm", exec: "pnpm exec", dlx: "pnpm dlx", lockfile: "pnpm-lock.yaml", prismaExec: "pnpm prisma", runDev: "pnpm dev", audit: "pnpm audit --prod" };
|
|
25
25
|
case "yarn":
|
|
26
|
-
return { name: "yarn", install: "yarn", ci: "yarn --frozen-lockfile", run: "yarn", exec: "yarn", dlx: "yarn dlx", lockfile: "yarn.lock", prismaExec: "yarn prisma", runDev: "yarn dev" };
|
|
26
|
+
return { name: "yarn", install: "yarn", ci: "yarn --frozen-lockfile", run: "yarn", exec: "yarn", dlx: "yarn dlx", lockfile: "yarn.lock", prismaExec: "yarn prisma", runDev: "yarn dev", audit: "yarn npm audit --environment production" };
|
|
27
27
|
case "bun":
|
|
28
|
-
return { name: "bun", install: "bun install", ci: "bun install --frozen-lockfile", run: "bun run", exec: "bunx", dlx: "bunx", lockfile: "bun.lockb", prismaExec: "bunx prisma", runDev: "bun run dev" };
|
|
28
|
+
return { name: "bun", install: "bun install", ci: "bun install --frozen-lockfile", run: "bun run", exec: "bunx", dlx: "bunx", lockfile: "bun.lockb", prismaExec: "bunx prisma", runDev: "bun run dev", audit: "bun audit --prod" };
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
function detectPackageManager(cwd) {
|
|
@@ -369,6 +369,22 @@ function render(template, vars) {
|
|
|
369
369
|
}
|
|
370
370
|
return output.join("\n").replace(/\n{3,}/g, "\n\n");
|
|
371
371
|
}
|
|
372
|
+
async function renderEjsInDir(dir, vars) {
|
|
373
|
+
if (!existsSync(dir)) return;
|
|
374
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
375
|
+
for (const entry of entries) {
|
|
376
|
+
const full = join(dir, entry.name);
|
|
377
|
+
if (entry.isDirectory()) {
|
|
378
|
+
await renderEjsInDir(full, vars);
|
|
379
|
+
} else if (entry.name.endsWith(".ejs")) {
|
|
380
|
+
const content = await readFile(full, "utf-8");
|
|
381
|
+
const rendered = render(content, vars);
|
|
382
|
+
const out = full.slice(0, -".ejs".length);
|
|
383
|
+
await writeFile(out, rendered);
|
|
384
|
+
await rm(full);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
372
388
|
function detectProjectName(cwd, components, componentPaths) {
|
|
373
389
|
for (const component of components) {
|
|
374
390
|
const dir = componentPaths[component] ?? component;
|
|
@@ -420,5 +436,6 @@ export {
|
|
|
420
436
|
discoverComponentPaths,
|
|
421
437
|
discoverComponentsFromMarkers,
|
|
422
438
|
render,
|
|
439
|
+
renderEjsInDir,
|
|
423
440
|
detectProjectName
|
|
424
441
|
};
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
matchesSkip,
|
|
10
10
|
saveBaselineRef,
|
|
11
11
|
writeTemplateToDir
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-D33FXCNT.js";
|
|
13
13
|
import {
|
|
14
14
|
COMPONENTS,
|
|
15
15
|
COMPONENT_MARKER,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
toTitle,
|
|
34
34
|
writeComponentMarker,
|
|
35
35
|
writeProjxConfig
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-LTIJPVRZ.js";
|
|
37
37
|
|
|
38
38
|
// src/index.ts
|
|
39
39
|
import { existsSync as existsSync11 } from "fs";
|
|
@@ -371,7 +371,7 @@ function hasUncommittedChanges(cwd) {
|
|
|
371
371
|
async function findPinnedFilesWithUpdates(cwd, repoDir, components, componentPaths, vars, version, componentSkips, rootSkip) {
|
|
372
372
|
const { mkdir: mkdir5, rm: rm2, readFile: readFile7 } = await import("fs/promises");
|
|
373
373
|
const { tmpdir: tmpdir2 } = await import("os");
|
|
374
|
-
const { writeTemplateToDir: writeTemplateToDir2 } = await import("./baseline-
|
|
374
|
+
const { writeTemplateToDir: writeTemplateToDir2 } = await import("./baseline-KTCFW2FK.js");
|
|
375
375
|
const config = await readProjxConfig(cwd);
|
|
376
376
|
const rootPinned = Array.isArray(config.skip) ? config.skip : [];
|
|
377
377
|
const componentPinned = [];
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
readFileOrNull,
|
|
24
24
|
readProjxConfig,
|
|
25
25
|
render,
|
|
26
|
+
renderEjsInDir,
|
|
26
27
|
replaceInDir,
|
|
27
28
|
replaceInFile,
|
|
28
29
|
sharedTemplateDir,
|
|
@@ -32,7 +33,7 @@ import {
|
|
|
32
33
|
upsertComponentMarker,
|
|
33
34
|
writeComponentMarker,
|
|
34
35
|
writeProjxConfig
|
|
35
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-LTIJPVRZ.js";
|
|
36
37
|
export {
|
|
37
38
|
COMPONENTS,
|
|
38
39
|
COMPONENT_MARKER,
|
|
@@ -58,6 +59,7 @@ export {
|
|
|
58
59
|
readFileOrNull,
|
|
59
60
|
readProjxConfig,
|
|
60
61
|
render,
|
|
62
|
+
renderEjsInDir,
|
|
61
63
|
replaceInDir,
|
|
62
64
|
replaceInFile,
|
|
63
65
|
sharedTemplateDir,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-projx",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.2",
|
|
4
4
|
"description": "Scaffold production-grade fullstack projects in seconds. FastAPI, Fastify, React, Flutter, Terraform — with auth, database, CI/CD, E2E tests, and Docker. One command, ready to deploy.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,13 +10,6 @@
|
|
|
10
10
|
"dist",
|
|
11
11
|
"src/templates"
|
|
12
12
|
],
|
|
13
|
-
"scripts": {
|
|
14
|
-
"build": "tsup src/index.ts --format esm --target node18 --clean",
|
|
15
|
-
"dev": "tsup src/index.ts --format esm --target node18 --watch",
|
|
16
|
-
"test": "vitest run",
|
|
17
|
-
"test:watch": "vitest",
|
|
18
|
-
"prepublishOnly": "npm run build"
|
|
19
|
-
},
|
|
20
13
|
"keywords": [
|
|
21
14
|
"projx",
|
|
22
15
|
"scaffold",
|
|
@@ -61,5 +54,11 @@
|
|
|
61
54
|
"typescript": "^5",
|
|
62
55
|
"typescript-eslint": "^8.58.0",
|
|
63
56
|
"vitest": "^4.1.2"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "tsup src/index.ts --format esm --target node18 --clean",
|
|
60
|
+
"dev": "tsup src/index.ts --format esm --target node18 --watch",
|
|
61
|
+
"test": "vitest run",
|
|
62
|
+
"test:watch": "vitest"
|
|
64
63
|
}
|
|
65
|
-
}
|
|
64
|
+
}
|
|
@@ -24,7 +24,7 @@ Scaffolded with [Projx](https://github.com/ukanhaupa/projx).
|
|
|
24
24
|
<% if (components.includes('infra')) { %>
|
|
25
25
|
| **<%= paths.infra %>/** | Terraform, AWS (EKS, RDS, VPC, CodePipeline) |
|
|
26
26
|
<% } %>
|
|
27
|
-
| **Identity** |
|
|
27
|
+
| **Identity** | OIDC / JWT |
|
|
28
28
|
| **Containers** | Docker, Docker Compose |
|
|
29
29
|
|
|
30
30
|
## Getting Started
|
package/src/templates/ci.yml.ejs
CHANGED
|
@@ -61,10 +61,21 @@ jobs:
|
|
|
61
61
|
<%= paths.infra %>:
|
|
62
62
|
- '<%= paths.infra %>/**'
|
|
63
63
|
<% } %>
|
|
64
|
+
|
|
65
|
+
secrets:
|
|
66
|
+
name: Secret scan
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v5
|
|
70
|
+
with:
|
|
71
|
+
fetch-depth: 0
|
|
72
|
+
- uses: gitleaks/gitleaks-action@v2
|
|
73
|
+
env:
|
|
74
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
64
75
|
<% if (components.includes('fastapi')) { %>
|
|
65
76
|
|
|
66
77
|
<%= paths.fastapi %>:
|
|
67
|
-
name: <%= displayNames.fastapi %> (format + lint)
|
|
78
|
+
name: <%= displayNames.fastapi %> (format + lint + typecheck + test + audit)
|
|
68
79
|
needs: changes
|
|
69
80
|
if: needs.changes.outputs.<%= paths.fastapi %> == 'true'
|
|
70
81
|
runs-on: ubuntu-latest
|
|
@@ -77,11 +88,14 @@ jobs:
|
|
|
77
88
|
- run: uv sync --group dev
|
|
78
89
|
- run: uv run ruff format --check src tests
|
|
79
90
|
- run: uv run ruff check src tests
|
|
91
|
+
- run: uv run mypy
|
|
92
|
+
- run: uv run pytest
|
|
93
|
+
- run: uv run pip-audit
|
|
80
94
|
<% } %>
|
|
81
95
|
<% if (components.includes('fastify')) { %>
|
|
82
96
|
|
|
83
97
|
<%= paths.fastify %>:
|
|
84
|
-
name: <%= displayNames.fastify %> (format + lint + typecheck)
|
|
98
|
+
name: <%= displayNames.fastify %> (format + lint + typecheck + audit)
|
|
85
99
|
needs: changes
|
|
86
100
|
if: needs.changes.outputs.<%= paths.fastify %> == 'true'
|
|
87
101
|
runs-on: ubuntu-latest
|
|
@@ -93,7 +107,7 @@ jobs:
|
|
|
93
107
|
<% if (pm === 'pnpm') { %>
|
|
94
108
|
- uses: pnpm/action-setup@v4
|
|
95
109
|
with:
|
|
96
|
-
version:
|
|
110
|
+
version: 10
|
|
97
111
|
<% } %>
|
|
98
112
|
<% if (pm === 'bun') { %>
|
|
99
113
|
- uses: oven-sh/setup-bun@v2
|
|
@@ -110,11 +124,12 @@ jobs:
|
|
|
110
124
|
- run: <%= pm.exec %> prettier --check .
|
|
111
125
|
- run: <%= pm.exec %> eslint .
|
|
112
126
|
- run: <%= pm.exec %> tsc --noEmit
|
|
127
|
+
- run: <%= pm.audit %>
|
|
113
128
|
<% } %>
|
|
114
129
|
<% if (components.includes('frontend')) { %>
|
|
115
130
|
|
|
116
131
|
<%= paths.frontend %>:
|
|
117
|
-
name: <%= displayNames.frontend %> (format + lint + typecheck)
|
|
132
|
+
name: <%= displayNames.frontend %> (format + lint + typecheck + audit)
|
|
118
133
|
needs: changes
|
|
119
134
|
if: needs.changes.outputs.<%= paths.frontend %> == 'true'
|
|
120
135
|
runs-on: ubuntu-latest
|
|
@@ -126,7 +141,7 @@ jobs:
|
|
|
126
141
|
<% if (pm === 'pnpm') { %>
|
|
127
142
|
- uses: pnpm/action-setup@v4
|
|
128
143
|
with:
|
|
129
|
-
version:
|
|
144
|
+
version: 10
|
|
130
145
|
<% } %>
|
|
131
146
|
<% if (pm === 'bun') { %>
|
|
132
147
|
- uses: oven-sh/setup-bun@v2
|
|
@@ -142,6 +157,7 @@ jobs:
|
|
|
142
157
|
- run: <%= pm.exec %> prettier --check .
|
|
143
158
|
- run: <%= pm.exec %> eslint 'src/**/*.{ts,tsx}'
|
|
144
159
|
- run: <%= pm.exec %> tsc --noEmit
|
|
160
|
+
- run: <%= pm.audit %>
|
|
145
161
|
<% } %>
|
|
146
162
|
<% if (components.includes('mobile')) { %>
|
|
147
163
|
|
|
@@ -166,7 +182,7 @@ jobs:
|
|
|
166
182
|
<% if (components.includes('e2e')) { %>
|
|
167
183
|
|
|
168
184
|
<%= paths.e2e %>:
|
|
169
|
-
name: <%= displayNames.e2e %> (format + lint + typecheck)
|
|
185
|
+
name: <%= displayNames.e2e %> (format + lint + typecheck + audit)
|
|
170
186
|
needs: changes
|
|
171
187
|
if: needs.changes.outputs.<%= paths.e2e %> == 'true'
|
|
172
188
|
runs-on: ubuntu-latest
|
|
@@ -178,7 +194,7 @@ jobs:
|
|
|
178
194
|
<% if (pm === 'pnpm') { %>
|
|
179
195
|
- uses: pnpm/action-setup@v4
|
|
180
196
|
with:
|
|
181
|
-
version:
|
|
197
|
+
version: 10
|
|
182
198
|
<% } %>
|
|
183
199
|
<% if (pm === 'bun') { %>
|
|
184
200
|
- uses: oven-sh/setup-bun@v2
|
|
@@ -194,6 +210,7 @@ jobs:
|
|
|
194
210
|
- run: <%= pm.exec %> prettier --check .
|
|
195
211
|
- run: <%= pm.exec %> eslint '**/*.ts'
|
|
196
212
|
- run: <%= pm.exec %> tsc --noEmit
|
|
213
|
+
- run: <%= pm.audit %>
|
|
197
214
|
<% } %>
|
|
198
215
|
<% if (components.includes('infra')) { %>
|
|
199
216
|
|
|
@@ -31,10 +31,11 @@ STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR)
|
|
|
31
31
|
|
|
32
32
|
<%= pathsUpper.fastapi %>_PY=$(echo "$STAGED_FILES" | grep '^<%= paths.fastapi %>/.*\.py$' || true)
|
|
33
33
|
if [ -n "$<%= pathsUpper.fastapi %>_PY" ]; then
|
|
34
|
-
echo "
|
|
34
|
+
echo "Running quality gates for <%= paths.fastapi %>..."
|
|
35
35
|
cd <%= paths.fastapi %>
|
|
36
36
|
echo "$<%= pathsUpper.fastapi %>_PY" | sed 's|^<%= paths.fastapi %>/||' | xargs uv run ruff format
|
|
37
37
|
echo "$<%= pathsUpper.fastapi %>_PY" | sed 's|^<%= paths.fastapi %>/||' | xargs uv run ruff check --fix
|
|
38
|
+
uv run mypy
|
|
38
39
|
cd ..
|
|
39
40
|
echo "$<%= pathsUpper.fastapi %>_PY" | xargs git add
|
|
40
41
|
fi
|