Skip to content

Commit 7a38434

Browse files
committed
chore(docs): add versioned documentation with auto-detection
Close #675
1 parent bd2db41 commit 7a38434

File tree

4 files changed

+467
-10
lines changed

4 files changed

+467
-10
lines changed
Lines changed: 360 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,381 @@
11
name: Publish Documentation
22
on:
33
push:
4-
branches:
5-
- main
4+
branches: [main]
5+
workflow_dispatch:
6+
inputs:
7+
deploy_as_release:
8+
description: 'Deploy as release version (e.g., v1.2.3) - will deploy the docs as if this is a release with this version'
9+
required: false
10+
type: string
11+
default: ''
12+
workflow_call:
13+
inputs:
14+
deploy_as_release:
15+
description: 'Deploy as release version (e.g., v1.2.3) - will deploy the docs as if this is a release with this version'
16+
required: false
17+
type: string
18+
default: ''
19+
skip_build:
20+
description: 'Skip build-and-test job (assumes artifacts already exist)'
21+
required: false
22+
type: boolean
23+
default: false
24+
25+
env:
26+
PYTHON_VERSION: '3.11'
27+
NODE_VERSION: '20'
628

729
jobs:
830
build-and-test:
31+
if: ${{ !inputs.skip_build }}
932
uses: ./.github/workflows/build-and-test.yaml
1033
secrets:
1134
SIEMENS_NPM_TOKEN: ${{ secrets.SIEMENS_NPM_TOKEN }}
1235
SIEMENS_NPM_USER: ${{ secrets.SIEMENS_NPM_USER }}
1336
MAPTILER_KEY: ${{ secrets.MAPTILER_KEY }}
1437

15-
publish-documentation:
16-
runs-on: ubuntu-24.04
38+
determine-documentation-versions:
39+
needs:
40+
- build-and-test
41+
if: ${{ always() && (needs.build-and-test.result == 'success' || inputs.skip_build) }}
1742
permissions:
43+
contents: write
1844
pages: write
1945
id-token: write
46+
runs-on: ubuntu-24.04
47+
outputs:
48+
deploy_latest: ${{ steps.deploy.outputs.deploy_latest }}
49+
deploy_major: ${{ steps.deploy.outputs.deploy_major }}
50+
deploy_preview: ${{ steps.deploy.outputs.deploy_preview }}
51+
major_version: ${{ steps.deploy.outputs.major_version }}
52+
version: ${{ steps.deploy.outputs.version }}
53+
steps:
54+
- name: Checkout
55+
uses: actions/checkout@v4
56+
with:
57+
fetch-depth: 0
58+
59+
- name: Determine deployment targets
60+
id: deploy
61+
run: |
62+
# Initialize all outputs
63+
DEPLOY_LATEST="false"
64+
DEPLOY_MAJOR="false"
65+
DEPLOY_PREVIEW="false"
66+
MAJOR_VERSION=""
67+
VERSION=""
68+
69+
IS_MANUAL="${{ github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call' }}"
70+
IS_MAIN="${{ github.ref == 'refs/heads/main' }}"
71+
DEPLOY_AS_RELEASE="${{ github.event.inputs.deploy_as_release || inputs.deploy_as_release }}"
72+
73+
# Validate manual version format if provided
74+
if [[ ("$IS_MANUAL" == "true" || "${{ github.event_name }}" == "workflow_call") && -n "$DEPLOY_AS_RELEASE" ]]; then
75+
# Ensure version starts with 'v'
76+
if [[ ! "$DEPLOY_AS_RELEASE" =~ ^v[0-9]+\.[0-9]+\.[0-9]+.*$ ]]; then
77+
echo "❌ Error: Deploy as release version must be in format 'v1.2.3' or 'v1.2.3-suffix'"
78+
echo " Provided: '$DEPLOY_AS_RELEASE'"
79+
exit 1
80+
fi
81+
echo "✅ Deploy as release version format is valid: $DEPLOY_AS_RELEASE"
82+
fi
83+
84+
# Extract version info if deploy_as_release is provided
85+
if [[ ("$IS_MANUAL" == "true" || "${{ github.event_name }}" == "workflow_call") && -n "$DEPLOY_AS_RELEASE" ]]; then
86+
VERSION="${DEPLOY_AS_RELEASE#v}"
87+
MAJOR_VERSION="v$(echo "$VERSION" | cut -d. -f1)"
88+
89+
# Check if it's a pre-release (contains -, like v1.0.0-rc1)
90+
IS_PRERELEASE="false"
91+
if [[ "$VERSION" =~ -.*$ ]]; then
92+
IS_PRERELEASE="true"
93+
fi
94+
fi
95+
96+
# 1. If on main, deploy "preview"
97+
if [[ "$IS_MAIN" == "true" ]]; then
98+
DEPLOY_PREVIEW="true"
99+
fi
100+
101+
# 2. If manually triggered with deploy_as_release, deploy "<version>"
102+
# except for pre/next/rc releases
103+
if [[ ("$IS_MANUAL" == "true" || "${{ github.event_name }}" == "workflow_call") && -n "$DEPLOY_AS_RELEASE" && "$IS_PRERELEASE" == "false" ]]; then
104+
DEPLOY_MAJOR="true"
105+
106+
# 3. If we're on main, also deploy "latest"
107+
if [[ "$IS_MAIN" == "true" ]]; then
108+
DEPLOY_LATEST="true"
109+
fi
110+
fi
111+
112+
# Output results
113+
echo "deploy_latest=$DEPLOY_LATEST" >> $GITHUB_OUTPUT
114+
echo "deploy_major=$DEPLOY_MAJOR" >> $GITHUB_OUTPUT
115+
echo "deploy_preview=$DEPLOY_PREVIEW" >> $GITHUB_OUTPUT
116+
echo "major_version=$MAJOR_VERSION" >> $GITHUB_OUTPUT
117+
echo "version=$VERSION" >> $GITHUB_OUTPUT
118+
119+
# Debug output
120+
echo "🚀 DEPLOYMENT PLAN"
121+
echo "=================="
122+
echo "Trigger: ${{ github.event_name }}"
123+
echo "Ref: ${{ github.ref_name }}"
124+
if [[ ("$IS_MANUAL" == "true" || "${{ github.event_name }}" == "workflow_call") && -n "$DEPLOY_AS_RELEASE" ]]; then
125+
echo "Deploy as release: $DEPLOY_AS_RELEASE"
126+
fi
127+
echo ""
128+
echo "Deployments:"
129+
echo " Latest: $DEPLOY_LATEST"
130+
echo " Major ($MAJOR_VERSION): $DEPLOY_MAJOR"
131+
echo " Preview: $DEPLOY_PREVIEW"
132+
echo " Version: $VERSION"
133+
134+
- name: Deployment Summary
135+
run: |
136+
echo "🚀 DEPLOYMENT SUMMARY"
137+
echo "====================="
138+
echo "Trigger: ${{ github.event_name }}"
139+
if [[ "${{ github.event_name }}" == "workflow_dispatch" || "${{ github.event_name }}" == "workflow_call" ]]; then
140+
DEPLOY_AS_RELEASE="${{ github.event.inputs.deploy_as_release || inputs.deploy_as_release }}"
141+
if [[ -n "$DEPLOY_AS_RELEASE" ]]; then
142+
echo "Deploy as release: $DEPLOY_AS_RELEASE"
143+
else
144+
echo "Manual trigger without version (preview only)"
145+
fi
146+
else
147+
echo "Branch/Tag: ${{ github.ref_name }}"
148+
fi
149+
if [[ "$DEPLOY_LATEST" == "true" ]]; then
150+
echo "✅ Will deploy to LATEST (root)"
151+
echo " URL: https://element.siemens.io/latest/ or https://element.siemens.io/"
152+
fi
153+
if [[ "$DEPLOY_MAJOR" == "true" ]]; then
154+
echo "✅ Will deploy to MAJOR VERSION $MAJOR_VERSION"
155+
echo " URL: https://element.siemens.io/"
156+
fi
157+
if [[ "$DEPLOY_PREVIEW" == "true" ]]; then
158+
echo "✅ Will deploy to PREVIEW"
159+
echo " URL: https://element.siemens.io/preview/"
160+
fi
161+
162+
echo "====================="
163+
164+
publish-documentation:
165+
runs-on: ubuntu-24.04
20166
needs:
21167
- build-and-test
168+
- determine-documentation-versions
169+
if: ${{ always() && needs.determine-documentation-versions.result == 'success' }}
170+
permissions:
171+
contents: write
172+
pages: write
173+
id-token: write
22174
steps:
23-
- uses: actions/configure-pages@v5
24-
- uses: actions/download-artifact@v5
175+
- name: Checkout
176+
uses: actions/checkout@v4
177+
with:
178+
fetch-depth: 0
179+
180+
- name: Download documentation artifact
181+
uses: actions/download-artifact@v5
25182
with:
26183
name: pages
27-
path: dist/design
28-
- uses: actions/upload-pages-artifact@v4
184+
path: new-docs
185+
186+
- name: Download existing site content from archive
187+
run: |
188+
REPO_OWNER=$(echo "${{ github.repository }}" | cut -d'/' -f1)
189+
REPO_NAME=$(echo "${{ github.repository }}" | cut -d'/' -f2)
190+
ARCHIVE_URL="https://${REPO_OWNER,,}.github.io/$REPO_NAME/documentation.tar.gz"
191+
192+
mkdir -p existing-site
193+
194+
echo "Attempting to download existing documentation archive from: $ARCHIVE_URL"
195+
196+
# Try to download existing documentation archive
197+
if curl -s -f -L "$ARCHIVE_URL" -o existing-documentation.tar.gz; then
198+
echo "Found existing documentation archive, extracting..."
199+
cd existing-site
200+
tar -xzf ../existing-documentation.tar.gz
201+
cd ..
202+
echo "Extracted existing site structure"
203+
204+
# Ensure versions.json exists
205+
if [[ ! -f "existing-site/versions.json" ]]; then
206+
echo "[]" > existing-site/versions.json
207+
fi
208+
else
209+
echo "No existing documentation archive found, will create fresh deployment"
210+
echo "[]" > existing-site/versions.json
211+
fi
212+
continue-on-error: true
213+
214+
- name: Prepare deployment
215+
run: |
216+
mkdir -p deploy-site
217+
218+
# Copy existing content first
219+
if [[ -d existing-site ]]; then
220+
cp -r existing-site/* deploy-site/ 2>/dev/null || true
221+
fi
222+
223+
echo "Deployment preparation complete"
224+
225+
- name: Deploy to latest (root)
226+
if: needs.determine-documentation-versions.outputs.deploy_latest == 'true'
227+
run: |
228+
echo "Deploying to latest (root)"
229+
230+
# Deploy to root and latest (preserve version subdirectories)
231+
# Delete all files in root except versions.json
232+
find deploy-site -maxdepth 1 -type f ! -name 'versions.json' -exec rm -f {} + 2>/dev/null || true
233+
# Delete all version directories except v*, preview, latest
234+
find deploy-site -maxdepth 1 -type d ! -name 'v*' ! -name 'preview' ! -name 'latest' ! -name 'deploy-site' -exec rm -rf {} + 2>/dev/null || true
235+
rm -rf deploy-site/latest 2>/dev/null || true
236+
mkdir -p deploy-site/latest
237+
cp -r new-docs/* deploy-site/
238+
cp -r new-docs/* deploy-site/latest/
239+
240+
echo "✅ Deployed to latest (root)"
241+
242+
- name: Deploy to major version
243+
if: needs.determine-documentation-versions.outputs.deploy_major == 'true'
244+
run: |
245+
MAJOR_VERSION="${{ needs.determine-documentation-versions.outputs.major_version }}"
246+
echo "Deploying to major version: $MAJOR_VERSION"
247+
248+
# Replace this major version directory
249+
rm -rf "deploy-site/$MAJOR_VERSION"
250+
mkdir -p "deploy-site/$MAJOR_VERSION"
251+
cp -r new-docs/* "deploy-site/$MAJOR_VERSION/"
252+
253+
echo "✅ Deployed to $MAJOR_VERSION"
254+
255+
- name: Deploy to preview
256+
if: needs.determine-documentation-versions.outputs.deploy_preview == 'true'
257+
run: |
258+
echo "Deploying to preview"
259+
260+
# Replace preview directory
261+
rm -rf deploy-site/preview
262+
mkdir -p deploy-site/preview
263+
cp -r new-docs/* deploy-site/preview/
264+
265+
echo "✅ Deployed to preview"
266+
267+
- name: Ensure latest exists as fallback
268+
run: |
269+
# If no root content exists, use preview or new docs as default
270+
if [[ ! -f "deploy-site/index.html" ]]; then
271+
if [[ -d "deploy-site/preview" ]]; then
272+
echo "Using preview as fallback for root"
273+
cp -r deploy-site/preview/* deploy-site/
274+
else
275+
echo "Using new docs as fallback for root"
276+
cp -r new-docs/* deploy-site/
277+
fi
278+
fi
279+
280+
- name: Generate dynamic versions.json
281+
run: |
282+
echo "Generating versions.json from discovered directories..."
283+
284+
# Start with latest
285+
VERSIONS='[{"version": "latest", "title": "Latest", "aliases": []}]'
286+
287+
# Add preview if it exists
288+
if [[ -d "deploy-site/preview" ]]; then
289+
VERSIONS=$(echo "$VERSIONS" | jq '. += [{"version": "preview", "title": "Preview", "aliases": []}]')
290+
fi
291+
292+
# Add all version directories in descending order
293+
for version_dir in $(ls -d deploy-site/v*/ 2>/dev/null | sort -Vr); do
294+
if [[ -d "$version_dir" ]]; then
295+
version_name=$(basename "$version_dir")
296+
version_num=$(echo "$version_name" | sed 's/^v//')
297+
VERSIONS=$(echo "$VERSIONS" | jq --arg version "$version_name" --arg title "v$version_num" '. += [{"version": $version, "title": $title, "aliases": []}]')
298+
fi
299+
done
300+
301+
# Read existing versions.json and merge with new versions
302+
EXISTING_VERSIONS='[]'
303+
if [[ -f "existing-site/versions.json" ]]; then
304+
EXISTING_VERSIONS=$(cat existing-site/versions.json)
305+
echo "Found existing versions.json:"
306+
echo "$EXISTING_VERSIONS" | jq .
307+
fi
308+
309+
# Merge existing versions with new ones, removing duplicates
310+
MERGED_VERSIONS=$(echo "$EXISTING_VERSIONS $VERSIONS" | jq -s '
311+
add |
312+
unique_by(.version) |
313+
sort_by(
314+
if .version == "latest" then 0
315+
elif .version == "preview" then 1
316+
elif (.version | type) == "string" and (.version | test("^v[0-9]+")) then
317+
(.version | ltrimstr("v") | split(".")[0] | tonumber) + 1000
318+
else 9999 end
319+
) |
320+
reverse
321+
')
322+
323+
# Write merged versions.json
324+
echo "$MERGED_VERSIONS" > deploy-site/versions.json
325+
326+
echo "Generated merged versions.json:"
327+
cat deploy-site/versions.json | jq .
328+
329+
- name: Update canonical URLs
330+
run: |
331+
REPO_OWNER=$(echo "${{ github.repository }}" | cut -d'/' -f1)
332+
REPO_NAME=$(echo "${{ github.repository }}" | cut -d'/' -f2)
333+
BASE_URL="https://${REPO_OWNER,,}.github.io/$REPO_NAME"
334+
335+
echo "Updating canonical URLs to: $BASE_URL"
336+
337+
# Update root canonical URLs
338+
if [[ -f "deploy-site/index.html" ]]; then
339+
find deploy-site -maxdepth 1 -name "*.html" -type f -exec sed -i.bak \
340+
-e "s|<link rel=\"canonical\" href=\"[^\"]*\"|<link rel=\"canonical\" href=\"$BASE_URL|g" \
341+
{} \;
342+
fi
343+
344+
# Update subdirectory canonical URLs
345+
for version_dir in deploy-site/*/; do
346+
if [[ -d "$version_dir" ]]; then
347+
version_name=$(basename "$version_dir")
348+
VERSION_URL="$BASE_URL/$version_name"
349+
350+
find "$version_dir" -name "*.html" -type f -exec sed -i.bak \
351+
-e "s|<link rel=\"canonical\" href=\"[^\"]*\"|<link rel=\"canonical\" href=\"$VERSION_URL|g" \
352+
{} \;
353+
fi
354+
done
355+
356+
# Clean up backup files
357+
find deploy-site -name "*.bak" -type f -delete 2>/dev/null || true
358+
359+
- name: Setup Pages
360+
uses: actions/configure-pages@v5
361+
362+
- name: Create documentation archive
363+
run: |
364+
echo "Creating documentation archive..."
365+
cd deploy-site
366+
tar -czf ../documentation.tar.gz .
367+
cd ..
368+
369+
# Store archive at root of deployment
370+
cp documentation.tar.gz deploy-site/
371+
372+
echo "Archive created and stored at root: documentation.tar.gz"
373+
echo "Archive size: $(du -h documentation.tar.gz | cut -f1)"
374+
375+
- name: Upload Pages artifact
376+
uses: actions/upload-pages-artifact@v4
29377
with:
30-
path: 'dist/design'
31-
- uses: actions/deploy-pages@v4
378+
path: 'deploy-site'
379+
380+
- name: Deploy to GitHub Pages
381+
uses: actions/deploy-pages@v4

0 commit comments

Comments
 (0)