-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
294 lines (240 loc) · 9.42 KB
/
Copy pathMakefile
File metadata and controls
294 lines (240 loc) · 9.42 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
# Use qvm to manage quarto
QUARTO_VERSION ?= 1.8.27
QUARTO_PATH = ~/.local/share/qvm/versions/v${QUARTO_VERSION}/bin/quarto
PATH_PKG_R := pkg-r
PATH_PKG_PY := pkg-py
PATH_PKG_JS := pkg-js
.PHONY: install-quarto
install-quarto:
@echo "🔵 Installing quarto"
@if [ -z "$$(command -v qvm)" ]; then \
echo "Error: qvm is not installed. Please visit https://github.com/dpastoor/qvm/releases/ to install it." >&2; \
exit 1; \
fi
qvm install v${QUARTO_VERSION}
@echo "🔹 Updating .vscode/settings.json"
@awk -v path="${QUARTO_PATH}" '/"quarto.path":/ {gsub(/"quarto.path": ".*"/, "\"quarto.path\": \"" path "\"")} 1' .vscode/settings.json > .vscode/settings.json.tmp && mv .vscode/settings.json.tmp .vscode/settings.json
@echo "🔹 Updating .github/workflows/website-py.yaml"
@awk -v ver="${QUARTO_VERSION}" '/QUARTO_VERSION:/ {gsub(/QUARTO_VERSION: .*/, "QUARTO_VERSION: " ver)} 1' .github/workflows/website-py.yaml > .github/workflows/website-py.yaml.tmp && mv .github/workflows/website-py.yaml.tmp .github/workflows/website-py.yaml
.PHONY: docs
docs: r-docs-render py-docs-render ## [docs] Build the documentation
.PHONY: docs-preview
docs-preview: ## [docs] Preview the documentation
@npx http-server docs -p 8080
.PHONY: js-setup
js-setup: ## [js] Install JS dependencies
@echo "🆙 Setup JS dependencies"
cd $(PATH_PKG_JS) && npm install
.PHONY: js-setup-ci
js-setup-ci: ## [js] Install JS dependencies as CI
@echo "🆙 Setup JS dependencies"
cd $(PATH_PKG_JS) && npm ci
.PHONY: js-lint
js-lint: ## [js] Lint JS code
@echo "📐 Linting JS code"
cd $(PATH_PKG_JS) && npm run lint
.PHONY: js-build
js-build: ## [js] Build JS code
@echo "🧳 Building JS code"
cd $(PATH_PKG_JS) && npm run build
.PHONY: js-build-watch
js-build-watch: ## [js] Build JS code in watch mode
@echo "🧳 Building JS code in watch mode"
cd $(PATH_PKG_JS) && npm run watch
.PHONY: js-test
js-test: ## [js] Run JS tests
@echo "🧪 Running JS tests"
cd $(PATH_PKG_JS) && npm test
.PHONY: update-dist
update-dist: js-build r-update-dist py-update-dist ## Update shinyreact web assets in all packages
# Skills that ship inside the installed packages, so an app author who only
# `pip install shinyreact` / `install.packages("shinyreact")` gets them too.
# `audit-shinyreact-features` is deliberately not in this list — it audits this
# repo and is meaningless outside it.
SHIPPED_SKILLS := shinyreact-build-app shinyreact-convert-app
.PHONY: update-skills
update-skills: ## Copy .claude/skills/ into pkg-py and pkg-r for shipping
@echo ""
@echo "🔄 Updating shipped skills"
rm -rf $(PATH_PKG_PY)/src/shinyreact/.agents/skills $(PATH_PKG_R)/inst/skills
mkdir -p $(PATH_PKG_PY)/src/shinyreact/.agents/skills $(PATH_PKG_R)/inst/skills
for s in $(SHIPPED_SKILLS); do \
cp -R .claude/skills/$$s $(PATH_PKG_PY)/src/shinyreact/.agents/skills/; \
cp -R .claude/skills/$$s $(PATH_PKG_R)/inst/skills/; \
done
.PHONY: r-setup
r-setup: ## [r] Install R dependencies
@echo "🆙 Updating R dependencies"
cd $(PATH_PKG_R) && Rscript -e "pak::local_install_dev_deps()"
.PHONY: r-check
r-check: r-check-format r-check-tests r-check-package ## [r] All R checks
.PHONY: r-document
r-document: ## [r] Document package
@echo "📜 Documenting R package"
cd $(PATH_PKG_R) && Rscript -e "devtools::document()"
.PHONY: r-format
r-format: ## [r] Format R code
air format $(PATH_PKG_R)/
.PHONY: r-check-package
r-check-package: ## [r] Check package (fails on NOTEs)
@echo ""
@echo "🔄 Running R CMD Check"
# `error_on = "note"` — the package is NOTE-free, so keep it that way. A NOTE is
# how R CMD check reports the things that bite later (undeclared imports, `:::`
# on another package's internals, stale docs); letting them accumulate is what
# made #182-#186 possible. If a NOTE is genuinely acceptable, fix the cause or
# record why in the PR rather than lowering this to "warning".
cd $(PATH_PKG_R) && Rscript -e "devtools::check(document = FALSE, error_on = \"note\")"
.PHONY: r-check-tests
r-check-tests: ## [r] Check tests
@echo ""
@echo "🧪 Running R tests"
cd $(PATH_PKG_R) && Rscript -e "devtools::test()"
.PHONY: r-check-format
r-check-format: ## [r] Check format
@echo ""
@echo "📐 Checking R format"
air format --check $(PATH_PKG_R)/
.PHONY: r-update-dist
r-update-dist: ## [r] Update shinyreact web assets
@echo ""
@echo "🔄 Updating shinyreact web assets"
if [ -d $(PATH_PKG_R)/inst/lib/shiny ]; then \
rm -rf $(PATH_PKG_R)/inst/lib/shiny; \
fi
mkdir -p $(PATH_PKG_R)/inst/lib/shiny
cp $(PATH_PKG_JS)/dist/shinyreact.js $(PATH_PKG_R)/inst/lib/shiny/
cp $(PATH_PKG_JS)/dist/shinyreact.css $(PATH_PKG_R)/inst/lib/shiny/
.PHONY: r-docs-render
r-docs-render: ## [r] Build R docs
@echo "📖 Rendering R docs with pkgdown"
cd $(PATH_PKG_R) && Rscript -e "pkgdown::build_site()"
.PHONY: r-docs-preview
r-docs-preview: ## [r] Preview R docs
@echo "📖 Previewing R docs with pkgdown"
cd $(PATH_PKG_R) && Rscript -e "pkgdown::preview_site()"
.PHONY: py-setup
py-setup: ## [py] Setup python environment
uv sync --all-extras --all-groups --upgrade
.PHONY: py-check
py-check: py-check-format py-check-types py-check-tests ## [py] Run python checks
.PHONY: py-check-tox
py-check-tox: ## [py] Run python checks across versions with tox
@echo ""
@echo "🔄 Running tests and type checking with tox for Python 3.10--3.14"
uv run tox run-parallel
.PHONY: py-check-tests
py-check-tests: ## [py] Run python tests
@echo ""
@echo "🧪 Running tests with pytest"
uv run pytest
.PHONY: py-check-types
py-check-types: ## [py] Run python type checks
@echo ""
@echo "📝 Checking types with pyright"
uv run pyright
.PHONY: py-check-format
py-check-format: ## [py] Check python formatting
@echo ""
@echo "📐 Checking format with ruff"
uv run ruff check pkg-py --config pyproject.toml
.PHONY: py-format
py-format: ## [py] Format python code
uv run ruff check --fix pkg-py --config pyproject.toml
uv run ruff format pkg-py --config pyproject.toml
.PHONY: py-install-e2e
py-install-e2e: ## [py] Install Playwright browsers for e2e tests
@echo "🆙 Installing Playwright browsers"
uv sync --group tests-e2e
uv run playwright install --with-deps chromium
.PHONY: py-test-e2e
py-test-e2e: ## [py] Run Playwright e2e tests (chromium)
@echo "🧪 Running Playwright e2e tests"
uv run pytest pkg-py/tests/playwright \
--browser chromium \
--tracing=retain-on-failure \
--screenshot=only-on-failure \
-o addopts= \
-v
.PHONY: py-coverage
py-coverage: ## [py] Generate coverage report
@echo "📔 Generating coverage report"
uv run coverage run -m pytest
uv run coverage report
.PHONY: py-coverage-report
py-coverage-report: py-coverage ## [py] Generate coverage report and open it in browser
uv run coverage html
@echo ""
@echo "📡 Serving coverage report at http://localhost:8081/"
@npx http-server htmlcov --silent -p 8081
.PHONY: py-update-snaps
py-update-snaps: ## [py] Update python test snapshots
@echo "📸 Updating pytest snapshots"
uv run pytest --snapshot-update
.PHONY: py-docs
py-docs: py-docs-api py-docs-render ## [py] Build python docs
.PHONY: py-docs-render
py-docs-render: ## [py] Render python docs
@echo "📖 Rendering python docs with quarto"
@$(eval export IN_QUARTODOC=true)
${QUARTO_PATH} render pkg-py/docs
.PHONY: py-docs-preview
py-docs-preview: ## [py] Preview python docs
@echo "📖 Rendering python docs with quarto"
@$(eval export IN_QUARTODOC=true)
${QUARTO_PATH} preview pkg-py/docs
.PHONY: py-docs-api
py-docs-api: ## [py] Update python API docs
@echo "📖 Generating python docs with quartodoc"
@$(eval export IN_QUARTODOC=true)
cd pkg-py/docs && uv run quartodoc build
cd pkg-py/docs && uv run quartodoc interlinks
.PHONY: py-docs-api-watch
py-docs-api-watch: ## [py] Update python docs
@echo "📖 Generating python docs with quartodoc"
@$(eval export IN_QUARTODOC=true)
uv run quartodoc build --config pkg-py/docs/_quarto.yml --watch
.PHONY: py-docs-clean
py-docs-clean: ## [py] Clean python docs
@echo "🧹 Cleaning python docs"
rm -r pkg-py/docs/api
find pkg-py/docs/py -name '*.quarto_ipynb' -delete
.PHONY: py-build
py-build: ## [py] Build python package
@echo "🧳 Building python package"
@[ -d dist ] && rm -r dist || true
uv build
.PHONY: py-update-dist
py-update-dist: ## [py] Update shinyreact web assets
@echo ""
@echo "🔄 Updating shinyreact web assets"
if [ -d $(PATH_PKG_PY)/src/shinyreact/www ]; then \
rm -rf $(PATH_PKG_PY)/src/shinyreact/www; \
fi
mkdir -p $(PATH_PKG_PY)/src/shinyreact/www
cp $(PATH_PKG_JS)/dist/shinyreact.js $(PATH_PKG_PY)/src/shinyreact/www/
cp $(PATH_PKG_JS)/dist/shinyreact.css $(PATH_PKG_PY)/src/shinyreact/www/
.PHONY: pre-commit-setup
pre-commit-setup: ## Setup pre-commit hooks
uv run pre-commit install
.PHONY: setup
setup: py-setup js-setup pre-commit-setup ## Setup development environment
.PHONY: ai-setup
ai-setup: setup ## Setup environment for AI agents
.PHONY: help
help: ## Show help messages for make targets
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; { \
printf "\033[32m%-18s\033[0m", $$1; \
if ($$2 ~ /^\[docs\]/) { \
printf "\033[37m[docs]\033[0m%s\n", substr($$2, 7); \
} else if ($$2 ~ /^\[py\]/) { \
printf " \033[31m[py]\033[0m%s\n", substr($$2, 5); \
} else if ($$2 ~ /^\[r\]/) { \
printf " \033[34m[r]\033[0m%s\n", substr($$2, 4); \
} else if ($$2 ~ /^\[js\]/) { \
printf " \033[33m[js]\033[0m%s\n", substr($$2, 5); \
} else { \
printf " %s\n", $$2; \
} \
}'
.DEFAULT_GOAL := help