-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
256 lines (218 loc) · 11.5 KB
/
Copy pathMakefile
File metadata and controls
256 lines (218 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# PQF — Product Quality Framework
# Usage: make <target>
# All Python targets assume the venv/dev deps are installed: make install
# All UI targets run inside ui/
.DEFAULT_GOAL := help
.PHONY: help install install-ui install-all \
lint format format-check ci-check \
validate \
test test-ui test-all \
build dev \
audit audit-python audit-ui \
score score-docs score-no-llm \
score-all score-all-no-llm _merge _assemble \
e2e _require-github-token _require-openrouter-key \
catalog-discovery catalog-discovery-fetch catalog-discovery-report \
catalog-import-products
PYTHON := python3
PIP := pip
NPM := npm
SCORE_DIR := .pqf-score
# Auto-populate GITHUB_TOKEN from `gh auth token` when not already set.
# In CI (GitHub Actions) the token is injected directly; locally this means
# you just need `gh` installed and authenticated — no export needed.
GITHUB_TOKEN ?= $(shell gh auth token 2>/dev/null)
export GITHUB_TOKEN
# ── Help ──────────────────────────────────────────────────────────────────────
help:
@echo ""
@echo " PQF — Product Quality Framework"
@echo ""
@echo " Setup"
@echo " make install Install Python dev dependencies"
@echo " make install-ui Install Node/UI dependencies"
@echo " make install-all Install everything"
@echo ""
@echo " Python"
@echo " make lint Lint Python with ruff"
@echo " make format Auto-format Python with ruff"
@echo " make format-check Check Python formatting without modifying"
@echo " make ci-check Run everything CI runs: lint + format-check + test + test-ui"
@echo " make validate Validate config YAML files against JSON Schemas"
@echo " make test Run Python unit tests"
@echo ""
@echo " UI (React/TypeScript)"
@echo " make test-ui Run Vitest unit tests"
@echo " make build Build the React app (ui/dist/)"
@echo " make dev Start Vite dev server"
@echo " make e2e Run Playwright end-to-end tests"
@echo ""
@echo " Combined"
@echo " make test-all Run both Python and UI tests"
@echo ""
@echo " Security"
@echo " make audit Run pip-audit + npm audit"
@echo " make audit-python Run pip-audit only"
@echo " make audit-ui Run npm audit only"
@echo ""
@echo " Scoring (requires GITHUB_TOKEN; OPENROUTER_API_KEY optional)"
@echo " make score PRODUCT=<id> Score one product (all dimensions, with LLM)"
@echo " make score-no-llm PRODUCT=<id> Score one product (skip AI doc checks)"
@echo " make score-docs PRODUCT=<id> Run only the documentation scorer"
@echo " make score-all Score all products + rebuild portfolio.json (with LLM)"
@echo " make score-all-no-llm Score all products + rebuild portfolio.json (no LLM)"
@echo " make catalog-discovery Generate docs-vs-PQF catalog discovery artifact"
@echo " make catalog-import-products Import all docs products into products/ (temporary migration)"
@echo ""
# ── Setup ─────────────────────────────────────────────────────────────────────
install:
$(PIP) install -e ".[dev]"
install-ui:
cd ui && $(NPM) install
install-all: install install-ui
# ── Config validation ─────────────────────────────────────────────────────────
validate:
$(PYTHON) -m engine.validate
# ── Python: lint & format ────────────────────────────────────────────────────
lint:
ruff check .
format:
ruff format .
format-check:
ruff format --check .
ci-check: lint format-check test test-ui
# ── Python: tests ─────────────────────────────────────────────────────────────
test:
pytest --tb=short
# ── UI: tests, build, dev ─────────────────────────────────────────────────────
test-ui:
cd ui && $(NPM) test
build:
cd ui && $(NPM) run build
dev:
cd ui && $(NPM) run dev
e2e:
cd ui && $(NPM) run e2e
# ── Combined ──────────────────────────────────────────────────────────────────
test-all: test test-ui
# ── Security audits ───────────────────────────────────────────────────────────
audit-python:
pip-audit
audit-ui:
cd ui && $(NPM) audit --audit-level=high
audit: audit-python audit-ui
# ── Scoring ───────────────────────────────────────────────────────────────────
# Usage: make score PRODUCT=matrix
PRODUCT ?= $(error PRODUCT is required. Usage: make score PRODUCT=matrix)
score: _require-github-token _require-openrouter-key
@echo "Scoring product: $(PRODUCT)"
@mkdir -p $(SCORE_DIR)/$(PRODUCT)
$(PYTHON) scorers/test_verification/scorer.py --product-yaml products/$(PRODUCT).yaml --products-dir products/ \
> $(SCORE_DIR)/$(PRODUCT)/test_verification.json
$(PYTHON) scorers/documentation/scorer.py --product-yaml products/$(PRODUCT).yaml --products-dir products/ \
> $(SCORE_DIR)/$(PRODUCT)/documentation.json
$(PYTHON) scorers/substrate_compat/scorer.py --product-yaml products/$(PRODUCT).yaml --products-dir products/ \
> $(SCORE_DIR)/$(PRODUCT)/substrate_compat.json
$(PYTHON) scorers/security_ssdlc/scorer.py --product-yaml products/$(PRODUCT).yaml --products-dir products/ \
> $(SCORE_DIR)/$(PRODUCT)/security_ssdlc.json
$(PYTHON) scorers/engagement/scorer.py --product-yaml products/$(PRODUCT).yaml --products-dir products/ \
> $(SCORE_DIR)/$(PRODUCT)/engagement.json
@echo ""
@echo "Results in $(SCORE_DIR)/$(PRODUCT)/"
@for f in $(SCORE_DIR)/$(PRODUCT)/*.json; do echo " $$f:"; cat $$f | $(PYTHON) -m json.tool --indent 2; echo ""; done
score-no-llm: _require-github-token
@echo "Scoring product: $(PRODUCT) (LLM checks skipped — diataxis/style will be 0/false)"
@mkdir -p $(SCORE_DIR)/$(PRODUCT)
$(PYTHON) scorers/test_verification/scorer.py --product-yaml products/$(PRODUCT).yaml --products-dir products/ \
> $(SCORE_DIR)/$(PRODUCT)/test_verification.json
OPENROUTER_API_KEY= $(PYTHON) scorers/documentation/scorer.py --product-yaml products/$(PRODUCT).yaml --products-dir products/ \
> $(SCORE_DIR)/$(PRODUCT)/documentation.json
$(PYTHON) scorers/substrate_compat/scorer.py --product-yaml products/$(PRODUCT).yaml --products-dir products/ \
> $(SCORE_DIR)/$(PRODUCT)/substrate_compat.json
$(PYTHON) scorers/security_ssdlc/scorer.py --product-yaml products/$(PRODUCT).yaml --products-dir products/ \
> $(SCORE_DIR)/$(PRODUCT)/security_ssdlc.json
$(PYTHON) scorers/engagement/scorer.py --product-yaml products/$(PRODUCT).yaml --products-dir products/ \
> $(SCORE_DIR)/$(PRODUCT)/engagement.json
@echo ""
@echo "Results in $(SCORE_DIR)/$(PRODUCT)/"
@for f in $(SCORE_DIR)/$(PRODUCT)/*.json; do echo " $$f:"; cat $$f | $(PYTHON) -m json.tool --indent 2; echo ""; done
score-docs: _require-github-token _require-openrouter-key
$(PYTHON) scorers/documentation/scorer.py --product-yaml products/$(PRODUCT).yaml --products-dir products/
# ── Score all products and rebuild portfolio.json ─────────────────────────────
# Discovers all product YAMLs in products/, scores each one, merges the raw
# scorer outputs into computed/<id>.json, then runs assemble.py to regenerate
# public/portfolio.json — ready for `make dev`.
#
# score-all — full run including LLM-powered doc checks (needs OPENROUTER_API_KEY)
# score-all-no-llm — skips AI checks; useful locally without an OpenRouter key
_PRODUCTS := $(patsubst products/%.yaml,%,$(wildcard products/*.yaml))
score-all: _require-github-token _require-openrouter-key
@echo "Scoring all products: $(_PRODUCTS)"
@for p in $(_PRODUCTS); do \
echo ""; \
echo "── $$p ──────────────────────────────────────────────"; \
$(MAKE) --no-print-directory score PRODUCT=$$p; \
$(MAKE) --no-print-directory _merge PRODUCT=$$p; \
done
@$(MAKE) --no-print-directory _assemble
@echo ""
@echo "Done. public/portfolio.json updated — run 'make dev' to view."
score-all-no-llm: _require-github-token
@echo "Scoring all products (no LLM): $(_PRODUCTS)"
@for p in $(_PRODUCTS); do \
echo ""; \
echo "── $$p ──────────────────────────────────────────────"; \
$(MAKE) --no-print-directory score-no-llm PRODUCT=$$p; \
$(MAKE) --no-print-directory _merge PRODUCT=$$p; \
done
@$(MAKE) --no-print-directory _assemble
@echo ""
@echo "Done. public/portfolio.json updated — run 'make dev' to view."
# Merge raw scorer output for one product into computed/<id>.json
_merge:
$(PYTHON) engine/merge_computed.py \
--product-id $(PRODUCT) \
--scorers-output-dir $(SCORE_DIR)/$(PRODUCT) \
--dimensions config/dimensions.yaml \
--output computed/$(PRODUCT).json
@echo " → computed/$(PRODUCT).json updated"
# Rebuild public/portfolio.json from all computed/*.json
_assemble:
$(PYTHON) engine/assemble.py \
--products-dir products/ \
--computed-dir computed/ \
--dimensions config/dimensions.yaml \
--drift-history drift-history.json \
--output public/portfolio.json
@echo " → public/portfolio.json updated"
_require-github-token:
@test -n "$(GITHUB_TOKEN)" || (echo "Error: GITHUB_TOKEN is not set" && exit 1)
_require-openrouter-key:
@test -n "$(OPENROUTER_API_KEY)" || (echo "Error: OPENROUTER_API_KEY is not set" && exit 1)
# Temporary migration workflow:
# - fetch docs products into a local cache
# - generate a discovery artifact from cached docs + repo PQF products
# Remove the fetch step once the catalog migration no longer needs external docs.
DOCS_PRODUCTS_DIR ?= .pqf-cache/platform-engineering-docs/data/products
DOCS_PRODUCTS_REPO ?= canonical/platform-engineering-docs
DOCS_PRODUCTS_REF ?= main
CATALOG_OVERRIDES_FILE ?=
catalog-discovery: catalog-discovery-fetch catalog-discovery-report
catalog-discovery-fetch:
$(PYTHON) tools/fetch_platform_engineering_docs_products.py \
--repo $(DOCS_PRODUCTS_REPO) \
--ref $(DOCS_PRODUCTS_REF) \
--output-dir $(DOCS_PRODUCTS_DIR)
catalog-discovery-report:
$(PYTHON) tools/generate_catalog_discovery.py \
--docs-products-dir $(DOCS_PRODUCTS_DIR) \
--pqf-products-dir products \
--pqf-schema-path config/schemas/product.schema.json \
--ui-types-path ui/src/types.ts \
$(if $(CATALOG_OVERRIDES_FILE),--overrides $(CATALOG_OVERRIDES_FILE),) \
--output docs/superpowers/artifacts/2026-07-20-product-catalog-discovery.json
catalog-import-products: catalog-discovery-fetch
$(PYTHON) tools/import_platform_engineering_docs_products.py \
--docs-products-dir $(DOCS_PRODUCTS_DIR) \
--output-dir products \
--clean