~ 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

knotless checks --ref takes a branch named bare

Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:run/private-checks
.changeset/checks-bare-ref.mdnew+7−0
@@ -0,0 +1,7 @@
---
default: patch
---
# `knotless checks --ref` takes a branch named bare
`knotless checks --ref main` lists the checks of `refs/heads/main`, as `rerun` and `workflows` read a bare name, rather than none; a tag of that name, when there is no such branch. A branch deleted since, as a merged pull's, still names its checks. The MCP `checks` tool's `ref` takes one the same way.
crates/knotless/src/checks.rs+44−2
@@ -23,8 +23,9 @@ use tokio::time::Instant;
/// Which checks [`list`] gives.
#[derive(Debug, Clone, Copy, Default)]
pub struct Filter<'a> {
/// Only those of pushes to this ref, and runs asked for there, in
/// full, such as `refs/heads/main`: not a pull's or a batch's.
/// Only those of pushes to this ref, and runs asked for there, such
/// as `refs/heads/main`, or `main` as [`full_ref`] reads it: not a
/// pull's or a batch's.
pub refname: Option<&'a str>,
/// Only those of the commits whose hex IDs start with this, as
/// [`commit`] gives it.
@@ -125,9 +126,30 @@ pub async fn list(ctx: &Ctx, url: &RepoUrl, filter: Filter<'_>, logs: bool) -> R
);
}
let runners: Vec<String> = repo.value.runners.iter().map(|r| r.did.clone()).collect();
let refname = filter
.refname
.map(|n| full_ref(n, |r| snap.find_ref(r).is_some()));
let filter = Filter {
refname: refname.as_deref(),
..filter
};
by(ctx, &remote, &repo.value.key, &runners, filter, logs).await
}
/// The ref whose checks `name` asks for, where `has` says which refs the
/// repository has: itself in full (`refs/…`), else the tag of that name
/// when there is a tag and no branch of it, else the branch, as git takes
/// a bare name: a branch deleted since, as a merged pull's, still names
/// its checks.
pub fn full_ref(name: &str, has: impl Fn(&str) -> bool) -> String {
let (branch, tag) = (format!("refs/heads/{name}"), format!("refs/tags/{name}"));
match name.starts_with("refs/") {
true => name.to_string(),
false if !has(&branch) && has(&tag) => tag,
false => branch,
}
}
/// The checks `runners` filed of the repository `remote` reads, keyed
/// `key`, as [`list`] gives them, whether the repository names them or not.
pub async fn by(
@@ -510,6 +532,26 @@ mod tests {
assert_eq!(scan_prefix(o, k, &queue), batches);
}
#[test]
fn a_bare_name_is_a_branch_or_else_a_tag() {
let has = |r: &str| {
[
"refs/heads/main",
"refs/tags/v1",
"refs/heads/both",
"refs/tags/both",
]
.contains(&r)
};
assert_eq!(full_ref("refs/heads/main", has), "refs/heads/main");
assert_eq!(full_ref("refs/notes/x", has), "refs/notes/x");
assert_eq!(full_ref("main", has), "refs/heads/main");
assert_eq!(full_ref("v1", has), "refs/tags/v1");
assert_eq!(full_ref("both", has), "refs/heads/both");
// A branch gone since, as a merged pull's, is still a branch.
assert_eq!(full_ref("gone", has), "refs/heads/gone");
}
#[test]
fn a_commit_is_its_hex_id_or_the_start_of_it() {
assert_eq!(commit("0838C57").unwrap(), "0838c57");
crates/knotless/tests/cli.rs+6−0
@@ -768,6 +768,12 @@ fn runners() {
assert_eq!(v.as_array().unwrap().len(), 1);
assert_eq!(v[0]["runner"], ci.account.did.as_str());
assert_eq!(v[0]["steps"][0]["durationMs"], 5);
// A branch named bare, as git takes it, whether the repository still
// has it or not.
let (_, bare) = s.cli(&["checks", &url, "--ref", "main", "--json"], b"");
assert_eq!(bare, out);
let (_, out) = s.cli(&["checks", &url, "--ref", "x"], b"");
assert!(out.starts_with("success\tlint\trefs/heads/x"), "{out}");
let (_, out) = s.cli(&["checks", &url, "--commit", &b], b"");
assert!(out.starts_with("success\tlint"), "{out}");
// As `git log --oneline` prints it, and in capitals.
crates/knotless-mcp/src/lib.rs+3−3
@@ -294,9 +294,9 @@ pub struct History {
pub struct Checks {
/// `handle/name`, `did/name` or `knotless://handle/name`.
pub repo: String,
/// Only checks of pushes to this ref, and runs asked for there, in
/// full, such as `refs/heads/main`: a pull's runs are found by `pull`,
/// a batch's by `queue`.
/// Only checks of pushes to this ref, and runs asked for there, such
/// as `refs/heads/main`, or a branch or tag named bare, as `main`: a
/// pull's runs are found by `pull`, a batch's by `queue`.
#[serde(rename = "ref")]
pub refname: Option<String>,
/// Only checks of this commit: its hex object ID, or at least its
docs/reference/cli.md+1−1
@@ -201,7 +201,7 @@ queue](../design/merge-queue.md).
| `runners <url> [add \| remove <handle>]` | the accounts whose checks of the repository readers show; `add` makes the account a member of a private repository, and invites it as `create` does (`added`, then `warning: …` if it could not be), which `remove` leaves it (`unshare` takes it back). A runner added after secrets were set has none of them, as nothing keeps their values to seal again: `warning: <did> gets the secrets set before only once each is set again: <names>`. `remove` deletes the secrets sealed to it |
| `secret <url> set <name> [--ref <pattern>]... [--runner <handle>]...` | as owner, give the repository's runners the secret `<name>`, read from stdin less one line ending, sealed to the key each publishes so only it reads it, and left at the appview (`KNOTLESS_APPVIEW`), replacing one of the same name; `--ref`, repeatable, limits it to pushes to those refs, as a trigger's `refs` match; `--runner`, repeatable, by handle or DID, gives it to those of the repository's runners alone, and takes back the copy any other of them had. Prints `sealed <name> to <runners>`. Fails if the repository names no runners, a `--runner` is not one of them, or one it seals to publishes no key (a knotless-run from before). `<name>` is a shell variable's, not starting `KNOTLESS_RUN`; the value at most 16 KiB, the refs at most 16. See [Secrets](../design/runner.md#secrets) |
| `secret <url> ls \| rm <name>` | as owner, each secret given, one line per runner, `<name>\t<runner>\t<refs, or *>\t<updated>`, never a value; or take one back from every runner, printing `removed <name>` |
| `checks <url> [--ref <name>] [--commit <sha>] [--pull <at-uri>] [--queue <branch>] [--workflow <name>] [--log] [--images <dir>] [--wait <secs>] [--json]` | what those runners report, newest first; `--ref`, of pushes to that ref and runs asked for there (a pull's are read with `--pull`); `--queue`, of the merge queue's batches; `--log` adds the end of each log; `--images` saves each check's pictures; `--wait` waits for runs to finish |
| `checks <url> [--ref <name>] [--commit <sha>] [--pull <at-uri>] [--queue <branch>] [--workflow <name>] [--log] [--images <dir>] [--wait <secs>] [--json]` | what those runners report, newest first; `--ref`, of pushes to that ref and runs asked for there, in full or a branch or tag named bare, as `main` (a pull's are read with `--pull`); `--queue`, of the merge queue's batches; `--log` adds the end of each log; `--images` saves each check's pictures; `--wait` waits for runs to finish |
| `rerun <url> --ref <name> \| --pull <at-uri> [--workflow <name>]` | as owner, ask the runners to run it again, or only one of its workflows |
| `rerun <url> --ref <name> --workflow <name> [-e <name>=<value>]...` | as owner, ask for one workflow there, with variables its steps see |
| `workflows <url> [<ref>]` | the workflows at a branch or tag (the default branch), and what runs each there |