Help us shape the future of Go! Take the 2026 Go Developer Survey

checkout

package
v0.62.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: BSD-3-Clause Imports: 10 Imported by: 0

Documentation

Overview

Package checkout holds the two questions every working-tree scanner has to ask before it believes what it read.

⛔ THEY WERE ASKED IN TWO PLACES AND DRIFTED. testscan and judgescan each had their own staleness(); on 2026-09-27 testscan's learnt to count commits and judgescan's did not, so the same clone was stale for one tool and fresh for the other. judgescan never had the ownership question at all and was still reporting forks. Two answers to one question is one answer being wrong.

Index

Constants

View Source
const FetchHorizon = time.Hour

FetchHorizon is how long a checkout's remote refs are treated as current when nobody asked the remote.

⛔ IT IS A FALLBACK, NOT THE ANSWER, and the case that produced this file proves why: go-compressions/compress had fetched 36 MINUTES earlier and was already one commit behind, because the commit it was missing was merged in between. Any horizon long enough to be quiet is long enough to miss that. There is no interval that knows whether a remote moved; the only thing that knows is a fetch. So Refresh below does one, for the handful of checkouts a scanner is about to name, and this constant only covers a fetch that could not be done.

Variables

This section is empty.

Functions

func Branch

func Branch(dir string) (name string, dirty bool)

Branch is the branch a checkout is ON, and whether its tree is dirty.

⛔ A tool that reads the working tree is not reading the default branch, and on this machine it usually is not: of seventeen checkouts read on 2026-10-18, SIX were on another session's branch. Three findings were wrong because of it -- two repositories whose nested module looked fine had been tidied on the branch they happened to be sitting on. A fleet report that does not say which branch it read is a report about seventeen different things.

Returns "" for a detached HEAD, which `git branch --show-current` also does: a worktree made for a measurement has no branch, and saying so is better than naming the commit as if it were one.

func DefaultRef

func DefaultRef(dir string) (string, bool)

DefaultRef names the remote default branch of a checkout.

func DefaultRoot

func DefaultRoot() string

DefaultRoot is where this machine keeps its org/repo checkouts.

func MaterialiseAt

func MaterialiseAt(dir, ref string) (string, func(), bool)

MaterialiseAt writes the tree at a ref into a temporary directory and returns its path with a cleanup function.

⛔ THIS EXISTS BECAUSE REFRESHING IS NOT RE-DERIVING, which is the sentence these scanners have been PRINTING at their users for weeks while not doing it themselves. On 2026-09-27 testscan reported 10 repositories with no CI; after the clones were pulled by hand it reported 2. judgescan the same morning reported 8 and then 4. Eight and four findings, every one of them describing a workflow file that had gained the very thing the tool said was missing -- because the clone farm drifts under Renovate and under my own merges, and a scan of a stale tree manufactures findings that look exactly like real ones.

Fetching told us the distance. It did not change the bytes being parsed. This does: the caller re-runs its ORDINARY scan over the materialised tree, so there is no second copy of the parsing to drift from the first.

It is called for the handful of repositories that produced a finding, never for the fleet, because `git archive` of nine hundred repositories to answer a question about five of them is not a measurement, it is a cost.

func Ours

func Ours(repos []string, owners map[string]bool, haveOwners bool, ask func(string) Ownership) (keep map[string]bool, dropped []string)

Ours reports which of these repositories a finding list should keep, and why the others go.

It asks GitHub once per candidate, never per repository scanned: on 2026-09-27 that was nineteen calls against nine hundred and twenty-five checkouts. ask is a parameter so callers can test without a network — the first test written against the real one got a real 404 for its made-up repository and failed for a reason that had nothing to do with the logic.

func OwnerOf

func OwnerOf(repo string) string

OwnerOf is the account half of owner/repo.

func Owners

func Owners() (map[string]bool, bool)

Owners is every account whose repositories are ours: the organisations this token belongs to, and the user themself.

⛔ The user is in the set deliberately. Leaving them out drops every personal repository, and on this machine several real modules live there; the noisy ones under that account are forks, which the fork test catches on its own.

func Refresh

func Refresh(dir string) (behind int, ok bool)

Refresh fetches one checkout's remote refs and re-measures the distance.

A scanner reports a handful of repositories out of nine hundred, so this runs over the findings and not over the fleet: the cost is a few fetches, and what it buys is a distance that was MEASURED rather than remembered. It never touches the working tree -- git fetch moves refs and nothing else.

func Repos

func Repos(root, only string) ([]string, error)

Repos lists the org/repo directories under root that are git checkouts.

⛔ A worktree's .git is a FILE holding `gitdir: ...`, not a directory. It is the same repository checked out again, so counting it inflates the total and prints every finding once per worktree -- openweft/weft-loom-server appeared three times.

This lived in testscan and in judgescan, which is how this package came to exist: two answers to one question is one answer being wrong. The copies had already begun to drift when they were merged here.

func Staleness

func Staleness(dir string) (behind int, fetchAge time.Duration, ok bool)

Staleness reports how far a checkout's HEAD is behind its remote default branch, and how long since it last fetched.

⛔ THE DISTANCE IS THE SIGNAL, NOT THE AGE. `git fetch` refreshes FETCH_HEAD and the remote refs and does NOT touch the working tree, so a clone fetched a minute ago can be twenty commits behind — and on 2026-09-27 ten of twelve findings were exactly that. An earlier version returned a hard-coded 0 here while its own doc promised the distance.

ok is false when this cannot be measured. Unknown is reported as unknown: it must not read as up to date.

func StalenessWarning

func StalenessWarning(ages []Age, confirmed bool) string

StalenessWarning is the sentence a scanner prints about the evidence under its findings, or "" when there is nothing to say.

It lives here because judgescan and testscan had the SAME twelve lines, separately, and that is the drift this package exists to stop: the distance fix landed in one of them on 2026-09-27 and not the other, and the comment left behind in the second said so. confirmed says whether the caller RE-DERIVED each behind finding against the remote default. It changes what the sentence is allowed to claim: with it, being behind is a note; without it, it is a reason to distrust the list.

func WhyNotOurs

func WhyNotOurs(o Ownership) string

WhyNotOurs names the reason a repository does not belong on a finding list, or "" — including when the question was never answered, which must read as "keep it".

Types

type Age

type Age struct {
	Behind     int
	FetchAge   time.Duration
	FetchKnown bool
}

Age is one finding's checkout, as Staleness measured it.

type Ownership

type Ownership struct {
	Fork    bool
	Missing bool // GitHub does not have it
	Asked   bool // the question was answered at all
}

Ownership is what GitHub says about one repository.

func Ask

func Ask(repo string) Ownership

Ask puts the question to GitHub.

⛔ A 404 IS AN ANSWER; EVERY OTHER FAILURE IS NOT. gh exits 1 for a rate limit and for a missing token as readily as for a missing repository, so keying on the exit status would delete real findings during exactly the minutes when the API is refusing — which is when a sweep is most likely to be running. The message has to say so.

type Verdict

type Verdict int

Verdict is what one checkout's distance actually tells you.

const (
	Current Verdict = iota // behind 0, against a remote ref fetched recently
	Behind                 // the remote default has commits this tree does not
	Unknown                // behind 0, but nobody has asked the remote lately
)

func Judge

func Judge(behind int, fetchAge time.Duration, ok bool) Verdict

Judge turns Staleness's three numbers into one answer.

⛔ A DISTANCE OF ZERO IS NOT FRESHNESS. `git rev-list HEAD..origin/main` compares against the LOCAL copy of origin/main, and that copy is only as current as the last fetch. A clone nobody has fetched from since its own commits were merged upstream reports zero, which reads exactly like being up to date.

MEASURED, go-compressions/compress on 2026-09-27, 36 minutes after its last fetch and minutes after its fix was merged:

before git fetch: 0 behind
after  git fetch: 1 behind

Note what that witness also says about THIS function: 36 minutes is inside any sane horizon, so Judge alone would have called it Current and been wrong. Judge is what is left when Refresh could not run.

judgescan printed the repository as a finding again, on a tree whose fix was already on main, and said nothing about the tree being old -- because behind was 0. The fetch age WAS being computed, and then never read: the two fields were assigned into the finding and nothing looked at them.

An answer nobody obtained is not a negative answer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL