Skip to content

Commit b7a0c56

Browse files
committed
ci(docs): add caching and parallel build scripts for doc generation
Add Go module and Hugo resource caching to both hugo-build composite actions. Optimize Dockerfile with BuildKit cache mounts and better layer ordering. Add new scripts for parallel versioned doc generation (discover-versions, generate-single-version, assemble-versions) — not yet referenced by any workflow. jira: trivial risk: nonprod
1 parent 3698ce1 commit b7a0c56

6 files changed

Lines changed: 212 additions & 6 deletions

File tree

.github/actions/hugo-build-action/action.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ runs:
1212
uses: actions/setup-go@v5
1313
with:
1414
go-version: '>=1.20.1'
15+
cache: false
16+
- name: "Cache Go modules"
17+
uses: actions/cache@v4
18+
with:
19+
path: ~/go/pkg/mod
20+
key: go-mod-${{ hashFiles('docs/go.sum') }}
21+
restore-keys: go-mod-
1522
- name: "Setup Node"
1623
uses: actions/setup-node@v4
1724
with:
@@ -28,6 +35,12 @@ runs:
2835
working-directory: ./docs
2936
run: |
3037
npm ci
38+
- name: "Cache Hugo resources"
39+
uses: actions/cache@v4
40+
with:
41+
path: docs/resources/_gen
42+
key: hugo-resources-${{ hashFiles('docs/go.sum', 'docs/config/**') }}
43+
restore-keys: hugo-resources-
3144
- name: "Build documentation"
3245
working-directory: ./docs
3346
env:

.github/actions/hugo-build-versioned-action/action.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ runs:
3535
- uses: actions/setup-go@v5
3636
with:
3737
go-version: '>=1.20.1'
38+
cache: false
39+
- name: "Cache Go modules"
40+
uses: actions/cache@v4
41+
with:
42+
path: ~/go/pkg/mod
43+
key: go-mod-${{ hashFiles('docs/go.sum') }}
44+
restore-keys: go-mod-
3845
- name: "Setup Node"
3946
uses: actions/setup-node@v4
4047
with:
@@ -59,6 +66,12 @@ runs:
5966
wget https://raw.githubusercontent.com/gooddata/gooddata-python-sdk/master/scripts/generate.sh
6067
chmod +x ./generate.sh
6168
./generate.sh ${{ inputs.fetch-from }} master
69+
- name: "Cache Hugo resources"
70+
uses: actions/cache@v4
71+
with:
72+
path: docs/resources/_gen
73+
key: hugo-resources-${{ hashFiles('docs/go.sum', 'docs/config/**') }}
74+
restore-keys: hugo-resources-
6275
- name: "Build documentation"
6376
working-directory: ./docs
6477
env:

docs/Dockerfile

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1+
# syntax=docker/dockerfile:1
12
FROM python:3.14-slim AS builder
23

34
RUN apt-get update && apt-get install -y git make curl
45

6+
# Install Python deps first (changes rarely) for better layer caching.
7+
# Copy only dependency manifests and package source before installing.
58
COPY scripts/script-requirements.txt /scripts/script-requirements.txt
6-
COPY docs docs
7-
COPY scripts/docs/ /docs
89
COPY gooddata-api-client /gooddata-api-client
910
COPY packages/gooddata-sdk /gooddata-sdk
1011
COPY packages/gooddata-pandas /gooddata-pandas
1112

12-
RUN pip install --no-cache-dir -r /scripts/script-requirements.txt
13+
RUN --mount=type=cache,target=/root/.cache/pip \
14+
pip install -r /scripts/script-requirements.txt
15+
16+
# Copy source (docs content changes most frequently, scripts less so)
17+
COPY docs docs
18+
COPY scripts/docs/ /docs
1319

1420
WORKDIR /docs
1521

@@ -21,16 +27,20 @@ RUN python json_builder.py && \
2127

2228
FROM node:20.18.0-bookworm-slim
2329

24-
COPY --from=builder /docs /docs
25-
2630
RUN apt-get update && \
2731
apt-get install -y git make golang-go curl && \
2832
npm install -g hugo-extended@0.117.0 && \
2933
apt-get clean && \
3034
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
3135

36+
COPY --from=builder /docs /docs
37+
3238
WORKDIR /docs
33-
RUN npm install && \
39+
40+
# Use BuildKit cache mounts so npm/Go package downloads survive layer rebuilds
41+
RUN --mount=type=cache,target=/root/.npm \
42+
--mount=type=cache,target=/root/go/pkg/mod \
43+
npm install && \
3444
hugo mod get
3545

3646
# accessible on http://localhost:1313/latest/

scripts/assemble-versions.sh

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/bin/bash
2+
# (C) 2026 GoodData Corporation
3+
# Assembles version artifacts into the final versioned_docs structure.
4+
# Run from the docs/ directory after downloading version artifacts.
5+
#
6+
# Expects:
7+
# - versioned_docs-raw/ directory with version-* subdirectories (from artifact download)
8+
# - content/en/ directory with master branch content (from current checkout)
9+
set -e
10+
11+
content_dir=versioned_docs
12+
13+
# Start with clean versioned_docs
14+
rm -rf "$content_dir"
15+
mkdir -p "$content_dir"
16+
17+
# 1. Copy master/current branch content (provides versions page and root structure)
18+
echo "Copying master content from content/en/"
19+
cp -r content/en/. "$content_dir/"
20+
21+
# 2. Move version artifacts from download directory into versioned_docs
22+
if [ -d "versioned_docs-raw" ]; then
23+
for dir in versioned_docs-raw/version-*/; do
24+
[ -d "$dir" ] || continue
25+
section=$(basename "$dir" | sed 's/^version-//')
26+
echo "Installing version artifact: $section"
27+
# Remove any existing content for this section (from master copy)
28+
rm -rf "${content_dir:?}/$section"
29+
mv "$dir" "$content_dir/$section"
30+
done
31+
rm -rf versioned_docs-raw
32+
fi
33+
34+
# 3. Remove master's "latest" directory — it will be replaced by the highest numbered version
35+
echo "Removing master's latest directory"
36+
rm -rf "${content_dir:?}/latest"
37+
38+
# 4. Find the highest numbered version and promote it to "latest"
39+
highest_version=$(ls -1 "./$content_dir/" | grep -E '^[0-9]+$' | sort -V | tail -n 1)
40+
41+
if [ -n "$highest_version" ]; then
42+
echo "Promoting version $highest_version to /latest"
43+
mv -f "./$content_dir/$highest_version" "./$content_dir/latest"
44+
45+
# Update version references in links.json
46+
if [ -f "./$content_dir/latest/links.json" ]; then
47+
sed "s|${highest_version}|latest|g" "./$content_dir/latest/links.json" > temp_links.json
48+
mv temp_links.json "./$content_dir/latest/links.json"
49+
fi
50+
else
51+
echo "WARNING: No numbered version directory found to promote to latest"
52+
fi
53+
54+
echo "Assembly complete. Contents of $content_dir/:"
55+
ls -la "$content_dir/"

scripts/discover-versions.sh

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/bin/bash
2+
# (C) 2026 GoodData Corporation
3+
# Discovers release versions for parallel doc generation.
4+
# Outputs a JSON array suitable for GitHub Actions matrix strategy.
5+
# Usage: discover-versions.sh [remote_name] [num_versions]
6+
set -e
7+
8+
remote_name=${1:-origin}
9+
num_versions=${2:-4}
10+
11+
git fetch "$remote_name" 2>/dev/null
12+
13+
# Build a map of section -> branch, keeping only the latest minor per section.
14+
# Associative arrays preserve last-write-wins semantics, matching the original
15+
# generate.sh behavior where later branches overwrite earlier ones.
16+
declare -A section_map
17+
declare -a section_order
18+
19+
while IFS= read -r vers; do
20+
section="${vers%.*}"
21+
if [ -z "${section_map[$section]+x}" ]; then
22+
section_order+=("$section")
23+
fi
24+
# Later (higher minor) versions overwrite earlier ones for the same major
25+
section_map["$section"]="rel/$vers"
26+
done < <(git branch -rl "$remote_name/rel/*" | sed 's|.*/rel/||' | grep -E '^[0-9]+\.[0-9]+$' | sort -t. -k1,1n -k2,2n | tail -n"$num_versions")
27+
28+
# Add dev branch if it exists
29+
if git branch -rl "$remote_name/rel/dev" | grep -q "rel/dev"; then
30+
if [ -z "${section_map[dev]+x}" ]; then
31+
section_order+=("dev")
32+
fi
33+
section_map["dev"]="rel/dev"
34+
fi
35+
36+
# Output as JSON array
37+
echo -n "["
38+
first=true
39+
for section in "${section_order[@]}"; do
40+
branch="${section_map[$section]}"
41+
if [ "$first" = true ]; then
42+
first=false
43+
else
44+
echo -n ","
45+
fi
46+
echo -n "{\"branch\":\"$branch\",\"section\":\"$section\"}"
47+
done
48+
echo "]"

scripts/generate-single-version.sh

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/bin/bash
2+
# (C) 2026 GoodData Corporation
3+
# Generates documentation for a single version branch.
4+
# This is the per-version logic extracted from generate.sh for parallel execution.
5+
#
6+
# Usage: generate-single-version.sh <full-branch-ref> <section>
7+
# Example: generate-single-version.sh origin/rel/1.3 1
8+
#
9+
# Prerequisites:
10+
# - Repository checked out with the target branch fetched
11+
# - Python environment with script-requirements.txt installed from the TARGET branch
12+
set -e
13+
14+
branch=$1
15+
section=$2
16+
17+
if [ -z "$branch" ] || [ -z "$section" ]; then
18+
echo "Usage: generate-single-version.sh <full-branch-ref> <section>"
19+
echo "Example: generate-single-version.sh origin/rel/1.3 1"
20+
exit 1
21+
fi
22+
23+
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
24+
cd "$REPO_ROOT/docs"
25+
26+
content_dir=versioned_docs
27+
28+
mkdir -p "$content_dir/$section"
29+
30+
# Determine source content path on the branch
31+
if git ls-tree -d "$branch" -- "content/en/docs" 2>/dev/null | grep -q "content/en/docs"; then
32+
src_section=docs
33+
else
34+
src_section=latest
35+
fi
36+
37+
# Extract documentation content from the branch
38+
echo "Extracting docs from $branch for section $section (src=$src_section)"
39+
# strip-components=3 removes content/en/{src_section} prefix
40+
git archive "$branch" "content/en/$src_section" | tar xf - -C "$content_dir/$section" \
41+
--strip-components=3 "content/en/$src_section"
42+
43+
# Generate API reference if json_builder.py exists on the branch
44+
API_GEN_FILE="$branch:scripts/docs/json_builder.py"
45+
if git cat-file -e "$API_GEN_FILE" 2>/dev/null; then
46+
echo "Generating API ref for section $section..."
47+
48+
# Get api_spec.toml from the branch
49+
if git ls-tree --name-only "$branch" | grep -q "^api_spec.toml$"; then
50+
git checkout "$branch" -- api_spec.toml
51+
else
52+
echo "No api_spec.toml on $branch, removing local copy"
53+
rm -f api_spec.toml
54+
fi
55+
56+
# Generate API introspection data from this version's SDK
57+
python3 ../scripts/docs/json_builder.py
58+
mv -f data.json "$content_dir/$section/"
59+
60+
# Generate API reference markdown files
61+
python3 ../scripts/docs/python_ref_builder.py api_spec.toml \
62+
"./$content_dir/$section/data.json" "$section" "$content_dir"
63+
else
64+
echo "No json_builder.py on $branch, skipping API ref generation"
65+
fi
66+
67+
echo "Done: section $section from $branch"

0 commit comments

Comments
 (0)