@nitra/cursor 1.27.9 → 1.28.1
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/CHANGELOG.md +25 -0
- package/package.json +1 -1
- package/rules/abie/js/applies.mjs +3 -2
- package/rules/abie/js/env_dns.mjs +4 -2
- package/rules/abie/js/firebase_hosting.mjs +3 -2
- package/rules/abie/js/hc_pairing.mjs +3 -2
- package/rules/abie/js/ua_http_route.mjs +4 -2
- package/rules/abie/js/ua_node_selector.mjs +4 -2
- package/rules/adr/js/hooks.mjs +36 -28
- package/rules/bun/js/layout.mjs +16 -11
- package/rules/capacitor/js/platforms.mjs +3 -2
- package/rules/changelog/js/consistency.mjs +85 -63
- package/rules/changelog/lib/package-manifest.mjs +5 -4
- package/rules/docker/js/lint.mjs +3 -2
- package/rules/ga/js/workflows.mjs +41 -32
- package/rules/graphql/js/tooling.mjs +15 -11
- package/rules/hasura/js/internal_urls.mjs +14 -10
- package/rules/image-avif/js/avif_generation.mjs +36 -23
- package/rules/image-compress/js/package_setup.mjs +18 -12
- package/rules/js-bun-db/js/safety.mjs +3 -2
- package/rules/js-lint/js/tooling.mjs +45 -32
- package/rules/js-run/js/runtime.mjs +21 -15
- package/rules/k8s/js/manifests.mjs +3 -2
- package/rules/nginx-default-tpl/js/template.mjs +7 -6
- package/rules/npm-module/js/package_structure.mjs +82 -57
- package/rules/rego/js/applies.mjs +4 -4
- package/rules/rust/js/applies.mjs +5 -3
- package/rules/security/js/sample_secret.mjs +2 -2
- package/rules/security/js/trufflehog.mjs +6 -4
- package/rules/style-lint/js/tooling.mjs +15 -8
- package/rules/test/coverage/coverage.mjs +1 -1
- package/rules/test/js/data/vitest_config/vitest.config.baseline.js +7 -0
- package/rules/test/js/location.mjs +3 -2
- package/rules/test/js/no-process-chdir.mjs +89 -0
- package/rules/test/js/no-relative-fs-path.mjs +259 -0
- package/rules/test/js/vitest-config-pool-forks.mjs +52 -0
- package/rules/test/test.mdc +21 -0
- package/rules/text/js/forbidden-prettier.mjs +4 -2
- package/rules/text/js/formatting.mjs +25 -16
- package/rules/vue/js/packages.mjs +33 -25
|
@@ -53,13 +53,14 @@ const REGISTRY_TIMEOUT_MS = 10_000
|
|
|
53
53
|
const LEADING_DOTSLASH_RE = /^\.\//
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
|
-
* Тихо запускає `git` і повертає stdout або `null` при будь-якій помилці.
|
|
56
|
+
* Тихо запускає `git` у заданому `cwd` і повертає stdout або `null` при будь-якій помилці.
|
|
57
57
|
* @param {string[]} args аргументи `git`
|
|
58
|
+
* @param {string} cwd робочий каталог процесу
|
|
58
59
|
* @returns {Promise<string | null>} результат
|
|
59
60
|
*/
|
|
60
|
-
async function gitOrNull(args) {
|
|
61
|
+
async function gitOrNull(args, cwd) {
|
|
61
62
|
try {
|
|
62
|
-
const { stdout } = await execFileAsync('git', args)
|
|
63
|
+
const { stdout } = await execFileAsync('git', args, { cwd })
|
|
63
64
|
return stdout
|
|
64
65
|
} catch {
|
|
65
66
|
return null
|
|
@@ -67,18 +68,20 @@ async function gitOrNull(args) {
|
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
/**
|
|
71
|
+
* @param {string} cwd робочий каталог
|
|
70
72
|
* @returns {Promise<boolean>} результат
|
|
71
73
|
*/
|
|
72
|
-
async function isInsideGitRepo() {
|
|
73
|
-
const out = await gitOrNull(['rev-parse', '--is-inside-work-tree'])
|
|
74
|
+
async function isInsideGitRepo(cwd) {
|
|
75
|
+
const out = await gitOrNull(['rev-parse', '--is-inside-work-tree'], cwd)
|
|
74
76
|
return typeof out === 'string' && out.trim() === 'true'
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
/**
|
|
80
|
+
* @param {string} cwd робочий каталог
|
|
78
81
|
* @returns {Promise<string | null>} результат
|
|
79
82
|
*/
|
|
80
|
-
async function currentBranchName() {
|
|
81
|
-
const out = await gitOrNull(['rev-parse', '--abbrev-ref', 'HEAD'])
|
|
83
|
+
async function currentBranchName(cwd) {
|
|
84
|
+
const out = await gitOrNull(['rev-parse', '--abbrev-ref', 'HEAD'], cwd)
|
|
82
85
|
return typeof out === 'string' ? out.trim() : null
|
|
83
86
|
}
|
|
84
87
|
|
|
@@ -93,20 +96,22 @@ function baseRefLabel(ref) {
|
|
|
93
96
|
/**
|
|
94
97
|
* @param {string} ancestor предок
|
|
95
98
|
* @param {string} descendant нащадок
|
|
99
|
+
* @param {string} cwd робочий каталог
|
|
96
100
|
* @returns {Promise<boolean>} результат
|
|
97
101
|
*/
|
|
98
|
-
async function isGitAncestor(ancestor, descendant) {
|
|
99
|
-
const out = await gitOrNull(['merge-base', '--is-ancestor', ancestor, descendant])
|
|
102
|
+
async function isGitAncestor(ancestor, descendant, cwd) {
|
|
103
|
+
const out = await gitOrNull(['merge-base', '--is-ancestor', ancestor, descendant], cwd)
|
|
100
104
|
return typeof out === 'string' && out.trim() === 'true'
|
|
101
105
|
}
|
|
102
106
|
|
|
103
107
|
/**
|
|
104
108
|
* @param {string} branchName локальна або remote-tracking гілка
|
|
109
|
+
* @param {string} cwd робочий каталог
|
|
105
110
|
* @returns {Promise<string | null>} ref для git або null
|
|
106
111
|
*/
|
|
107
|
-
async function resolveBranchRef(branchName) {
|
|
112
|
+
async function resolveBranchRef(branchName, cwd) {
|
|
108
113
|
for (const ref of [branchName, `origin/${branchName}`]) {
|
|
109
|
-
const out = await gitOrNull(['rev-parse', '--verify', '--quiet', ref])
|
|
114
|
+
const out = await gitOrNull(['rev-parse', '--verify', '--quiet', ref], cwd)
|
|
110
115
|
if (typeof out === 'string' && out.trim().length > 0) {
|
|
111
116
|
return ref
|
|
112
117
|
}
|
|
@@ -125,11 +130,12 @@ function isChangelogIgnoredPath(relPath) {
|
|
|
125
130
|
|
|
126
131
|
/**
|
|
127
132
|
* @param {string} relPath параметр
|
|
133
|
+
* @param {string} cwd робочий каталог
|
|
128
134
|
* @returns {Promise<boolean>} результат
|
|
129
135
|
*/
|
|
130
|
-
async function isPathGitIgnored(relPath) {
|
|
136
|
+
async function isPathGitIgnored(relPath, cwd) {
|
|
131
137
|
try {
|
|
132
|
-
await execFileAsync('git', ['check-ignore', '-q', '--', relPath])
|
|
138
|
+
await execFileAsync('git', ['check-ignore', '-q', '--', relPath], { cwd })
|
|
133
139
|
return true
|
|
134
140
|
} catch {
|
|
135
141
|
return false
|
|
@@ -138,10 +144,11 @@ async function isPathGitIgnored(relPath) {
|
|
|
138
144
|
|
|
139
145
|
/**
|
|
140
146
|
* @param {string} baseRef параметр
|
|
147
|
+
* @param {string} cwd робочий каталог
|
|
141
148
|
* @returns {Promise<string | null>} результат
|
|
142
149
|
*/
|
|
143
|
-
async function resolveMergeBase(baseRef) {
|
|
144
|
-
const out = await gitOrNull(['merge-base', baseRef, 'HEAD'])
|
|
150
|
+
async function resolveMergeBase(baseRef, cwd) {
|
|
151
|
+
const out = await gitOrNull(['merge-base', baseRef, 'HEAD'], cwd)
|
|
145
152
|
if (typeof out !== 'string') return null
|
|
146
153
|
const sha = out.trim()
|
|
147
154
|
return sha.length > 0 ? sha : null
|
|
@@ -150,22 +157,23 @@ async function resolveMergeBase(baseRef) {
|
|
|
150
157
|
/**
|
|
151
158
|
* Точка порівняння git для changelog (ref або SHA для `git diff` / `git show`).
|
|
152
159
|
* @param {string | null} branch поточна гілка
|
|
160
|
+
* @param {string} cwd робочий каталог
|
|
153
161
|
* @returns {Promise<{ ref: string, label: string } | null>} результат
|
|
154
162
|
*/
|
|
155
|
-
async function resolveChangelogComparisonPoint(branch) {
|
|
163
|
+
async function resolveChangelogComparisonPoint(branch, cwd) {
|
|
156
164
|
if (branch === LOCAL_ONLY_SKIP_BRANCH) {
|
|
157
165
|
return null
|
|
158
166
|
}
|
|
159
167
|
|
|
160
168
|
if (branch === 'main') {
|
|
161
|
-
const originMainRaw = await gitOrNull(['rev-parse', '--verify', '--quiet', 'origin/main'])
|
|
169
|
+
const originMainRaw = await gitOrNull(['rev-parse', '--verify', '--quiet', 'origin/main'], cwd)
|
|
162
170
|
const originMainSha = originMainRaw?.trim()
|
|
163
|
-
const headRaw = await gitOrNull(['rev-parse', 'HEAD'])
|
|
171
|
+
const headRaw = await gitOrNull(['rev-parse', 'HEAD'], cwd)
|
|
164
172
|
const headSha = headRaw?.trim()
|
|
165
|
-
if (originMainSha && headSha && (originMainSha === headSha || (await isGitAncestor('origin/main', 'HEAD')))) {
|
|
173
|
+
if (originMainSha && headSha && (originMainSha === headSha || (await isGitAncestor('origin/main', 'HEAD', cwd)))) {
|
|
166
174
|
return { ref: 'origin/main', label: 'main' }
|
|
167
175
|
}
|
|
168
|
-
const parent = await gitOrNull(['rev-parse', '--verify', '--quiet', 'HEAD~1'])
|
|
176
|
+
const parent = await gitOrNull(['rev-parse', '--verify', '--quiet', 'HEAD~1'], cwd)
|
|
169
177
|
if (typeof parent === 'string' && parent.trim().length > 0) {
|
|
170
178
|
return { ref: parent.trim(), label: 'main~1' }
|
|
171
179
|
}
|
|
@@ -173,11 +181,11 @@ async function resolveChangelogComparisonPoint(branch) {
|
|
|
173
181
|
}
|
|
174
182
|
|
|
175
183
|
for (const name of FEATURE_BASE_BRANCH_CANDIDATES) {
|
|
176
|
-
const baseRef = await resolveBranchRef(name)
|
|
184
|
+
const baseRef = await resolveBranchRef(name, cwd)
|
|
177
185
|
if (!baseRef) {
|
|
178
186
|
continue
|
|
179
187
|
}
|
|
180
|
-
const mergeBase = await resolveMergeBase(baseRef)
|
|
188
|
+
const mergeBase = await resolveMergeBase(baseRef, cwd)
|
|
181
189
|
if (!mergeBase) {
|
|
182
190
|
continue
|
|
183
191
|
}
|
|
@@ -215,11 +223,12 @@ function splitNulPaths(nulSeparated) {
|
|
|
215
223
|
/**
|
|
216
224
|
* @param {string} baseRef параметр
|
|
217
225
|
* @param {string[]} pathspec параметр
|
|
226
|
+
* @param {string} cwd робочий каталог
|
|
218
227
|
* @returns {Promise<string[]>} результат
|
|
219
228
|
*/
|
|
220
|
-
async function listChangedPathsAgainstBase(baseRef, pathspec) {
|
|
221
|
-
const diffOut = await gitOrNull(['diff', '--name-only', '-z', baseRef, '--', ...pathspec])
|
|
222
|
-
const untrackedOut = await gitOrNull(['ls-files', '--others', '--exclude-standard', '-z', '--', ...pathspec])
|
|
229
|
+
async function listChangedPathsAgainstBase(baseRef, pathspec, cwd) {
|
|
230
|
+
const diffOut = await gitOrNull(['diff', '--name-only', '-z', baseRef, '--', ...pathspec], cwd)
|
|
231
|
+
const untrackedOut = await gitOrNull(['ls-files', '--others', '--exclude-standard', '-z', '--', ...pathspec], cwd)
|
|
223
232
|
return [...new Set([...splitNulPaths(diffOut), ...splitNulPaths(untrackedOut)])]
|
|
224
233
|
}
|
|
225
234
|
|
|
@@ -227,16 +236,17 @@ async function listChangedPathsAgainstBase(baseRef, pathspec) {
|
|
|
227
236
|
* @param {string} baseRef параметр
|
|
228
237
|
* @param {string} ws параметр
|
|
229
238
|
* @param {string[]} subWorkspaces параметр
|
|
239
|
+
* @param {string} cwd робочий каталог
|
|
230
240
|
* @returns {Promise<boolean>} результат
|
|
231
241
|
*/
|
|
232
|
-
async function workspaceHasRelevantChangesAgainstBase(baseRef, ws, subWorkspaces) {
|
|
242
|
+
async function workspaceHasRelevantChangesAgainstBase(baseRef, ws, subWorkspaces, cwd) {
|
|
233
243
|
const pathspec = pathspecForWorkspace(ws, subWorkspaces)
|
|
234
|
-
const paths = await listChangedPathsAgainstBase(baseRef, pathspec)
|
|
244
|
+
const paths = await listChangedPathsAgainstBase(baseRef, pathspec, cwd)
|
|
235
245
|
for (const p of paths) {
|
|
236
246
|
if (isChangelogIgnoredPath(p)) {
|
|
237
247
|
continue
|
|
238
248
|
}
|
|
239
|
-
if (await isPathGitIgnored(p)) {
|
|
249
|
+
if (await isPathGitIgnored(p, cwd)) {
|
|
240
250
|
continue
|
|
241
251
|
}
|
|
242
252
|
return true
|
|
@@ -248,11 +258,12 @@ async function workspaceHasRelevantChangesAgainstBase(baseRef, ws, subWorkspaces
|
|
|
248
258
|
* Версія з маніфесту на `baseRef`.
|
|
249
259
|
* @param {string} baseRef параметр
|
|
250
260
|
* @param {import('../lib/package-manifest.mjs').PackageManifest} manifest параметр
|
|
261
|
+
* @param {string} cwd робочий каталог
|
|
251
262
|
* @returns {Promise<string | null>} результат
|
|
252
263
|
*/
|
|
253
|
-
async function readBaseVersion(baseRef, manifest) {
|
|
264
|
+
async function readBaseVersion(baseRef, manifest, cwd) {
|
|
254
265
|
const wsPath = manifest.ws === '.' ? manifest.manifestRel : `${manifest.ws}/${manifest.manifestRel}`
|
|
255
|
-
const out = await gitOrNull(['show', `${baseRef}:${wsPath}`])
|
|
266
|
+
const out = await gitOrNull(['show', `${baseRef}:${wsPath}`], cwd)
|
|
256
267
|
if (out === null) return null
|
|
257
268
|
if (manifest.kind === 'npm') {
|
|
258
269
|
try {
|
|
@@ -356,21 +367,23 @@ function checkNpmFilesArrayContainsChangelog(manifest, pass, fail) {
|
|
|
356
367
|
* @param {string} version параметр
|
|
357
368
|
* @param {(msg: string) => void} pass параметр
|
|
358
369
|
* @param {(msg: string) => void} fail параметр
|
|
370
|
+
* @param {string} cwd робочий каталог
|
|
359
371
|
* @returns {Promise<boolean>} результат
|
|
360
372
|
*/
|
|
361
|
-
async function verifyChangelogEntry(ws, version, pass, fail) {
|
|
373
|
+
async function verifyChangelogEntry(ws, version, pass, fail, cwd) {
|
|
362
374
|
const label = ws === '.' ? '<root>' : ws
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
375
|
+
const changelogRel = join(ws, 'CHANGELOG.md')
|
|
376
|
+
const changelogAbs = join(cwd, changelogRel)
|
|
377
|
+
if (!existsSync(changelogAbs)) {
|
|
378
|
+
fail(`${label}: відсутній ${changelogRel} (Keep a Changelog, див. n-changelog.mdc)`)
|
|
366
379
|
return false
|
|
367
380
|
}
|
|
368
|
-
const text = await readFile(
|
|
381
|
+
const text = await readFile(changelogAbs, 'utf8')
|
|
369
382
|
if (changelogHasVersionEntry(text, version)) {
|
|
370
|
-
pass(`${
|
|
383
|
+
pass(`${changelogRel}: знайдено запис для версії ${version}`)
|
|
371
384
|
return true
|
|
372
385
|
}
|
|
373
|
-
fail(`${
|
|
386
|
+
fail(`${changelogRel}: відсутній запис для ${version} (формат "## [${version}] - YYYY-MM-DD")`)
|
|
374
387
|
return false
|
|
375
388
|
}
|
|
376
389
|
|
|
@@ -388,19 +401,20 @@ function workspaceLabel(manifest) {
|
|
|
388
401
|
* @param {string[]} subWorkspaces параметр
|
|
389
402
|
* @param {(msg: string) => void} pass параметр
|
|
390
403
|
* @param {(msg: string) => void} fail параметр
|
|
404
|
+
* @param {string} cwd робочий каталог
|
|
391
405
|
* @returns {Promise<void>} результат
|
|
392
406
|
*/
|
|
393
|
-
async function checkPublishedWorkspacePendingGitChanges(manifest, Vcurrent, subWorkspaces, pass, fail) {
|
|
407
|
+
async function checkPublishedWorkspacePendingGitChanges(manifest, Vcurrent, subWorkspaces, pass, fail, cwd) {
|
|
394
408
|
const label = workspaceLabel(manifest)
|
|
395
409
|
const mf = manifestFilePath(manifest.ws, manifest)
|
|
396
|
-
if (!(await isInsideGitRepo())) {
|
|
410
|
+
if (!(await isInsideGitRepo(cwd))) {
|
|
397
411
|
return
|
|
398
412
|
}
|
|
399
413
|
|
|
400
|
-
const branch = await currentBranchName()
|
|
414
|
+
const branch = await currentBranchName(cwd)
|
|
401
415
|
|
|
402
416
|
if (branch === LOCAL_ONLY_SKIP_BRANCH) {
|
|
403
|
-
if (await workspaceHasRelevantChangesAgainstBase('HEAD', manifest.ws, subWorkspaces)) {
|
|
417
|
+
if (await workspaceHasRelevantChangesAgainstBase('HEAD', manifest.ws, subWorkspaces, cwd)) {
|
|
404
418
|
fail(
|
|
405
419
|
`${label}: у registry-published пакеті є незакомічені зміни при version ${Vcurrent}, що вже в реєстрі. ` +
|
|
406
420
|
`Підвищ version у ${mf} і додай запис у CHANGELOG.md (n-changelog.mdc)`
|
|
@@ -409,15 +423,18 @@ async function checkPublishedWorkspacePendingGitChanges(manifest, Vcurrent, subW
|
|
|
409
423
|
return
|
|
410
424
|
}
|
|
411
425
|
|
|
412
|
-
const comparison = await resolveChangelogComparisonPoint(branch)
|
|
413
|
-
if (
|
|
414
|
-
|
|
426
|
+
const comparison = await resolveChangelogComparisonPoint(branch, cwd)
|
|
427
|
+
if (
|
|
428
|
+
comparison &&
|
|
429
|
+
(await workspaceHasRelevantChangesAgainstBase(comparison.ref, manifest.ws, subWorkspaces, cwd))
|
|
430
|
+
) {
|
|
431
|
+
const Vbase = await readBaseVersion(comparison.ref, manifest, cwd)
|
|
415
432
|
const baseLabel = comparison.label
|
|
416
433
|
if (Vbase === null) {
|
|
417
434
|
pass(
|
|
418
435
|
`${label}: новий registry-published воркспейс (на ${baseLabel} відсутній ${mf}) — перевіряємо CHANGELOG для ${Vcurrent}`
|
|
419
436
|
)
|
|
420
|
-
await verifyChangelogEntry(manifest.ws, Vcurrent, pass, fail)
|
|
437
|
+
await verifyChangelogEntry(manifest.ws, Vcurrent, pass, fail, cwd)
|
|
421
438
|
checkNpmFilesArrayContainsChangelog(manifest, pass, fail)
|
|
422
439
|
} else if (Vbase === Vcurrent) {
|
|
423
440
|
fail(
|
|
@@ -429,7 +446,7 @@ async function checkPublishedWorkspacePendingGitChanges(manifest, Vcurrent, subW
|
|
|
429
446
|
}
|
|
430
447
|
}
|
|
431
448
|
|
|
432
|
-
if (branch === 'main' && (await workspaceHasRelevantChangesAgainstBase('HEAD', manifest.ws, subWorkspaces))) {
|
|
449
|
+
if (branch === 'main' && (await workspaceHasRelevantChangesAgainstBase('HEAD', manifest.ws, subWorkspaces, cwd))) {
|
|
433
450
|
fail(
|
|
434
451
|
`${label}: у registry-published пакеті є незакомічені зміни при version ${Vcurrent}, що вже в реєстрі. ` +
|
|
435
452
|
`Підвищ version у ${mf} і додай запис у CHANGELOG.md (n-changelog.mdc)`
|
|
@@ -443,9 +460,10 @@ async function checkPublishedWorkspacePendingGitChanges(manifest, Vcurrent, subW
|
|
|
443
460
|
* @param {(name: string, kind?: import('../lib/package-manifest.mjs').PackageKind) => Promise<string | null>} getPublishedVersion параметр
|
|
444
461
|
* @param {(msg: string) => void} pass параметр
|
|
445
462
|
* @param {(msg: string) => void} fail параметр
|
|
463
|
+
* @param {string} cwd робочий каталог
|
|
446
464
|
* @returns {Promise<void>} результат
|
|
447
465
|
*/
|
|
448
|
-
async function checkPublishedWorkspace(manifest, subWorkspaces, getPublishedVersion, pass, fail) {
|
|
466
|
+
async function checkPublishedWorkspace(manifest, subWorkspaces, getPublishedVersion, pass, fail, cwd) {
|
|
449
467
|
const label = workspaceLabel(manifest)
|
|
450
468
|
const mf = manifestFilePath(manifest.ws, manifest)
|
|
451
469
|
const Vcurrent = manifest.version
|
|
@@ -465,11 +483,11 @@ async function checkPublishedWorkspace(manifest, subWorkspaces, getPublishedVers
|
|
|
465
483
|
}
|
|
466
484
|
if (Vpublished === Vcurrent) {
|
|
467
485
|
pass(`${label}: ${name}@${Vcurrent} збігається з реєстром — перевіряємо git на незрелізні зміни`)
|
|
468
|
-
await checkPublishedWorkspacePendingGitChanges(manifest, Vcurrent, subWorkspaces, pass, fail)
|
|
486
|
+
await checkPublishedWorkspacePendingGitChanges(manifest, Vcurrent, subWorkspaces, pass, fail, cwd)
|
|
469
487
|
return
|
|
470
488
|
}
|
|
471
489
|
pass(`${label}: ${name} — нова локальна версія (${Vpublished} → ${Vcurrent})`)
|
|
472
|
-
await verifyChangelogEntry(manifest.ws, Vcurrent, pass, fail)
|
|
490
|
+
await verifyChangelogEntry(manifest.ws, Vcurrent, pass, fail, cwd)
|
|
473
491
|
checkNpmFilesArrayContainsChangelog(manifest, pass, fail)
|
|
474
492
|
}
|
|
475
493
|
|
|
@@ -479,8 +497,9 @@ async function checkPublishedWorkspace(manifest, subWorkspaces, getPublishedVers
|
|
|
479
497
|
* @param {string} baseLabel параметр
|
|
480
498
|
* @param {(msg: string) => void} pass параметр
|
|
481
499
|
* @param {(msg: string) => void} fail параметр
|
|
500
|
+
* @param {string} cwd робочий каталог
|
|
482
501
|
*/
|
|
483
|
-
async function checkLocalOnlyChangedWorkspace(comparisonRef, manifest, baseLabel, pass, fail) {
|
|
502
|
+
async function checkLocalOnlyChangedWorkspace(comparisonRef, manifest, baseLabel, pass, fail, cwd) {
|
|
484
503
|
const label = workspaceLabel(manifest)
|
|
485
504
|
const mf = manifestFilePath(manifest.ws, manifest)
|
|
486
505
|
const Vcurrent = manifest.version
|
|
@@ -488,10 +507,10 @@ async function checkLocalOnlyChangedWorkspace(comparisonRef, manifest, baseLabel
|
|
|
488
507
|
fail(`${label}: у ${mf} відсутнє поле version (потрібне для запису в CHANGELOG)`)
|
|
489
508
|
return
|
|
490
509
|
}
|
|
491
|
-
const Vbase = await readBaseVersion(comparisonRef, manifest)
|
|
510
|
+
const Vbase = await readBaseVersion(comparisonRef, manifest, cwd)
|
|
492
511
|
if (Vbase === null) {
|
|
493
512
|
pass(`${label}: новий воркспейс (на ${baseLabel} відсутній ${mf}) — перевіряємо CHANGELOG для ${Vcurrent}`)
|
|
494
|
-
if (!(await verifyChangelogEntry(manifest.ws, Vcurrent, pass, fail))) return
|
|
513
|
+
if (!(await verifyChangelogEntry(manifest.ws, Vcurrent, pass, fail, cwd))) return
|
|
495
514
|
checkNpmFilesArrayContainsChangelog(manifest, pass, fail)
|
|
496
515
|
return
|
|
497
516
|
}
|
|
@@ -502,7 +521,7 @@ async function checkLocalOnlyChangedWorkspace(comparisonRef, manifest, baseLabel
|
|
|
502
521
|
return
|
|
503
522
|
}
|
|
504
523
|
pass(`${label}: version підвищено (${Vbase} → ${Vcurrent})`)
|
|
505
|
-
if (!(await verifyChangelogEntry(manifest.ws, Vcurrent, pass, fail))) return
|
|
524
|
+
if (!(await verifyChangelogEntry(manifest.ws, Vcurrent, pass, fail, cwd))) return
|
|
506
525
|
checkNpmFilesArrayContainsChangelog(manifest, pass, fail)
|
|
507
526
|
}
|
|
508
527
|
|
|
@@ -511,20 +530,21 @@ async function checkLocalOnlyChangedWorkspace(comparisonRef, manifest, baseLabel
|
|
|
511
530
|
* @param {string[]} subWorkspaces параметр
|
|
512
531
|
* @param {(msg: string) => void} pass параметр
|
|
513
532
|
* @param {(msg: string) => void} fail параметр
|
|
533
|
+
* @param {string} cwd робочий каталог
|
|
514
534
|
*/
|
|
515
|
-
async function runLocalOnlyChecks(localOnly, subWorkspaces, pass, fail) {
|
|
535
|
+
async function runLocalOnlyChecks(localOnly, subWorkspaces, pass, fail, cwd) {
|
|
516
536
|
if (localOnly.length === 0) return
|
|
517
537
|
|
|
518
|
-
if (!(await isInsideGitRepo())) {
|
|
538
|
+
if (!(await isInsideGitRepo(cwd))) {
|
|
519
539
|
pass('changelog: не git-репозиторій — local-only перевірку пропущено')
|
|
520
540
|
return
|
|
521
541
|
}
|
|
522
|
-
const branch = await currentBranchName()
|
|
542
|
+
const branch = await currentBranchName(cwd)
|
|
523
543
|
if (branch === LOCAL_ONLY_SKIP_BRANCH) {
|
|
524
544
|
pass('changelog: поточна гілка = dev — local-only перевірку пропущено')
|
|
525
545
|
return
|
|
526
546
|
}
|
|
527
|
-
const comparison = await resolveChangelogComparisonPoint(branch)
|
|
547
|
+
const comparison = await resolveChangelogComparisonPoint(branch, cwd)
|
|
528
548
|
if (!comparison) {
|
|
529
549
|
pass('changelog: ref dev/main (та origin/*) не знайдено — local-only перевірку пропущено')
|
|
530
550
|
return
|
|
@@ -532,9 +552,9 @@ async function runLocalOnlyChecks(localOnly, subWorkspaces, pass, fail) {
|
|
|
532
552
|
|
|
533
553
|
let checkedAny = false
|
|
534
554
|
for (const manifest of localOnly) {
|
|
535
|
-
if (!(await workspaceHasRelevantChangesAgainstBase(comparison.ref, manifest.ws, subWorkspaces))) continue
|
|
555
|
+
if (!(await workspaceHasRelevantChangesAgainstBase(comparison.ref, manifest.ws, subWorkspaces, cwd))) continue
|
|
536
556
|
checkedAny = true
|
|
537
|
-
await checkLocalOnlyChangedWorkspace(comparison.ref, manifest, comparison.label, pass, fail)
|
|
557
|
+
await checkLocalOnlyChangedWorkspace(comparison.ref, manifest, comparison.label, pass, fail, cwd)
|
|
538
558
|
}
|
|
539
559
|
if (!checkedAny) {
|
|
540
560
|
pass(`changelog: local-only воркспейси без змін відносно ${comparison.label}`)
|
|
@@ -544,14 +564,16 @@ async function runLocalOnlyChecks(localOnly, subWorkspaces, pass, fail) {
|
|
|
544
564
|
/**
|
|
545
565
|
* @param {object} [opts] опції перевірки
|
|
546
566
|
* @param {(name: string, kind?: import('../lib/package-manifest.mjs').PackageKind) => Promise<string | null>} [opts.getPublishedVersion] перевизначення npm/PyPI у тестах
|
|
567
|
+
* @param {string} [opts.cwd] корінь репозиторію (за замовчуванням `process.cwd()`)
|
|
547
568
|
* @returns {Promise<number>} exit-код перевірки
|
|
548
569
|
*/
|
|
549
570
|
export async function check(opts = {}) {
|
|
550
571
|
const reporter = createCheckReporter()
|
|
551
572
|
const { pass, fail } = reporter
|
|
552
573
|
const getPublishedVersion = opts.getPublishedVersion ?? createDefaultGetPublishedVersion()
|
|
574
|
+
const cwd = opts.cwd ?? process.cwd()
|
|
553
575
|
|
|
554
|
-
const workspaces = await getMonorepoProjectRootDirs(
|
|
576
|
+
const workspaces = await getMonorepoProjectRootDirs(cwd)
|
|
555
577
|
const subWorkspaces = workspaces.filter(w => w !== '.')
|
|
556
578
|
// Корінь монорепо (`.` за наявності підпакетів) — це glue/конфіг/tooling, а не логіка
|
|
557
579
|
// продукту: власного CHANGELOG він не веде, помітні зміни документують підпакети.
|
|
@@ -573,7 +595,7 @@ export async function check(opts = {}) {
|
|
|
573
595
|
)
|
|
574
596
|
continue
|
|
575
597
|
}
|
|
576
|
-
const manifest = await readPackageManifest(ws)
|
|
598
|
+
const manifest = await readPackageManifest(ws, cwd)
|
|
577
599
|
if (!manifest) {
|
|
578
600
|
continue
|
|
579
601
|
}
|
|
@@ -585,10 +607,10 @@ export async function check(opts = {}) {
|
|
|
585
607
|
}
|
|
586
608
|
|
|
587
609
|
for (const manifest of published) {
|
|
588
|
-
await checkPublishedWorkspace(manifest, subWorkspaces, getPublishedVersion, pass, fail)
|
|
610
|
+
await checkPublishedWorkspace(manifest, subWorkspaces, getPublishedVersion, pass, fail, cwd)
|
|
589
611
|
}
|
|
590
612
|
|
|
591
|
-
await runLocalOnlyChecks(localOnly, subWorkspaces, pass, fail)
|
|
613
|
+
await runLocalOnlyChecks(localOnly, subWorkspaces, pass, fail, cwd)
|
|
592
614
|
|
|
593
615
|
return reporter.getExitCode()
|
|
594
616
|
}
|
|
@@ -71,11 +71,12 @@ export function parsePyprojectFields(text) {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
|
-
* @param {string} ws шлях воркспейсу
|
|
74
|
+
* @param {string} ws шлях воркспейсу (відносно `cwd`)
|
|
75
|
+
* @param {string} [cwd] корінь репозиторію (за замовчуванням `process.cwd()`)
|
|
75
76
|
* @returns {Promise<PackageManifest | null>} маніфест пакета або null
|
|
76
77
|
*/
|
|
77
|
-
export async function readPackageManifest(ws) {
|
|
78
|
-
const pkgPath = join(ws, 'package.json')
|
|
78
|
+
export async function readPackageManifest(ws, cwd = process.cwd()) {
|
|
79
|
+
const pkgPath = join(cwd, ws, 'package.json')
|
|
79
80
|
if (existsSync(pkgPath)) {
|
|
80
81
|
try {
|
|
81
82
|
const parsed = JSON.parse(await readFile(pkgPath, 'utf8'))
|
|
@@ -99,7 +100,7 @@ export async function readPackageManifest(ws) {
|
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
const pyPath = join(ws, 'pyproject.toml')
|
|
103
|
+
const pyPath = join(cwd, ws, 'pyproject.toml')
|
|
103
104
|
if (!existsSync(pyPath)) {
|
|
104
105
|
return null
|
|
105
106
|
}
|
package/rules/docker/js/lint.mjs
CHANGED
|
@@ -284,13 +284,14 @@ export function getNonRootRuntimeHint(fileContent) {
|
|
|
284
284
|
|
|
285
285
|
/**
|
|
286
286
|
* Перевіряє Dockerfile / Containerfile через hadolint (docker.mdc).
|
|
287
|
+
* @param {string} [cwd] корінь репозиторію
|
|
287
288
|
* @returns {Promise<number>} 0 — все OK, 1 — є зауваження або помилка запуску
|
|
288
289
|
*/
|
|
289
|
-
export async function check() {
|
|
290
|
+
export async function check(cwd = process.cwd()) {
|
|
290
291
|
const reporter = createCheckReporter()
|
|
291
292
|
const { pass } = reporter
|
|
292
293
|
|
|
293
|
-
const root =
|
|
294
|
+
const root = cwd
|
|
294
295
|
const ignorePaths = await loadCursorIgnorePaths(root)
|
|
295
296
|
const files = await findDockerfilePaths(root, ignorePaths)
|
|
296
297
|
|