Skip to content

Commit 020df31

Browse files
committed
docs: add a script for automatic documentation deploy
1 parent 54d86f6 commit 020df31

File tree

2 files changed

+576
-0
lines changed

2 files changed

+576
-0
lines changed
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
# .github/actions/build-docc/action.yml
2+
name: 'Build DocC Documentation'
3+
description: 'Builds Swift DocC documentation for multiple products and platforms'
4+
5+
inputs:
6+
products:
7+
description: 'Comma-separated list of product names (e.g., "ValidatorCore,ValidatorUI")'
8+
required: true
9+
docc-paths:
10+
description: 'Comma-separated list of .docc paths (e.g., "Sources/ValidatorCore/Validator.docc,Sources/ValidatorUI/ValidatorUI.docc")'
11+
required: false
12+
default: ''
13+
bundle-identifier-prefix:
14+
description: 'Bundle identifier prefix (e.g., "dev.validator")'
15+
required: false
16+
default: 'dev.package'
17+
bundle-version:
18+
description: 'Bundle version for documentation'
19+
required: false
20+
default: '1.0.0'
21+
platforms:
22+
description: 'Comma-separated list of platforms to build for (e.g., "iOS,macOS,watchOS,tvOS,visionOS")'
23+
required: false
24+
default: 'iOS,macOS,watchOS,tvOS,visionOS'
25+
output-path:
26+
description: 'Output directory for generated documentation'
27+
required: false
28+
default: './docs'
29+
hosting-base-path:
30+
description: 'Base path for static hosting (leave empty for root)'
31+
required: false
32+
default: ''
33+
34+
runs:
35+
using: 'composite'
36+
steps:
37+
- name: Verify Schemes
38+
shell: bash
39+
run: |
40+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
41+
echo "Verifying available schemes"
42+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
43+
xcodebuild -list
44+
echo ""
45+
46+
IFS=',' read -ra PRODUCTS <<< "${{ inputs.products }}"
47+
for PRODUCT in "${PRODUCTS[@]}"; do
48+
if xcodebuild -list | grep -q "^\s*${PRODUCT}\s*$"; then
49+
echo "✓ Scheme '${PRODUCT}' found"
50+
else
51+
echo "✗ Scheme '${PRODUCT}' NOT FOUND"
52+
echo " Available schemes:"
53+
xcodebuild -list | grep -A 100 "Schemes:" | grep "^\s" | head -20
54+
exit 1
55+
fi
56+
done
57+
58+
- name: Setup Build Directories
59+
shell: bash
60+
run: |
61+
mkdir -p .build/symbol-graphs
62+
mkdir -p ${{ inputs.output-path }}
63+
64+
- name: Build Symbol Graphs
65+
shell: bash
66+
run: |
67+
IFS=',' read -ra PRODUCTS <<< "${{ inputs.products }}"
68+
IFS=',' read -ra PLATFORMS <<< "${{ inputs.platforms }}"
69+
70+
for PRODUCT in "${PRODUCTS[@]}"; do
71+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
72+
echo "Building symbol graphs for ${PRODUCT}"
73+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
74+
75+
for PLATFORM in "${PLATFORMS[@]}"; do
76+
echo "→ Platform: ${PLATFORM}"
77+
SYMBOL_DIR=".build/symbol-graphs/${PRODUCT}/${PLATFORM}"
78+
mkdir -p "${SYMBOL_DIR}"
79+
80+
xcodebuild build \
81+
-scheme "${PRODUCT}" \
82+
-destination "generic/platform=${PLATFORM}" \
83+
-derivedDataPath .deriveddata \
84+
DOCC_EXTRACT_EXTENSION_SYMBOLS=YES \
85+
OTHER_SWIFT_FLAGS="-Xfrontend -emit-symbol-graph -Xfrontend -emit-symbol-graph-dir -Xfrontend ${SYMBOL_DIR} -Xfrontend -emit-extension-block-symbols"
86+
87+
BUILD_STATUS=$?
88+
if [ $BUILD_STATUS -eq 0 ]; then
89+
echo "✓ ${PRODUCT} built successfully for ${PLATFORM}"
90+
echo " Symbol graphs in: ${SYMBOL_DIR}"
91+
ls -la "${SYMBOL_DIR}" || echo " (empty)"
92+
else
93+
echo "✗ ${PRODUCT} build failed for ${PLATFORM} (exit code: ${BUILD_STATUS})"
94+
fi
95+
done
96+
done
97+
98+
- name: Generate Documentation
99+
shell: bash
100+
run: |
101+
IFS=',' read -ra PRODUCTS <<< "${{ inputs.products }}"
102+
IFS=',' read -ra DOCC_PATHS <<< "${{ inputs.docc-paths }}"
103+
104+
for i in "${!PRODUCTS[@]}"; do
105+
PRODUCT="${PRODUCTS[$i]}"
106+
DOCC_PATH=""
107+
108+
if [ ${#DOCC_PATHS[@]} -gt $i ]; then
109+
DOCC_PATH="${DOCC_PATHS[$i]}"
110+
fi
111+
112+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
113+
echo "Generating documentation for ${PRODUCT}"
114+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
115+
116+
BUNDLE_ID="${{ inputs.bundle-identifier-prefix }}.${PRODUCT}"
117+
SYMBOL_GRAPHS_DIR=".build/symbol-graphs/${PRODUCT}"
118+
119+
# Check if symbol graphs exist
120+
if [ -d "${SYMBOL_GRAPHS_DIR}" ]; then
121+
SYMBOL_COUNT=$(find "${SYMBOL_GRAPHS_DIR}" -name "*.symbols.json" | wc -l)
122+
echo "Found ${SYMBOL_COUNT} symbol graph files"
123+
124+
if [ $SYMBOL_COUNT -gt 0 ]; then
125+
echo "Symbol graph files:"
126+
find "${SYMBOL_GRAPHS_DIR}" -name "*.symbols.json" -exec basename {} \; | head -10
127+
128+
# Count public symbols
129+
TOTAL_SYMBOLS=0
130+
for SYMBOL_FILE in $(find "${SYMBOL_GRAPHS_DIR}" -name "*.symbols.json"); do
131+
SYMBOL_FILE_COUNT=$(jq '[.symbols[].kind.identifier] | length' "${SYMBOL_FILE}" 2>/dev/null || echo "0")
132+
TOTAL_SYMBOLS=$((TOTAL_SYMBOLS + SYMBOL_FILE_COUNT))
133+
done
134+
echo "Total public symbols found: ${TOTAL_SYMBOLS}"
135+
136+
if [ $TOTAL_SYMBOLS -eq 0 ]; then
137+
echo "⚠ Warning: Symbol graphs exist but contain no public symbols"
138+
echo " Make sure your types/functions are declared as 'public' or 'open'"
139+
fi
140+
else
141+
echo "⚠ Warning: No symbol graphs found for ${PRODUCT}"
142+
echo " This usually means:"
143+
echo " - The build failed"
144+
echo " - There are no public APIs (everything is internal/private)"
145+
echo " - The scheme doesn't include the right targets"
146+
fi
147+
else
148+
echo "⚠ Warning: Symbol graphs directory not found: ${SYMBOL_GRAPHS_DIR}"
149+
fi
150+
151+
if [ -n "${DOCC_PATH}" ] && [ -d "${DOCC_PATH}" ]; then
152+
echo "Using .docc catalog: ${DOCC_PATH}"
153+
echo "Contents of .docc catalog:"
154+
ls -la "${DOCC_PATH}"
155+
156+
$(xcrun --find docc) convert "${DOCC_PATH}" \
157+
--fallback-display-name "${PRODUCT}" \
158+
--fallback-bundle-identifier "${BUNDLE_ID}" \
159+
--fallback-bundle-version "${{ inputs.bundle-version }}" \
160+
--output-dir "${PRODUCT}.doccarchive" \
161+
--additional-symbol-graph-dir "${SYMBOL_GRAPHS_DIR}"
162+
else
163+
echo "⚠ .docc catalog not found at: ${DOCC_PATH}"
164+
echo "Generating from symbol graphs only"
165+
166+
if [ ! -d "${SYMBOL_GRAPHS_DIR}" ] || [ $(find "${SYMBOL_GRAPHS_DIR}" -name "*.symbols.json" | wc -l) -eq 0 ]; then
167+
echo "✗ Error: Cannot generate documentation without .docc catalog or symbol graphs"
168+
continue
169+
fi
170+
171+
$(xcrun --find docc) convert \
172+
--fallback-display-name "${PRODUCT}" \
173+
--fallback-bundle-identifier "${BUNDLE_ID}" \
174+
--fallback-bundle-version "${{ inputs.bundle-version }}" \
175+
--output-dir "${PRODUCT}.doccarchive" \
176+
--additional-symbol-graph-dir "${SYMBOL_GRAPHS_DIR}"
177+
fi
178+
179+
DOCC_STATUS=$?
180+
if [ $DOCC_STATUS -ne 0 ]; then
181+
echo "✗ Failed to generate documentation for ${PRODUCT}"
182+
continue
183+
fi
184+
185+
# Check if .doccarchive was created
186+
if [ ! -d "${PRODUCT}.doccarchive" ]; then
187+
echo "✗ Error: ${PRODUCT}.doccarchive was not created"
188+
continue
189+
fi
190+
191+
echo "✓ Documentation archive created"
192+
193+
# Transform for static hosting
194+
if [ -n "${{ inputs.hosting-base-path }}" ]; then
195+
BASE_PATH="${{ inputs.hosting-base-path }}/${PRODUCT}"
196+
else
197+
BASE_PATH="${PRODUCT}"
198+
fi
199+
200+
echo "Transforming for static hosting with base path: ${BASE_PATH}"
201+
202+
$(xcrun --find docc) process-archive transform-for-static-hosting \
203+
"${PRODUCT}.doccarchive" \
204+
--output-path "${{ inputs.output-path }}/${PRODUCT}" \
205+
--hosting-base-path "${BASE_PATH}"
206+
207+
TRANSFORM_STATUS=$?
208+
if [ $TRANSFORM_STATUS -eq 0 ]; then
209+
echo "✓ ${PRODUCT} documentation generated successfully"
210+
echo " Output: ${{ inputs.output-path }}/${PRODUCT}"
211+
ls -la "${{ inputs.output-path }}/${PRODUCT}" | head -10
212+
else
213+
echo "✗ Failed to transform ${PRODUCT} for static hosting"
214+
fi
215+
done
216+
217+
- name: Verify Generated Documentation
218+
shell: bash
219+
run: |
220+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
221+
echo "Verifying generated documentation structure"
222+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
223+
224+
IFS=',' read -ra PRODUCTS <<< "${{ inputs.products }}"
225+
226+
for PRODUCT in "${PRODUCTS[@]}"; do
227+
DOCS_DIR="${{ inputs.output-path }}/${PRODUCT}"
228+
229+
if [ ! -d "${DOCS_DIR}" ]; then
230+
echo "✗ Documentation directory not found: ${DOCS_DIR}"
231+
continue
232+
fi
233+
234+
echo "Checking ${PRODUCT}:"
235+
236+
# Check for essential files
237+
if [ -f "${DOCS_DIR}/index.html" ]; then
238+
echo " ✓ index.html exists"
239+
else
240+
echo " ✗ index.html MISSING"
241+
fi
242+
243+
if [ -d "${DOCS_DIR}/documentation" ]; then
244+
echo " ✓ documentation/ directory exists"
245+
DOC_COUNT=$(find "${DOCS_DIR}/documentation" -name "*.html" | wc -l)
246+
echo " Found ${DOC_COUNT} HTML documentation pages"
247+
else
248+
echo " ✗ documentation/ directory MISSING"
249+
fi
250+
251+
if [ -d "${DOCS_DIR}/data" ]; then
252+
echo " ✓ data/ directory exists"
253+
JSON_COUNT=$(find "${DOCS_DIR}/data" -name "*.json" | wc -l)
254+
echo " Found ${JSON_COUNT} JSON data files"
255+
else
256+
echo " ✗ data/ directory MISSING"
257+
fi
258+
259+
echo ""
260+
done
261+
262+
- name: Cleanup Build Artifacts
263+
shell: bash
264+
if: always()
265+
run: |
266+
rm -rf .deriveddata
267+
rm -rf .build
268+
rm -rf *.doccarchive

0 commit comments

Comments
 (0)