metabook-py 1.0.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.
- metabook_py-1.0.1/.github/WORKFLOW.md +214 -0
- metabook_py-1.0.1/.github/actions/build-dist/action.yml +23 -0
- metabook_py-1.0.1/.github/actions/publish-pypi/action.yml +26 -0
- metabook_py-1.0.1/.github/actions/setup/action.yml +17 -0
- metabook_py-1.0.1/.github/dependabot.yml +12 -0
- metabook_py-1.0.1/.github/rulesets/dev.json +54 -0
- metabook_py-1.0.1/.github/rulesets/main.json +57 -0
- metabook_py-1.0.1/.github/rulesets/next.json +54 -0
- metabook_py-1.0.1/.github/rulesets/release.json +51 -0
- metabook_py-1.0.1/.github/rulesets/tags.json +37 -0
- metabook_py-1.0.1/.github/workflows/automerge.yml +21 -0
- metabook_py-1.0.1/.github/workflows/matrix.yml +58 -0
- metabook_py-1.0.1/.github/workflows/next.yml +48 -0
- metabook_py-1.0.1/.github/workflows/pr-merged.yml +66 -0
- metabook_py-1.0.1/.github/workflows/pr.yml +121 -0
- metabook_py-1.0.1/.github/workflows/promote.yml +80 -0
- metabook_py-1.0.1/.github/workflows/publish.yml +68 -0
- metabook_py-1.0.1/.github/workflows/release.yml +99 -0
- metabook_py-1.0.1/.gitignore +24 -0
- metabook_py-1.0.1/.python-version +1 -0
- metabook_py-1.0.1/Dockerfile +33 -0
- metabook_py-1.0.1/LICENSE +21 -0
- metabook_py-1.0.1/PKG-INFO +67 -0
- metabook_py-1.0.1/README.md +47 -0
- metabook_py-1.0.1/SETUP_INSTRUCTIONS.md +59 -0
- metabook_py-1.0.1/bin/clean.sh +38 -0
- metabook_py-1.0.1/bin/publish.sh +245 -0
- metabook_py-1.0.1/bin/setup.sh +44 -0
- metabook_py-1.0.1/bin/update_deps.sh +16 -0
- metabook_py-1.0.1/docker-compose.yml +18 -0
- metabook_py-1.0.1/makefile +511 -0
- metabook_py-1.0.1/pyproject.toml +63 -0
- metabook_py-1.0.1/requirements.txt +9 -0
- metabook_py-1.0.1/src/metabook_py/__init__.py +0 -0
- metabook_py-1.0.1/src/metabook_py/core/__init__.py +0 -0
- metabook_py-1.0.1/src/metabook_py/core/cache.py +58 -0
- metabook_py-1.0.1/src/metabook_py/core/config.py +15 -0
- metabook_py-1.0.1/src/metabook_py/core/exceptions.py +33 -0
- metabook_py-1.0.1/src/metabook_py/main.py +91 -0
- metabook_py-1.0.1/src/metabook_py/mcp_server.py +127 -0
- metabook_py-1.0.1/src/metabook_py/models/__init__.py +0 -0
- metabook_py-1.0.1/src/metabook_py/models/book.py +36 -0
- metabook_py-1.0.1/src/metabook_py/models/structure.py +94 -0
- metabook_py-1.0.1/src/metabook_py/routers/__init__.py +0 -0
- metabook_py-1.0.1/src/metabook_py/routers/books.py +140 -0
- metabook_py-1.0.1/src/metabook_py/services/__init__.py +0 -0
- metabook_py-1.0.1/src/metabook_py/services/counter.py +398 -0
- metabook_py-1.0.1/src/metabook_py/services/detector.py +198 -0
- metabook_py-1.0.1/src/metabook_py/services/discovery.py +145 -0
- metabook_py-1.0.1/src/metabook_py/services/fetcher.py +137 -0
- metabook_py-1.0.1/tests/conftest.py +158 -0
- metabook_py-1.0.1/tests/test_counter.py +179 -0
- metabook_py-1.0.1/tests/test_detector.py +91 -0
- metabook_py-1.0.1/tests/test_discovery.py +168 -0
- metabook_py-1.0.1/uv.lock +1815 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Branching and release
|
|
2
|
+
|
|
3
|
+
Two long-lived integration lanes (`dev`, `next`) plus `main` and the tags.
|
|
4
|
+
Release branches are temporary and versioned.
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
<type>/<slug> ──PR──> dev ──(daily/manual)──> next ──cut──> release/vX.Y.Z ──draft PR──> main
|
|
8
|
+
(deleted on merge) (preview) (deleted on release)
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Adapted from [exegia/corpora-py](https://github.com/exegia/corpora-py). This
|
|
12
|
+
repo is currently a scaffold only: merging a release tags `vX.Y.Z`, which
|
|
13
|
+
triggers `publish.yml` to ship the wheel to PyPI (once a `pypi` trusted
|
|
14
|
+
publisher is configured for this repo). There is no deploy job.
|
|
15
|
+
|
|
16
|
+
## Feature branches
|
|
17
|
+
|
|
18
|
+
Named `<type>/<slug>` — `feat`, `fix`, `chore`, `docs`, `ci`, `refactor`,
|
|
19
|
+
`test`, `perf`, `build`, `style`, `revert`. (Git forbids `:` in a ref name, so
|
|
20
|
+
the conventional-commit form lives in the **PR title**: `feat: add parser`.)
|
|
21
|
+
|
|
22
|
+
Branch off `dev` and open a PR back into it. While the PR is a draft only the
|
|
23
|
+
guard runs; marking it **ready for review** starts the tests and the AI review
|
|
24
|
+
(if `CLAUDE_CODE_OAUTH_TOKEN` is configured), which then re-run on every push.
|
|
25
|
+
`guard` and `check` are required, so a red one cannot land.
|
|
26
|
+
|
|
27
|
+
**Stacked PRs** (a feature branch based on another feature branch, not `dev`
|
|
28
|
+
directly) are supported: the guard validates a `<type>/<slug>` base the same
|
|
29
|
+
way it validates the head, so `feat/b → feat/a → dev` passes as long as both
|
|
30
|
+
branches and the title follow the convention. Merge bottom-up; each merge
|
|
31
|
+
rebases the remaining stack onto `dev`.
|
|
32
|
+
|
|
33
|
+
When it merges the branch deletes itself (repository setting) and `dev` moves
|
|
34
|
+
forward. Nothing is versioned yet.
|
|
35
|
+
|
|
36
|
+
Dependabot is the one exception: it opens `dependabot/<ecosystem>/<dep>-<ver>`
|
|
37
|
+
with a `Bump X from A to B` title, and neither is renameable. `make pr-guard`
|
|
38
|
+
waves those through whichever branch they target.
|
|
39
|
+
|
|
40
|
+
## `dev` and `next`
|
|
41
|
+
|
|
42
|
+
`dev` is the working branch. Features land here all day.
|
|
43
|
+
|
|
44
|
+
`next` is staging. A scheduled workflow (22:00 UTC daily) and a manual
|
|
45
|
+
**Promote to next** action open a PR from `dev` into `next` when `dev` is
|
|
46
|
+
ahead. That PR auto-merges once `guard` and `check` pass. Every push to
|
|
47
|
+
`next` also runs the os × Python matrix.
|
|
48
|
+
|
|
49
|
+
## Versioning
|
|
50
|
+
|
|
51
|
+
The promote job classifies the bump from line-count churn
|
|
52
|
+
(`git diff --shortstat origin/next...origin/dev`, insertions + deletions):
|
|
53
|
+
|
|
54
|
+
| Churn | Makefile bump | Semver | Your label |
|
|
55
|
+
|-------|---------------|--------|------------|
|
|
56
|
+
| `< 100` | `patch` | `0.0.+1` | minor |
|
|
57
|
+
| `100–999` | `minor` | `0.+1.0` | major |
|
|
58
|
+
| `≥ 1000` | `major` | `+1.0.0` | breaking |
|
|
59
|
+
|
|
60
|
+
`workflow_dispatch` can override with `major` / `minor` / `patch`. The chosen
|
|
61
|
+
version is stored on the promote PR as `<!-- release: vX.Y.Z -->` so the cut
|
|
62
|
+
still knows it after `dev` and `next` are equal.
|
|
63
|
+
|
|
64
|
+
The version is written into `pyproject.toml` plus `uv.lock`. Version lives
|
|
65
|
+
only on `release/v*` until `main` is merged back.
|
|
66
|
+
|
|
67
|
+
## Release branches
|
|
68
|
+
|
|
69
|
+
Named `release/vX.Y.Z`, and always carry that version in `pyproject.toml`.
|
|
70
|
+
The guard rejects a PR into `main` where the root and the branch name
|
|
71
|
+
disagree.
|
|
72
|
+
|
|
73
|
+
A push to `next` cuts (or refreshes) the branch from `next` plus a
|
|
74
|
+
`chore(release): open vX.Y.Z` commit. Exactly one is in flight at a time: if a
|
|
75
|
+
draft PR into `main` is already open, later promotions fast-forward that same
|
|
76
|
+
branch and **keep its version**.
|
|
77
|
+
|
|
78
|
+
Last-minute fixes can still PR `<type>/<slug>` directly into that in-flight
|
|
79
|
+
`release/v*` (same guard/check as `dev`). A push refreshes the draft into
|
|
80
|
+
`main`.
|
|
81
|
+
|
|
82
|
+
Its ruleset deliberately omits `creation` and `deletion` rules — `make
|
|
83
|
+
cut-release` has to create it and `make delete-branch` has to remove it after
|
|
84
|
+
the release. The automation App is on the bypass list so it can push a
|
|
85
|
+
refresh without opening a PR (once one is configured — see Secrets below).
|
|
86
|
+
|
|
87
|
+
## `main`
|
|
88
|
+
|
|
89
|
+
No direct pushes; PRs only from `release/vX.Y.Z`. Merging one creates the
|
|
90
|
+
`vX.Y.Z` tag and GitHub Release, deletes the release branch, then opens PRs
|
|
91
|
+
that merge `main` back into `next` and `dev` and deletes leftover remote
|
|
92
|
+
feature / `release/v*` heads.
|
|
93
|
+
|
|
94
|
+
It does **not** cut the next release branch. That waits for the next promote.
|
|
95
|
+
|
|
96
|
+
Everything downstream hangs off that tag: `publish.yml` sends the wheel to
|
|
97
|
+
PyPI.
|
|
98
|
+
|
|
99
|
+
## Workflows
|
|
100
|
+
|
|
101
|
+
| File | Trigger | Does |
|
|
102
|
+
| ------------------- | -------------------------------- | --------------------------------------------------- |
|
|
103
|
+
| `pr.yml` | PR opened / ready / pushed | `guard`, `check`, `package` (into main), `review` (into `dev`) |
|
|
104
|
+
| `promote.yml` | 22:00 UTC daily / manual | bootstrap lanes, open `dev` → `next` PR, auto-merge |
|
|
105
|
+
| `next.yml` | push to `next` | cut/refresh `release/v*` |
|
|
106
|
+
| `pr-merged.yml` | push to `release/v*` | upsert the draft release PR into `main` |
|
|
107
|
+
| `release.yml` | PR merged into `main` | tag, sync lanes, cleanup |
|
|
108
|
+
| `matrix.yml` | push to `next` / `release/v*`, weekly | os × Python coverage |
|
|
109
|
+
| `publish.yml` | push of a `vX.Y.Z` tag | builds and publishes the wheel to PyPI |
|
|
110
|
+
| `automerge.yml` | Dependabot PR | enables auto-merge |
|
|
111
|
+
|
|
112
|
+
Every step in the first five is a `make` target, so anything CI does can be
|
|
113
|
+
reproduced locally.
|
|
114
|
+
|
|
115
|
+
### Merge methods differ by level
|
|
116
|
+
|
|
117
|
+
Feature PRs into `dev` (or an in-flight `release/v*`) are **squashed** — that
|
|
118
|
+
is this repo's convention and it keeps each feature one commit. PRs into
|
|
119
|
+
`next` and the release PR into `main` are a **merge**, and the rulesets
|
|
120
|
+
enforce that. Squashing the release PR would collapse the whole release into
|
|
121
|
+
a single commit, and `gh release --generate-notes` would have nothing to list.
|
|
122
|
+
|
|
123
|
+
### The tag must not be created by `GITHUB_TOKEN`
|
|
124
|
+
|
|
125
|
+
`make tag-release` should run with the automation App's token, and that is
|
|
126
|
+
load-bearing rather than incidental. Events raised by `GITHUB_TOKEN` do not
|
|
127
|
+
start new workflow runs, so a tag pushed with it would leave `publish.yml`
|
|
128
|
+
sitting there, never firing, with nothing to indicate the release had not
|
|
129
|
+
shipped.
|
|
130
|
+
|
|
131
|
+
The same rule is why `pr-merged.yml`, `promote.yml` and `next.yml` run as the
|
|
132
|
+
App: a PR opened by `GITHUB_TOKEN` cannot trigger further workflows, and
|
|
133
|
+
`guard` and `check` are *required* checks — those PRs would never be
|
|
134
|
+
mergeable.
|
|
135
|
+
|
|
136
|
+
### Apply the rulesets after the first cut lands on `main`
|
|
137
|
+
|
|
138
|
+
`.github/rulesets/*.json` is inert until `make rulesets-apply`. Each file's
|
|
139
|
+
`bypass_actors` currently only lists the repository-admin role (`actor_id:
|
|
140
|
+
5`, `RepositoryRole`) — add your automation App's Integration id to each
|
|
141
|
+
file once one is set up, the same way `corpora-py` does, or the App won't be
|
|
142
|
+
able to push refreshes without opening a PR for itself.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
make rulesets-diff # what GitHub has now
|
|
146
|
+
make rulesets-apply # push all five files
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`make rulesets-apply` matches by `.name`, so a file must keep the name of the
|
|
150
|
+
ruleset already on GitHub (`Protect main branch`, `Protect dev branch`,
|
|
151
|
+
`Protect next branch`, `Protect release branches`, `Publishing`) or a second
|
|
152
|
+
one is created alongside it.
|
|
153
|
+
|
|
154
|
+
Enable **Allow auto-merge** on the repository. Promote and post-release sync
|
|
155
|
+
PRs use `gh pr merge --auto`.
|
|
156
|
+
|
|
157
|
+
## Bootstrap and manual operations
|
|
158
|
+
|
|
159
|
+
There are no `dev` / `next` branches until the first wrapup. Run the
|
|
160
|
+
**Release** workflow manually (`Actions → Release → Run workflow`) — the
|
|
161
|
+
release job skips and wrapup creates the lanes. Locally:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
make bootstrap-lanes
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`dev` is created from the newest `release/v*` if one exists, otherwise `main`.
|
|
168
|
+
`next` is created from `main`. Then run **Promote to next** (or wait until
|
|
169
|
+
22:00 UTC) once there is work on `dev`.
|
|
170
|
+
|
|
171
|
+
Other useful targets:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
make ci # what CI runs on a PR
|
|
175
|
+
make pack # build the publishable wheel
|
|
176
|
+
make pkg-version # the version in pyproject.toml
|
|
177
|
+
make churn-info FROM=origin/next TO=origin/dev
|
|
178
|
+
make next-version BUMP=patch # what the next tag would be called
|
|
179
|
+
make release-notes RANGE=origin/main..HEAD
|
|
180
|
+
make cleanup-local # prune local feature / release branches
|
|
181
|
+
make rulesets-diff # rulesets GitHub actually has
|
|
182
|
+
make rulesets-apply # push .github/rulesets/*.json
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`make tag-release` is idempotent — a tag already released is skipped, not an
|
|
186
|
+
error.
|
|
187
|
+
|
|
188
|
+
Everything is parameterised on `TRUNK`, so a one-off against a different trunk
|
|
189
|
+
is `make pr-guard TRUNK=some-branch ...`.
|
|
190
|
+
|
|
191
|
+
Scheduled workflows are read from the **default branch**. `promote.yml` will
|
|
192
|
+
not fire on a cron until this file has shipped to `main`.
|
|
193
|
+
|
|
194
|
+
## Secrets
|
|
195
|
+
|
|
196
|
+
| Name | Where | Used by |
|
|
197
|
+
| --------------------------------------------------- | ---------------- | --------------------------- |
|
|
198
|
+
| `AUTOMATION_APP_ID` / `AUTOMATION_APP_PRIVATE_KEY` | repo or org | opening PRs, branches, tags |
|
|
199
|
+
| `CLAUDE_CODE_OAUTH_TOKEN` | repo or org | the AI review (optional) |
|
|
200
|
+
|
|
201
|
+
Neither is set up yet on this scaffold. Without the automation App secrets,
|
|
202
|
+
`promote.yml`, `next.yml`, `pr-merged.yml` and the `wrapup` job in
|
|
203
|
+
`release.yml` will fail at their first step — a PR opened with `GITHUB_TOKEN`
|
|
204
|
+
cannot trigger further workflows, so the release PR's own checks would never
|
|
205
|
+
start. Set these up (a small GitHub App with `contents: write` +
|
|
206
|
+
`pull_requests: write`, installed on this repo) before relying on the
|
|
207
|
+
automated promote/release flow.
|
|
208
|
+
|
|
209
|
+
PyPI needs no secret once set up — `publish.yml` uses OIDC trusted publishing
|
|
210
|
+
against the `pypi` environment. **That binding names the workflow file**, so
|
|
211
|
+
renaming `publish.yml` breaks it until the publisher is re-pointed on PyPI.
|
|
212
|
+
|
|
213
|
+
Without `CLAUDE_CODE_OAUTH_TOKEN` the review job skips with a note in the job
|
|
214
|
+
summary rather than failing.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: 'Build Distribution'
|
|
2
|
+
description: 'Installs uv, builds the sdist and wheel, and uploads them as an artifact'
|
|
3
|
+
runs:
|
|
4
|
+
using: "composite"
|
|
5
|
+
steps:
|
|
6
|
+
- name: Install uv
|
|
7
|
+
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
|
|
8
|
+
with:
|
|
9
|
+
enable-cache: true
|
|
10
|
+
|
|
11
|
+
- name: Build the metabook-py sdist and wheel
|
|
12
|
+
shell: bash
|
|
13
|
+
run: |
|
|
14
|
+
uv build --out-dir dist/
|
|
15
|
+
echo "Built distributions:"
|
|
16
|
+
ls -lh dist/
|
|
17
|
+
|
|
18
|
+
- name: Upload artifact
|
|
19
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
20
|
+
with:
|
|
21
|
+
name: dist
|
|
22
|
+
path: dist/
|
|
23
|
+
if-no-files-found: error
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: "Publish to PyPI"
|
|
2
|
+
description: "Download the metabook-py wheel artifact and publish it to PyPI"
|
|
3
|
+
runs:
|
|
4
|
+
using: "composite"
|
|
5
|
+
steps:
|
|
6
|
+
- name: Install uv
|
|
7
|
+
uses: astral-sh/setup-uv@v5 # v5
|
|
8
|
+
with:
|
|
9
|
+
enable-cache: true
|
|
10
|
+
|
|
11
|
+
- name: Download artifact
|
|
12
|
+
uses: actions/download-artifact@v8 # v4
|
|
13
|
+
with:
|
|
14
|
+
name: dist
|
|
15
|
+
path: dist/
|
|
16
|
+
|
|
17
|
+
- name: List wheels to publish
|
|
18
|
+
shell: bash
|
|
19
|
+
run: ls -lh dist/*.whl dist/*.tar.gz 2>/dev/null || true
|
|
20
|
+
|
|
21
|
+
- name: Publish all distributions to PyPI
|
|
22
|
+
shell: bash
|
|
23
|
+
# `uv publish dist/` passes a directory, which matches no files ("No
|
|
24
|
+
# files found to publish"); uv expects file globs. Bare `uv publish`
|
|
25
|
+
# defaults to the `dist/*` glob and uploads every built wheel.
|
|
26
|
+
run: uv publish
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: Setup
|
|
2
|
+
description: uv and the project's Python toolchain.
|
|
3
|
+
|
|
4
|
+
runs:
|
|
5
|
+
using: composite
|
|
6
|
+
steps:
|
|
7
|
+
- uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7
|
|
8
|
+
with:
|
|
9
|
+
enable-cache: true
|
|
10
|
+
cache-dependency-glob: uv.lock
|
|
11
|
+
|
|
12
|
+
# uv provisions the interpreter itself, so there is no actions/setup-python
|
|
13
|
+
# here. With no argument, it reads .python-version, which is the same file
|
|
14
|
+
# every local checkout resolves against.
|
|
15
|
+
- name: Install Python
|
|
16
|
+
shell: bash
|
|
17
|
+
run: uv python install
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "pip" # See documentation for possible values.
|
|
4
|
+
directory: "/" # Location of package manifests.
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
|
|
8
|
+
# Maintain dependencies for GitHub Actions.
|
|
9
|
+
- package-ecosystem: "github-actions"
|
|
10
|
+
directory: "/"
|
|
11
|
+
schedule:
|
|
12
|
+
interval: "weekly"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Protect dev branch",
|
|
3
|
+
"target": "branch",
|
|
4
|
+
"enforcement": "active",
|
|
5
|
+
"bypass_actors": [
|
|
6
|
+
{
|
|
7
|
+
"actor_id": 5,
|
|
8
|
+
"actor_type": "RepositoryRole",
|
|
9
|
+
"bypass_mode": "always"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"conditions": {
|
|
13
|
+
"ref_name": {
|
|
14
|
+
"include": [
|
|
15
|
+
"refs/heads/dev"
|
|
16
|
+
],
|
|
17
|
+
"exclude": []
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"rules": [
|
|
21
|
+
{
|
|
22
|
+
"type": "deletion"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"type": "non_fast_forward"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"type": "pull_request",
|
|
29
|
+
"parameters": {
|
|
30
|
+
"dismiss_stale_reviews_on_push": true,
|
|
31
|
+
"require_code_owner_review": false,
|
|
32
|
+
"require_last_push_approval": false,
|
|
33
|
+
"required_approving_review_count": 0,
|
|
34
|
+
"required_review_thread_resolution": true,
|
|
35
|
+
"allowed_merge_methods": ["merge"]
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"type": "required_status_checks",
|
|
40
|
+
"parameters": {
|
|
41
|
+
"do_not_enforce_on_create": false,
|
|
42
|
+
"required_status_checks": [
|
|
43
|
+
{
|
|
44
|
+
"context": "guard"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"context": "check"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"strict_required_status_checks_policy": true
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Protect main branch",
|
|
3
|
+
"target": "branch",
|
|
4
|
+
"enforcement": "active",
|
|
5
|
+
"bypass_actors": [
|
|
6
|
+
{
|
|
7
|
+
"actor_id": 5,
|
|
8
|
+
"actor_type": "RepositoryRole",
|
|
9
|
+
"bypass_mode": "always"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"conditions": {
|
|
13
|
+
"ref_name": {
|
|
14
|
+
"include": [
|
|
15
|
+
"refs/heads/main"
|
|
16
|
+
],
|
|
17
|
+
"exclude": []
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"rules": [
|
|
21
|
+
{
|
|
22
|
+
"type": "deletion"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"type": "non_fast_forward"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"type": "pull_request",
|
|
29
|
+
"parameters": {
|
|
30
|
+
"dismiss_stale_reviews_on_push": true,
|
|
31
|
+
"require_code_owner_review": false,
|
|
32
|
+
"require_last_push_approval": false,
|
|
33
|
+
"required_approving_review_count": 0,
|
|
34
|
+
"required_review_thread_resolution": true,
|
|
35
|
+
"allowed_merge_methods": ["merge"]
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"type": "required_status_checks",
|
|
40
|
+
"parameters": {
|
|
41
|
+
"do_not_enforce_on_create": false,
|
|
42
|
+
"required_status_checks": [
|
|
43
|
+
{
|
|
44
|
+
"context": "guard"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"context": "check"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"context": "package"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"strict_required_status_checks_policy": true
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Protect next branch",
|
|
3
|
+
"target": "branch",
|
|
4
|
+
"enforcement": "active",
|
|
5
|
+
"bypass_actors": [
|
|
6
|
+
{
|
|
7
|
+
"actor_id": 5,
|
|
8
|
+
"actor_type": "RepositoryRole",
|
|
9
|
+
"bypass_mode": "always"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"conditions": {
|
|
13
|
+
"ref_name": {
|
|
14
|
+
"include": [
|
|
15
|
+
"refs/heads/next"
|
|
16
|
+
],
|
|
17
|
+
"exclude": []
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"rules": [
|
|
21
|
+
{
|
|
22
|
+
"type": "deletion"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"type": "non_fast_forward"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"type": "pull_request",
|
|
29
|
+
"parameters": {
|
|
30
|
+
"dismiss_stale_reviews_on_push": true,
|
|
31
|
+
"require_code_owner_review": false,
|
|
32
|
+
"require_last_push_approval": false,
|
|
33
|
+
"required_approving_review_count": 0,
|
|
34
|
+
"required_review_thread_resolution": true,
|
|
35
|
+
"allowed_merge_methods": ["merge"]
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"type": "required_status_checks",
|
|
40
|
+
"parameters": {
|
|
41
|
+
"do_not_enforce_on_create": false,
|
|
42
|
+
"required_status_checks": [
|
|
43
|
+
{
|
|
44
|
+
"context": "guard"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"context": "check"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"strict_required_status_checks_policy": true
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Protect release branches",
|
|
3
|
+
"target": "branch",
|
|
4
|
+
"enforcement": "active",
|
|
5
|
+
"bypass_actors": [
|
|
6
|
+
{
|
|
7
|
+
"actor_id": 5,
|
|
8
|
+
"actor_type": "RepositoryRole",
|
|
9
|
+
"bypass_mode": "always"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"conditions": {
|
|
13
|
+
"ref_name": {
|
|
14
|
+
"include": [
|
|
15
|
+
"refs/heads/release/v*"
|
|
16
|
+
],
|
|
17
|
+
"exclude": []
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"rules": [
|
|
21
|
+
{
|
|
22
|
+
"type": "non_fast_forward"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"type": "pull_request",
|
|
26
|
+
"parameters": {
|
|
27
|
+
"dismiss_stale_reviews_on_push": false,
|
|
28
|
+
"require_code_owner_review": false,
|
|
29
|
+
"require_last_push_approval": false,
|
|
30
|
+
"required_approving_review_count": 0,
|
|
31
|
+
"required_review_thread_resolution": false,
|
|
32
|
+
"allowed_merge_methods": ["squash", "merge"]
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"type": "required_status_checks",
|
|
37
|
+
"parameters": {
|
|
38
|
+
"do_not_enforce_on_create": false,
|
|
39
|
+
"required_status_checks": [
|
|
40
|
+
{
|
|
41
|
+
"context": "guard"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"context": "check"
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"strict_required_status_checks_policy": false
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Publishing",
|
|
3
|
+
"target": "tag",
|
|
4
|
+
"enforcement": "active",
|
|
5
|
+
"bypass_actors": [
|
|
6
|
+
{
|
|
7
|
+
"actor_id": 5,
|
|
8
|
+
"actor_type": "RepositoryRole",
|
|
9
|
+
"bypass_mode": "always"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"conditions": {
|
|
13
|
+
"ref_name": {
|
|
14
|
+
"exclude": [],
|
|
15
|
+
"include": [
|
|
16
|
+
"refs/tags/v*"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"rules": [
|
|
21
|
+
{
|
|
22
|
+
"type": "deletion"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"type": "non_fast_forward"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"type": "creation"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"type": "update"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"type": "required_signatures"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: Dependabot auto-merge
|
|
2
|
+
|
|
3
|
+
on: pull_request
|
|
4
|
+
|
|
5
|
+
# NOTE: "workflows" is not a valid permission scope — its presence made this
|
|
6
|
+
# file unparseable, so GitHub reported a failed run on EVERY push. Dependabot
|
|
7
|
+
# PRs that modify workflow files can't be auto-merged by GITHUB_TOKEN anyway
|
|
8
|
+
# (that needs the `workflow` OAuth scope, which isn't grantable here).
|
|
9
|
+
permissions:
|
|
10
|
+
contents: write
|
|
11
|
+
pull-requests: write
|
|
12
|
+
jobs:
|
|
13
|
+
dependabot:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
if: ${{ github.actor == 'dependabot[bot]' }}
|
|
16
|
+
steps:
|
|
17
|
+
- name: Enable auto-merge for Dependabot PRs
|
|
18
|
+
run: gh pr merge --auto --merge "$PR_URL"
|
|
19
|
+
env:
|
|
20
|
+
PR_URL: ${{github.event.pull_request.html_url}}
|
|
21
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Cross-platform, cross-version coverage.
|
|
2
|
+
#
|
|
3
|
+
# `check` in pr.yml is deliberately a single job on one runner: it is a
|
|
4
|
+
# required status check on main, and a matrixed job reports contexts like
|
|
5
|
+
# "check (macos-latest, 3.14)" rather than the plain "check" the ruleset names,
|
|
6
|
+
# which would leave every PR unmergeable. This workflow keeps the breadth an
|
|
7
|
+
# os x Python matrix needs — ubuntu + macOS across the supported Python
|
|
8
|
+
# versions — where it does not collide with a required context:
|
|
9
|
+
#
|
|
10
|
+
# * every push to `next` or a release branch, so a macOS- or 3.14-only break
|
|
11
|
+
# surfaces on staging / the in-flight RC rather than on the release PR;
|
|
12
|
+
# * weekly, to catch upstream dependency drift on an untouched tree;
|
|
13
|
+
# * on demand.
|
|
14
|
+
name: Matrix
|
|
15
|
+
|
|
16
|
+
on:
|
|
17
|
+
push:
|
|
18
|
+
branches:
|
|
19
|
+
- next
|
|
20
|
+
- "release/v*"
|
|
21
|
+
schedule:
|
|
22
|
+
# Every Sunday at 8:05 UTC.
|
|
23
|
+
- cron: "5 8 * * 0"
|
|
24
|
+
workflow_dispatch:
|
|
25
|
+
|
|
26
|
+
concurrency:
|
|
27
|
+
group: matrix-${{ github.ref }}
|
|
28
|
+
cancel-in-progress: true
|
|
29
|
+
|
|
30
|
+
permissions:
|
|
31
|
+
contents: read
|
|
32
|
+
|
|
33
|
+
jobs:
|
|
34
|
+
test:
|
|
35
|
+
name: test (${{ matrix.os }}, ${{ matrix.python-version }})
|
|
36
|
+
runs-on: ${{ matrix.os }}
|
|
37
|
+
strategy:
|
|
38
|
+
fail-fast: false
|
|
39
|
+
matrix:
|
|
40
|
+
os: [ ubuntu-latest, macos-latest ]
|
|
41
|
+
python-version: [ "3.13", "3.14" ]
|
|
42
|
+
|
|
43
|
+
# uv provisions the matrix Python itself, overriding .python-version.
|
|
44
|
+
env:
|
|
45
|
+
UV_PYTHON: ${{ matrix.python-version }}
|
|
46
|
+
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
49
|
+
|
|
50
|
+
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
|
|
51
|
+
with:
|
|
52
|
+
enable-cache: true
|
|
53
|
+
cache-dependency-glob: uv.lock
|
|
54
|
+
|
|
55
|
+
- name: Install Python ${{ matrix.python-version }}
|
|
56
|
+
run: uv python install ${{ matrix.python-version }}
|
|
57
|
+
|
|
58
|
+
- run: make ci
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# `next` moved: cut/refresh `release/vX.Y.Z`.
|
|
2
|
+
#
|
|
3
|
+
# `pr.yml` already ran the full suite on the promote PR, so this only versions.
|
|
4
|
+
# Pushing the release branch is what starts pr-merged.yml, which opens or
|
|
5
|
+
# refreshes the draft PR into main.
|
|
6
|
+
name: Next
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
branches:
|
|
11
|
+
- next
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: next
|
|
16
|
+
cancel-in-progress: false
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
cut-release:
|
|
23
|
+
name: cut-release
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3
|
|
27
|
+
id: app-token
|
|
28
|
+
with:
|
|
29
|
+
app-id: ${{ secrets.AUTOMATION_APP_ID }}
|
|
30
|
+
private-key: ${{ secrets.AUTOMATION_APP_PRIVATE_KEY }}
|
|
31
|
+
|
|
32
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
33
|
+
with:
|
|
34
|
+
fetch-depth: 0
|
|
35
|
+
fetch-tags: true
|
|
36
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
37
|
+
|
|
38
|
+
# `make cut-release` re-locks: uv.lock pins the workspace versions.
|
|
39
|
+
- uses: ./.github/actions/setup
|
|
40
|
+
|
|
41
|
+
- name: Cut or refresh the release branch
|
|
42
|
+
env:
|
|
43
|
+
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
|
44
|
+
GH_REPO: ${{ github.repository }}
|
|
45
|
+
run: |
|
|
46
|
+
git config user.name "metabook-automation[bot]"
|
|
47
|
+
git config user.email "metabook-automation[bot]@users.noreply.github.com"
|
|
48
|
+
make cut-release
|