3535 - " source/**"
3636
3737jobs :
38- build_and_deploy :
38+ lint :
3939 runs-on : ubuntu-latest
40- permissions :
41- contents : write
42- actions : read
43- pages : read
44-
4540 steps :
4641 - name : Checkout Code
4742 uses : actions/checkout@v5
4843 with :
49- token : ${{ secrets.GITHUB_TOKEN }}
5044 fetch-depth : 0
5145
52- - name : Configure Git Credentials
53- run : |
54- git config --global user.name github-actions[bot]
55- git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com
56-
57- - name : Install system dependencies
58- run : |
59- sudo apt-get update
60- sudo apt-get install -y libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev
61-
62- - name : Install the latest version of uv
63- uses : astral-sh/setup-uv@v7
64-
65- - name : Install documentation dependencies
66- run : uv sync
46+ - uses : ./.github/actions/setup-build-env
6747
6848 - name : Lint YAML files
6949 run : uv run yamllint -c .github/linters/.yamllint.yml .
@@ -74,75 +54,126 @@ jobs:
7454 with :
7555 files : source/**
7656
77- - name : Install ucp-schema for runtime resolution
78- run : |
79- cargo install ucp-schema
80- echo "$HOME/.cargo/bin" >> $GITHUB_PATH
81-
8257 - name : Lint source schemas
83- if : steps.source_files_changed.outputs.any_changed == 'true'
58+ if : steps.source_files_changed.outputs.any_changed == 'true' || github.event_name == 'workflow_dispatch'
8459 run : ucp-schema lint source/
8560
86- - name : Create folders for JSON publishing
61+ build_and_verify_main :
62+ needs : lint
63+ runs-on : ubuntu-latest
64+ if : github.ref == 'refs/heads/main' || github.event.pull_request.base.ref == 'main'
65+ steps :
66+ - name : Checkout Code
67+ uses : actions/checkout@v5
68+ with :
69+ fetch-depth : 0
70+
71+ - name : Configure Git Credentials
8772 run : |
88- mkdir -p site/schemas
89- mkdir -p site/services
90- mkdir -p site/handlers
91- mkdir -p site/discovery
73+ git config --global user.name github-actions[bot]
74+ git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com
75+
76+ - uses : ./.github/actions/setup-build-env
9277
9378 - name : Configure Site URL
9479 env :
9580 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
9681 run : |
97- # Fetch the Pages URL. Fails safely if not enabled.
9882 PAGES_URL=$(gh api "repos/${{ github.repository }}/pages" --jq '.html_url' 2>/dev/null || true)
99-
100- if [ -z "$PAGES_URL" ]; then
101- echo "Pages URL not detected. Falling back to default structure."
102- PAGES_URL="https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}"
103- fi
104-
105- # Ensure trailing slash
106- if [[ "$PAGES_URL" != */ ]]; then
107- PAGES_URL="${PAGES_URL}/"
108- fi
109-
110- echo "Set SITE_URL to $PAGES_URL"
83+ if [ -z "$PAGES_URL" ]; then PAGES_URL="https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}"; fi
84+ if [[ "$PAGES_URL" != */ ]]; then PAGES_URL="${PAGES_URL}/"; fi
11185 echo "SITE_URL=$PAGES_URL" >> $GITHUB_ENV
86+ echo "SPEC_URL=${PAGES_URL}latest/specification/overview/" >> $GITHUB_ENV
11287
11388 - name : Build and Verify Documentation Site (Main/PR)
114- if : github.ref == 'refs/heads/main' || github.event.pull_request.base.ref == 'main'
11589 run : |
116- # Create a full local preview (including mike logic) for validation
11790 bash scripts/build_local.sh --main-only
11891 uv run python scripts/check_links.py local_preview
11992
93+ build_and_verify_release :
94+ needs : lint
95+ runs-on : ubuntu-latest
96+ if : startsWith(github.ref, 'refs/heads/release/') || startsWith(github.event.pull_request.base.ref, 'release/')
97+ steps :
98+ - name : Checkout Code
99+ uses : actions/checkout@v5
100+ with :
101+ fetch-depth : 0
102+
103+ - name : Configure Git Credentials
104+ run : |
105+ git config --global user.name github-actions[bot]
106+ git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com
107+
108+ - uses : ./.github/actions/setup-build-env
109+
110+ - name : Configure Site URL
111+ env :
112+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
113+ run : |
114+ PAGES_URL=$(gh api "repos/${{ github.repository }}/pages" --jq '.html_url' 2>/dev/null || true)
115+ if [ -z "$PAGES_URL" ]; then PAGES_URL="https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}"; fi
116+ if [[ "$PAGES_URL" != */ ]]; then PAGES_URL="${PAGES_URL}/"; fi
117+ echo "SITE_URL=$PAGES_URL" >> $GITHUB_ENV
118+ echo "SPEC_URL=${PAGES_URL}latest/specification/overview/" >> $GITHUB_ENV
119+
120120 - name : Build and Verify Specification Docs (Release Branches)
121- if : startsWith(github.ref, 'refs/heads/release/') || startsWith(github.event.pull_request.base.ref, 'release/')
122121 run : |
123122 export DOCS_MODE=spec
124123 uv run mkdocs build --strict
125124 uv run python scripts/check_links.py site
126125
126+ deploy_main :
127+ needs : build_and_verify_main
128+ runs-on : ubuntu-latest
129+ if : contains(fromJson('["push", "workflow_dispatch"]'), github.event_name) && github.ref == 'refs/heads/main'
130+ permissions :
131+ contents : write
132+ pages : read
133+ steps :
134+ - name : Checkout Code
135+ uses : actions/checkout@v5
136+ with :
137+ token : ${{ secrets.GITHUB_TOKEN }}
138+ fetch-depth : 0
139+
140+ - name : Configure Git Credentials
141+ run : |
142+ git config --global user.name github-actions[bot]
143+ git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com
144+
145+ - uses : ./.github/actions/setup-build-env
146+
147+ - name : Configure Site URL
148+ env :
149+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
150+ run : |
151+ PAGES_URL=$(gh api "repos/${{ github.repository }}/pages" --jq '.html_url' 2>/dev/null || true)
152+ if [ -z "$PAGES_URL" ]; then PAGES_URL="https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}"; fi
153+ if [[ "$PAGES_URL" != */ ]]; then PAGES_URL="${PAGES_URL}/"; fi
154+ echo "SITE_URL=$PAGES_URL" >> $GITHUB_ENV
155+ echo "SPEC_URL=${PAGES_URL}latest/specification/overview/" >> $GITHUB_ENV
156+
127157 - name : Deploy development version from main branch
128- if : github.event_name == 'push' && github.ref == 'refs/heads/main'
129158 run : |
130- # 1. Deploy Specification Site using mike (DOCS_MODE=spec)
131159 export DOCS_MODE=spec
132160 uv run mike deploy --push draft
133161
134- # 2. Build Root Site (DOCS_MODE=root)
135162 export DOCS_MODE=root
136163 uv run mkdocs build --strict
137164
138- # 3. Deploy Root Site to gh-pages root
139- # Fetch and checkout gh-pages
140- git fetch origin gh-pages
141- git checkout gh-pages
165+ # Checkout gh-pages into a separate directory to avoid overwriting the workspace
166+ # and causing GitHub Actions post-run hooks to fail (as they need .github/actions)
167+ git clone --branch gh-pages "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" gh-pages-branch
168+ cd gh-pages-branch
169+
170+ # Remove existing root files except versions and git metadata
171+ git ls-files | grep -vE "^(\.nojekyll|draft|latest|[0-9]{4}-[0-9]{2}-[0-9]{2}|versions\.json|\.git)" | xargs -r rm -f
172+ find . -maxdepth 1 -type d -empty -not -path "./.git*" -delete
142173
143174 # Copy build artifacts to root
144- cp -r site/* .
145- rm -rf site
175+ cp -r ../ site/* .
176+ rm -rf ../ site
146177
147178 # Add redirects for all specification files
148179 rm -rf specification
@@ -153,43 +184,72 @@ jobs:
153184 git commit -m "Deploy root site from main" --allow-empty
154185 git push origin gh-pages
155186
187+ deploy_release :
188+ needs : build_and_verify_release
189+ runs-on : ubuntu-latest
190+ if : contains(fromJson('["push", "workflow_dispatch"]'), github.event_name) && startsWith(github.ref, 'refs/heads/release/')
191+ permissions :
192+ contents : write
193+ pages : read
194+ steps :
195+ - name : Checkout Code
196+ uses : actions/checkout@v5
197+ with :
198+ token : ${{ secrets.GITHUB_TOKEN }}
199+ fetch-depth : 0
200+
201+ - name : Configure Git Credentials
202+ run : |
203+ git config --global user.name github-actions[bot]
204+ git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com
205+
206+ - uses : ./.github/actions/setup-build-env
207+
208+ - name : Configure Site URL
209+ env :
210+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
211+ run : |
212+ PAGES_URL=$(gh api "repos/${{ github.repository }}/pages" --jq '.html_url' 2>/dev/null || true)
213+ if [ -z "$PAGES_URL" ]; then PAGES_URL="https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}"; fi
214+ if [[ "$PAGES_URL" != */ ]]; then PAGES_URL="${PAGES_URL}/"; fi
215+ echo "SITE_URL=$PAGES_URL" >> $GITHUB_ENV
216+ echo "SPEC_URL=${PAGES_URL}latest/specification/overview/" >> $GITHUB_ENV
217+
156218 - name : Deploy release version
157- if : startsWith(github.ref, 'refs/heads/release/')
158219 run : |
159220 export DOCS_MODE=spec
160- # Extract the date (e.g., release/2026-01-11 -> 2026-01-11)
161221 VERSION_NAME=${GITHUB_REF#refs/heads/release/}
162-
163- # Fetch all release branches to determine if this is the latest
164222 git fetch origin "+refs/heads/release/*:refs/remotes/origin/release/*"
165-
166- # Find the highest version number among all release branches
167223 LATEST_VERSION=$(git branch -r --list "origin/release/*" | sed 's|origin/release/||' | sort -V | tail -n 1 | tr -d ' ')
168224
169- echo "Deploying version: $VERSION_NAME"
170- echo "Latest detected version: $LATEST_VERSION"
171-
172225 if [ "$VERSION_NAME" = "$LATEST_VERSION" ]; then
173- echo "This is the latest version. Updating 'latest' alias."
174226 uv run mike deploy --push --update-aliases "$VERSION_NAME" latest
175227 else
176- echo "This is NOT the latest version. Deploying without updating 'latest' alias."
177228 uv run mike deploy --push "$VERSION_NAME"
178229 fi
179230
231+ create_release :
232+ needs : deploy_release
233+ runs-on : ubuntu-latest
234+ if : contains(fromJson('["push", "workflow_dispatch"]'), github.event_name) && startsWith(github.ref, 'refs/heads/release/')
235+ permissions :
236+ contents : write
237+ steps :
238+ - name : Checkout Code
239+ uses : actions/checkout@v5
240+ with :
241+ token : ${{ secrets.GITHUB_TOKEN }}
242+ fetch-depth : 0
243+
180244 - name : Create GitHub Release and Tag
181- if : startsWith(github.ref, 'refs/heads/release/')
182245 env :
183246 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
184247 run : |
185248 VERSION_DATE=${GITHUB_REF#refs/heads/release/}
186249 TAG_NAME="v$VERSION_DATE"
187250
188- # Create Release (This implicitly creates the git tag)
189- # The '|| true' ensures the workflow doesn't fail if you
190- # push updates to this branch later (re-running the build).
191251 gh release create "$TAG_NAME" \
192252 --title "Release $TAG_NAME" \
193253 --generate-notes \
194254 --target "$GITHUB_REF_NAME" \
195- || echo "Release $TAG_NAME already exists, skipping creation."
255+ || echo "Release $TAG_NAME already exists, skipping creation."
0 commit comments