The gitea-prs reference documented `milestone` as "settable on both "create" and "update"". It is not: `pull_request_write method: "create"` accepts the parameter, returns no error or warning, and discards it. Verified against the gitea-mcp v1.6.0 source rather than by observation alone. `createPullRequestFn` builds its `CreatePullRequestOption` from owner, repo, title, body, head, base, draft, labels and deadline only — so the drop is not limited to `milestone` as issue #104 supposed. `assignee`, `assignees`, `reviewers` and `team_reviewers` are discarded on create too, and `reviewers`/`team_reviewers` are discarded on "update" as well; they are only ever read by "add_reviewers" and "remove_reviewers". Two properties made the original error easy to make and hard to catch, so both are now written down next to the correction: `labels` sits beside `milestone`, reads identically, and does apply on create; and `issue_write method: "create"` honours `assignees` and `milestone`, so the asymmetry is specific to pull requests. While in the file, corrected the adjacent draft gotcha. It prescribed reconstructing the un-prefixed title by hand to un-draft a PR; `applyDraftPrefix` shows "update" with `draft: false` and no `title` fetches the stored title and strips the prefix server-side. Impact: documentation only, no behaviour change. Callers following the old text silently created PRs with no milestone, assignee or reviewer. Confined to references/pull-requests.md, so the ADR-0020 skill gates do not apply and gitea-prs needs no #99 retrofit first. Fixes: #104 Refs: #99 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ETxbGFetkbJQBHsx442Brt
85 lines
7.7 KiB
Markdown
85 lines
7.7 KiB
Markdown
---
|
|
topic: pull-requests
|
|
source_keys:
|
|
- gitea-mcp-repo
|
|
- gitea-mcp-slim-go
|
|
---
|
|
|
|
# Pull request read/write execution detail
|
|
|
|
Parameter signatures below are cross-checked live against the deployed gitea-mcp server tool schemas at authoring time — not copied verbatim from the plugin's research doc for this domain, which has a known history of drifting from the deployed server (e.g. a prior `type` parameter that no longer exists on `list_issues`, and the `review_scomments` typo covered in `references/reviews.md`). Re-verify via `ToolSearch` before trusting this file if the gitea-mcp version changes.
|
|
|
|
## `list_pull_requests`
|
|
|
|
**Parameters:**
|
|
- `owner` (string, required)
|
|
- `repo` (string, required)
|
|
- `state` (string, optional, default `"all"`) — `"open"` | `"closed"` | `"all"`
|
|
- `sort` (string, optional, default `"recentupdate"`) — `"oldest"` | `"recentupdate"` | `"leastupdate"` | `"mostcomment"` | `"leastcomment"` | `"priority"`
|
|
- `milestone` (number, optional) — milestone ID filter, not a title
|
|
- `page` (number, optional, default 1)
|
|
- `per_page` (number, optional, default 30)
|
|
|
|
List responses trim PRs down to summary fields — `head`/`base` are bare ref strings and `milestone` does not appear as an object. Don't rely on this call to resolve a milestone's ID; see the Gotcha below.
|
|
|
|
## `pull_request_read`
|
|
|
|
**Parameters:**
|
|
- `method` (string, required) — `"get"` | `"get_diff"` | `"get_files"` | `"get_status"` | `"get_reviews"` | `"get_review"` | `"get_review_comments"`
|
|
- `owner` (string, required)
|
|
- `repo` (string, required)
|
|
- `pull_number` (number, required)
|
|
- `review_id` (number, optional) — required for `"get_review"` and `"get_review_comments"`; see `references/reviews.md`
|
|
- `binary` (boolean, optional) — include binary diff content for `"get_diff"`
|
|
- `page` (number, optional, default 1)
|
|
- `per_page` (number, optional, default 30)
|
|
|
|
`"get"`, `"get_diff"`, `"get_files"`, and `"get_status"` are covered here. `"get_reviews"`, `"get_review"`, and `"get_review_comments"` are covered in `references/reviews.md`.
|
|
|
|
- `"get"` returns the full PR object: state, draft, merged, mergeable flags; `head`/`base` as full objects (`{ref, sha, repo?}`); `milestone` as a bare title string (not `{id, title}`); `review_scomments` (typo, see `references/reviews.md`).
|
|
- `"get_diff"` returns raw diff text.
|
|
- `"get_files"` returns the list of changed file objects.
|
|
- `"get_status"` returns the combined commit status for the PR's head commit — CI result only, not review/approval state (see `references/merging.md`).
|
|
|
|
**Milestone gotcha:** because `pull_request_read` only ever returns a milestone title, never an ID, resolving "which milestone ID does this PR belong to" requires calling into `gitea-labels-milestones`' `milestone_read method: "list"` and matching by title. Do not attempt to infer or guess the ID. This is the read-side milestone problem; for the separate write-side one, see the `"create"` drop Gotcha under `pull_request_write`.
|
|
|
|
## `pull_request_write`
|
|
|
|
**Parameters:**
|
|
- `method` (string, required) — `"create"` | `"update"` | `"close"` | `"reopen"` | `"merge"` | `"update_branch"` | `"add_reviewers"` | `"remove_reviewers"`
|
|
- `owner` (string, required)
|
|
- `repo` (string, required)
|
|
- `pull_number` (number, required for every method except `"create"` — this is enforced by convention, not by the tool's schema, so passing it incorrectly produces a runtime error rather than a client-side validation error)
|
|
- `title` (string, required for `"create"`; optional for `"update"`)
|
|
- `body` (string, required for `"create"`; optional for `"update"`)
|
|
- `head` (string, required for `"create"`) — source branch; same-repo PRs use a bare branch name, cross-repo fork PRs use `"fork-owner:branch-name"` (see Gotcha)
|
|
- `base` (string, required for `"create"`) — target branch
|
|
- `assignee` (string, optional) — single login; **`"update"` only** — silently dropped on `"create"` (see Gotcha)
|
|
- `assignees` (array of strings, optional) — login names; **`"update"` only** — silently dropped on `"create"` (see Gotcha)
|
|
- `milestone` (number, optional) — milestone ID, never a title; **`"update"` only** — silently dropped on `"create"` (see Gotcha)
|
|
- `state` (string, optional, for `"update"`) — `"open"` | `"closed"` (no `"all"` — unlike issue state filters)
|
|
- `allow_maintainer_edit` (boolean, optional, for `"update"`)
|
|
- `labels` (array of numbers, optional) — label IDs, never names — resolve via `gitea-labels-milestones` first
|
|
- `deadline` (string, optional) — ISO 8601
|
|
- `remove_deadline` (boolean, optional)
|
|
- `reviewers` (array of strings, optional) — login names; **`"add_reviewers"`/`"remove_reviewers"` only** — silently dropped on both `"create"` and `"update"` (see Gotcha)
|
|
- `team_reviewers` (array of strings, optional) — same as `reviewers`: `"add_reviewers"`/`"remove_reviewers"` only
|
|
- `draft` (boolean, optional) — prepends `"WIP:"` to the title; honoured on both `"create"` and `"update"` (see Gotcha)
|
|
|
|
Merge-specific parameters (`merge_style`, `delete_branch`, `force_merge`, `merge_when_checks_succeed`, `head_commit_id`, `message` as merge commit message) are covered in `references/merging.md`.
|
|
|
|
**`"create"` silently drops most optional parameters.** `"create"` reads only `owner`, `repo`, `title`, `body`, `head`, `base`, `draft`, `labels`, and `deadline`. Every other optional parameter — `assignee`, `assignees`, `milestone`, `reviewers`, `team_reviewers` — is accepted without error and discarded. There is no error, no warning, and nothing in the response distinguishing a dropped parameter from one that was never passed: the response simply omits the key. Setting any of them requires a second call after the PR exists — `"update"` for `assignee`/`assignees`/`milestone`, `"add_reviewers"` for `reviewers`/`team_reviewers`.
|
|
|
|
Two things make this easy to miss:
|
|
|
|
- **`labels` does apply on `"create"`.** It sits next to `milestone` in the parameter list and reads identically, so a caller who confirms the labels landed will reasonably assume the milestone did too.
|
|
- **`issue_write method: "create"` does honour `assignees` and `milestone`.** The asymmetry is specific to pull requests; experience with the issue write does not transfer.
|
|
|
|
To verify a milestone actually applied, re-read the PR and check for the `milestone` key, or check that the milestone's `open_issues` count moved — the create response alone cannot tell you.
|
|
|
|
**Cross-repo head format:** `head` must be `"fork-owner:branch-name"` for a PR originating from a fork of the base repo. Passing a bare branch name causes Gitea to search for that branch in the base repo instead, and returns 422 when it isn't found there.
|
|
|
|
**Draft/WIP behavior:** `draft: true` on `"create"` is implemented by prepending `"WIP:"` to the title — there is no first-class draft boolean stored separately from the title. The title returned by subsequent reads will include the prefix. To un-draft, call `"update"` with `draft: false` and no `title` — the server reads the PR's current title and strips the prefix itself, so you do not need to reconstruct the un-prefixed text. Passing `title` alongside `draft` applies the prefix rule to the title you passed rather than the stored one.
|
|
|
|
**`update_branch`:** takes only `owner`, `repo`, `pull_number` — no other parameters. It merges the current base branch into the PR's head branch server-side, resolving a PR that Gitea reports as behind its base (analogous to GitHub's "Update branch" button). Use it when a PR shows `mergeable: false` or an out-of-date status due to base-branch drift rather than an actual conflict; if the head and base have truly diverged with conflicting changes, this call fails and the conflict must be resolved by pushing a merge/rebase to the head branch directly, outside this skill's scope.
|