edsger 0.13.2 → 0.13.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.
|
@@ -8,7 +8,9 @@ import { execSync } from 'child_process';
|
|
|
8
8
|
import { fetchCodeRefineContext, } from './context.js';
|
|
9
9
|
import { getFeedbacksForPhase, formatFeedbacksForContext, } from '../../services/feedbacks.js';
|
|
10
10
|
import { createSystemPrompt, createCodeRefinePrompt } from './prompts.js';
|
|
11
|
-
import { preparePhaseGitEnvironment, hasUncommittedChanges, getUncommittedFiles, } from '../../utils/git-branch-manager.js';
|
|
11
|
+
import { preparePhaseGitEnvironment, hasUncommittedChanges, getUncommittedFiles, syncFeatBranchWithMain, } from '../../utils/git-branch-manager.js';
|
|
12
|
+
import { getFeature } from '../../api/features/get-feature.js';
|
|
13
|
+
import { parsePullRequestUrl } from './context.js';
|
|
12
14
|
function userMessage(content) {
|
|
13
15
|
return {
|
|
14
16
|
type: 'user',
|
|
@@ -62,6 +64,23 @@ export const refineCodeFromPRFeedback = async (options, config) => {
|
|
|
62
64
|
if (verbose) {
|
|
63
65
|
logInfo(`Starting code refine for feature ID: ${featureId}`);
|
|
64
66
|
}
|
|
67
|
+
// Sync feat branch with main before preparing git environment
|
|
68
|
+
// This prevents extra commits from appearing in PR when dev branch is rebased
|
|
69
|
+
try {
|
|
70
|
+
const feature = await getFeature(featureId, verbose);
|
|
71
|
+
if (feature.pull_request_url) {
|
|
72
|
+
const prInfo = parsePullRequestUrl(feature.pull_request_url);
|
|
73
|
+
if (prInfo) {
|
|
74
|
+
await syncFeatBranchWithMain(featureId, githubToken, prInfo.owner, prInfo.repo, 'main', verbose);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (verbose) {
|
|
80
|
+
logInfo(`⚠️ Could not sync feat branch: ${error instanceof Error ? error.message : String(error)}`);
|
|
81
|
+
}
|
|
82
|
+
// Continue even if sync fails - it's not critical
|
|
83
|
+
}
|
|
65
84
|
// Prepare git environment: switch to feature branch and rebase with main
|
|
66
85
|
const cleanupGit = preparePhaseGitEnvironment(featureId, 'main', verbose);
|
|
67
86
|
try {
|
|
@@ -71,3 +71,16 @@ export declare function returnToMainBranch(baseBranch?: string, verbose?: boolea
|
|
|
71
71
|
* @returns Cleanup function that will return to main branch
|
|
72
72
|
*/
|
|
73
73
|
export declare function preparePhaseGitEnvironment(featureId: string, baseBranch?: string, verbose?: boolean): () => void;
|
|
74
|
+
/**
|
|
75
|
+
* Sync feat branch with main using GitHub API
|
|
76
|
+
* This ensures the feat branch (PR base) is up to date with main,
|
|
77
|
+
* preventing extra commits from appearing in PRs when dev branch is rebased.
|
|
78
|
+
*
|
|
79
|
+
* @param featureId - The feature ID (will be used to construct branch name "feat/{featureId}")
|
|
80
|
+
* @param githubToken - GitHub personal access token or app token
|
|
81
|
+
* @param owner - Repository owner
|
|
82
|
+
* @param repo - Repository name
|
|
83
|
+
* @param baseBranch - The base branch to sync from (default: "main")
|
|
84
|
+
* @param verbose - Whether to log verbose output
|
|
85
|
+
*/
|
|
86
|
+
export declare function syncFeatBranchWithMain(featureId: string, githubToken: string, owner: string, repo: string, baseBranch?: string, verbose?: boolean): Promise<boolean>;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Shared utilities for consistent git branch management across all phases
|
|
4
4
|
*/
|
|
5
5
|
import { execSync } from 'child_process';
|
|
6
|
+
import { Octokit } from '@octokit/rest';
|
|
6
7
|
import { logInfo, logError } from './logger.js';
|
|
7
8
|
/**
|
|
8
9
|
* Get current Git branch name
|
|
@@ -358,3 +359,100 @@ export function preparePhaseGitEnvironment(featureId, baseBranch = 'main', verbo
|
|
|
358
359
|
// Return cleanup function
|
|
359
360
|
return cleanup;
|
|
360
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* Sync feat branch with main using GitHub API
|
|
364
|
+
* This ensures the feat branch (PR base) is up to date with main,
|
|
365
|
+
* preventing extra commits from appearing in PRs when dev branch is rebased.
|
|
366
|
+
*
|
|
367
|
+
* @param featureId - The feature ID (will be used to construct branch name "feat/{featureId}")
|
|
368
|
+
* @param githubToken - GitHub personal access token or app token
|
|
369
|
+
* @param owner - Repository owner
|
|
370
|
+
* @param repo - Repository name
|
|
371
|
+
* @param baseBranch - The base branch to sync from (default: "main")
|
|
372
|
+
* @param verbose - Whether to log verbose output
|
|
373
|
+
*/
|
|
374
|
+
export async function syncFeatBranchWithMain(featureId, githubToken, owner, repo, baseBranch = 'main', verbose) {
|
|
375
|
+
const featBranch = `feat/${featureId}`;
|
|
376
|
+
try {
|
|
377
|
+
const octokit = new Octokit({ auth: githubToken });
|
|
378
|
+
// Check if feat branch exists
|
|
379
|
+
if (verbose) {
|
|
380
|
+
logInfo(`🔍 Checking if ${featBranch} branch exists...`);
|
|
381
|
+
}
|
|
382
|
+
try {
|
|
383
|
+
await octokit.repos.getBranch({
|
|
384
|
+
owner,
|
|
385
|
+
repo,
|
|
386
|
+
branch: featBranch,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
catch (error) {
|
|
390
|
+
if (error.status === 404) {
|
|
391
|
+
if (verbose) {
|
|
392
|
+
logInfo(`ℹ️ ${featBranch} branch does not exist, skipping sync`);
|
|
393
|
+
}
|
|
394
|
+
return true; // Not an error, just no feat branch yet
|
|
395
|
+
}
|
|
396
|
+
throw error;
|
|
397
|
+
}
|
|
398
|
+
// Get the latest SHA of the base branch
|
|
399
|
+
const { data: baseBranchData } = await octokit.repos.getBranch({
|
|
400
|
+
owner,
|
|
401
|
+
repo,
|
|
402
|
+
branch: baseBranch,
|
|
403
|
+
});
|
|
404
|
+
const mainSha = baseBranchData.commit.sha;
|
|
405
|
+
// Get the current SHA of the feat branch
|
|
406
|
+
const { data: featBranchData } = await octokit.repos.getBranch({
|
|
407
|
+
owner,
|
|
408
|
+
repo,
|
|
409
|
+
branch: featBranch,
|
|
410
|
+
});
|
|
411
|
+
const featSha = featBranchData.commit.sha;
|
|
412
|
+
// Check if feat branch is already up to date (same as main or ahead)
|
|
413
|
+
// We need to merge main into feat to keep it updated
|
|
414
|
+
if (verbose) {
|
|
415
|
+
logInfo(`📥 Syncing ${featBranch} with ${baseBranch}...`);
|
|
416
|
+
logInfo(` ${baseBranch} SHA: ${mainSha.substring(0, 7)}`);
|
|
417
|
+
logInfo(` ${featBranch} SHA: ${featSha.substring(0, 7)}`);
|
|
418
|
+
}
|
|
419
|
+
// Use GitHub merge API to merge main into feat branch
|
|
420
|
+
try {
|
|
421
|
+
await octokit.repos.merge({
|
|
422
|
+
owner,
|
|
423
|
+
repo,
|
|
424
|
+
base: featBranch,
|
|
425
|
+
head: baseBranch,
|
|
426
|
+
commit_message: `chore: sync ${featBranch} with ${baseBranch}`,
|
|
427
|
+
});
|
|
428
|
+
if (verbose) {
|
|
429
|
+
logInfo(`✅ Successfully synced ${featBranch} with ${baseBranch}`);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
catch (mergeError) {
|
|
433
|
+
// 409 means nothing to merge (already up to date)
|
|
434
|
+
if (mergeError.status === 409) {
|
|
435
|
+
if (verbose) {
|
|
436
|
+
logInfo(`ℹ️ ${featBranch} is already up to date with ${baseBranch}`);
|
|
437
|
+
}
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
// 404 means branch doesn't exist (shouldn't happen since we checked above)
|
|
441
|
+
if (mergeError.status === 404) {
|
|
442
|
+
if (verbose) {
|
|
443
|
+
logInfo(`ℹ️ ${featBranch} branch not found, skipping sync`);
|
|
444
|
+
}
|
|
445
|
+
return true;
|
|
446
|
+
}
|
|
447
|
+
throw mergeError;
|
|
448
|
+
}
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
catch (error) {
|
|
452
|
+
if (verbose) {
|
|
453
|
+
logError(`⚠️ Failed to sync ${featBranch} with ${baseBranch}: ${error instanceof Error ? error.message : String(error)}`);
|
|
454
|
+
}
|
|
455
|
+
// Don't fail the whole process if sync fails, just log warning
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
}
|