zapdev 1.4.0 → 1.6.0
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 +9 -6
- package/dist/cli.js +141 -75
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,13 +37,14 @@ flowchart LR
|
|
|
37
37
|
|
|
38
38
|
## Environment Variables
|
|
39
39
|
|
|
40
|
-
| Variable
|
|
41
|
-
|
|
|
42
|
-
| `ZD_URL`
|
|
43
|
-
| `ZD_MODEL`
|
|
44
|
-
| `ZD_EFFORT`
|
|
40
|
+
| Variable | Required | Description |
|
|
41
|
+
| ----------------- | ------------ | --------------------------------------------------------------------------------------------------- |
|
|
42
|
+
| `ZD_URL` | For `commit` | Complete HTTP(S) Chat Completions endpoint, including its path |
|
|
43
|
+
| `ZD_MODEL` | For `commit` | Model identifier supported by the endpoint |
|
|
44
|
+
| `ZD_EFFORT` | For `commit` | Sent as `reasoning_effort`; use a value supported by your model, such as `low`, `medium`, or `high` |
|
|
45
|
+
| `ZD_HOOK_TIMEOUT` | No | Deadline per Git hook in seconds (default: `60`); positive numbers from `0.001` to `2147483.647` |
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
The LLM settings have no defaults, automatic provider detection, or backup models. CLI flags override these settings. Legacy `OLLAMA_*` variables are no longer read.
|
|
47
48
|
|
|
48
49
|
Requests use the OpenAI Chat Completions format over plain `fetch`, without a provider SDK. No authentication headers are sent; use an endpoint that does not require them. The endpoint and model must support `reasoning_effort`.
|
|
49
50
|
|
|
@@ -139,6 +140,8 @@ Before contacting the LLM endpoint, zapdev runs `gitleaks git --staged --verbose
|
|
|
139
140
|
|
|
140
141
|
Failures are reported per repository while the others continue. Any failure produces a nonzero exit code.
|
|
141
142
|
|
|
143
|
+
In a terminal, Git and its hooks display live logs and support native prompts, even with `--yes` (which only skips zapdev prompts). Git controls hook stdin; interactive hooks should read from the terminal, for example `/dev/tty`. Each hook has a 60-second deadline, including time spent answering prompts; override it with `ZD_HOOK_TIMEOUT=120 zapdev commit`.
|
|
144
|
+
|
|
142
145
|
Pushing is optimistic, with no preliminary fetch. If the branch is behind upstream, `--rebase` runs `git pull --rebase`, while `--merge` runs `git pull --no-rebase --no-edit`; zapdev then retries once. Without either flag, interactive runs ask whether to rebase, merge, or quit. Runs using `--yes` or without a TTY must provide one of the flags.
|
|
143
146
|
|
|
144
147
|
Without a TTY, zapdev commits all prepared repositories automatically and only pushes when `--push` is set.
|
package/dist/cli.js
CHANGED
|
@@ -554,7 +554,7 @@ function _getBuiltinFlags(long, short, userNames, userAliases) {
|
|
|
554
554
|
// package.json
|
|
555
555
|
var package_default = {
|
|
556
556
|
name: "zapdev",
|
|
557
|
-
version: "1.
|
|
557
|
+
version: "1.6.0",
|
|
558
558
|
description: "Fast, performant and lightweight git chores and dev tools using your terminal and an OpenAI-compatible LLM endpoint.",
|
|
559
559
|
type: "module",
|
|
560
560
|
bin: {
|
|
@@ -1815,6 +1815,13 @@ function sanitizeCommitMessage(raw) {
|
|
|
1815
1815
|
}
|
|
1816
1816
|
|
|
1817
1817
|
// src/lib/config.ts
|
|
1818
|
+
function resolveHookTimeout(env = process.env) {
|
|
1819
|
+
const timeout = Number(env.ZD_HOOK_TIMEOUT ?? 60) * 1e3;
|
|
1820
|
+
if (!Number.isFinite(timeout) || timeout < 1 || timeout > 2147483647) {
|
|
1821
|
+
throw new Error("ZD_HOOK_TIMEOUT must be a number of seconds between 0.001 and 2147483.647.");
|
|
1822
|
+
}
|
|
1823
|
+
return timeout;
|
|
1824
|
+
}
|
|
1818
1825
|
function resolveConfig(env = process.env, overrides = {}) {
|
|
1819
1826
|
const config = {
|
|
1820
1827
|
url: (overrides.url ?? env.ZD_URL)?.trim() ?? "",
|
|
@@ -1837,6 +1844,7 @@ function resolveConfig(env = process.env, overrides = {}) {
|
|
|
1837
1844
|
}
|
|
1838
1845
|
|
|
1839
1846
|
// src/lib/git.ts
|
|
1847
|
+
import { execFileSync } from "node:child_process";
|
|
1840
1848
|
import { readdir } from "node:fs/promises";
|
|
1841
1849
|
import { join } from "node:path";
|
|
1842
1850
|
import { createInterface as createInterface2 } from "node:readline";
|
|
@@ -2168,10 +2176,22 @@ var R2 = (e2, t3, n4) => {
|
|
|
2168
2176
|
};
|
|
2169
2177
|
var z = R2;
|
|
2170
2178
|
|
|
2179
|
+
// src/lib/errors.ts
|
|
2180
|
+
var GitOutputError = class extends Error {
|
|
2181
|
+
constructor(message, hookFailureReported = false) {
|
|
2182
|
+
super(message);
|
|
2183
|
+
this.hookFailureReported = hookFailureReported;
|
|
2184
|
+
}
|
|
2185
|
+
hookFailureReported;
|
|
2186
|
+
};
|
|
2187
|
+
function errorMessage(error) {
|
|
2188
|
+
return error instanceof Error ? error.message : String(error);
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2171
2191
|
// src/lib/git-hooks.ts
|
|
2172
|
-
function createHookReporter(onHook) {
|
|
2192
|
+
function createHookReporter(onHook, onTimeout, timeout) {
|
|
2173
2193
|
const hooks = /* @__PURE__ */ new Map();
|
|
2174
|
-
|
|
2194
|
+
const report = (line) => {
|
|
2175
2195
|
let event;
|
|
2176
2196
|
try {
|
|
2177
2197
|
const value = JSON.parse(line);
|
|
@@ -2183,13 +2203,22 @@ function createHookReporter(onHook) {
|
|
|
2183
2203
|
if (typeof event.sid !== "string" || typeof event.child_id !== "number") return;
|
|
2184
2204
|
const key = `${event.sid}:${event.child_id}`;
|
|
2185
2205
|
if (event.event === "child_start" && event.child_class === "hook" && typeof event.hook_name === "string") {
|
|
2186
|
-
|
|
2187
|
-
|
|
2206
|
+
const name = event.hook_name;
|
|
2207
|
+
hooks.set(key, { name, timer: setTimeout(() => onTimeout(name), timeout) });
|
|
2208
|
+
onHook?.({ name, phase: "start" });
|
|
2188
2209
|
} else if (event.event === "child_exit" && typeof event.code === "number") {
|
|
2189
|
-
const
|
|
2190
|
-
if (
|
|
2210
|
+
const hook = hooks.get(key);
|
|
2211
|
+
if (!hook) return;
|
|
2212
|
+
clearTimeout(hook.timer);
|
|
2191
2213
|
hooks.delete(key);
|
|
2192
|
-
onHook({ name, phase: "exit", exitCode: event.code });
|
|
2214
|
+
onHook?.({ name: hook.name, phase: "exit", exitCode: event.code });
|
|
2215
|
+
}
|
|
2216
|
+
};
|
|
2217
|
+
return {
|
|
2218
|
+
report,
|
|
2219
|
+
close() {
|
|
2220
|
+
for (const { timer } of hooks.values()) clearTimeout(timer);
|
|
2221
|
+
hooks.clear();
|
|
2193
2222
|
}
|
|
2194
2223
|
};
|
|
2195
2224
|
}
|
|
@@ -2197,18 +2226,73 @@ function createHookReporter(onHook) {
|
|
|
2197
2226
|
// src/lib/git.ts
|
|
2198
2227
|
var UPSTREAM_REF = "@{upstream}";
|
|
2199
2228
|
async function git(args, cwd, onHook) {
|
|
2229
|
+
const timeout = resolveHookTimeout();
|
|
2230
|
+
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY && ["commit", "push", "pull", "fetch"].includes(args[0] ?? ""));
|
|
2231
|
+
const terminalState = interactive && process.platform !== "win32" ? execFileSync("stty", ["-g"], { stdio: ["inherit", "pipe", "ignore"], encoding: "utf8" }).trim() : void 0;
|
|
2200
2232
|
const child = R2("git", args, {
|
|
2201
|
-
nodeOptions:
|
|
2233
|
+
nodeOptions: {
|
|
2234
|
+
cwd,
|
|
2235
|
+
detached: !interactive && process.platform !== "win32",
|
|
2236
|
+
env: { ...process.env, GIT_TRACE2_EVENT: "3" },
|
|
2237
|
+
stdio: interactive ? ["inherit", "inherit", "inherit", "pipe"] : ["pipe", "pipe", "pipe", "pipe"]
|
|
2238
|
+
}
|
|
2202
2239
|
});
|
|
2240
|
+
let timeoutError;
|
|
2241
|
+
let hookFailureReported = false;
|
|
2242
|
+
const { report, close } = createHookReporter((event) => {
|
|
2243
|
+
if (onHook && event.phase === "exit" && event.exitCode !== 0) hookFailureReported = true;
|
|
2244
|
+
onHook?.(event);
|
|
2245
|
+
}, (name) => {
|
|
2246
|
+
if (timeoutError || child.pid === void 0) return;
|
|
2247
|
+
timeoutError = new Error(`${name} hook timed out after ${timeout / 1e3} seconds`);
|
|
2248
|
+
try {
|
|
2249
|
+
if (process.platform === "win32") {
|
|
2250
|
+
execFileSync("taskkill", ["/pid", String(child.pid), "/T", "/F"], { stdio: "ignore" });
|
|
2251
|
+
} else if (interactive) {
|
|
2252
|
+
killProcessTree(child.pid);
|
|
2253
|
+
} else {
|
|
2254
|
+
process.kill(-child.pid, "SIGKILL");
|
|
2255
|
+
}
|
|
2256
|
+
} catch {
|
|
2257
|
+
child.kill("SIGKILL");
|
|
2258
|
+
}
|
|
2259
|
+
}, timeout);
|
|
2203
2260
|
const trace = child.process?.stdio[3];
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2261
|
+
const reader = trace instanceof Readable ? createInterface2({ input: trace }).on("line", report) : void 0;
|
|
2262
|
+
try {
|
|
2263
|
+
const result = await child;
|
|
2264
|
+
if (timeoutError) throw timeoutError;
|
|
2265
|
+
if (result.exitCode !== 0) {
|
|
2266
|
+
const message = result.stderr.trim() || `git ${args.join(" ")} failed`;
|
|
2267
|
+
if (interactive) throw new GitOutputError(message, hookFailureReported);
|
|
2268
|
+
throw new Error(message);
|
|
2269
|
+
}
|
|
2270
|
+
return result.stdout;
|
|
2271
|
+
} finally {
|
|
2272
|
+
reader?.close();
|
|
2273
|
+
close();
|
|
2274
|
+
if (terminalState) execFileSync("stty", [terminalState], { stdio: ["inherit", "ignore", "ignore"] });
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
function killProcessTree(pid) {
|
|
2278
|
+
const children = /* @__PURE__ */ new Map();
|
|
2279
|
+
const output = execFileSync("ps", ["-A", "-o", "pid=,ppid="], { encoding: "utf8" });
|
|
2280
|
+
for (const line of output.trim().split("\n")) {
|
|
2281
|
+
const [child, parent] = line.trim().split(/\s+/).map(Number);
|
|
2282
|
+
if (child === void 0 || parent === void 0) continue;
|
|
2283
|
+
const siblings = children.get(parent) ?? [];
|
|
2284
|
+
siblings.push(child);
|
|
2285
|
+
children.set(parent, siblings);
|
|
2286
|
+
}
|
|
2287
|
+
const pids = [pid];
|
|
2288
|
+
for (const parent of pids) pids.push(...children.get(parent) ?? []);
|
|
2289
|
+
for (const child of pids.reverse()) {
|
|
2290
|
+
try {
|
|
2291
|
+
process.kill(child, "SIGKILL");
|
|
2292
|
+
} catch (error) {
|
|
2293
|
+
if (error.code !== "ESRCH") throw error;
|
|
2294
|
+
}
|
|
2210
2295
|
}
|
|
2211
|
-
return result.stdout;
|
|
2212
2296
|
}
|
|
2213
2297
|
async function tryGit(args, cwd) {
|
|
2214
2298
|
const result = await R2("git", args, { nodeOptions: { cwd } });
|
|
@@ -2221,7 +2305,7 @@ async function getStagedDiff(repo) {
|
|
|
2221
2305
|
return git(["diff", "--cached"], repo);
|
|
2222
2306
|
}
|
|
2223
2307
|
async function commit(repo, message, onHook) {
|
|
2224
|
-
await git(["commit", "-m", message], repo, onHook);
|
|
2308
|
+
await git(["commit", "--quiet", "-m", message], repo, onHook);
|
|
2225
2309
|
}
|
|
2226
2310
|
async function currentBranch(repo) {
|
|
2227
2311
|
return (await git(["symbolic-ref", "--short", "HEAD"], repo)).trim();
|
|
@@ -2239,19 +2323,19 @@ async function hasUpstream(repo) {
|
|
|
2239
2323
|
return result !== null;
|
|
2240
2324
|
}
|
|
2241
2325
|
async function push(repo, onHook) {
|
|
2242
|
-
await git(["push"], repo, onHook);
|
|
2326
|
+
await git(["push", "--quiet"], repo, onHook);
|
|
2243
2327
|
}
|
|
2244
2328
|
async function pushSetUpstream(repo, branch, onHook) {
|
|
2245
|
-
await git(["push", "-u", "origin", branch], repo, onHook);
|
|
2329
|
+
await git(["push", "--quiet", "-u", "origin", branch], repo, onHook);
|
|
2246
2330
|
}
|
|
2247
2331
|
async function pullRebase(repo, onHook) {
|
|
2248
|
-
await git(["pull", "--rebase"], repo, onHook);
|
|
2332
|
+
await git(["pull", "--quiet", "--rebase"], repo, onHook);
|
|
2249
2333
|
}
|
|
2250
2334
|
async function pullMerge(repo, onHook) {
|
|
2251
|
-
await git(["pull", "--no-rebase", "--no-edit"], repo, onHook);
|
|
2335
|
+
await git(["pull", "--quiet", "--no-rebase", "--no-edit"], repo, onHook);
|
|
2252
2336
|
}
|
|
2253
2337
|
async function fetchRemote(repo, onHook) {
|
|
2254
|
-
await git(["fetch"], repo, onHook);
|
|
2338
|
+
await git(["fetch", "--quiet"], repo, onHook);
|
|
2255
2339
|
}
|
|
2256
2340
|
async function behindCount(repo) {
|
|
2257
2341
|
const out = await tryGit(["rev-list", "--count", `HEAD..${UPSTREAM_REF}`], repo);
|
|
@@ -2270,11 +2354,6 @@ async function repoRoot(dir) {
|
|
|
2270
2354
|
return (await tryGit(["rev-parse", "--show-toplevel"], dir))?.trim() ?? null;
|
|
2271
2355
|
}
|
|
2272
2356
|
|
|
2273
|
-
// src/lib/errors.ts
|
|
2274
|
-
function errorMessage(error) {
|
|
2275
|
-
return error instanceof Error ? error.message : String(error);
|
|
2276
|
-
}
|
|
2277
|
-
|
|
2278
2357
|
// src/lib/gitleaks.ts
|
|
2279
2358
|
async function hasGitleaks() {
|
|
2280
2359
|
try {
|
|
@@ -2438,6 +2517,7 @@ var commitCommand = defineCommand({
|
|
|
2438
2517
|
}
|
|
2439
2518
|
let config;
|
|
2440
2519
|
try {
|
|
2520
|
+
resolveHookTimeout();
|
|
2441
2521
|
config = resolveConfig(process.env, {
|
|
2442
2522
|
url: args.url,
|
|
2443
2523
|
model: args.model,
|
|
@@ -2503,17 +2583,13 @@ var commitCommand = defineCommand({
|
|
|
2503
2583
|
}
|
|
2504
2584
|
const committed = [];
|
|
2505
2585
|
for (const draft of selected) {
|
|
2506
|
-
|
|
2507
|
-
const message = `${draft.label}: committing`;
|
|
2508
|
-
loader2?.start(message);
|
|
2586
|
+
log.info(`${draft.label}: committing`);
|
|
2509
2587
|
try {
|
|
2510
|
-
await commit(draft.repo, draft.message, reportHooks(draft.label
|
|
2511
|
-
loader2?.clear();
|
|
2588
|
+
await commit(draft.repo, draft.message, reportHooks(draft.label));
|
|
2512
2589
|
committed.push(draft);
|
|
2513
2590
|
log.success(`${draft.label}: committed ${draft.message}`);
|
|
2514
2591
|
} catch (error) {
|
|
2515
|
-
|
|
2516
|
-
log.error(`${draft.pendingLabel}: commit failed: ${errorMessage(error)}`);
|
|
2592
|
+
reportGitFailure(`${draft.pendingLabel}: commit failed`, error);
|
|
2517
2593
|
process.exitCode = 1;
|
|
2518
2594
|
}
|
|
2519
2595
|
}
|
|
@@ -2535,13 +2611,12 @@ var commitCommand = defineCommand({
|
|
|
2535
2611
|
try {
|
|
2536
2612
|
const pushed = await pushOptimistic(
|
|
2537
2613
|
repository,
|
|
2538
|
-
interactive,
|
|
2539
2614
|
interactive && !args.yes,
|
|
2540
2615
|
syncStrategy
|
|
2541
2616
|
);
|
|
2542
2617
|
if (!pushed) process.exitCode = 1;
|
|
2543
2618
|
} catch (error) {
|
|
2544
|
-
|
|
2619
|
+
reportGitFailure(`${repository.label}: push failed`, error);
|
|
2545
2620
|
process.exitCode = 1;
|
|
2546
2621
|
}
|
|
2547
2622
|
}
|
|
@@ -2549,17 +2624,19 @@ var commitCommand = defineCommand({
|
|
|
2549
2624
|
if (interactive) outro(process.exitCode ? "Finished with errors." : "Done.");
|
|
2550
2625
|
}
|
|
2551
2626
|
});
|
|
2552
|
-
function
|
|
2627
|
+
function reportGitFailure(message, error, level = "error") {
|
|
2628
|
+
if (error instanceof GitOutputError && error.hookFailureReported) return;
|
|
2629
|
+
log[level](error instanceof GitOutputError ? message : `${message}: ${errorMessage(error)}`);
|
|
2630
|
+
}
|
|
2631
|
+
function reportHooks(label) {
|
|
2632
|
+
const options = { secondarySymbol: "" };
|
|
2553
2633
|
return (event) => {
|
|
2554
2634
|
const hook = `${label}: ${event.name}`;
|
|
2555
2635
|
if (event.phase === "start") {
|
|
2556
|
-
|
|
2557
|
-
else log.info(`${hook} running\u2026`);
|
|
2636
|
+
log.step(styleText3("bold", hook), options);
|
|
2558
2637
|
} else {
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
else log.error(`${hook} \u2717 (exit ${event.exitCode})`);
|
|
2562
|
-
loader?.start(message);
|
|
2638
|
+
if (event.exitCode === 0) log.success(`${hook}: completed`, options);
|
|
2639
|
+
else log.error(`${hook}: failed (exit ${event.exitCode})`, options);
|
|
2563
2640
|
}
|
|
2564
2641
|
};
|
|
2565
2642
|
}
|
|
@@ -2595,36 +2672,33 @@ async function reviewMessages(drafts, canPrompt) {
|
|
|
2595
2672
|
action.draft.message = edited.trim();
|
|
2596
2673
|
}
|
|
2597
2674
|
}
|
|
2598
|
-
async function syncWithUpstream({ repo, label }, strategy
|
|
2599
|
-
const loader = interactive ? spinner() : void 0;
|
|
2675
|
+
async function syncWithUpstream({ repo, label }, strategy) {
|
|
2600
2676
|
const actionLabel = strategy === "rebase" ? "Rebase" : "Merge";
|
|
2601
|
-
|
|
2602
|
-
loader?.start(message);
|
|
2677
|
+
log.info(`${label}: pulling --${strategy === "rebase" ? "rebase" : "no-rebase"}`);
|
|
2603
2678
|
try {
|
|
2604
|
-
await (strategy === "rebase" ? pullRebase : pullMerge)(repo, reportHooks(label
|
|
2605
|
-
|
|
2679
|
+
await (strategy === "rebase" ? pullRebase : pullMerge)(repo, reportHooks(label));
|
|
2680
|
+
log.success(`${label}: ${strategy === "rebase" ? "rebased on upstream" : "merged upstream"}`);
|
|
2606
2681
|
return true;
|
|
2607
2682
|
} catch (error) {
|
|
2608
|
-
|
|
2609
|
-
log.error(`${label}: ${actionLabel} failed (resolve conflicts, then push): ${errorMessage(error)}`);
|
|
2683
|
+
reportGitFailure(`${label}: ${actionLabel} failed (resolve conflicts, then push)`, error);
|
|
2610
2684
|
return false;
|
|
2611
2685
|
}
|
|
2612
2686
|
}
|
|
2613
|
-
async function pushOptimistic(repository,
|
|
2687
|
+
async function pushOptimistic(repository, canPrompt, strategy) {
|
|
2614
2688
|
const { repo, label } = repository;
|
|
2615
2689
|
const [upstream, branch] = await Promise.all([hasUpstream(repo), currentBranch(repo)]);
|
|
2616
2690
|
const doPush = (onHook) => upstream ? push(repo, onHook) : pushSetUpstream(repo, branch, onHook);
|
|
2617
|
-
const first = await tryPush(repository,
|
|
2691
|
+
const first = await tryPush(repository, doPush);
|
|
2618
2692
|
if (first.ok) return true;
|
|
2619
|
-
if (upstream && await isBehind(repository
|
|
2693
|
+
if (upstream && await isBehind(repository)) {
|
|
2620
2694
|
const syncStrategy = strategy ?? await chooseSyncStrategy(repository, canPrompt);
|
|
2621
|
-
if (!syncStrategy || !await syncWithUpstream(repository, syncStrategy
|
|
2622
|
-
const retry = await tryPush(repository,
|
|
2695
|
+
if (!syncStrategy || !await syncWithUpstream(repository, syncStrategy)) return false;
|
|
2696
|
+
const retry = await tryPush(repository, doPush);
|
|
2623
2697
|
if (retry.ok) return true;
|
|
2624
|
-
|
|
2698
|
+
reportGitFailure(`${label}: push failed`, retry.error);
|
|
2625
2699
|
return false;
|
|
2626
2700
|
}
|
|
2627
|
-
|
|
2701
|
+
reportGitFailure(`${label}: push failed`, first.error);
|
|
2628
2702
|
return false;
|
|
2629
2703
|
}
|
|
2630
2704
|
async function chooseSyncStrategy({ label }, interactive) {
|
|
@@ -2646,33 +2720,25 @@ async function chooseSyncStrategy({ label }, interactive) {
|
|
|
2646
2720
|
}
|
|
2647
2721
|
return action;
|
|
2648
2722
|
}
|
|
2649
|
-
async function tryPush({ label },
|
|
2650
|
-
|
|
2651
|
-
const message = `${label}: pushing`;
|
|
2652
|
-
loader?.start(message);
|
|
2723
|
+
async function tryPush({ label }, doPush) {
|
|
2724
|
+
log.info(`${label}: pushing`);
|
|
2653
2725
|
try {
|
|
2654
|
-
await doPush(reportHooks(label
|
|
2655
|
-
|
|
2726
|
+
await doPush(reportHooks(label));
|
|
2727
|
+
log.success(`${label}: pushed`);
|
|
2656
2728
|
return { ok: true };
|
|
2657
2729
|
} catch (error) {
|
|
2658
|
-
loader?.error("Push failed");
|
|
2659
2730
|
return { ok: false, error };
|
|
2660
2731
|
}
|
|
2661
2732
|
}
|
|
2662
|
-
async function isBehind({ repo, label }
|
|
2663
|
-
|
|
2664
|
-
const message = `${label}: checking upstream`;
|
|
2665
|
-
loader?.start(message);
|
|
2733
|
+
async function isBehind({ repo, label }) {
|
|
2734
|
+
log.info(`${label}: checking upstream`);
|
|
2666
2735
|
try {
|
|
2667
|
-
await fetchRemote(repo, reportHooks(label
|
|
2736
|
+
await fetchRemote(repo, reportHooks(label));
|
|
2668
2737
|
const behind = await behindCount(repo);
|
|
2669
|
-
|
|
2670
|
-
behind > 0 ? `Behind upstream by ${behind} commit${behind > 1 ? "s" : ""}` : "Up to date with upstream"
|
|
2671
|
-
);
|
|
2738
|
+
log.info(`${label}: ${behind > 0 ? `Behind upstream by ${behind} commit${behind > 1 ? "s" : ""}` : "Up to date with upstream"}`);
|
|
2672
2739
|
return behind > 0;
|
|
2673
2740
|
} catch (error) {
|
|
2674
|
-
|
|
2675
|
-
log.warn(`${label}: could not check upstream: ${errorMessage(error)}`);
|
|
2741
|
+
reportGitFailure(`${label}: could not check upstream`, error, "warn");
|
|
2676
2742
|
return false;
|
|
2677
2743
|
}
|
|
2678
2744
|
}
|