Add fix-branch-references task
- add nox session "fix-branch-references" + the session is a task executed in the normal develop environment + it rewrites all branch labels in links in *.ipynb and *.md files
This commit is contained in:
parent
3b9fc59cb6
commit
d88dc0f91c
1 changed files with 117 additions and 2 deletions
119
noxfile.py
119
noxfile.py
|
@ -1,9 +1,24 @@
|
|||
"""Configure nox as the task runner."""
|
||||
"""Configure nox as the task runner.
|
||||
|
||||
Nox provides the following tasks:
|
||||
|
||||
- "fix-branch-references": adjusts links with git branch references in
|
||||
various files (e.g., Mardown or notebooks)
|
||||
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
import nox
|
||||
|
||||
|
||||
PYTHON = "3.8"
|
||||
REPOSITORY = "webartifex/intro-to-python"
|
||||
|
||||
# Use a unified .cache/ folder for all develop tools.
|
||||
nox.options.envdir = ".cache/nox"
|
||||
|
@ -11,3 +26,103 @@ nox.options.envdir = ".cache/nox"
|
|||
# All tools except git and poetry are project dependencies.
|
||||
# Avoid accidental successes if the environment is not set up properly.
|
||||
nox.options.error_on_external_run = True
|
||||
|
||||
|
||||
@nox.session(name="fix-branch-references", venv_backend="none")
|
||||
def fix_branch_references(_session):
|
||||
"""Change git branch references.
|
||||
|
||||
Intended to be run as a pre-commit hook.
|
||||
|
||||
Many files in the project (e.g., README.md) contain links to resources on
|
||||
github.com, nbviewer.jupyter.org, or mybinder.org that contain git branch
|
||||
labels.
|
||||
|
||||
This task rewrites branch labels into either "main" or "develop".
|
||||
"""
|
||||
# Glob patterns that expand into the files whose links are re-written.
|
||||
paths = ["*.md", "**/*.ipynb"]
|
||||
|
||||
branch = (
|
||||
subprocess.check_output(
|
||||
("git", "rev-parse", "--abbrev-ref", "HEAD"),
|
||||
)
|
||||
.decode()
|
||||
.strip()
|
||||
)
|
||||
# If the current branch is only temporary and will be merged into "main", ...
|
||||
if branch.startswith("release-") or branch.startswith("hotfix-"):
|
||||
branch = "main"
|
||||
# If the branch is not "main", we assume it is a feature branch.
|
||||
elif branch != "main":
|
||||
branch = "develop"
|
||||
|
||||
rewrites = [
|
||||
{
|
||||
"name": "github",
|
||||
"pattern": re.compile(
|
||||
fr"((((http)|(https))://github\.com/{REPOSITORY}/((blob)|(tree))/)([\w-]+)/)"
|
||||
),
|
||||
"replacement": fr"\2{branch}/",
|
||||
},
|
||||
{
|
||||
"name": "nbviewer",
|
||||
"pattern": re.compile(
|
||||
fr"((((http)|(https))://nbviewer\.jupyter\.org/github/{REPOSITORY}/((blob)|(tree))/)([\w-]+)/)",
|
||||
),
|
||||
"replacement": fr"\2{branch}/",
|
||||
},
|
||||
{
|
||||
"name": "mybinder",
|
||||
"pattern": re.compile(
|
||||
fr"((((http)|(https))://mybinder\.org/v2/gh/{REPOSITORY}/)([\w-]+)\?)",
|
||||
),
|
||||
"replacement": fr"\2{branch}?",
|
||||
},
|
||||
]
|
||||
|
||||
for expanded in _expand(*paths):
|
||||
with _line_by_line_replace(expanded) as (old_file, new_file):
|
||||
for line in old_file:
|
||||
for rewrite in rewrites:
|
||||
line = re.sub(rewrite["pattern"], rewrite["replacement"], line)
|
||||
new_file.write(line)
|
||||
|
||||
|
||||
def _expand(*patterns):
|
||||
"""Expand glob patterns into paths.
|
||||
|
||||
Args:
|
||||
*patterns: the patterns to be expanded
|
||||
|
||||
Yields:
|
||||
path: a single expanded path
|
||||
"""
|
||||
for pattern in patterns:
|
||||
yield from glob.glob(pattern.strip())
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _line_by_line_replace(path):
|
||||
"""Replace/change the lines in a file one by one.
|
||||
|
||||
This generator function yields two file handles, one to the current file
|
||||
(i.e., `old_file`) and one to its replacement (i.e., `new_file`).
|
||||
|
||||
Usage: loop over the lines in `old_file` and write the files to be kept
|
||||
to `new_file`. Files not written to `new_file` are removed!
|
||||
|
||||
Args:
|
||||
path: the file whose lines are to be replaced
|
||||
|
||||
Yields:
|
||||
old_file, new_file: handles to a file and its replacement
|
||||
"""
|
||||
file_handle, new_file_path = tempfile.mkstemp()
|
||||
with os.fdopen(file_handle, "w") as new_file:
|
||||
with open(path) as old_file:
|
||||
yield old_file, new_file
|
||||
|
||||
shutil.copymode(path, new_file_path)
|
||||
os.remove(path)
|
||||
shutil.move(new_file_path, path)
|
||||
|
|
Loading…
Reference in a new issue