-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathMakefile
More file actions
395 lines (349 loc) · 15.6 KB
/
Copy pathMakefile
File metadata and controls
395 lines (349 loc) · 15.6 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
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# agent-pmo:74cf183
# =============================================================================
# Standard Makefile — Nimblesite.DataProvider.Core
# Cross-platform: Linux, macOS, Windows (via GNU Make)
# All targets are language-agnostic. Add language-specific helpers below.
# =============================================================================
.PHONY: build test lint fmt clean ci setup check coverage vsix help
# -----------------------------------------------------------------------------
# OS Detection — portable commands for Linux, macOS, and Windows
# On Windows, run via GNU Make with PowerShell (e.g., make from Git Bash or
# choco install make). The $(OS) variable is set to "Windows_NT" automatically.
# -----------------------------------------------------------------------------
ifeq ($(OS),Windows_NT)
SHELL := powershell.exe
.SHELLFLAGS := -NoProfile -Command
RM = Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
MKDIR = New-Item -ItemType Directory -Force
HOME ?= $(USERPROFILE)
else
# Force bash for non-Windows. Some recipes use bash-only constructs
# (e.g. ${PIPESTATUS[0]}, [[ ... ]]), and Ubuntu's default /bin/sh is dash.
SHELL := /bin/bash
RM = rm -rf
MKDIR = mkdir -p
endif
# All .NET test projects (one per line for readability)
DOTNET_TEST_PROJECTS = \
DataProvider/Nimblesite.DataProvider.Tests \
DataProvider/Nimblesite.DataProvider.Example.Tests \
Lql/Nimblesite.Lql.Tests \
Lql/Nimblesite.Lql.TypeProvider.FSharp.Tests \
Migration/Nimblesite.DataProvider.Migration.Tests \
Sync/Nimblesite.Sync.Tests \
Sync/Nimblesite.Sync.SQLite.Tests \
Sync/Nimblesite.Sync.Postgres.Tests \
Sync/Nimblesite.Sync.Integration.Tests \
Sync/Nimblesite.Sync.Http.Tests \
Reporting/Nimblesite.Reporting.Tests \
Reporting/Nimblesite.Reporting.Integration.Tests
# =============================================================================
# Standard Targets
#
# Portfolio-wide uniform interface — these 7 targets exist in every repo and
# their names never change. See REPO-STANDARDS-SPEC [MAKE-TARGETS].
# Do NOT add extra public targets here — put them in the Repo-Specific
# Targets section below.
# =============================================================================
## build: Compile/assemble all artifacts
build:
@echo "==> Building..."
$(MAKE) _build
## test: Fail-fast tests + coverage + threshold enforcement.
## See REPO-STANDARDS-SPEC [TEST-RULES].
test:
@echo "==> Testing..."
$(MAKE) _test
## lint: Run all linters/analyzers (read-only). Does NOT format.
lint:
@echo "==> Linting..."
$(MAKE) _lint
## fmt: Format all code in-place. Pass CHECK=1 for read-only verification (CI).
fmt:
@echo "==> Formatting$(if $(CHECK), (check mode),)..."
$(MAKE) _fmt$(if $(CHECK),_check,)
## clean: Remove all build artifacts
clean:
@echo "==> Cleaning..."
$(MAKE) _clean
## ci: lint + test + build (full CI simulation)
ci: lint test build
## setup: Post-create dev environment setup (used by devcontainer)
setup:
@echo "==> Setting up development environment..."
$(MAKE) _setup
@echo "==> Setup complete. Run 'make ci' to validate."
# =============================================================================
# -----------------------------------------------------------------------------
# Repo-Specific Targets (NOT part of the portfolio standard 7)
#
# Add helpers unique to this repo below. They MUST NOT shadow any of the 7
# standard targets above. See REPO-STANDARDS-SPEC [MAKE-TARGETS].
# -----------------------------------------------------------------------------
# =============================================================================
## check: lint + test (pre-commit shortcut)
check: lint test
## coverage: Generate HTML coverage report (runs tests first)
coverage:
@echo "==> Coverage report..."
$(MAKE) _coverage
## vsix: Build Rust LSP (release), compile & package the VS Code extension (.vsix), and install it
vsix:
@echo "==> Building and packaging VSIX..."
bash Lql/lql-lsp-rust/build-vsix.sh
# =============================================================================
# LANGUAGE-SPECIFIC IMPLEMENTATIONS
# =============================================================================
_build: _build_dotnet _build_rust _build_ts
_test: _test_dotnet _test_rust _test_ts
_lint: _lint_dotnet _lint_rust _lint_ts
_fmt: _fmt_dotnet _fmt_rust
# Internal — invoked by `make fmt CHECK=1`.
_fmt_check: _fmt_check_dotnet _fmt_check_rust
_clean: _clean_dotnet _clean_rust _clean_ts
_coverage: _coverage_dotnet
_setup: _setup_dotnet _setup_ts
# =============================================================================
# COVERAGE ENFORCEMENT (shared shell logic)
# =============================================================================
# Each test target collects coverage, compares against coverage-thresholds.json,
# fails hard if below, and ratchets up if above.
#
# coverage-thresholds.json keys are SOURCE project paths, e.g.:
# "DataProvider/Nimblesite.DataProvider.Core": { "threshold": 88, "include": "..." }
#
# The SRC_KEY mapping converts test project paths -> source project keys.
# CI calls these same make targets — no duplication.
# =============================================================================
# --- C#/.NET ---
_build_dotnet:
dotnet build DataProvider.sln --configuration Release
_test_dotnet:
@for test_proj in $(DOTNET_TEST_PROJECTS); do \
SRC_KEY=$$(echo "$$test_proj" | sed 's/\.Tests$$//'); \
case "$$SRC_KEY" in \
"DataProvider/Nimblesite.DataProvider") SRC_KEY="DataProvider/Nimblesite.DataProvider.Core" ;; \
"DataProvider/Nimblesite.DataProvider.Example") ;; \
"Lql/Nimblesite.Lql") SRC_KEY="Lql/Nimblesite.Lql.Core" ;; \
"Lql/Nimblesite.Lql.TypeProvider.FSharp") ;; \
"Migration/Nimblesite.DataProvider.Migration") SRC_KEY="Migration/Nimblesite.DataProvider.Migration.Core" ;; \
"Sync/Nimblesite.Sync") SRC_KEY="Sync/Nimblesite.Sync.Core" ;; \
"Sync/Nimblesite.Sync.SQLite") ;; \
"Sync/Nimblesite.Sync.Postgres") ;; \
"Sync/Nimblesite.Sync.Integration") ;; \
"Sync/Nimblesite.Sync.Http") ;; \
"Reporting/Nimblesite.Reporting") ;; \
"Reporting/Nimblesite.Reporting.Integration") ;; \
esac; \
THRESHOLD=$$(jq -r ".projects[\"$$SRC_KEY\"].threshold // .default_threshold" coverage-thresholds.json); \
INCLUDE=$$(jq -r ".projects[\"$$SRC_KEY\"].include // empty" coverage-thresholds.json); \
echo ""; \
echo "============================================================"; \
echo "==> Testing $$SRC_KEY (via $$test_proj, threshold: $$THRESHOLD%)"; \
if [ -n "$$INCLUDE" ]; then echo " Include filter: $$INCLUDE"; fi; \
echo "============================================================"; \
rm -rf "$$test_proj/TestResults"; \
if [ -n "$$INCLUDE" ]; then \
dotnet test "$$test_proj" --configuration Release \
--settings coverlet.runsettings \
--collect:"XPlat Code Coverage" \
--results-directory "$$test_proj/TestResults" \
--verbosity normal \
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Include="$$INCLUDE"; \
else \
dotnet test "$$test_proj" --configuration Release \
--settings coverlet.runsettings \
--collect:"XPlat Code Coverage" \
--results-directory "$$test_proj/TestResults" \
--verbosity normal; \
fi; \
if [ $$? -ne 0 ]; then \
echo "FAIL [$$SRC_KEY]: Tests failed ($$test_proj)"; \
exit 1; \
fi; \
COBERTURA=$$(find "$$test_proj/TestResults" -name "coverage.cobertura.xml" -type f 2>/dev/null | head -1); \
if [ -z "$$COBERTURA" ]; then \
echo "FAIL [$$SRC_KEY]: No coverage file produced ($$test_proj)"; \
exit 1; \
fi; \
LINE_RATE=$$(sed -n 's/.*line-rate="\([0-9.]*\)".*/\1/p' "$$COBERTURA" | head -1); \
if [ -z "$$LINE_RATE" ]; then \
echo "FAIL [$$SRC_KEY]: Could not parse line-rate from $$COBERTURA"; \
exit 1; \
fi; \
COVERAGE=$$(echo "$$LINE_RATE * 100" | bc -l); \
COVERAGE_FMT=$$(printf "%.2f" $$COVERAGE); \
echo ""; \
echo " [$$SRC_KEY] Coverage: $$COVERAGE_FMT% | Threshold: $$THRESHOLD%"; \
BELOW=$$(echo "$$COVERAGE < $$THRESHOLD" | bc -l); \
if [ "$$BELOW" = "1" ]; then \
echo " FAIL [$$SRC_KEY]: $$COVERAGE_FMT% is BELOW threshold $$THRESHOLD%"; \
exit 1; \
fi; \
ABOVE=$$(echo "$$COVERAGE > $$THRESHOLD" | bc -l); \
if [ "$$ABOVE" = "1" ]; then \
NEW=$$(echo "$$COVERAGE" | awk '{print int($$1)}'); \
echo " Ratcheting threshold: $$THRESHOLD% -> $$NEW%"; \
jq ".projects[\"$$SRC_KEY\"].threshold = $$NEW" coverage-thresholds.json > coverage-thresholds.json.tmp && mv coverage-thresholds.json.tmp coverage-thresholds.json; \
fi; \
echo " PASS [$$SRC_KEY]"; \
done; \
echo ""; \
echo "==> All .NET test projects passed coverage thresholds."
_lint_dotnet:
dotnet build DataProvider.sln --configuration Release
dotnet csharpier check .
_fmt_dotnet:
dotnet csharpier format .
_fmt_check_dotnet:
dotnet csharpier check .
_clean_dotnet:
ifeq ($(OS),Windows_NT)
Get-ChildItem -Recurse -Directory -Include bin,obj -Exclude lql-lsp-rust | Remove-Item -Recurse -Force
$(RM) TestResults
else
find . -type d \( -name bin -o -name obj \) -not -path './Lql/lql-lsp-rust/*' | xargs rm -rf
$(RM) TestResults
endif
_coverage_dotnet:
$(MAKE) _test_dotnet
reportgenerator -reports:"**/TestResults/**/coverage.cobertura.xml" \
-targetdir:coverage/html -reporttypes:Html
ifeq ($(OS),Windows_NT)
Start-Process coverage/html/index.html
else ifeq ($(shell uname -s),Darwin)
open coverage/html/index.html
else
xdg-open coverage/html/index.html
endif
_setup_dotnet:
dotnet restore
dotnet tool restore
# --- RUST (LQL LSP) ---
_build_rust:
cd Lql/lql-lsp-rust && cargo build --release
_test_rust:
@THRESHOLD=$$(jq -r '.projects["Lql/lql-lsp-rust"].threshold // .default_threshold' coverage-thresholds.json); \
echo ""; \
echo "============================================================"; \
echo "==> Testing Lql/lql-lsp-rust (threshold: $$THRESHOLD%)"; \
echo "============================================================"; \
cd Lql/lql-lsp-rust && cargo tarpaulin --workspace --skip-clean \
--exclude-files 'crates/lql-parser/src/generated/*' \
--exclude-files 'crates/lql-lsp/tests/*' \
2>&1 | tee /tmp/_dp_tarpaulin_out.txt; \
TARP_EXIT=$${PIPESTATUS[0]}; \
if [ $$TARP_EXIT -ne 0 ]; then \
echo "FAIL [Lql/lql-lsp-rust]: cargo tarpaulin failed"; \
exit 1; \
fi; \
COVERAGE=$$(grep -oE '[0-9]+\.[0-9]+% coverage' /tmp/_dp_tarpaulin_out.txt | tail -1 | grep -oE '[0-9]+\.[0-9]+'); \
if [ -z "$$COVERAGE" ]; then \
echo "FAIL [Lql/lql-lsp-rust]: Could not parse coverage from tarpaulin output"; \
exit 1; \
fi; \
echo ""; \
echo " [Lql/lql-lsp-rust] Coverage: $$COVERAGE% | Threshold: $$THRESHOLD%"; \
BELOW=$$(echo "$$COVERAGE < $$THRESHOLD" | bc -l); \
if [ "$$BELOW" = "1" ]; then \
echo " FAIL [Lql/lql-lsp-rust]: $$COVERAGE% is BELOW threshold $$THRESHOLD%"; \
exit 1; \
fi; \
ABOVE=$$(echo "$$COVERAGE > $$THRESHOLD" | bc -l); \
if [ "$$ABOVE" = "1" ]; then \
NEW=$$(echo "$$COVERAGE" | awk '{print int($$1)}'); \
echo " Ratcheting threshold: $$THRESHOLD% -> $$NEW%"; \
cd "$(CURDIR)" && jq '.projects["Lql/lql-lsp-rust"].threshold = '"$$NEW" coverage-thresholds.json > coverage-thresholds.json.tmp && mv coverage-thresholds.json.tmp coverage-thresholds.json; \
fi; \
echo " PASS [Lql/lql-lsp-rust]"
_lint_rust:
cd Lql/lql-lsp-rust && cargo fmt --all --check
cd Lql/lql-lsp-rust && cargo clippy --workspace --all-targets -- -D warnings
_fmt_rust:
cd Lql/lql-lsp-rust && cargo fmt --all
_fmt_check_rust:
cd Lql/lql-lsp-rust && cargo fmt --all --check
_clean_rust:
cd Lql/lql-lsp-rust && cargo clean
# --- TYPESCRIPT (LQL Extension) ---
_build_ts:
cd Lql/LqlExtension && npm install --no-audit --no-fund && npm run compile
# Ensure the lql-lsp binary exists before running VSIX tests, so the
# extension can find a matching --version on PATH and start the LSP
# without trying to download a release from GitHub.
_ensure_lql_lsp_on_path:
@if [ ! -x "$(CURDIR)/Lql/lql-lsp-rust/target/release/lql-lsp" ] && \
[ ! -x "$(CURDIR)/Lql/lql-lsp-rust/target/debug/lql-lsp" ]; then \
echo "==> Building lql-lsp (release) for VSIX tests"; \
cd Lql/lql-lsp-rust && cargo build --release -p lql-lsp; \
fi
_test_ts: _ensure_lql_lsp_on_path
@THRESHOLD=$$(jq -r '.projects["Lql/LqlExtension"].threshold // .default_threshold' coverage-thresholds.json); \
echo ""; \
echo "============================================================"; \
echo "==> Testing Lql/LqlExtension (threshold: $$THRESHOLD%)"; \
echo "============================================================"; \
export PATH="$(CURDIR)/Lql/lql-lsp-rust/target/release:$(CURDIR)/Lql/lql-lsp-rust/target/debug:$$PATH"; \
unset ELECTRON_RUN_AS_NODE; \
echo " lql-lsp on PATH: $$(command -v lql-lsp || echo 'NOT FOUND')"; \
echo " lql-lsp --version: $$(lql-lsp --version 2>&1 || echo 'failed')"; \
cd Lql/LqlExtension && \
npx vsce package --no-git-tag-version --no-update-package-json && \
rm -rf out-cov && npx nyc instrument --include='out/**/*.js' --exclude='out/test/**' --no-all out out-cov && cp -R out-cov/. out/ && rm -rf out-cov && \
if command -v xvfb-run >/dev/null 2>&1; then \
xvfb-run -a node ./out/test/runTest.js; \
else \
node ./out/test/runTest.js; \
fi && \
npx nyc report --reporter=json-summary --reporter=text; \
if [ $$? -ne 0 ]; then \
echo "FAIL [Lql/LqlExtension]: Extension tests failed"; \
exit 1; \
fi; \
SUMMARY="$(CURDIR)/Lql/LqlExtension/coverage/coverage-summary.json"; \
if [ ! -f "$$SUMMARY" ]; then \
SUMMARY="$(CURDIR)/Lql/LqlExtension/.nyc_output/coverage-summary.json"; \
fi; \
if [ ! -f "$$SUMMARY" ]; then \
echo " WARN [Lql/LqlExtension]: No coverage summary produced (cross-process instrumentation skipped); treating as 0%"; \
COVERAGE=0; \
else \
COVERAGE=$$(jq -r '.total.lines.pct' "$$SUMMARY"); \
fi; \
echo ""; \
echo " [Lql/LqlExtension] Coverage: $$COVERAGE% | Threshold: $$THRESHOLD%"; \
BELOW=$$(echo "$$COVERAGE < $$THRESHOLD" | bc -l); \
if [ "$$BELOW" = "1" ]; then \
echo " FAIL [Lql/LqlExtension]: $$COVERAGE% is BELOW threshold $$THRESHOLD%"; \
exit 1; \
fi; \
ABOVE=$$(echo "$$COVERAGE > $$THRESHOLD" | bc -l); \
if [ "$$ABOVE" = "1" ]; then \
NEW=$$(echo "$$COVERAGE" | awk '{print int($$1)}'); \
echo " Ratcheting threshold: $$THRESHOLD% -> $$NEW%"; \
jq '.projects["Lql/LqlExtension"].threshold = '"$$NEW" "$(CURDIR)/coverage-thresholds.json" > "$(CURDIR)/coverage-thresholds.json.tmp" && mv "$(CURDIR)/coverage-thresholds.json.tmp" "$(CURDIR)/coverage-thresholds.json"; \
fi; \
echo " PASS [Lql/LqlExtension]"
_lint_ts:
cd Lql/LqlExtension && npm run lint
_clean_ts:
$(RM) Lql/LqlExtension/node_modules Lql/LqlExtension/out
_setup_ts:
cd Lql/LqlExtension && npm install --no-audit --no-fund
# =============================================================================
# HELP
# =============================================================================
help:
@echo "Standard targets (portfolio-wide):"
@echo " build - Compile/assemble all artifacts"
@echo " test - Fail-fast tests + coverage + threshold enforcement"
@echo " lint - Run all linters/analyzers (read-only)"
@echo " fmt - Format all code in-place (CHECK=1 for read-only verify)"
@echo " clean - Remove build artifacts"
@echo " ci - lint + test + build (full CI simulation)"
@echo " setup - Post-create dev environment setup"
@echo ""
@echo "Repo-specific targets:"
@echo " check - lint + test (pre-commit shortcut)"
@echo " coverage - Generate and open HTML coverage report"
@echo " vsix - Build LSP + compile & package VS Code extension (.vsix)"