Skip to content

Commit 30ccd96

Browse files
authored
Merge pull request #7 from Gecode/codex/astro-cloudflare-migration
Migrate the website to Astro and prepare Cloudflare documentation cutover
2 parents e7f812a + 4730b1c commit 30ccd96

11,986 files changed

Lines changed: 911060 additions & 461665 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/pages.yml‎

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,43 +11,49 @@ permissions:
1111
id-token: write
1212

1313
concurrency:
14-
group: pages
15-
cancel-in-progress: true
14+
group: pages-${{ github.event_name }}-${{ github.ref }}
15+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
1616

1717
jobs:
1818
build:
1919
runs-on: ubuntu-latest
2020
steps:
2121
- name: Checkout
22-
uses: actions/checkout@v4
22+
uses: actions/checkout@v7
2323

2424
- name: Setup Node
25-
uses: actions/setup-node@v4
25+
uses: actions/setup-node@v6
2626
with:
27-
node-version: 20
27+
node-version: 24
2828
cache: npm
2929

30-
- name: Setup Ruby
31-
uses: ruby/setup-ruby@v1
32-
with:
33-
ruby-version: '3.1'
34-
bundler-cache: true
35-
3630
- name: Install Node dependencies
3731
run: npm ci
3832

3933
- name: Check executable bits
4034
run: npm run check:mode
4135

42-
- name: Build site
43-
run: npm run build
36+
- name: Validate documentation hosting tools
37+
run: npm run check:docs-hosting
4438

45-
- name: Verify generated CSS
46-
run: npm run check:css
39+
- name: Build site
40+
run: npm run build:pages
4741

4842
- name: Validate generated HTML
4943
run: npm run check:html
5044

45+
- name: Validate canonical URLs
46+
run: npm run check:canonical-urls
47+
48+
- name: Validate rendered content and metadata
49+
run: npm run check:site-semantics && npm run test:content
50+
51+
- name: Validate classic URL redirects
52+
run: npm run test:redirect-worker && npm run check:redirect-worker
53+
54+
- name: Validate email routing
55+
run: npm run test:email-worker && npm run check:email-worker
56+
5157
- name: Collect active HTML pages
5258
id: active_pages
5359
run: |
@@ -65,6 +71,8 @@ jobs:
6571
with:
6672
args: >-
6773
--verbose --no-progress --offline --exclude-mail
74+
--root-dir '${{ github.workspace }}/_site'
75+
--exclude '^file://.*/_site/doc(-latest)?(/|$)'
6876
${{ steps.active_pages.outputs.pages }}
6977
env:
7078
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -75,6 +83,8 @@ jobs:
7583
with:
7684
args: >-
7785
--verbose --no-progress --exclude-mail
86+
--root-dir '${{ github.workspace }}/_site'
87+
--exclude '^file://.*/_site/doc(-latest)?(/|$)'
7888
${{ steps.active_pages.outputs.pages }}
7989
env:
8090
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -83,12 +93,18 @@ jobs:
8393
uses: actions/configure-pages@v5
8494

8595
- name: Upload artifact
86-
uses: actions/upload-pages-artifact@v3
96+
uses: actions/upload-pages-artifact@v4
8797
with:
8898
path: ./_site
99+
retention-days: 30
89100

90101
deploy:
91-
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
102+
# Keep production deployment manual until the Astro cutover is complete.
103+
# Pushes and pull requests still build and validate the full Pages artifact.
104+
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main'
105+
concurrency:
106+
group: pages-production
107+
cancel-in-progress: false
92108
environment:
93109
name: github-pages
94110
url: ${{ steps.deployment.outputs.page_url }}
@@ -97,4 +113,4 @@ jobs:
97113
steps:
98114
- name: Deploy to GitHub Pages
99115
id: deployment
100-
uses: actions/deploy-pages@v4
116+
uses: actions/deploy-pages@v5

‎.github/workflows/workers.yml‎

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
name: Deploy edge workers
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
operation:
7+
description: Deployment operation
8+
required: true
9+
default: deploy
10+
type: choice
11+
options:
12+
- deploy
13+
- remove-canary
14+
environment:
15+
description: Cloudflare environment
16+
required: true
17+
default: staging
18+
type: choice
19+
options:
20+
- staging
21+
- canary
22+
- production
23+
worker:
24+
description: Worker to deploy
25+
required: true
26+
default: documentation
27+
type: choice
28+
options:
29+
- both
30+
- documentation
31+
- redirects
32+
- email
33+
34+
permissions:
35+
contents: read
36+
37+
concurrency:
38+
group: edge-workers-${{ inputs.environment }}
39+
cancel-in-progress: false
40+
41+
jobs:
42+
deploy:
43+
name: Deploy ${{ inputs.worker }} to ${{ inputs.environment }}
44+
runs-on: ubuntu-latest
45+
environment: cloudflare-${{ inputs.environment }}
46+
steps:
47+
- name: Validate production ref
48+
if: inputs.environment == 'production'
49+
env:
50+
DEPLOY_REF: ${{ github.ref }}
51+
DEPLOY_WORKER: ${{ inputs.worker }}
52+
run: |
53+
if [[ "$DEPLOY_REF" == refs/heads/main ]]; then exit 0; fi
54+
if [[ "$DEPLOY_WORKER" == documentation && "$DEPLOY_REF" =~ ^refs/heads/release/[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.-]+)?-website$ ]]; then exit 0; fi
55+
echo "Production requires main, or an approved release website branch for documentation." >&2
56+
exit 2
57+
58+
- name: Validate operation
59+
if: inputs.operation == 'remove-canary' && inputs.environment != 'canary'
60+
run: |
61+
echo "remove-canary requires the canary environment" >&2
62+
exit 2
63+
64+
- name: Validate canary worker
65+
if: inputs.environment == 'canary' && inputs.worker != 'documentation'
66+
run: |
67+
echo "canary operations require the documentation worker" >&2
68+
exit 2
69+
70+
- name: Validate email environment
71+
if: inputs.worker == 'email' && inputs.environment != 'production'
72+
run: |
73+
echo "the email worker is deployed only through the production environment" >&2
74+
exit 2
75+
76+
- name: Checkout
77+
uses: actions/checkout@v7
78+
79+
- name: Setup Node
80+
uses: actions/setup-node@v6
81+
with:
82+
node-version: 24
83+
cache: npm
84+
85+
- name: Install dependencies
86+
run: npm ci
87+
88+
- name: Validate documentation Worker
89+
if: inputs.worker == 'both' || inputs.worker == 'documentation'
90+
run: npm run test:docs-worker && npm run check:docs-worker
91+
92+
- name: Validate redirect Worker
93+
if: inputs.worker == 'both' || inputs.worker == 'redirects'
94+
run: npm run test:redirect-worker && npm run check:redirect-worker
95+
96+
- name: Validate email Worker
97+
if: inputs.worker == 'email'
98+
run: npm run test:email-worker && npm run check:email-worker
99+
100+
- name: Deploy documentation Worker to staging
101+
if: inputs.operation == 'deploy' && inputs.environment == 'staging' && (inputs.worker == 'both' || inputs.worker == 'documentation')
102+
run: npx wrangler deploy --env="" --config workers/docs/wrangler.jsonc
103+
104+
- name: Verify staging documentation
105+
if: inputs.operation == 'deploy' && inputs.environment == 'staging' && (inputs.worker == 'both' || inputs.worker == 'documentation')
106+
run: |
107+
version=$(node -p "JSON.parse(require('fs').readFileSync('workers/docs/wrangler.jsonc', 'utf8')).vars.LATEST_DOC_VERSION")
108+
for attempt in 1 2 3 4 5 6; do
109+
if node scripts/docs/smoke-worker.mjs https://docs-staging.gecode.dev "$version"; then exit 0; fi
110+
if [ "$attempt" -eq 6 ]; then exit 1; fi
111+
echo "Waiting for the staging deployment to propagate (attempt $attempt)."
112+
sleep 10
113+
done
114+
115+
- name: Deploy documentation Worker to production
116+
if: inputs.operation == 'deploy' && inputs.environment == 'production' && (inputs.worker == 'both' || inputs.worker == 'documentation')
117+
run: npx wrangler deploy --env production --config workers/docs/wrangler.jsonc
118+
119+
- name: Deploy documentation Worker to canary
120+
if: inputs.operation == 'deploy' && inputs.environment == 'canary' && (inputs.worker == 'both' || inputs.worker == 'documentation')
121+
run: npx wrangler deploy --env canary --config workers/docs/wrangler.jsonc
122+
123+
- name: Verify documentation canary
124+
if: inputs.operation == 'deploy' && inputs.environment == 'canary' && inputs.worker == 'documentation'
125+
run: |
126+
version=$(node -p "JSON.parse(require('fs').readFileSync('workers/docs/wrangler.jsonc', 'utf8')).env.canary.vars.LATEST_DOC_VERSION")
127+
for attempt in 1 2 3 4 5 6; do
128+
if node scripts/docs/smoke-worker.mjs https://www.gecode.dev "$version" --immutable-only; then exit 0; fi
129+
if [ "$attempt" -eq 6 ]; then exit 1; fi
130+
echo "Waiting for the canary deployment to propagate (attempt $attempt)."
131+
sleep 10
132+
done
133+
134+
- name: Remove documentation canary
135+
if: inputs.operation == 'remove-canary'
136+
run: npx wrangler delete --env canary --config workers/docs/wrangler.jsonc --force
137+
138+
- name: Deploy redirect Worker to staging
139+
if: inputs.operation == 'deploy' && inputs.environment == 'staging' && (inputs.worker == 'both' || inputs.worker == 'redirects')
140+
run: npx wrangler deploy --env="" --config workers/redirects/wrangler.jsonc
141+
142+
- name: Deploy redirect Worker to production
143+
if: inputs.operation == 'deploy' && inputs.environment == 'production' && (inputs.worker == 'both' || inputs.worker == 'redirects')
144+
run: npx wrangler deploy --env production --config workers/redirects/wrangler.jsonc
145+
146+
- name: Deploy email Worker to production
147+
if: inputs.operation == 'deploy' && inputs.environment == 'production' && inputs.worker == 'email'
148+
run: npx wrangler deploy --config workers/email/wrangler.jsonc
149+
env:
150+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
151+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}

‎.gitignore‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
node_modules/
22
_site/
3+
.astro/
4+
.astro-public/
5+
dist/
36
.jekyll-cache/
47
.jekyll-metadata
58
.sass-cache/
69
.lighthouseci/
10+
.wrangler/
11+
.documentation-manifests/
12+
full-cf-token*.txt
713
.DS_Store
814
vendor/bundle/
915
.bundle/

‎README.md‎

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
# Gecode Website (Jekyll + GitHub Pages)
1+
# Gecode Website (Astro + GitHub Pages)
22

3-
This repository hosts the Gecode website and is built with Jekyll and Tailwind CSS.
3+
This repository hosts the Gecode website and is built with Astro and Tailwind
4+
CSS 4. React is available for future interactive islands, but the current site
5+
does not require client-side JavaScript.
46

57
## Requirements
68

7-
- Ruby `3.1.6` (or compatible `>= 3.1`)
8-
- Bundler (for the selected Ruby version)
9-
- Node.js `20.x`
9+
- Node.js `22.12` or newer (Node.js 24 is used in CI)
1010
- npm
1111

1212
## Quick Start
@@ -17,7 +17,7 @@ This repository hosts the Gecode website and is built with Jekyll and Tailwind C
1717
npm ci
1818
```
1919

20-
2. Start local development (Tailwind watch + Jekyll serve):
20+
2. Start local development:
2121

2222
```bash
2323
npm run dev
@@ -39,12 +39,39 @@ npm run check:quality
3939

4040
This command:
4141

42-
- rebuilds CSS and site output
43-
- verifies generated CSS is in sync with source
42+
- builds the active Astro site
4443
- checks executable-bit hygiene
4544
- validates generated active-site HTML pages
45+
- checks content transformations, metadata, and canonical URLs
46+
- validates the documentation and redirect Workers
47+
48+
For the GitHub Pages artifact, including the mailing-list archive but excluding
49+
documentation now served from R2, run:
50+
51+
```bash
52+
npm run build:pages
53+
```
54+
55+
The legacy rollback/comparison build still copies both frozen archives:
56+
57+
```bash
58+
npm run build:deploy
59+
```
60+
61+
That legacy artifact exceeds GitHub Pages' 1 GB published-site limit and must
62+
not be used by the production workflow.
4663

4764
## Notes on Scope
4865

4966
- `doc/` and `users-archive/` are treated as frozen historical archives.
5067
- Active-page checks intentionally exclude those frozen archives.
68+
- The Jekyll files remain temporarily as source for the compatibility content
69+
loader. They can be converted to native Astro content collections in a later,
70+
reviewable migration step.
71+
72+
## Migration Plans
73+
74+
- [Astro migration analysis](docs/astro-migration.md)
75+
- [Classical site parity review](docs/classic-parity-review.md)
76+
- [Deployment runbook](docs/deployment-runbook.md)
77+
- [Static documentation hosting plan](docs/static-documentation-hosting.md)
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
2-
title: Models by Håkan Kjellerstrand
2+
title: Models by Håkan Kjellerstrand
33
---
44

55
<a href="http://www.hakank.org/constraint_programming_blog/2009/03/my_first_gecode_models_1.html">
66
H&#229;kan's blog</a> now contains a collection of
7-
<a href="http://www.hakank.org/gecode">Gecode models</a>.
7+
<a href="http://www.hakank.org/gecode">Gecode models</a>.

‎astro.config.mjs‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { defineConfig } from "astro/config";
2+
import react from "@astrojs/react";
3+
import sitemap from "@astrojs/sitemap";
4+
import tailwindcss from "@tailwindcss/vite";
5+
import archiveDev from "./scripts/archive-dev.mjs";
6+
7+
export default defineConfig({
8+
site: "https://www.gecode.dev",
9+
publicDir: ".astro-public",
10+
output: "static",
11+
outDir: "./_site",
12+
trailingSlash: "always",
13+
build: {
14+
format: "directory",
15+
},
16+
integrations: [react(), sitemap()],
17+
vite: {
18+
plugins: [tailwindcss(), archiveDev()],
19+
},
20+
});

0 commit comments

Comments
 (0)