feat: add pr edit, close, and reopen (task 0011)
Add the PR-side state mutations mirroring the issue-side slice: - `pr edit` applies title/body/base/milestone and the recomputed assignee list in one PATCH, with additive label endpoints and (per the ADR 0007 amendment) the dedicated requested-reviewers POST/DELETE endpoints for `--add-reviewer`/`--remove-reviewer`. - `pr close --comment` posts the comment after the PATCH and surfaces a comment-post failure; an already-closed or merged PR is an `already: true` no-op reporting the actual state. - `pr reopen` is an `already: true` no-op when already open. Extract the fetch-then-patch assignee merge into a shared `src/assignees.ts` (`mergeAssignees` + `assigneeLogins`), now used by both `issue edit` and `pr edit`.
This commit was merged in pull request #11.
This commit is contained in:
44
src/assignees.ts
Normal file
44
src/assignees.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/** The subset of a Gitea `User` this module reads: just the login, if present. */
|
||||
interface AssigneeLike {
|
||||
login?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The logins of an entity's current assignees, dropping any without one. The
|
||||
* shared read side of fetch-then-patch: `issue edit` and `pr edit` both take the
|
||||
* `assignees` off a freshly fetched entity and feed the result to
|
||||
* {@link mergeAssignees}.
|
||||
*/
|
||||
export function assigneeLogins(assignees: AssigneeLike[] | undefined): string[] {
|
||||
return (assignees ?? []).flatMap((assignee) => (assignee.login ? [assignee.login] : []));
|
||||
}
|
||||
|
||||
/**
|
||||
* The full assignee login list to PATCH under fetch-then-patch semantics
|
||||
* (ADR 0007): the entity's current assignees with the requested additions
|
||||
* appended and removals dropped. Matching is case-insensitive and the result is
|
||||
* de-duplicated, order-preserving, so a login already assigned never lands in the
|
||||
* list twice. Shared by `issue edit` and `pr edit`, whose PATCH bodies both
|
||||
* replace the whole assignee list rather than adding or removing individual
|
||||
* entries.
|
||||
*/
|
||||
export function mergeAssignees(current: string[], add: string[], remove: string[]): string[] {
|
||||
const removeSet = new Set(remove.map((login) => login.toLowerCase()));
|
||||
const seen = new Set<string>();
|
||||
const result: string[] = [];
|
||||
const push = (login: string): void => {
|
||||
const key = login.toLowerCase();
|
||||
if (removeSet.has(key) || seen.has(key)) {
|
||||
return;
|
||||
}
|
||||
seen.add(key);
|
||||
result.push(login);
|
||||
};
|
||||
for (const login of current) {
|
||||
push(login);
|
||||
}
|
||||
for (const login of add) {
|
||||
push(login);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user