repoactive 0.2.8.dev2__tar.gz → 0.3.1__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.
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/PKG-INFO +418 -152
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/README.md +417 -151
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/pyproject.toml +1 -1
- repoactive-0.3.1/src/repoactive/boxquote.py +51 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/cli.py +1 -1
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/config.py +151 -5
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/jj.py +12 -1
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/runner.py +170 -23
- repoactive-0.2.8.dev2/src/repoactive/boxquote.py +0 -32
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/.gitignore +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/LICENSE +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/__init__.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/constants.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/graph.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/jobtree.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/lock.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/platforms/__init__.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/platforms/base.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/platforms/github.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/platforms/gitlab.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/progress.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/selection.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/settings.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/trailers.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/ui.py +0 -0
- {repoactive-0.2.8.dev2 → repoactive-0.3.1}/src/repoactive/updates.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: repoactive
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Script-driven code changes with automated merge requests
|
|
5
5
|
License-Expression: GPL-3.0-or-later
|
|
6
6
|
License-File: LICENSE
|
|
@@ -27,27 +27,37 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
|
|
28
28
|
# repoactive - Script-driven code changes with automated merge requests
|
|
29
29
|
|
|
30
|
+
[](https://pypi.org/project/repoactive/)
|
|
31
|
+
[](https://github.com/schmir/repoactive/actions/workflows/ci.yml)
|
|
32
|
+
[](https://pypi.org/project/repoactive/)
|
|
33
|
+
[](LICENSE)
|
|
34
|
+
|
|
30
35
|
> **Warning:** This project is in an early stage of development. Use at your
|
|
31
36
|
> own risk.
|
|
32
37
|
|
|
33
38
|
`repoactive` runs your scripts against a git repository and optionally keeps
|
|
34
39
|
the corresponding merge requests up to date. You write the scripts that
|
|
35
40
|
produce the code changes; `repoactive` handles the rest - branches, commits,
|
|
36
|
-
and (with `--mode publish`) the full MR lifecycle.
|
|
41
|
+
and (with `--mode publish`) the full MR lifecycle. This document says merge
|
|
42
|
+
request (MR) throughout; on GitHub, read that as pull request (PR).
|
|
37
43
|
|
|
38
44
|
## Contents
|
|
39
45
|
|
|
40
46
|
- [Use cases](#use-cases)
|
|
47
|
+
- [How it compares](#how-it-compares)
|
|
41
48
|
- [Installation](#installation)
|
|
42
49
|
- [Quick start](#quick-start)
|
|
43
50
|
- [How it works](#how-it-works)
|
|
51
|
+
- [What a run produces](#what-a-run-produces)
|
|
44
52
|
- [Keeping the local clone current](#keeping-the-local-clone-current)
|
|
45
|
-
- [
|
|
53
|
+
- [Undoing a run](#undoing-a-run)
|
|
54
|
+
- [Commands](#commands)
|
|
55
|
+
- [`repoactive run`](#repoactive-run)
|
|
56
|
+
- [`repoactive recent-commits`](#repoactive-recent-commits)
|
|
57
|
+
- [`repoactive validate-config`](#repoactive-validate-config)
|
|
58
|
+
- [`repoactive info jobs`](#repoactive-info-jobs)
|
|
59
|
+
- [`repoactive info tags`](#repoactive-info-tags)
|
|
46
60
|
- [Environment variables](#environment-variables)
|
|
47
|
-
- [Inspecting repoactive commits](#inspecting-repoactive-commits)
|
|
48
|
-
- [Validating configuration](#validating-configuration)
|
|
49
|
-
- [Listing jobs](#listing-jobs)
|
|
50
|
-
- [Listing tags](#listing-tags)
|
|
51
61
|
- [Configuration](#configuration)
|
|
52
62
|
- [`[job-defaults]`](#job-defaults)
|
|
53
63
|
- [`[job.<name>]`](#jobname)
|
|
@@ -55,20 +65,23 @@ and (with `--mode publish`) the full MR lifecycle.
|
|
|
55
65
|
- [Example](#example)
|
|
56
66
|
- [`[platform.<name>]`](#platformname)
|
|
57
67
|
- [Config file locations](#config-file-locations)
|
|
68
|
+
- [Variables passed to job commands](#variables-passed-to-job-commands)
|
|
69
|
+
- [Passing secrets to commands with `secret_env`](#passing-secrets-to-commands-with-secret_env)
|
|
58
70
|
- [Overriding values on the command line](#overriding-values-on-the-command-line)
|
|
59
|
-
- [
|
|
60
|
-
- [
|
|
61
|
-
- [Disabling jobs](#disabling-jobs)
|
|
62
|
-
- [Running a job on a schedule](#running-a-job-on-a-schedule)
|
|
63
|
-
- [
|
|
64
|
-
- [
|
|
65
|
-
- [Throttling
|
|
66
|
-
- [
|
|
67
|
-
- [
|
|
68
|
-
- [Generating jobs dynamically](#generating-jobs-dynamically)
|
|
71
|
+
- [Run control](#run-control)
|
|
72
|
+
- [Selecting jobs with tags](#selecting-jobs-with-tags)
|
|
73
|
+
- [Disabling jobs](#disabling-jobs)
|
|
74
|
+
- [Running a job on a schedule](#running-a-job-on-a-schedule)
|
|
75
|
+
- [Gating jobs with `run_only_if_changed`](#gating-jobs-with-run_only_if_changed)
|
|
76
|
+
- [Throttling jobs with `cooldown_period`](#throttling-jobs-with-cooldown_period)
|
|
77
|
+
- [Throttling a job when a superset lands with `cooldown_on`](#throttling-a-job-when-a-superset-lands-with-cooldown_on)
|
|
78
|
+
- [Limiting job runtime with `timeout`](#limiting-job-runtime-with-timeout)
|
|
79
|
+
- [Generating jobs dynamically](#generating-jobs-dynamically)
|
|
69
80
|
- [Requirements](#requirements)
|
|
70
81
|
- [Appendix](#appendix)
|
|
71
82
|
- [jj revset aliases](#jj-revset-aliases)
|
|
83
|
+
- [Changelog](#changelog)
|
|
84
|
+
- [License](#license)
|
|
72
85
|
|
|
73
86
|
## Use cases
|
|
74
87
|
|
|
@@ -79,6 +92,23 @@ and (with `--mode publish`) the full MR lifecycle.
|
|
|
79
92
|
- Automating any periodic code transformation that should go through a
|
|
80
93
|
review process
|
|
81
94
|
|
|
95
|
+
### How it compares
|
|
96
|
+
|
|
97
|
+
[Renovate](https://docs.renovatebot.com/) and
|
|
98
|
+
[Dependabot](https://docs.github.com/en/code-security/dependabot) are built
|
|
99
|
+
around dependency updates; repoactive runs whatever script you write, so the
|
|
100
|
+
change can be anything the repository generates - a lock-file upgrade is
|
|
101
|
+
just the simplest case.
|
|
102
|
+
[multi-gitter](https://github.com/lindell/multi-gitter) also runs your
|
|
103
|
+
script and opens the MR, but as a one-shot bulk operation across
|
|
104
|
+
repositories; repoactive is built for re-running against one repository: an
|
|
105
|
+
unchanged diff leaves the MR untouched, a changed one updates it, branches
|
|
106
|
+
are rebased onto the moving base branch, cooldowns keep a landed change from
|
|
107
|
+
immediately reopening, and jobs can stack their MRs on one another. And it
|
|
108
|
+
is a plain CLI working against your local clone - no hosted service and
|
|
109
|
+
nothing to install into the repository - that talks to GitHub and GitLab,
|
|
110
|
+
including self-hosted instances.
|
|
111
|
+
|
|
82
112
|
## Installation
|
|
83
113
|
|
|
84
114
|
`repoactive` is published on [PyPI](https://pypi.org/project/repoactive/).
|
|
@@ -123,7 +153,7 @@ needs a GitHub or GitLab API token in the environment. See
|
|
|
123
153
|
4. **Run the job locally.** In the default `local` mode nothing is pushed
|
|
124
154
|
and no MR is created - repoactive just records the diff your script
|
|
125
155
|
produced on the branch `repoactive/uv-lock-upgrade` and prints a
|
|
126
|
-
`jj op restore` command to undo the run:
|
|
156
|
+
`jj op restore` command to [undo the run](#undoing-a-run):
|
|
127
157
|
|
|
128
158
|
```bash
|
|
129
159
|
repoactive run
|
|
@@ -156,14 +186,6 @@ With `--mode publish` it also:
|
|
|
156
186
|
Branches and MR descriptions are managed automatically - the only code you
|
|
157
187
|
need to write is the script that produces the change.
|
|
158
188
|
|
|
159
|
-
```
|
|
160
|
-
[your script] → diff → repoactive → branch
|
|
161
|
-
↓ (with --mode push or --mode publish)
|
|
162
|
-
git push → merge request
|
|
163
|
-
↑ (with --mode publish)
|
|
164
|
-
(create or update)
|
|
165
|
-
```
|
|
166
|
-
|
|
167
189
|
1. `repoactive` creates a new commit on top of the base branch or on top of
|
|
168
190
|
other repoactive managed branches.
|
|
169
191
|
2. It runs the job's script against the working tree.
|
|
@@ -188,6 +210,46 @@ need to write is the script that produces the change.
|
|
|
188
210
|
> `.gitignore` up to date so build artifacts, caches, and other stray files
|
|
189
211
|
> your script produces do not end up in the diff.
|
|
190
212
|
|
|
213
|
+
### What a run produces
|
|
214
|
+
|
|
215
|
+
For the quick-start job above, a `--mode publish` run pushes the branch
|
|
216
|
+
`repoactive/uv-lock-upgrade` and opens an MR titled
|
|
217
|
+
`[repoactive] build: upgrade dependencies`. Its description holds the job's
|
|
218
|
+
`description` (when set), the command and its captured output in a code
|
|
219
|
+
block, and - for [stacked jobs](#stacking-mrs) - links to the parent MRs
|
|
220
|
+
([a real example](https://github.com/schmir/repoactive/pull/7)):
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
$ uv lock --upgrade
|
|
224
|
+
Using CPython 3.14.1
|
|
225
|
+
Resolved 51 packages in 4.19s
|
|
226
|
+
Updated annotated-types v0.7.0 -> v0.8.0
|
|
227
|
+
Updated nox v2026.4.10 -> v2026.7.11
|
|
228
|
+
Updated ruff v0.15.21 -> v0.16.0
|
|
229
|
+
Updated ty v0.0.58 -> v0.0.63
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
The commit carries the same output (unless `output_in_commit` is disabled)
|
|
233
|
+
plus the `Repoactive-Job` trailer that
|
|
234
|
+
[`recent-commits`](#repoactive-recent-commits), the
|
|
235
|
+
[cooldown check](#throttling-jobs-with-cooldown_period), and the
|
|
236
|
+
[unmerged-branch refresh](#keeping-unmerged-branches-current) all key on:
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
[repoactive] build: upgrade dependencies
|
|
240
|
+
|
|
241
|
+
,----[ uv lock --upgrade ]
|
|
242
|
+
| Using CPython 3.14.1
|
|
243
|
+
| Resolved 51 packages in 4.19s
|
|
244
|
+
| Updated annotated-types v0.7.0 -> v0.8.0
|
|
245
|
+
| Updated nox v2026.4.10 -> v2026.7.11
|
|
246
|
+
| Updated ruff v0.15.21 -> v0.16.0
|
|
247
|
+
| Updated ty v0.0.58 -> v0.0.63
|
|
248
|
+
`----
|
|
249
|
+
|
|
250
|
+
Repoactive-Job: uv-lock-upgrade
|
|
251
|
+
```
|
|
252
|
+
|
|
191
253
|
### Keeping the local clone current
|
|
192
254
|
|
|
193
255
|
`repoactive` works entirely from the **local** repository view and never
|
|
@@ -204,13 +266,39 @@ because the commit that would trigger it has not reached the local base
|
|
|
204
266
|
branch. See
|
|
205
267
|
[ADR 0005](docs/adr/0005-local-repository-is-the-source-of-truth.md).
|
|
206
268
|
|
|
207
|
-
|
|
269
|
+
### Undoing a run
|
|
270
|
+
|
|
271
|
+
Every `run` captures the jj operation id beforehand and prints a
|
|
272
|
+
`jj op restore <id>` command at the end of the run (last, since a run can
|
|
273
|
+
produce a lot of output). Run it to roll the local repository - commits,
|
|
274
|
+
bookmarks and colocated git refs - back to the state it was in before the
|
|
275
|
+
run. It only undoes local changes: a branch already pushed or an MR already
|
|
276
|
+
created by a `--mode push`/`--mode publish` run is not affected, as the hint
|
|
277
|
+
panel itself points out.
|
|
278
|
+
|
|
279
|
+
## Commands
|
|
208
280
|
|
|
209
281
|
```bash
|
|
210
282
|
# Print the installed version and exit
|
|
211
283
|
repoactive --version
|
|
212
284
|
```
|
|
213
285
|
|
|
286
|
+
Every command accepts `--repo`/`-r` and `--debug`/`-d`. The commands that
|
|
287
|
+
read configuration - `run`, `validate-config`, `info jobs`, and
|
|
288
|
+
`info tags` - also accept the same `--config`/`-c` and `--set`/`-s` options,
|
|
289
|
+
described in the [`repoactive run`](#repoactive-run) table below.
|
|
290
|
+
`recent-commits` works from the repository alone and reads no configuration.
|
|
291
|
+
|
|
292
|
+
All commands exit with these status codes:
|
|
293
|
+
|
|
294
|
+
| Code | Meaning |
|
|
295
|
+
| ---- | ------------------------------------------------------------------------------------------ |
|
|
296
|
+
| 0 | Success |
|
|
297
|
+
| 1 | Failure (invalid configuration, a failed job, ...) |
|
|
298
|
+
| 2 | `run` only: another run holds the [per-repository lock](#one-run-at-a-time-per-repository) |
|
|
299
|
+
|
|
300
|
+
### `repoactive run`
|
|
301
|
+
|
|
214
302
|
```
|
|
215
303
|
repoactive run [OPTIONS] [JOBS]...
|
|
216
304
|
```
|
|
@@ -247,64 +335,7 @@ repoactive run --debug
|
|
|
247
335
|
| `--tag TAG` | `-t` | Run jobs carrying any of these tags (repeatable). With no tags/jobs the default run targets the `enabled` tag |
|
|
248
336
|
| `--debug` | `-d` | Enable debug logging |
|
|
249
337
|
|
|
250
|
-
###
|
|
251
|
-
|
|
252
|
-
Besides the command-line options, repoactive reads a few `REPOACTIVE_*`
|
|
253
|
-
environment variables that tune how it presents itself in the current
|
|
254
|
-
environment (as opposed to the [configuration](#configuration), which
|
|
255
|
-
describes the jobs to run). They are handled uniformly: all of them go
|
|
256
|
-
through a single settings model and are validated together at startup, so a
|
|
257
|
-
misconfigured variable fails immediately with a one-line error naming it
|
|
258
|
-
instead of surfacing mid-run or being silently ignored. Values are
|
|
259
|
-
case-insensitive.
|
|
260
|
-
|
|
261
|
-
#### `REPOACTIVE_UI`
|
|
262
|
-
|
|
263
|
-
`interactive` (default) or `noninteractive`.
|
|
264
|
-
|
|
265
|
-
Every `run` captures the jj operation id beforehand and prints a
|
|
266
|
-
`jj op restore <id>` command at the end of the run (last, since a run can
|
|
267
|
-
produce a lot of output). Run it to roll the local repository - commits,
|
|
268
|
-
bookmarks and colocated git refs - back to the state it was in before the
|
|
269
|
-
run. It only undoes local changes: a branch already pushed or an MR already
|
|
270
|
-
created by a `--mode push`/`--mode publish` run is not affected, as the hint
|
|
271
|
-
panel itself points out.
|
|
272
|
-
|
|
273
|
-
`noninteractive` suppresses these "how to undo" hint panels. Set it where
|
|
274
|
-
nobody is at the keyboard, say an unattended CI job. This is an explicit
|
|
275
|
-
switch rather than CI auto-detection, because a CI container someone has
|
|
276
|
-
logged in to _is_ interactive.
|
|
277
|
-
|
|
278
|
-
#### `REPOACTIVE_LOG_LEVEL`
|
|
279
|
-
|
|
280
|
-
`debug`, `info`, `warning`, `error`, or `critical`; unset by default
|
|
281
|
-
(logging off).
|
|
282
|
-
|
|
283
|
-
Enables logging at that level without passing `--debug` on every invocation;
|
|
284
|
-
an explicit `--debug` takes precedence.
|
|
285
|
-
|
|
286
|
-
#### `REPOACTIVE_LOG_HANDLER`
|
|
287
|
-
|
|
288
|
-
`rich` or `plain`; defaults to `rich`, or `plain` when `REPOACTIVE_UI` is
|
|
289
|
-
`noninteractive`.
|
|
290
|
-
|
|
291
|
-
How log records are rendered: a colorized column layout via
|
|
292
|
-
[rich](https://github.com/Textualize/rich), or the stdlib's plain stream
|
|
293
|
-
handler (e.g. when the output is collected by a log aggregator).
|
|
294
|
-
|
|
295
|
-
#### `REPOACTIVE_PROGRESS_LINES`
|
|
296
|
-
|
|
297
|
-
An integer (default: `8`).
|
|
298
|
-
|
|
299
|
-
While a job's command runs in an interactive terminal, repoactive shows a
|
|
300
|
-
live, scrolling block of its most recent output lines. The block stays on
|
|
301
|
-
screen once the command finishes, with the job's status line printed below
|
|
302
|
-
it. `REPOACTIVE_PROGRESS_LINES` sets how many lines that live tail shows;
|
|
303
|
-
`0` or less disables the live block entirely. When output is not a terminal
|
|
304
|
-
(piped or in CI) the block is disabled and the command's output is left
|
|
305
|
-
untouched.
|
|
306
|
-
|
|
307
|
-
## Inspecting repoactive commits
|
|
338
|
+
### `repoactive recent-commits`
|
|
308
339
|
|
|
309
340
|
```
|
|
310
341
|
repoactive recent-commits [OPTIONS] [JOBS]...
|
|
@@ -337,7 +368,7 @@ repoactive recent-commits --status unmerged
|
|
|
337
368
|
| `--status [all\|merged\|unmerged]` | `-s` | Filter by merge status into trunk (default: `all`) |
|
|
338
369
|
| `--debug` | `-d` | Enable debug logging |
|
|
339
370
|
|
|
340
|
-
|
|
371
|
+
### `repoactive validate-config`
|
|
341
372
|
|
|
342
373
|
```
|
|
343
374
|
repoactive validate-config [OPTIONS]
|
|
@@ -364,10 +395,7 @@ code 1.
|
|
|
364
395
|
Validation checks include unknown keys, missing required fields, invalid
|
|
365
396
|
`depends_on` references, and circular job dependencies.
|
|
366
397
|
|
|
367
|
-
|
|
368
|
-
options as [`repoactive run`](#usage).
|
|
369
|
-
|
|
370
|
-
## Listing jobs
|
|
398
|
+
### `repoactive info jobs`
|
|
371
399
|
|
|
372
400
|
```
|
|
373
401
|
repoactive info jobs [OPTIONS]
|
|
@@ -391,10 +419,7 @@ build Build the project enabled
|
|
|
391
419
|
└── deploy Deploy to staging nightly, risky
|
|
392
420
|
```
|
|
393
421
|
|
|
394
|
-
|
|
395
|
-
options as [`repoactive run`](#usage).
|
|
396
|
-
|
|
397
|
-
## Listing tags
|
|
422
|
+
### `repoactive info tags`
|
|
398
423
|
|
|
399
424
|
```
|
|
400
425
|
repoactive info tags [OPTIONS]
|
|
@@ -426,8 +451,54 @@ nightly:
|
|
|
426
451
|
benchmark Run nightly benchmarks nightly
|
|
427
452
|
```
|
|
428
453
|
|
|
429
|
-
|
|
430
|
-
|
|
454
|
+
### Environment variables
|
|
455
|
+
|
|
456
|
+
Besides the command-line options, repoactive reads a few `REPOACTIVE_*`
|
|
457
|
+
environment variables that tune how it presents itself in the current
|
|
458
|
+
environment (as opposed to the [configuration](#configuration), which
|
|
459
|
+
describes the jobs to run). They are handled uniformly: all of them go
|
|
460
|
+
through a single settings model and are validated together at startup, so a
|
|
461
|
+
misconfigured variable fails immediately with a one-line error naming it
|
|
462
|
+
instead of surfacing mid-run or being silently ignored. Values are
|
|
463
|
+
case-insensitive.
|
|
464
|
+
|
|
465
|
+
#### `REPOACTIVE_UI`
|
|
466
|
+
|
|
467
|
+
`interactive` (default) or `noninteractive`.
|
|
468
|
+
|
|
469
|
+
`noninteractive` suppresses the ["how to undo" hint panels](#undoing-a-run)
|
|
470
|
+
printed after each run. Set it where nobody is at the keyboard, say an
|
|
471
|
+
unattended CI job. This is an explicit switch rather than CI auto-detection,
|
|
472
|
+
because a CI container someone has logged in to _is_ interactive.
|
|
473
|
+
|
|
474
|
+
#### `REPOACTIVE_LOG_LEVEL`
|
|
475
|
+
|
|
476
|
+
`debug`, `info`, `warning`, `error`, or `critical`; unset by default
|
|
477
|
+
(logging off).
|
|
478
|
+
|
|
479
|
+
Enables logging at that level without passing `--debug` on every invocation;
|
|
480
|
+
an explicit `--debug` takes precedence.
|
|
481
|
+
|
|
482
|
+
#### `REPOACTIVE_LOG_HANDLER`
|
|
483
|
+
|
|
484
|
+
`rich` or `plain`; defaults to `rich`, or `plain` when `REPOACTIVE_UI` is
|
|
485
|
+
`noninteractive`.
|
|
486
|
+
|
|
487
|
+
How log records are rendered: a colorized column layout via
|
|
488
|
+
[rich](https://github.com/Textualize/rich), or the stdlib's plain stream
|
|
489
|
+
handler (e.g. when the output is collected by a log aggregator).
|
|
490
|
+
|
|
491
|
+
#### `REPOACTIVE_PROGRESS_LINES`
|
|
492
|
+
|
|
493
|
+
An integer (default: `8`).
|
|
494
|
+
|
|
495
|
+
While a job's command runs in an interactive terminal, repoactive shows a
|
|
496
|
+
live, scrolling block of its most recent output lines. The block stays on
|
|
497
|
+
screen once the command finishes, with the job's status line printed below
|
|
498
|
+
it. `REPOACTIVE_PROGRESS_LINES` sets how many lines that live tail shows;
|
|
499
|
+
`0` or less disables the live block entirely. When output is not a terminal
|
|
500
|
+
(piped or in CI) the block is disabled and the command's output is left
|
|
501
|
+
untouched.
|
|
431
502
|
|
|
432
503
|
## Configuration
|
|
433
504
|
|
|
@@ -450,14 +521,13 @@ block.
|
|
|
450
521
|
|
|
451
522
|
### `[job-defaults]`
|
|
452
523
|
|
|
453
|
-
**MR
|
|
524
|
+
**MR options:**
|
|
454
525
|
|
|
455
|
-
- **`labels`** (default: `[]`) - Labels applied to every MR
|
|
526
|
+
- **`labels`** (default: `[]`) - Labels applied to every MR. Per-job
|
|
456
527
|
`labels` are merged with, not replaced by, this list.
|
|
457
528
|
- **`auto_merge`** (default: `false`) - When `true`, enable auto-merge on
|
|
458
|
-
every MR
|
|
459
|
-
|
|
460
|
-
settings.
|
|
529
|
+
every MR so it merges automatically once its pipeline passes. On GitHub,
|
|
530
|
+
the repository must have "Allow auto-merge" enabled in its settings.
|
|
461
531
|
- **`required_approvals`** (default: none) - Minimum number of approvals
|
|
462
532
|
required before the MR can be merged. **GitLab only** - this sets the
|
|
463
533
|
per-MR approval requirement. GitHub has no per-PR equivalent (required
|
|
@@ -467,13 +537,17 @@ block.
|
|
|
467
537
|
**Branch and commit options:**
|
|
468
538
|
|
|
469
539
|
- **`branch_prefix`** (default: `"repoactive/"`) - Prefix prepended to the
|
|
470
|
-
job name to form the branch name.
|
|
540
|
+
job name to form the branch name. Set to `""` to use the job name alone.
|
|
541
|
+
With an empty prefix the branch name is exactly the job name, so make sure
|
|
542
|
+
no job is named after your base branch (e.g. a job named `main`) - the two
|
|
543
|
+
branches would otherwise collide.
|
|
471
544
|
- **`mr_title_prefix`** (default: `"[repoactive] "`) - Prefix prepended to
|
|
472
|
-
every MR
|
|
545
|
+
every MR title. Set to `""` to disable.
|
|
473
546
|
- **`commit_title_prefix`** (default: `"[repoactive] "`) - Prefix prepended
|
|
474
547
|
to every commit title. Set to `""` to disable.
|
|
475
548
|
- **`base_branch`** (default: repo default) - Target branch for all jobs
|
|
476
|
-
that do not set their own.
|
|
549
|
+
that do not set their own. May also be a jj revset expression such as
|
|
550
|
+
`trunk()`, `root()`, or a user-defined revset alias.
|
|
477
551
|
|
|
478
552
|
**Run control:**
|
|
479
553
|
|
|
@@ -484,6 +558,18 @@ block.
|
|
|
484
558
|
- **`timeout`** (default: `"2m"`) - Maximum runtime for a job's command.
|
|
485
559
|
Same format as `cooldown_period`. See
|
|
486
560
|
[Limiting job runtime with `timeout`](#limiting-job-runtime-with-timeout).
|
|
561
|
+
- **`shell`** (default: `/bin/sh`) - Interpreter used to run job commands. A
|
|
562
|
+
bare name is resolved on `PATH` (e.g. `"bash"`); an absolute path also
|
|
563
|
+
works. The command runs as `<shell> -c <command>`. Arguments are not
|
|
564
|
+
allowed - the value must be a single binary.
|
|
565
|
+
|
|
566
|
+
**Secrets:**
|
|
567
|
+
|
|
568
|
+
- **`secret_env`** (default: `[]`) - Names of environment variables to mark
|
|
569
|
+
as secrets config-wide. Each marked name is stripped from every job
|
|
570
|
+
command's environment, but a job still reads one only by listing it in its
|
|
571
|
+
own `secret_env`; `job-defaults` marks names, it does not grant them. See
|
|
572
|
+
[Passing secrets to commands with `secret_env`](#passing-secrets-to-commands-with-secret_env).
|
|
487
573
|
|
|
488
574
|
### `[job.<name>]`
|
|
489
575
|
|
|
@@ -495,34 +581,35 @@ underscores.
|
|
|
495
581
|
|
|
496
582
|
- **`command`** - Shell command (or executable path) run in the repository
|
|
497
583
|
working directory. A non-zero exit is a failure.
|
|
498
|
-
- **`title`** - MR
|
|
584
|
+
- **`title`** - MR title (also the commit subject, after
|
|
499
585
|
`commit_title_prefix`).
|
|
500
586
|
|
|
501
|
-
**MR
|
|
587
|
+
**MR options:**
|
|
502
588
|
|
|
503
|
-
- **`description`** - Body text of the MR
|
|
504
|
-
- **`labels`** (default: `[]`) - Extra labels for this job's MR
|
|
505
|
-
|
|
506
|
-
- **`draft`** (default: `false`) - Open the MR
|
|
507
|
-
|
|
508
|
-
- **`create_mr`** (default: `true`) - Whether to create an MR
|
|
589
|
+
- **`description`** - Body text of the MR.
|
|
590
|
+
- **`labels`** (default: `[]`) - Extra labels for this job's MR, merged with
|
|
591
|
+
`job-defaults.labels`.
|
|
592
|
+
- **`draft`** (default: `false`) - Open the MR as a draft. On GitHub, draft
|
|
593
|
+
state cannot be changed after creation.
|
|
594
|
+
- **`create_mr`** (default: `true`) - Whether to create an MR: `true`
|
|
509
595
|
(always), `false` (push the branch but skip the MR), or
|
|
510
596
|
`"unless-superseded"` (skip when a dependent's MR from the same run
|
|
511
597
|
already contains this job's changes - see [Stacking MRs](#stacking-mrs)).
|
|
512
598
|
- **`auto_merge`** (default: inherited from `job-defaults`) - When `true`,
|
|
513
|
-
enable auto-merge on this job's MR
|
|
599
|
+
enable auto-merge on this job's MR.
|
|
514
600
|
- **`required_approvals`** (default: inherited from `job-defaults`) -
|
|
515
601
|
Minimum number of approvals required before this job's MR can be merged.
|
|
516
602
|
GitLab only; see `job-defaults.required_approvals`.
|
|
517
603
|
|
|
518
604
|
**Branch and commit options:**
|
|
519
605
|
|
|
520
|
-
- **`base_branch`** (default: inherited) - Target branch for this job's
|
|
521
|
-
|
|
606
|
+
- **`base_branch`** (default: inherited) - Target branch for this job's MR.
|
|
607
|
+
May also be a jj revset expression such as `trunk()`, `root()`, or a
|
|
608
|
+
user-defined revset alias.
|
|
522
609
|
- **`branch_prefix`** (default: inherited) - Override the branch-name prefix
|
|
523
610
|
for this job only.
|
|
524
|
-
- **`mr_title_prefix`** (default: inherited) - Override the MR
|
|
525
|
-
|
|
611
|
+
- **`mr_title_prefix`** (default: inherited) - Override the MR title prefix
|
|
612
|
+
for this job only.
|
|
526
613
|
- **`commit_title_prefix`** (default: inherited) - Override the commit title
|
|
527
614
|
prefix for this job only.
|
|
528
615
|
- **`output_in_commit`** (default: `true`) - Append the job's command and
|
|
@@ -553,9 +640,20 @@ underscores.
|
|
|
553
640
|
- **`timeout`** (default: inherited) - Maximum runtime for this job's
|
|
554
641
|
command. Set to `"0s"` to disable the timeout entirely. See
|
|
555
642
|
[Limiting job runtime with `timeout`](#limiting-job-runtime-with-timeout).
|
|
643
|
+
- **`shell`** (default: inherited) - Interpreter used to run this job's
|
|
644
|
+
command, overriding `job-defaults.shell`. See
|
|
645
|
+
[`job-defaults.shell`](#job-defaults).
|
|
556
646
|
- **`emits_jobs`** (default: `false`) - Generator job: the command writes
|
|
557
|
-
`*.toml` job fragments into `$
|
|
558
|
-
|
|
647
|
+
`*.toml` job fragments into `$RA_JOBS_DIR` instead of producing a diff.
|
|
648
|
+
See [Generating jobs dynamically](#generating-jobs-dynamically).
|
|
649
|
+
|
|
650
|
+
**Secrets:**
|
|
651
|
+
|
|
652
|
+
- **`secret_env`** (default: `[]`) - Names of environment variables holding
|
|
653
|
+
secrets this job's command may read. A marked name is stripped from every
|
|
654
|
+
command's environment; only a job that lists it here has it injected back
|
|
655
|
+
for its own command. See
|
|
656
|
+
[Passing secrets to commands with `secret_env`](#passing-secrets-to-commands-with-secret_env).
|
|
559
657
|
|
|
560
658
|
### Stacking MRs
|
|
561
659
|
|
|
@@ -569,14 +667,13 @@ Because a dependent's MR already contains its dependencies' changes, a
|
|
|
569
667
|
dependency chain normally opens one MR per job that produced a diff. Setting
|
|
570
668
|
`create_mr = "unless-superseded"` on the earlier jobs collapses that: such a
|
|
571
669
|
job skips its MR when a dependent job produced an MR in the same run, so the
|
|
572
|
-
chain yields a single MR on the topmost job that actually changed
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
limitations.
|
|
670
|
+
chain yields a single MR on the topmost job that actually changed
|
|
671
|
+
something - falling back to the job below it when the jobs above came up
|
|
672
|
+
empty. The branch is still pushed either way. Only the current run counts: a
|
|
673
|
+
dependent that is empty, failed, on cooldown, or not selected does not
|
|
674
|
+
suppress anything. See
|
|
675
|
+
[ADR 0009](docs/adr/0009-unless-superseded-mr-creation.md) for details and
|
|
676
|
+
limitations.
|
|
580
677
|
|
|
581
678
|
### Example
|
|
582
679
|
|
|
@@ -658,6 +755,165 @@ directory of `*.toml` files, and may be repeated to merge several sources;
|
|
|
658
755
|
later sources win. Explicit paths are resolved relative to the current
|
|
659
756
|
directory, not `--repo`.
|
|
660
757
|
|
|
758
|
+
### Variables passed to job commands
|
|
759
|
+
|
|
760
|
+
`repoactive` injects a few `RA_`-prefixed environment variables into every
|
|
761
|
+
job command's environment. These are distinct from the `REPOACTIVE_`
|
|
762
|
+
variables [above](#environment-variables), which configure `repoactive`
|
|
763
|
+
itself.
|
|
764
|
+
|
|
765
|
+
| Variable | Value | Set when |
|
|
766
|
+
| ---------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
|
767
|
+
| `RA_JOB_NAME` | The name of the job the command belongs to. | Always. |
|
|
768
|
+
| `RA_WORKSPACE_DIR` | The temporary jj workspace created for the job (also the command's working directory). | Always. |
|
|
769
|
+
| `RA_JOB_BRANCH` | The bookmark/branch repoactive uses for the job's output. | Always. |
|
|
770
|
+
| `RA_JOB_BASE_BRANCH` | The branch the job's MR targets (`base_branch`, or `trunk()` by default). | Always. |
|
|
771
|
+
| `RA_CONFIG_SOURCE_DIR` | The directory of the config file that defined the command. | The command came from a config file (not a `--set` override or a built-in default). |
|
|
772
|
+
| `RA_JOBS_DIR` | The directory a generator writes its `*.toml` job fragments into. | The command is a [generator](#generating-jobs-dynamically) (`emits_jobs`). |
|
|
773
|
+
|
|
774
|
+
#### `RA_JOB_NAME`
|
|
775
|
+
|
|
776
|
+
`RA_JOB_NAME` holds the name of the job the command belongs to. A command
|
|
777
|
+
shared by several jobs (for instance one set in `[job-defaults]` or emitted
|
|
778
|
+
by a generator) can read it to tell which job is running:
|
|
779
|
+
|
|
780
|
+
```toml
|
|
781
|
+
[job.lint]
|
|
782
|
+
command = "./run-check.sh $RA_JOB_NAME"
|
|
783
|
+
title = "run the shared check script for this job"
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
#### `RA_WORKSPACE_DIR`
|
|
787
|
+
|
|
788
|
+
A job's command runs in a temporary jj workspace, which is also its working
|
|
789
|
+
directory. `RA_WORKSPACE_DIR` names that directory explicitly, so a command
|
|
790
|
+
that changes directory can still find its way back:
|
|
791
|
+
|
|
792
|
+
```toml
|
|
793
|
+
[job.build]
|
|
794
|
+
command = "cd subdir && make && cp result $RA_WORKSPACE_DIR/subdir/"
|
|
795
|
+
title = "build in a subdirectory"
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
#### `RA_JOB_BRANCH`
|
|
799
|
+
|
|
800
|
+
`RA_JOB_BRANCH` holds the bookmark (git branch) repoactive uses for the
|
|
801
|
+
job's output, e.g. `repoactive/uv-lock-upgrade`. The command runs on a fresh
|
|
802
|
+
commit while that bookmark still points at the **previous** run's commit, so
|
|
803
|
+
a command can inspect what it produced last time - for example to build on
|
|
804
|
+
it or diff against it:
|
|
805
|
+
|
|
806
|
+
```toml
|
|
807
|
+
[job.notes]
|
|
808
|
+
command = "jj diff --from $RA_JOB_BRANCH --to @ > /tmp/delta || true; ./make-notes.sh"
|
|
809
|
+
title = "regenerate release notes from what changed since last run"
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
The bookmark may not exist yet: a job's first run, a run that produced no
|
|
813
|
+
diff, and a generator all leave it unset on the remote, so a command that
|
|
814
|
+
reads it should tolerate a missing ref.
|
|
815
|
+
|
|
816
|
+
#### `RA_JOB_BASE_BRANCH`
|
|
817
|
+
|
|
818
|
+
`RA_JOB_BASE_BRANCH` holds the branch the job's merge request targets - its
|
|
819
|
+
`base_branch`, or `trunk()` when that is unset. A command can use it to look
|
|
820
|
+
at only what changed relative to the target, for instance to lint or
|
|
821
|
+
reformat just the affected files:
|
|
822
|
+
|
|
823
|
+
```toml
|
|
824
|
+
[job.format]
|
|
825
|
+
command = "treefmt $(git diff --name-only $RA_JOB_BASE_BRANCH)"
|
|
826
|
+
title = "format files changed since the base branch"
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
This is the branch you _configured_ as the base. When a job stacks on
|
|
830
|
+
another via `depends_on`, its commit actually sits on top of that other
|
|
831
|
+
job's output, so `RA_JOB_BASE_BRANCH` names the ultimate target of the
|
|
832
|
+
stack, not the immediate parent.
|
|
833
|
+
|
|
834
|
+
#### `RA_CONFIG_SOURCE_DIR`
|
|
835
|
+
|
|
836
|
+
Because the command runs in that throwaway workspace rather than in the
|
|
837
|
+
directory its config lives in, a relative path cannot reach a helper file
|
|
838
|
+
kept beside the config. `RA_CONFIG_SOURCE_DIR` bridges that: it holds the
|
|
839
|
+
directory of the config file that defined the job's command:
|
|
840
|
+
|
|
841
|
+
- a job defined in `.repoactive.toml` gets the directory holding it (the
|
|
842
|
+
repo directory, by default);
|
|
843
|
+
- a job defined in `.repoactive.d/foo.toml` gets the `.repoactive.d`
|
|
844
|
+
directory.
|
|
845
|
+
|
|
846
|
+
```toml
|
|
847
|
+
[job.fixup]
|
|
848
|
+
command = "$RA_CONFIG_SOURCE_DIR/fixup.sh"
|
|
849
|
+
title = "run the fixup script kept beside the config"
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
The value is the config file's real location on disk, so it is the same
|
|
853
|
+
whether the file was discovered automatically or named with `-c`. A command
|
|
854
|
+
whose value came from a `--set` override has no config file, so
|
|
855
|
+
`RA_CONFIG_SOURCE_DIR` is unset for it.
|
|
856
|
+
|
|
857
|
+
### Passing secrets to commands with `secret_env`
|
|
858
|
+
|
|
859
|
+
A job command inherits `repoactive`'s environment, so a secret exported
|
|
860
|
+
before the run (an LLM key, a registry token) reaches it. Left unmanaged
|
|
861
|
+
that secret reaches **every** job, whether it needs it or not. `secret_env`
|
|
862
|
+
scopes secrets to the jobs that ask for them.
|
|
863
|
+
|
|
864
|
+
The field separates two things:
|
|
865
|
+
|
|
866
|
+
- **Marking** - naming a variable in _any_ `secret_env` (a job's or
|
|
867
|
+
`[job-defaults]`') marks it a secret and **removes it from every job
|
|
868
|
+
command's environment**.
|
|
869
|
+
- **Granting** - a job reads a marked secret back only by listing it in
|
|
870
|
+
**its own** `secret_env`. `[job-defaults].secret_env` marks names but
|
|
871
|
+
grants to no job.
|
|
872
|
+
|
|
873
|
+
So a secret is present only in the jobs that name it, never ambient:
|
|
874
|
+
|
|
875
|
+
```toml
|
|
876
|
+
[job-defaults]
|
|
877
|
+
secret_env = ["OPENAI_API_KEY"]
|
|
878
|
+
|
|
879
|
+
[job.rewrite-docs]
|
|
880
|
+
command = "./llm-rewrite.sh"
|
|
881
|
+
title = "docs: rewrite with the LLM"
|
|
882
|
+
secret_env = ["OPENAI_API_KEY"]
|
|
883
|
+
|
|
884
|
+
[job.format]
|
|
885
|
+
command = "treefmt"
|
|
886
|
+
title = "format the tree"
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
Here `OPENAI_API_KEY` is marked in `[job-defaults]`, so `format` (which does
|
|
890
|
+
not grant it) runs without it in its environment; only `rewrite-docs`, which
|
|
891
|
+
lists it in its own `secret_env`, can read it.
|
|
892
|
+
|
|
893
|
+
A job that grants a secret which is **unset** in `repoactive`'s environment
|
|
894
|
+
fails at its start with a clear error, rather than letting the command fail
|
|
895
|
+
obscurely later. Secret **values** must never be written in config - a
|
|
896
|
+
`.repoactive.toml` is checked into the repo; `secret_env` names variables,
|
|
897
|
+
your environment (or your CI's secret store) supplies the values. The `RA_`
|
|
898
|
+
and `REPOACTIVE_` prefixes are reserved and rejected.
|
|
899
|
+
|
|
900
|
+
A [generated job](#generating-jobs-dynamically) may only grant a secret that
|
|
901
|
+
the static config already marks; an emitted `secret_env` naming a variable
|
|
902
|
+
no static job or `[job-defaults]` marked is rejected. Mark such a secret up
|
|
903
|
+
front in `[job-defaults].secret_env` (or on the generator), and the emitted
|
|
904
|
+
jobs grant it.
|
|
905
|
+
|
|
906
|
+
A platform's `token_env` is normally stripped from every command
|
|
907
|
+
([the platform token](#platformname) is kept out of jobs). A job that
|
|
908
|
+
genuinely needs it can opt back in by naming that variable in its own
|
|
909
|
+
`secret_env`; only that job then receives it.
|
|
910
|
+
|
|
911
|
+
> **Note:** `secret_env` scopes _which jobs_ can read a secret. It does not
|
|
912
|
+
> yet redact secret values from a command's captured output, so a command
|
|
913
|
+
> that echoes a secret it was granted can still write it into the commit
|
|
914
|
+
> message. Avoid printing granted secrets. See
|
|
915
|
+
> [ADR 0017](docs/adr/0017-secret-env-redaction.md).
|
|
916
|
+
|
|
661
917
|
### Overriding values on the command line
|
|
662
918
|
|
|
663
919
|
`--set NAME=VALUE`/`-s` tweaks individual config values without editing a
|
|
@@ -693,7 +949,13 @@ job across several flags - put a new job's required fields in one expression
|
|
|
693
949
|
unknown key or malformed value is reported with the offending `--set`
|
|
694
950
|
argument named.
|
|
695
951
|
|
|
696
|
-
##
|
|
952
|
+
## Run control
|
|
953
|
+
|
|
954
|
+
The sections below cover the run-control options from the
|
|
955
|
+
[configuration reference](#jobname) in detail: which jobs a run selects, how
|
|
956
|
+
to schedule and throttle them, and how to generate jobs dynamically.
|
|
957
|
+
|
|
958
|
+
### Selecting jobs with tags
|
|
697
959
|
|
|
698
960
|
Which jobs a `repoactive run` touches is decided by **tags**. Every job has
|
|
699
961
|
a set of tags, with a smart default:
|
|
@@ -728,8 +990,8 @@ mistyped one.
|
|
|
728
990
|
Because assigning a tag removes the implicit `enabled` tag, **tags are
|
|
729
991
|
load-bearing, not free-form labels**: tagging a job takes it out of the bare
|
|
730
992
|
`repoactive run`. If you want a job to stay in the default run _and_ belong
|
|
731
|
-
to a group, list both: `tags = ["enabled", "weekly"]`. (For MR
|
|
732
|
-
|
|
993
|
+
to a group, list both: `tags = ["enabled", "weekly"]`. (For MR labels, use
|
|
994
|
+
`labels` - a separate concept.)
|
|
733
995
|
|
|
734
996
|
Tag selection is _explicit_ selection, so - like naming a job - it ignores
|
|
735
997
|
the `enabled`/`disabled` defaults and force-includes dependencies. The bare
|
|
@@ -737,7 +999,7 @@ the `enabled`/`disabled` defaults and force-includes dependencies. The bare
|
|
|
737
999
|
itself selected is dropped
|
|
738
1000
|
(`==> [name] skipped (dependency not in default run)`).
|
|
739
1001
|
|
|
740
|
-
|
|
1002
|
+
#### Keeping unmerged branches current
|
|
741
1003
|
|
|
742
1004
|
The bare `repoactive run` additionally refreshes **any job that currently
|
|
743
1005
|
has an unmerged branch**, regardless of its tags. A branch is "unmerged"
|
|
@@ -756,7 +1018,7 @@ don't have to wait for the next weekly run to resolve a conflict with
|
|
|
756
1018
|
disabled job's unmerged branch is refreshed too: it was most likely created
|
|
757
1019
|
by an explicit run, and letting it drift out of date helps no one.)
|
|
758
1020
|
|
|
759
|
-
|
|
1021
|
+
### Disabling jobs
|
|
760
1022
|
|
|
761
1023
|
Set `disabled = true` on a `[job.<name>]` to keep it in the config but leave
|
|
762
1024
|
it out of normal runs; it is exactly sugar for `tags = ["disabled"]` (so the
|
|
@@ -777,7 +1039,7 @@ disabled = true
|
|
|
777
1039
|
`repoactive run --tag disabled`, which runs everything currently turned
|
|
778
1040
|
off.
|
|
779
1041
|
|
|
780
|
-
|
|
1042
|
+
### Running a job on a schedule
|
|
781
1043
|
|
|
782
1044
|
`repoactive` is not a daemon and has no built-in scheduler - the cadence of
|
|
783
1045
|
a job is whatever cadence you invoke it with. To run a job on a fixed
|
|
@@ -805,7 +1067,7 @@ inferring a schedule from `repoactive`'s own history: real cron is stateful
|
|
|
805
1067
|
and excludes the other days, whereas `repoactive` only ever sees what has
|
|
806
1068
|
_landed_ (see `cooldown_period` below).
|
|
807
1069
|
|
|
808
|
-
|
|
1070
|
+
#### One run at a time per repository
|
|
809
1071
|
|
|
810
1072
|
A `repoactive run` takes an exclusive per-repository lock for its duration,
|
|
811
1073
|
so two runs against the same repository never interleave (and corrupt each
|
|
@@ -823,7 +1085,7 @@ The lock is an advisory `flock` on `.jj/repoactive.lock`; the OS releases it
|
|
|
823
1085
|
automatically if a run is killed, so a crashed run never leaves the
|
|
824
1086
|
repository locked.
|
|
825
1087
|
|
|
826
|
-
|
|
1088
|
+
### Gating jobs with `run_only_if_changed`
|
|
827
1089
|
|
|
828
1090
|
`run_only_if_changed` lets a job declare that it should only run when
|
|
829
1091
|
specific upstream jobs actually produced a diff. If none of the named jobs
|
|
@@ -831,12 +1093,12 @@ changed anything in the current run, the job is skipped.
|
|
|
831
1093
|
|
|
832
1094
|
```toml
|
|
833
1095
|
[job.prek-autoupdate]
|
|
834
|
-
command = "
|
|
1096
|
+
command = "uvx prek autoupdate"
|
|
835
1097
|
title = "ci: update pre-commit hooks"
|
|
836
1098
|
tags = ["weekly"]
|
|
837
1099
|
|
|
838
1100
|
[job.prek-run-all]
|
|
839
|
-
command = "sh -c '
|
|
1101
|
+
command = "sh -c 'uvx prek run -a; true'"
|
|
840
1102
|
title = "ci: apply pre-commit fixes"
|
|
841
1103
|
depends_on = ["prek-autoupdate"]
|
|
842
1104
|
run_only_if_changed = ["prek-autoupdate"]
|
|
@@ -862,7 +1124,7 @@ Key behaviour:
|
|
|
862
1124
|
order can be listed; in practice most usages name a direct dependency, as
|
|
863
1125
|
in the example above.
|
|
864
1126
|
|
|
865
|
-
|
|
1127
|
+
### Throttling jobs with `cooldown_period`
|
|
866
1128
|
|
|
867
1129
|
Every commit `repoactive` creates carries a `Repoactive-Job: <name>` trailer
|
|
868
1130
|
identifying the job that produced it. When a job sets `cooldown_period`,
|
|
@@ -885,7 +1147,7 @@ runs: `repoactive` does not fetch, so a clone that has not pulled the merge
|
|
|
885
1147
|
will not see the cooldown and will re-run the job. See
|
|
886
1148
|
[Keeping the local clone current](#keeping-the-local-clone-current).
|
|
887
1149
|
|
|
888
|
-
|
|
1150
|
+
### Throttling a job when a superset lands with `cooldown_on`
|
|
889
1151
|
|
|
890
1152
|
Some jobs are strict supersets of others. `uv lock --upgrade` refreshes
|
|
891
1153
|
every dependency group, so its diff already contains everything
|
|
@@ -925,7 +1187,7 @@ has an open, unmerged branch is always refreshed regardless of cooldown (see
|
|
|
925
1187
|
its branch is rebased and, if the change is now redundant, self-closes on
|
|
926
1188
|
the next run.
|
|
927
1189
|
|
|
928
|
-
|
|
1190
|
+
### Limiting job runtime with `timeout`
|
|
929
1191
|
|
|
930
1192
|
A job's `command` can hang or run away. Setting `timeout` caps how long the
|
|
931
1193
|
command may run; when the limit is reached `repoactive` kills the command's
|
|
@@ -955,15 +1217,15 @@ title = "chore: fix lint"
|
|
|
955
1217
|
timeout = "0s" # opt out of the timeout entirely
|
|
956
1218
|
```
|
|
957
1219
|
|
|
958
|
-
|
|
1220
|
+
### Generating jobs dynamically
|
|
959
1221
|
|
|
960
1222
|
Sometimes the useful set of jobs depends on the repository's contents - one
|
|
961
1223
|
job per package in a monorepo, one per entry in a manifest - and you don't
|
|
962
1224
|
want to hand-maintain them. A **generator** is an ordinary `[job.<name>]`
|
|
963
1225
|
with `emits_jobs = true`. Instead of producing a diff, its command writes
|
|
964
1226
|
one or more `*.toml` job fragments into the directory named by the
|
|
965
|
-
`
|
|
966
|
-
|
|
1227
|
+
`RA_JOBS_DIR` environment variable, and the jobs it emits run in the same
|
|
1228
|
+
invocation.
|
|
967
1229
|
|
|
968
1230
|
```toml
|
|
969
1231
|
[job.per-package]
|
|
@@ -978,7 +1240,7 @@ cooldown_period = "7d"
|
|
|
978
1240
|
The command writes fragments using the normal `[job.<name>]` syntax, e.g.
|
|
979
1241
|
|
|
980
1242
|
```toml
|
|
981
|
-
# $
|
|
1243
|
+
# $RA_JOBS_DIR/pkg-a.toml
|
|
982
1244
|
[job.upgrade-pkg-a]
|
|
983
1245
|
command = "uv lock --upgrade --package pkg-a"
|
|
984
1246
|
title = "build: upgrade pkg-a"
|
|
@@ -986,7 +1248,7 @@ title = "build: upgrade pkg-a"
|
|
|
986
1248
|
|
|
987
1249
|
Fragments may only contain `[job.<name>]` tables; anything else (e.g.
|
|
988
1250
|
`[job-defaults]`) fails the generator. To set defaults for the emitted jobs,
|
|
989
|
-
set them on the generator itself
|
|
1251
|
+
set them on the generator itself - they are inherited (see below).
|
|
990
1252
|
|
|
991
1253
|
Key points:
|
|
992
1254
|
|
|
@@ -1033,13 +1295,8 @@ design.
|
|
|
1033
1295
|
- [jj (Jujutsu)](https://github.com/jj-vcs/jj) - `repoactive` uses jj to
|
|
1034
1296
|
manage branches and commits in the target repository
|
|
1035
1297
|
- A configured jj user name and email - jj records them as the commit
|
|
1036
|
-
author. Set them once with
|
|
1037
|
-
|
|
1038
|
-
```bash
|
|
1039
|
-
jj config set --user user.name "My Name"
|
|
1040
|
-
jj config set --user user.email "me@example.com"
|
|
1041
|
-
```
|
|
1042
|
-
|
|
1298
|
+
author. Set them once with the `jj config set` commands shown in
|
|
1299
|
+
[Quick start](#quick-start) step 1.
|
|
1043
1300
|
- A GitLab or GitHub API token exposed via the environment variable named in
|
|
1044
1301
|
`platform.token_env` (default: `GITHUB_TOKEN` for GitHub.com,
|
|
1045
1302
|
`GITLAB_TOKEN` for GitLab.com)
|
|
@@ -1067,3 +1324,12 @@ jj log -r 'repoactive_unmerged()'
|
|
|
1067
1324
|
jj log -r 'repoactive() & committer_date(after:"2025-01-01")'
|
|
1068
1325
|
jj log -r 'repoactive() & description(regex:"(?m)^Repoactive-Job: uv-lock-upgrade$")'
|
|
1069
1326
|
```
|
|
1327
|
+
|
|
1328
|
+
## Changelog
|
|
1329
|
+
|
|
1330
|
+
User-facing changes are recorded in [CHANGELOG.md](CHANGELOG.md).
|
|
1331
|
+
|
|
1332
|
+
## License
|
|
1333
|
+
|
|
1334
|
+
`repoactive` is licensed under the
|
|
1335
|
+
[GNU General Public License v3.0 or later](LICENSE).
|