Skip to content

Commit 067ea8a

Browse files
authored
Merge pull request #45 from per1234/versioned-mkdocs
Add template for versioned MkDocs website generation system
2 parents 10714ab + 5e16c3a commit 067ea8a

File tree

5 files changed

+484
-0
lines changed

5 files changed

+484
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
version: "3"
2+
3+
vars:
4+
DOCS_VERSION: dev
5+
DOCS_ALIAS: ""
6+
DOCS_REMOTE: "origin"
7+
8+
tasks:
9+
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/deploy-mkdocs-versioned/Taskfile.yml
10+
docs:publish:
11+
desc: Use Mike to build and push versioned docs
12+
cmds:
13+
- poetry run mike deploy --update-aliases --push --remote {{.DOCS_REMOTE}} {{.DOCS_VERSION}} {{.DOCS_ALIAS}}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# Source:
2+
# https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/deploy-mkdocs-versioned/build.py
3+
4+
# Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
5+
6+
# This software is released under the GNU General Public License version 3
7+
# The terms of this license can be found at:
8+
# https://www.gnu.org/licenses/gpl-3.0.en.html
9+
10+
# You can be released from the requirements of the above licenses by purchasing
11+
# a commercial license. Buying such a license is mandatory if you want to
12+
# modify or otherwise use the software for commercial activities involving the
13+
# Arduino software without disclosing the source code of your own applications.
14+
# To purchase a commercial license, send an email to [email protected].
15+
import os
16+
import sys
17+
import re
18+
import unittest
19+
import subprocess
20+
21+
import click
22+
from git import Repo
23+
24+
# In order to provide support for multiple project releases, Documentation is versioned so that visitors can select
25+
# which version of the documentation website should be displayed. Unfortunately this feature isn't provided by GitHub
26+
# pages or MkDocs, so we had to implement it on top of the generation process.
27+
#
28+
# - A special version of the documentation called `dev` is provided to reflect the status of the project on the
29+
# default branch - this includes unreleased features and bugfixes.
30+
# - Docs are versioned after the minor version of a release. For example, release version `0.99.1` and
31+
# `0.99.2` will be both covered by documentation version `0.99`.
32+
#
33+
# The CI is responsible for guessing which version of the project we're building docs for, so that generated content
34+
# will be stored in the appropriate section of the documentation website. Because this guessing might be fairly complex,
35+
# the logic is implemented in this Python script. The script will determine the version of the project that was
36+
# modified in the current commit (either `dev` or an official, numbered release) and whether the redirect to the latest
37+
# version that happens on the landing page should be updated or not.
38+
39+
40+
DEV_BRANCHES = ["main"] # Name of the branch used for the "dev" website source content
41+
42+
43+
class TestScript(unittest.TestCase):
44+
def test_get_docs_version(self):
45+
ver, alias = get_docs_version("main", [])
46+
self.assertEqual(ver, "dev")
47+
self.assertEqual(alias, "")
48+
49+
release_names = ["1.4.x", "0.13.x"]
50+
ver, alias = get_docs_version("0.13.x", release_names)
51+
self.assertEqual(ver, "0.13")
52+
self.assertEqual(alias, "")
53+
ver, alias = get_docs_version("1.4.x", release_names)
54+
self.assertEqual(ver, "1.4")
55+
self.assertEqual(alias, "latest")
56+
57+
ver, alias = get_docs_version("0.1.x", [])
58+
self.assertIsNone(ver)
59+
self.assertIsNone(alias)
60+
61+
62+
def get_docs_version(ref_name, release_branches):
63+
if ref_name in DEV_BRANCHES:
64+
return "dev", ""
65+
66+
if ref_name in release_branches:
67+
# if version is latest, add an alias
68+
alias = "latest" if ref_name == release_branches[0] else ""
69+
# strip `.x` suffix from the branch name to get the version: 0.3.x -> 0.3
70+
return ref_name[:-2], alias
71+
72+
return None, None
73+
74+
75+
def get_rel_branch_names(blist):
76+
"""Get the names of the release branches, sorted from newest to older.
77+
78+
Only process remote refs so we're sure to get all of them and clean up the
79+
name so that we have a list of strings like 0.6.x, 0.7.x, ...
80+
"""
81+
pattern = re.compile(r"origin/(\d+\.\d+\.x)")
82+
names = []
83+
for b in blist:
84+
res = pattern.search(b.name)
85+
if res is not None:
86+
names.append(res.group(1))
87+
88+
# Since sorting is stable, first sort by major...
89+
names = sorted(names, key=lambda x: int(x.split(".")[0]), reverse=True)
90+
# ...then by minor
91+
return sorted(names, key=lambda x: int(x.split(".")[1]), reverse=True)
92+
93+
94+
@click.command()
95+
@click.option("--test", is_flag=True)
96+
@click.option("--dry", is_flag=True)
97+
@click.option("--remote", default="origin", help="The git remote where to push.")
98+
def main(test, dry, remote):
99+
# Run tests if requested
100+
if test:
101+
unittest.main(argv=[""], exit=False)
102+
sys.exit(0)
103+
104+
# Detect repo root folder
105+
here = os.path.dirname(os.path.realpath(__file__))
106+
repo_dir = os.path.join(here, "..")
107+
108+
# Get current repo
109+
repo = Repo(repo_dir)
110+
111+
# Get the list of release branch names
112+
rel_br_names = get_rel_branch_names(repo.refs)
113+
114+
# Deduce docs version from current branch. Use the 'latest' alias if
115+
# version is the most recent
116+
docs_version, alias = get_docs_version(repo.active_branch.name, rel_br_names)
117+
if docs_version is None:
118+
print(f"Can't get version from current branch '{repo.active_branch}', skip docs generation")
119+
return 0
120+
121+
# Taskfile args aren't regular args so we put everything in one string
122+
cmd = (f"task docs:publish DOCS_REMOTE={remote} DOCS_VERSION={docs_version} DOCS_ALIAS={alias}",)
123+
124+
if dry:
125+
print(cmd)
126+
return 0
127+
128+
subprocess.run(cmd, shell=True, check=True, cwd=repo_dir)
129+
130+
131+
# Usage:
132+
#
133+
# To run the tests:
134+
# $python build.py --test
135+
#
136+
# To run the script (must be run from within the repo tree):
137+
# $python build.py
138+
#
139+
if __name__ == "__main__":
140+
sys.exit(main())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/deploy-mkdocs-versioned-poetry.md
2+
name: Deploy Website
3+
4+
on:
5+
push:
6+
branches:
7+
# Branch to base "dev" website on. Set in build.py also.
8+
- main
9+
# Release branches have names like 0.8.x, 0.9.x, ...
10+
- "[0-9]+.[0-9]+.x"
11+
paths:
12+
- "docs/**"
13+
- ".github/workflows/deploy-mkdocs-versioned-poetry.ya?ml"
14+
- "Taskfile.ya?ml"
15+
- "mkdocs.ya?ml"
16+
- "poetry.lock"
17+
- "pyproject.toml"
18+
# Run on branch or tag creation (will be filtered by the publish-determination job).
19+
create:
20+
21+
jobs:
22+
publish-determination:
23+
runs-on: ubuntu-latest
24+
outputs:
25+
result: ${{ steps.determination.outputs.result }}
26+
steps:
27+
- name: Determine if documentation should be published on this workflow run
28+
id: determination
29+
run: |
30+
RELEASE_BRANCH_REGEX="refs/heads/[0-9]+.[0-9]+.x"
31+
if [[ "${{ github.event_name }}" == "push" || ( "${{ github.event_name }}" == "create" && "${{ github.ref }}" =~ $RELEASE_BRANCH_REGEX ) ]]; then
32+
RESULT="true"
33+
else
34+
RESULT="false"
35+
fi
36+
37+
echo "::set-output name=result::$RESULT"
38+
39+
publish:
40+
runs-on: ubuntu-latest
41+
needs: publish-determination
42+
if: needs.publish-determination.outputs.result == 'true'
43+
44+
steps:
45+
- name: Checkout repository
46+
uses: actions/checkout@v2
47+
48+
- name: Install Taskfile
49+
uses: arduino/setup-task@v1
50+
with:
51+
repo-token: ${{ secrets.GITHUB_TOKEN }}
52+
version: 3.x
53+
54+
- name: Install Python
55+
uses: actions/setup-python@v2
56+
with:
57+
python-version: "3.9"
58+
59+
- name: Cache dependencies
60+
uses: actions/cache@v2
61+
with:
62+
path: ~/.cache/pip
63+
key: ${{ runner.os }}-pip-${{ hashFiles('./pyproject.toml') }}
64+
restore-keys: |
65+
${{ runner.os }}-pip-
66+
67+
- name: Install Poetry
68+
run: |
69+
python -m pip install --upgrade pip
70+
python -m pip install poetry
71+
72+
- name: Install Python dependencies
73+
run: poetry install --no-root
74+
75+
- name: Publish documentation
76+
# Determine docs version for the commit pushed and publish accordingly using Mike.
77+
# Publishing implies creating a git commit on the gh-pages branch, we let @ArduinoBot own these commits.
78+
run: |
79+
git config --global user.email "[email protected]"
80+
git config --global user.name "ArduinoBot"
81+
git fetch --no-tags --prune --depth=1 origin +refs/heads/gh-pages:refs/remotes/origin/gh-pages
82+
poetry run python docs/build.py

0 commit comments

Comments
 (0)