@lumy-pack/line-lore 0.0.4 → 0.0.5

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/dist/cli.mjs CHANGED
@@ -305,6 +305,51 @@ async function gitExec(args, options) {
305
305
  LineLoreErrorCode.GIT_COMMAND_FAILED
306
306
  );
307
307
  }
308
+ async function gitPipe(producerArgs, consumerArgs, options) {
309
+ const { cwd, timeout } = options ?? {};
310
+ const pipeArgs = [...producerArgs, "|", ...consumerArgs];
311
+ try {
312
+ const result = await execa("git", producerArgs, {
313
+ cwd,
314
+ timeout,
315
+ reject: false
316
+ }).pipe("git", consumerArgs, { cwd, timeout, reject: false });
317
+ const exitCode = result.exitCode ?? 0;
318
+ if (exitCode !== 0) {
319
+ throw new LineLoreError(
320
+ LineLoreErrorCode.GIT_COMMAND_FAILED,
321
+ `git pipe failed with exit code ${exitCode}: ${result.stderr}`,
322
+ {
323
+ command: "git",
324
+ args: pipeArgs,
325
+ exitCode,
326
+ stderr: result.stderr,
327
+ cwd
328
+ }
329
+ );
330
+ }
331
+ return {
332
+ stdout: result.stdout,
333
+ stderr: result.stderr,
334
+ exitCode
335
+ };
336
+ } catch (error) {
337
+ if (error instanceof LineLoreError) throw error;
338
+ const isTimeout = error instanceof Error && "isTerminated" in error && error.timedOut === true;
339
+ if (isTimeout) {
340
+ throw new LineLoreError(
341
+ LineLoreErrorCode.GIT_TIMEOUT,
342
+ `git pipe timed out after ${timeout}ms`,
343
+ { command: "git", args: pipeArgs, timeout, cwd }
344
+ );
345
+ }
346
+ throw new LineLoreError(
347
+ LineLoreErrorCode.GIT_COMMAND_FAILED,
348
+ `git pipe failed: ${error instanceof Error ? error.message : String(error)}`,
349
+ { command: "git", args: pipeArgs, cwd }
350
+ );
351
+ }
352
+ }
308
353
  async function shellExec(command, args, options) {
309
354
  return execCommand(
310
355
  command,
@@ -420,14 +465,10 @@ async function computePatchId(commitSha, options) {
420
465
  const cached = await cache.get(commitSha);
421
466
  if (cached) return cached;
422
467
  try {
423
- const cwd = options?.cwd ?? ".";
424
- const result = await shellExec(
425
- "bash",
426
- [
427
- "-c",
428
- `git -C "${cwd}" diff "${commitSha}^..${commitSha}" | git patch-id --stable`
429
- ],
430
- { timeout: options?.timeout }
468
+ const result = await gitPipe(
469
+ ["diff", `${commitSha}^..${commitSha}`],
470
+ ["patch-id", "--stable"],
471
+ { cwd: options?.cwd, timeout: options?.timeout }
431
472
  );
432
473
  const patchId = result.stdout.trim().split(/\s+/)[0];
433
474
  if (!patchId) return null;
@@ -443,15 +484,18 @@ async function findPatchIdMatch(commitSha, options) {
443
484
  const targetPatchId = await computePatchId(commitSha, options);
444
485
  if (!targetPatchId) return null;
445
486
  try {
446
- const logResult = await gitExec(
447
- ["log", "--format=%H", `-${scanDepth}`, ref],
448
- { cwd: options?.cwd, timeout: options?.timeout }
487
+ const result = await gitPipe(
488
+ ["log", `-${scanDepth}`, "-p", ref],
489
+ ["patch-id", "--stable"],
490
+ { cwd: options?.cwd, timeout: options?.timeout ?? 6e4 }
449
491
  );
450
- const candidates = filter5(logResult.stdout.trim().split("\n"), isTruthy5);
451
- for (const candidateSha of candidates) {
452
- if (candidateSha === commitSha) continue;
453
- const candidatePatchId = await computePatchId(candidateSha, options);
454
- if (candidatePatchId && candidatePatchId === targetPatchId) {
492
+ const lines = filter5(result.stdout.trim().split("\n"), isTruthy5);
493
+ const cache = getCache(options?.repoId, options?.noCache);
494
+ for (const line of lines) {
495
+ const [patchId, candidateSha] = line.split(/\s+/);
496
+ if (!patchId || !candidateSha) continue;
497
+ await cache.set(candidateSha, patchId);
498
+ if (candidateSha !== commitSha && patchId === targetPatchId) {
455
499
  return { matchedSha: candidateSha, patchId: targetPatchId };
456
500
  }
457
501
  }
@@ -536,17 +580,6 @@ async function lookupPR(commitSha, adapter, options) {
536
580
  }
537
581
  }
538
582
  }
539
- const patchIdMatch = await findPatchIdMatch(commitSha, {
540
- ...options,
541
- scanDepth: options?.deep ? DEEP_SCAN_DEPTH : void 0
542
- });
543
- if (patchIdMatch) {
544
- const result = await lookupPR(patchIdMatch.matchedSha, adapter, options);
545
- if (result) {
546
- await cache.set(commitSha, result);
547
- return result;
548
- }
549
- }
550
583
  if (mergeBasedPR) {
551
584
  await cache.set(commitSha, mergeBasedPR);
552
585
  return mergeBasedPR;
@@ -558,6 +591,17 @@ async function lookupPR(commitSha, adapter, options) {
558
591
  return prInfo;
559
592
  }
560
593
  }
594
+ const patchIdMatch = await findPatchIdMatch(commitSha, {
595
+ ...options,
596
+ scanDepth: options?.deep ? DEEP_SCAN_DEPTH : void 0
597
+ });
598
+ if (patchIdMatch) {
599
+ const result = await lookupPR(patchIdMatch.matchedSha, adapter, options);
600
+ if (result) {
601
+ await cache.set(commitSha, result);
602
+ return result;
603
+ }
604
+ }
561
605
  return null;
562
606
  }
563
607
  function resetPRCache() {
@@ -593,7 +637,7 @@ var VERSION;
593
637
  var init_version = __esm({
594
638
  "src/version.ts"() {
595
639
  "use strict";
596
- VERSION = "0.0.4";
640
+ VERSION = "0.0.5";
597
641
  }
598
642
  });
599
643
 
@@ -1,3 +1,4 @@
1
1
  import type { GitExecOptions, GitExecResult } from '../types/index.js';
2
2
  export declare function gitExec(args: string[], options?: GitExecOptions): Promise<GitExecResult>;
3
+ export declare function gitPipe(producerArgs: string[], consumerArgs: string[], options?: GitExecOptions): Promise<GitExecResult>;
3
4
  export declare function shellExec(command: string, args: string[], options?: GitExecOptions): Promise<GitExecResult>;
@@ -1,3 +1,3 @@
1
- export { gitExec, shellExec } from './executor.js';
1
+ export { gitExec, gitPipe, shellExec } from './executor.js';
2
2
  export { detectPlatform, getRemoteInfo, parseRemoteUrl } from './remote.js';
3
3
  export { checkGitHealth } from './health.js';
package/dist/index.cjs CHANGED
@@ -317,6 +317,51 @@ async function gitExec(args, options) {
317
317
  LineLoreErrorCode.GIT_COMMAND_FAILED
318
318
  );
319
319
  }
320
+ async function gitPipe(producerArgs, consumerArgs, options) {
321
+ const { cwd, timeout } = options ?? {};
322
+ const pipeArgs = [...producerArgs, "|", ...consumerArgs];
323
+ try {
324
+ const result = await (0, import_execa.execa)("git", producerArgs, {
325
+ cwd,
326
+ timeout,
327
+ reject: false
328
+ }).pipe("git", consumerArgs, { cwd, timeout, reject: false });
329
+ const exitCode = result.exitCode ?? 0;
330
+ if (exitCode !== 0) {
331
+ throw new LineLoreError(
332
+ LineLoreErrorCode.GIT_COMMAND_FAILED,
333
+ `git pipe failed with exit code ${exitCode}: ${result.stderr}`,
334
+ {
335
+ command: "git",
336
+ args: pipeArgs,
337
+ exitCode,
338
+ stderr: result.stderr,
339
+ cwd
340
+ }
341
+ );
342
+ }
343
+ return {
344
+ stdout: result.stdout,
345
+ stderr: result.stderr,
346
+ exitCode
347
+ };
348
+ } catch (error) {
349
+ if (error instanceof LineLoreError) throw error;
350
+ const isTimeout = error instanceof Error && "isTerminated" in error && error.timedOut === true;
351
+ if (isTimeout) {
352
+ throw new LineLoreError(
353
+ LineLoreErrorCode.GIT_TIMEOUT,
354
+ `git pipe timed out after ${timeout}ms`,
355
+ { command: "git", args: pipeArgs, timeout, cwd }
356
+ );
357
+ }
358
+ throw new LineLoreError(
359
+ LineLoreErrorCode.GIT_COMMAND_FAILED,
360
+ `git pipe failed: ${error instanceof Error ? error.message : String(error)}`,
361
+ { command: "git", args: pipeArgs, cwd }
362
+ );
363
+ }
364
+ }
320
365
  async function shellExec(command, args, options) {
321
366
  return execCommand(
322
367
  command,
@@ -437,14 +482,10 @@ async function computePatchId(commitSha, options) {
437
482
  const cached = await cache.get(commitSha);
438
483
  if (cached) return cached;
439
484
  try {
440
- const cwd = options?.cwd ?? ".";
441
- const result = await shellExec(
442
- "bash",
443
- [
444
- "-c",
445
- `git -C "${cwd}" diff "${commitSha}^..${commitSha}" | git patch-id --stable`
446
- ],
447
- { timeout: options?.timeout }
485
+ const result = await gitPipe(
486
+ ["diff", `${commitSha}^..${commitSha}`],
487
+ ["patch-id", "--stable"],
488
+ { cwd: options?.cwd, timeout: options?.timeout }
448
489
  );
449
490
  const patchId = result.stdout.trim().split(/\s+/)[0];
450
491
  if (!patchId) return null;
@@ -460,15 +501,18 @@ async function findPatchIdMatch(commitSha, options) {
460
501
  const targetPatchId = await computePatchId(commitSha, options);
461
502
  if (!targetPatchId) return null;
462
503
  try {
463
- const logResult = await gitExec(
464
- ["log", "--format=%H", `-${scanDepth}`, ref],
465
- { cwd: options?.cwd, timeout: options?.timeout }
504
+ const result = await gitPipe(
505
+ ["log", `-${scanDepth}`, "-p", ref],
506
+ ["patch-id", "--stable"],
507
+ { cwd: options?.cwd, timeout: options?.timeout ?? 6e4 }
466
508
  );
467
- const candidates = (0, import_common_utils10.filter)(logResult.stdout.trim().split("\n"), import_common_utils10.isTruthy);
468
- for (const candidateSha of candidates) {
469
- if (candidateSha === commitSha) continue;
470
- const candidatePatchId = await computePatchId(candidateSha, options);
471
- if (candidatePatchId && candidatePatchId === targetPatchId) {
509
+ const lines = (0, import_common_utils10.filter)(result.stdout.trim().split("\n"), import_common_utils10.isTruthy);
510
+ const cache = getCache(options?.repoId, options?.noCache);
511
+ for (const line of lines) {
512
+ const [patchId, candidateSha] = line.split(/\s+/);
513
+ if (!patchId || !candidateSha) continue;
514
+ await cache.set(candidateSha, patchId);
515
+ if (candidateSha !== commitSha && patchId === targetPatchId) {
472
516
  return { matchedSha: candidateSha, patchId: targetPatchId };
473
517
  }
474
518
  }
@@ -556,17 +600,6 @@ async function lookupPR(commitSha, adapter, options) {
556
600
  }
557
601
  }
558
602
  }
559
- const patchIdMatch = await findPatchIdMatch(commitSha, {
560
- ...options,
561
- scanDepth: options?.deep ? DEEP_SCAN_DEPTH : void 0
562
- });
563
- if (patchIdMatch) {
564
- const result = await lookupPR(patchIdMatch.matchedSha, adapter, options);
565
- if (result) {
566
- await cache.set(commitSha, result);
567
- return result;
568
- }
569
- }
570
603
  if (mergeBasedPR) {
571
604
  await cache.set(commitSha, mergeBasedPR);
572
605
  return mergeBasedPR;
@@ -578,6 +611,17 @@ async function lookupPR(commitSha, adapter, options) {
578
611
  return prInfo;
579
612
  }
580
613
  }
614
+ const patchIdMatch = await findPatchIdMatch(commitSha, {
615
+ ...options,
616
+ scanDepth: options?.deep ? DEEP_SCAN_DEPTH : void 0
617
+ });
618
+ if (patchIdMatch) {
619
+ const result = await lookupPR(patchIdMatch.matchedSha, adapter, options);
620
+ if (result) {
621
+ await cache.set(commitSha, result);
622
+ return result;
623
+ }
624
+ }
581
625
  return null;
582
626
  }
583
627
  function resetPRCache() {
package/dist/index.mjs CHANGED
@@ -305,6 +305,51 @@ async function gitExec(args, options) {
305
305
  LineLoreErrorCode.GIT_COMMAND_FAILED
306
306
  );
307
307
  }
308
+ async function gitPipe(producerArgs, consumerArgs, options) {
309
+ const { cwd, timeout } = options ?? {};
310
+ const pipeArgs = [...producerArgs, "|", ...consumerArgs];
311
+ try {
312
+ const result = await execa("git", producerArgs, {
313
+ cwd,
314
+ timeout,
315
+ reject: false
316
+ }).pipe("git", consumerArgs, { cwd, timeout, reject: false });
317
+ const exitCode = result.exitCode ?? 0;
318
+ if (exitCode !== 0) {
319
+ throw new LineLoreError(
320
+ LineLoreErrorCode.GIT_COMMAND_FAILED,
321
+ `git pipe failed with exit code ${exitCode}: ${result.stderr}`,
322
+ {
323
+ command: "git",
324
+ args: pipeArgs,
325
+ exitCode,
326
+ stderr: result.stderr,
327
+ cwd
328
+ }
329
+ );
330
+ }
331
+ return {
332
+ stdout: result.stdout,
333
+ stderr: result.stderr,
334
+ exitCode
335
+ };
336
+ } catch (error) {
337
+ if (error instanceof LineLoreError) throw error;
338
+ const isTimeout = error instanceof Error && "isTerminated" in error && error.timedOut === true;
339
+ if (isTimeout) {
340
+ throw new LineLoreError(
341
+ LineLoreErrorCode.GIT_TIMEOUT,
342
+ `git pipe timed out after ${timeout}ms`,
343
+ { command: "git", args: pipeArgs, timeout, cwd }
344
+ );
345
+ }
346
+ throw new LineLoreError(
347
+ LineLoreErrorCode.GIT_COMMAND_FAILED,
348
+ `git pipe failed: ${error instanceof Error ? error.message : String(error)}`,
349
+ { command: "git", args: pipeArgs, cwd }
350
+ );
351
+ }
352
+ }
308
353
  async function shellExec(command, args, options) {
309
354
  return execCommand(
310
355
  command,
@@ -423,14 +468,10 @@ async function computePatchId(commitSha, options) {
423
468
  const cached = await cache.get(commitSha);
424
469
  if (cached) return cached;
425
470
  try {
426
- const cwd = options?.cwd ?? ".";
427
- const result = await shellExec(
428
- "bash",
429
- [
430
- "-c",
431
- `git -C "${cwd}" diff "${commitSha}^..${commitSha}" | git patch-id --stable`
432
- ],
433
- { timeout: options?.timeout }
471
+ const result = await gitPipe(
472
+ ["diff", `${commitSha}^..${commitSha}`],
473
+ ["patch-id", "--stable"],
474
+ { cwd: options?.cwd, timeout: options?.timeout }
434
475
  );
435
476
  const patchId = result.stdout.trim().split(/\s+/)[0];
436
477
  if (!patchId) return null;
@@ -446,15 +487,18 @@ async function findPatchIdMatch(commitSha, options) {
446
487
  const targetPatchId = await computePatchId(commitSha, options);
447
488
  if (!targetPatchId) return null;
448
489
  try {
449
- const logResult = await gitExec(
450
- ["log", "--format=%H", `-${scanDepth}`, ref],
451
- { cwd: options?.cwd, timeout: options?.timeout }
490
+ const result = await gitPipe(
491
+ ["log", `-${scanDepth}`, "-p", ref],
492
+ ["patch-id", "--stable"],
493
+ { cwd: options?.cwd, timeout: options?.timeout ?? 6e4 }
452
494
  );
453
- const candidates = filter5(logResult.stdout.trim().split("\n"), isTruthy5);
454
- for (const candidateSha of candidates) {
455
- if (candidateSha === commitSha) continue;
456
- const candidatePatchId = await computePatchId(candidateSha, options);
457
- if (candidatePatchId && candidatePatchId === targetPatchId) {
495
+ const lines = filter5(result.stdout.trim().split("\n"), isTruthy5);
496
+ const cache = getCache(options?.repoId, options?.noCache);
497
+ for (const line of lines) {
498
+ const [patchId, candidateSha] = line.split(/\s+/);
499
+ if (!patchId || !candidateSha) continue;
500
+ await cache.set(candidateSha, patchId);
501
+ if (candidateSha !== commitSha && patchId === targetPatchId) {
458
502
  return { matchedSha: candidateSha, patchId: targetPatchId };
459
503
  }
460
504
  }
@@ -541,17 +585,6 @@ async function lookupPR(commitSha, adapter, options) {
541
585
  }
542
586
  }
543
587
  }
544
- const patchIdMatch = await findPatchIdMatch(commitSha, {
545
- ...options,
546
- scanDepth: options?.deep ? DEEP_SCAN_DEPTH : void 0
547
- });
548
- if (patchIdMatch) {
549
- const result = await lookupPR(patchIdMatch.matchedSha, adapter, options);
550
- if (result) {
551
- await cache.set(commitSha, result);
552
- return result;
553
- }
554
- }
555
588
  if (mergeBasedPR) {
556
589
  await cache.set(commitSha, mergeBasedPR);
557
590
  return mergeBasedPR;
@@ -563,6 +596,17 @@ async function lookupPR(commitSha, adapter, options) {
563
596
  return prInfo;
564
597
  }
565
598
  }
599
+ const patchIdMatch = await findPatchIdMatch(commitSha, {
600
+ ...options,
601
+ scanDepth: options?.deep ? DEEP_SCAN_DEPTH : void 0
602
+ });
603
+ if (patchIdMatch) {
604
+ const result = await lookupPR(patchIdMatch.matchedSha, adapter, options);
605
+ if (result) {
606
+ await cache.set(commitSha, result);
607
+ return result;
608
+ }
609
+ }
566
610
  return null;
567
611
  }
568
612
  function resetPRCache() {
package/dist/version.d.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * Current package version from package.json
3
3
  * Automatically synchronized during build process
4
4
  */
5
- export declare const VERSION = "0.0.4";
5
+ export declare const VERSION = "0.0.5";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumy-pack/line-lore",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "CLI tool for tracing code lines to their originating Pull Requests via git blame",
5
5
  "keywords": [
6
6
  "cli",