~ 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 push in the feed links to the commit it left, which outlives its branch

Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:serve/feed-tip
crates/knotless-serve/src/web/feed.rs+3−0
@@ -72,6 +72,8 @@ pub enum Action {
#[serde(rename = "ref")]
refname: String,
created: bool,
/// The commit the ref was left at, which outlives the ref.
to: String,
#[serde(skip_serializing_if = "std::ops::Not::not")]
forced: bool,
count: usize,
@@ -447,6 +449,7 @@ async fn events(
Action::Pushed {
refname: last.refname.clone(),
created: first.from.is_none(),
to: to.clone(),
forced: !replaced.is_empty(),
count: brought.len(),
new: new.len(),
crates/knotless-serve/tests/web.rs+2−0
@@ -2086,6 +2086,8 @@ fn a_forced_push() {
"{pushed}"
);
assert_eq!(pushed["commits"][0]["sha"], b.as_str());
// Where it left the ref, for a link that outlives the ref.
assert_eq!(pushed["to"], b.as_str());
// One that only moved forward was not forced.
owner.commit_file(&work, "c", "c\n");
owner.git(&work, &["push", "-q", &url, "main"]);
docs/reference/api.md+3−2
@@ -220,7 +220,7 @@ Answers `events` (`createdAt`, `actor` `{did, handle, avatar?}`, `repo`
| `$type` | Fields |
| --- | --- |
| `dev.knotless.getFeed#created` | `description?`, `forkOf?` |
| `dev.knotless.getFeed#pushed` | `ref`, `created`, `forced?`, `count`, `new`, `commits` (`sha`, `message`, `merge?`) |
| `dev.knotless.getFeed#pushed` | `ref`, `created`, `to?`, `forced?`, `count`, `new`, `commits` (`sha`, `message`, `merge?`) |
| `dev.knotless.getFeed#deleted` | `ref` |
| `dev.knotless.getFeed#opened` | `subject`, `title` |
| `dev.knotless.getFeed#commented` | `subject`, `title`, `text`, `verdict?` |
@@ -231,7 +231,8 @@ A push's `actor` is the account that pushed: a ref's claim or record that
names a `pusher` the repository lists among its collaborators or runners
is theirs, and any other is the owner's. `actor` and `filter=following`
choose pushes by that account too. Pushes to one ref by one account within
an hour of each other are one event. A push walks
an hour of each other are one event. `to` is the commit the last of them left
the ref at, which a page links to as the ref may since have been deleted. A push walks
at most 100 commits and lists at most 10; `count` is what it brought, and
`new` those no other ref had first. `forced` is a push that left commits
behind, as a rebase or a rewrite does: its `count` and `new` leave out the
lexicons/dev/knotless/getFeed.json+4−0
@@ -76,6 +76,10 @@
"properties": {
"ref": { "type": "string", "description": "The full ref name, such as refs/heads/main." },
"created": { "type": "boolean", "description": "Whether the ref was new." },
"to": {
"type": "string",
"description": "The commit the ref was left at, in hex: what the push brought, which a page can link to after the ref is gone."
},
"forced": { "type": "boolean", "description": "Whether the ref moved to where it no longer reaches some of what it did, as a rebase or a rewrite does. Absent when not." },
"count": { "type": "integer", "minimum": 0, "maximum": 100, "description": "Commits the push brought; 100 means at least that many. A forced push's leave out those it brought again: the same author, at the same time, with the same message as a commit it left behind." },
"new": { "type": "integer", "minimum": 0, "maximum": 100, "description": "Of those, the commits no other ref of the repository had before, and no event before it on the same page lists; the rest are only counted." },
web/src/lib/molecules/FeedItem.svelte+6−4
@@ -25,7 +25,9 @@
type Known = Extract<getFeed.EventView['action'], { $type: `dev.knotless.getFeed#${string}` }>;
const a = $derived(x.kind === 'event' ? (x.event.action as Known) : null);
const repo = $derived(repoHref(x.repo.handle, x.repo.name));
const log = (ref: string) => `${repo}/commits/${urlPath(shortRef(ref))}`;
// A branch is often gone once its pull lands, so its log is of the
// commit the push left it at, which stays.
const log = (b: { ref: string; to?: string }) => `${repo}/commits/${b.to ?? urlPath(shortRef(b.ref))}`;
/**
* A lone event's sentence after who did it: words, then what it was done
@@ -80,7 +82,7 @@
{#snippet where()}{' on '}<RepoLink owner={x.repo.handle} name={x.repo.name} />{/snippet}
{#snippet who()}{#if !own}<a class="who" href="/{urlPath(x.actor.handle)}">{x.actor.handle}</a>{/if}{own ? '' : ' '}{/snippet}
{#snippet rest(b: { count: number; merges: number; elsewhere: number; ref: string }, listed: number)}<p class="feed-rest">{#if b.count > listed}<span class="feed-badge">+{b.count - listed} more</span>{/if}{#if b.merges}<span class="feed-badge">{b.merges === 1 ? '1 merge' : `${b.merges} merges`}</span>{/if}{#if b.elsewhere}<span class="feed-badge">{`+${b.elsewhere} from other branches`}</span>{/if}<a class="feed-log" href={log(b.ref)}>Commits →</a></p>{/snippet}
{#snippet rest(b: { count: number; merges: number; elsewhere: number; ref: string; to?: string }, listed: number)}<p class="feed-rest">{#if b.count > listed}<span class="feed-badge">+{b.count - listed} more</span>{/if}{#if b.merges}<span class="feed-badge">{b.merges === 1 ? '1 merge' : `${b.merges} merges`}</span>{/if}{#if b.elsewhere}<span class="feed-badge">{`+${b.elsewhere} from other branches`}</span>{/if}<a class="feed-log" href={log(b)}>Commits →</a></p>{/snippet}
<li>
<Time at={x.createdAt} show={(at) => span(x.since, at)} />
@@ -95,12 +97,12 @@
{:else if x.kind === 'pushes'}
<p>{@render who()}{x.branches.length ? `pushed to ${x.branches.length + x.caught.length} branches` : `brought ${x.caught.length} branches up to date`}{@render where()}</p>
<ul class="feed-branches">
{#each x.branches as b, i (i)}<li><Ref name={shortRef(b.ref)} /><span class="clip">{b.commits[0] ? subject(b.commits[0].message) : ''}</span><span class="feed-end"><span class="feed-count">{b.created ? `new · ${b.count}` : b.count}</span><a class="feed-log" href={log(b.ref)}>Commits →</a></span></li>{/each}
{#each x.branches as b, i (i)}<li><Ref name={shortRef(b.ref)} /><span class="clip">{b.commits[0] ? subject(b.commits[0].message) : ''}</span><span class="feed-end"><span class="feed-count">{b.created ? `new · ${b.count}` : b.count}</span><a class="feed-log" href={log(b)}>Commits →</a></span></li>{/each}
{#each x.caught as ref, i (i)}<li class="caught"><Ref name={shortRef(ref)} /><span class="clip">brought up to date</span></li>{/each}
</ul>
{:else if x.kind === 'merged'}
<p>{@render who()}merged pull <a href={itemHref(repo, x.subject)}>{x.title}</a>{@render where()}</p>
{#if x.landed}<p class="feed-rest">{`${commits(x.landed.count)} to `}<Ref name={shortRef(x.landed.ref)} /><a class="feed-log" href={log(x.landed.ref)}>Commits →</a></p>{/if}
{#if x.landed}<p class="feed-rest">{`${commits(x.landed.count)} to `}<Ref name={shortRef(x.landed.ref)} /><a class="feed-log" href={log(x.landed)}>Commits →</a></p>{/if}
{:else if x.kind === 'starred' && x.actors.length > 1}
<Crowd actors={x.actors} />
<p><a class="who" href="/{urlPath(x.actor.handle)}">{x.actor.handle}</a>{` and ${others === 1 ? '1 other' : `${others} others`} starred `}<RepoLink owner={x.repo.handle} name={x.repo.name} /></p>
web/src/lib/feed.ts+3−0
@@ -25,6 +25,8 @@ export type Kind = (typeof KINDS)[number][0];
*/
export type Branch = {
ref: string;
/** The commit the ref was left at, absent from an older answer. */
to?: string;
created: boolean;
forced: boolean;
commits: getFeed.CommitView[];
@@ -39,6 +41,7 @@ function branch(a: Pushed): Branch {
const unlisted = Math.max(0, a.new - a.commits.length);
return {
ref: a.ref,
to: a.to,
created: a.created,
forced: !!a.forced,
commits: real,