Skip to content

Commit 02ced7b

Browse files
committed
Proof-of-Concept for testing code samples
There are a number of code samples throughout nix.dev. How do we know they still work? We don't! This commit introduces a way for us to extract these code samples into files and then run tests against them in CI. This will hopefully help us catch regressions in future updates to nix, NixOS and/or this guide. Additionally, I included a darwin specific nix-shell configuration that I use personally on my M1 Mac to work on this repo. Might be useful for someone.
1 parent e6bcbd4 commit 02ced7b

File tree

7 files changed

+264
-110
lines changed

7 files changed

+264
-110
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ jobs:
2121
run: nix-build
2222
- name: Linkcheck
2323
run: nix-shell --run "make linkcheck"
24+
- name: Run code block tests
25+
run: nix-shell --run "./run_code_block_tests.sh"

.gitignore

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
result
1+
.direnv/
2+
.envrc
23
build/
4+
extracted/
35
requirements_frozen.txt
4-
5-
6+
result
7+
source/_ext/__pycache__/
8+
TODO.txt

run_code_block_tests.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
find extracted -name "test_*" -exec echo "running {}" \; -execdir {} \;

shell-darwin.nix

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# @zupo uses this file to work on nix.dev on his M1 Monterey
2+
3+
let
4+
nixpkgs = builtins.fetchTarball {
5+
# https://status.nixos.org/ -> nixos-21.11 on 2022-04-06
6+
url = "https://github.com/nixos/nixpkgs/archive/ccb90fb9e11459aeaf83cc28d5f8910816d90dd0.tar.gz";
7+
};
8+
pkgs = import nixpkgs {};
9+
poetry2nix = import (fetchTarball {
10+
# https://github.com/nix-community/poetry2nix/commits/master on 2022-04-06
11+
url = "https://github.com/nix-community/poetry2nix/archive/99c79568352799af09edaeefc858d337e6d9c56f.tar.gz";
12+
}) {
13+
pkgs = pkgs;
14+
};
15+
16+
env = poetry2nix.mkPoetryEnv {
17+
pyproject = ./pyproject.toml;
18+
poetrylock = ./poetry.lock;
19+
editablePackageSources = {};
20+
};
21+
in
22+
23+
pkgs.mkShell {
24+
name = "dev-shell";
25+
buildInputs = [
26+
env
27+
pkgs.poetry
28+
];
29+
30+
}

source/_ext/extractable_code_block.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
from docutils import nodes
2+
from docutils.nodes import Node
3+
from docutils.parsers.rst import Directive
4+
from docutils.parsers.rst import directives
5+
from sphinx.directives import optional_int
6+
from sphinx.directives.code import CodeBlock
7+
from sphinx.util import logging
8+
from sphinx.util.typing import OptionSpec
9+
from typing import List
10+
11+
import os
12+
import stat
13+
14+
logger = logging.getLogger(__name__)
15+
16+
17+
class ExtractableCodeBlock(CodeBlock):
18+
"""A custom directive to extract code blocks into files.
19+
20+
We want our code samples to be tested in CI. This class overrides the
21+
default `code-block` to allow passing a second argument: the filename
22+
to extract the code block to.
23+
24+
Out-of-the-box Sphinx behaviour:
25+
26+
```python
27+
foo = "bar"
28+
```
29+
30+
Additional extraction of a code block in `mydoc.md` file into
31+
`./extracted/mydoc/foo.py` file:
32+
33+
```python foo.py
34+
foo = "bar"
35+
```
36+
"""
37+
38+
EXTRACT_DIR = "extracted"
39+
optional_arguments = 2
40+
41+
def run(self) -> List[Node]:
42+
# This is out-of-the-box usage of code-blocks, with a single
43+
# argument: the programming language
44+
# Don't do any extraction
45+
if len(self.arguments) < 2:
46+
return super(ExtractableCodeBlock, self).run()
47+
48+
location = self.state_machine.get_source_and_line(self.lineno)
49+
50+
path = os.path.join(
51+
# top-level dir containing extracted code blocks
52+
self.EXTRACT_DIR,
53+
# subdir containing extracted code blocks from a single .md file
54+
os.path.splitext(os.path.basename(self.state.document.current_source))[0],
55+
# file name of the extracted code block
56+
self.arguments[1],
57+
)
58+
logger.info(
59+
f"Extracting code block into {path}",
60+
location=location,
61+
)
62+
os.makedirs(os.path.dirname(path), exist_ok=True)
63+
with open(path, "w") as f:
64+
f.write(self.block_text)
65+
66+
# make bash scripts executable
67+
if path.endswith(".sh"):
68+
st = os.stat(path)
69+
os.chmod(path, st.st_mode | stat.S_IEXEC)
70+
71+
return super(ExtractableCodeBlock, self).run()
72+
73+
74+
def setup(app):
75+
app.add_directive("code-block", ExtractableCodeBlock, override=True)
76+
77+
return {
78+
"version": "0.1",
79+
"parallel_read_safe": True,
80+
"parallel_write_safe": True,
81+
}

0 commit comments

Comments
 (0)