Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ jobs:
- name: Install
run: python -m pip install -e ".[dev]"
- name: Lint
run: ruff check .
run: |
ruff check .
ruff format --check .
- name: Unit and contract tests
run: python -m pytest -q
- name: Consumer install test (fresh venv)
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ Format: [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), [Semantic Vers

## [Unreleased]

### Geändert / Changed

- Gesamter Baum mit `ruff format` formatiert (keine Codeänderung, AST identisch); CI prüft jetzt
zusätzlich `ruff format --check` / whole tree formatted with `ruff format` (no code change, AST
identical); CI now also runs `ruff format --check`.
- README (EN/DE) mit Banner (`assets/banner.png`, Quelle `assets/banner.svg`); Testkommentar
neutral formuliert / README banner added; a test comment worded neutrally.

## [0.2.1] - 2026-10-11

### Geändert / Changed
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ gelten Pull Requests unter der Lizenz des Projekts.
pip install -e ".[dev]"
python -m pytest
ruff check .
ruff format --check .
```

Schreibende Funktionen laufen ausschließlich über `githubbot_core.actions` (Vorschau/Ausführen,
Expand Down Expand Up @@ -81,6 +82,7 @@ pull requests are understood to be submitted under the project's license.
pip install -e ".[dev]"
python -m pytest
ruff check .
ruff format --check .
```

Every write goes through `githubbot_core.actions` (preview/apply, permission
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# githubbot-core

<p align="center"><img src="assets/banner.png" width="100%" alt="githubbot-core banner"></p>

**English** | [Deutsch](README_de.md)

Neutral, installable core for GitHub repository maintenance: issue triage, duplicate detection,
Expand Down Expand Up @@ -128,21 +130,22 @@ my-extension = "my_extension:create"
from githubbot_core.actions import Action
from githubbot_core.plugins import SPI_VERSION


class MyExtension:
name = "my-extension"
spi_version = SPI_VERSION

def describe(self):
return {"version": "1.0.0", "capabilities": ["plan"]}

def plan(self, ctx): # ctx.config, ctx.transport (read-only), ctx.args
def plan(self, ctx): # ctx.config, ctx.transport (read-only), ctx.args
data, error = ctx.transport.get("repos/owner/repo")
return [Action("api.request", {"method": "PUT", "endpoint": "user/starred/owner/repo"},
reason="example")]
return [Action("api.request", {"method": "PUT", "endpoint": "user/starred/owner/repo"}, reason="example")]

def pr_policy_checks(self, pr, files, diff): # optional
def pr_policy_checks(self, pr, files, diff): # optional
return [("no_large_binaries", True, "OK")]


def create():
return MyExtension()
```
Expand All @@ -164,6 +167,7 @@ trust boundaries and rollback: [docs/REVIEW_GATE.md](docs/REVIEW_GATE.md).
pip install -e ".[dev]"
python -m pytest # unit and contract tests
ruff check .
ruff format --check .
GITHUBBOT_CORE_CONSUMER_TEST=1 python -m pytest tests/test_consumer_install.py # fresh-venv install test
```

Expand Down
12 changes: 8 additions & 4 deletions README_de.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# githubbot-core

<p align="center"><img src="assets/banner.png" width="100%" alt="githubbot-core Banner"></p>

[English](README.md) | **Deutsch**

Neutraler, installierbarer Kern für die Pflege von GitHub-Repositories: Issue-Triage,
Expand Down Expand Up @@ -130,21 +132,22 @@ my-extension = "my_extension:create"
from githubbot_core.actions import Action
from githubbot_core.plugins import SPI_VERSION


class MyExtension:
name = "my-extension"
spi_version = SPI_VERSION

def describe(self):
return {"version": "1.0.0", "capabilities": ["plan"]}

def plan(self, ctx): # ctx.config, ctx.transport (nur lesend), ctx.args
def plan(self, ctx): # ctx.config, ctx.transport (nur lesend), ctx.args
data, error = ctx.transport.get("repos/owner/repo")
return [Action("api.request", {"method": "PUT", "endpoint": "user/starred/owner/repo"},
reason="example")]
return [Action("api.request", {"method": "PUT", "endpoint": "user/starred/owner/repo"}, reason="example")]

def pr_policy_checks(self, pr, files, diff): # optional
def pr_policy_checks(self, pr, files, diff): # optional
return [("no_large_binaries", True, "OK")]


def create():
return MyExtension()
```
Expand All @@ -166,6 +169,7 @@ Details, Vertrauensgrenzen und Rollback: [docs/REVIEW_GATE.md](docs/REVIEW_GATE.
pip install -e ".[dev]"
python -m pytest # Unit- und Vertragstests
ruff check .
ruff format --check .
GITHUBBOT_CORE_CONSUMER_TEST=1 python -m pytest tests/test_consumer_install.py # Installationstest im frischen venv
```

Expand Down
Binary file added assets/banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
141 changes: 141 additions & 0 deletions assets/banner.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 13 additions & 4 deletions src/githubbot_core/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,23 @@ def apply(
"""Execute permitted actions. Every action gets exactly one receipt."""
digest = plan_digest(actions)
if expected_plan_sha256 and expected_plan_sha256 != digest:
return {"mode": "apply", "plan_sha256": digest, "receipts": [], "writes": 0,
"error": "plan changed since preview (plan_sha256 mismatch); nothing applied"}
return {
"mode": "apply",
"plan_sha256": digest,
"receipts": [],
"writes": 0,
"error": "plan changed since preview (plan_sha256 mismatch); nothing applied",
}
applied_before = _load_applied(receipt_store)
receipts: list[dict[str, Any]] = []
writes = 0
for action in actions:
record: dict[str, Any] = {"id": action.action_id, "kind": action.kind, "source": action.source,
"at": datetime.now(timezone.utc).isoformat(timespec="seconds")}
record: dict[str, Any] = {
"id": action.action_id,
"kind": action.kind,
"source": action.source,
"at": datetime.now(timezone.utc).isoformat(timespec="seconds"),
}
reason = denial_reason(action, config)
if reason:
record.update(status="denied", detail=reason)
Expand Down
Loading
Loading