git-watchtower 1.9.1 → 1.9.3
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/bin/git-watchtower.js +18 -7
- package/package.json +1 -1
- package/src/polling/engine.js +33 -0
package/bin/git-watchtower.js
CHANGED
|
@@ -82,6 +82,7 @@ const { parseGitHubPr, parseGitLabMr, parseGitHubPrList, parseGitLabMrList, isBa
|
|
|
82
82
|
// Security & Validation (imported from src/git/branch.js and src/git/commands.js)
|
|
83
83
|
// ============================================================================
|
|
84
84
|
const { isValidBranchName, sanitizeBranchName, getGoneBranches, deleteGoneBranches } = require('../src/git/branch');
|
|
85
|
+
const { pruneStaleEntries } = require('../src/polling/engine');
|
|
85
86
|
const { isGitAvailable: checkGitAvailable, execGit, execGitSilent, getDiffStats: getDiffStatsSafe, getAheadBehind, getDiffShortstat } = require('../src/git/commands');
|
|
86
87
|
|
|
87
88
|
// Session stats (always-on, non-casino stats)
|
|
@@ -993,11 +994,11 @@ async function refreshAllSparklines() {
|
|
|
993
994
|
return; // Don't refresh too often
|
|
994
995
|
}
|
|
995
996
|
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
if (branch.isDeleted) continue;
|
|
997
|
+
const currentBranches = store.get('branches');
|
|
998
|
+
for (const branch of currentBranches.slice(0, 20)) { // Limit to top 20
|
|
999
|
+
if (branch.isDeleted) continue;
|
|
1000
1000
|
|
|
1001
|
+
try {
|
|
1001
1002
|
// Get commit counts for last 7 days (try remote, fall back to local)
|
|
1002
1003
|
const sparkResult = await execGitSilent(
|
|
1003
1004
|
['log', `origin/${branch.name}`, '--since=7 days ago', '--format=%ad', '--date=format:%Y-%m-%d'],
|
|
@@ -1027,11 +1028,11 @@ async function refreshAllSparklines() {
|
|
|
1027
1028
|
|
|
1028
1029
|
const counts = Array.from(dayCounts.values());
|
|
1029
1030
|
store.get('sparklineCache').set(branch.name, generateSparkline(counts));
|
|
1031
|
+
} catch (e) {
|
|
1032
|
+
// Skip this branch - don't let one failure abort all sparkline updates
|
|
1030
1033
|
}
|
|
1031
|
-
lastSparklineUpdate = now;
|
|
1032
|
-
} catch (e) {
|
|
1033
|
-
// Silently fail - sparklines are optional
|
|
1034
1034
|
}
|
|
1035
|
+
lastSparklineUpdate = now;
|
|
1035
1036
|
}
|
|
1036
1037
|
|
|
1037
1038
|
async function getPreviewData(branchName) {
|
|
@@ -1817,6 +1818,16 @@ async function pollGitChanges() {
|
|
|
1817
1818
|
}
|
|
1818
1819
|
}
|
|
1819
1820
|
|
|
1821
|
+
// Prune stale entries: remove branches from tracking sets/caches
|
|
1822
|
+
// that no longer exist in git (deleted >30s ago or already gone)
|
|
1823
|
+
pruneStaleEntries({
|
|
1824
|
+
knownBranchNames,
|
|
1825
|
+
fetchedBranchNames,
|
|
1826
|
+
allBranches,
|
|
1827
|
+
caches: [previousBranchStates, prInfoCache, store.get('sparklineCache'), store.get('aheadBehindCache')],
|
|
1828
|
+
now,
|
|
1829
|
+
});
|
|
1830
|
+
|
|
1820
1831
|
// Note: isNew flag is only cleared when branch becomes current (see below)
|
|
1821
1832
|
|
|
1822
1833
|
// Keep deleted branches in the list (don't remove them)
|
package/package.json
CHANGED
package/src/polling/engine.js
CHANGED
|
@@ -147,6 +147,38 @@ function restoreSelection(branches, previousName, previousIndex) {
|
|
|
147
147
|
return { selectedIndex: previousIndex, selectedBranchName: previousName };
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Prune stale entries from tracking sets and caches for branches
|
|
152
|
+
* that no longer exist in git.
|
|
153
|
+
* @param {Object} opts
|
|
154
|
+
* @param {Set<string>} opts.knownBranchNames - Known branch names (mutated)
|
|
155
|
+
* @param {Set<string>} opts.fetchedBranchNames - Currently fetched branch names
|
|
156
|
+
* @param {Array<{name: string, isDeleted?: boolean, deletedAt?: number}>} opts.allBranches - All branches including deleted
|
|
157
|
+
* @param {Map<string, *>[]} opts.caches - Maps to prune stale keys from
|
|
158
|
+
* @param {number} [opts.retentionMs=30000] - How long to keep deleted branches before pruning
|
|
159
|
+
* @param {number} [opts.now] - Current timestamp (defaults to Date.now())
|
|
160
|
+
* @returns {string[]} Names of pruned branches
|
|
161
|
+
*/
|
|
162
|
+
function pruneStaleEntries({ knownBranchNames, fetchedBranchNames, allBranches, caches, retentionMs = 30000, now }) {
|
|
163
|
+
const timestamp = now ?? Date.now();
|
|
164
|
+
const pruned = [];
|
|
165
|
+
for (const knownName of [...knownBranchNames]) {
|
|
166
|
+
if (fetchedBranchNames.has(knownName)) continue;
|
|
167
|
+
const deletedBranch = allBranches.find(b => b.name === knownName && b.isDeleted);
|
|
168
|
+
const shouldPrune = deletedBranch
|
|
169
|
+
? (deletedBranch.deletedAt && (timestamp - deletedBranch.deletedAt) > retentionMs)
|
|
170
|
+
: true; // Not in allBranches at all — stale entry
|
|
171
|
+
if (shouldPrune) {
|
|
172
|
+
knownBranchNames.delete(knownName);
|
|
173
|
+
for (const cache of caches) {
|
|
174
|
+
cache.delete(knownName);
|
|
175
|
+
}
|
|
176
|
+
pruned.push(knownName);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return pruned;
|
|
180
|
+
}
|
|
181
|
+
|
|
150
182
|
module.exports = {
|
|
151
183
|
detectNewBranches,
|
|
152
184
|
detectDeletedBranches,
|
|
@@ -154,4 +186,5 @@ module.exports = {
|
|
|
154
186
|
sortBranches,
|
|
155
187
|
calculateAdaptiveInterval,
|
|
156
188
|
restoreSelection,
|
|
189
|
+
pruneStaleEntries,
|
|
157
190
|
};
|