edsger 0.6.2 → 0.6.4
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/commands/workflow/feature-coordinator.js +2 -0
- package/dist/commands/workflow/phase-orchestrator.js +62 -0
- package/dist/phases/pull-request/creator.js +41 -6
- package/dist/phases/pull-request/handler.js +61 -0
- package/dist/services/audit-logs.d.ts +2 -2
- package/dist/types/pipeline.d.ts +1 -1
- package/package.json +1 -1
|
@@ -114,12 +114,14 @@ export function getExecutionModeDescription(mode) {
|
|
|
114
114
|
only_technical_design: 'Execute only: technical design',
|
|
115
115
|
only_code_implementation: 'Execute only: code implementation',
|
|
116
116
|
only_functional_testing: 'Execute only: functional testing',
|
|
117
|
+
only_pull_request: 'Execute only: create pull request',
|
|
117
118
|
only_code_refine: 'Execute only: code refine (address PR review feedback and verify resolution)',
|
|
118
119
|
only_code_review: 'Execute only: code review (review PR code and create review comments)',
|
|
119
120
|
from_feature_analysis: 'Execute from feature analysis to end: analysis → design → implementation → testing',
|
|
120
121
|
from_technical_design: 'Execute from technical design to end: design → implementation → testing',
|
|
121
122
|
from_code_implementation: 'Execute from code implementation to end: implementation → testing',
|
|
122
123
|
from_functional_testing: 'Execute from functional testing to end: testing',
|
|
124
|
+
from_pull_request: 'Execute from pull request creation to end: pull-request → code-review → code-refine → code-refine-verification',
|
|
123
125
|
from_code_review: 'Execute from code review to end: code-review → code-refine → code-refine-verification',
|
|
124
126
|
};
|
|
125
127
|
return descriptions[mode] || 'Unknown execution mode';
|
|
@@ -62,6 +62,11 @@ export const runPipelineByMode = async (options, config, executionMode) => {
|
|
|
62
62
|
return await runOnlyFunctionalTesting(options, config);
|
|
63
63
|
case 'from_functional_testing':
|
|
64
64
|
return await runFromFunctionalTesting(options, config);
|
|
65
|
+
// Pull Request
|
|
66
|
+
case 'only_pull_request':
|
|
67
|
+
return await runOnlyPullRequest(options, config);
|
|
68
|
+
case 'from_pull_request':
|
|
69
|
+
return await runFromPullRequest(options, config);
|
|
65
70
|
// Code Refine
|
|
66
71
|
case 'only_code_refine':
|
|
67
72
|
return await runOnlyCodeRefine(options, config);
|
|
@@ -311,6 +316,30 @@ const runFromFunctionalTesting = async (options, config) => {
|
|
|
311
316
|
}
|
|
312
317
|
return logPipelineComplete(results, verbose);
|
|
313
318
|
};
|
|
319
|
+
/**
|
|
320
|
+
* Run only pull request creation phase
|
|
321
|
+
*/
|
|
322
|
+
const runOnlyPullRequest = async (options, config) => {
|
|
323
|
+
const { featureId, verbose } = options;
|
|
324
|
+
logPipelineStart(featureId, verbose);
|
|
325
|
+
const results = [];
|
|
326
|
+
// Note: We create a mock testing result since this mode assumes testing already passed
|
|
327
|
+
const mockTestingResult = {
|
|
328
|
+
featureId,
|
|
329
|
+
phase: 'functional-testing',
|
|
330
|
+
status: 'success',
|
|
331
|
+
message: 'Functional testing assumed to have passed',
|
|
332
|
+
data: {},
|
|
333
|
+
};
|
|
334
|
+
// Create pull request only
|
|
335
|
+
await handlePullRequestCreation({
|
|
336
|
+
featureId,
|
|
337
|
+
results,
|
|
338
|
+
testingResult: mockTestingResult,
|
|
339
|
+
verbose,
|
|
340
|
+
});
|
|
341
|
+
return logPipelineComplete(results, verbose);
|
|
342
|
+
};
|
|
314
343
|
/**
|
|
315
344
|
* Run only code refine phase (refine code based on PR feedback)
|
|
316
345
|
* Includes automatic retry loop for verification failures
|
|
@@ -362,6 +391,39 @@ const runFromCodeReview = async (options, config) => {
|
|
|
362
391
|
});
|
|
363
392
|
return logPipelineComplete(results, verbose);
|
|
364
393
|
};
|
|
394
|
+
/**
|
|
395
|
+
* Run from pull request creation to end (pull-request → code-review → code-refine → code-refine-verification)
|
|
396
|
+
*/
|
|
397
|
+
const runFromPullRequest = async (options, config) => {
|
|
398
|
+
const { featureId, verbose } = options;
|
|
399
|
+
logPipelineStart(featureId, verbose);
|
|
400
|
+
const results = [];
|
|
401
|
+
// Note: We create a mock testing result since this mode assumes testing already passed
|
|
402
|
+
// The PR creation handler needs this for context
|
|
403
|
+
const mockTestingResult = {
|
|
404
|
+
featureId,
|
|
405
|
+
phase: 'functional-testing',
|
|
406
|
+
status: 'success',
|
|
407
|
+
message: 'Functional testing assumed to have passed',
|
|
408
|
+
data: {},
|
|
409
|
+
};
|
|
410
|
+
// 1. Create pull request
|
|
411
|
+
const prCreated = await handlePullRequestCreation({
|
|
412
|
+
featureId,
|
|
413
|
+
results,
|
|
414
|
+
testingResult: mockTestingResult,
|
|
415
|
+
verbose,
|
|
416
|
+
});
|
|
417
|
+
if (!prCreated) {
|
|
418
|
+
if (verbose) {
|
|
419
|
+
logInfo('⚠️ Pull request creation failed, stopping workflow');
|
|
420
|
+
}
|
|
421
|
+
return logPipelineComplete(results, verbose);
|
|
422
|
+
}
|
|
423
|
+
// 2. Continue with code review and refine workflow
|
|
424
|
+
await continueWithCodeReviewAndRefine(options, config, results, verbose);
|
|
425
|
+
return logPipelineComplete(results, verbose);
|
|
426
|
+
};
|
|
365
427
|
/**
|
|
366
428
|
* Continue with code review and refine after PR creation
|
|
367
429
|
* This is the post-PR workflow: code-review → code-refine → code-refine-verification → code-testing
|
|
@@ -15,6 +15,39 @@ const getCurrentBranch = () => {
|
|
|
15
15
|
throw new Error(`Failed to get current branch: ${error}`);
|
|
16
16
|
}
|
|
17
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* Check if a branch exists
|
|
20
|
+
*/
|
|
21
|
+
const branchExists = (branch) => {
|
|
22
|
+
try {
|
|
23
|
+
execSync(`git rev-parse --verify ${branch}`, { encoding: 'utf-8' });
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Switch to an existing branch
|
|
32
|
+
*/
|
|
33
|
+
const switchToBranch = (branch, verbose) => {
|
|
34
|
+
try {
|
|
35
|
+
// First check if branch exists
|
|
36
|
+
if (!branchExists(branch)) {
|
|
37
|
+
throw new Error(`Branch '${branch}' does not exist. The branch should have been created during code implementation phase.`);
|
|
38
|
+
}
|
|
39
|
+
if (verbose) {
|
|
40
|
+
console.log(`🔀 Switching to branch: ${branch}`);
|
|
41
|
+
}
|
|
42
|
+
execSync(`git checkout ${branch}`, { encoding: 'utf-8' });
|
|
43
|
+
if (verbose) {
|
|
44
|
+
console.log(`✅ Switched to branch: ${branch}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw new Error(`Failed to switch to branch ${branch}: ${error}`);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
18
51
|
/**
|
|
19
52
|
* Push current branch to remote
|
|
20
53
|
*/
|
|
@@ -93,16 +126,18 @@ export async function createPullRequest(config, feature) {
|
|
|
93
126
|
auth: githubToken,
|
|
94
127
|
});
|
|
95
128
|
// Get current branch (should be dev/feature-id)
|
|
96
|
-
|
|
129
|
+
let currentBranch = getCurrentBranch();
|
|
97
130
|
if (verbose) {
|
|
98
131
|
console.log(`🔍 Current branch: ${currentBranch}`);
|
|
99
132
|
}
|
|
100
|
-
//
|
|
133
|
+
// If we're on the base branch, switch to dev branch (should already exist)
|
|
101
134
|
if (currentBranch === baseBranch) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
135
|
+
const devBranch = `dev/${feature.id}`;
|
|
136
|
+
if (verbose) {
|
|
137
|
+
console.log(`⚠️ Currently on ${baseBranch} branch, switching to ${devBranch}`);
|
|
138
|
+
}
|
|
139
|
+
switchToBranch(devBranch, verbose);
|
|
140
|
+
currentBranch = devBranch;
|
|
106
141
|
}
|
|
107
142
|
// Extract feature ID from current branch (dev/feature-id)
|
|
108
143
|
let targetBranch = baseBranch;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { getFeature } from '../../api/features/index.js';
|
|
5
5
|
import { createPullRequest, updateFeatureWithPullRequest } from './creator.js';
|
|
6
|
+
import { logFeaturePhaseEvent } from '../../services/audit-logs.js';
|
|
6
7
|
/**
|
|
7
8
|
* Create pull request for successful feature implementation
|
|
8
9
|
* Returns true if PR was successfully created, false otherwise
|
|
@@ -11,12 +12,33 @@ export async function handlePullRequestCreation({ featureId, results, testingRes
|
|
|
11
12
|
if (verbose) {
|
|
12
13
|
console.log('🔄 Creating pull request for successful feature...');
|
|
13
14
|
}
|
|
15
|
+
// Log phase start
|
|
16
|
+
await logFeaturePhaseEvent({
|
|
17
|
+
featureId,
|
|
18
|
+
eventType: 'phase_started',
|
|
19
|
+
phase: 'pull_request',
|
|
20
|
+
result: 'info',
|
|
21
|
+
metadata: {
|
|
22
|
+
timestamp: new Date().toISOString(),
|
|
23
|
+
},
|
|
24
|
+
}, verbose);
|
|
14
25
|
// Get feature details for PR creation
|
|
15
26
|
const feature = await getFeature(featureId, verbose);
|
|
16
27
|
if (!feature) {
|
|
17
28
|
if (verbose) {
|
|
18
29
|
console.log('⚠️ Could not fetch feature details for pull request creation');
|
|
19
30
|
}
|
|
31
|
+
// Log phase failure
|
|
32
|
+
await logFeaturePhaseEvent({
|
|
33
|
+
featureId,
|
|
34
|
+
eventType: 'phase_failed',
|
|
35
|
+
phase: 'pull_request',
|
|
36
|
+
result: 'error',
|
|
37
|
+
errorMessage: 'Could not fetch feature details',
|
|
38
|
+
metadata: {
|
|
39
|
+
timestamp: new Date().toISOString(),
|
|
40
|
+
},
|
|
41
|
+
}, verbose);
|
|
20
42
|
return false;
|
|
21
43
|
}
|
|
22
44
|
// Get GitHub configuration from environment
|
|
@@ -28,6 +50,22 @@ export async function handlePullRequestCreation({ featureId, results, testingRes
|
|
|
28
50
|
console.log('⚠️ GitHub configuration not found. Skipping pull request creation.');
|
|
29
51
|
console.log(' Set GITHUB_TOKEN, GITHUB_OWNER, and GITHUB_REPO environment variables.');
|
|
30
52
|
}
|
|
53
|
+
// Log phase failure
|
|
54
|
+
await logFeaturePhaseEvent({
|
|
55
|
+
featureId,
|
|
56
|
+
eventType: 'phase_failed',
|
|
57
|
+
phase: 'pull_request',
|
|
58
|
+
result: 'error',
|
|
59
|
+
errorMessage: 'GitHub configuration not found',
|
|
60
|
+
metadata: {
|
|
61
|
+
missing_vars: [
|
|
62
|
+
!githubToken && 'GITHUB_TOKEN',
|
|
63
|
+
!githubOwner && 'GITHUB_OWNER',
|
|
64
|
+
!githubRepo && 'GITHUB_REPO',
|
|
65
|
+
].filter(Boolean),
|
|
66
|
+
timestamp: new Date().toISOString(),
|
|
67
|
+
},
|
|
68
|
+
}, verbose);
|
|
31
69
|
return false;
|
|
32
70
|
}
|
|
33
71
|
const prResult = await createPullRequest({
|
|
@@ -49,6 +87,18 @@ export async function handlePullRequestCreation({ featureId, results, testingRes
|
|
|
49
87
|
if (prResult.success && prResult.pullRequestUrl) {
|
|
50
88
|
// Update feature with PR URL and status
|
|
51
89
|
await updateFeatureWithPullRequest(featureId, prResult.pullRequestUrl, verbose);
|
|
90
|
+
// Log phase completion
|
|
91
|
+
await logFeaturePhaseEvent({
|
|
92
|
+
featureId,
|
|
93
|
+
eventType: 'phase_completed',
|
|
94
|
+
phase: 'pull_request',
|
|
95
|
+
result: 'success',
|
|
96
|
+
metadata: {
|
|
97
|
+
pull_request_url: prResult.pullRequestUrl,
|
|
98
|
+
pull_request_number: prResult.pullRequestNumber,
|
|
99
|
+
timestamp: new Date().toISOString(),
|
|
100
|
+
},
|
|
101
|
+
}, verbose);
|
|
52
102
|
if (verbose) {
|
|
53
103
|
console.log(`✅ Pull request created and feature updated to ready_for_review`);
|
|
54
104
|
}
|
|
@@ -58,6 +108,17 @@ export async function handlePullRequestCreation({ featureId, results, testingRes
|
|
|
58
108
|
if (verbose) {
|
|
59
109
|
console.log(`⚠️ Pull request creation failed: ${prResult.error}`);
|
|
60
110
|
}
|
|
111
|
+
// Log phase failure
|
|
112
|
+
await logFeaturePhaseEvent({
|
|
113
|
+
featureId,
|
|
114
|
+
eventType: 'phase_failed',
|
|
115
|
+
phase: 'pull_request',
|
|
116
|
+
result: 'error',
|
|
117
|
+
errorMessage: prResult.error,
|
|
118
|
+
metadata: {
|
|
119
|
+
timestamp: new Date().toISOString(),
|
|
120
|
+
},
|
|
121
|
+
}, verbose);
|
|
61
122
|
return false;
|
|
62
123
|
}
|
|
63
124
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
export interface LogPhaseEventParams {
|
|
6
6
|
featureId: string;
|
|
7
7
|
eventType: 'phase_started' | 'phase_completed' | 'phase_failed';
|
|
8
|
-
phase: 'feature_analysis' | 'technical_design' | 'code_implementation' | 'functional_testing' | '
|
|
8
|
+
phase: 'feature_analysis' | 'technical_design' | 'code_implementation' | 'functional_testing' | 'pull_request' | 'code_review' | 'code_refine' | 'code_refine_verification';
|
|
9
9
|
result?: 'success' | 'error' | 'warning' | 'info';
|
|
10
10
|
metadata?: Record<string, any>;
|
|
11
11
|
errorMessage?: string;
|
|
@@ -19,7 +19,7 @@ export interface LogChecklistEventParams {
|
|
|
19
19
|
}
|
|
20
20
|
export interface LogVerificationEventParams {
|
|
21
21
|
featureId: string;
|
|
22
|
-
phase: 'feature_analysis' | 'technical_design' | 'code_implementation' | 'functional_testing' | '
|
|
22
|
+
phase: 'feature_analysis' | 'technical_design' | 'code_implementation' | 'functional_testing' | 'pull_request' | 'code_review' | 'code_refine' | 'code_refine_verification';
|
|
23
23
|
iteration: number;
|
|
24
24
|
result: 'success' | 'error';
|
|
25
25
|
verificationData: {
|
package/dist/types/pipeline.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { EdsgerConfig } from './index.js';
|
|
5
5
|
import { ChecklistPhaseContext } from '../services/checklist.js';
|
|
6
|
-
export type ExecutionMode = 'full_pipeline' | 'only_feature_analysis' | 'only_technical_design' | 'only_code_implementation' | 'only_functional_testing' | 'only_code_refine' | 'only_code_review' | 'from_feature_analysis' | 'from_technical_design' | 'from_code_implementation' | 'from_functional_testing' | 'from_code_review';
|
|
6
|
+
export type ExecutionMode = 'full_pipeline' | 'only_feature_analysis' | 'only_technical_design' | 'only_code_implementation' | 'only_functional_testing' | 'only_pull_request' | 'only_code_refine' | 'only_code_review' | 'from_feature_analysis' | 'from_technical_design' | 'from_code_implementation' | 'from_functional_testing' | 'from_code_review' | 'from_pull_request';
|
|
7
7
|
export interface PipelinePhaseOptions {
|
|
8
8
|
readonly featureId: string;
|
|
9
9
|
readonly verbose?: boolean;
|