@yaroslavhaidash/gitstats-cli 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +30 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Counts commits and lines in the git repos on your computer and sends **only the numbers** (per repo, per week) to your [gitstats](https://gitstats-three-zeta.vercel.app) profile. No file contents, no diffs, no GitHub tokens, no permissions on GitHub.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npx
|
|
6
|
+
npx @yaroslavhaidash/gitstats-cli@latest link
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
That pairs this computer (you confirm in the browser), scans your home folder for repos, uploads the last year, and installs a daily background sync (launchd on macOS, Task Scheduler on Windows, systemd user timer on Linux). Nothing else to remember.
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* gitstats CLI — counts commits and lines in the git repos on this machine and sends ONLY the
|
|
4
4
|
* numbers (per repo, per week) to your gitstats profile. No file contents, no diffs, no GitHub tokens.
|
|
5
5
|
*
|
|
6
|
-
* npx
|
|
6
|
+
* npx @yaroslavhaidash/gitstats-cli@latest link
|
|
7
7
|
* pair this computer, scan for repos, sync, install a daily sync
|
|
8
8
|
* gitstats sync fetch each repo's default branch, recount the last year, upload (idempotent; --no-fetch to skip)
|
|
9
9
|
* gitstats status show what is linked and when it last ran
|
|
@@ -29,6 +29,7 @@ const DIR = join(HOME, ".gitstats");
|
|
|
29
29
|
const CONFIG = join(DIR, "config.json");
|
|
30
30
|
const SELF = join(DIR, "cli");
|
|
31
31
|
const DAYS = 365;
|
|
32
|
+
const PENDING_DAYS = 30;
|
|
32
33
|
const SKIP_DIRS = new Set(["node_modules", "Library", "Applications", ".Trash", "vendor", "target", "build", "dist", ".venv", "venv", "__pycache__", "Pods", "DerivedData", "go", ".cargo", ".rustup", ".npm", ".cache", ".local", "snap", "AppData"]);
|
|
33
34
|
const args = process.argv.slice(2);
|
|
34
35
|
const cmd = args[0] ?? "help";
|
|
@@ -127,6 +128,30 @@ function defaultRef(repo) {
|
|
|
127
128
|
}
|
|
128
129
|
return "HEAD";
|
|
129
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Remote branches whose work has not landed on the default branch yet. Only `refs/remotes/origin`
|
|
133
|
+
* counts, and only tips touched in the last 30 days: local branches left behind by squash-merged
|
|
134
|
+
* worktrees are the same commits over again, and they inflated pending by 14x.
|
|
135
|
+
*/
|
|
136
|
+
function pendingRefs(repo, ref) {
|
|
137
|
+
const out = git(repo, "for-each-ref", "--format=%(refname) %(committerdate:unix)", "refs/remotes/origin");
|
|
138
|
+
if (out === null)
|
|
139
|
+
return [];
|
|
140
|
+
const cutoff = Date.now() / 1000 - PENDING_DAYS * 86_400;
|
|
141
|
+
const refs = [];
|
|
142
|
+
for (const line of out.split("\n")) {
|
|
143
|
+
const [name, when] = line.split(" ");
|
|
144
|
+
if (!name || !when)
|
|
145
|
+
continue;
|
|
146
|
+
const short = name.slice("refs/remotes/".length);
|
|
147
|
+
if (short === ref || short === "origin/HEAD")
|
|
148
|
+
continue;
|
|
149
|
+
if (Number(when) < cutoff)
|
|
150
|
+
continue;
|
|
151
|
+
refs.push(name);
|
|
152
|
+
}
|
|
153
|
+
return refs;
|
|
154
|
+
}
|
|
130
155
|
// ---------- counting ----------
|
|
131
156
|
const LANG = {
|
|
132
157
|
ts: "TypeScript", tsx: "TypeScript", js: "JavaScript", jsx: "JavaScript", mjs: "JavaScript", cjs: "JavaScript",
|
|
@@ -199,8 +224,8 @@ function countRepo(repo, emails, since, salt, sendNames, fetch) {
|
|
|
199
224
|
const out = git(repo, "log", ref, ...common, ...authors);
|
|
200
225
|
if (out === null)
|
|
201
226
|
return null;
|
|
202
|
-
|
|
203
|
-
const pendingOut = git(repo, "log",
|
|
227
|
+
const unmerged = pendingRefs(repo, ref);
|
|
228
|
+
const pendingOut = unmerged.length > 0 ? git(repo, "log", ...unmerged, "--not", ref, ...common, ...authors) : null;
|
|
204
229
|
const merged = tally(out, all);
|
|
205
230
|
const pending = pendingOut === null ? EMPTY_TALLY() : tally(pendingOut, all);
|
|
206
231
|
if (merged.weeks.size === 0 && pending.weeks.size === 0)
|
|
@@ -493,14 +518,14 @@ async function link() {
|
|
|
493
518
|
log(`\n scheduled: ${how}`);
|
|
494
519
|
log(` config: ${CONFIG}`);
|
|
495
520
|
log(`\n done. It re-syncs on its own. To run commands by hand, either use`);
|
|
496
|
-
log(` npx
|
|
521
|
+
log(` npx @yaroslavhaidash/gitstats-cli@latest <command>`);
|
|
497
522
|
log(` or add ${BIN} to your PATH and use \`gitstats <command>\`.`);
|
|
498
523
|
log(` Commands and how to stop: ${server}/docs\n`);
|
|
499
524
|
}
|
|
500
525
|
function requireConfig() {
|
|
501
526
|
const c = loadConfig();
|
|
502
527
|
if (!c)
|
|
503
|
-
throw new Error("not linked yet; run: npx
|
|
528
|
+
throw new Error("not linked yet; run: npx @yaroslavhaidash/gitstats-cli@latest link");
|
|
504
529
|
return c;
|
|
505
530
|
}
|
|
506
531
|
async function main() {
|