Skip to content

Commit d61a2d9

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

File tree

7 files changed

+532
-17
lines changed

7 files changed

+532
-17
lines changed
Lines changed: 303 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,325 @@
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+
force_deploy:
13+
description: 'Force deployment even on non-main branches (for testing)'
14+
required: false
15+
type: boolean
16+
default: false
17+
skip_build:
18+
description: 'Skip build-and-test job (use existing artifacts)'
19+
required: false
20+
type: boolean
21+
default: false
22+
workflow_call:
23+
inputs:
24+
deploy_as_release:
25+
description: 'Deploy as release version (e.g., v1.2.3) - will deploy the docs as if this is a release with this version'
26+
required: false
27+
type: string
28+
default: ''
29+
skip_build:
30+
description: 'Skip build-and-test job (assumes artifacts already exist)'
31+
required: false
32+
type: boolean
33+
default: false
34+
secrets:
35+
SIEMENS_NPM_TOKEN:
36+
required: false
37+
SIEMENS_NPM_USER:
38+
required: false
39+
MAPTILER_KEY:
40+
required: false
41+
42+
env:
43+
PYTHON_VERSION: '3.11'
44+
NODE_VERSION: '20'
45+
VERSIONED_BUCKET_NAME: simpl-element-release
46+
CLOUDFRONT_DOMAIN: d2uqfzn4lxgtwv.cloudfront.net
647

748
jobs:
849
build-and-test:
50+
if: ${{ !inputs.skip_build && github.event.inputs.skip_build != 'true' }}
951
uses: ./.github/workflows/build-and-test.yaml
1052
secrets:
1153
SIEMENS_NPM_TOKEN: ${{ secrets.SIEMENS_NPM_TOKEN }}
1254
SIEMENS_NPM_USER: ${{ secrets.SIEMENS_NPM_USER }}
1355
MAPTILER_KEY: ${{ secrets.MAPTILER_KEY }}
1456

15-
publish-documentation:
57+
# Simple deployment for main branch (no versioning)
58+
publish-documentation-main:
1659
runs-on: ubuntu-24.04
60+
needs:
61+
- build-and-test
62+
if: >-
63+
${{
64+
needs.build-and-test.result == 'success' &&
65+
github.ref == format('refs/heads/{0}', github.event.repository.default_branch) &&
66+
!inputs.deploy_as_release
67+
}}
1768
permissions:
69+
contents: write
1870
pages: write
1971
id-token: write
20-
needs:
21-
- build-and-test
2272
steps:
23-
- uses: actions/configure-pages@v5
24-
- uses: actions/download-artifact@v7
73+
- name: Download documentation artifact
74+
uses: actions/download-artifact@v7
2575
with:
2676
name: pages
2777
path: dist/design
28-
- uses: actions/upload-pages-artifact@v4
78+
79+
- name: Setup Pages
80+
uses: actions/configure-pages@v5
81+
82+
- name: Upload Pages artifact
83+
uses: actions/upload-pages-artifact@v4
2984
with:
3085
path: 'dist/design'
31-
- uses: actions/deploy-pages@v4
86+
87+
- name: Deploy to GitHub Pages
88+
uses: actions/deploy-pages@v4
89+
90+
determine-documentation-versions:
91+
needs:
92+
- build-and-test
93+
if: ${{ always() && (needs.build-and-test.result == 'success' || inputs.skip_build) && inputs.deploy_as_release }}
94+
permissions:
95+
contents: read
96+
runs-on: ubuntu-24.04
97+
outputs:
98+
deploy_major: ${{ steps.deploy.outputs.deploy_major }}
99+
major_version: ${{ steps.deploy.outputs.major_version }}
100+
version: ${{ steps.deploy.outputs.version }}
101+
should_deploy: ${{ steps.deploy.outputs.should_deploy }}
102+
steps:
103+
- name: Checkout
104+
uses: actions/checkout@v4
105+
with:
106+
fetch-depth: 0
107+
108+
- name: Determine deployment targets
109+
id: deploy
110+
run: |
111+
# Initialize all outputs
112+
DEPLOY_MAJOR="false"
113+
MAJOR_VERSION=""
114+
VERSION=""
115+
SHOULD_DEPLOY="false"
116+
117+
DEPLOY_AS_RELEASE="${{ github.event.inputs.deploy_as_release || inputs.deploy_as_release }}"
118+
119+
# Validate and extract version info
120+
if [[ -n "$DEPLOY_AS_RELEASE" ]]; then
121+
# Ensure version starts with 'v'
122+
if [[ ! "$DEPLOY_AS_RELEASE" =~ ^v[0-9]+\.[0-9]+\.[0-9]+.*$ ]]; then
123+
echo "Error: Deploy as release version must be in format 'v1.2.3' or 'v1.2.3-suffix'"
124+
echo "Provided: '$DEPLOY_AS_RELEASE'"
125+
exit 1
126+
fi
127+
128+
VERSION="${DEPLOY_AS_RELEASE#v}"
129+
MAJOR_VERSION="v$(echo "$VERSION" | cut -d. -f1)"
130+
131+
# Check if it's a pre-release (contains -, like v1.0.0-rc1)
132+
IS_PRERELEASE="false"
133+
if [[ "$VERSION" =~ -.*$ ]]; then
134+
IS_PRERELEASE="true"
135+
fi
136+
137+
# Deploy to major version except for pre/next/rc releases
138+
if [[ "$IS_PRERELEASE" == "false" ]]; then
139+
DEPLOY_MAJOR="true"
140+
SHOULD_DEPLOY="true"
141+
fi
142+
fi
143+
144+
echo "deploy_major=$DEPLOY_MAJOR" >> $GITHUB_OUTPUT
145+
echo "major_version=$MAJOR_VERSION" >> $GITHUB_OUTPUT
146+
echo "version=$VERSION" >> $GITHUB_OUTPUT
147+
echo "should_deploy=$SHOULD_DEPLOY" >> $GITHUB_OUTPUT
148+
149+
echo "DEPLOYMENT PLAN"
150+
echo "==============="
151+
echo "Branch: ${{ github.ref }}"
152+
echo "Trigger: ${{ github.event_name }}"
153+
echo "Major ($MAJOR_VERSION): $DEPLOY_MAJOR"
154+
155+
# Versioned deployment for releases (S3 only, not GitHub Pages)
156+
publish-documentation-release:
157+
runs-on: ubuntu-24.04
158+
needs:
159+
- build-and-test
160+
- determine-documentation-versions
161+
# always() is required because build-and-test may be skipped (when skip_build=true)
162+
# We still want to run if determine-documentation-versions succeeded
163+
if: >-
164+
${{
165+
always() &&
166+
needs.determine-documentation-versions.result == 'success' &&
167+
needs.determine-documentation-versions.outputs.should_deploy == 'true'
168+
}}
169+
permissions:
170+
contents: write
171+
id-token: write
172+
steps:
173+
- name: Checkout
174+
uses: actions/checkout@v4
175+
with:
176+
fetch-depth: 0
177+
178+
- name: Download documentation artifact
179+
uses: actions/download-artifact@v7
180+
with:
181+
name: pages
182+
path: new-docs
183+
184+
- name: Configure AWS credentials
185+
uses: aws-actions/configure-aws-credentials@v5.1.1
186+
with:
187+
role-to-assume: arn:aws:iam::974483672234:role/simpl-element-release
188+
role-session-name: element-release-docs
189+
aws-region: eu-west-1
190+
191+
- name: List existing versions from S3
192+
run: |
193+
mkdir -p deploy-site
194+
195+
# List existing version directories from S3 (no download needed)
196+
echo "Listing existing versions from S3..."
197+
aws s3 ls s3://${{ env.VERSIONED_BUCKET_NAME }}/ || echo "No existing versions found"
198+
199+
- name: Update with new version(s)
200+
run: |
201+
# Deploy to major version directory
202+
MAJOR_VERSION="${{ needs.determine-documentation-versions.outputs.major_version }}"
203+
204+
echo "Updating /$MAJOR_VERSION/..."
205+
# Remove old version to ensure clean deployment
206+
rm -rf "deploy-site/$MAJOR_VERSION"
207+
mkdir -p "deploy-site/$MAJOR_VERSION"
208+
cp -r new-docs/* "deploy-site/$MAJOR_VERSION/"
209+
210+
# Add base tag to docs HTML files only (exclude element-examples, dashboards-demo, coverage)
211+
find "deploy-site/$MAJOR_VERSION" -name "*.html" -type f \
212+
! -path "*/element-examples/*" \
213+
! -path "*/dashboards-demo/*" \
214+
! -path "*/coverage/*" \
215+
-exec sed -i.bak "s|<head>|<head>\n <base href=\"/$MAJOR_VERSION/\">|" {} \;
216+
217+
find "deploy-site/$MAJOR_VERSION" -name "*.bak" -type f -delete
218+
219+
- name: Generate versions.json
220+
run: |
221+
# Generate versions.json from S3 directory listing (no download needed)
222+
echo "Generating versions.json from S3 directory listing..."
223+
224+
# Collect all versions from S3
225+
ALL_VERSIONS=()
226+
227+
# List all existing version-specific folders from S3 (v1, v2, v48, etc.)
228+
# aws s3 ls lists directories with trailing slashes, e.g., "PRE v1/"
229+
aws s3 ls s3://${{ env.VERSIONED_BUCKET_NAME }}/ | grep "PRE v" | awk '{print $2}' | sed 's/\/$//' > s3-versions.txt || true
230+
231+
# Add the currently deploying version to ensure it's included
232+
MAJOR_VERSION="${{ needs.determine-documentation-versions.outputs.major_version }}"
233+
echo "$MAJOR_VERSION" >> s3-versions.txt
234+
235+
# Read all versions and remove duplicates
236+
while IFS= read -r version_name; do
237+
if [[ -n "$version_name" ]]; then
238+
ALL_VERSIONS+=("$version_name")
239+
fi
240+
done < s3-versions.txt
241+
242+
# Remove duplicates and sort versions in descending order
243+
SORTED_VERSIONS=($(printf '%s\n' "${ALL_VERSIONS[@]}" | sort -u -t 'v' -k 2 -n -r))
244+
245+
# Find the highest version for "Latest"
246+
LATEST_VERSION="${SORTED_VERSIONS[0]}"
247+
echo "Latest version: $LATEST_VERSION"
248+
249+
# Build versions.json with correct order:
250+
# 1. Latest (empty version string)
251+
# 2. All versions in descending order (v48, v18, v17, etc.)
252+
# 3. Preview (redirect to element.siemens.io)
253+
254+
VERSIONS='[]'
255+
256+
# Add Latest first (empty version string points to root)
257+
latest_num=$(echo "$LATEST_VERSION" | sed 's/^v//')
258+
echo "Adding: Latest (${latest_num}.x)"
259+
VERSIONS=$(echo "$VERSIONS" | jq '. += [{"version": "", "title": "Latest"}]')
260+
261+
# Add all versions in descending order
262+
for version_name in "${SORTED_VERSIONS[@]}"; do
263+
version_num=$(echo "$version_name" | sed 's/^v//')
264+
echo "Adding: $version_name (${version_num}.x)"
265+
VERSIONS=$(echo "$VERSIONS" | jq --arg version "$version_name" --arg title "${version_num}.x" '. += [{"version": $version, "title": $title}]')
266+
done
267+
268+
# Add Preview last
269+
echo "Adding: Preview (redirect to https://element.siemens.io)"
270+
VERSIONS=$(echo "$VERSIONS" | jq '. += [{"version": "https://element.siemens.io", "title": "Preview"}]')
271+
272+
# Write to deploy-site/versions.json
273+
mkdir -p deploy-site
274+
echo "$VERSIONS" | jq '.' > deploy-site/versions.json
275+
276+
echo "Generated versions.json:"
277+
cat deploy-site/versions.json
278+
279+
- name: Update canonical URLs
280+
run: |
281+
SITE_URL="https://element.siemens.io/"
282+
283+
# Update canonical URLs for version directories
284+
MAJOR_VERSION="${{ needs.determine-documentation-versions.outputs.major_version }}"
285+
VERSION_URL="${SITE_URL}${MAJOR_VERSION}/"
286+
287+
find "deploy-site/$MAJOR_VERSION" -name "*.html" -type f -exec sed -i.bak \
288+
-e "s|<link rel=\"canonical\" href=\"https://element.siemens.io/|<link rel=\"canonical\" href=\"${VERSION_URL}|g" \
289+
{} \;
290+
291+
# Clean up backup files
292+
find deploy-site -name "*.bak" -type f -delete 2>/dev/null || true
293+
294+
- name: Upload to S3
295+
run: |
296+
echo "Uploading versioned documentation to S3..."
297+
298+
MAJOR_VERSION="${{ needs.determine-documentation-versions.outputs.major_version }}"
299+
300+
# Upload versioned directory
301+
echo "Uploading /$MAJOR_VERSION/..."
302+
if [[ ! -d "deploy-site/$MAJOR_VERSION" ]]; then
303+
echo "Error: deploy-site/$MAJOR_VERSION directory does not exist"
304+
exit 1
305+
fi
306+
aws s3 sync --quiet --no-progress --delete "deploy-site/$MAJOR_VERSION/" "s3://${{ env.VERSIONED_BUCKET_NAME }}/$MAJOR_VERSION/"
307+
308+
# If on main branch, also copy to root (without version prefix in path)
309+
if [[ "${{ github.ref }}" == "refs/heads/${{ github.event.repository.default_branch }}" ]]; then
310+
echo "On main branch - copying /$MAJOR_VERSION/ to root..."
311+
# Delete old files but exclude version directories and versions.json from sync and deletion
312+
aws s3 sync --quiet --no-progress --delete "deploy-site/$MAJOR_VERSION/" "s3://${{ env.VERSIONED_BUCKET_NAME }}/" \
313+
--exclude "v*" \
314+
--exclude "versions.json"
315+
fi
316+
317+
# Upload versions.json with short cache-control for quick updates
318+
if [[ ! -f "deploy-site/versions.json" ]]; then
319+
echo "Error: deploy-site/versions.json file does not exist"
320+
exit 1
321+
fi
322+
aws s3 cp deploy-site/versions.json s3://${{ env.VERSIONED_BUCKET_NAME }}/versions.json \
323+
--cache-control "max-age=60,public"
324+
325+
echo "Uploaded versioned documentation to S3 at s3://${{ env.VERSIONED_BUCKET_NAME }}/"

.github/workflows/release.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ jobs:
1616
- build-and-test
1717
permissions:
1818
id-token: write
19+
outputs:
20+
new_release: ${{ steps.check_release.outputs.new_release }}
21+
release_tag: ${{ steps.check_release.outputs.release_tag }}
1922
steps:
2023
- uses: actions/checkout@v6
2124
with:
@@ -30,6 +33,13 @@ jobs:
3033
name: dist
3134
path: dist
3235
- run: npm ci --prefer-offline --no-audit
36+
37+
- name: Get tag before semantic-release
38+
id: before_release
39+
run: |
40+
BEFORE_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
41+
echo "before_tag=$BEFORE_TAG" >> $GITHUB_OUTPUT
42+
3343
- run: npx semantic-release
3444
env:
3545
SKIP_COMMIT: ${{ github.ref_name == 'next' && 'true' || '' }}
@@ -38,3 +48,28 @@ jobs:
3848
GIT_COMMITTER_NAME: 'Siemens Element Bot'
3949
GIT_COMMITTER_EMAIL: 'simpl.si@siemens.com'
4050
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_GITHUB_TOKEN }}
51+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
52+
53+
- name: Check if new release was created
54+
id: check_release
55+
run: |
56+
AFTER_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
57+
BEFORE_TAG="${{ steps.before_release.outputs.before_tag }}"
58+
59+
if [[ -n "$AFTER_TAG" && "$AFTER_TAG" != "$BEFORE_TAG" ]]; then
60+
echo "release_tag=$AFTER_TAG" >> $GITHUB_OUTPUT
61+
echo "new_release=true" >> $GITHUB_OUTPUT
62+
else
63+
echo "new_release=false" >> $GITHUB_OUTPUT
64+
echo "release_tag=" >> $GITHUB_OUTPUT
65+
fi
66+
67+
trigger-documentation:
68+
uses: ./.github/workflows/publish-documentation.yaml
69+
needs:
70+
- publish
71+
- build-and-test
72+
if: success() && needs.publish.outputs.new_release == 'true'
73+
with:
74+
deploy_as_release: ${{ needs.publish.outputs.release_tag }}
75+
skip_build: true

0 commit comments

Comments
 (0)