feat: assign issues to milestones on create/update (#22) #25

Merged
Latte merged 6 commits from feat/issue-milestone-assignment into main 2026-06-22 16:00:30 +00:00
Owner

Implements the milestone-assignment part of #22.

Changes

  • create_issue / update_issue now accept a milestone argument: a numeric milestone id or a milestone title (resolved case-insensitively against open and closed milestones; unknown titles return a clear error). On update_issue, milestone: 0 clears the milestone.
  • New GiteaClient._resolve_milestone_id mirrors the existing label name->id resolver.
  • A BeforeValidator rejects booleans so they are not silently coerced to an id.
  • MCP schemas, docs/api-reference.md and docs/write-mode.md updated (the write-mode tool list was stale — 6 listed vs 16 implemented — now complete).
  • 8 new tests; make lint (ruff/black/mypy) and full suite green at 83% coverage.

Projects investigation (also part of #22)

Gitea 1.26.2 (this instance) exposes no project endpoints in its REST API (verified via swagger.v1.json). Project/board support is therefore not implementable and is documented as intentionally unsupported. Closes the actionable scope of #22.

Guardrails

All new behaviour stays behind the existing write-mode + policy gating (write_operation=True); no new default-on surface.

Refs #22

Implements the milestone-assignment part of #22. ## Changes - `create_issue` / `update_issue` now accept a `milestone` argument: a numeric milestone **id** or a milestone **title** (resolved case-insensitively against open and closed milestones; unknown titles return a clear error). On `update_issue`, `milestone: 0` clears the milestone. - New `GiteaClient._resolve_milestone_id` mirrors the existing label name->id resolver. - A `BeforeValidator` rejects booleans so they are not silently coerced to an id. - MCP schemas, `docs/api-reference.md` and `docs/write-mode.md` updated (the write-mode tool list was stale — 6 listed vs 16 implemented — now complete). - 8 new tests; `make lint` (ruff/black/mypy) and full suite green at 83% coverage. ## Projects investigation (also part of #22) Gitea 1.26.2 (this instance) exposes **no project endpoints** in its REST API (verified via `swagger.v1.json`). Project/board support is therefore not implementable and is documented as intentionally unsupported. Closes the actionable scope of #22. ## Guardrails All new behaviour stays behind the existing write-mode + policy gating (`write_operation=True`); no new default-on surface. Refs #22
Latte added 6 commits 2026-06-22 15:38:11 +00:00
fix: tolerate null labels/assignees/user in get_issue (#13)
test / test (push) Successful in 25s
lint / lint (push) Successful in 27s
docker / test (pull_request) Successful in 32s
docker / lint (pull_request) Successful in 39s
lint / lint (pull_request) Successful in 34s
test / test (pull_request) Successful in 32s
docker / docker-test (pull_request) Successful in 11s
docker / docker-publish (pull_request) Has been skipped
478aee9bed
Gitea may return JSON null for an issue's `labels`, `assignees`, or
`user` fields. `dict.get(key, [])` returns None when the key is present
with a null value (the default is only used for missing keys), so the
list comprehensions raised `'NoneType' object is not iterable` for
otherwise-valid issues. Coalesce with `or []` / `or {}` so empty/null
collections normalize to empty results.

Adds a regression test covering all three null fields.
Merge pull request 'fix: tolerate null labels/assignees/user in get_issue (#13)' (#23) from fix/get-issue-none-iterable into dev
docker / test (push) Successful in 29s
docker / lint (push) Successful in 36s
test / test (push) Successful in 36s
lint / lint (push) Successful in 36s
docker / docker-test (push) Successful in 7s
docker / docker-publish (push) Successful in 5s
cd309ee290
Reviewed-on: #23
feat: add structured logging helpers and instrument get_issue (#14)
docker / test (pull_request) Successful in 29s
test / test (push) Successful in 38s
lint / lint (push) Successful in 39s
docker / lint (pull_request) Successful in 39s
docker / docker-test (pull_request) Successful in 12s
docker / docker-publish (pull_request) Has been skipped
lint / lint (pull_request) Successful in 28s
test / test (pull_request) Successful in 22s
f53e1a3a5a
Adds reusable, secret-safe logging helpers to `logging_utils`:
- `log_event(logger, level, event, **context)` emits a named event with a
  sanitized `context` mapping (sensitive keys masked as `***`).
- `log_nullable_field(...)` records whether a parsed field is None plus its
  runtime type, without dumping its contents.
- `sanitize_context(...)` is the shared masking primitive.

The JSON formatter now serializes a record's `context` into the payload.

`get_issue_tool` is instrumented at DEBUG (`get_issue.start`,
`get_issue.payload_shape`, `get_issue.field_check` for labels/assignees/user)
so the nullable-field parsing that caused #13 is diagnosable going forward.

Adds tests for the helpers, the formatter, and the get_issue instrumentation,
and documents the pattern in docs/observability.md.
test: cover write-tool auth and backend error branches
lint / lint (push) Successful in 36s
docker / test (pull_request) Successful in 32s
test / test (push) Successful in 38s
docker / lint (pull_request) Successful in 38s
docker / docker-test (pull_request) Successful in 12s
docker / docker-publish (pull_request) Has been skipped
test / test (pull_request) Successful in 25s
lint / lint (pull_request) Successful in 27s
538d6d964a
Every write tool's `except (Auth...)` re-raise and `except GiteaError ->
RuntimeError` wrapping was previously untested, leaving write_tools at 60%
coverage and the repo below the 80% gate. Adds parametrized error-path tests
for all 15 write tools (backend error wrapping + auth propagation), raising
write_tools coverage to 99% and total coverage above the gate.
Merge pull request 'feat: structured logging helpers + get_issue instrumentation (#14)' (#24) from feat/get-issue-debug-logging into dev
docker / test (pull_request) Successful in 27s
docker / lint (pull_request) Successful in 34s
lint / lint (pull_request) Successful in 36s
docker / docker-test (pull_request) Successful in 7s
test / test (pull_request) Successful in 35s
docker / docker-publish (pull_request) Has been skipped
lint / lint (push) Successful in 36s
docker / test (push) Successful in 28s
docker / lint (push) Successful in 35s
test / test (push) Successful in 36s
docker / docker-test (push) Successful in 11s
docker / docker-publish (push) Successful in 5s
10a307ac02
Reviewed-on: #24
feat: assign issues to milestones on create/update (#22)
docker / test (pull_request) Successful in 29s
docker / lint (pull_request) Successful in 35s
lint / lint (pull_request) Successful in 35s
test / test (pull_request) Successful in 35s
docker / docker-test (pull_request) Successful in 8s
docker / docker-publish (pull_request) Has been skipped
test / test (push) Successful in 23s
lint / lint (push) Successful in 23s
e08ba42697
Add a `milestone` argument to `create_issue` and `update_issue` accepting
either a numeric milestone id or a title (resolved case-insensitively against
open and closed milestones, with a clear error for unknown titles). On
`update_issue`, `milestone: 0` clears the milestone. A BeforeValidator rejects
booleans so they are not silently coerced to an id.

Gitea Projects (Kanban boards) were investigated for #22 and are intentionally
left unsupported: Gitea 1.26.2 exposes no project endpoints in its REST API.
Documented this in api-reference.md and refreshed the (stale) write-mode tool
list to cover all 16 write tools.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Latte merged commit 026f3a654f into main 2026-06-22 16:00:30 +00:00
Latte deleted branch feat/issue-milestone-assignment 2026-06-22 16:00:30 +00:00
Sign in to join this conversation.