edsger 0.30.2 → 0.30.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.
@@ -1,5 +1,6 @@
1
- import { execSync } from 'child_process';
1
+ import { execSync, execFileSync } from 'child_process';
2
2
  import { logInfo, logError } from '../../utils/logger.js';
3
+ import { buildCredentialArgs } from '../../utils/git-push.js';
3
4
  import { getFeature } from '../../api/features/index.js';
4
5
  import { getPullRequests, } from '../../services/pull-requests.js';
5
6
  import { getGitHubConfig } from '../../api/github.js';
@@ -76,26 +77,26 @@ export async function fetchPRExecutionContext(featureId, verbose) {
76
77
  throw new Error(`Development branch '${devBranchName}' does not exist. ` +
77
78
  `The feature must have code on the dev branch before PR execution.`);
78
79
  }
79
- // If branch only exists on remote, fetch it
80
+ // Fetch GitHub config and data in parallel
81
+ const [feature, pullRequests, githubConfig] = await Promise.all([
82
+ getFeature(featureId, verbose),
83
+ getPullRequests({ featureId, verbose }),
84
+ getGitHubConfig(featureId, verbose),
85
+ ]);
86
+ // If branch only exists on remote, fetch it (using credential helper)
80
87
  if (!localExists && remoteExists) {
81
88
  if (verbose) {
82
89
  logInfo(`Fetching remote branch ${devBranchName}...`);
83
90
  }
84
- execSync(`git fetch origin ${devBranchName}`, {
91
+ const credArgs = buildCredentialArgs(githubConfig.token);
92
+ execFileSync('git', [...credArgs, 'fetch', 'origin', devBranchName], {
85
93
  encoding: 'utf-8',
86
94
  stdio: 'pipe',
87
95
  });
88
96
  }
89
- // Fetch data in parallel
90
- const [feature, pullRequests] = await Promise.all([
91
- getFeature(featureId, verbose),
92
- getPullRequests({ featureId, verbose }),
93
- ]);
94
97
  if (pullRequests.length === 0) {
95
98
  throw new Error('No PR plan found. Run the pr-splitting phase first to create a PR plan.');
96
99
  }
97
- // Fetch GitHub config
98
- const githubConfig = await getGitHubConfig(featureId, verbose);
99
100
  if (!githubConfig.configured) {
100
101
  throw new Error(`GitHub is not configured. ${githubConfig.message || 'Please configure GitHub integration.'}`);
101
102
  }
@@ -1,5 +1,6 @@
1
- import { execSync } from 'child_process';
1
+ import { execSync, execFileSync } from 'child_process';
2
2
  import { logInfo, logError } from '../../utils/logger.js';
3
+ import { buildCredentialArgs } from '../../utils/git-push.js';
3
4
  import { getFeature } from '../../api/features/index.js';
4
5
  import { getProduct } from '../../api/products.js';
5
6
  import { getBranches } from '../../services/branches.js';
@@ -82,25 +83,25 @@ export async function fetchPRSplittingContext(featureId, verbose, replaceExistin
82
83
  throw new Error(`Development branch '${devBranchName}' does not exist. ` +
83
84
  `The feature must have code on the dev branch before PR splitting.`);
84
85
  }
85
- // If branch only exists on remote, fetch it
86
+ // Fetch database data and GitHub config in parallel
87
+ const [feature, existing_branches, existing_pull_requests, githubConfig] = await Promise.all([
88
+ getFeature(featureId, verbose),
89
+ getBranches({ featureId, verbose }).catch(() => []),
90
+ getPullRequests({ featureId, verbose }).catch(() => []),
91
+ getGitHubConfig(featureId, verbose),
92
+ ]);
93
+ // If branch only exists on remote, fetch it (using credential helper)
86
94
  if (!localExists && remoteExists) {
87
95
  if (verbose) {
88
96
  logInfo(`Fetching remote branch ${devBranchName}...`);
89
97
  }
90
- execSync(`git fetch origin ${devBranchName}`, {
98
+ const credArgs = buildCredentialArgs(githubConfig.token);
99
+ execFileSync('git', [...credArgs, 'fetch', 'origin', devBranchName], {
91
100
  encoding: 'utf-8',
92
101
  stdio: 'pipe',
93
102
  });
94
103
  }
95
- // Fetch database data in parallel
96
- const [feature, existing_branches, existing_pull_requests] = await Promise.all([
97
- getFeature(featureId, verbose),
98
- getBranches({ featureId, verbose }).catch(() => []),
99
- getPullRequests({ featureId, verbose }).catch(() => []),
100
- ]);
101
104
  const product = await getProduct(feature.product_id, verbose);
102
- // Fetch GitHub config
103
- const githubConfig = await getGitHubConfig(featureId, verbose);
104
105
  // Detect fork status
105
106
  let forkInfo = { isFork: false };
106
107
  if (githubConfig.configured && githubConfig.token && githubConfig.owner && githubConfig.repo) {
@@ -67,7 +67,7 @@ export declare function branchExists(branch: string): boolean;
67
67
  /**
68
68
  * Check if a remote branch exists
69
69
  */
70
- export declare function remoteBranchExists(branch: string): boolean;
70
+ export declare function remoteBranchExists(branch: string, githubToken?: string): boolean;
71
71
  /**
72
72
  * Options for switchToBranch
73
73
  */
@@ -79,6 +79,8 @@ export interface SwitchToBranchOptions {
79
79
  * Set this to true to skip the remote check (useful for well-known local branches like 'main').
80
80
  */
81
81
  skipRemoteCheck?: boolean;
82
+ /** GitHub App installation token for authenticated remote operations */
83
+ githubToken?: string;
82
84
  }
83
85
  /**
84
86
  * Switch to a specific Git branch, creating it if it doesn't exist
@@ -99,7 +101,7 @@ export declare function switchToBranch(branch: string, verbose?: boolean, option
99
101
  /**
100
102
  * Pull latest changes from remote for a specific branch
101
103
  */
102
- export declare function pullLatestFromBranch(branch: string, verbose?: boolean): void;
104
+ export declare function pullLatestFromBranch(branch: string, verbose?: boolean, githubToken?: string): void;
103
105
  /**
104
106
  * Switch to feature branch and rebase with main
105
107
  * This should be called at the START of each phase
@@ -109,7 +111,7 @@ export declare function pullLatestFromBranch(branch: string, verbose?: boolean):
109
111
  * @param verbose - Whether to log verbose output
110
112
  * @returns Object containing the previous branch name
111
113
  */
112
- export declare function switchToFeatureBranchAndRebase(featureBranch: string, baseBranch?: string, verbose?: boolean): {
114
+ export declare function switchToFeatureBranchAndRebase(featureBranch: string, baseBranch?: string, verbose?: boolean, githubToken?: string): {
113
115
  previousBranch: string;
114
116
  };
115
117
  /**
@@ -2,12 +2,12 @@
2
2
  * Git Branch Manager
3
3
  * Shared utilities for consistent git branch management across all phases
4
4
  */
5
- import { execSync } from 'child_process';
5
+ import { execSync, execFileSync } from 'child_process';
6
6
  import * as fs from 'fs';
7
7
  import * as path from 'path';
8
8
  import { Octokit } from '@octokit/rest';
9
9
  import { logInfo, logError } from './logger.js';
10
- import { gitForcePush } from './git-push.js';
10
+ import { gitForcePush, buildCredentialArgs } from './git-push.js';
11
11
  /**
12
12
  * Get current Git branch name
13
13
  */
@@ -225,10 +225,11 @@ export function branchExists(branch) {
225
225
  /**
226
226
  * Check if a remote branch exists
227
227
  */
228
- export function remoteBranchExists(branch) {
228
+ export function remoteBranchExists(branch, githubToken) {
229
229
  try {
230
230
  // Fetch remote refs first to ensure we have latest info
231
- execSync('git fetch origin --prune', { encoding: 'utf-8', stdio: 'pipe' });
231
+ const credArgs = buildCredentialArgs(githubToken);
232
+ execFileSync('git', [...credArgs, 'fetch', 'origin', '--prune'], { encoding: 'utf-8', stdio: 'pipe' });
232
233
  execSync(`git rev-parse --verify origin/${branch}`, {
233
234
  encoding: 'utf-8',
234
235
  stdio: 'pipe',
@@ -280,7 +281,8 @@ export function switchToBranch(branch, verbose, options) {
280
281
  // This handles multi-clone scenarios where branch was pushed from another clone
281
282
  try {
282
283
  // Fetch to get latest remote refs
283
- execSync('git fetch origin', { encoding: 'utf-8', stdio: 'pipe' });
284
+ const switchCredArgs = buildCredentialArgs(options?.githubToken);
285
+ execFileSync('git', [...switchCredArgs, 'fetch', 'origin'], { encoding: 'utf-8', stdio: 'pipe' });
284
286
  // Check if remote branch exists
285
287
  execSync(`git rev-parse --verify origin/${branch}`, {
286
288
  encoding: 'utf-8',
@@ -317,7 +319,7 @@ export function switchToBranch(branch, verbose, options) {
317
319
  /**
318
320
  * Pull latest changes from remote for a specific branch
319
321
  */
320
- export function pullLatestFromBranch(branch, verbose) {
322
+ export function pullLatestFromBranch(branch, verbose, githubToken) {
321
323
  try {
322
324
  // Check for uncommitted changes and reset if found
323
325
  if (hasUncommittedChanges()) {
@@ -329,7 +331,8 @@ export function pullLatestFromBranch(branch, verbose) {
329
331
  if (verbose) {
330
332
  logInfo(`šŸ“„ Pulling latest changes from origin/${branch}...`);
331
333
  }
332
- execSync(`git pull origin ${branch} --rebase`, {
334
+ const credArgs = buildCredentialArgs(githubToken);
335
+ execFileSync('git', [...credArgs, 'pull', 'origin', branch, '--rebase'], {
333
336
  encoding: 'utf-8',
334
337
  stdio: verbose ? 'inherit' : 'pipe',
335
338
  });
@@ -350,7 +353,7 @@ export function pullLatestFromBranch(branch, verbose) {
350
353
  * @param verbose - Whether to log verbose output
351
354
  * @returns Object containing the previous branch name
352
355
  */
353
- export function switchToFeatureBranchAndRebase(featureBranch, baseBranch = 'main', verbose) {
356
+ export function switchToFeatureBranchAndRebase(featureBranch, baseBranch = 'main', verbose, githubToken) {
354
357
  const previousBranch = getCurrentBranch();
355
358
  if (verbose) {
356
359
  logInfo(`\nšŸ”„ Preparing feature branch: ${featureBranch}`);
@@ -373,7 +376,7 @@ export function switchToFeatureBranchAndRebase(featureBranch, baseBranch = 'main
373
376
  if (verbose) {
374
377
  logInfo(` Pulling latest ${baseBranch}...`);
375
378
  }
376
- pullLatestFromBranch(baseBranch, verbose);
379
+ pullLatestFromBranch(baseBranch, verbose, githubToken);
377
380
  }
378
381
  catch (error) {
379
382
  if (verbose) {
@@ -397,7 +400,8 @@ export function switchToFeatureBranchAndRebase(featureBranch, baseBranch = 'main
397
400
  resetUncommittedChanges(verbose);
398
401
  }
399
402
  // Fetch to get latest remote state (may have been fetched in switchToBranch, but ensures fresh data)
400
- execSync('git fetch origin', { encoding: 'utf-8', stdio: 'pipe' });
403
+ const credArgs = buildCredentialArgs(githubToken);
404
+ execFileSync('git', [...credArgs, 'fetch', 'origin'], { encoding: 'utf-8', stdio: 'pipe' });
401
405
  // Check if remote feature branch exists
402
406
  try {
403
407
  execSync(`git rev-parse --verify origin/${featureBranch}`, {
@@ -459,7 +463,8 @@ export function switchToFeatureBranchAndRebase(featureBranch, baseBranch = 'main
459
463
  }
460
464
  resetUncommittedChanges(verbose);
461
465
  }
462
- execSync(`git pull origin ${baseBranch} --rebase`, {
466
+ const rebaseCredArgs = buildCredentialArgs(githubToken);
467
+ execFileSync('git', [...rebaseCredArgs, 'pull', 'origin', baseBranch, '--rebase'], {
463
468
  encoding: 'utf-8',
464
469
  stdio: verbose ? 'inherit' : 'pipe',
465
470
  });
@@ -716,7 +721,7 @@ export async function switchToFeatureBranchAndRebaseAsync(options) {
716
721
  if (verbose) {
717
722
  logInfo(` Pulling latest ${baseBranch}...`);
718
723
  }
719
- pullLatestFromBranch(baseBranch, verbose);
724
+ pullLatestFromBranch(baseBranch, verbose, githubToken);
720
725
  }
721
726
  catch (error) {
722
727
  if (verbose) {
@@ -739,7 +744,8 @@ export async function switchToFeatureBranchAndRebaseAsync(options) {
739
744
  resetUncommittedChanges(verbose);
740
745
  }
741
746
  // Fetch to get latest remote state (may have been fetched in switchToBranch, but ensures fresh data)
742
- execSync('git fetch origin', { encoding: 'utf-8', stdio: 'pipe' });
747
+ const syncCredArgs = buildCredentialArgs(githubToken);
748
+ execFileSync('git', [...syncCredArgs, 'fetch', 'origin'], { encoding: 'utf-8', stdio: 'pipe' });
743
749
  try {
744
750
  execSync(`git rev-parse --verify origin/${featureBranch}`, {
745
751
  encoding: 'utf-8',
@@ -802,7 +808,8 @@ export async function switchToFeatureBranchAndRebaseAsync(options) {
802
808
  resetUncommittedChanges(verbose);
803
809
  }
804
810
  // Fetch the target branch first
805
- execSync(`git fetch origin ${actualRebaseTarget}`, {
811
+ const fetchCredArgs = buildCredentialArgs(githubToken);
812
+ execFileSync('git', [...fetchCredArgs, 'fetch', 'origin', actualRebaseTarget], {
806
813
  encoding: 'utf-8',
807
814
  stdio: 'pipe',
808
815
  });
@@ -812,7 +819,7 @@ export async function switchToFeatureBranchAndRebaseAsync(options) {
812
819
  // Command: git rebase --onto <new-base> <old-base>
813
820
  // This rebases commits from <old-base>..HEAD onto <new-base>
814
821
  // Also fetch the originalBaseBranch for the --onto reference
815
- execSync(`git fetch origin ${originalBaseBranch}`, {
822
+ execFileSync('git', [...fetchCredArgs, 'fetch', 'origin', originalBaseBranch], {
816
823
  encoding: 'utf-8',
817
824
  stdio: 'pipe',
818
825
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edsger",
3
- "version": "0.30.2",
3
+ "version": "0.30.3",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "edsger": "dist/index.js"