-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjustfile
More file actions
302 lines (257 loc) · 10 KB
/
Copy pathjustfile
File metadata and controls
302 lines (257 loc) · 10 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
set shell := ["bash", "-euo", "pipefail", "-c"]
set no-exit-message
# `LINT_VERBOSE`: per-tool “Running …” lines (dim) before quiet linters (unset ⇒ auto-on in CI).
# CI / verbosity are pure Just (`~/dev/just/tests/conditional.rs`). `quote` + `\` continuation for bundle assembly.
export LINT_VERBOSE := env('LINT_VERBOSE', '')
ok_msg := '''\033[32m ok\033[0m'''
[private]
_lv := trim(env('LINT_VERBOSE', ''))
# Mirrors the previous Bash CI probe. `\` continuation so `:=` parses (~/dev/just/manual multi-line constructs).
[private]
_is_ci := if env('CI', '') == 'true' { 'yes' } else if env('CI', '') == '1' { 'yes' } else if env('CONTINUOUS_INTEGRATION', '') != '' { 'yes' } else if env('GITHUB_ACTIONS', '') != '' { 'yes' } else if env('GITLAB_CI', '') != '' { 'yes' } else if env('BUILDKITE', '') != '' { 'yes' } else if env('CIRCLECI', '') != '' { 'yes' } else if env('JENKINS_URL', '') != '' { 'yes' } else if env('TRAVIS', '') != '' { 'yes' } else if env('APPVEYOR', '') != '' { 'yes' } else if env('TF_BUILD', '') != '' { 'yes' } else if env('SYSTEM_TEAMFOUNDATIONCOLLECTIONURI', '') != '' { 'yes' } else { '' }
# Empty `LINT_VERBOSE` ⇒ defer to `_is_ci`. Explicit tokens override; unknown nonempty ⇒ never emit “Running…”.
[private]
_show_running := if _lv == '' { if _is_ci == 'yes' { 'yes' } else { '' } } else if _lv == '1' { 'yes' } else if _lv == 'true' { 'yes' } else if _lv == 'TRUE' { 'yes' } else if _lv == 'yes' { 'yes' } else if _lv == 'YES' { 'yes' } else if _lv == 'on' { 'yes' } else if _lv == 'ON' { 'yes' } else if _lv == '0' { '' } else if _lv == 'false' { '' } else if _lv == 'FALSE' { '' } else if _lv == 'no' { '' } else if _lv == 'NO' { '' } else if _lv == 'off' { '' } else if _lv == 'OFF' { '' } else { '' }
[private]
_shell_export := 'export JUST_SHOW_RUNNING=' + quote(_show_running)
[private]
_bash_lint_helpers := '''
JUST_DIM=$'\033[2m'
JUST_GREEN=$'\033[32m'
JUST_RED=$'\033[31m'
JUST_RST=$'\033[0m'
lint_running() {
[[ "${JUST_SHOW_RUNNING:-}" == "yes" ]] || return 0
printf '%s · Running %s%s\n' "$JUST_DIM" "$1" "$JUST_RST" >&2
}
lint_ok() {
printf '%s ok%s %s\n' "$JUST_GREEN" "$JUST_RST" "$1" >&2
}
lint_fail() {
printf '%sFAIL%s %s\n' "$JUST_RED" "$JUST_RST" "$1" >&2
}
# run_quiet NAME CMD [ARGS…] — run quietly; on failure, re-run loud.
run_quiet() {
local _name="$1"; shift
lint_running "$_name"
local _out _code
_out=$("$@" 2>&1) && { lint_ok "$_name"; return 0; }
_code=$?
lint_fail "$_name"
printf '%s\n' "$_out" >&2
return "$_code"
}
run_semgrep() {
lint_running "semgrep"
local _tmp _code
_tmp=$(mktemp) || { echo "semgrep: mktemp failed" >&2; return 1; }
set +e
uv run semgrep scan --config=auto --quiet --emacs --error --disable-version-check src/ 2>"$_tmp"
_code=$?
set -e
if [ -s "$_tmp" ]; then
grep -vE '^[┌│└├].*|^[[:space:]]*Semgrep[[:space:]]+CLI|^[[:space:]]*╭' "$_tmp" | sed '/^[[:space:]]*$/d' >&2 || true
fi
rm -f "$_tmp"
if [ "$_code" -eq 0 ]; then
lint_ok "semgrep"
fi
return "$_code"
}
'''
[private]
_lint_bundle := _shell_export + "\n" + _bash_lint_helpers
[private]
default:
@just --list
# --- Quality ---
# (`[group]` is for `just --list`; it is unrelated to PEP 735 `[dependency-groups]`.)
[doc('Lint tracked Python, shell, docs, spelling (contributor-facing)')]
[group('quality')]
lint: _lint-py _lint-sh _lint-docs _lint-spell
@printf '%b %s\n' "{{ ok_msg }}" "lint" >&2
[group('quality')]
lint-maintainer: _lint-workflows
@printf '%b %s\n' "{{ ok_msg }}" "lint-maintainer" >&2
[doc('`uv sync`, then workflow / security tooling (matches `maintain` PEP 735 deps)')]
[group('quality')]
maintain:
uv sync
@{{ just_executable() }} _lint-workflows
@printf '%b %s\n' "{{ ok_msg }}" "maintain" >&2
[group('quality')]
lint-all: lint lint-maintainer
@printf '%b %s\n' "{{ ok_msg }}" "lint-all" >&2
[group('quality')]
lint-fix: _lint-py-fix _lint-sh-fix _lint-docs-fix
[group('quality')]
test:
uv run pytest
# Run the test suite under coverage. Produces a term-missing report and an
# HTML report at ``htmlcov/index.html`` for drilling into uncovered branches.
# Target: 90% combined coverage. CI's no-regression floor is in ``ci.yml``.
[group('quality')]
test-cov:
#!/usr/bin/env bash
set -euo pipefail
rm -f .coverage .coverage.*
uv run coverage run -m pytest
uv run coverage combine 2>/dev/null || true
uv run coverage report --skip-empty
uv run coverage html --skip-empty --skip-covered
printf '\nHTML report: htmlcov/index.html\n'
# Open the HTML coverage report in the default browser (macOS / Linux).
[group('quality')]
cov-open: test-cov
@command -v open >/dev/null && open htmlcov/index.html || xdg-open htmlcov/index.html
[group('quality')]
check: lint test
[doc('Run the self-benchmark suite under benchmarks/')]
[group('quality')]
bench:
uv run --group bench pytest benchmarks/ \
-o python_files=bench_*.py \
--benchmark-only \
--benchmark-columns=min,mean,median,stddev,ops,rounds
[doc('Run the benchmark suite and save a baseline named ARG (default: HEAD short SHA)')]
[group('quality')]
bench-save name='':
#!/usr/bin/env bash
set -euo pipefail
name="{{ name }}"
if [ -z "$name" ]; then
name=$(git rev-parse --short HEAD)
fi
uv run --group bench pytest benchmarks/ \
-o python_files=bench_*.py \
--benchmark-only \
--benchmark-autosave \
--benchmark-save="$name"
# --- Build ---
[group('build')]
build:
uv build
# --- Release (maintainer) ---
[doc('Prepare a release: PSR stamps version + changelog, creates branch')]
[group('release')]
release-prepare:
#!/usr/bin/env bash
set -euo pipefail
test -z "$(git status --porcelain)" || { echo "error: working tree not clean"; exit 1; }
git fetch origin main
git diff --quiet HEAD..origin/main || { echo "error: not up to date with origin/main"; exit 1; }
version=$(uv run semantic-release version --print 2>/dev/null) \
|| { echo "error: no releasable commits (or not on main)"; exit 1; }
echo "Preparing release v${version}"
git checkout -b "release/v${version}"
uv run semantic-release version --no-commit --no-push --no-tag --no-vcs-release
echo ""
echo "Files stamped. Review CHANGELOG.md, then run:"
echo " git add -A && git commit -m 'chore(release): v${version}'"
echo " git push -u origin HEAD"
echo " gh pr create --title 'chore(release): v${version}'"
[doc('After release PR merges, tag to trigger release CI')]
[group('release')]
release-tag version:
#!/usr/bin/env bash
set -euo pipefail
git checkout main && git pull --ff-only
file_version=$(grep '__version__' src/yarlpattern/_version.py | sed 's/.*"\(.*\)"/\1/')
test "${file_version}" = "{{ version }}" \
|| { echo "error: _version.py says ${file_version}, expected {{ version }}"; exit 1; }
if git tag -l "v{{ version }}" | grep -q .; then
echo "error: tag v{{ version }} already exists"
exit 1
fi
git tag "v{{ version }}"
git push origin "v{{ version }}"
echo "Tag v{{ version }} pushed. Release CI will build and publish."
# --- Docs ---
[doc('Regenerate docs/wpt-compliance.md — full WPT conformance matrix')]
[group('docs')]
compliance-report:
uv run python scripts/generate_compliance_report.py
[doc('Build the documentation site to site/ in strict mode')]
[group('docs')]
docs:
uv run properdocs build --strict
[doc('Serve docs at http://127.0.0.1:8000 with live reload')]
[group('docs')]
docs-serve:
uv run properdocs serve
# --- Dev ---
[group('dev')]
dev: setup test
[group('dev')]
setup:
uv sync --all-groups
git config commit.gpgsign true
[group('dev')]
clean:
uv run pyclean . --debris all
[group('dev')]
renovate-validate:
@uv run check-jsonschema --schemafile "https://docs.renovatebot.com/renovate-schema.json" renovate.json
# --- Private ---
[private]
_lint-py:
#!/usr/bin/env bash
set -euo pipefail
{{ _lint_bundle }}
run_quiet "ruff check" uv run ruff check --quiet .
run_quiet "ruff format" uv run ruff format --quiet --check .
run_quiet "mypy" uv run mypy --no-error-summary src tests scripts
run_quiet "pyright" uv run pyright
run_quiet "ty" uv run ty check --quiet --quiet
run_quiet "validate-pyproject" uv run validate-pyproject pyproject.toml
run_quiet "interrogate" uv run interrogate --quiet src/yarlpattern/
run_semgrep
[private]
_lint-py-fix:
uv run ruff check --fix .
uv run ruff format .
[private]
_lint-sh:
#!/usr/bin/env bash
set -euo pipefail
command -v shellcheck >/dev/null || {
echo 'error: install shellcheck (e.g. brew install shellcheck)' >&2
exit 1
}
{{ _lint_bundle }}
targets=()
while IFS= read -r _f; do
targets+=("$_f")
done < <(git ls-files '*.sh')
(( ${#targets[@]} == 0 )) && exit 0
run_quiet "shellcheck" shellcheck -f quiet -x "${targets[@]}"
[private]
_lint-sh-fix:
@{{ just_executable() }} _lint-sh || (printf '\033[33mNote: shellcheck has no auto-fix mode — review the output above and fix manually.\033[0m\n' >&2 && exit 1)
[private]
_lint-docs:
#!/usr/bin/env bash
set -euo pipefail
{{ _lint_bundle }}
run_quiet "rumdl" uv run rumdl check --quiet .
[private]
_lint-workflows:
#!/usr/bin/env bash
set -euo pipefail
command -v actionlint >/dev/null || {
echo 'error: install actionlint (e.g. brew install actionlint)' >&2
exit 1
}
{{ _lint_bundle }}
run_quiet "actionlint" actionlint -no-color
run_quiet "check-jsonschema (renovate.json)" uv run check-jsonschema --schemafile "https://docs.renovatebot.com/renovate-schema.json" renovate.json
run_quiet "zizmor" uv run zizmor -q .
[private]
_lint-docs-fix:
uv run rumdl fmt .
[private]
_lint-spell:
#!/usr/bin/env bash
set -euo pipefail
{{ _lint_bundle }}
run_quiet "codespell" uv run codespell src tests docs scripts *.md *.toml