Skip to content

Commit c95814a

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

File tree

4 files changed

+395
-10
lines changed

4 files changed

+395
-10
lines changed
Lines changed: 300 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,321 @@
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+
fi
82+
83+
# Extract version info if deploy_as_release is provided
84+
if [[ ("$IS_MANUAL" == "true" || "${{ github.event_name }}" == "workflow_call") && -n "$DEPLOY_AS_RELEASE" ]]; then
85+
VERSION="${DEPLOY_AS_RELEASE#v}"
86+
MAJOR_VERSION="v$(echo "$VERSION" | cut -d. -f1)"
87+
88+
# Check if it's a pre-release (contains -, like v1.0.0-rc1)
89+
IS_PRERELEASE="false"
90+
if [[ "$VERSION" =~ -.*$ ]]; then
91+
IS_PRERELEASE="true"
92+
fi
93+
fi
94+
95+
# 1. If on main, deploy "preview"
96+
if [[ "$IS_MAIN" == "true" ]]; then
97+
DEPLOY_PREVIEW="true"
98+
fi
99+
100+
# 2. If manually triggered with deploy_as_release, deploy "<version>"
101+
# except for pre/next/rc releases
102+
if [[ ("$IS_MANUAL" == "true" || "${{ github.event_name }}" == "workflow_call") && -n "$DEPLOY_AS_RELEASE" && "$IS_PRERELEASE" == "false" ]]; then
103+
DEPLOY_MAJOR="true"
104+
105+
# 3. If we're on main, also deploy "latest"
106+
if [[ "$IS_MAIN" == "true" ]]; then
107+
DEPLOY_LATEST="true"
108+
fi
109+
fi
110+
111+
# Output results
112+
echo "deploy_latest=$DEPLOY_LATEST" >> $GITHUB_OUTPUT
113+
echo "deploy_major=$DEPLOY_MAJOR" >> $GITHUB_OUTPUT
114+
echo "deploy_preview=$DEPLOY_PREVIEW" >> $GITHUB_OUTPUT
115+
echo "major_version=$MAJOR_VERSION" >> $GITHUB_OUTPUT
116+
echo "version=$VERSION" >> $GITHUB_OUTPUT
117+
118+
echo "DEPLOYMENT PLAN"
119+
echo "==============="
120+
echo "Trigger: ${{ github.event_name }}"
121+
echo "Latest: $DEPLOY_LATEST"
122+
echo "Major ($MAJOR_VERSION): $DEPLOY_MAJOR"
123+
echo "Preview: $DEPLOY_PREVIEW"
124+
125+
publish-documentation:
126+
runs-on: ubuntu-24.04
20127
needs:
21128
- build-and-test
129+
- determine-documentation-versions
130+
if: ${{ always() && needs.determine-documentation-versions.result == 'success' }}
131+
permissions:
132+
contents: write
133+
pages: write
134+
id-token: write
22135
steps:
23-
- uses: actions/configure-pages@v5
24-
- uses: actions/download-artifact@v5
136+
- name: Checkout
137+
uses: actions/checkout@v4
138+
with:
139+
fetch-depth: 0
140+
141+
- name: Download documentation artifact
142+
uses: actions/download-artifact@v5
25143
with:
26144
name: pages
27-
path: dist/design
28-
- uses: actions/upload-pages-artifact@v4
145+
path: new-docs
146+
147+
- name: Download existing site content from archive
148+
run: |
149+
REPO_OWNER=$(echo "${{ github.repository }}" | cut -d'/' -f1)
150+
REPO_NAME=$(echo "${{ github.repository }}" | cut -d'/' -f2)
151+
152+
# Determine archive URLs - try custom domain first, then GitHub Pages
153+
if [[ "$REPO_OWNER" == "siemens" && "$REPO_NAME" == "element" ]]; then
154+
PRIMARY_ARCHIVE_URL="https://element.siemens.io/documentation.tar.gz"
155+
FALLBACK_ARCHIVE_URL="https://${REPO_OWNER,,}.github.io/$REPO_NAME/documentation.tar.gz"
156+
else
157+
PRIMARY_ARCHIVE_URL="https://${REPO_OWNER,,}.github.io/$REPO_NAME/documentation.tar.gz"
158+
FALLBACK_ARCHIVE_URL=""
159+
fi
160+
161+
mkdir -p existing-site
162+
163+
# Try to download existing documentation archive
164+
if curl -s -f -L "$PRIMARY_ARCHIVE_URL" -o existing-documentation.tar.gz; then
165+
echo "Downloaded archive from: $PRIMARY_ARCHIVE_URL"
166+
cd existing-site
167+
tar -xzf ../existing-documentation.tar.gz
168+
cd ..
169+
if [[ ! -f "existing-site/versions.json" ]]; then
170+
echo "[]" > existing-site/versions.json
171+
fi
172+
elif [[ -n "$FALLBACK_ARCHIVE_URL" ]] && curl -s -f -L "$FALLBACK_ARCHIVE_URL" -o existing-documentation.tar.gz; then
173+
echo "Downloaded archive from fallback: $FALLBACK_ARCHIVE_URL"
174+
cd existing-site
175+
tar -xzf ../existing-documentation.tar.gz
176+
cd ..
177+
if [[ ! -f "existing-site/versions.json" ]]; then
178+
echo "[]" > existing-site/versions.json
179+
fi
180+
else
181+
echo "[]" > existing-site/versions.json
182+
fi
183+
continue-on-error: true
184+
185+
- name: Prepare deployment
186+
run: |
187+
mkdir -p deploy-site
188+
189+
# Copy existing content first
190+
if [[ -d existing-site ]]; then
191+
cp -r existing-site/* deploy-site/ 2>/dev/null || true
192+
fi
193+
194+
- name: Deploy to latest (root)
195+
if: needs.determine-documentation-versions.outputs.deploy_latest == 'true'
196+
run: |
197+
find deploy-site -maxdepth 1 -type f ! -name 'versions.json' -exec rm -f {} + 2>/dev/null || true
198+
find deploy-site -maxdepth 1 -type d ! -name 'v*' ! -name 'preview' ! -name 'latest' ! -name 'deploy-site' -exec rm -rf {} + 2>/dev/null || true
199+
rm -rf deploy-site/latest 2>/dev/null || true
200+
mkdir -p deploy-site/latest
201+
cp -r new-docs/* deploy-site/
202+
cp -r new-docs/* deploy-site/latest/
203+
204+
- name: Deploy to major version
205+
if: needs.determine-documentation-versions.outputs.deploy_major == 'true'
206+
run: |
207+
MAJOR_VERSION="${{ needs.determine-documentation-versions.outputs.major_version }}"
208+
rm -rf "deploy-site/$MAJOR_VERSION"
209+
mkdir -p "deploy-site/$MAJOR_VERSION"
210+
cp -r new-docs/* "deploy-site/$MAJOR_VERSION/"
211+
212+
- name: Deploy to preview
213+
if: needs.determine-documentation-versions.outputs.deploy_preview == 'true'
214+
run: |
215+
rm -rf deploy-site/preview
216+
mkdir -p deploy-site/preview
217+
cp -r new-docs/* deploy-site/preview/
218+
219+
- name: Ensure latest exists as fallback
220+
run: |
221+
# If no root content exists, use preview or new docs as default
222+
if [[ ! -f "deploy-site/index.html" ]]; then
223+
if [[ -d "deploy-site/preview" ]]; then
224+
cp -r deploy-site/preview/* deploy-site/
225+
else
226+
cp -r new-docs/* deploy-site/
227+
fi
228+
fi
229+
230+
- name: Generate dynamic versions.json
231+
run: |
232+
# Start with latest
233+
VERSIONS='[{"version": "latest", "title": "Latest", "aliases": []}]'
234+
235+
# Add preview if it exists
236+
if [[ -d "deploy-site/preview" ]]; then
237+
VERSIONS=$(echo "$VERSIONS" | jq '. += [{"version": "preview", "title": "Preview", "aliases": []}]')
238+
fi
239+
240+
# Add all version directories in descending order
241+
for version_dir in $(ls -d deploy-site/v*/ 2>/dev/null | sort -Vr); do
242+
if [[ -d "$version_dir" ]]; then
243+
version_name=$(basename "$version_dir")
244+
version_num=$(echo "$version_name" | sed 's/^v//')
245+
VERSIONS=$(echo "$VERSIONS" | jq --arg version "$version_name" --arg title "v$version_num" '. += [{"version": $version, "title": $title, "aliases": []}]')
246+
fi
247+
done
248+
249+
# Read existing versions.json and merge with new versions
250+
EXISTING_VERSIONS='[]'
251+
if [[ -f "existing-site/versions.json" ]]; then
252+
EXISTING_VERSIONS=$(cat existing-site/versions.json)
253+
fi
254+
255+
# Merge existing versions with new ones, removing duplicates
256+
MERGED_VERSIONS=$(echo "$EXISTING_VERSIONS $VERSIONS" | jq -s '
257+
add |
258+
unique_by(.version) |
259+
sort_by(
260+
if .version == "latest" then 0
261+
elif .version == "preview" then 1
262+
elif (.version | type) == "string" and (.version | test("^v[0-9]+")) then
263+
(.version | ltrimstr("v") | split(".")[0] | tonumber) + 1000
264+
else 9999 end
265+
) |
266+
reverse
267+
')
268+
269+
echo "$MERGED_VERSIONS" > deploy-site/versions.json
270+
271+
- name: Update canonical URLs
272+
run: |
273+
REPO_OWNER=$(echo "${{ github.repository }}" | cut -d'/' -f1)
274+
REPO_NAME=$(echo "${{ github.repository }}" | cut -d'/' -f2)
275+
276+
# Determine the base URL - prefer element.siemens.io for siemens/element repo
277+
if [[ "$REPO_OWNER" == "siemens" && "$REPO_NAME" == "element" ]]; then
278+
BASE_URL="https://element.siemens.io"
279+
else
280+
BASE_URL="https://${REPO_OWNER,,}.github.io/$REPO_NAME"
281+
fi
282+
283+
# Update root canonical URLs
284+
if [[ -f "deploy-site/index.html" ]]; then
285+
find deploy-site -maxdepth 1 -name "*.html" -type f -exec sed -i.bak \
286+
-e "s|<link rel=\"canonical\" href=\"[^\"]*\"|<link rel=\"canonical\" href=\"$BASE_URL|g" \
287+
{} \;
288+
fi
289+
290+
# Update subdirectory canonical URLs
291+
for version_dir in deploy-site/*/; do
292+
if [[ -d "$version_dir" ]]; then
293+
version_name=$(basename "$version_dir")
294+
VERSION_URL="$BASE_URL/$version_name"
295+
296+
find "$version_dir" -name "*.html" -type f -exec sed -i.bak \
297+
-e "s|<link rel=\"canonical\" href=\"[^\"]*\"|<link rel=\"canonical\" href=\"$VERSION_URL|g" \
298+
{} \;
299+
fi
300+
done
301+
302+
# Clean up backup files
303+
find deploy-site -name "*.bak" -type f -delete 2>/dev/null || true
304+
305+
- name: Setup Pages
306+
uses: actions/configure-pages@v5
307+
308+
- name: Create documentation archive
309+
run: |
310+
cd deploy-site
311+
tar -czf ../documentation.tar.gz .
312+
cd ..
313+
cp documentation.tar.gz deploy-site/
314+
315+
- name: Upload Pages artifact
316+
uses: actions/upload-pages-artifact@v4
29317
with:
30-
path: 'dist/design'
31-
- uses: actions/deploy-pages@v4
318+
path: 'deploy-site'
319+
320+
- name: Deploy to GitHub Pages
321+
uses: actions/deploy-pages@v4

.github/workflows/release.yaml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ jobs:
1414
runs-on: ubuntu-24.04
1515
needs:
1616
- build-and-test
17+
outputs:
18+
new_release: ${{ steps.check_release.outputs.new_release }}
19+
release_tag: ${{ steps.check_release.outputs.release_tag }}
1720
steps:
1821
- uses: actions/checkout@v5
1922
with:
@@ -28,6 +31,13 @@ jobs:
2831
name: dist
2932
path: dist
3033
- run: npm ci --prefer-offline --no-audit
34+
35+
- name: Get tag before semantic-release
36+
id: before_release
37+
run: |
38+
BEFORE_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
39+
echo "before_tag=$BEFORE_TAG" >> $GITHUB_OUTPUT
40+
3141
- run: npx semantic-release
3242
env:
3343
GIT_AUTHOR_NAME: 'Siemens Element Bot'
@@ -36,3 +46,27 @@ jobs:
3646
GIT_COMMITTER_EMAIL: 'simpl.si@siemens.com'
3747
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_GITHUB_TOKEN }}
3848
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
49+
50+
- name: Check if new release was created
51+
id: check_release
52+
run: |
53+
AFTER_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
54+
BEFORE_TAG="${{ steps.before_release.outputs.before_tag }}"
55+
56+
if [[ -n "$AFTER_TAG" && "$AFTER_TAG" != "$BEFORE_TAG" ]]; then
57+
echo "release_tag=$AFTER_TAG" >> $GITHUB_OUTPUT
58+
echo "new_release=true" >> $GITHUB_OUTPUT
59+
else
60+
echo "new_release=false" >> $GITHUB_OUTPUT
61+
echo "release_tag=" >> $GITHUB_OUTPUT
62+
fi
63+
64+
trigger-documentation:
65+
uses: ./.github/workflows/publish-documentation.yaml
66+
needs:
67+
- publish
68+
- build-and-test
69+
if: success() && needs.publish.outputs.new_release == 'true'
70+
with:
71+
deploy_as_release: ${{ needs.publish.outputs.release_tag }}
72+
skip_build: true

0 commit comments

Comments
 (0)