|
| 1 | +# Global settings |
| 2 | +set shell := ["bash", "-eu", "-o", "pipefail", "-c"] |
| 3 | +set unstable := true |
| 4 | + |
| 5 | +# Tooling knobs (overridable via env) |
| 6 | +TT := env_var_or_default("TT", "tt") |
| 7 | +TT_JOBS := env_var_or_default("TT_JOBS", "4") |
| 8 | +TYPST := env_var_or_default("TYPST", "typst") |
| 9 | +TYPSTYLE := env_var_or_default("TYPSTYLE", "typstyle") |
| 10 | + |
| 11 | +# Paths |
| 12 | +THUMB_SRC := "tests/demo/test.typ" |
| 13 | +THUMB_OUT := "thumbnail.png" |
| 14 | +THEME_SRC := "tests/theme-gallery/test.typ" |
| 15 | +THEME_OUT := "themeshots.png" |
| 16 | +DEMO_SRC := "tests/demo/test.typ" |
| 17 | +DEMO_OUT := "build/demo.pdf" |
| 18 | + |
| 19 | +# Aliases |
| 20 | +alias c := check |
| 21 | +alias f := fmt |
| 22 | +alias t := test |
| 23 | +alias w := watch |
| 24 | + |
| 25 | +# Default entrypoint |
| 26 | +[default] |
| 27 | +help: |
| 28 | + @just --list --unsorted |
| 29 | + |
| 30 | +# ---------------------------- CI / quality ---------------------------- |
| 31 | + |
| 32 | +# Format all Typst files |
| 33 | +[group('ci')] |
| 34 | +fmt: |
| 35 | + rg --files -g '*.typ' | xargs -r {{TYPSTYLE}} --inplace |
| 36 | + |
| 37 | +# Check formatting without modifying files |
| 38 | +[group('ci')] |
| 39 | +fmt-check: |
| 40 | + rg --files -g '*.typ' | xargs -r {{TYPSTYLE}} --check |
| 41 | + |
| 42 | +# Run all quality checks |
| 43 | +[group('ci')] |
| 44 | +check: fmt-check test |
| 45 | + |
| 46 | +# Run tests with optional arguments |
| 47 | +[group('ci')] |
| 48 | +test *args: |
| 49 | + {{TT}} run --jobs {{TT_JOBS}} {{args}} |
| 50 | + |
| 51 | +# Accept test outputs as new references |
| 52 | +[group('ci')] |
| 53 | +accept *args: |
| 54 | + {{TT}} accept {{args}} |
| 55 | + |
| 56 | +# ---------------------------- Dev UX ---------------------------- |
| 57 | + |
| 58 | +# Watch for changes and run tests automatically |
| 59 | +[group('dev')] |
| 60 | +watch *args: |
| 61 | + watchexec \ |
| 62 | + --watch . \ |
| 63 | + --clear \ |
| 64 | + --delay-run 5s \ |
| 65 | + --ignore 'tests/**/diff/**' \ |
| 66 | + --ignore 'tests/**/out/**' \ |
| 67 | + --ignore 'tests/**/ref/**' \ |
| 68 | + "{{TT}} run --jobs {{TT_JOBS}} {{args}}" |
| 69 | + |
| 70 | +# ---------------------------- Artifacts ---------------------------- |
| 71 | + |
| 72 | +# Build demo.typ -> demo.pdf |
| 73 | +[group('artifacts')] |
| 74 | +demo: |
| 75 | + mkdir -p "$(dirname {{DEMO_OUT}})" |
| 76 | + {{TYPST}} compile --root . {{DEMO_SRC}} {{DEMO_OUT}} |
| 77 | + @echo "Wrote {{DEMO_OUT}}" |
| 78 | + |
| 79 | +# Build all preview images |
| 80 | +# Build all preview images |
| 81 | +[group('artifacts')] |
| 82 | +images: |
| 83 | + {{TT}} run theme-gallery && cp tests/theme-gallery/out/*.png {{THEME_OUT}} |
| 84 | + {{TT}} run demo && cp tests/demo/out/*.png {{THUMB_OUT}} |
| 85 | + |
| 86 | +# ---------------------------- Housekeeping ---------------------------- |
| 87 | + |
| 88 | +# Remove all generated test files and build artifacts |
| 89 | +[group('housekeeping')] |
| 90 | +clean: |
| 91 | + rg --files tests -g '**/diff/**' -g '**/out/**' 2>/dev/null \ |
| 92 | + | xargs -r dirname \ |
| 93 | + | sort -u \ |
| 94 | + | xargs -r bash -c 'for d; do echo "Removing files under: $d"; rm -rf -- "$d"/*; done' _ \ |
| 95 | + || true |
| 96 | + rm -rf build |
| 97 | + |
| 98 | +# ---------------------------- Release tooling ---------------------------- |
| 99 | + |
| 100 | +# Bump version by level (major|minor|patch) or to explicit version |
| 101 | +[group('release')] |
| 102 | +[script("python3")] |
| 103 | +bump version_or_level: |
| 104 | + import re |
| 105 | + from pathlib import Path |
| 106 | + |
| 107 | + arg = "{{version_or_level}}".strip() |
| 108 | + if not arg: |
| 109 | + raise SystemExit("Usage: just bump <major|minor|patch|x.y.z>") |
| 110 | + |
| 111 | + # If it's a level keyword, calculate the new version |
| 112 | + if arg.lower() in {"major", "minor", "patch"}: |
| 113 | + level = arg.lower() |
| 114 | + data = Path("typst.toml").read_text() |
| 115 | + m = re.search(r'^version\s*=\s*"([^"]+)"', data, re.MULTILINE) |
| 116 | + if not m: |
| 117 | + raise SystemExit("Could not find current version in typst.toml") |
| 118 | + |
| 119 | + major, minor, patch = map(int, m.group(1).split(".")) |
| 120 | + old_version = m.group(1) |
| 121 | + |
| 122 | + if level == "major": |
| 123 | + major, minor, patch = major + 1, 0, 0 |
| 124 | + elif level == "minor": |
| 125 | + major, minor, patch = major, minor + 1, 0 |
| 126 | + else: |
| 127 | + patch += 1 |
| 128 | + |
| 129 | + version = f"{major}.{minor}.{patch}" |
| 130 | + print(f"Bumping {level} version: {old_version} → {version}") |
| 131 | + else: |
| 132 | + # It's an explicit version |
| 133 | + version = arg |
| 134 | + print(f"Setting version to {version}") |
| 135 | + |
| 136 | + # Update files |
| 137 | + def update(path: Path, pattern: re.Pattern): |
| 138 | + text = path.read_text() |
| 139 | + new_text, count = pattern.subn(lambda m: m.group(1) + version + m.group(3), text, count=1) |
| 140 | + if count == 0: |
| 141 | + raise SystemExit(f"Failed to update {path}") |
| 142 | + path.write_text(new_text) |
| 143 | + |
| 144 | + update(Path("typst.toml"), re.compile(r'^(version\s*=\s*")([^"]+)(")', re.MULTILINE)) |
| 145 | + update(Path("README.md"), re.compile(r'(#import "@preview/glossy:)([^"]+)(": \*)')) |
| 146 | + print(f"Updated typst.toml and README.md") |
| 147 | + |
| 148 | + |
| 149 | +# Run full pre-submission checks |
| 150 | +[group('release')] |
| 151 | +pre-submit: clean images check |
0 commit comments