@nitra/cursor 1.9.18 → 1.9.20
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 +50 -0
- package/bin/auto-skills.md +2 -0
- package/mdc/abie.mdc +21 -249
- package/mdc/hasura.mdc +1 -1
- package/mdc/k8s.mdc +2 -2
- package/package.json +1 -1
- package/policy/abie/base_deployment_preem/base_deployment_preem.rego +2 -2
- package/policy/abie/clean_merged_ignore_branches/clean_merged_ignore_branches.rego +2 -2
- package/policy/abie/clean_merged_ignore_branches/clean_merged_ignore_branches_test.rego +5 -5
- package/policy/rego/package_json/package_json.rego +35 -0
- package/policy/rego/package_json/package_json_test.rego +42 -0
- package/policy/rego/vscode_extensions/vscode_extensions.rego +19 -0
- package/policy/rego/vscode_extensions/vscode_extensions_test.rego +34 -0
- package/policy/rego/vscode_settings/vscode_settings.rego +38 -0
- package/policy/rego/vscode_settings/vscode_settings_test.rego +55 -0
- package/policy/tauri/vscode_extensions/vscode_extensions.rego +28 -0
- package/policy/tauri/vscode_extensions/vscode_extensions_test.rego +44 -0
- package/scripts/check-abie.mjs +73 -934
- package/scripts/check-hasura.mjs +8 -14
- package/scripts/check-k8s.mjs +1 -18
- package/scripts/check-rego.mjs +106 -0
- package/scripts/check-tauri.mjs +88 -0
- package/scripts/lint-conftest.mjs +1 -1
- package/skills/abie-clean/SKILL.md +138 -0
- package/skills/abie-kustomize/SKILL.md +1 -1
package/scripts/check-hasura.mjs
CHANGED
|
@@ -7,11 +7,9 @@
|
|
|
7
7
|
* вказує на `https://github.com/nitra/...` або `https://github.com/abinbevefes/...`
|
|
8
8
|
* (інші репозиторії пропускаються без помилок — як у check-abie).
|
|
9
9
|
*
|
|
10
|
-
* Очікуваний формат URL —
|
|
10
|
+
* Очікуваний формат URL — кластерний DNS-суфікс `<cluster>.internal`:
|
|
11
11
|
* - GKE / GCP: `http://<service>.<namespace>.svc.<cluster>.internal:<port>`
|
|
12
12
|
* приклад: `http://contract-h.ua-contract.svc.abie-ua.internal:8080`
|
|
13
|
-
* - стандартний k8s / Yandex Cloud: `http://<service>.<namespace>.svc.cluster.local:<port>`
|
|
14
|
-
* приклад: `http://apruv-h-hl.ru-apruv.svc.cluster.local:8080`
|
|
15
13
|
*
|
|
16
14
|
* Сегменти беруться з `hasura/k8s/base/svc-hl.yaml` (`metadata.name` —
|
|
17
15
|
* має закінчуватись на `-h`, headless-сервіс) і `hasura/k8s/base/namespace.yaml`
|
|
@@ -43,18 +41,15 @@ const HASURA_NAMESPACE_FILE = `${HASURA_BASE_DIR}/namespace.yaml`
|
|
|
43
41
|
|
|
44
42
|
const ENV_FILE_RE = /\.env$/u
|
|
45
43
|
const HASURA_ENDPOINT_LINE_RE = /^[ \t]*(?:export[ \t]+)?HASURA_GRAPHQL_ENDPOINT[ \t]*=[ \t]*['"]?([^'"\r\n#]+)/mu
|
|
46
|
-
// Дозволяємо
|
|
47
|
-
|
|
48
|
-
const INTERNAL_HASURA_URL_RE = /^http:\/\/([^./]+)\.([^./]+)\.svc\.((?:[^./:]+\.internal)|cluster\.local):(\d+)\/?$/u
|
|
44
|
+
// Дозволяємо лише DNS-суфікс кластера `<name>.internal` (GKE/GCP).
|
|
45
|
+
const INTERNAL_HASURA_URL_RE = /^http:\/\/([^./]+)\.([^./]+)\.svc\.([^./:]+\.internal):(\d+)\/?$/u
|
|
49
46
|
const INTERNAL_DNS_SUFFIX = '.internal'
|
|
50
47
|
|
|
51
48
|
/**
|
|
52
49
|
* Розбір значення `HASURA_GRAPHQL_ENDPOINT` як внутрішнього кластерного URL.
|
|
53
|
-
* Дозволяє лише `http://` (TLS усередині кластера зайвий) та
|
|
54
|
-
*
|
|
55
|
-
* (
|
|
56
|
-
* кластера без `.internal` (наприклад `abie-ua`); для YC — повний суфікс
|
|
57
|
-
* `cluster.local` (бо своєї «назви кластера» в DNS немає).
|
|
50
|
+
* Дозволяє лише `http://` (TLS усередині кластера зайвий) та DNS-суфікс
|
|
51
|
+
* `<cluster>.internal` (GKE/GCP). Поле `cluster` містить ім'я кластера без
|
|
52
|
+
* `.internal` (наприклад `abie-ua`).
|
|
58
53
|
* @param {string} url значення з `.env` (без огорнутих лапок)
|
|
59
54
|
* @returns {{ ok: true, service: string, namespace: string, cluster: string, port: string } | { ok: false }}
|
|
60
55
|
* розібрані сегменти або `{ ok: false }`, якщо формат не відповідає внутрішньому кластерному URL
|
|
@@ -65,7 +60,7 @@ export function parseInternalHasuraEndpoint(url) {
|
|
|
65
60
|
return { ok: false }
|
|
66
61
|
}
|
|
67
62
|
const suffix = m[3]
|
|
68
|
-
const cluster = suffix.
|
|
63
|
+
const cluster = suffix.slice(0, -INTERNAL_DNS_SUFFIX.length)
|
|
69
64
|
return { ok: true, service: m[1], namespace: m[2], cluster, port: m[4] }
|
|
70
65
|
}
|
|
71
66
|
|
|
@@ -148,8 +143,7 @@ async function checkEnvFile(relPath, expected, reporter) {
|
|
|
148
143
|
const value = m[1].trim()
|
|
149
144
|
const parsed = parseInternalHasuraEndpoint(value)
|
|
150
145
|
if (!parsed.ok) {
|
|
151
|
-
const example =
|
|
152
|
-
'https://<service>.<namespace>.svc.<cluster>.internal:<port> або http://<service>.<namespace>.svc.cluster.local:<port>'
|
|
146
|
+
const example = "https://<service>.<namespace>.svc.<cluster>.internal:<port>"
|
|
153
147
|
fail(
|
|
154
148
|
`${relPath}: HASURA_GRAPHQL_ENDPOINT="${value}" — потрібен внутрішній кластерний URL виду ${example} (hasura.mdc)`
|
|
155
149
|
)
|
package/scripts/check-k8s.mjs
CHANGED
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
* `hpa.yaml` і `pdb.yaml` (як єдині або принаймні обов'язкові), `hpa.yaml` (валідний `autoscaling/v2`
|
|
98
98
|
* HorizontalPodAutoscaler з `scaleTargetRef.name` = ім'я Deployment, dev-like `min=max=1`), `pdb.yaml` (валідний
|
|
99
99
|
* `policy/v1` PodDisruptionBudget з `selector.matchLabels.app` = мітка `app` Deployment, dev-like `minAvailable=0`).
|
|
100
|
-
* Overlays (`ua/`,
|
|
100
|
+
* Overlays (`ua/`, прод-overlays) підключають `components: [- ../components]` і додають JSON6902-патчі для
|
|
101
101
|
* прод-значень: `/spec/minReplicas`, `/spec/maxReplicas` (HPA), `/spec/minAvailable` (PDB). HPA поруч із Deployment
|
|
102
102
|
* у не-base оверлеях — як раніше (див. k8s.mdc).
|
|
103
103
|
* Env-залежні межі за сегментом після `/k8s/`: **dev-like** (`base`, `dev`, `*-qa`) — для HPA, що лишився після
|
|
@@ -324,10 +324,6 @@ const API_VERSION_FIELD_RE = /^\s*apiVersion:\s*(\S+)\s*$/
|
|
|
324
324
|
const KIND_FIELD_RE = /^\s*kind:\s*(\S+)\s*$/
|
|
325
325
|
const TYPE_FIELD_RE = /^\s*type:\s*(\S+)\s*$/
|
|
326
326
|
const YAML_DOC_SEPARATOR_LINE_RE = /^---\s*$/
|
|
327
|
-
const HEALTHCHECK_DELETE_RE = /\$patch:\s*delete/u
|
|
328
|
-
const HEALTHCHECK_KIND_RE = /kind:\s*HealthCheckPolicy/u
|
|
329
|
-
const METADATA_LINE_RE = /metadata:/u
|
|
330
|
-
const NAME_NON_EMPTY_RE = /name:\s*\S+/u
|
|
331
327
|
const K8S_BASE_KUSTOMIZATION_PATH_RE = /(^|\/)k8s\/base\/kustomization\.yaml$/u
|
|
332
328
|
const K8S_BASE_SEGMENT_RE = /(^|\/)k8s\/base\//u
|
|
333
329
|
const OXLINT_SCHEMA_MODELINE_RE = /^\s*#\s*yaml-language-server:\s*\$schema=\S+/u
|
|
@@ -2025,19 +2021,6 @@ export function k8sYamlFirstDocIsAlbYcHttpBackendGroup(yamlBody) {
|
|
|
2025
2021
|
return apiVersion === 'alb.yc.io/v1alpha1' && kind === 'HttpBackendGroup'
|
|
2026
2022
|
}
|
|
2027
2023
|
|
|
2028
|
-
/**
|
|
2029
|
-
* Чи вміст overlay **`ru/kustomization.yaml`** містить Kustomize patch видалення **HealthCheckPolicy**.
|
|
2030
|
-
* @param {string} raw повний текст файлу
|
|
2031
|
-
* @returns {boolean} true, якщо є `$patch: delete` і блоки kind/metadata для HealthCheckPolicy
|
|
2032
|
-
*/
|
|
2033
|
-
export function ruKustomizationHasHealthCheckDeletePatch(raw) {
|
|
2034
|
-
if (!HEALTHCHECK_DELETE_RE.test(raw)) return false
|
|
2035
|
-
if (!HEALTHCHECK_KIND_RE.test(raw)) return false
|
|
2036
|
-
if (!METADATA_LINE_RE.test(raw)) return false
|
|
2037
|
-
if (!NAME_NON_EMPTY_RE.test(raw)) return false
|
|
2038
|
-
return true
|
|
2039
|
-
}
|
|
2040
|
-
|
|
2041
2024
|
/**
|
|
2042
2025
|
* Чи абсолютний шлях лежить усередині кореня репозиторію (без виходу через `..`).
|
|
2043
2026
|
* @param {string} rootAbs абсолютний корінь
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Перевіряє інструментарій rego (rego.mdc): VSCode та `package.json` для проєктів,
|
|
3
|
+
* які мають хоча б один `.rego` файл у дереві.
|
|
4
|
+
*
|
|
5
|
+
* Cross-file gating (JS):
|
|
6
|
+
* 1. Walk дерева від `cwd` (з типовими skip-ами і `.n-cursor.json:ignore`).
|
|
7
|
+
* 2. Якщо немає жодного `.rego` — пропустити перевірку (rego-tooling не вимагається).
|
|
8
|
+
* 3. Інакше — для кожного канонічного файла:
|
|
9
|
+
* - FS-existence (з повідомленням, якщо відсутній);
|
|
10
|
+
* - делегувати content-валідацію rego-пакетам через `runConftestBatch`:
|
|
11
|
+
* `rego.vscode_extensions` — `.vscode/extensions.json`: `tsandall.opa`
|
|
12
|
+
* у `recommendations`;
|
|
13
|
+
* `rego.vscode_settings` — `.vscode/settings.json`: `[rego]` з
|
|
14
|
+
* `editor.defaultFormatter: "tsandall.opa"` і `editor.formatOnSave: true`;
|
|
15
|
+
* `rego.package_json` — `package.json#scripts.lint-rego` має бути
|
|
16
|
+
* канонічним `"bun ./npm/scripts/lint-rego.mjs"`.
|
|
17
|
+
*
|
|
18
|
+
* Rego-полісі глобально у `lint-conftest` НЕ реєструються — це conditional
|
|
19
|
+
* правило (без `.rego` файлів вимоги не діють). Plan B: Rego-authoritative +
|
|
20
|
+
* JS-orchestrator з `runConftestBatch`.
|
|
21
|
+
*
|
|
22
|
+
* `bun run lint-rego` (`npm/scripts/lint-rego.mjs`) — окрема перевірка САМИХ
|
|
23
|
+
* rego-полісі (opa check / regal lint / conftest verify), не плутати з цим
|
|
24
|
+
* скриптом, який перевіряє ПРОЄКТНЕ оточення для роботи з rego.
|
|
25
|
+
*/
|
|
26
|
+
import { existsSync } from 'node:fs'
|
|
27
|
+
|
|
28
|
+
import { createCheckReporter } from './utils/check-reporter.mjs'
|
|
29
|
+
import { loadCursorIgnorePaths } from './utils/load-cursor-config.mjs'
|
|
30
|
+
import { runConftestBatch } from './utils/run-conftest-batch.mjs'
|
|
31
|
+
import { walkDir } from './utils/walkDir.mjs'
|
|
32
|
+
|
|
33
|
+
/** Список (path, namespace, policyDirRel) для трьох канонічних конфігів rego.mdc. */
|
|
34
|
+
const REGO_TARGETS = [
|
|
35
|
+
['.vscode/extensions.json', 'rego.vscode_extensions', 'rego/vscode_extensions'],
|
|
36
|
+
['.vscode/settings.json', 'rego.vscode_settings', 'rego/vscode_settings'],
|
|
37
|
+
['package.json', 'rego.package_json', 'rego/package_json']
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Чи є хоча б один `.rego` файл у дереві від `cwd`.
|
|
42
|
+
* @param {string} root абсолютний шлях кореня
|
|
43
|
+
* @param {string[]} ignorePaths шляхи каталогів, повністю виключених з обходу
|
|
44
|
+
* @returns {Promise<boolean>} `true`, якщо знайдено хоча б один `.rego`
|
|
45
|
+
*/
|
|
46
|
+
async function projectHasRegoFiles(root, ignorePaths) {
|
|
47
|
+
let found = false
|
|
48
|
+
await walkDir(
|
|
49
|
+
root,
|
|
50
|
+
p => {
|
|
51
|
+
if (p.endsWith('.rego')) {
|
|
52
|
+
found = true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
ignorePaths
|
|
56
|
+
)
|
|
57
|
+
return found
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Делегує content-валідацію одного канонічного конфіга rego-пакету через
|
|
62
|
+
* `runConftestBatch`. FS-існування — попередньо перевірено.
|
|
63
|
+
* @param {string} path відносний шлях до файлу
|
|
64
|
+
* @param {string} namespace rego-пакет (наприклад `rego.vscode_extensions`)
|
|
65
|
+
* @param {string} policyDirRel піддиректорія у `npm/policy/`
|
|
66
|
+
* @param {(msg: string) => void} pass success-репортер
|
|
67
|
+
* @param {(msg: string) => void} fail fail-репортер
|
|
68
|
+
* @returns {void}
|
|
69
|
+
*/
|
|
70
|
+
function runRegoPolicyOnPath(path, namespace, policyDirRel, pass, fail) {
|
|
71
|
+
const violations = runConftestBatch({ policyDirRel, namespace, files: [path] })
|
|
72
|
+
if (violations.length === 0) {
|
|
73
|
+
pass(`${path} відповідає ${namespace} (rego)`)
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
for (const v of violations) fail(v.message)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Перевіряє відповідність проєкту правилам rego.mdc.
|
|
81
|
+
* @returns {Promise<number>} 0 — все OK, 1 — є проблеми
|
|
82
|
+
*/
|
|
83
|
+
export async function check() {
|
|
84
|
+
const reporter = createCheckReporter()
|
|
85
|
+
const { pass, fail } = reporter
|
|
86
|
+
|
|
87
|
+
const root = process.cwd()
|
|
88
|
+
const ignorePaths = await loadCursorIgnorePaths(root)
|
|
89
|
+
const hasRego = await projectHasRegoFiles(root, ignorePaths)
|
|
90
|
+
if (!hasRego) {
|
|
91
|
+
pass('Немає *.rego у дереві — rego-tooling не вимагається (rego.mdc)')
|
|
92
|
+
return reporter.getExitCode()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
pass('Знайдено *.rego у дереві — перевіряємо канонічні конфіги rego.mdc')
|
|
96
|
+
|
|
97
|
+
for (const [path, namespace, policyDirRel] of REGO_TARGETS) {
|
|
98
|
+
if (!existsSync(path)) {
|
|
99
|
+
fail(`${path} не існує — створи згідно rego.mdc (${namespace})`)
|
|
100
|
+
continue
|
|
101
|
+
}
|
|
102
|
+
runRegoPolicyOnPath(path, namespace, policyDirRel, pass, fail)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return reporter.getExitCode()
|
|
106
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Перевіряє інструментарій Tauri (tauri.mdc): VSCode `extensions.json` для
|
|
3
|
+
* проєктів, у яких є маркер Tauri.
|
|
4
|
+
*
|
|
5
|
+
* Cross-file gating (JS):
|
|
6
|
+
* 1. Tauri-маркер визначаємо за **будь-яким** з:
|
|
7
|
+
* - існує каталог `src-tauri/` у `cwd`;
|
|
8
|
+
* - існує файл `tauri.conf.json` у `cwd` або в workspace-пакетах;
|
|
9
|
+
* - кореневий `package.json#devDependencies` або `dependencies` містить
|
|
10
|
+
* ключ з префіксом `@tauri-apps/`.
|
|
11
|
+
* 2. Якщо маркера немає — пропустити перевірку (tauri-tooling не вимагається).
|
|
12
|
+
* 3. Інакше — для `.vscode/extensions.json` зробити FS-existence + делегувати
|
|
13
|
+
* content `rego.tauri.vscode_extensions` через `runConftestBatch`.
|
|
14
|
+
*
|
|
15
|
+
* Rego-полісі глобально у `lint-conftest` НЕ реєструється — це conditional
|
|
16
|
+
* правило. Plan B: Rego-authoritative + JS-orchestrator з `runConftestBatch`.
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, statSync } from 'node:fs'
|
|
19
|
+
import { readFile } from 'node:fs/promises'
|
|
20
|
+
|
|
21
|
+
import { createCheckReporter } from './utils/check-reporter.mjs'
|
|
22
|
+
import { runConftestBatch } from './utils/run-conftest-batch.mjs'
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Чи є префікс `@tauri-apps/` у ключах `dependencies` або `devDependencies`.
|
|
26
|
+
* @param {Record<string, unknown> | null | undefined} pkg розпарсений `package.json`
|
|
27
|
+
* @returns {boolean} true, якщо знайдено хоча б один `@tauri-apps/*`
|
|
28
|
+
*/
|
|
29
|
+
function packageHasTauriDep(pkg) {
|
|
30
|
+
if (!pkg || typeof pkg !== 'object') return false
|
|
31
|
+
for (const field of ['dependencies', 'devDependencies']) {
|
|
32
|
+
const deps = /** @type {Record<string, unknown> | undefined} */ (pkg[field])
|
|
33
|
+
if (!deps || typeof deps !== 'object') continue
|
|
34
|
+
for (const name of Object.keys(deps)) {
|
|
35
|
+
if (name.startsWith('@tauri-apps/')) return true
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Чи є у проєкті маркер Tauri: `src-tauri/`, `tauri.conf.json` (root або
|
|
43
|
+
* workspace), або `@tauri-apps/*` у залежностях кореневого `package.json`.
|
|
44
|
+
* @returns {Promise<boolean>} true, якщо проєкт використовує Tauri
|
|
45
|
+
*/
|
|
46
|
+
async function projectHasTauriMarker() {
|
|
47
|
+
if (existsSync('src-tauri') && statSync('src-tauri').isDirectory()) return true
|
|
48
|
+
if (existsSync('tauri.conf.json')) return true
|
|
49
|
+
if (!existsSync('package.json')) return false
|
|
50
|
+
const pkg = JSON.parse(await readFile('package.json', 'utf8'))
|
|
51
|
+
if (packageHasTauriDep(pkg)) return true
|
|
52
|
+
return false
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Перевіряє відповідність проєкту правилам tauri.mdc.
|
|
57
|
+
* @returns {Promise<number>} 0 — все OK, 1 — є проблеми
|
|
58
|
+
*/
|
|
59
|
+
export async function check() {
|
|
60
|
+
const reporter = createCheckReporter()
|
|
61
|
+
const { pass, fail } = reporter
|
|
62
|
+
|
|
63
|
+
const hasTauri = await projectHasTauriMarker()
|
|
64
|
+
if (!hasTauri) {
|
|
65
|
+
pass('Немає маркера Tauri (src-tauri/, tauri.conf.json, @tauri-apps/*) — tauri-tooling не вимагається')
|
|
66
|
+
return reporter.getExitCode()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
pass('Знайдено маркер Tauri — перевіряємо канонічні конфіги tauri.mdc')
|
|
70
|
+
|
|
71
|
+
const extPath = '.vscode/extensions.json'
|
|
72
|
+
if (!existsSync(extPath)) {
|
|
73
|
+
fail(`${extPath} не існує — створи з recommendations "tauri-apps.tauri-vscode" і "rust-lang.rust-analyzer" (tauri.mdc)`)
|
|
74
|
+
return reporter.getExitCode()
|
|
75
|
+
}
|
|
76
|
+
const violations = runConftestBatch({
|
|
77
|
+
policyDirRel: 'tauri/vscode_extensions',
|
|
78
|
+
namespace: 'tauri.vscode_extensions',
|
|
79
|
+
files: [extPath]
|
|
80
|
+
})
|
|
81
|
+
if (violations.length === 0) {
|
|
82
|
+
pass(`${extPath} відповідає tauri.vscode_extensions (rego)`)
|
|
83
|
+
} else {
|
|
84
|
+
for (const v of violations) fail(v.message)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return reporter.getExitCode()
|
|
88
|
+
}
|
|
@@ -363,7 +363,7 @@ const TARGETS = [
|
|
|
363
363
|
}
|
|
364
364
|
},
|
|
365
365
|
|
|
366
|
-
// abie clean-merged-branch.yml: with.ignore_branches має містити dev/ua
|
|
366
|
+
// abie clean-merged-branch.yml: with.ignore_branches має містити dev/ua.
|
|
367
367
|
{
|
|
368
368
|
namespace: 'abie.clean_merged_ignore_branches',
|
|
369
369
|
policyDir: 'abie/clean_merged_ignore_branches',
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: n-abie-clean
|
|
3
|
+
description: >-
|
|
4
|
+
Очистка проєкту від ru-середовища: гілка `ru`, директорії `ru/`, файли з суфіксом
|
|
5
|
+
`-ru`/`values-ru.*`, гілки `endsWith(...'ru')` у GitHub Actions, ru-умови у
|
|
6
|
+
Dockerfile/nginx, посилання на `cr.yandex` та раннер `ya`
|
|
7
|
+
version: '1.1'
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Скіл прибирає з проєкту все, що належить **ru-середовищу**. Залишаються тільки `dev` (як база) та `ua` як активне продакшн-середовище. Працюй послідовно по секціях нижче — після кожної секції перевіряй, що проєкт лишається консистентним (`kustomization.yaml` посилається лише на наявні файли, GitHub Actions-вирази синтаксично коректні).
|
|
11
|
+
|
|
12
|
+
## 1. Директорії з назвою `ru`
|
|
13
|
+
|
|
14
|
+
Видали всі директорії з назвою `ru` у проєкті:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
find . -type d -name "ru" -exec rm -rf {} +
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Це чистить як `country/ru/`, так і `k8s/<...>/ru/` (overlay у kustomize). Після видалення overlay `ru/` обов’язково прибери відповідний запис у `resources:` у батьківському `kustomization.yaml`, якщо він там лишився.
|
|
21
|
+
|
|
22
|
+
## 2. Файли з ru-суфіксом
|
|
23
|
+
|
|
24
|
+
Видали файли, у назві яких є явний ru-маркер:
|
|
25
|
+
|
|
26
|
+
- `values-ru.ini`, `values-ru.yaml`, `values-ru.*` (Helm/абстракції values на середовище)
|
|
27
|
+
- будь-які файли, що закінчуються на `-ru` або `-ru.<ext>`, наприклад `site/.env.prod-ru`, `*.env.prod-ru`, `*.prod-ru.conf`
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
find . -type f \( -name "values-ru.*" -o -name "*-ru" -o -name "*.prod-ru" -o -name "*.prod-ru.*" \) -delete
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 3. `.github/workflows/*.yml`
|
|
34
|
+
|
|
35
|
+
### 3.1. Тригери `on.push.branches`
|
|
36
|
+
|
|
37
|
+
Прибирай `ru` зі списку гілок.
|
|
38
|
+
|
|
39
|
+
Було:
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
on:
|
|
43
|
+
push:
|
|
44
|
+
branches: [dev, ru, ua]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Стало:
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
on:
|
|
51
|
+
push:
|
|
52
|
+
branches: [dev, ua]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 3.2. Тернарні вирази `endsWith(github.ref_name, …)`
|
|
56
|
+
|
|
57
|
+
У ланцюжках `endsWith(...)` залишай тільки гілки `dev` та `ua`. Гілку `ru` (а також пов’язаний з нею fallback на раннер `ya`, реєстр `cr.yandex/...`, NATS `cluster.local` тощо) — прибирай. Останнє значення в ланцюжку стає fallback’ом для всього, що не `dev`.
|
|
58
|
+
|
|
59
|
+
`runs-on` — було:
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
runs-on: ${{ endsWith(github.ref_name, 'dev') && 'dev' || ( endsWith(github.ref_name, 'ua') && 'ua' || 'ya' ) }}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Стало:
|
|
66
|
+
|
|
67
|
+
```yaml
|
|
68
|
+
runs-on: ${{ endsWith(github.ref_name, 'dev') && 'dev' || 'ua' }}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`NATS_URL` — було:
|
|
72
|
+
|
|
73
|
+
```yaml
|
|
74
|
+
NATS_URL: ${{ endsWith(github.ref_name, 'dev') && 'nats.nats.svc.abie-dev.internal:4222' || ( endsWith(github.ref_name, 'ua') && 'nats.nats.svc.abie-ua.internal:4222' || 'nats.nats.svc.cluster.local:4222' ) }}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Стало:
|
|
78
|
+
|
|
79
|
+
```yaml
|
|
80
|
+
NATS_URL: ${{ endsWith(github.ref_name, 'dev') && 'nats.nats.svc.abie-dev.internal:4222' || 'nats.nats.svc.abie-ua.internal:4222' }}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`NATS_STREAM` — було:
|
|
84
|
+
|
|
85
|
+
```yaml
|
|
86
|
+
NATS_STREAM: ${{ endsWith(github.ref_name, 'dev') && 'dev' || ( endsWith(github.ref_name, 'ua') && 'ua' || 'ru' ) }}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Стало:
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
NATS_STREAM: ${{ endsWith(github.ref_name, 'dev') && 'dev' || 'ua' }}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`REGISTRY` — було:
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
REGISTRY: ${{ endsWith(github.ref_name, 'ru') && 'cr.yandex/crpaerfcq9t16fse5onm' || ( endsWith(github.ref_name, 'ua') && 'europe-west4-docker.pkg.dev/abie-ua/c' || 'europe-north1-docker.pkg.dev/abie-dev/c' ) }}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Стало:
|
|
102
|
+
|
|
103
|
+
```yaml
|
|
104
|
+
REGISTRY: ${{ endsWith(github.ref_name, 'ua') && 'europe-west4-docker.pkg.dev/abie-ua/c' || 'europe-north1-docker.pkg.dev/abie-dev/c' }}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Загальне правило: у фінальному виразі мають лишитися лише `endsWith(github.ref_name, 'dev')` та `endsWith(github.ref_name, 'ua')` (або лише один із них, якщо середовище одне). Будь-яка згадка `'ru'`, `'ya'`, `cr.yandex`, `cluster.local`-fallback для ru — прибирається.
|
|
108
|
+
|
|
109
|
+
### 3.3. `ignore_branches` / `branches-ignore`
|
|
110
|
+
|
|
111
|
+
У всіх workflow-файлах та конфігах (включно з тими, що використовуються правилом **abie** `clean_merged_ignore_branches`) прибирай `ru` зі списків ignore-гілок.
|
|
112
|
+
|
|
113
|
+
## 4. Dockerfile / nginx / build-скрипти
|
|
114
|
+
|
|
115
|
+
Прибирай умовні гілки `if [ "$BRANCH" = "ru" ]; then …` та копіювання `country/ru/*`. Лишається лише той код, що працює для `dev`/`ua`.
|
|
116
|
+
|
|
117
|
+
Було:
|
|
118
|
+
|
|
119
|
+
```dockerfile
|
|
120
|
+
RUN if [ "$BRANCH" = "ru" ]; then cp -r country/ru/* public/ || true; fi && \
|
|
121
|
+
bun install && \
|
|
122
|
+
if [ "$BRANCH" = "ru" ]; then BASE="/itool/"; else BASE="/contract/"; fi && \
|
|
123
|
+
bun vite build --mode "prod-$BRANCH" --base="$BASE"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Стало:
|
|
127
|
+
|
|
128
|
+
```dockerfile
|
|
129
|
+
RUN bun install && bun vite build --mode "prod-$BRANCH" --base="$BASE"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Те саме стосується `nginx`-конфігів (`server_name`, `proxy_pass` з ru-доменами), `*.sh`-скриптів та `package.json` scripts (`build:ru`, `deploy:ru`, `prod-ru` тощо).
|
|
133
|
+
|
|
134
|
+
## 5. Після очистки
|
|
135
|
+
|
|
136
|
+
- Переконайся, що `kustomization.yaml` у кожній директорії `k8s/` не посилається на видалені overlay або файли.
|
|
137
|
+
- Пройдись `git grep` по репозиторію на залишки: `git grep -n -i -e '\bru\b' -e cr\.yandex -e country/ru -e prod-ru -e values-ru -e "'ya'"` — переглянь усі знахідки вручну, бо `ru` як слово може траплятися в легітимних контекстах (наприклад, `truncate`, `Aurum`, `cruft`). Видаляй лише ті входження, що належать ru-середовищу.
|
|
138
|
+
- Перевір CI локально: `npx @nitra/cursor check abie` (якщо правило **abie** ввімкнене у проєкті).
|
|
@@ -27,7 +27,7 @@ README має бути в директорії **k8s**.
|
|
|
27
27
|
|
|
28
28
|
Застарілі файли прибирай.
|
|
29
29
|
|
|
30
|
-
Для
|
|
30
|
+
Для overlay **ua** `namespace` задавай у `kustomization.yaml` (без окремих patch лише на зміну namespace). Деталі — **n-k8s** / **abie** у `.cursor/rules/`, якщо ці правила увімкнені в проєкті.
|
|
31
31
|
|
|
32
32
|
## Виключення: CNPG `Cluster`
|
|
33
33
|
|