rundot 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rundot-0.6.0/.github/workflows/ci.yml +65 -0
- rundot-0.6.0/.gitignore +21 -0
- rundot-0.6.0/.python-version +1 -0
- rundot-0.6.0/CHANGELOG.md +67 -0
- rundot-0.6.0/CLAUDE.md +9 -0
- rundot-0.6.0/CODE_OF_CONDUCT.md +32 -0
- rundot-0.6.0/CONTRIBUTING.md +158 -0
- rundot-0.6.0/CONTRIBUTORS.md +3 -0
- rundot-0.6.0/LICENSE +21 -0
- rundot-0.6.0/Makefile +49 -0
- rundot-0.6.0/PKG-INFO +132 -0
- rundot-0.6.0/PUBLISHING.md +134 -0
- rundot-0.6.0/README.md +115 -0
- rundot-0.6.0/SECURITY.md +11 -0
- rundot-0.6.0/docs/CHANGELOG.md +67 -0
- rundot-0.6.0/docs/CNAME +1 -0
- rundot-0.6.0/docs/backends.md +248 -0
- rundot-0.6.0/docs/cli.md +306 -0
- rundot-0.6.0/docs/demo.svg +88 -0
- rundot-0.6.0/docs/example.png +0 -0
- rundot-0.6.0/docs/index.md +136 -0
- rundot-0.6.0/docs/install.md +42 -0
- rundot-0.6.0/docs/library.md +101 -0
- rundot-0.6.0/docs/runbook-format.md +281 -0
- rundot-0.6.0/examples/clientele-publishing.md +160 -0
- rundot-0.6.0/examples/hello.md +30 -0
- rundot-0.6.0/mkdocs.yml +48 -0
- rundot-0.6.0/pyproject.toml +175 -0
- rundot-0.6.0/rundot/__init__.py +0 -0
- rundot-0.6.0/rundot/backends/__init__.py +244 -0
- rundot-0.6.0/rundot/backends/python.py +51 -0
- rundot-0.6.0/rundot/backends/shell.py +80 -0
- rundot-0.6.0/rundot/cli.py +513 -0
- rundot-0.6.0/rundot/inputs.py +88 -0
- rundot-0.6.0/rundot/library.py +69 -0
- rundot-0.6.0/rundot/runbook.py +216 -0
- rundot-0.6.0/rundot/runner.py +305 -0
- rundot-0.6.0/rundot/settings.py +3 -0
- rundot-0.6.0/rundot/transcript.py +139 -0
- rundot-0.6.0/rundot/validate.py +323 -0
- rundot-0.6.0/specs/SPEC-0.2.0.md +263 -0
- rundot-0.6.0/specs/SPEC-0.3.0.md +91 -0
- rundot-0.6.0/specs/SPEC-0.6.0.md +32 -0
- rundot-0.6.0/specs/SPEC.md +370 -0
- rundot-0.6.0/tasks/plan-0.2.0.md +126 -0
- rundot-0.6.0/tasks/plan-0.3.0.md +35 -0
- rundot-0.6.0/tasks/plan-0.6.0.md +26 -0
- rundot-0.6.0/tasks/plan.md +121 -0
- rundot-0.6.0/tasks/todo-0.2.0.md +349 -0
- rundot-0.6.0/tasks/todo-0.3.0.md +64 -0
- rundot-0.6.0/tasks/todo-0.6.0.md +45 -0
- rundot-0.6.0/tasks/todo.md +488 -0
- rundot-0.6.0/tests/__init__.py +0 -0
- rundot-0.6.0/tests/backends/__init__.py +0 -0
- rundot-0.6.0/tests/backends/test_python.py +205 -0
- rundot-0.6.0/tests/backends/test_shell.py +336 -0
- rundot-0.6.0/tests/conftest.py +52 -0
- rundot-0.6.0/tests/library/say-where.md +24 -0
- rundot-0.6.0/tests/library/update-project-deps.md +31 -0
- rundot-0.6.0/tests/output.py +52 -0
- rundot-0.6.0/tests/runbooks/all_features.md +72 -0
- rundot-0.6.0/tests/runbooks/broken/block-before-first-step.md +15 -0
- rundot-0.6.0/tests/runbooks/broken/choice-does-not-match-pattern.md +14 -0
- rundot-0.6.0/tests/runbooks/broken/choices-not-a-list-of-strings.md +13 -0
- rundot-0.6.0/tests/runbooks/broken/choices-on-a-secret.md +14 -0
- rundot-0.6.0/tests/runbooks/broken/default-does-not-match-pattern.md +14 -0
- rundot-0.6.0/tests/runbooks/broken/default-not-a-string.md +13 -0
- rundot-0.6.0/tests/runbooks/broken/default-not-one-of-the-choices.md +14 -0
- rundot-0.6.0/tests/runbooks/broken/default-on-a-secret.md +14 -0
- rundot-0.6.0/tests/runbooks/broken/duplicate-input-name.md +14 -0
- rundot-0.6.0/tests/runbooks/broken/input-block-before-first-step.md +14 -0
- rundot-0.6.0/tests/runbooks/broken/input-block-env-used-before.md +20 -0
- rundot-0.6.0/tests/runbooks/broken/input-block-in-output-path.md +15 -0
- rundot-0.6.0/tests/runbooks/broken/input-block-invalid-yaml.md +10 -0
- rundot-0.6.0/tests/runbooks/broken/input-block-missing-description.md +13 -0
- rundot-0.6.0/tests/runbooks/broken/input-block-name-already-declared.md +17 -0
- rundot-0.6.0/tests/runbooks/broken/input-block-not-a-mapping.md +10 -0
- rundot-0.6.0/tests/runbooks/broken/input-block-placeholder-used-before.md +20 -0
- rundot-0.6.0/tests/runbooks/broken/input-missing-description.md +11 -0
- rundot-0.6.0/tests/runbooks/broken/input-missing-name.md +11 -0
- rundot-0.6.0/tests/runbooks/broken/input-name-not-upper-snake-case.md +12 -0
- rundot-0.6.0/tests/runbooks/broken/invalid-pattern.md +13 -0
- rundot-0.6.0/tests/runbooks/broken/missing-title.md +9 -0
- rundot-0.6.0/tests/runbooks/broken/python-not-on-path.md +10 -0
- rundot-0.6.0/tests/runbooks/broken/python-syntax-error.md +11 -0
- rundot-0.6.0/tests/runbooks/broken/run-block-with-no-backend.md +9 -0
- rundot-0.6.0/tests/runbooks/broken/secret-as-placeholder.md +13 -0
- rundot-0.6.0/tests/runbooks/broken/shell-syntax-error.md +11 -0
- rundot-0.6.0/tests/runbooks/broken/step-not-true-or-false.md +10 -0
- rundot-0.6.0/tests/runbooks/broken/title-not-a-string.md +11 -0
- rundot-0.6.0/tests/runbooks/broken/undeclared-placeholder-in-confirm.md +9 -0
- rundot-0.6.0/tests/runbooks/broken/undeclared-placeholder-in-docstring.md +9 -0
- rundot-0.6.0/tests/runbooks/broken/undeclared-placeholder-in-output-path.md +10 -0
- rundot-0.6.0/tests/runbooks/broken/undeclared-placeholder.md +10 -0
- rundot-0.6.0/tests/runbooks/broken-body.md +21 -0
- rundot-0.6.0/tests/runbooks/choices-example.md +33 -0
- rundot-0.6.0/tests/runbooks/default-example.md +35 -0
- rundot-0.6.0/tests/runbooks/docstring-and-confirm-example.md +42 -0
- rundot-0.6.0/tests/runbooks/dry-run-example.md +43 -0
- rundot-0.6.0/tests/runbooks/input-block-example.md +53 -0
- rundot-0.6.0/tests/runbooks/inputs-example.md +42 -0
- rundot-0.6.0/tests/runbooks/minimal.md +9 -0
- rundot-0.6.0/tests/runbooks/python-example.md +45 -0
- rundot-0.6.0/tests/runbooks/step-example.md +37 -0
- rundot-0.6.0/tests/runbooks/step-frontmatter-example.md +34 -0
- rundot-0.6.0/tests/runbooks/transcript-example.md +46 -0
- rundot-0.6.0/tests/runbooks/two_steps.md +29 -0
- rundot-0.6.0/tests/test_backend_loading.py +132 -0
- rundot-0.6.0/tests/test_cli.py +2040 -0
- rundot-0.6.0/tests/test_docs.py +174 -0
- rundot-0.6.0/tests/test_examples.py +86 -0
- rundot-0.6.0/tests/test_inputs.py +249 -0
- rundot-0.6.0/tests/test_interrupt.py +364 -0
- rundot-0.6.0/tests/test_library.py +175 -0
- rundot-0.6.0/tests/test_output.py +22 -0
- rundot-0.6.0/tests/test_runbook.py +810 -0
- rundot-0.6.0/tests/test_runner.py +1516 -0
- rundot-0.6.0/tests/test_transcript.py +490 -0
- rundot-0.6.0/tests/test_validate.py +874 -0
- rundot-0.6.0/uv.lock +964 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: CI - Lint and Test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.12", "3.13", "3.14", "3.15-dev"]
|
|
15
|
+
steps:
|
|
16
|
+
#----------------------------------------------
|
|
17
|
+
# check-out repo and set-up python
|
|
18
|
+
#----------------------------------------------
|
|
19
|
+
- name: Check out repository
|
|
20
|
+
uses: actions/checkout@v7
|
|
21
|
+
- name: Set up python
|
|
22
|
+
id: setup-python
|
|
23
|
+
uses: actions/setup-python@v7
|
|
24
|
+
with:
|
|
25
|
+
python-version: ${{matrix.python-version}}
|
|
26
|
+
#----------------------------------------------
|
|
27
|
+
# ----- install & configure uv -----
|
|
28
|
+
#----------------------------------------------
|
|
29
|
+
# Pointing uv at the interpreter setup-python installed overrides .python-version,
|
|
30
|
+
# which would otherwise make every matrix entry run on 3.14.
|
|
31
|
+
- name: Install UV
|
|
32
|
+
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
33
|
+
with:
|
|
34
|
+
python-version: ${{ steps.setup-python.outputs.python-path }}
|
|
35
|
+
enable-cache: true
|
|
36
|
+
cache-dependency-glob: "uv.lock"
|
|
37
|
+
|
|
38
|
+
#----------------------------------------------
|
|
39
|
+
# install dependencies
|
|
40
|
+
#----------------------------------------------
|
|
41
|
+
- name: Install dependencies
|
|
42
|
+
run: uv sync --frozen
|
|
43
|
+
- name: Show Python version
|
|
44
|
+
run: uv run python --version
|
|
45
|
+
#----------------------------------------------
|
|
46
|
+
# Run linting and tests
|
|
47
|
+
#----------------------------------------------
|
|
48
|
+
- name: Ruff format check
|
|
49
|
+
run: |
|
|
50
|
+
uv run ruff format --check .
|
|
51
|
+
- name: Ruff linting
|
|
52
|
+
run: |
|
|
53
|
+
uv run ruff check .
|
|
54
|
+
- name: Type check with ty
|
|
55
|
+
run: |
|
|
56
|
+
uv run ty check
|
|
57
|
+
- name: Check import contracts
|
|
58
|
+
run: |
|
|
59
|
+
make lint-imports
|
|
60
|
+
- name: Build docs
|
|
61
|
+
run: |
|
|
62
|
+
uv run zensical build --strict
|
|
63
|
+
- name: Test with pytest
|
|
64
|
+
run: |
|
|
65
|
+
uv run pytest -vv --cov=rundot --cov-branch --cov-report=term-missing --cov-config=pyproject.toml
|
rundot-0.6.0/.gitignore
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
.ty_cache/
|
|
3
|
+
.ruff_cache/
|
|
4
|
+
.import_linter_cache/
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
.idea/
|
|
7
|
+
__pycache__
|
|
8
|
+
.DS_Store
|
|
9
|
+
dist/
|
|
10
|
+
site/
|
|
11
|
+
htmlcov/
|
|
12
|
+
*.coverage*
|
|
13
|
+
coverage.xml
|
|
14
|
+
.cache/
|
|
15
|
+
|
|
16
|
+
# Transcripts written by running the fixture runbooks by hand
|
|
17
|
+
tests/runbooks/logs/
|
|
18
|
+
|
|
19
|
+
# Transcripts written by releasing rundot with PUBLISHING.md, or running the examples by hand
|
|
20
|
+
/logs/
|
|
21
|
+
examples/logs/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Change log
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
- **Breaking:** paulrun is now called rundot. Install it as `rundot`, and run it as `rundot` instead of `paulrun`. Subcommands and flags are unchanged.
|
|
6
|
+
- The package is `rundot`, so imports are `from rundot.backends import ...`.
|
|
7
|
+
- Backends register in the `rundot.backends` entry point group, which was `paulrun.backends`.
|
|
8
|
+
- `PAULRUN_LIBRARY` is now `RUNDOT_LIBRARY`.
|
|
9
|
+
- `PAULRUN_RUNBOOK_DIR`, set for blocks, is now `RUNDOT_RUNBOOK_DIR`.
|
|
10
|
+
- The docs are at [docs.rundot.dev](https://docs.rundot.dev/) and the code at [github.com/phalt/rundot](https://github.com/phalt/rundot).
|
|
11
|
+
|
|
12
|
+
## 0.6.0
|
|
13
|
+
|
|
14
|
+
- `paulrun run`'s output is easier to scan:
|
|
15
|
+
- the overview and how the run finished are in boxes
|
|
16
|
+
- each step is a numbered blue rule, e.g. `1/3 Build`
|
|
17
|
+
- each block is a bracket: `┌` with its language and when it started (`HH:MM:SS.mmm`), each line it printed after `│`, then `└ ✓ exit 0 · 0.4s` or `└ ✗ exit 3 · 0.4s`
|
|
18
|
+
- docstrings are dim, and confirms are in a yellow box
|
|
19
|
+
- A line a block writes to stderr has a red `│`.
|
|
20
|
+
- Code is hidden unless you pass `--show-code`. `--dry` always shows it.
|
|
21
|
+
- The transcript is unchanged.
|
|
22
|
+
- Backends: `output` takes an optional `stderr=True` for a stderr line, and `stream()` passes it when `output` accepts it. A backend that calls `output(line)` still works.
|
|
23
|
+
|
|
24
|
+
## 0.5.0
|
|
25
|
+
|
|
26
|
+
- A block's output is fenced off between `=== LOG: <when it started> ===` and `========`, with the time to the microsecond and a blank line either side, so it can't be mistaken for the block's code or paulrun's own lines. A block that prints nothing gets no LOG section. Under `--step`, a blank line comes before and after `Run this block?` too. The transcript is unchanged.
|
|
27
|
+
|
|
28
|
+
## 0.4.0
|
|
29
|
+
|
|
30
|
+
- Add a cool logo to the cli output
|
|
31
|
+
|
|
32
|
+
## 0.3.0
|
|
33
|
+
|
|
34
|
+
- A runbook can set `step: true` in its frontmatter to always run as if `--step` was given, asking before each `run` block. `--no-step` runs it straight through. `check` reports a `step` that isn't `true` or `false`.
|
|
35
|
+
- The book picker, `paulrun run` with no runbook, now takes `q` to quit, and says so: `Run which? (q to quit)`.
|
|
36
|
+
- A block skipped under `--step` is now shown, and recorded in the transcript, as `skipped` rather than `skipped (--step)`, since `step: true` skips blocks too.
|
|
37
|
+
|
|
38
|
+
## 0.2.0
|
|
39
|
+
|
|
40
|
+
### A runbook library
|
|
41
|
+
- keep runbooks you use across projects in `~/runbooks`, or wherever `PAULRUN_LIBRARY` says. Then run one by name from anywhere, e.g. `paulrun rebuild-frontend`. `run`, `check` and `inputs` all take a book's name as well as a path, and a file where you are is always used before a book with the same name. `paulrun library` lists the books in your library, with each one's title and description. `paulrun run`, with no runbook, lists them by number and runs the one you pick.
|
|
42
|
+
- A new docs page, [Your runbook library](https://docs.rundot.dev/library/), with a worked example of a book that rebuilds a frontend under nvm.
|
|
43
|
+
|
|
44
|
+
- **Breaking:** `paulrun go` is now `paulrun run`, and you don't need to type it: `paulrun RELEASING.md` runs `RELEASING.md`. Anything after `paulrun` that isn't a command is a runbook to run, so `paulrun go` is no longer a command. `paulrun` on its own still shows help.
|
|
45
|
+
- **Breaking:** blocks now run in the folder you run paulrun from, not the folder the runbook is in. A relative `output_path` is now relative to that folder too. A runbook kept at the root of its project, run from there, works as before. One run as `paulrun path/to/RUNBOOK.md` from another folder now works on that other folder and writes its transcript there. This includes blocks run by external backends, whose `cwd` is now the folder paulrun was started from.
|
|
46
|
+
- Blocks get `PAULRUN_RUNBOOK_DIR`, the folder the runbook is in, so a runbook can still use files kept next to it.
|
|
47
|
+
- Running a runbook shows the folder blocks will run in, as `directory:` straight after the title, so you can check it before answering `Start?`. `--dry` shows it too.
|
|
48
|
+
- `paulrun library`, the book picker and `paulrun inputs` are in colour in a terminal: names you type are bold cyan, details are dim, and secrets and problems stand out. Piped output has no colour, as before.
|
|
49
|
+
- Inputs can have a `default`, shown at the prompt and used when you press enter. The environment still comes first. `check` reports a default that isn't text, doesn't match the input's `pattern`, or is on a secret.
|
|
50
|
+
- Inputs can have `choices`: the only values accepted, listed at the prompt. You type the choice itself, and a value from the environment has to be one of them too. `check` reports choices that aren't a list of text, a choice the `pattern` refuses, a default that isn't a choice, and choices on a secret.
|
|
51
|
+
|
|
52
|
+
## 0.1.0
|
|
53
|
+
|
|
54
|
+
Initial release. paulrun runs hand-written markdown runbooks.
|
|
55
|
+
|
|
56
|
+
- `paulrun go` runs a runbook's steps in order, streaming each block's output as it's printed and stopping at the first block that fails.
|
|
57
|
+
- `run` blocks for shell (`sh`, `bash`, `shell`) and Python (`python`, `py`), with the `python` frontmatter key to choose the interpreter.
|
|
58
|
+
- `docstring` blocks to show notes as the runbook runs, and `confirm` blocks to pause for steps done by hand.
|
|
59
|
+
- `input` blocks to ask for a value part way through a run, once it exists: a pull request number from a step done by hand, or a one-time code that expires in seconds.
|
|
60
|
+
- Inputs, collected from the environment or by asking, with an optional `pattern` to check them against. Plain inputs fill in `<NAME>` placeholders; secrets are hidden as you type them and replaced with `****` everywhere paulrun shows or records them.
|
|
61
|
+
- `paulrun go --dry` to see every block with its inputs filled in, without running anything.
|
|
62
|
+
- `paulrun go --step` to run, skip or quit at each block.
|
|
63
|
+
- Transcripts: with `output_path` set, every run is added to a plain record of what ran, what it printed and how it finished.
|
|
64
|
+
- Ctrl-C stops a run cleanly, letting a running block stop and recording how far the run got.
|
|
65
|
+
- `paulrun check` to find problems before running anything: missing or malformed frontmatter, undeclared placeholders, secrets used as placeholders, blocks outside a step, and shell and Python syntax errors, with shellcheck warnings when it's installed.
|
|
66
|
+
- `paulrun inputs` to list the inputs a runbook needs, and `paulrun backends` to list the languages paulrun can run.
|
|
67
|
+
- Backends for other languages can be added by any package, through the `paulrun.backends` entry point group.
|
rundot-0.6.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
## Workflow
|
|
4
|
+
|
|
5
|
+
### Workflow for planned tasks
|
|
6
|
+
|
|
7
|
+
1. Read the plan, spec and todos, then present a short plan. STOP and wait for my approval.
|
|
8
|
+
2. Implement test-first in red-green slices. Keep 100% line and branch coverage.
|
|
9
|
+
3. Only tick checkboxes or approval boxes when I say so, or after CI is confirmed green.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# rundot Code of Conduct
|
|
2
|
+
|
|
3
|
+
Like the technical community as a whole, the rundot team and community is made up of a mixture of professionals and volunteers from all over the world, working on every aspect of the mission - including mentorship, teaching, and connecting people.
|
|
4
|
+
|
|
5
|
+
Diversity is one of our huge strengths, but it can also lead to communication issues and unhappiness. To that end, we have a few ground rules that we ask people to adhere to. This code applies equally to founders, mentors and those seeking help and guidance.
|
|
6
|
+
|
|
7
|
+
This isn’t an exhaustive list of things that you can’t do. Rather, take it in the spirit in which it’s intended - a guide to make it easier to enrich all of us and the technical communities in which we participate.
|
|
8
|
+
|
|
9
|
+
This code of conduct applies to all spaces managed by the rundot project or Paul Hallett. This includes the issue tracker, pull requests, discussions, and any other forums created by the project team which the community uses for communication. In addition, violations of this code outside these spaces may affect a person's ability to participate within them.
|
|
10
|
+
|
|
11
|
+
If you believe someone is violating the code of conduct, we ask that you report it by emailing [paulandrewhallett@gmail.com](mailto:paulandrewhallett@gmail.com).
|
|
12
|
+
|
|
13
|
+
- **Be friendly and patient.**
|
|
14
|
+
- **Be welcoming.** We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
|
|
15
|
+
- **Be considerate.** Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language.
|
|
16
|
+
- **Be respectful.** Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. Members of the rundot community should be respectful when dealing with other members as well as with people outside the rundot community.
|
|
17
|
+
- **Be careful in the words that you choose.** We are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. This includes, but is not limited to:
|
|
18
|
+
- Violent threats or language directed against another person.
|
|
19
|
+
- Discriminatory jokes and language.
|
|
20
|
+
- Posting sexually explicit or violent material.
|
|
21
|
+
- Posting (or threatening to post) other people's personally identifying information ("doxing").
|
|
22
|
+
- Personal insults, especially those using racist or sexist terms.
|
|
23
|
+
- Unwelcome sexual attention.
|
|
24
|
+
- Advocating for, or encouraging, any of the above behavior.
|
|
25
|
+
- Repeated harassment of others. In general, if someone asks you to stop, then stop.
|
|
26
|
+
- **When we disagree, try to understand why.** Disagreements, both social and technical, happen all the time and rundot is no exception. It is important that we resolve disagreements and differing views constructively. Remember that we’re different. The strength of rundot comes from its varied community, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.
|
|
27
|
+
|
|
28
|
+
Original text courtesy of the [Speak Up! project](http://web.archive.org/web/20141109123859/http://speakup.io/coc.html).
|
|
29
|
+
|
|
30
|
+
## Questions?
|
|
31
|
+
|
|
32
|
+
If you have questions, please see [CONTRIBUTING.md](CONTRIBUTING.md). If that doesn't answer your questions, feel free to [contact us](mailto:paulandrewhallett@gmail.com).
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
First things first: thank you for contributing! This project will be successful thanks to everyone who contributes, and we're happy to have you.
|
|
4
|
+
|
|
5
|
+
## AI disclosure
|
|
6
|
+
|
|
7
|
+
Within rundot we use coding agents to prototype and build out ideas, and then take the idea to fruition using human reviewed and approved code.
|
|
8
|
+
|
|
9
|
+
You, the human and the author of changes are responsible for the contributions, and if you cannot confidently explain or demonstrate understanding of the changes you are contributing, then they will not be accepted.
|
|
10
|
+
|
|
11
|
+
## Bug or issue?
|
|
12
|
+
|
|
13
|
+
To raise a bug or issue please use [our GitHub](https://github.com/phalt/rundot/issues).
|
|
14
|
+
|
|
15
|
+
Please check the issue has not been raised before by using the search feature.
|
|
16
|
+
|
|
17
|
+
When submitting an issue or bug, please make sure you provide thorough detail on:
|
|
18
|
+
|
|
19
|
+
1. The version of rundot you are using (`rundot --version`)
|
|
20
|
+
2. Your operating system and Python version
|
|
21
|
+
3. Any errors or outputs you see in your terminal
|
|
22
|
+
4. The smallest runbook that shows the problem (this is particularly important). Take out any secrets first!
|
|
23
|
+
|
|
24
|
+
## Contribution
|
|
25
|
+
|
|
26
|
+
If you want to directly contribute you can do so in two ways:
|
|
27
|
+
|
|
28
|
+
1. Documentation
|
|
29
|
+
2. Code
|
|
30
|
+
|
|
31
|
+
### Documentation
|
|
32
|
+
|
|
33
|
+
We use [Zensical](https://zensical.org/) and [GitHub pages](https://pages.github.com/) to deploy our docs.
|
|
34
|
+
|
|
35
|
+
Fixing grammar, spelling mistakes, or expanding the documentation to cover features that are not yet documented, are all valuable contributions.
|
|
36
|
+
|
|
37
|
+
Please see the **Set up** instructions below to run the docs locally on your computer, then:
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
make docs-serve
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The examples in the docs and the README are tested, so if you change one, run `make test` too.
|
|
44
|
+
|
|
45
|
+
### Code
|
|
46
|
+
|
|
47
|
+
Contribution by writing code for new features, or fixing bugs, is a great way to contribute to the project.
|
|
48
|
+
|
|
49
|
+
Please [open an issue](https://github.com/phalt/rundot/issues) to talk it through before changing the runbook format (frontmatter keys, what a fence does, placeholders or the transcript), adding a command or flag, or adding a dependency. These are hard to change once people's runbooks rely on them.
|
|
50
|
+
|
|
51
|
+
#### Set up
|
|
52
|
+
|
|
53
|
+
Clone the repo:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
git clone git@github.com:phalt/rundot.git
|
|
57
|
+
cd rundot
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Move to a feature branch:
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
git switch -c my-branch-name
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Install UV (if not already installed):
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
# On macOS and Linux:
|
|
70
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
71
|
+
|
|
72
|
+
# Or using pip:
|
|
73
|
+
pip install uv
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Install all the dependencies:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
make install
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
This will use UV to create a virtual environment and install all dependencies, including rundot itself, so its built-in backends are registered. UV handles the virtual environment automatically, so you don't need to manually activate it.
|
|
83
|
+
|
|
84
|
+
To make sure you have things set up correctly, please run the tests:
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
make test
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
You can run your copy of rundot with `uv run rundot`, e.g. on one of the example runbooks in `tests/runbooks/`:
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
uv run rundot tests/runbooks/two_steps.md
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Run `make help` to see every command.
|
|
97
|
+
|
|
98
|
+
### Adding a backend
|
|
99
|
+
|
|
100
|
+
rundot runs shell and Python blocks out of the box. To add another language to rundot itself:
|
|
101
|
+
|
|
102
|
+
1. Write `rundot/backends/<name>.py`, implementing the backend protocol
|
|
103
|
+
2. Add one entry point line for it in `pyproject.toml`, then run `make install`
|
|
104
|
+
3. Write `tests/backends/test_<name>.py`, which really runs blocks (skipped if the language isn't installed)
|
|
105
|
+
4. Add a section about it to `docs/backends.md`
|
|
106
|
+
5. Add a CHANGELOG entry
|
|
107
|
+
|
|
108
|
+
[docs/backends.md](https://docs.rundot.dev/backends/) explains each step, and how backends work.
|
|
109
|
+
|
|
110
|
+
A backend doesn't have to be part of rundot: the same page shows how to ship one in your own package.
|
|
111
|
+
|
|
112
|
+
### Preparing changes for review
|
|
113
|
+
|
|
114
|
+
Once you've made changes, here's a good checklist to run through before publishing for review:
|
|
115
|
+
|
|
116
|
+
Format and lint the code:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
make format
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Check the types:
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
make ty
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Check the import contracts:
|
|
129
|
+
|
|
130
|
+
```sh
|
|
131
|
+
make lint-imports
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
[Import Linter](https://import-linter.readthedocs.io/) checks that modules only import in the directions we want: `rundot.cli` sits on top and wires everything together, the runner and validator never import the CLI or each other, backends are only loaded through their entry points, and only the CLI uses `click` and `rich`. The contracts, and the reasons for them, are under `[tool.importlinter]` in `pyproject.toml`. If one breaks, change the import rather than the contract.
|
|
135
|
+
|
|
136
|
+
Run the tests:
|
|
137
|
+
|
|
138
|
+
```sh
|
|
139
|
+
make test
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
New behaviour needs tests, and each new runbook feature gets an example runbook in `tests/runbooks/` that shows it off.
|
|
143
|
+
|
|
144
|
+
If you've changed how runbooks are written or run, update `docs/runbook-format.md` or `docs/cli.md` to match.
|
|
145
|
+
|
|
146
|
+
Make sure you add to `CHANGELOG.md` and `docs/CHANGELOG.md` what changes you have made. The two must be identical, and a test checks they are.
|
|
147
|
+
|
|
148
|
+
Make sure you add your name to `CONTRIBUTORS.md` as well!
|
|
149
|
+
|
|
150
|
+
### Making a pull request
|
|
151
|
+
|
|
152
|
+
Please push your changes up to a feature branch and make a new [pull request](https://github.com/phalt/rundot/compare) on GitHub.
|
|
153
|
+
|
|
154
|
+
Please add a description to the PR and some information about why the change is being made.
|
|
155
|
+
|
|
156
|
+
After a review, you might need to make more changes.
|
|
157
|
+
|
|
158
|
+
Once accepted, a core contributor will merge your changes!
|
rundot-0.6.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Paul Hallett
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
rundot-0.6.0/Makefile
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
help:
|
|
2
|
+
@echo Developer commands for rundot
|
|
3
|
+
@echo
|
|
4
|
+
@grep -E '^[ .a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
|
|
5
|
+
@echo
|
|
6
|
+
|
|
7
|
+
install: ## Install requirements ready for development
|
|
8
|
+
uv sync
|
|
9
|
+
|
|
10
|
+
deploy-docs: ## Build and deploy the documentation
|
|
11
|
+
uv run zensical build --clean --strict
|
|
12
|
+
uv run ghp-import --no-jekyll --push --force --message "Deploy docs" site
|
|
13
|
+
|
|
14
|
+
docs-serve: ## Run a local documentation server
|
|
15
|
+
uv run zensical serve
|
|
16
|
+
|
|
17
|
+
release: ## Build a new version and release it
|
|
18
|
+
uv build
|
|
19
|
+
uv publish
|
|
20
|
+
|
|
21
|
+
ty: ## Run a static syntax check
|
|
22
|
+
uv run ty check .
|
|
23
|
+
|
|
24
|
+
lint-imports: ## Check the import contracts in pyproject.toml
|
|
25
|
+
uv run lint-imports
|
|
26
|
+
|
|
27
|
+
format: ## Format the code correctly
|
|
28
|
+
uv run ruff format .
|
|
29
|
+
uv run ruff check --fix .
|
|
30
|
+
|
|
31
|
+
clean: ## Clear any cache files and test files
|
|
32
|
+
rm -rf .ty_cache
|
|
33
|
+
rm -rf .pytest_cache
|
|
34
|
+
rm -rf .ruff_cache
|
|
35
|
+
rm -rf .import_linter_cache
|
|
36
|
+
rm -rf site/
|
|
37
|
+
rm -rf dist/
|
|
38
|
+
find rundot tests -name __pycache__ -prune -exec rm -rf {} +
|
|
39
|
+
rm -rf htmlcov/
|
|
40
|
+
rm -rf .coverage
|
|
41
|
+
|
|
42
|
+
test: ## Run tests
|
|
43
|
+
uv run pytest -vvv -x --cov=rundot --cov-report=term-missing --cov-report=html --cov-config=pyproject.toml
|
|
44
|
+
|
|
45
|
+
test-quiet: ## Quiet output of tests
|
|
46
|
+
uv run pytest -x --cov=rundot --cov-report=term-missing --cov-report=html --cov-config=pyproject.toml
|
|
47
|
+
|
|
48
|
+
shell: ## Run an ipython shell
|
|
49
|
+
uv run ipython
|
rundot-0.6.0/PKG-INFO
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: rundot
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: Run hand-written markdown runbooks
|
|
5
|
+
Project-URL: Homepage, https://github.com/phalt/rundot
|
|
6
|
+
Project-URL: Documentation, https://docs.rundot.dev/
|
|
7
|
+
Project-URL: Issues, https://github.com/phalt/rundot/issues
|
|
8
|
+
Author-email: Paul Hallett <paulandrewhallett@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Requires-Dist: click>=8.5.0
|
|
13
|
+
Requires-Dist: markdown-it-py>=4.2.0
|
|
14
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
15
|
+
Requires-Dist: rich>=15.0.0
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# 🏃♂️➡️📕 rundot
|
|
19
|
+
|
|
20
|
+
## What is rundot?
|
|
21
|
+
|
|
22
|
+
rundot executes the code blocks in your markdown file, turning them into runbooks.
|
|
23
|
+
|
|
24
|
+
A runbook is just a normal markdown file that a person can read and write, but if you annotate a code block `run`, then rundot can execute the code blocks for you, helping you to automate tedious multi-step tasks.
|
|
25
|
+
|
|
26
|
+
[](https://pypi.org/project/rundot)
|
|
27
|
+

|
|
28
|
+

|
|
29
|
+
|
|
30
|
+
## Example runbook
|
|
31
|
+
|
|
32
|
+
Save this as `hello.md`:
|
|
33
|
+
|
|
34
|
+
````markdown
|
|
35
|
+
---
|
|
36
|
+
title: Say hello
|
|
37
|
+
inputs:
|
|
38
|
+
- name: NAME
|
|
39
|
+
description: Who to say hello to
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
# Say hello
|
|
43
|
+
|
|
44
|
+
A runbook is just markdown. rundot runs the blocks marked `run`, shows the
|
|
45
|
+
`docstring` ones, and leaves everything else alone, like this paragraph.
|
|
46
|
+
|
|
47
|
+
## Greet
|
|
48
|
+
|
|
49
|
+
```docstring
|
|
50
|
+
Saying hello to <NAME>.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```sh run
|
|
54
|
+
echo "Hello, <NAME>!"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Count the letters
|
|
58
|
+
|
|
59
|
+
```python run
|
|
60
|
+
import os
|
|
61
|
+
|
|
62
|
+
name = os.environ["NAME"]
|
|
63
|
+
print(f"{name} has {len(name)} letters")
|
|
64
|
+
```
|
|
65
|
+
````
|
|
66
|
+
|
|
67
|
+
Check it, then run it:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
rundot check hello.md
|
|
71
|
+
rundot hello.md
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+

|
|
75
|
+
|
|
76
|
+
The command `check` will validate the formatting of your Markdown file to make sure it will work with Rundot.
|
|
77
|
+
|
|
78
|
+
When running a runbook, rundot asks for the inputs, shows the plan, and runs each step in order.
|
|
79
|
+
|
|
80
|
+
You can run through each step one at a time with `--step` and even show the code that will run with each step with `--show-code`.
|
|
81
|
+
|
|
82
|
+
## Your runbook library
|
|
83
|
+
|
|
84
|
+
Keep runbooks you use across projects in `~/runbooks`, and run them by name from anywhere:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
$ rundot library
|
|
88
|
+
library: /home/you/runbooks
|
|
89
|
+
rebuild-frontend Rebuild the frontend
|
|
90
|
+
update-project-deps Update a project's dependencies
|
|
91
|
+
|
|
92
|
+
$ cd ~/Projects/website
|
|
93
|
+
$ rundot rebuild-frontend
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
A book runs in the folder you're in, so one book works for every project. See [Your runbook library](https://docs.rundot.dev/library/).
|
|
97
|
+
|
|
98
|
+
## Why use rundot?
|
|
99
|
+
|
|
100
|
+
Release steps get forgotten. Writing them down helps; making the written-down version run itself fixes it.
|
|
101
|
+
|
|
102
|
+
- **It's just markdown** - A runbook reads like documentation, renders on GitHub, and works fine without rundot.
|
|
103
|
+
- **Check before you run** - `rundot check` finds broken frontmatter, undeclared placeholders and syntax errors.
|
|
104
|
+
- **See what would happen** - `rundot --dry RELEASING.md` shows every command with its inputs filled in, and runs nothing.
|
|
105
|
+
- **Inputs and secrets** - Ask for values once, check them against a pattern, and keep secrets off the screen and out of the log.
|
|
106
|
+
- **Manual steps too** - `confirm` blocks pause for the things only a person can do.
|
|
107
|
+
- **A record of every run** - An optional transcript keeps every command, its output and how it finished.
|
|
108
|
+
- **More than shell** - Shell and Python blocks are built in, and other languages can be added as backends.
|
|
109
|
+
|
|
110
|
+
## Install
|
|
111
|
+
|
|
112
|
+
rundot is a command-line tool, so install it on its own rather than into a project:
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
uv tool install rundot
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Or with pip:
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
pip install rundot
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
rundot needs Python 3.12 or later and `bash`, and runs on **macOS and Linux**. Windows isn't supported. It's for runbooks you run yourself, at a terminal; there's no CI mode.
|
|
125
|
+
|
|
126
|
+
## Getting started
|
|
127
|
+
|
|
128
|
+
👉 Read the [full documentation](https://docs.rundot.dev/) for the runbook format, every command, and writing your own backend.
|
|
129
|
+
|
|
130
|
+
See [`examples/`](https://github.com/phalt/rundot/tree/main/examples) for more runbooks, including a real release, and [`PUBLISHING.md`](https://github.com/phalt/rundot/blob/main/PUBLISHING.md) for the runbook rundot releases itself with.
|
|
131
|
+
|
|
132
|
+
Want to help? See [CONTRIBUTING.md](https://github.com/phalt/rundot/blob/main/CONTRIBUTING.md).
|