@7n/rules-ci-github 1.7.0 → 1.8.0
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
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.8.0] - 2026-07-20
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- service_deploy_workflow: перевірка outputs-мапінгу plan-джоби — кожен ключ гейта `needs.plan.outputs.<key>` має бути задекларований у `jobs.plan.outputs` і вказувати на `steps.<id>.outputs.<key>` реального кроку (інакше гейт тихо порожній і джоба скіпається завжди)
|
|
8
|
+
|
|
9
|
+
## [1.7.1] - 2026-07-19
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- release: @7n/rules@1.27.0, @7n/rules-lang-js@0.3.0, @7n/rules-lang-python@0.5.1, @7n/rules-lang-rust@0.5.1
|
|
14
|
+
|
|
3
15
|
## [1.7.0] - 2026-07-18
|
|
4
16
|
|
|
5
17
|
### Changed
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@ Rego-пакет: `ga.service_deploy_workflow`
|
|
|
12
12
|
4. **`test`-джоба** — `needs: plan`, `if: needs.plan.outputs.any == 'true'`; тести лише сервісу (`bun test run/<service>`; python-стек — `astral-sh/setup-uv` + `uv sync --locked` + `pytest run/<service>`).
|
|
13
13
|
5. **Деплой** — needs-ланцюг (можна через проміжний `build`) **транзитивно досягає** `plan` і всі lint/test-джоби; кожна джоба з `needs` на умовні lint-джоби має `if` з `!cancelled()` та `!contains(needs.*.result, 'failure')` — skipped-лінт не блокує деплой, failed — блокує.
|
|
14
14
|
|
|
15
|
-
Що перевіряє rego: наявність plan-джоби з `ci plan --path … --github`; збіг `on.push.paths` ↔ `--path`; для кожної lint-джоби — `needs: plan`, гейт по outputs, той самий `--path`, `--no-fix`, prep-крок, `fetch-depth: 0`; для термінальних джоб — транзитивну досяжність plan і всіх перевірок та skip-толерантний `if`.
|
|
15
|
+
Що перевіряє rego: наявність plan-джоби з `ci plan --path … --github`; збіг `on.push.paths` ↔ `--path`; outputs-мапінг plan-джоби (кожен ключ, на який посилається гейт `needs.plan.outputs.<key>`, задекларований у `jobs.plan.outputs` і вказує на `steps.<id>.outputs.<key>` реального кроку — інакше гейт тихо порожній); для кожної lint-джоби — `needs: plan`, гейт по outputs, той самий `--path`, `--no-fix`, prep-крок, `fetch-depth: 0`; для термінальних джоб — транзитивну досяжність plan і всіх перевірок та skip-толерантний `if`.
|
|
16
16
|
|
|
17
17
|
Що НЕ перевіряється (справа автора): добір доменів під вміст сервісу, зміст test/deploy-кроків, секрети/environment, uv-prep. Спільні workflow-інваріанти (persist-credentials, min-версії uses, існування paths-глобів) покривають `workflow_common` і `workflows`.
|
|
18
18
|
|
|
@@ -21,8 +21,7 @@
|
|
|
21
21
|
# Ланцюги deploy (build → deploy) законні: досяжність — graph.reachable.
|
|
22
22
|
#
|
|
23
23
|
# Не перевіряється тут (лишається .mdc-каноном): вибір набору доменів під
|
|
24
|
-
# сервіс, зміст test/deploy-кроків,
|
|
25
|
-
# python-стеку. Спільні workflow-перевірки (persist-credentials, min-версії
|
|
24
|
+
# сервіс, зміст test/deploy-кроків, uv-prep для python-стеку. Спільні workflow-перевірки (persist-credentials, min-версії
|
|
26
25
|
# uses) — у ga.workflow_common; існування paths-глобів — у ga/workflows.
|
|
27
26
|
package ga.service_deploy_workflow
|
|
28
27
|
|
|
@@ -65,6 +64,26 @@ service_paths contains p if {
|
|
|
65
64
|
p := m[0][1]
|
|
66
65
|
}
|
|
67
66
|
|
|
67
|
+
# Outputs-мапінг plan-джоби: гейт `needs.plan.outputs.<key>` працює лише коли
|
|
68
|
+
# jobs.plan.outputs декларує `<key>` з посиланням на `steps.<id>.outputs.<key>`
|
|
69
|
+
# кроку з таким id — інакше значення тихо порожнє і джоба скіпається завжди.
|
|
70
|
+
plan_outputs := object.get(object.get(jobs, "plan", {}), "outputs", {})
|
|
71
|
+
|
|
72
|
+
plan_step_ids contains id if {
|
|
73
|
+
some step in object.get(object.get(jobs, "plan", {}), "steps", [])
|
|
74
|
+
id := object.get(step, "id", "")
|
|
75
|
+
id != ""
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# Ключі plan-outputs, на які посилаються гейти інших джоб.
|
|
79
|
+
gated_output_keys contains k if {
|
|
80
|
+
some name, job in jobs
|
|
81
|
+
name != "plan"
|
|
82
|
+
cond := object.get(job, "if", "")
|
|
83
|
+
some m in regex.find_all_string_submatch_n(`needs\.plan\.outputs\.([A-Za-z0-9_]+)`, cond, -1)
|
|
84
|
+
k := m[1]
|
|
85
|
+
}
|
|
86
|
+
|
|
68
87
|
# Lint-джоби (крок `n-rules lint <domain> … --path …`) з розібраною командою.
|
|
69
88
|
lint_cmds contains cmd if {
|
|
70
89
|
some name, job in jobs
|
|
@@ -135,6 +154,24 @@ deny contains msg if {
|
|
|
135
154
|
not contains(r, "--github")
|
|
136
155
|
}
|
|
137
156
|
|
|
157
|
+
# ── deny: outputs-мапінг plan-джоби ─────────────────────────────────────
|
|
158
|
+
|
|
159
|
+
deny contains msg if {
|
|
160
|
+
is_service_workflow
|
|
161
|
+
jobs.plan
|
|
162
|
+
some k in gated_output_keys
|
|
163
|
+
not plan_outputs[k]
|
|
164
|
+
msg := sprintf("plan: jobs.plan.outputs не мапить `%s` (канон: `%s: ${{ steps.plan.outputs.%s }}`) — гейт `needs.plan.outputs.%s` тихо порожній і джоба скіпається завжди (ga.mdc)", [k, k, k, k])
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
deny contains msg if {
|
|
168
|
+
is_service_workflow
|
|
169
|
+
some k in gated_output_keys
|
|
170
|
+
v := plan_outputs[k]
|
|
171
|
+
not output_maps_plan_step(v, k)
|
|
172
|
+
msg := sprintf("plan: outputs.%s не посилається на `steps.<id>.outputs.%s` кроку з таким id — гейт тихо порожній (ga.mdc)", [k, k])
|
|
173
|
+
}
|
|
174
|
+
|
|
138
175
|
# ── deny: тригер paths ↔ сервісний каталог ─────────────────────────────
|
|
139
176
|
|
|
140
177
|
deny contains msg if {
|
|
@@ -245,6 +282,13 @@ glob_covers(sp) if {
|
|
|
245
282
|
startswith(g, sp)
|
|
246
283
|
}
|
|
247
284
|
|
|
285
|
+
# Значення output-а посилається на `steps.<id>.outputs.<key>` реального кроку.
|
|
286
|
+
output_maps_plan_step(v, k) if {
|
|
287
|
+
m := regex.find_all_string_submatch_n(sprintf(`steps\.([A-Za-z0-9_-]+)\.outputs\.%s`, [k]), v, 1)
|
|
288
|
+
count(m) > 0
|
|
289
|
+
m[0][1] in plan_step_ids
|
|
290
|
+
}
|
|
291
|
+
|
|
248
292
|
job_has_prep(job) if {
|
|
249
293
|
some step in object.get(job, "steps", [])
|
|
250
294
|
step.uses == "./.github/actions/setup-bun-deps"
|