Skip to content

Commit b3acefe

Browse files
authored
feat(build-and-docs) quick -webtest branch (#4008)
and a script to quickly build the website locally from the .json that is served by the current website without running verso
1 parent 5fb97cb commit b3acefe

3 files changed

Lines changed: 272 additions & 43 deletions

File tree

.github/workflows/build-and-docs.yml

Lines changed: 95 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,14 @@ on:
1818
push:
1919
branches:
2020
- main
21+
- '*-webtest'
2122
pull_request:
23+
workflow_dispatch:
24+
inputs:
25+
website_only:
26+
description: 'Skip Lean build and use live site data (for website development)'
27+
type: boolean
28+
default: false
2229

2330
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
2431
permissions:
@@ -37,14 +44,31 @@ jobs:
3744
with:
3845
fetch-depth: 0
3946

47+
# Detect whether this is a website-only build (skip slow Lean compilation).
48+
# Triggers:
49+
# - Branches ending in -webtest
50+
# - Manual workflow_dispatch with website_only=true
51+
- name: Detect build mode
52+
id: mode
53+
run: |
54+
if [[ "${{ inputs.website_only }}" == "true" ]] || \
55+
[[ "${{ github.ref_name }}" == *-webtest ]]; then
56+
echo "website_only=true" >> "$GITHUB_OUTPUT"
57+
echo "::notice::Website-only build: skipping Lean compilation, downloading data from live site."
58+
else
59+
echo "website_only=false" >> "$GITHUB_OUTPUT"
60+
fi
61+
4062
- name: Install elan
63+
if: steps.mode.outputs.website_only != 'true'
4164
run: |
4265
set -o pipefail
4366
curl -sSfL https://github.com/leanprover/elan/releases/download/v1.4.2/elan-x86_64-unknown-linux-gnu.tar.gz | tar xz
4467
./elan-init -y --default-toolchain none
4568
echo "$HOME/.elan/bin" >> $GITHUB_PATH
4669
4770
- name: Generate All.lean
71+
if: steps.mode.outputs.website_only != 'true'
4872
run: |
4973
lake exe mk_all --lib FormalConjectures || true
5074
# Avoid including Test files from `Util/` to avoid inflating the
@@ -53,6 +77,7 @@ jobs:
5377
grep -v "FormalConjectures\.Util\." FormalConjectures.lean > FormalConjectures/All.lean
5478
5579
- name: Restore ~/.cache/mathlib
80+
if: steps.mode.outputs.website_only != 'true'
5681
uses: actions/cache/restore@v3
5782
with:
5883
path: ~/.cache/mathlib
@@ -62,15 +87,18 @@ jobs:
6287
oleans-
6388
6489
- name: Get olean cache
90+
if: steps.mode.outputs.website_only != 'true'
6591
run: |
6692
lake exe cache unpack
6793
lake exe cache get
6894
6995
- name: Build project
96+
if: steps.mode.outputs.website_only != 'true'
7097
run: |
7198
lake --wfail build
7299
73100
- name: Build literate source pages
101+
if: steps.mode.outputs.website_only != 'true'
74102
run: |
75103
cd docbuild
76104
# Some modules crash verso-literate (e.g. metaprogramming-heavy util files),
@@ -82,27 +110,32 @@ jobs:
82110
lake exe verso-html .lake/build/literate ../_literate_html || true
83111
84112
- name: Post-process literate HTML
113+
if: steps.mode.outputs.website_only != 'true'
85114
run: |
86115
python3 site/fix_literate_html.py _literate_html
87116
88117
- name: Pack olean cache
118+
if: steps.mode.outputs.website_only != 'true'
89119
run: |
90120
lake exe cache pack
91121
ls ~/.cache/mathlib
92122
93123
- name: Save ~/.cache/mathlib
124+
if: steps.mode.outputs.website_only != 'true'
94125
uses: actions/cache/save@v3
95126
with:
96127
path: ~/.cache
97128
key: oleans-${{ hashFiles('lake-manifest.json') }}-${{ hashFiles('**/*.lean') }}
98129

99130
- name: Prepare documentation
131+
if: steps.mode.outputs.website_only != 'true'
100132
run: |
101133
cd docbuild
102134
export MATHLIB_NO_CACHE_ON_UPDATE=1 # avoids "Failed to prune ProofWidgets cloud release: no such file or directory"
103135
lake update formal_conjectures
104136
105137
- name: Cache documentation
138+
if: steps.mode.outputs.website_only != 'true'
106139
uses: actions/cache@v5
107140
with:
108141
path: docbuild/.lake/build/doc
@@ -112,11 +145,13 @@ jobs:
112145
MathlibDoc-
113146
114147
- name: Build documentation
148+
if: steps.mode.outputs.website_only != 'true'
115149
run: |
116150
cd docbuild
117151
lake build FormalConjectures:docs
118152
119153
- name: Extract documentation
154+
if: steps.mode.outputs.website_only != 'true'
120155
run: |
121156
cd docbuild
122157
mkdir out
@@ -128,20 +163,24 @@ jobs:
128163
rsync -a --files-from=out-files.txt --relative .lake/build/doc ./out
129164
130165
- name: Set up Python
166+
if: steps.mode.outputs.website_only != 'true'
131167
uses: actions/setup-python@v6
132168
with:
133169
python-version: '3.12.9'
134170

135171
- name: Install Python dependencies
172+
if: steps.mode.outputs.website_only != 'true'
136173
run: |
137174
python -m pip install --upgrade pip
138175
pip install pandas==2.2.3 numpy==2.2.3 plotly==5.20.0 beautifulsoup4 lxml
139176
140177
- name: Run plotting script
178+
if: steps.mode.outputs.website_only != 'true'
141179
run: |
142180
python docbuild/scripts/plot_growth.py
143181
144182
- name: Inject stats into index.html
183+
if: steps.mode.outputs.website_only != 'true'
145184
shell: bash
146185
run: |
147186
cd docbuild
@@ -153,14 +192,58 @@ jobs:
153192
node-version: '18'
154193

155194
- name: Generate conjectures data for website
195+
if: steps.mode.outputs.website_only != 'true'
156196
run: |
157197
mkdir -p site/data
158198
lake exe extract_names --exclude=statement,docstring,moduleDocstrings > site/data/conjectures.json || true
159199
160200
- name: Extract Verso fragments for website
201+
if: steps.mode.outputs.website_only != 'true'
161202
run: |
162203
python3 site/extract_verso_fragments.py _literate_html site/data/verso-fragments.json
163204
205+
# In website-only mode, download data from the live production site
206+
# instead of building it from scratch. The live site serves the processed
207+
# format ({ conjectures, versoFragments, ... }), so we convert it back to
208+
# the raw extract_names format ({ problems }) that build.js expects.
209+
- name: Download live site data
210+
if: steps.mode.outputs.website_only == 'true'
211+
run: |
212+
LIVE_URL="https://google-deepmind.github.io/formal-conjectures"
213+
mkdir -p site/data _literate_html docbuild/out
214+
echo "Downloading conjectures data from $LIVE_URL ..."
215+
curl -sfL "$LIVE_URL/data/conjectures.json" -o /tmp/live_conjectures.json
216+
node -e "
217+
const fs = require('fs');
218+
const data = JSON.parse(fs.readFileSync('/tmp/live_conjectures.json', 'utf8'));
219+
220+
// Convert processed conjectures back to raw extract_names format
221+
const problems = (data.conjectures || []).map(c => ({
222+
theorem: c.theorem,
223+
module: c.module,
224+
category: c.category,
225+
subjects: (c.subjects || []).map(s =>
226+
typeof s === 'object' ? s.code : s
227+
),
228+
formalProofKind: c.formalProofKind || null,
229+
formalProofLink: c.formalProofLink || null,
230+
hasSorryFreeProof: false,
231+
}));
232+
fs.writeFileSync(
233+
'site/data/conjectures.json',
234+
JSON.stringify({ problems })
235+
);
236+
237+
// Extract Verso fragments if present
238+
if (data.versoFragments) {
239+
fs.writeFileSync(
240+
'site/data/verso-fragments.json',
241+
JSON.stringify(data.versoFragments)
242+
);
243+
}
244+
console.log('Converted ' + problems.length + ' conjectures to raw format.');
245+
"
246+
164247
- name: Build website
165248
run: |
166249
cd site
@@ -174,10 +257,14 @@ jobs:
174257
mkdir -p _deploy
175258
# Website goes at root
176259
cp -r site/site/* _deploy/
177-
# Lean docs go under /doc
178-
cp -r docbuild/out _deploy/doc
179-
# Literate source pages go under /src
180-
cp -r _literate_html _deploy/src
260+
# Lean docs go under /doc (may not exist in website-only mode)
261+
if [[ -d docbuild/out ]]; then
262+
cp -r docbuild/out _deploy/doc
263+
fi
264+
# Literate source pages go under /src (may not exist in website-only mode)
265+
if [[ -d _literate_html ]] && [[ -n "$(ls -A _literate_html 2>/dev/null)" ]]; then
266+
cp -r _literate_html _deploy/src
267+
fi
181268
182269
- name: Upload deploy artifact
183270
id: deployment
@@ -187,7 +274,10 @@ jobs:
187274

188275
# Deployment job
189276
deploy:
190-
if: github.ref == 'refs/heads/main'
277+
if: >-
278+
github.ref == 'refs/heads/main' ||
279+
(github.repository != 'google-deepmind/formal-conjectures' &&
280+
endsWith(github.ref_name, '-webtest'))
191281
environment:
192282
name: github-pages
193283
url: ${{ steps.deployment.outputs.page_url }}

site/README.md

Lines changed: 92 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -72,60 +72,114 @@ Individual theorem pages are rendered client-side from `data/conjectures.json`
7272

7373
## Building locally
7474

75-
**Requirements:** Node.js 18 or later (no npm packages needed).
75+
The quickest way to develop the website locally is using `dev.sh`, which downloads
76+
the conjectures data from the live production site (no Lean build needed):
77+
78+
**Requirements:** Node.js 18+ and Python 3.
7679

7780
```bash
78-
# 1. Clone this repo
79-
git clone https://github.com/<org>/formal-conjectures-website
80-
cd formal-conjectures-website
81+
# Install Node.js if needed (e.g. via conda)
82+
conda install -c conda-forge nodejs
83+
84+
# Build and serve
85+
cd site
86+
./dev.sh # build + serve on http://localhost:8080
87+
./dev.sh --build-only # just build, no server
88+
./dev.sh --port 3000 # serve on a custom port
89+
```
90+
91+
To iterate on templates or styles, re-run `./dev.sh --build-only` after each change
92+
and refresh the browser.
8193

82-
# 2. (Optional) generate conjectures data from the formal-conjectures repo or create a placeholder dataset.
83-
cd path/to/formal-conjectures
94+
### Building with fresh data from a local Lean build
95+
96+
If you need the site to reflect local Lean changes (new conjectures, etc.):
97+
98+
```bash
99+
# In the formal-conjectures repo root
84100
lake exe cache get # download prebuilt Mathlib oleans (first time only)
85101
lake build
86-
lake exe extract_names > path/to/formal-conjectures-website/data/conjectures.json
87-
cd path/to/formal-conjectures-website
88-
89-
# 3. Build the site
102+
mkdir -p site/data
103+
lake exe extract_names --exclude=statement,docstring,moduleDocstrings > site/data/conjectures.json
104+
105+
# (Optional) Generate Verso literate fragments for rendered docstrings.
106+
# Without this, theorem detail pages will lack formatted docstrings and source links.
107+
# Warning: the literate build step can take a long time (30+ minutes).
108+
cd docbuild
109+
lake build FormalConjectures:literate || true
110+
find .lake/build/literate -name "*.json" -empty -delete 2>/dev/null || true
111+
lake exe verso-html .lake/build/literate ../_literate_html || true
112+
cd ..
113+
python3 site/fix_literate_html.py _literate_html
114+
python3 site/extract_verso_fragments.py _literate_html site/data/verso-fragments.json
115+
116+
# Build the site
117+
cd site
90118
node build.js # output goes to site/
91119

92-
# 4. Serve locally
120+
# Serve locally
93121
python3 -m http.server 8080 --directory site
94-
# then open http://localhost:8080
95-
96-
# Alternative: serve with uv (no Python installation required)
97-
uv run --no-project python -m http.server 8080 --directory site
98122
```
99123

100-
To iterate on templates or styles, re-run `node build.js` after each change and refresh the browser. There is no watch mode, but Node's built-in `--watch` flag works:
124+
## Developing on a fork (sharing a live preview)
125+
126+
To share a live preview of your website changes with others, you can deploy from
127+
a **`*-webtest`** branch on your GitHub fork. The CI workflow detects this naming
128+
convention and **skips the slow Lean build**, downloading data from the live
129+
production site instead.
130+
131+
### One-time fork setup
132+
133+
1. **Fork** the repository on GitHub.
134+
135+
2. **Enable GitHub Pages:**
136+
- Go to your fork's **Settings → Pages**
137+
- Set **Source** to **GitHub Actions**
138+
139+
3. **Allow webtest branches to deploy:**
140+
- Go to **Settings → Environments → `github-pages`**
141+
- Under **Deployment branches and tags**, click **Add deployment branch or tag rule**
142+
- Add the pattern **`*-webtest`**
143+
- Save
144+
145+
### Development workflow
101146

102147
```bash
103-
node --watch build.js
104-
```
148+
# Create a webtest branch from main
149+
git checkout -b my-feature-webtest origin/main
105150

106-
## Using a placeholder dataset for UI development
107-
108-
If you don't have the formal-conjectures repo built locally, you can populate `data/conjectures.json` with a small synthetic dataset for UI testing. The expected JSON format is an array of objects:
109-
110-
```json
111-
[
112-
{
113-
"theorem": "FormalConjectures.ErdosProblems.1.erdos_1",
114-
"module": "FormalConjectures.ErdosProblems.1",
115-
"category": "research open",
116-
"subjects": ["5", "11"],
117-
"statement": "∃ C > (0 : ℝ), ∀ (N : ℕ) ...",
118-
"docstring": "Erdős Problem 1: ...",
119-
"formalProofKind": null,
120-
"formalProofLink": null
121-
}
122-
]
151+
# Make your website changes (CSS, JS, templates, etc.)
152+
# ...
153+
154+
# Push to your fork — CI builds and deploys automatically
155+
git push <your-fork> my-feature-webtest
123156
```
124157

125-
Valid values for `category`: `"research open"`, `"research solved"`, `"research formally solved"`, `"textbook"`, `"test"`, `"API"`.
158+
Your site will be live at `https://<username>.github.io/formal-conjectures/`
159+
once the Action completes (typically ~2 minutes for a website-only build).
160+
161+
> **Note:** The naming convention `*-webtest` is what triggers the fast
162+
> website-only build. Branches without this suffix run the full Lean build.
163+
164+
> **Note:** GitHub Pages serves one deployment at a time per repo. Deploying
165+
> from a webtest branch replaces what was deployed from `main`. This is fine
166+
> for a fork used for previewing.
167+
168+
126169

127170
## CI / deployment
128171

129-
The GitHub Actions workflow in `.github/workflows/deploy.yml` triggers on any push to `main` that touches `data/conjectures.json`, `src/`, `build.js`, or `package.json`. It runs `node build.js` and deploys the `site/` directory to GitHub Pages using the standard `actions/upload-pages-artifact` + `actions/deploy-pages` actions.
172+
The GitHub Actions workflow in `.github/workflows/build-and-docs.yml` triggers on pushes to `main` and `*-webtest` branches, as well as on pull requests.
173+
174+
**Build modes:**
175+
176+
| Condition | Build mode | What happens |
177+
|-----------|-----------|--------------|
178+
| Push to `main` on upstream | Full build | Lean compilation + docs + website |
179+
| Push to `*-webtest` branch | Website-only | Downloads live data, builds website only (~2 min) |
180+
| Manual `workflow_dispatch` with `website_only=true` | Website-only | Same as above |
181+
| Pull request | Full build | Lean compilation + docs + website (no deploy) |
182+
183+
**Deployment** happens on pushes to `main`, and on `*-webtest` branches when on a fork.
130184

131-
To enable GitHub Pages for this repo, go to **Settings → Pages** and set the source to **GitHub Actions**.
185+
For GitHub Pages setup (including the environment rule needed for `*-webtest` branches), see [One-time fork setup](#one-time-fork-setup) above.

0 commit comments

Comments
 (0)