Skip to content

Commit 90e115e

Browse files
ci(build): preview PR builds via Read the Docs (#210)
1 parent 7607221 commit 90e115e

File tree

4 files changed

+361
-4
lines changed

4 files changed

+361
-4
lines changed

.github/workflows/jekyll-build.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,20 +95,20 @@ jobs:
9595
run: |
9696
case "${{ inputs.extract_archive }}" in
9797
*.tar.gz|*.tgz)
98-
tar -xzf ${{ inputs.extract_archive }} -C .
98+
tar -xzf "${{ inputs.extract_archive }}" -C .
9999
;;
100100
*.tar)
101-
tar -xf ${{ inputs.extract_archive }} -C .
101+
tar -xf "${{ inputs.extract_archive }}" -C .
102102
;;
103103
*.zip)
104-
7z x ${{ inputs.extract_archive }} -o.
104+
7z x "${{ inputs.extract_archive }}" -o.
105105
;;
106106
*)
107107
echo "Unsupported archive format"
108108
exit 1
109109
;;
110110
esac
111-
rm -f ${{ inputs.extract_archive }}
111+
rm -f "${{ inputs.extract_archive }}"
112112
113113
- name: Setup project
114114
if: ${{ github.repository == 'LizardByte/LizardByte.github.io' }}

.readthedocs.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
# Read the Docs configuration file
3+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
4+
5+
version: 2
6+
7+
build:
8+
os: ubuntu-24.04
9+
tools:
10+
ruby: "3.3"
11+
jobs:
12+
install:
13+
- chmod +x "./scripts/readthedocs_build.sh"
14+
build:
15+
html:
16+
- "./scripts/readthedocs_build.sh"
17+
18+
submodules:
19+
include: all
20+
recursive: true

README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,77 @@ jobs:
6666
```
6767
6868
For additional options see [jekyll-build.yml](.github/workflows/jekyll-build.yml)
69+
70+
### PR Previews
71+
72+
Changes to gh-pages can be previewed, by setting up the project in ReadTheDocs.
73+
It is recommended to use the following manual configuration:
74+
75+
Initial setup:
76+
```yml
77+
Name: LizardByte-gh-pages-<repo_name> # the project slug cannot be changed after creation
78+
Repository URL: https://github.com/LizardByte/<repo_name>.git
79+
Default-branch: master
80+
Language: English
81+
```
82+
83+
Project Settings:
84+
```yml
85+
Connected-repository: https://github.com/LizardByte/<repo_name>.git
86+
URL-versioning-scheme: Multiple versions without translations
87+
Path-for-.readthedocs.yaml: # only set if not in the root of the repo
88+
Programming-Language: Other
89+
Project-homepage: https://app.lizardbyte.dev/<repo_name>
90+
Description: Preview PRs for gh-pages
91+
Build-pull-requests-for-this-project: true
92+
```
93+
94+
Environment Variables:
95+
```yml
96+
# REQUIRED
97+
GITHUB_WORKFLOW: call-jekyll-build / Build Jekyll
98+
SITE_ARTIFACT: prep.zip # the name of the artifact to look for in the workflow
99+
100+
# OPTIONAL
101+
CONFIG_FILE: _config.yml
102+
EXTRACT_ARCHIVE: pre_built_database.zip # if there is a nested archive to extract
103+
GITHUB_TIMEOUT: 10 # timeout in minutes to use when searching for GitHub artifacts, max 15
104+
THEME_REF: master
105+
```
106+
107+
Additionally, do the following:
108+
109+
1. Deactivate the `stable` version
110+
2. Make the `latest` version hidden
111+
3. Add project as a subproject of `LizardByte-gh-pages-main`
112+
4. Update branch protection rules in GitHub repo settings to require status checks from ReadTheDocs
113+
5. Add the below `.readthedocs.yaml` file to the root of the repo, or a custom path as specified in the project settings
114+
115+
```yml
116+
---
117+
# Read the Docs configuration file
118+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
119+
120+
version: 2
121+
122+
build:
123+
os: ubuntu-24.04
124+
tools:
125+
ruby: "3.3"
126+
apt_packages:
127+
- 7zip
128+
- jq
129+
jobs:
130+
install:
131+
- |
132+
mkdir -p "./tmp"
133+
branch="master"
134+
base_url="https://raw.githubusercontent.com/LizardByte/LizardByte.github.io"
135+
url="${base_url}/refs/heads/${branch}/scripts/readthedocs_build.sh"
136+
curl -sSL -o "./tmp/readthedocs_build.sh" "${url}"
137+
chmod +x "./tmp/readthedocs_build.sh"
138+
build:
139+
html:
140+
- "./tmp/readthedocs_build.sh"
141+
142+
```

scripts/readthedocs_build.sh

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
# REQUIRED ENVIRONMENT VARIABLES (for subprojects)
5+
github_workflow=$(echo "$GITHUB_WORKFLOW" | tr -d "'")
6+
site_artifact=$(echo "$SITE_ARTIFACT" | tr -d "'")
7+
8+
# OPTIONAL ENVIRONMENT VARIABLES (for subprojects)
9+
config_file=$(echo "$CONFIG_FILE" | tr -d "'")
10+
extract_archive=$(echo "$EXTRACT_ARCHVIE" | tr -d "'")
11+
github_timeout=$GITHUB_TIMEOUT
12+
theme_ref=$THEME_REF
13+
14+
# From ReadTheDocs
15+
git_sha=$READTHEDOCS_GIT_COMMIT_HASH
16+
github_url=$READTHEDOCS_GIT_CLONE_URL
17+
18+
if [[ $github_url == git@* ]]; then
19+
# SSH URL format: [email protected]:user/repo.git
20+
github_user=$(echo "$github_url" | cut -d: -f2 | cut -d/ -f1)
21+
github_repo=$(echo "$github_url" | cut -d/ -f2 | sed 's/\.git$//')
22+
else
23+
# HTTPS URL format: https://github.com/user/repo
24+
github_user=$(echo "$github_url" | cut -d/ -f4)
25+
github_repo=$(echo "$github_url" | cut -d/ -f5 | sed 's/\.git$//')
26+
fi
27+
28+
export PAGES_REPO_NWO="${github_user}/${github_repo}"
29+
30+
# if timeout is not set then default to 10 minutes
31+
if [ -z "$github_timeout" ]; then
32+
github_timeout=10
33+
fi
34+
35+
# if config file is not set then default to _config.yml
36+
if [ -z "$config_file" ]; then
37+
config_file="_config.yml"
38+
fi
39+
40+
# if theme ref is not set then default to master
41+
if [ -z "$theme_ref" ]; then
42+
theme_ref="master"
43+
fi
44+
45+
echo "git sha: $git_sha"
46+
echo "github url: $github_url"
47+
echo "github user: $github_user"
48+
echo "github repo: $github_repo"
49+
50+
# set default directories
51+
project_dir="."
52+
theme_dir="."
53+
54+
# if not the theme project then we need to clone the theme with submodules
55+
sub_project="false"
56+
if [ "$READTHEDOCS_PROJECT" != "lizardbyte-gh-pages-main" ]; then
57+
sub_project="true"
58+
echo "Building a subproject: $READTHEDOCS_PROJECT"
59+
echo "github workflow: $github_workflow"
60+
echo "site artifact: $site_artifact"
61+
echo "github timeout: $github_timeout"
62+
echo "extract archive: $extract_archive"
63+
echo "config file: $config_file"
64+
echo "theme ref: $theme_ref"
65+
66+
start_time=$(date +%s)
67+
max_time=$((start_time + 60 * github_timeout))
68+
sleep_interval=10
69+
70+
# fail if the workflow is not set
71+
if [ -z "$github_workflow" ]; then
72+
echo "github_workflow is not set"
73+
exit 1
74+
fi
75+
76+
# fail if the site artifact is not set
77+
if [ -z "$site_artifact" ]; then
78+
echo "site_artifact is not set"
79+
exit 1
80+
fi
81+
82+
project_dir="project"
83+
theme_dir="theme"
84+
85+
mkdir -p "${project_dir}"
86+
87+
git clone https://github.com/LizardByte/LizardByte.github.io.git "${theme_dir}"
88+
pushd "${theme_dir}"
89+
git checkout "${theme_ref}"
90+
git submodule update --init --recursive
91+
popd
92+
93+
encoded_workflow=$(echo "$github_workflow" | sed 's/ /%20/g')
94+
check_api_url="https://api.github.com/repos/${github_user}/${github_repo}/commits/${git_sha}/check-runs?check_name=${encoded_workflow}"
95+
echo "Check API URL: $check_api_url"
96+
97+
# Wait for check runs to be available
98+
count=1
99+
while true; do
100+
current_time=$(date +%s)
101+
if [ $current_time -gt $max_time ]; then
102+
echo "Timeout waiting for check runs"
103+
exit 1
104+
fi
105+
echo "Checking check runs: $count"
106+
107+
response=$(curl -s -H "Accept: application/vnd.github.v3+json" "$check_api_url")
108+
check_runs=$(echo "$response" | jq -r '.check_runs')
109+
check_run_count=$(echo "$check_runs" | jq -r 'length')
110+
111+
echo "Check runs count: $check_run_count"
112+
113+
if [ "$check_run_count" -gt 0 ]; then
114+
check_run=$(echo "$check_runs" | jq -r '.[0]')
115+
check_job_id=$(echo "$check_run" | jq -r '.id')
116+
check_run_html_url=$(echo "$check_run" | jq -r '.html_url')
117+
echo "Check job id: $check_job_id"
118+
echo "Check run URL: $check_run_html_url"
119+
break
120+
fi
121+
122+
echo "Waiting for check runs to be available..."
123+
sleep $sleep_interval
124+
count=$((count + 1))
125+
done
126+
127+
# get the run id from the html url
128+
# e.g. https://github.com/LizardByte/LizardByte.github.io/actions/runs/13687305039/job/38273540489
129+
check_run_id=$(echo "$check_run_html_url" | cut -d/ -f8)
130+
echo "Check run id: $check_run_id"
131+
132+
# wait for the check run to complete, cancelled, timed out, etc.
133+
check_run_api_url="https://api.github.com/repos/${github_user}/${github_repo}/actions/runs/${check_run_id}"
134+
echo "Check run API URL: $check_run_api_url"
135+
136+
count=1
137+
while true; do
138+
current_time=$(date +%s)
139+
if [ $current_time -gt $max_time ]; then
140+
echo "Timeout waiting for check runs"
141+
exit 1
142+
fi
143+
echo "Checking check run status: $count"
144+
145+
check_run_response=$(curl -s -H "Accept: application/vnd.github.v3+json" "$check_run_api_url")
146+
147+
check_run_status=$(echo "$check_run_response" | jq -r '.status')
148+
check_run_conclusion=$(echo "$check_run_response" | jq -r '.conclusion')
149+
150+
echo "Check run status: $check_run_status"
151+
if [ "$check_run_status" == "completed" ]; then
152+
break
153+
fi
154+
155+
echo "Waiting for check run to complete..."
156+
sleep $sleep_interval
157+
count=$((count + 1))
158+
done
159+
160+
# if not successful then exit
161+
if [ "$check_run_conclusion" != "success" ]; then
162+
echo "Check run did not complete successfully"
163+
exit 1
164+
fi
165+
166+
# download the artifact using nightly.link
167+
artifact_url="https://nightly.link/${github_user}/${github_repo}/actions/runs/${check_run_id}/${site_artifact}"
168+
169+
# download and extract the ZIP artifact
170+
curl -sL "$artifact_url" -o "${project_dir}/artifact.zip"
171+
7z x "${project_dir}/artifact.zip" -o"${project_dir}"
172+
rm "${project_dir}/artifact.zip"
173+
174+
# if there is a name provided for extract_artifact, then we will extract the nested archive
175+
if [ -n "$extract_archive" ]; then
176+
pushd "${project_dir}"
177+
case "$extract_archive" in
178+
*.tar.gz|*.tgz)
179+
tar -xzf "$extract_archive" -C .
180+
;;
181+
*.tar)
182+
tar -xf "$extract_archive" -C .
183+
;;
184+
*.zip)
185+
7z x "$extract_archive" -o.
186+
;;
187+
*)
188+
echo "Unsupported archive format"
189+
exit 1
190+
;;
191+
esac
192+
rm -f "$extract_archive"
193+
popd
194+
fi
195+
fi
196+
197+
TMPDIR=$(pwd)/../tmp
198+
mkdir -p "${TMPDIR}"
199+
200+
base_dirs=(
201+
"${theme_dir}/third-party/beautiful-jekyll"
202+
"${theme_dir}"
203+
)
204+
205+
targets=(
206+
*.gemspec
207+
_data
208+
_includes
209+
_layouts
210+
_sass
211+
assets
212+
404.html
213+
_config_theme.yml
214+
favicon.ico
215+
feed.xml
216+
Gemfile
217+
staticman.yml
218+
tags.html
219+
)
220+
221+
for base_dir in "${base_dirs[@]}"; do
222+
for target in "${targets[@]}"; do
223+
if [ -e "$base_dir/$target" ]; then
224+
cp -rf "$base_dir/$target" "${TMPDIR}/"
225+
fi
226+
done
227+
done
228+
229+
# copy project directory, they should only come from the project repo
230+
cp -RTf "${project_dir}/" "${TMPDIR}/"
231+
232+
cd "${TMPDIR}"
233+
234+
gem install bundle
235+
bundle install
236+
echo "baseurl: $READTHEDOCS_VERSION" > _config_rtd.yml
237+
echo "_config_rtd.yml:"
238+
cat _config_rtd.yml
239+
echo "_config_theme.yml:"
240+
cat _config_theme.yml
241+
242+
config_files=_config_rtd.yml,_config_theme.yml
243+
if [ -n "$config_file" ] && [ -e "$config_file" ]; then
244+
config_files="${config_files},$config_file"
245+
echo "config file: $config_file"
246+
cat "$config_file"
247+
fi
248+
249+
bundle exec jekyll build \
250+
--future \
251+
--config $config_files \
252+
--destination "${READTHEDOCS_OUTPUT}html"
253+
254+
# mimic gh-pages
255+
if [ "$sub_project" == "true" ]; then
256+
mkdir -p "${READTHEDOCS_OUTPUT}html/${github_repo}/assets"
257+
cp -RTf "${READTHEDOCS_OUTPUT}html/assets" "${READTHEDOCS_OUTPUT}html/${github_repo}/assets"
258+
fi
259+
260+
echo "Build finished"
261+
echo "Output directory: ${READTHEDOCS_OUTPUT}html"
262+
echo "Listing output directory:"
263+
ls -Ra "$READTHEDOCS_OUTPUT"

0 commit comments

Comments
 (0)