edsger 0.21.7 ā 0.21.8
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/phases/code-implementation/index.js +8 -2
- package/dist/phases/code-refine/index.js +6 -1
- package/dist/phases/code-review/index.js +6 -1
- package/dist/services/branches.d.ts +5 -3
- package/dist/services/branches.js +8 -6
- package/dist/utils/git-branch-manager.d.ts +12 -1
- package/dist/utils/git-branch-manager.js +20 -12
- package/package.json +1 -1
|
@@ -114,6 +114,7 @@ export const implementFeatureCode = async (options, config, checklistContext) =>
|
|
|
114
114
|
// Determine the actual base branch for branch chaining
|
|
115
115
|
// If the current feature branch depends on another branch, use that as the base
|
|
116
116
|
let actualBaseBranch = baseBranch;
|
|
117
|
+
let rebaseTargetBranch;
|
|
117
118
|
let originalBaseBranch;
|
|
118
119
|
if (currentBranch && currentBranch.base_branch_id) {
|
|
119
120
|
try {
|
|
@@ -123,11 +124,15 @@ export const implementFeatureCode = async (options, config, checklistContext) =>
|
|
|
123
124
|
});
|
|
124
125
|
const baseBranchInfo = await getBaseBranchInfo(currentBranch, allBranches, baseBranch);
|
|
125
126
|
actualBaseBranch = baseBranchInfo.baseBranch;
|
|
127
|
+
rebaseTargetBranch = baseBranchInfo.rebaseTargetBranch;
|
|
126
128
|
originalBaseBranch = baseBranchInfo.originalBaseBranch;
|
|
127
129
|
if (verbose) {
|
|
128
130
|
logInfo(`š Branch chaining detected:`);
|
|
129
131
|
logInfo(` Current branch: ${currentBranch.name}`);
|
|
130
|
-
logInfo(` Base branch: ${actualBaseBranch}`);
|
|
132
|
+
logInfo(` Base branch (for new branches): ${actualBaseBranch}`);
|
|
133
|
+
if (rebaseTargetBranch) {
|
|
134
|
+
logInfo(` Rebase target: ${rebaseTargetBranch}`);
|
|
135
|
+
}
|
|
131
136
|
if (originalBaseBranch) {
|
|
132
137
|
logInfo(` Original base branch: ${originalBaseBranch} (for --onto rebase)`);
|
|
133
138
|
}
|
|
@@ -183,7 +188,8 @@ export const implementFeatureCode = async (options, config, checklistContext) =>
|
|
|
183
188
|
const { cleanup: cleanupGit } = await prepareCustomBranchGitEnvironmentAsync({
|
|
184
189
|
featureBranch: devBranchName,
|
|
185
190
|
baseBranch: actualBaseBranch,
|
|
186
|
-
|
|
191
|
+
rebaseTargetBranch, // For --onto rebase target (e.g., main) when base branch is merged
|
|
192
|
+
originalBaseBranch, // For --onto rebase starting point when base branch was squash-merged
|
|
187
193
|
verbose,
|
|
188
194
|
forcePushAfterRebase: featSyncedToMain, // Trigger GitHub to recalculate PR diff
|
|
189
195
|
});
|
|
@@ -76,6 +76,7 @@ export const refineCodeFromPRFeedback = async (options, config) => {
|
|
|
76
76
|
let currentBranch = null;
|
|
77
77
|
let allBranches = [];
|
|
78
78
|
let baseBranchForRebase = 'main'; // Default base branch for rebase
|
|
79
|
+
let rebaseTargetBranchForRebase; // Target for --onto rebase (e.g., main)
|
|
79
80
|
let originalBaseBranchForRebase; // For --onto when base was squash-merged
|
|
80
81
|
try {
|
|
81
82
|
// Get all branches to determine base branch info
|
|
@@ -92,9 +93,12 @@ export const refineCodeFromPRFeedback = async (options, config) => {
|
|
|
92
93
|
const baseBranchInfo = await getBaseBranchInfo(currentBranch, allBranches, 'main');
|
|
93
94
|
// Always use the baseBranch from getBaseBranchInfo - it handles all cases:
|
|
94
95
|
// - No base branch: returns 'main'
|
|
95
|
-
// - Base branch merged: returns feat branch (
|
|
96
|
+
// - Base branch merged: returns feat branch (new branches created from feat/xxx)
|
|
97
|
+
// - Base branch completed: returns main
|
|
96
98
|
// - Base branch not merged: returns dev branch
|
|
97
99
|
baseBranchForRebase = baseBranchInfo.baseBranch;
|
|
100
|
+
// When base branch is merged, rebaseTargetBranch is 'main' (target for --onto)
|
|
101
|
+
rebaseTargetBranchForRebase = baseBranchInfo.rebaseTargetBranch;
|
|
98
102
|
// When base branch is merged (squash merge), we need originalBaseBranch for --onto
|
|
99
103
|
originalBaseBranchForRebase = baseBranchInfo.originalBaseBranch;
|
|
100
104
|
if (verbose) {
|
|
@@ -162,6 +166,7 @@ export const refineCodeFromPRFeedback = async (options, config) => {
|
|
|
162
166
|
? await prepareCustomBranchGitEnvironmentAsync({
|
|
163
167
|
featureBranch: branchName,
|
|
164
168
|
baseBranch: baseBranchForRebase,
|
|
169
|
+
rebaseTargetBranch: rebaseTargetBranchForRebase,
|
|
165
170
|
originalBaseBranch: originalBaseBranchForRebase,
|
|
166
171
|
verbose,
|
|
167
172
|
resolveConflicts: true,
|
|
@@ -128,6 +128,7 @@ export const reviewPullRequest = async (options, config) => {
|
|
|
128
128
|
let currentBranch = null;
|
|
129
129
|
let allBranches = [];
|
|
130
130
|
let baseBranchForRebase = 'main'; // Default base branch for rebase
|
|
131
|
+
let rebaseTargetBranchForRebase; // Target for --onto rebase (e.g., main)
|
|
131
132
|
let originalBaseBranchForRebase; // For --onto when base was squash-merged
|
|
132
133
|
try {
|
|
133
134
|
// Get all branches to determine base branch info
|
|
@@ -145,9 +146,12 @@ export const reviewPullRequest = async (options, config) => {
|
|
|
145
146
|
const baseBranchInfo = await getBaseBranchInfo(currentBranch, allBranches, 'main');
|
|
146
147
|
// Always use the baseBranch from getBaseBranchInfo - it handles all cases:
|
|
147
148
|
// - No base branch: returns 'main'
|
|
148
|
-
// - Base branch merged: returns feat branch (
|
|
149
|
+
// - Base branch merged: returns feat branch (new branches created from feat/xxx)
|
|
150
|
+
// - Base branch completed: returns main
|
|
149
151
|
// - Base branch not merged: returns dev branch
|
|
150
152
|
baseBranchForRebase = baseBranchInfo.baseBranch;
|
|
153
|
+
// When base branch is merged, rebaseTargetBranch is 'main' (target for --onto)
|
|
154
|
+
rebaseTargetBranchForRebase = baseBranchInfo.rebaseTargetBranch;
|
|
151
155
|
// When base branch is merged (squash merge), we need originalBaseBranch for --onto
|
|
152
156
|
originalBaseBranchForRebase = baseBranchInfo.originalBaseBranch;
|
|
153
157
|
if (verbose) {
|
|
@@ -215,6 +219,7 @@ export const reviewPullRequest = async (options, config) => {
|
|
|
215
219
|
? await prepareCustomBranchGitEnvironmentAsync({
|
|
216
220
|
featureBranch: branchName,
|
|
217
221
|
baseBranch: baseBranchForRebase,
|
|
222
|
+
rebaseTargetBranch: rebaseTargetBranchForRebase,
|
|
218
223
|
originalBaseBranch: originalBaseBranchForRebase,
|
|
219
224
|
verbose,
|
|
220
225
|
resolveConflicts: true,
|
|
@@ -65,14 +65,16 @@ export declare function allBranchesCompleted(options: PipelinePhaseOptions): Pro
|
|
|
65
65
|
* Rebase strategies based on base branch status:
|
|
66
66
|
* - no base_branch_id: git rebase main (first branch in chain)
|
|
67
67
|
* - completed (feat merged to main): git rebase main
|
|
68
|
-
* - merged (dev merged to feat): git rebase --onto main feat/xxx
|
|
68
|
+
* - merged (dev merged to feat): create from feat/xxx, then git rebase --onto main feat/xxx
|
|
69
69
|
* - in_progress/pending: git rebase dev/xxx (base on parent dev branch)
|
|
70
70
|
*
|
|
71
|
-
* For 'merged' status
|
|
72
|
-
*
|
|
71
|
+
* For 'merged' status:
|
|
72
|
+
* - New branches are created from feat/xxx (which contains squashed commits)
|
|
73
|
+
* - We use --onto to rebase only new commits (after feat branch) onto main
|
|
73
74
|
*/
|
|
74
75
|
export declare function getBaseBranchInfo(branch: Branch, allBranches: Branch[], mainBranch?: string): Promise<{
|
|
75
76
|
baseBranch: string;
|
|
77
|
+
rebaseTargetBranch?: string;
|
|
76
78
|
originalBaseBranch?: string;
|
|
77
79
|
needsRebase: boolean;
|
|
78
80
|
baseBranchMerged: boolean;
|
|
@@ -164,11 +164,12 @@ export async function allBranchesCompleted(options) {
|
|
|
164
164
|
* Rebase strategies based on base branch status:
|
|
165
165
|
* - no base_branch_id: git rebase main (first branch in chain)
|
|
166
166
|
* - completed (feat merged to main): git rebase main
|
|
167
|
-
* - merged (dev merged to feat): git rebase --onto main feat/xxx
|
|
167
|
+
* - merged (dev merged to feat): create from feat/xxx, then git rebase --onto main feat/xxx
|
|
168
168
|
* - in_progress/pending: git rebase dev/xxx (base on parent dev branch)
|
|
169
169
|
*
|
|
170
|
-
* For 'merged' status
|
|
171
|
-
*
|
|
170
|
+
* For 'merged' status:
|
|
171
|
+
* - New branches are created from feat/xxx (which contains squashed commits)
|
|
172
|
+
* - We use --onto to rebase only new commits (after feat branch) onto main
|
|
172
173
|
*/
|
|
173
174
|
export async function getBaseBranchInfo(branch, allBranches, mainBranch = 'main') {
|
|
174
175
|
// No base branch - start from main (first branch in chain)
|
|
@@ -204,8 +205,8 @@ export async function getBaseBranchInfo(branch, allBranches, mainBranch = 'main'
|
|
|
204
205
|
// Check if base branch is merged (dev merged to feat, but feat not yet merged to main)
|
|
205
206
|
if (baseBranch.status === 'merged') {
|
|
206
207
|
// Base branch's dev is squash-merged to feat
|
|
208
|
+
// New branches should be created from feat/xxx (which has the squashed commits)
|
|
207
209
|
// Use --onto to rebase only new commits (after feat branch) onto main
|
|
208
|
-
// This correctly handles the case where feat contains squashed commits
|
|
209
210
|
if (!baseBranch.branch_name) {
|
|
210
211
|
return {
|
|
211
212
|
baseBranch: mainBranch,
|
|
@@ -215,8 +216,9 @@ export async function getBaseBranchInfo(branch, allBranches, mainBranch = 'main'
|
|
|
215
216
|
}
|
|
216
217
|
const featBranchName = baseBranch.branch_name.replace(/^dev\//, 'feat/');
|
|
217
218
|
return {
|
|
218
|
-
baseBranch:
|
|
219
|
-
|
|
219
|
+
baseBranch: featBranchName, // Create new branches from feat/xxx
|
|
220
|
+
rebaseTargetBranch: mainBranch, // Rebase onto main
|
|
221
|
+
originalBaseBranch: featBranchName, // Use feat branch for --onto starting point
|
|
220
222
|
needsRebase: true,
|
|
221
223
|
baseBranchMerged: true,
|
|
222
224
|
};
|
|
@@ -174,10 +174,21 @@ export declare function syncFeatBranchWithMain(featBranch: string, githubToken:
|
|
|
174
174
|
*/
|
|
175
175
|
export interface RebaseWithConflictResolutionOptions {
|
|
176
176
|
featureBranch: string;
|
|
177
|
+
/**
|
|
178
|
+
* Base branch to create new branches from.
|
|
179
|
+
* For merged parent branches, this is feat/xxx.
|
|
180
|
+
* For completed parent branches, this is main.
|
|
181
|
+
*/
|
|
177
182
|
baseBranch?: string;
|
|
183
|
+
/**
|
|
184
|
+
* Target branch for --onto rebase.
|
|
185
|
+
* When set, uses `git rebase --onto rebaseTargetBranch originalBaseBranch`.
|
|
186
|
+
* If not set, baseBranch is used as the rebase target.
|
|
187
|
+
*/
|
|
188
|
+
rebaseTargetBranch?: string;
|
|
178
189
|
/**
|
|
179
190
|
* Original base branch before squash merge.
|
|
180
|
-
* When set, uses `git rebase --onto
|
|
191
|
+
* When set, uses `git rebase --onto <target> originalBaseBranch` to only
|
|
181
192
|
* rebase commits that are new relative to originalBaseBranch.
|
|
182
193
|
* This is required when the base branch was squash-merged, otherwise
|
|
183
194
|
* git will try to reapply all the original commits causing many conflicts.
|
|
@@ -689,7 +689,10 @@ export async function syncFeatBranchWithMain(featBranch, githubToken, owner, rep
|
|
|
689
689
|
* @returns Object containing the previous branch name and conflict resolution result
|
|
690
690
|
*/
|
|
691
691
|
export async function switchToFeatureBranchAndRebaseAsync(options) {
|
|
692
|
-
const { featureBranch, baseBranch = 'main', originalBaseBranch, verbose, resolveConflicts = false, conflictResolverConfig, forcePushAfterRebase = false, } = options;
|
|
692
|
+
const { featureBranch, baseBranch = 'main', rebaseTargetBranch, originalBaseBranch, verbose, resolveConflicts = false, conflictResolverConfig, forcePushAfterRebase = false, } = options;
|
|
693
|
+
// Determine the actual target branch for rebase
|
|
694
|
+
// If rebaseTargetBranch is set (e.g., main), use it; otherwise use baseBranch
|
|
695
|
+
const actualRebaseTarget = rebaseTargetBranch || baseBranch;
|
|
693
696
|
const previousBranch = getCurrentBranch();
|
|
694
697
|
if (verbose) {
|
|
695
698
|
logInfo(`\nš Preparing feature branch: ${featureBranch}`);
|
|
@@ -781,13 +784,13 @@ export async function switchToFeatureBranchAndRebaseAsync(options) {
|
|
|
781
784
|
logInfo(`ā ļø Could not sync with remote feature branch, continuing with local branch`);
|
|
782
785
|
}
|
|
783
786
|
}
|
|
784
|
-
// Rebase feature branch with latest
|
|
787
|
+
// Rebase feature branch with latest target branch
|
|
785
788
|
if (verbose) {
|
|
786
789
|
if (originalBaseBranch) {
|
|
787
|
-
logInfo(`š„ Rebasing ${featureBranch} onto origin/${
|
|
790
|
+
logInfo(`š„ Rebasing ${featureBranch} onto origin/${actualRebaseTarget} (from ${originalBaseBranch})...`);
|
|
788
791
|
}
|
|
789
792
|
else {
|
|
790
|
-
logInfo(`š„ Rebasing ${featureBranch} with origin/${
|
|
793
|
+
logInfo(`š„ Rebasing ${featureBranch} with origin/${actualRebaseTarget}...`);
|
|
791
794
|
}
|
|
792
795
|
}
|
|
793
796
|
try {
|
|
@@ -797,8 +800,8 @@ export async function switchToFeatureBranchAndRebaseAsync(options) {
|
|
|
797
800
|
}
|
|
798
801
|
resetUncommittedChanges(verbose);
|
|
799
802
|
}
|
|
800
|
-
// Fetch the
|
|
801
|
-
execSync(`git fetch origin ${
|
|
803
|
+
// Fetch the target branch first
|
|
804
|
+
execSync(`git fetch origin ${actualRebaseTarget}`, {
|
|
802
805
|
encoding: 'utf-8',
|
|
803
806
|
stdio: 'pipe',
|
|
804
807
|
});
|
|
@@ -807,23 +810,28 @@ export async function switchToFeatureBranchAndRebaseAsync(options) {
|
|
|
807
810
|
// This prevents re-applying commits that were already included in the squash
|
|
808
811
|
// Command: git rebase --onto <new-base> <old-base>
|
|
809
812
|
// This rebases commits from <old-base>..HEAD onto <new-base>
|
|
813
|
+
// Also fetch the originalBaseBranch for the --onto reference
|
|
814
|
+
execSync(`git fetch origin ${originalBaseBranch}`, {
|
|
815
|
+
encoding: 'utf-8',
|
|
816
|
+
stdio: 'pipe',
|
|
817
|
+
});
|
|
810
818
|
if (verbose) {
|
|
811
819
|
logInfo(` Using --onto to rebase only new commits (after ${originalBaseBranch})`);
|
|
812
820
|
}
|
|
813
|
-
execSync(`git rebase --onto origin/${
|
|
821
|
+
execSync(`git rebase --onto origin/${actualRebaseTarget} origin/${originalBaseBranch}`, {
|
|
814
822
|
encoding: 'utf-8',
|
|
815
823
|
stdio: verbose ? 'inherit' : 'pipe',
|
|
816
824
|
});
|
|
817
825
|
}
|
|
818
826
|
else {
|
|
819
827
|
// Normal rebase
|
|
820
|
-
execSync(`git rebase origin/${
|
|
828
|
+
execSync(`git rebase origin/${actualRebaseTarget}`, {
|
|
821
829
|
encoding: 'utf-8',
|
|
822
830
|
stdio: verbose ? 'inherit' : 'pipe',
|
|
823
831
|
});
|
|
824
832
|
}
|
|
825
833
|
if (verbose) {
|
|
826
|
-
logInfo(`ā
Successfully rebased ${featureBranch} with origin/${
|
|
834
|
+
logInfo(`ā
Successfully rebased ${featureBranch} with origin/${actualRebaseTarget}\n`);
|
|
827
835
|
}
|
|
828
836
|
// Force push after rebase to trigger GitHub to recalculate PR diff
|
|
829
837
|
if (forcePushAfterRebase) {
|
|
@@ -866,7 +874,7 @@ export async function switchToFeatureBranchAndRebaseAsync(options) {
|
|
|
866
874
|
});
|
|
867
875
|
if (result.success) {
|
|
868
876
|
if (verbose) {
|
|
869
|
-
logInfo(`ā
Successfully resolved conflicts and rebased ${featureBranch} with origin/${
|
|
877
|
+
logInfo(`ā
Successfully resolved conflicts and rebased ${featureBranch} with origin/${actualRebaseTarget}\n`);
|
|
870
878
|
}
|
|
871
879
|
// Force push after rebase to trigger GitHub to recalculate PR diff
|
|
872
880
|
if (forcePushAfterRebase) {
|
|
@@ -898,7 +906,7 @@ export async function switchToFeatureBranchAndRebaseAsync(options) {
|
|
|
898
906
|
else {
|
|
899
907
|
// Conflict resolution failed, abort rebase
|
|
900
908
|
abortRebase(verbose);
|
|
901
|
-
throw new Error(`Failed to automatically resolve conflicts during rebase ${featureBranch} with ${
|
|
909
|
+
throw new Error(`Failed to automatically resolve conflicts during rebase ${featureBranch} with ${actualRebaseTarget}.\n` +
|
|
902
910
|
`${result.error || 'Unknown error'}\n` +
|
|
903
911
|
`Please resolve conflicts manually and try again.`);
|
|
904
912
|
}
|
|
@@ -909,7 +917,7 @@ export async function switchToFeatureBranchAndRebaseAsync(options) {
|
|
|
909
917
|
if (verbose) {
|
|
910
918
|
logError(`ā Rebase failed and was aborted. Repository is in clean state.`);
|
|
911
919
|
}
|
|
912
|
-
throw new Error(`Failed to rebase ${featureBranch} with ${
|
|
920
|
+
throw new Error(`Failed to rebase ${featureBranch} with ${actualRebaseTarget}: ${error instanceof Error ? error.message : String(error)}\n` +
|
|
913
921
|
`This usually means there are conflicts between your feature branch and base branch.\n` +
|
|
914
922
|
`Please resolve conflicts manually and try again.`);
|
|
915
923
|
}
|