yadflow 2.4.1 → 2.4.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/CHANGELOG.md CHANGED
@@ -1,9 +1,9 @@
1
- ## [2.4.1](https://github.com/abdelrahmannasr/yadflow/compare/v2.4.0...v2.4.1) (2026-06-14)
1
+ ## [2.4.2](https://github.com/abdelrahmannasr/yadflow/compare/v2.4.1...v2.4.2) (2026-06-14)
2
2
 
3
3
 
4
4
  ### Bug Fixes
5
5
 
6
- * migrate pre-2.0 sdlc-* skills during `yad setup` ([5b53e40](https://github.com/abdelrahmannasr/yadflow/commit/5b53e40480b3049d4efc596792f2630597d837fd))
6
+ * route GitLab CI gate jobs to tag-locked runners via $YAD_RUNNER_TAGS ([a0311c5](https://github.com/abdelrahmannasr/yadflow/commit/a0311c5af647f63968f3f34e8e6e6fa48b7423d8)), closes [#50](https://github.com/abdelrahmannasr/yadflow/issues/50)
7
7
 
8
8
  # [2.2.0](https://github.com/abdelrahmannasr/yadflow/compare/v2.1.0...v2.2.0) (2026-06-14)
9
9
 
package/cli/doctor.mjs CHANGED
@@ -162,9 +162,43 @@ export function projectChecks(checks, root) {
162
162
  }
163
163
  if (!registry.repos.length) check(checks, 'repos', 'project', 'warn', 'no code repos registered', 'run `yad setup` to connect one');
164
164
  }
165
+
166
+ ciTagsChecks(checks, root, hub, registry);
165
167
  return { hub, registry };
166
168
  }
167
169
 
170
+ // GitLab CI runner tags: the wired fragments run docker-image jobs. On instances whose runners are
171
+ // all tag-locked (run_untagged: false), an untagged image job matches no runner and sits `pending`
172
+ // forever — silently blocking the gates (issue #50). A current fragment carries
173
+ // `tags: [$YAD_RUNNER_TAGS]`; warn on any wired GitLab fragment that sets an `image:` but has no
174
+ // `tags:` (an old install, or one hand-reverted by a sync). Pure local read — no API calls.
175
+ export function ciTagsChecks(checks, root, hub, registry) {
176
+ const untagged = (p) => {
177
+ try {
178
+ const txt = fs.readFileSync(p, 'utf8');
179
+ return /^\s*image:/m.test(txt) && !/^\s*tags:/m.test(txt);
180
+ } catch { return false; } // absent fragment is not this check's concern
181
+ };
182
+ const fragments = [];
183
+ if (hub?.platform === 'gitlab' && (hub.bridge_enabled === true || hub.bridge === true)) {
184
+ fragments.push(
185
+ { scope: 'hub', file: '.gitlab/ci/yad-gate-sync.yml', path: path.join(root, '.gitlab/ci/yad-gate-sync.yml') },
186
+ { scope: 'hub', file: '.gitlab/ci/yad-verified-commits.yml', path: path.join(root, '.gitlab/ci/yad-verified-commits.yml') },
187
+ );
188
+ }
189
+ for (const repo of registry?.repos || []) {
190
+ if (repo.platform !== 'gitlab' || !repo.path) continue;
191
+ fragments.push({ scope: repo.name, file: '.gitlab/ci/yad-checks.yml', path: path.join(path.resolve(root, repo.path), '.gitlab/ci/yad-checks.yml') });
192
+ }
193
+ for (const f of fragments) {
194
+ if (untagged(f.path)) {
195
+ check(checks, `ci-tags:${f.scope}`, 'project', 'warn',
196
+ `${f.scope}: ${f.file} runs a docker job with no \`tags:\` [YAD-CI-001]`,
197
+ 'tag-locked runners (run_untagged: false) will strand it at `pending` — run `yad update`, then set the `YAD_RUNNER_TAGS` CI/CD variable');
198
+ }
199
+ }
200
+ }
201
+
168
202
  export function epicChecks(checks, root) {
169
203
  const epicsDir = path.join(root, 'epics');
170
204
  if (!exists(epicsDir)) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yadflow",
3
- "version": "2.4.1",
3
+ "version": "2.4.2",
4
4
  "description": "Yadflow — the gated, team, multi-repo SDLC: author → review → build with a PR-driven review gate and a zero-dependency `yad` CLI (setup, gate, commit, open-pr, repo). A BMAD module + 22 yad-* skills.",
5
5
  "type": "module",
6
6
  "author": "AbdelRahman Nasr",
@@ -88,6 +88,13 @@ Copy from this skill's `templates/`:
88
88
  human to paste (graceful degradation — never guess-edit a pipeline you cannot parse).
89
89
  - The legacy standalone `templates/gitlab/.gitlab-ci.yml` is retained only for a clean greenfield repo
90
90
  that prefers a single self-contained file; the include path above is the default.
91
+ - **Tag-locked runners** (`run_untagged: false`, common on self-hosted): the fragment's jobs run a
92
+ docker image, so set a `YAD_RUNNER_TAGS` CI/CD variable (e.g. `dind_runner`) to route them — the
93
+ `default:` block emits `tags: [$YAD_RUNNER_TAGS]`. When unset, current GitLab (≥15) drops the
94
+ empty-expanded tag so the jobs run untagged (gitlab.com shared runners); older versions may
95
+ strand them `pending`, in which case set the variable to a real tag. The variable lives in
96
+ project settings, so it survives every `yad` sync. Single value only — `tags: [$VAR]` is one tag
97
+ equal to the whole variable, not a comma-split.
91
98
 
92
99
  - Ensure `<repo>/package.json` defines `lint`, `build`, `test` scripts (see `references/check-gates.md`
93
100
  for the canonical scripts). **Only ADD a missing script; never overwrite an existing one.**
@@ -11,6 +11,14 @@
11
11
  # colliding with the host project's own job names.
12
12
  default:
13
13
  image: node:20
14
+ # Runner selection. These jobs need a docker/dind executor; on instances whose runners are all
15
+ # tag-locked (run_untagged: false) an untagged image job never starts. Set the YAD_RUNNER_TAGS
16
+ # CI/CD variable (Settings → CI/CD → Variables, e.g. `dind_runner`) to route them — it lives in
17
+ # project settings, so it survives every `yad` sync. When unset, current GitLab (>=15) drops the
18
+ # empty-expanded tag so the job runs untagged (gitlab.com shared runners); some older versions
19
+ # instead strand it `pending` — if so, set the variable to a real tag. Single value only:
20
+ # `tags: [$VAR]` is one tag equal to the whole variable, not a comma-split.
21
+ tags: [$YAD_RUNNER_TAGS]
14
22
 
15
23
  .sdlc_mr_only:
16
24
  rules:
@@ -12,6 +12,11 @@
12
12
  # Job name is yad-hub-prefixed so it can coexist with the code-repo fragment in one pipeline.
13
13
  yad-hub-verified-commits:
14
14
  needs: []
15
+ # Runner selection: set the YAD_RUNNER_TAGS CI/CD variable (e.g. `dind_runner`) to route this
16
+ # docker job on instances whose runners are tag-locked (run_untagged: false) — it lives in
17
+ # project Settings → CI/CD → Variables, so it survives every `yad` sync. When unset, current
18
+ # GitLab (>=15) runs the job untagged; older versions may strand it — set a real tag if so.
19
+ tags: [$YAD_RUNNER_TAGS]
15
20
  image: node:20
16
21
  variables:
17
22
  GIT_DEPTH: "0" # full history so the gate can diff against the target branch
@@ -89,6 +89,14 @@ remains valid and is the fallback whenever CI cannot push.
89
89
  `SDLC_GATE_TOKEN` project-access-token variable (`read_api` + `write_repository`). GitLab fires no
90
90
  pipeline on an approval alone, so the schedule is the path that picks approvals up (≤ ~15 min
91
91
  latency); MR events and the merge are near-immediate.
92
+ - **If your runners are tag-locked** (`run_untagged: false`, common on self-hosted): set a
93
+ `YAD_RUNNER_TAGS` CI/CD variable (e.g. `dind_runner`) so the docker-image `yad-gate-sync` job
94
+ is routed to a runner — otherwise it sits `pending` forever. The fragment emits
95
+ `tags: [$YAD_RUNNER_TAGS]`. When unset, current GitLab (≥15) drops the empty-expanded tag so the
96
+ job runs untagged (gitlab.com shared runners); older versions may strand it `pending`, in which
97
+ case set the variable to a real tag. The variable lives in project settings, so it survives
98
+ every `yad` sync. Single value only — `tags: [$VAR]` is one tag equal to the whole variable,
99
+ not a comma-split.
92
100
  3. Commit the workflow to the hub. GitHub needs nothing else — the ephemeral `github.token` reads the
93
101
  PR and pushes the ledger. If the default branch is protected, see the workflow header for the
94
102
  bypass / PAT options; until then the run fails visibly and manual `yad gate sync` still works.
@@ -31,6 +31,11 @@ variables:
31
31
 
32
32
  yad-gate-sync:
33
33
  needs: []
34
+ # Runner selection: set the YAD_RUNNER_TAGS CI/CD variable (e.g. `dind_runner`) to route this
35
+ # docker job on instances whose runners are tag-locked (run_untagged: false) — it lives in
36
+ # project Settings → CI/CD → Variables, so it survives every `yad` sync. When unset, current
37
+ # GitLab (>=15) runs the job untagged; older versions may strand it — set a real tag if so.
38
+ tags: [$YAD_RUNNER_TAGS]
34
39
  image: node:20
35
40
  rules:
36
41
  # MR-event path: fires on MR open / push to the review branch — NOT on approval (see header).