Skip to content

Commit 4117d9a

Browse files
committed
Add CI workflow to deploy a versioned MkDocs-based website to GitHub Pages
On every push to the repository's default branch or release branch, deploy the repository's MkDocs-based static website to GitHub Pages. Documentation content will sometimes apply only to a specific version of the project. For this reason, it's important for the reader to be able to access the documentation for the specific version of the project they are using. The documentation system provides access to: - The tip of the default branch ("dev") - The latest release ("latest") - Each minor version series (e.g., "1.2") The website version is selectable via a menu on the website as well as the URL of each documentation page.
1 parent 31c1fcc commit 4117d9a

File tree

9 files changed

+677
-8
lines changed

9 files changed

+677
-8
lines changed

.github/workflows/publish-docs.yaml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: publish-docs
2+
3+
on:
4+
push:
5+
branches:
6+
# Branch to base "dev" website on. Set in build.py also.
7+
- main
8+
# release branches have names like 0.8.x, 0.9.x, ...
9+
- "[0-9]+.[0-9]+.x"
10+
paths:
11+
- "docs/**"
12+
- "docsgen/**"
13+
- "cli/**"
14+
- ".github/workflows/publish-docs.ya?ml"
15+
- "Taskfile.ya?ml"
16+
- "mkdocs.ya?ml"
17+
- "poetry.lock"
18+
- "pyproject.toml"
19+
# Run on branch or tag creation (will be filtered by the publish-determination job)
20+
create:
21+
22+
jobs:
23+
publish-determination:
24+
runs-on: ubuntu-latest
25+
outputs:
26+
result: ${{ steps.determination.outputs.result }}
27+
steps:
28+
- name: Determine if documentation should be published on this workflow run
29+
id: determination
30+
run: |
31+
RELEASE_BRANCH_REGEX="refs/heads/[0-9]+.[0-9]+.x"
32+
if [[ "${{ github.event_name }}" == "push" || ( "${{ github.event_name }}" == "create" && "${{ github.ref }}" =~ $RELEASE_BRANCH_REGEX ) ]]; then
33+
RESULT="true"
34+
else
35+
RESULT="false"
36+
fi
37+
38+
echo "::set-output name=result::$RESULT"
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
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: Setup Go
55+
uses: actions/setup-go@v2
56+
with:
57+
go-version: "1.16"
58+
59+
- name: Install Python
60+
uses: actions/setup-python@v2
61+
with:
62+
python-version: "3.8"
63+
64+
- name: Install Python dependencies
65+
run: |
66+
python -m pip install --upgrade pip
67+
python -m pip install poetry
68+
69+
- name: Install Python dependencies
70+
poetry install --no-root
71+
72+
- name: Publish docs
73+
# Determine docs version for the commit pushed and publish accordingly using Mike.
74+
# Publishing implies creating a git commit on the gh-pages branch, we let @ArduinoBot own these commits.
75+
run: |
76+
git config --global user.email "bot@arduino.cc"
77+
git config --global user.name "ArduinoBot"
78+
git fetch --no-tags --prune --depth=1 origin +refs/heads/gh-pages:refs/remotes/origin/gh-pages
79+
poetry run python docs/build/build.py

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,8 @@ __pycache__/
88

99
# Misc.
1010
.DS_Store
11+
12+
# Mkdocs
13+
/site/
14+
/docsgen/arduino-fwuploader
15+
/docs/commands/*.md

Taskfile.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,25 @@ includes:
44
dist: ./DistTasks.yml
55

66
tasks:
7+
docs:publish:
8+
desc: Use Mike to build and push versioned docs
9+
deps:
10+
- docs:gen:commands
11+
cmds:
12+
- poetry run mike deploy --update-aliases --push --remote {{.DOCS_REMOTE}} {{.DOCS_VERSION}} {{.DOCS_ALIAS}}
13+
14+
docs:gen:commands:
15+
desc: Generate command reference files
16+
dir: ./docsgen
17+
cmds:
18+
# docs will generate examples using os.Args[0] so we need to call
19+
# the generator `arduino-cli`
20+
- go build -o {{.PROJECT_NAME}}
21+
# we invoke `arduino-cli` like this instead of `./arduino-cli` to remove
22+
# the `./` chars from the examples
23+
- PATH=. {{.PROJECT_NAME}} ../docs/commands
24+
- task: docs:format
25+
726
docs:check:
827
desc: Run documentation linting
928
cmds:
@@ -126,3 +145,6 @@ vars:
126145
sh: go list -f {{"{{"}}".Target{{"}}"}}" golang.org/x/lint/golint
127146
GOLINTFLAGS: "-min_confidence 0.8 -set_exit_status"
128147
PRETTIER: prettier@2.0.5
148+
DOCS_VERSION: dev
149+
DOCS_ALIAS: ""
150+
DOCS_REMOTE: "origin"

docs/build/build.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Source:
2+
# https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/deploy-mkdocs-versioned/build/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 license@arduino.cc.
15+
import os
16+
import sys
17+
import re
18+
import subprocess
19+
20+
import click
21+
from git import Repo
22+
23+
# In order to provide support for multiple project releases, Documentation is versioned so that visitors can select
24+
# which version of the documentation website should be displayed. Unfortunately this feature isn't provided by GitHub
25+
# pages or MkDocs, so we had to implement it on top of the generation process.
26+
#
27+
# - A special version of the documentation called `dev` is provided to reflect the status of the project on the
28+
# default branch - this includes unreleased features and bugfixes.
29+
# - Docs are versioned after the minor version of a release. For example, release version `0.99.1` and
30+
# `0.99.2` will be both covered by documentation version `0.99`.
31+
#
32+
# The CI is responsible for guessing which version of the project we're building docs for, so that generated content
33+
# will be stored in the appropriate section of the documentation website. Because this guessing might be fairly complex,
34+
# the logic is implemented in this Python script. The script will determine the version of the project that was
35+
# modified in the current commit (either `dev` or an official, numbered release) and whether the redirect to the latest
36+
# version that happens on the landing page should be updated or not.
37+
38+
39+
DEV_BRANCHES = ["main"] # Name of the branch used for the "dev" website source content
40+
41+
42+
def get_docs_version(ref_name, release_branches):
43+
if ref_name in DEV_BRANCHES:
44+
return "dev", ""
45+
46+
if ref_name in release_branches:
47+
# if version is latest, add an alias
48+
alias = "latest" if ref_name == release_branches[0] else ""
49+
# strip `.x` suffix from the branch name to get the version: 0.3.x -> 0.3
50+
return ref_name[:-2], alias
51+
52+
return None, None
53+
54+
55+
def get_rel_branch_names(blist):
56+
"""Get the names of the release branches, sorted from newest to older.
57+
Only process remote refs so we're sure to get all of them and clean up the
58+
name so that we have a list of strings like 0.6.x, 0.7.x, ...
59+
"""
60+
pattern = re.compile(r"origin/(\d+\.\d+\.x)")
61+
names = []
62+
for b in blist:
63+
res = pattern.search(b.name)
64+
if res is not None:
65+
names.append(res.group(1))
66+
67+
# Since sorting is stable, first sort by major...
68+
names = sorted(names, key=lambda x: int(x.split(".")[0]), reverse=True)
69+
# ...then by minor
70+
return sorted(names, key=lambda x: int(x.split(".")[1]), reverse=True)
71+
72+
73+
@click.command()
74+
@click.option("--dry", is_flag=True)
75+
@click.option("--remote", default="origin", help="The git remote where to push.")
76+
def main(dry, remote):
77+
# Detect repo root folder
78+
here = os.path.dirname(os.path.realpath(__file__))
79+
repo_dir = os.path.join(here, "..", "..")
80+
81+
# Get current repo
82+
repo = Repo(repo_dir)
83+
84+
# Get the list of release branch names
85+
rel_br_names = get_rel_branch_names(repo.refs)
86+
87+
# Deduce docs version from current branch. Use the 'latest' alias if
88+
# version is the most recent
89+
docs_version, alias = get_docs_version(repo.active_branch.name, rel_br_names)
90+
if docs_version is None:
91+
print(f"Can't get version from current branch '{repo.active_branch}', skip docs generation")
92+
return 0
93+
94+
# Taskfile args aren't regular args so we put everything in one string
95+
cmd = (f"task docs:publish DOCS_REMOTE={remote} DOCS_VERSION={docs_version} DOCS_ALIAS={alias}",)
96+
97+
if dry:
98+
print(cmd)
99+
return 0
100+
101+
subprocess.run(cmd, shell=True, check=True, cwd=repo_dir)
102+
103+
104+
# Usage:
105+
# To run the script (must be run from within the repo tree):
106+
# $python build.py
107+
#
108+
if __name__ == "__main__":
109+
sys.exit(main())

docs/commands/.gitkeep

Whitespace-only changes.

docsgen/main.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
arduino-fwuploader
3+
Copyright (c) 2021 Arduino LLC. All right reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package main
21+
22+
import (
23+
"log"
24+
"os"
25+
26+
"github.com/arduino/arduino-fwuploader/cli"
27+
"github.com/spf13/cobra/doc"
28+
)
29+
30+
func main() {
31+
if len(os.Args) < 2 {
32+
log.Fatal("Please provide output folder")
33+
}
34+
35+
cli := cli.NewCommand()
36+
cli.DisableAutoGenTag = true // Disable addition of auto-generated date stamp
37+
err := doc.GenMarkdownTree(cli, os.Args[1])
38+
if err != nil {
39+
log.Fatal(err)
40+
}
41+
}

go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
6262
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
6363
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
6464
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
65+
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
6566
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
6667
github.com/creack/goselect v0.1.1 h1:tiSSgKE1eJtxs1h/VgGQWuXUP0YS4CDIFMp6vaI1ls0=
6768
github.com/creack/goselect v0.1.1/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
@@ -253,6 +254,7 @@ github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnH
253254
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
254255
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
255256
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
257+
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
256258
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
257259
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
258260
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
@@ -262,6 +264,7 @@ github.com/segmentio/objconv v1.0.1/go.mod h1:auayaH5k3137Cl4SoXTgrzQcuQDmvuVtZg
262264
github.com/segmentio/stats/v4 v4.5.3/go.mod h1:LsaahUJR7iiSs8mnkvQvdQ/RLHAS5adGLxuntg0ydGo=
263265
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
264266
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
267+
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
265268
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
266269
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
267270
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=

0 commit comments

Comments
 (0)