~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

A gate's review shows as a required reviewer

Closed chadtmiller.com asked to merge into main from chadtmiller.com/knotless:web/gate-reviewer
crates/knotless-serve/src/web/items.rs+3−0
@@ -377,6 +377,8 @@ pub async fn get_thread(
// Against the head as it is now: a merged pull's reviews stand as
// they were.
let at = changes.as_ref().and_then(|c| c.head.as_deref());
let rule = item.base.as_deref().and_then(|b| record.rule(b));
let gates = (rule.and_then(|r| r.reviews.as_ref())).map_or(&[][..], |r| &r.gates[..]);
let reviews = futures::future::join_all(item.reviews.iter().map(|r| async {
ReviewView {
reviewer: actor(&app, &r.by).await,
@@ -385,6 +387,7 @@ pub async fn get_thread(
commit: r.commit.clone(),
outdated: at.is_some_and(|at| !r.at_head(at)),
maintainer: r.by == repo.did || record.is_collaborator(&r.by),
gate: gates.iter().any(|g| g.did == r.by),
}
}))
.await;
crates/knotless-serve/src/web/views.rs+4−0
@@ -375,6 +375,10 @@ pub struct ReviewView {
pub outdated: bool,
/// Whether the reviewer is the repository's owner or a collaborator.
pub maintainer: bool,
/// Whether the rule protecting the pull's base names the reviewer as
/// a gate.
#[serde(skip_serializing_if = "std::ops::Not::not")]
pub gate: bool,
}
/// `dev.knotless.defs#pullHeadView`: the branch a pull brings in.
crates/knotless-serve/tests/web.rs+2−0
@@ -1366,6 +1366,8 @@ fn pulls_and_issues() {
(&review[0]["outdated"], &review[0]["maintainer"]),
(&serde_json::json!(false), &serde_json::json!(true))
);
// No rule names the owner a gate of main.
assert_eq!(review[0].get("gate"), None);
// Checks: those of the runners each repository names, the newest run
// of each workflow, of the commit a listing shows and of a pull's branch.
docs/reference/api.md+1−1
@@ -550,7 +550,7 @@ name it has now.
| `dev.knotless.listBranches?repo=&limit=&cursor=&commits=` | the branches, the default first, 100 a page by default; with `commits`, each with its tip and that commit's newest checks |
| `dev.knotless.listTags?repo=&limit=&cursor=&commits=` | the tags that name a commit, the newest commit first, 100 a page by default; with `commits`, each with its commit and that commit's newest checks |
| `dev.knotless.listItems?repo=&kind=&state=&q=&limit=&cursor=` | the open or closed pulls or issues that the filter `q` matches ([collaboration.md](../design/collaboration.md#filtering-pulls-and-issues)), `review-requested:@me` and `assignee:@me` the asker, each with `draft` for a draft pull, the `reviewers` asked and the `assignees`, 50 a page by default, how many of each, and the repository's labels and the items' authors, for a filter to name |
| `dev.knotless.getThread?repo=&uri=&filesOnly=&firstRows=` | a pull or an issue and everything said on it, each comment with its `uri`, Markdown `body` and, for a review, the `commit` it looked at; on a pull's lines, its `line` (`path`, `side`, `line`, `startLine`, the `lines` it names as they were, at most 20, and `outdated` once that side of the file has changed), the `review` it went with and `resolved`; an answer's `reply`, the comment starting its thread; for a pull, `reviews`, where each reviewer stands (`outdated` once the open pull has moved past the head it looked at, `maintainer` for the owner or a collaborator), and in `changes` the `head` it is at; for a merged pull, `revertedBy` (`{uri, title}`), the revert whose merge undid it; for an issue, `mentionedBy`, the pulls on the repository whose title or body names it, oldest first, each its `item` and `closes` where it names it after a closing keyword; in each `html`, a bare `at://` URI of a pull or issue on the repository, or a link to one, as a link to its page, a bare one showing its title; for a pull of a public repository, the minutes each runner counts for its owner (`dev.knotless.minutes`); with an index, `reactions` on the item and on each comment, by content in GitHub's order, each naming the asker's own `reaction` when it has an asker; and with an asker, what it may do (`viewer`: `setState`, `hide`, `revert` for a merged pull, `assign`, and the `labels` it may set); with `filesOnly`, a pull's changed files without their rows, and with `firstRows` too, the rows of the first files, up to 10 files or 1500 lines, passing over any that changes more than 400 |
| `dev.knotless.getThread?repo=&uri=&filesOnly=&firstRows=` | a pull or an issue and everything said on it, each comment with its `uri`, Markdown `body` and, for a review, the `commit` it looked at; on a pull's lines, its `line` (`path`, `side`, `line`, `startLine`, the `lines` it names as they were, at most 20, and `outdated` once that side of the file has changed), the `review` it went with and `resolved`; an answer's `reply`, the comment starting its thread; for a pull, `reviews`, where each reviewer stands (`outdated` once the open pull has moved past the head it looked at, `maintainer` for the owner or a collaborator, `gate` for an account the rule protecting its base waits for a review from), and in `changes` the `head` it is at; for a merged pull, `revertedBy` (`{uri, title}`), the revert whose merge undid it; for an issue, `mentionedBy`, the pulls on the repository whose title or body names it, oldest first, each its `item` and `closes` where it names it after a closing keyword; in each `html`, a bare `at://` URI of a pull or issue on the repository, or a link to one, as a link to its page, a bare one showing its title; for a pull of a public repository, the minutes each runner counts for its owner (`dev.knotless.minutes`); with an index, `reactions` on the item and on each comment, by content in GitHub's order, each naming the asker's own `reaction` when it has an asker; and with an asker, what it may do (`viewer`: `setState`, `hide`, `revert` for a merged pull, `assign`, and the `labels` it may set); with `filesOnly`, a pull's changed files without their rows, and with `firstRows` too, the rows of the first files, up to 10 files or 1500 lines, passing over any that changes more than 400 |
| `dev.knotless.getPullDiff?repo=&uri=&paths=` | the files of a pull's diff that `paths` names (repeated, 1 to 50), rows and all: what the pull page fetches as the reader comes to each file |
| `dev.knotless.getTemplate?repo=&kind=&base=` | the template a new pull (at `base`) or issue is asked to follow, `.knotless/<kind>.md`, as `knotless template` reads it; `{}` with none, 400 for a `kind` that is neither |
| `dev.knotless.getCompare?repo=&base=&head=&branch=` | the repositories a pull can come from (`heads`: this one, then its forks), and with `branch` what it brings in from `head` (this repository if not given) into `base` (the default branch if not given), as a pull's `changes`: 404 for a branch on neither |
lexicons/dev/knotless/defs.json+2−1
@@ -543,7 +543,8 @@
"uri": { "type": "string", "format": "at-uri", "description": "The dev.knotless.comment that reviewed it." },
"commit": { "type": "string", "description": "The hex object ID of the head it looked at." },
"outdated": { "type": "boolean", "description": "Whether the open pull has moved past the head it looked at: an approval then stands for what the pull was, not what it is." },
"maintainer": { "type": "boolean", "description": "Whether the reviewer is the repository's owner or a collaborator." }
"maintainer": { "type": "boolean", "description": "Whether the reviewer is the repository's owner or a collaborator." },
"gate": { "type": "boolean", "description": "Whether the rule protecting the pull's base names the reviewer as a gate, whose review of the head the pull waits for though it may not write." }
}
},
"reactionContent": {
web/src/lib/molecules/ReviewersFact.svelte+3−2
@@ -7,7 +7,8 @@
* Who reviews a pull, as a fact of it: their faces, each marked with
* where they stand, and how many, opening to a row each, their latest
* verdict linked to the review that gave it, then those `requested` who
* have not reviewed it yet. With `people` and `ask`, as its author, it
* have not reviewed it yet. A gate the branch waits for is a required reviewer, and
* another who may not write, that their approval does not count. With `people` and `ask`, as its author, it
web/src/lib/molecules/ReviewersFact.sveltelines 10 to 11

This sentence is broken: "and another who may not write, that their approval does not count". It also runs long. Something like: "A gate is marked as a required reviewer; another reviewer who may not write is marked as not counted."

web/src/lib/molecules/ReviewersFact.sveltelines 10 to 11

Still not a sentence. Something like: "A gate is marked as a required reviewer; another reviewer who may not write is marked as not counted."

* also asks them to review it, or stops asking one not yet heard from.
*/
let { reviews, requested = [], people = [], ask }: { reviews: ReviewView[]; requested?: ActorView[]; people?: ActorView[]; ask?: (did: ActorView['did'], removed: boolean) => Promise<unknown> } = $props();
@@ -48,7 +49,7 @@
{#each reviews as r (r.uri)}
<a class="menu-item reviewer" href={anchor(r)} onclick={() => (open = false)}>
<Avatar name={r.reviewer.handle} did={r.reviewer.did} src={r.reviewer.avatar} />
<span class="who">{r.reviewer.handle}{#if !r.maintainer && r.verdict === 'approve'}<small>Not a collaborator, so not counted</small>{/if}</span>
<span class="who">{r.reviewer.handle}{#if r.gate}<small>Required reviewer</small>{:else if !r.maintainer && r.verdict === 'approve'}<small>Not a collaborator, so not counted</small>{/if}</span>
<span class="said {stand(r)}">{said[stand(r)]}</span>
{#if ask && awaited.length}<span class="stop-room"></span>{/if}
</a>