little-sister-github 0.1.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.
- little_sister_github-0.1.0/LICENSE +21 -0
- little_sister_github-0.1.0/PKG-INFO +141 -0
- little_sister_github-0.1.0/README.md +119 -0
- little_sister_github-0.1.0/pyproject.toml +125 -0
- little_sister_github-0.1.0/src/little_sister_github/__init__.py +24 -0
- little_sister_github-0.1.0/src/little_sister_github/github.py +1091 -0
- little_sister_github-0.1.0/src/little_sister_github/py.typed +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Michael Meyling
|
|
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.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: little-sister-github
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: GitHub overview check type for little-sister.
|
|
5
|
+
Keywords: monitoring,status,github,little-sister
|
|
6
|
+
Author: Michael Meyling
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Requires-Dist: little-sister>=0.3.11
|
|
16
|
+
Requires-Python: >=3.11
|
|
17
|
+
Project-URL: homepage, https://github.com/m-31/little-sister-github
|
|
18
|
+
Project-URL: repository, https://github.com/m-31/little-sister-github
|
|
19
|
+
Project-URL: issues, https://github.com/m-31/little-sister-github/issues
|
|
20
|
+
Project-URL: changelog, https://github.com/m-31/little-sister-github/blob/main/CHANGELOG.md
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# little-sister-github
|
|
24
|
+
|
|
25
|
+
The **`github`** check type for [little-sister](https://github.com/m-31/little-sister):
|
|
26
|
+
one node per configured team, with a child per aspect — open pull requests,
|
|
27
|
+
Dependabot advisories, code-scanning and secret-scanning alerts, SBOM presence,
|
|
28
|
+
workflow runs and open issues.
|
|
29
|
+
|
|
30
|
+
Every finding is an individually addressable line, so an operator who opens a
|
|
31
|
+
ticket for one alert can put **that line** into maintenance and the rest of the
|
|
32
|
+
aspect keeps reporting.
|
|
33
|
+
|
|
34
|
+
## The contract
|
|
35
|
+
|
|
36
|
+
- **Requires** `little-sister >= 0.3.11` — a floor, never a pin.
|
|
37
|
+
- **Runs on** Python **3.11 or newer** — the library's floor, not a higher
|
|
38
|
+
one of its own.
|
|
39
|
+
- **Registers** one check type: **`github`**.
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
```toml
|
|
44
|
+
# your deployment's pyproject.toml
|
|
45
|
+
[project]
|
|
46
|
+
dependencies = ["little-sister", "little-sister-github"]
|
|
47
|
+
|
|
48
|
+
# Only while *this* one comes from git: little-sister resolves from the index.
|
|
49
|
+
# Delete the table once this package is on an index too — nothing else changes.
|
|
50
|
+
[tool.uv.sources]
|
|
51
|
+
little-sister-github = { git = "…/little-sister-github.git", tag = "v0.1.0" }
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
# wsgi.py — registrations first, the app last. The order is load-bearing:
|
|
56
|
+
# importing little_sister.app builds the engine and loads the check configs, so
|
|
57
|
+
# every check type must already be registered. `isort: off` keeps an import
|
|
58
|
+
# sorter from quietly reversing that.
|
|
59
|
+
# isort: off
|
|
60
|
+
import little_sister_github # noqa: F401 registers the `github` type
|
|
61
|
+
from little_sister.app import app
|
|
62
|
+
# isort: on
|
|
63
|
+
|
|
64
|
+
__all__ = ["app"] # without it, lint calls the app import unused
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Configure
|
|
68
|
+
|
|
69
|
+
Copy [`examples/github.yaml`](https://github.com/m-31/little-sister-github/blob/v0.1.0/examples/github.yaml) into your deployment's
|
|
70
|
+
`config/checks/`, set `org`, `team` and the token reference, and you are done —
|
|
71
|
+
one file per team. The credential is a **reference**, never a value:
|
|
72
|
+
|
|
73
|
+
```yaml
|
|
74
|
+
type: github
|
|
75
|
+
path: /platform/github
|
|
76
|
+
secrets:
|
|
77
|
+
token: env://PLATFORM_GITHUB_TOKEN
|
|
78
|
+
org: example-org
|
|
79
|
+
team: platform
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The token needs `read:org`, `repo`, `security_events` and dependency-graph read
|
|
83
|
+
access. Each team's check carries its own credential, so a second team is a second
|
|
84
|
+
config file rather than a code change.
|
|
85
|
+
|
|
86
|
+
The per-aspect display text ships **with the type** and expands `{org}` / `{team}`
|
|
87
|
+
from the config, so it is not copied per team. Your deployment's own policy — a
|
|
88
|
+
remediation deadline, who to notify — goes in that config's `subnodes:` block,
|
|
89
|
+
appended to the shipped text with `{default}`.
|
|
90
|
+
|
|
91
|
+
## What it reads
|
|
92
|
+
|
|
93
|
+
| Aspect | Endpoint | Grade |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `pull_requests` | `GET /repos/{r}/pulls?state=open` | any open PR (minus `ignore_title_prefixes`) → **WARN** |
|
|
96
|
+
| `security_advisories` | `GET /repos/{r}/dependabot/alerts?state=open` | one leaf per selected severity, graded by `security_advisories.severity_map` |
|
|
97
|
+
| `code_scanning_alerts` | `GET /repos/{r}/code-scanning/alerts?state=open` | one leaf per severity, graded by `code_scanning_alerts.severity_map` |
|
|
98
|
+
| `secret_scanning_alerts` | `GET /repos/{r}/secret-scanning/alerts?state=open` | any open alert → **ERROR**; scanning disabled → **ERROR** (`secret_scanning.require_enabled`) |
|
|
99
|
+
| `sbom_check` | `GET /repos/{r}/dependency-graph/sbom` | no dependency graph → **ERROR** (`sbom_check.ignore`) |
|
|
100
|
+
| `actions` | `GET /repos/{r}/actions/runs` | coded entries: last completed verdict, plus a newer in-flight run |
|
|
101
|
+
| `issues` | `GET /repos/{r}/issues?state=open` | any open issue → **WARN** (`issues.ignore`); issues disabled → **WARN** |
|
|
102
|
+
|
|
103
|
+
The check's own node carries the discovery coverage reading (`expect_min_repos`)
|
|
104
|
+
and the repository roster, and rolls up worst-of its aspects. Only stdlib
|
|
105
|
+
`urllib` is used — the package has no dependency but little-sister itself.
|
|
106
|
+
|
|
107
|
+
## Develop
|
|
108
|
+
|
|
109
|
+
little-sister is declared as a **floor** — the release that promised the surface
|
|
110
|
+
this package imports — and it resolves **from the index**, like any other
|
|
111
|
+
dependency. There is no `[tool.uv.sources]` table here, and the committed
|
|
112
|
+
`uv.lock` is what a release runs against. To work against a local library
|
|
113
|
+
checkout, add the redirect and **do not commit it**: uv reads the sources table of
|
|
114
|
+
a dependency it resolves from a path or a checkout, so a committed line would
|
|
115
|
+
follow this package into every deployment that installs it.
|
|
116
|
+
|
|
117
|
+
```toml
|
|
118
|
+
# pyproject.toml — locally, never committed
|
|
119
|
+
[tool.uv.sources]
|
|
120
|
+
little-sister = { path = "../little-sister" }
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Restore `uv.lock` with it. The next `uv run` — the pre-commit gate is one — rewrites
|
|
124
|
+
the lock to `source = { directory = … }`, so a redirect kept out of `pyproject.toml`
|
|
125
|
+
can still reach a commit through the lock beside it.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
uv sync
|
|
129
|
+
uv run ruff check
|
|
130
|
+
uv run mypy
|
|
131
|
+
uv run mypy --python-version 3.11 # against the floor, not the interpreter you have
|
|
132
|
+
uv run pytest -q
|
|
133
|
+
# The same gate runs before every commit once the hook is enabled:
|
|
134
|
+
git config core.hooksPath hooks
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The tests are fixture-based; nothing in this repository calls GitHub.
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT — see [LICENSE](https://github.com/m-31/little-sister-github/blob/v0.1.0/LICENSE).
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# little-sister-github
|
|
2
|
+
|
|
3
|
+
The **`github`** check type for [little-sister](https://github.com/m-31/little-sister):
|
|
4
|
+
one node per configured team, with a child per aspect — open pull requests,
|
|
5
|
+
Dependabot advisories, code-scanning and secret-scanning alerts, SBOM presence,
|
|
6
|
+
workflow runs and open issues.
|
|
7
|
+
|
|
8
|
+
Every finding is an individually addressable line, so an operator who opens a
|
|
9
|
+
ticket for one alert can put **that line** into maintenance and the rest of the
|
|
10
|
+
aspect keeps reporting.
|
|
11
|
+
|
|
12
|
+
## The contract
|
|
13
|
+
|
|
14
|
+
- **Requires** `little-sister >= 0.3.11` — a floor, never a pin.
|
|
15
|
+
- **Runs on** Python **3.11 or newer** — the library's floor, not a higher
|
|
16
|
+
one of its own.
|
|
17
|
+
- **Registers** one check type: **`github`**.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```toml
|
|
22
|
+
# your deployment's pyproject.toml
|
|
23
|
+
[project]
|
|
24
|
+
dependencies = ["little-sister", "little-sister-github"]
|
|
25
|
+
|
|
26
|
+
# Only while *this* one comes from git: little-sister resolves from the index.
|
|
27
|
+
# Delete the table once this package is on an index too — nothing else changes.
|
|
28
|
+
[tool.uv.sources]
|
|
29
|
+
little-sister-github = { git = "…/little-sister-github.git", tag = "v0.1.0" }
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
# wsgi.py — registrations first, the app last. The order is load-bearing:
|
|
34
|
+
# importing little_sister.app builds the engine and loads the check configs, so
|
|
35
|
+
# every check type must already be registered. `isort: off` keeps an import
|
|
36
|
+
# sorter from quietly reversing that.
|
|
37
|
+
# isort: off
|
|
38
|
+
import little_sister_github # noqa: F401 registers the `github` type
|
|
39
|
+
from little_sister.app import app
|
|
40
|
+
# isort: on
|
|
41
|
+
|
|
42
|
+
__all__ = ["app"] # without it, lint calls the app import unused
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Configure
|
|
46
|
+
|
|
47
|
+
Copy [`examples/github.yaml`](https://github.com/m-31/little-sister-github/blob/v0.1.0/examples/github.yaml) into your deployment's
|
|
48
|
+
`config/checks/`, set `org`, `team` and the token reference, and you are done —
|
|
49
|
+
one file per team. The credential is a **reference**, never a value:
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
type: github
|
|
53
|
+
path: /platform/github
|
|
54
|
+
secrets:
|
|
55
|
+
token: env://PLATFORM_GITHUB_TOKEN
|
|
56
|
+
org: example-org
|
|
57
|
+
team: platform
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The token needs `read:org`, `repo`, `security_events` and dependency-graph read
|
|
61
|
+
access. Each team's check carries its own credential, so a second team is a second
|
|
62
|
+
config file rather than a code change.
|
|
63
|
+
|
|
64
|
+
The per-aspect display text ships **with the type** and expands `{org}` / `{team}`
|
|
65
|
+
from the config, so it is not copied per team. Your deployment's own policy — a
|
|
66
|
+
remediation deadline, who to notify — goes in that config's `subnodes:` block,
|
|
67
|
+
appended to the shipped text with `{default}`.
|
|
68
|
+
|
|
69
|
+
## What it reads
|
|
70
|
+
|
|
71
|
+
| Aspect | Endpoint | Grade |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| `pull_requests` | `GET /repos/{r}/pulls?state=open` | any open PR (minus `ignore_title_prefixes`) → **WARN** |
|
|
74
|
+
| `security_advisories` | `GET /repos/{r}/dependabot/alerts?state=open` | one leaf per selected severity, graded by `security_advisories.severity_map` |
|
|
75
|
+
| `code_scanning_alerts` | `GET /repos/{r}/code-scanning/alerts?state=open` | one leaf per severity, graded by `code_scanning_alerts.severity_map` |
|
|
76
|
+
| `secret_scanning_alerts` | `GET /repos/{r}/secret-scanning/alerts?state=open` | any open alert → **ERROR**; scanning disabled → **ERROR** (`secret_scanning.require_enabled`) |
|
|
77
|
+
| `sbom_check` | `GET /repos/{r}/dependency-graph/sbom` | no dependency graph → **ERROR** (`sbom_check.ignore`) |
|
|
78
|
+
| `actions` | `GET /repos/{r}/actions/runs` | coded entries: last completed verdict, plus a newer in-flight run |
|
|
79
|
+
| `issues` | `GET /repos/{r}/issues?state=open` | any open issue → **WARN** (`issues.ignore`); issues disabled → **WARN** |
|
|
80
|
+
|
|
81
|
+
The check's own node carries the discovery coverage reading (`expect_min_repos`)
|
|
82
|
+
and the repository roster, and rolls up worst-of its aspects. Only stdlib
|
|
83
|
+
`urllib` is used — the package has no dependency but little-sister itself.
|
|
84
|
+
|
|
85
|
+
## Develop
|
|
86
|
+
|
|
87
|
+
little-sister is declared as a **floor** — the release that promised the surface
|
|
88
|
+
this package imports — and it resolves **from the index**, like any other
|
|
89
|
+
dependency. There is no `[tool.uv.sources]` table here, and the committed
|
|
90
|
+
`uv.lock` is what a release runs against. To work against a local library
|
|
91
|
+
checkout, add the redirect and **do not commit it**: uv reads the sources table of
|
|
92
|
+
a dependency it resolves from a path or a checkout, so a committed line would
|
|
93
|
+
follow this package into every deployment that installs it.
|
|
94
|
+
|
|
95
|
+
```toml
|
|
96
|
+
# pyproject.toml — locally, never committed
|
|
97
|
+
[tool.uv.sources]
|
|
98
|
+
little-sister = { path = "../little-sister" }
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Restore `uv.lock` with it. The next `uv run` — the pre-commit gate is one — rewrites
|
|
102
|
+
the lock to `source = { directory = … }`, so a redirect kept out of `pyproject.toml`
|
|
103
|
+
can still reach a commit through the lock beside it.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
uv sync
|
|
107
|
+
uv run ruff check
|
|
108
|
+
uv run mypy
|
|
109
|
+
uv run mypy --python-version 3.11 # against the floor, not the interpreter you have
|
|
110
|
+
uv run pytest -q
|
|
111
|
+
# The same gate runs before every commit once the hook is enabled:
|
|
112
|
+
git config core.hooksPath hooks
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The tests are fixture-based; nothing in this repository calls GitHub.
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
MIT — see [LICENSE](https://github.com/m-31/little-sister-github/blob/v0.1.0/LICENSE).
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "little-sister-github"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "GitHub overview check type for little-sister."
|
|
5
|
+
authors = [
|
|
6
|
+
{ name = "Michael Meyling" }
|
|
7
|
+
]
|
|
8
|
+
readme = {file = "README.md", content-type = "text/markdown"}
|
|
9
|
+
license = "MIT"
|
|
10
|
+
license-files = ["LICENSE"]
|
|
11
|
+
keywords = ["monitoring", "status", "github", "little-sister"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Programming Language :: Python :: 3.14",
|
|
19
|
+
]
|
|
20
|
+
# The **library's floor**, not the interpreter this is developed on
|
|
21
|
+
# (little-sister ADR-0054). Asking for more than the library asks would mean
|
|
22
|
+
# somebody installs little-sister on 3.12 and then cannot install the package
|
|
23
|
+
# that was the reason they came — and metadata is frozen per artifact, so
|
|
24
|
+
# correcting it afterwards costs a version. The classifiers above repeat the
|
|
25
|
+
# same claim for a human reading the index rather than a resolver, which is why
|
|
26
|
+
# they start at the floor and run contiguously; the release check refuses a
|
|
27
|
+
# disagreement between the two.
|
|
28
|
+
requires-python = ">=3.11"
|
|
29
|
+
# A **floor, and never a pin.** A deployment pins little-sister; two plugins that
|
|
30
|
+
# each pinned an exact version could not be installed together at all. The floor
|
|
31
|
+
# names the release that promised the check-authoring surface this module imports
|
|
32
|
+
# (little-sister architecture.md §11) — a statement about that surface, not about
|
|
33
|
+
# a release. The upgrade a floor cannot see, the library moving *past* the
|
|
34
|
+
# surface, is caught by `require_api()` in `__init__.py`.
|
|
35
|
+
#
|
|
36
|
+
# **0.3.11 rather than 0.3.0**, which is where the surface was first promised:
|
|
37
|
+
# 0.3.0 was tagged but never uploaded, so it names no version a resolver can
|
|
38
|
+
# actually fetch, and it is 0.3.11 that lowered the library's own floor to 3.11 —
|
|
39
|
+
# the floor this package promises above. A lower number would ask the index for
|
|
40
|
+
# something it does not have, on an interpreter the answer could not run.
|
|
41
|
+
dependencies = [
|
|
42
|
+
"little-sister>=0.3.11",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
# The public home, and the reason it was absent until now: metadata pointing at a
|
|
46
|
+
# URL that does not resolve is worse than metadata that says nothing.
|
|
47
|
+
#
|
|
48
|
+
# `repository` is **load-bearing, not a duplicate of `homepage`**: the release
|
|
49
|
+
# refuses without it, and the published README's absolute links are built from it at
|
|
50
|
+
# build time — `blob/v<version>`, so a link is immutable and cannot outlive the
|
|
51
|
+
# artifact that carries it. Relocating the forge is then an edit to this one line.
|
|
52
|
+
#
|
|
53
|
+
# No `documentation` key: for a package this size the README *is* the documentation,
|
|
54
|
+
# and it arrives with the artifact. A key pointing at a directory that holds one
|
|
55
|
+
# design record would promise a manual that does not exist.
|
|
56
|
+
[project.urls]
|
|
57
|
+
homepage = "https://github.com/m-31/little-sister-github"
|
|
58
|
+
repository = "https://github.com/m-31/little-sister-github"
|
|
59
|
+
issues = "https://github.com/m-31/little-sister-github/issues"
|
|
60
|
+
changelog = "https://github.com/m-31/little-sister-github/blob/main/CHANGELOG.md"
|
|
61
|
+
|
|
62
|
+
# The one line that differs from a deployment's pyproject.toml: a plugin is a
|
|
63
|
+
# **built** package, so a consumer can install it from a tag (and later an index).
|
|
64
|
+
[tool.uv]
|
|
65
|
+
package = true
|
|
66
|
+
|
|
67
|
+
# **No `[tool.uv.sources]`, deliberately.** little-sister is on the index, so the
|
|
68
|
+
# floor above resolves like any other dependency and there is nothing left to
|
|
69
|
+
# redirect. The table is not merely unnecessary now, it is harmful: uv reads the
|
|
70
|
+
# sources table of a dependency it resolves from a path or a git checkout, so a
|
|
71
|
+
# committed line here would be imposed on **every deployment that installs this
|
|
72
|
+
# package** (little-sister `plugin-repository.md` §3).
|
|
73
|
+
#
|
|
74
|
+
# To develop against a local library checkout, add the redirect and do not commit
|
|
75
|
+
# it:
|
|
76
|
+
#
|
|
77
|
+
# [tool.uv.sources]
|
|
78
|
+
# little-sister = { path = "../little-sister" }
|
|
79
|
+
#
|
|
80
|
+
# It leaves a second trace: the next `uv run` rewrites the committed `uv.lock` to
|
|
81
|
+
# `source = { directory = … }`, and the pre-commit gate is a `uv run`. Restore both
|
|
82
|
+
# files before committing, or the path this table exists to keep out of the package
|
|
83
|
+
# arrives in the lock instead.
|
|
84
|
+
|
|
85
|
+
[dependency-groups]
|
|
86
|
+
# Floors match little-sister's dev group, so every repository in the family runs
|
|
87
|
+
# one gate and a contributor moving between them meets one set of rules.
|
|
88
|
+
dev = [
|
|
89
|
+
"mypy>=2.1.0",
|
|
90
|
+
"pytest>=9.0.3",
|
|
91
|
+
"pytest-cov>=7.1.0",
|
|
92
|
+
"ruff>=0.16.1",
|
|
93
|
+
"types-PyYAML",
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
[tool.ruff]
|
|
97
|
+
target-version = "py311"
|
|
98
|
+
|
|
99
|
+
[tool.ruff.lint]
|
|
100
|
+
# Copied from little-sister as it stands. Beyond ruff's default (E, F): import
|
|
101
|
+
# sorting (I), pyupgrade (UP), bugbear (B), comprehensions (C4) and Ruff's own
|
|
102
|
+
# rules (RUF). The ambiguous-unicode rules are off: reason and subnode text use
|
|
103
|
+
# typographic "—", "…" and "×" on purpose.
|
|
104
|
+
select = ["E", "F", "W", "I", "UP", "B", "C4", "RUF"]
|
|
105
|
+
ignore = ["RUF001", "RUF002", "RUF003"]
|
|
106
|
+
|
|
107
|
+
[tool.mypy]
|
|
108
|
+
files = ["src"]
|
|
109
|
+
strict = true
|
|
110
|
+
|
|
111
|
+
[tool.pytest.ini_options]
|
|
112
|
+
# Adapted, not copied: little-sister's own `addopts` names `--cov=little_sister`,
|
|
113
|
+
# which from here would measure somebody else's code.
|
|
114
|
+
addopts = "--cov=little_sister_github --cov-report=term-missing"
|
|
115
|
+
|
|
116
|
+
[build-system]
|
|
117
|
+
# One **major** line, not the `<0.12.0` uv generates: that pins the minor uv shipped
|
|
118
|
+
# with and turns every uv upgrade into a release-blocking edit in every repository of
|
|
119
|
+
# the family. The backend's contract here is one sentence long — a
|
|
120
|
+
# `src/<import package>` layout — so a minor bump has nothing to break, and what
|
|
121
|
+
# would notice one that changed the artifact anyway is not vigilance but the publish
|
|
122
|
+
# step, which opens the wheel and the sdist and refuses anything the release tree
|
|
123
|
+
# drops. Same bound as little-sister, verified there against both minors.
|
|
124
|
+
requires = ["uv_build>=0.11.14,<1.0.0"]
|
|
125
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""little-sister check type: ``github``.
|
|
2
|
+
|
|
3
|
+
Importing this package registers the type in little-sister's ``CHECK_TYPES``. A
|
|
4
|
+
deployment therefore needs one line in its ``wsgi.py``, before it imports
|
|
5
|
+
``little_sister.app``::
|
|
6
|
+
|
|
7
|
+
import little_sister_github # noqa: F401 registers its type
|
|
8
|
+
from little_sister.app import app # noqa: E402 builds the engine
|
|
9
|
+
|
|
10
|
+
``require_api`` declares the **check API epoch** this package was built for. It
|
|
11
|
+
refuses at startup, naming both epochs, when the library has moved past the
|
|
12
|
+
surface below — the upgrade an install-time floor cannot see, because a floor has
|
|
13
|
+
no ceiling (little-sister ADR-0051). Without it the same mismatch would surface as
|
|
14
|
+
an ``ImportError`` from inside this package, which reads like our bug.
|
|
15
|
+
"""
|
|
16
|
+
from little_sister.checks import require_api
|
|
17
|
+
|
|
18
|
+
require_api(1)
|
|
19
|
+
|
|
20
|
+
from little_sister_github import github # noqa: E402 registers the type
|
|
21
|
+
|
|
22
|
+
__version__ = "0.1.0"
|
|
23
|
+
|
|
24
|
+
__all__ = ["github"]
|