Skip to content

Commit 1352ddb

Browse files
committed
Merge remote-tracking branch 'origin/development' into ci/enable-shared-e2e
# Conflicts: # .github/workflows/code-quality.yml
2 parents 92dd733 + a873914 commit 1352ddb

4 files changed

Lines changed: 56 additions & 15 deletions

File tree

.githooks/pre-commit

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/bin/sh
2+
# Committed pre-commit hook (activated via `git config core.hooksPath .githooks`,
3+
# which `npm install` / `composer install` set automatically — see package.json
4+
# "prepare" and composer.json "post-install-cmd").
5+
#
6+
# Regenerates docs/features.json whenever staged changes touch openspec/specs/
7+
# or the features overlay, so the commercial capability list can never go
8+
# stale. CI (features-check / features-extract) only VERIFIES — generation
9+
# happens here, before the commit, never in the pipeline.
10+
#
11+
# Best-effort by design: any failure only warns and never blocks the commit —
12+
# the CI gate is the enforcement backstop.
13+
14+
if git diff --cached --name-only | grep -qE "^openspec/(specs/|features\.overlay\.json)"; then
15+
CACHE=".git/extract-features.py"
16+
# Fetch the canonical script (single source of truth in ConductionNL/.github);
17+
# fall back to a previously cached copy when offline.
18+
curl -sf --max-time 10 \
19+
https://raw.githubusercontent.com/ConductionNL/.github/main/scripts/extract-features.py \
20+
-o "$CACHE" 2>/dev/null || true
21+
22+
if [ -f "$CACHE" ]; then
23+
if command -v python3 >/dev/null 2>&1; then PY="python3";
24+
elif command -v py >/dev/null 2>&1; then PY="py -3";
25+
else PY="python"; fi
26+
27+
if $PY "$CACHE" --app-root . >/dev/null 2>&1; then
28+
git add docs/features.json
29+
echo "pre-commit: docs/features.json regenerated from openspec/specs/."
30+
else
31+
echo "pre-commit: WARNING — could not regenerate docs/features.json (python or pyyaml missing?). CI features-check will verify." >&2
32+
fi
33+
else
34+
echo "pre-commit: WARNING — could not fetch extract-features.py (offline?). CI features-check will verify." >&2
35+
fi
36+
fi
37+
38+
exit 0

.github/workflows/code-quality.yml

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,21 @@ concurrency:
2222
group: quality-${{ github.head_ref || github.ref_name }}
2323
cancel-in-progress: true
2424

25-
# Union of two intents, both of which are load-bearing:
25+
# Permission CEILING for the called quality pipeline. GitHub statically
26+
# validates the called workflow's declared job permissions against this
27+
# grant — even for jobs that are disabled — so it must cover the maximum any
28+
# nested job declares: journeydoc-capture (contents+actions write),
29+
# update-baseline / features-extract (contents write), SBOM (packages read),
30+
# and the Quality Report PR comment (issues / pull-requests write).
2631
#
27-
# * `issues: write` + `pull-requests: write` come from development's
28-
# least-privilege pass (#257) — the Quality Report job posts a sticky PR
29-
# comment and cannot without them.
30-
# * `contents: write` + `actions: write` + `packages: read` are required by
31-
# jobs the called workflow declares (coverage-baseline update, journeydoc
32-
# capture, SBOM). A caller cannot grant a reusable workflow more than it
33-
# holds itself, so capping those at `read` makes the whole call fail to
34-
# START: zero jobs, no annotations — indistinguishable from "nothing to
35-
# run". `development` at cb101f1 shows exactly that, two `startup_failure`
36-
# runs in a row.
32+
# A caller cannot grant a reusable workflow more than it holds itself, so
33+
# capping any of these at `read` makes the whole call fail to START: zero jobs,
34+
# no annotations — indistinguishable from "nothing to run". `development` at
35+
# cb101f1 shows exactly that, two `startup_failure` runs in a row.
3736
#
38-
# Keeping only development's block would therefore trade a posted comment for a
39-
# pipeline that never starts. Keeping only this branch's would silently drop
40-
# the comment. Both are kept.
37+
# This block is the UNION of both branches' grants, which agreed on every entry
38+
# except `packages: read`. Dropping development's half would silently lose the
39+
# PR comment; dropping this branch's half would stop the pipeline starting.
4140
permissions:
4241
contents: write
4342
actions: write

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@
6666
"@quality:phpmd-score",
6767
"@quality:psalm-score",
6868
"@quality:phpstan-score"
69+
],
70+
"post-install-cmd": [
71+
"git config core.hooksPath .githooks || true"
6972
]
7073
},
7174
"config": {

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"check:json-strict": "node tests/validate-json-strict.js",
2222
"check:specs": "npm run check:json-strict && npm run check:manifest && npm run check:register",
2323
"seed:e2e": "node tests/e2e/seed-example-data.mjs",
24-
"test:js-unit": "node --test tests/unit-js/*.test.mjs"
24+
"test:js-unit": "node --test tests/unit-js/*.test.mjs",
25+
"prepare": "git config core.hooksPath .githooks || true"
2526
},
2627
"browserslist": [
2728
"extends @nextcloud/browserslist-config"

0 commit comments

Comments
 (0)