Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions dist/commands/index-cmd.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/commands/index-cmd.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions dist/commitlore.mjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ them; you do not.
## The index is derived

`.git/commitlore/index.db` is a cache. The authority is the commit trailers and
`refs/notes/commitlore`, so `commitlore index --rebuild` can always reconstruct
it, and `--no-index` answers the same questions from Git alone — more slowly.
The gap between the two at scale is measured in [evidence.md](evidence.md).
`refs/notes/commitlore`, so `commitlore index --rebuild` reconstructs it from
whatever Git holds here — and says so on stderr when `refs/notes/commitlore` was
never fetched, because then it rebuilds from one source of the two. `--no-index`
answers the same questions from Git alone — more slowly. The gap between the two
at scale is measured in [evidence.md](evidence.md).
30 changes: 30 additions & 0 deletions src/commands/index-cmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
scanTrailers,
type IndexStats,
} from '../core/index-db.js';
import { NOTES_REF, notesAvailability } from '../core/notes.js';

interface IndexCommandOptions {
rebuild?: boolean;
Expand All @@ -40,6 +41,33 @@ const fail = (message: string): void => {
const plural = (count: number, unit: string): string =>
`${count} ${unit}${count === 1 ? '' : 's'}`;

/**
* Records come from two places, and this command can only ever read one of them
* locally. `rebuild` is what a user runs *because* they suspect the index is
* wrong, so reporting a clean count over a mirror that was never fetched is the
* least useful moment to leave that unsaid — the same defect `r-fetchowed` fixed
* one command over, where `doctor --fix` printed `ok` for configuration it had
* not fetched through.
*
* The state is `notesAvailability`'s, so this is a report and not a new check.
* The exit code deliberately does not follow `context`, which exits 3 on the
* same state: 3 there marks an *answer* drawn from an incomplete store, and this
* command's contract is 0 built, 2 could not run. The index it wrote is the one
* git can support, which is a build that succeeded — moving the code would make
* every unfetched clone's `init` and CI step fail over a cache that is correct.
*
* Like every other diagnostic it goes to stderr, so `--json` stays parseable
* while the caller still hears it.
*/
const reportUnfetchedNotes = (subject: string): void => {
if (notesAvailability() !== 'unfetched') return;
process.stderr.write(
`commitlore: the notes mirror has not been fetched here, so ${subject} covers the commit ` +
`messages alone and may be missing records that exist upstream (git fetch does not fetch ` +
`${NOTES_REF} by default). fix: commitlore doctor --fix, then git fetch, then rerun\n`,
);
};

const runScan = (options: IndexCommandOptions): void => {
const started = Date.now();
const trailers = scanTrailers();
Expand Down Expand Up @@ -142,9 +170,11 @@ export const register = (program: Command): void => {
fail('--rebuild and --no-index ask for opposite things');
return;
}
reportUnfetchedNotes('this scan');
runScan(options);
return;
}
reportUnfetchedNotes('this index');
runIndex(options);
} catch (error) {
fail(error instanceof Error ? error.message : String(error));
Expand Down
Loading
Loading