@nahisaho/musubix-codegraph 2.3.2 → 2.3.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/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +318 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/pr/errors.d.ts +63 -0
- package/dist/pr/errors.d.ts.map +1 -0
- package/dist/pr/errors.js +116 -0
- package/dist/pr/errors.js.map +1 -0
- package/dist/pr/git-operations.d.ts +186 -0
- package/dist/pr/git-operations.d.ts.map +1 -0
- package/dist/pr/git-operations.js +441 -0
- package/dist/pr/git-operations.js.map +1 -0
- package/dist/pr/github-adapter.d.ts +163 -0
- package/dist/pr/github-adapter.d.ts.map +1 -0
- package/dist/pr/github-adapter.js +467 -0
- package/dist/pr/github-adapter.js.map +1 -0
- package/dist/pr/index.d.ts +20 -0
- package/dist/pr/index.d.ts.map +1 -0
- package/dist/pr/index.js +26 -0
- package/dist/pr/index.js.map +1 -0
- package/dist/pr/pr-creator.d.ts +173 -0
- package/dist/pr/pr-creator.d.ts.map +1 -0
- package/dist/pr/pr-creator.js +468 -0
- package/dist/pr/pr-creator.js.map +1 -0
- package/dist/pr/pr-template.d.ts +105 -0
- package/dist/pr/pr-template.d.ts.map +1 -0
- package/dist/pr/pr-template.js +273 -0
- package/dist/pr/pr-template.js.map +1 -0
- package/dist/pr/refactoring-applier.d.ts +143 -0
- package/dist/pr/refactoring-applier.d.ts.map +1 -0
- package/dist/pr/refactoring-applier.js +412 -0
- package/dist/pr/refactoring-applier.js.map +1 -0
- package/dist/pr/types.d.ts +362 -0
- package/dist/pr/types.d.ts.map +1 -0
- package/dist/pr/types.js +63 -0
- package/dist/pr/types.js.map +1 -0
- package/package.json +11 -2
package/dist/pr/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nahisaho/musubix-codegraph/pr - PR Creation Module
|
|
3
|
+
*
|
|
4
|
+
* Automatic PR generation from refactoring suggestions
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
* @module @nahisaho/musubix-codegraph/pr
|
|
8
|
+
*
|
|
9
|
+
* @see REQ-CG-PR-001 - REQ-CG-PR-009
|
|
10
|
+
* @see DES-CG-PR-001 - DES-CG-PR-006
|
|
11
|
+
*/
|
|
12
|
+
// Main PR Creator
|
|
13
|
+
export { PRCreator, createPRCreator, createRefactoringPR, } from './pr-creator.js';
|
|
14
|
+
// Error Handling (v2.3.4 NEW)
|
|
15
|
+
export { PRCreatorError, PRErrorMessages, } from './errors.js';
|
|
16
|
+
// Git Operations
|
|
17
|
+
export { GitOperations, createGitOperations, } from './git-operations.js';
|
|
18
|
+
// GitHub Adapter
|
|
19
|
+
export { GitHubAdapter, createGitHubAdapter, } from './github-adapter.js';
|
|
20
|
+
// Refactoring Applier
|
|
21
|
+
export { RefactoringApplier, createRefactoringApplier, } from './refactoring-applier.js';
|
|
22
|
+
// PR Template Generator
|
|
23
|
+
export { PRTemplateGenerator, createPRTemplateGenerator, generateSimplePRBody, generatePRTitle, } from './pr-template.js';
|
|
24
|
+
// Utility Functions
|
|
25
|
+
export { REFACTORING_TO_COMMIT_TYPE, generateBranchName, generateCommitMessage, } from './types.js';
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pr/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,kBAAkB;AAClB,OAAO,EACL,SAAS,EACT,eAAe,EACf,mBAAmB,GAGpB,MAAM,iBAAiB,CAAC;AAEzB,8BAA8B;AAC9B,OAAO,EACL,cAAc,EACd,eAAe,GAEhB,MAAM,aAAa,CAAC;AAErB,iBAAiB;AACjB,OAAO,EACL,aAAa,EACb,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAE7B,iBAAiB;AACjB,OAAO,EACL,aAAa,EACb,mBAAmB,GAIpB,MAAM,qBAAqB,CAAC;AAE7B,sBAAsB;AACtB,OAAO,EACL,kBAAkB,EAClB,wBAAwB,GAIzB,MAAM,0BAA0B,CAAC;AAElC,wBAAwB;AACxB,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,oBAAoB,EACpB,eAAe,GAEhB,MAAM,kBAAkB,CAAC;AAsC1B,oBAAoB;AACpB,OAAO,EACL,0BAA0B,EAC1B,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nahisaho/musubix-codegraph - PR Creator
|
|
3
|
+
*
|
|
4
|
+
* Main orchestrator for creating PRs from refactoring suggestions
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
* @module @nahisaho/musubix-codegraph/pr
|
|
8
|
+
*
|
|
9
|
+
* @see REQ-CG-PR-001 - GitHub Authentication
|
|
10
|
+
* @see REQ-CG-PR-002 - Auto Apply Refactoring
|
|
11
|
+
* @see REQ-CG-PR-003 - Git Branch Creation
|
|
12
|
+
* @see REQ-CG-PR-004 - Auto Commit
|
|
13
|
+
* @see REQ-CG-PR-005 - GitHub PR Creation
|
|
14
|
+
* @see DES-CG-PR-001 - Component Design
|
|
15
|
+
* @see DES-CG-PR-005 - Sequence Diagram
|
|
16
|
+
*/
|
|
17
|
+
import { EventEmitter } from 'node:events';
|
|
18
|
+
import type { RefactoringSuggestion, PRCreateOptions, PRCreateResult, PRPreview, PRCreatorEvents } from './types.js';
|
|
19
|
+
/**
|
|
20
|
+
* PRCreator state
|
|
21
|
+
* @see DES-CG-v234-003
|
|
22
|
+
*/
|
|
23
|
+
export type PRCreatorState = 'uninitialized' | 'offline' | 'full';
|
|
24
|
+
/**
|
|
25
|
+
* PR Creator configuration
|
|
26
|
+
*/
|
|
27
|
+
export interface PRCreatorConfig {
|
|
28
|
+
/** Repository root path */
|
|
29
|
+
repoPath: string;
|
|
30
|
+
/** GitHub token (optional, will try env or gh CLI) */
|
|
31
|
+
githubToken?: string;
|
|
32
|
+
/** Remote name (default: origin) */
|
|
33
|
+
remote?: string;
|
|
34
|
+
/** Create backups before modifications */
|
|
35
|
+
createBackups?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* PR Creator
|
|
39
|
+
*
|
|
40
|
+
* Orchestrates the entire PR creation workflow:
|
|
41
|
+
* 1. Authenticate with GitHub
|
|
42
|
+
* 2. Create a new branch
|
|
43
|
+
* 3. Apply refactoring changes
|
|
44
|
+
* 4. Commit changes
|
|
45
|
+
* 5. Push to remote
|
|
46
|
+
* 6. Create PR on GitHub
|
|
47
|
+
*
|
|
48
|
+
* @see DES-CG-PR-001
|
|
49
|
+
* @see DES-CG-PR-005
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const creator = new PRCreator({ repoPath: '/path/to/repo' });
|
|
53
|
+
* await creator.initialize();
|
|
54
|
+
*
|
|
55
|
+
* const result = await creator.create({
|
|
56
|
+
* suggestion: refactoringSuggestion,
|
|
57
|
+
* baseBranch: 'main',
|
|
58
|
+
* labels: ['refactoring', 'auto-generated'],
|
|
59
|
+
* });
|
|
60
|
+
*
|
|
61
|
+
* console.log(`PR created: ${result.pr?.url}`);
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare class PRCreator extends EventEmitter {
|
|
65
|
+
private readonly config;
|
|
66
|
+
private git;
|
|
67
|
+
private github;
|
|
68
|
+
private applier;
|
|
69
|
+
private templateGenerator;
|
|
70
|
+
private initialized;
|
|
71
|
+
private originalBranch;
|
|
72
|
+
private state;
|
|
73
|
+
/**
|
|
74
|
+
* Create a new PRCreator
|
|
75
|
+
* @param config - Configuration options
|
|
76
|
+
*/
|
|
77
|
+
constructor(config: PRCreatorConfig);
|
|
78
|
+
/**
|
|
79
|
+
* Initialize for offline operations (preview only)
|
|
80
|
+
* Does not require GitHub authentication
|
|
81
|
+
*
|
|
82
|
+
* @see REQ-CG-v234-001
|
|
83
|
+
* @see DES-CG-v234-001
|
|
84
|
+
*/
|
|
85
|
+
initializeOffline(): Promise<{
|
|
86
|
+
success: boolean;
|
|
87
|
+
error?: string;
|
|
88
|
+
}>;
|
|
89
|
+
/**
|
|
90
|
+
* Initialize the PR creator with full GitHub authentication
|
|
91
|
+
* Sets up Git operations and authenticates with GitHub
|
|
92
|
+
*/
|
|
93
|
+
initialize(): Promise<{
|
|
94
|
+
success: boolean;
|
|
95
|
+
error?: string;
|
|
96
|
+
}>;
|
|
97
|
+
/**
|
|
98
|
+
* Check if initialized
|
|
99
|
+
*/
|
|
100
|
+
isInitialized(): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Get current state
|
|
103
|
+
* @see DES-CG-v234-003
|
|
104
|
+
*/
|
|
105
|
+
getState(): PRCreatorState;
|
|
106
|
+
/**
|
|
107
|
+
* Generate PR preview without creating
|
|
108
|
+
* Works in both offline and full modes
|
|
109
|
+
*
|
|
110
|
+
* @see REQ-CG-v234-001
|
|
111
|
+
* @see DES-CG-v234-001
|
|
112
|
+
*/
|
|
113
|
+
previewSuggestion(suggestion: RefactoringSuggestion): PRPreview;
|
|
114
|
+
/**
|
|
115
|
+
* Create a PR from a refactoring suggestion
|
|
116
|
+
* Requires full initialization (GitHub authentication)
|
|
117
|
+
*
|
|
118
|
+
* @see REQ-CG-PR-002, REQ-CG-PR-003, REQ-CG-PR-004, REQ-CG-PR-005
|
|
119
|
+
*/
|
|
120
|
+
create(options: PRCreateOptions): Promise<PRCreateResult>;
|
|
121
|
+
/**
|
|
122
|
+
* Preview PR creation without actually creating
|
|
123
|
+
* @see REQ-CG-PR-007
|
|
124
|
+
*/
|
|
125
|
+
preview(options: PRCreateOptions): Promise<PRPreview>;
|
|
126
|
+
/**
|
|
127
|
+
* Validate a suggestion can be applied
|
|
128
|
+
*/
|
|
129
|
+
validate(suggestion: RefactoringSuggestion): {
|
|
130
|
+
valid: boolean;
|
|
131
|
+
reason?: string;
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Dry run implementation
|
|
135
|
+
*/
|
|
136
|
+
private dryRun;
|
|
137
|
+
/**
|
|
138
|
+
* Ensure initialized before operations (legacy)
|
|
139
|
+
* @deprecated Use ensureState() instead
|
|
140
|
+
*/
|
|
141
|
+
private ensureInitialized;
|
|
142
|
+
/**
|
|
143
|
+
* Ensure PRCreator is in one of the allowed states
|
|
144
|
+
* @see DES-CG-v234-003
|
|
145
|
+
*/
|
|
146
|
+
private ensureState;
|
|
147
|
+
/**
|
|
148
|
+
* Typed event emitter methods
|
|
149
|
+
*/
|
|
150
|
+
emit<K extends keyof PRCreatorEvents>(event: K, data: PRCreatorEvents[K]): boolean;
|
|
151
|
+
on<K extends keyof PRCreatorEvents>(event: K, listener: (data: PRCreatorEvents[K]) => void): this;
|
|
152
|
+
once<K extends keyof PRCreatorEvents>(event: K, listener: (data: PRCreatorEvents[K]) => void): this;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Create a PRCreator instance
|
|
156
|
+
*/
|
|
157
|
+
export declare function createPRCreator(repoPath: string, options?: Partial<PRCreatorConfig>): PRCreator;
|
|
158
|
+
/**
|
|
159
|
+
* Quick PR creation helper
|
|
160
|
+
*
|
|
161
|
+
* One-shot function to create a PR from a suggestion.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* const result = await createRefactoringPR(
|
|
166
|
+
* '/path/to/repo',
|
|
167
|
+
* suggestion,
|
|
168
|
+
* { labels: ['refactoring'] }
|
|
169
|
+
* );
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
export declare function createRefactoringPR(repoPath: string, suggestion: RefactoringSuggestion, options?: Partial<PRCreateOptions>): Promise<PRCreateResult>;
|
|
173
|
+
//# sourceMappingURL=pr-creator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-creator.d.ts","sourceRoot":"","sources":["../../src/pr/pr-creator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nahisaho/musubix-codegraph - PR Creator
|
|
3
|
+
*
|
|
4
|
+
* Main orchestrator for creating PRs from refactoring suggestions
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
* @module @nahisaho/musubix-codegraph/pr
|
|
8
|
+
*
|
|
9
|
+
* @see REQ-CG-PR-001 - GitHub Authentication
|
|
10
|
+
* @see REQ-CG-PR-002 - Auto Apply Refactoring
|
|
11
|
+
* @see REQ-CG-PR-003 - Git Branch Creation
|
|
12
|
+
* @see REQ-CG-PR-004 - Auto Commit
|
|
13
|
+
* @see REQ-CG-PR-005 - GitHub PR Creation
|
|
14
|
+
* @see DES-CG-PR-001 - Component Design
|
|
15
|
+
* @see DES-CG-PR-005 - Sequence Diagram
|
|
16
|
+
*/
|
|
17
|
+
import { EventEmitter } from 'node:events';
|
|
18
|
+
import { GitOperations } from './git-operations.js';
|
|
19
|
+
import { GitHubAdapter } from './github-adapter.js';
|
|
20
|
+
import { RefactoringApplier } from './refactoring-applier.js';
|
|
21
|
+
import { PRTemplateGenerator } from './pr-template.js';
|
|
22
|
+
import { PRCreatorError, PRErrorMessages } from './errors.js';
|
|
23
|
+
import { generateBranchName, generateCommitMessage, } from './types.js';
|
|
24
|
+
/**
|
|
25
|
+
* PR Creator
|
|
26
|
+
*
|
|
27
|
+
* Orchestrates the entire PR creation workflow:
|
|
28
|
+
* 1. Authenticate with GitHub
|
|
29
|
+
* 2. Create a new branch
|
|
30
|
+
* 3. Apply refactoring changes
|
|
31
|
+
* 4. Commit changes
|
|
32
|
+
* 5. Push to remote
|
|
33
|
+
* 6. Create PR on GitHub
|
|
34
|
+
*
|
|
35
|
+
* @see DES-CG-PR-001
|
|
36
|
+
* @see DES-CG-PR-005
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* const creator = new PRCreator({ repoPath: '/path/to/repo' });
|
|
40
|
+
* await creator.initialize();
|
|
41
|
+
*
|
|
42
|
+
* const result = await creator.create({
|
|
43
|
+
* suggestion: refactoringSuggestion,
|
|
44
|
+
* baseBranch: 'main',
|
|
45
|
+
* labels: ['refactoring', 'auto-generated'],
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* console.log(`PR created: ${result.pr?.url}`);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export class PRCreator extends EventEmitter {
|
|
52
|
+
config;
|
|
53
|
+
git = null;
|
|
54
|
+
github = null;
|
|
55
|
+
applier = null;
|
|
56
|
+
templateGenerator;
|
|
57
|
+
initialized = false;
|
|
58
|
+
originalBranch = null;
|
|
59
|
+
state = 'uninitialized';
|
|
60
|
+
/**
|
|
61
|
+
* Create a new PRCreator
|
|
62
|
+
* @param config - Configuration options
|
|
63
|
+
*/
|
|
64
|
+
constructor(config) {
|
|
65
|
+
super();
|
|
66
|
+
this.config = {
|
|
67
|
+
remote: 'origin',
|
|
68
|
+
createBackups: true,
|
|
69
|
+
...config,
|
|
70
|
+
};
|
|
71
|
+
this.templateGenerator = new PRTemplateGenerator();
|
|
72
|
+
}
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// Initialization
|
|
75
|
+
// ============================================================================
|
|
76
|
+
/**
|
|
77
|
+
* Initialize for offline operations (preview only)
|
|
78
|
+
* Does not require GitHub authentication
|
|
79
|
+
*
|
|
80
|
+
* @see REQ-CG-v234-001
|
|
81
|
+
* @see DES-CG-v234-001
|
|
82
|
+
*/
|
|
83
|
+
async initializeOffline() {
|
|
84
|
+
try {
|
|
85
|
+
// Initialize Git operations (local only)
|
|
86
|
+
this.git = new GitOperations({
|
|
87
|
+
repoPath: this.config.repoPath,
|
|
88
|
+
remote: this.config.remote,
|
|
89
|
+
});
|
|
90
|
+
// Initialize refactoring applier
|
|
91
|
+
this.applier = new RefactoringApplier({
|
|
92
|
+
repoPath: this.config.repoPath,
|
|
93
|
+
createBackups: this.config.createBackups,
|
|
94
|
+
});
|
|
95
|
+
// Store current branch for potential rollback
|
|
96
|
+
this.originalBranch = this.git.getCurrentBranch();
|
|
97
|
+
this.state = 'offline';
|
|
98
|
+
this.initialized = true;
|
|
99
|
+
return { success: true };
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
error: error instanceof Error ? error.message : String(error),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Initialize the PR creator with full GitHub authentication
|
|
110
|
+
* Sets up Git operations and authenticates with GitHub
|
|
111
|
+
*/
|
|
112
|
+
async initialize() {
|
|
113
|
+
try {
|
|
114
|
+
// First do offline initialization if not already done
|
|
115
|
+
if (this.state === 'uninitialized') {
|
|
116
|
+
const offlineResult = await this.initializeOffline();
|
|
117
|
+
if (!offlineResult.success) {
|
|
118
|
+
return offlineResult;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Parse GitHub owner/repo from remote
|
|
122
|
+
const remoteInfo = this.git.parseRemoteUrl();
|
|
123
|
+
if (!remoteInfo) {
|
|
124
|
+
const err = PRErrorMessages.REMOTE_PARSE_FAILED;
|
|
125
|
+
return {
|
|
126
|
+
success: false,
|
|
127
|
+
error: `${err.message}. ${err.suggestion}`,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
// Initialize GitHub adapter
|
|
131
|
+
this.github = new GitHubAdapter({
|
|
132
|
+
owner: remoteInfo.owner,
|
|
133
|
+
repo: remoteInfo.repo,
|
|
134
|
+
token: this.config.githubToken,
|
|
135
|
+
});
|
|
136
|
+
// Authenticate with GitHub
|
|
137
|
+
const authResult = await this.github.authenticate();
|
|
138
|
+
if (!authResult.authenticated) {
|
|
139
|
+
const err = PRErrorMessages.AUTH_FAILED;
|
|
140
|
+
return {
|
|
141
|
+
success: false,
|
|
142
|
+
error: `${err.message}: ${authResult.error}. ${err.suggestion}`,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
this.state = 'full';
|
|
146
|
+
this.initialized = true;
|
|
147
|
+
return { success: true };
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
return {
|
|
151
|
+
success: false,
|
|
152
|
+
error: error instanceof Error ? error.message : String(error),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Check if initialized
|
|
158
|
+
*/
|
|
159
|
+
isInitialized() {
|
|
160
|
+
return this.initialized;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Get current state
|
|
164
|
+
* @see DES-CG-v234-003
|
|
165
|
+
*/
|
|
166
|
+
getState() {
|
|
167
|
+
return this.state;
|
|
168
|
+
}
|
|
169
|
+
// ============================================================================
|
|
170
|
+
// Main Operations
|
|
171
|
+
// ============================================================================
|
|
172
|
+
/**
|
|
173
|
+
* Generate PR preview without creating
|
|
174
|
+
* Works in both offline and full modes
|
|
175
|
+
*
|
|
176
|
+
* @see REQ-CG-v234-001
|
|
177
|
+
* @see DES-CG-v234-001
|
|
178
|
+
*/
|
|
179
|
+
previewSuggestion(suggestion) {
|
|
180
|
+
this.ensureState('offline', 'full');
|
|
181
|
+
const branchName = generateBranchName(suggestion);
|
|
182
|
+
const commitMessage = generateCommitMessage(suggestion);
|
|
183
|
+
const title = this.templateGenerator.generateTitle(suggestion);
|
|
184
|
+
const diffs = this.applier.preview(suggestion);
|
|
185
|
+
const body = this.templateGenerator.generate(suggestion, diffs);
|
|
186
|
+
const baseBranch = this.git.getDefaultBranch();
|
|
187
|
+
return {
|
|
188
|
+
branchName,
|
|
189
|
+
baseBranch,
|
|
190
|
+
title,
|
|
191
|
+
body,
|
|
192
|
+
diffs,
|
|
193
|
+
commitMessage,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Create a PR from a refactoring suggestion
|
|
198
|
+
* Requires full initialization (GitHub authentication)
|
|
199
|
+
*
|
|
200
|
+
* @see REQ-CG-PR-002, REQ-CG-PR-003, REQ-CG-PR-004, REQ-CG-PR-005
|
|
201
|
+
*/
|
|
202
|
+
async create(options) {
|
|
203
|
+
this.ensureState('full');
|
|
204
|
+
const { suggestion, dryRun } = options;
|
|
205
|
+
const warnings = [];
|
|
206
|
+
try {
|
|
207
|
+
this.emit('pr:start', { suggestion });
|
|
208
|
+
// Generate branch name
|
|
209
|
+
const branchName = options.branchName ?? generateBranchName(suggestion);
|
|
210
|
+
// Check for uncommitted changes
|
|
211
|
+
if (this.git.hasUncommittedChanges()) {
|
|
212
|
+
warnings.push('Repository has uncommitted changes. They will be stashed.');
|
|
213
|
+
this.git.stash('musubix-pr-creator-auto-stash');
|
|
214
|
+
}
|
|
215
|
+
// Dry run mode - just preview
|
|
216
|
+
if (dryRun) {
|
|
217
|
+
return this.dryRun(options, branchName);
|
|
218
|
+
}
|
|
219
|
+
// Determine base branch
|
|
220
|
+
const baseBranch = options.baseBranch ?? this.git.getDefaultBranch();
|
|
221
|
+
// Create and checkout new branch
|
|
222
|
+
this.emit('pr:branch', { name: branchName });
|
|
223
|
+
this.git.createBranch(branchName, baseBranch);
|
|
224
|
+
// Apply refactoring changes
|
|
225
|
+
const diffs = this.applier.preview(suggestion);
|
|
226
|
+
for (const diff of diffs) {
|
|
227
|
+
this.emit('pr:applying', { file: diff.filePath, changes: 1 });
|
|
228
|
+
}
|
|
229
|
+
const applyResult = this.applier.apply(suggestion);
|
|
230
|
+
if (!applyResult.success) {
|
|
231
|
+
// Rollback branch
|
|
232
|
+
this.git.checkout(this.originalBranch);
|
|
233
|
+
this.git.deleteBranch(branchName, true);
|
|
234
|
+
return {
|
|
235
|
+
success: false,
|
|
236
|
+
branchName,
|
|
237
|
+
filesChanged: [],
|
|
238
|
+
linesAdded: 0,
|
|
239
|
+
linesDeleted: 0,
|
|
240
|
+
error: `Failed to apply changes: ${applyResult.error}`,
|
|
241
|
+
warnings,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
// Stage all changes
|
|
245
|
+
this.git.stageAll();
|
|
246
|
+
// Generate commit message
|
|
247
|
+
const commitMessage = generateCommitMessage(suggestion);
|
|
248
|
+
// Commit
|
|
249
|
+
const commitInfo = this.git.commit(commitMessage);
|
|
250
|
+
this.emit('pr:commit', { hash: commitInfo.hash, message: commitMessage });
|
|
251
|
+
// Push to remote
|
|
252
|
+
this.emit('pr:push', { branch: branchName, remote: this.config.remote });
|
|
253
|
+
this.git.push({ setUpstream: true });
|
|
254
|
+
// Generate PR body
|
|
255
|
+
const prTitle = options.title ?? this.templateGenerator.generateTitle(suggestion);
|
|
256
|
+
const prBody = options.body ?? this.templateGenerator.generate(suggestion, diffs);
|
|
257
|
+
// Create PR
|
|
258
|
+
const pr = await this.github.createPullRequest({
|
|
259
|
+
title: prTitle,
|
|
260
|
+
body: prBody,
|
|
261
|
+
head: branchName,
|
|
262
|
+
base: baseBranch,
|
|
263
|
+
draft: options.draft,
|
|
264
|
+
});
|
|
265
|
+
this.emit('pr:created', { pr });
|
|
266
|
+
// Add labels, assignees, reviewers
|
|
267
|
+
if (options.labels && options.labels.length > 0) {
|
|
268
|
+
await this.github.addLabels(pr.number, options.labels);
|
|
269
|
+
}
|
|
270
|
+
if (options.assignees && options.assignees.length > 0) {
|
|
271
|
+
await this.github.addAssignees(pr.number, options.assignees);
|
|
272
|
+
}
|
|
273
|
+
if (options.reviewers && options.reviewers.length > 0) {
|
|
274
|
+
await this.github.addReviewers(pr.number, options.reviewers);
|
|
275
|
+
}
|
|
276
|
+
// Calculate stats
|
|
277
|
+
const stats = this.git.getDiffStats(baseBranch);
|
|
278
|
+
const result = {
|
|
279
|
+
success: true,
|
|
280
|
+
pr,
|
|
281
|
+
branchName,
|
|
282
|
+
commitHash: commitInfo.hash,
|
|
283
|
+
filesChanged: applyResult.filesModified,
|
|
284
|
+
linesAdded: stats.additions,
|
|
285
|
+
linesDeleted: stats.deletions,
|
|
286
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
287
|
+
};
|
|
288
|
+
this.emit('pr:complete', { result });
|
|
289
|
+
// Switch back to original branch
|
|
290
|
+
this.git.checkout(this.originalBranch);
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
295
|
+
this.emit('pr:error', { error: error, stage: 'create' });
|
|
296
|
+
// Attempt cleanup
|
|
297
|
+
try {
|
|
298
|
+
if (this.git && this.originalBranch) {
|
|
299
|
+
const currentBranch = this.git.getCurrentBranch();
|
|
300
|
+
if (currentBranch !== this.originalBranch) {
|
|
301
|
+
this.git.checkout(this.originalBranch);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
// Ignore cleanup errors
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
success: false,
|
|
310
|
+
branchName: options.branchName ?? generateBranchName(suggestion),
|
|
311
|
+
filesChanged: [],
|
|
312
|
+
linesAdded: 0,
|
|
313
|
+
linesDeleted: 0,
|
|
314
|
+
error: errorMessage,
|
|
315
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Preview PR creation without actually creating
|
|
321
|
+
* @see REQ-CG-PR-007
|
|
322
|
+
*/
|
|
323
|
+
async preview(options) {
|
|
324
|
+
this.ensureInitialized();
|
|
325
|
+
const { suggestion } = options;
|
|
326
|
+
const branchName = options.branchName ?? generateBranchName(suggestion);
|
|
327
|
+
const baseBranch = options.baseBranch ?? this.git.getDefaultBranch();
|
|
328
|
+
// Generate preview
|
|
329
|
+
const diffs = this.applier.preview(suggestion);
|
|
330
|
+
const title = options.title ?? this.templateGenerator.generateTitle(suggestion);
|
|
331
|
+
const body = options.body ?? this.templateGenerator.generate(suggestion, diffs);
|
|
332
|
+
const commitMessage = generateCommitMessage(suggestion);
|
|
333
|
+
return {
|
|
334
|
+
branchName,
|
|
335
|
+
baseBranch,
|
|
336
|
+
title,
|
|
337
|
+
body,
|
|
338
|
+
diffs,
|
|
339
|
+
commitMessage,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Validate a suggestion can be applied
|
|
344
|
+
*/
|
|
345
|
+
validate(suggestion) {
|
|
346
|
+
this.ensureInitialized();
|
|
347
|
+
const result = this.applier.canApply(suggestion);
|
|
348
|
+
return { valid: result.canApply, reason: result.reason };
|
|
349
|
+
}
|
|
350
|
+
// ============================================================================
|
|
351
|
+
// Private Helpers
|
|
352
|
+
// ============================================================================
|
|
353
|
+
/**
|
|
354
|
+
* Dry run implementation
|
|
355
|
+
*/
|
|
356
|
+
dryRun(options, branchName) {
|
|
357
|
+
const { suggestion } = options;
|
|
358
|
+
const baseBranch = options.baseBranch ?? this.git.getDefaultBranch();
|
|
359
|
+
// Generate preview
|
|
360
|
+
const diffs = this.applier.preview(suggestion);
|
|
361
|
+
const title = options.title ?? this.templateGenerator.generateTitle(suggestion);
|
|
362
|
+
const body = options.body ?? this.templateGenerator.generate(suggestion, diffs);
|
|
363
|
+
const commitMessage = generateCommitMessage(suggestion);
|
|
364
|
+
// Calculate stats from diffs
|
|
365
|
+
let linesAdded = 0;
|
|
366
|
+
let linesDeleted = 0;
|
|
367
|
+
for (const diff of diffs) {
|
|
368
|
+
linesAdded += diff.additions;
|
|
369
|
+
linesDeleted += diff.deletions;
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
success: true,
|
|
373
|
+
branchName,
|
|
374
|
+
filesChanged: diffs.map(d => d.filePath),
|
|
375
|
+
linesAdded,
|
|
376
|
+
linesDeleted,
|
|
377
|
+
preview: {
|
|
378
|
+
branchName,
|
|
379
|
+
baseBranch,
|
|
380
|
+
title,
|
|
381
|
+
body,
|
|
382
|
+
diffs,
|
|
383
|
+
commitMessage,
|
|
384
|
+
},
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Ensure initialized before operations (legacy)
|
|
389
|
+
* @deprecated Use ensureState() instead
|
|
390
|
+
*/
|
|
391
|
+
ensureInitialized() {
|
|
392
|
+
if (!this.initialized) {
|
|
393
|
+
throw PRCreatorError.fromCode('NOT_INITIALIZED');
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Ensure PRCreator is in one of the allowed states
|
|
398
|
+
* @see DES-CG-v234-003
|
|
399
|
+
*/
|
|
400
|
+
ensureState(...allowed) {
|
|
401
|
+
if (!allowed.includes(this.state)) {
|
|
402
|
+
if (this.state === 'uninitialized') {
|
|
403
|
+
throw PRCreatorError.fromCode('NOT_INITIALIZED');
|
|
404
|
+
}
|
|
405
|
+
else if (this.state === 'offline' && allowed.includes('full')) {
|
|
406
|
+
throw PRCreatorError.fromCode('OFFLINE_MODE');
|
|
407
|
+
}
|
|
408
|
+
throw PRCreatorError.fromCode('NOT_INITIALIZED');
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
// ============================================================================
|
|
412
|
+
// Event Typing
|
|
413
|
+
// ============================================================================
|
|
414
|
+
/**
|
|
415
|
+
* Typed event emitter methods
|
|
416
|
+
*/
|
|
417
|
+
emit(event, data) {
|
|
418
|
+
return super.emit(event, data);
|
|
419
|
+
}
|
|
420
|
+
on(event, listener) {
|
|
421
|
+
return super.on(event, listener);
|
|
422
|
+
}
|
|
423
|
+
once(event, listener) {
|
|
424
|
+
return super.once(event, listener);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Create a PRCreator instance
|
|
429
|
+
*/
|
|
430
|
+
export function createPRCreator(repoPath, options) {
|
|
431
|
+
return new PRCreator({
|
|
432
|
+
repoPath,
|
|
433
|
+
...options,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Quick PR creation helper
|
|
438
|
+
*
|
|
439
|
+
* One-shot function to create a PR from a suggestion.
|
|
440
|
+
*
|
|
441
|
+
* @example
|
|
442
|
+
* ```typescript
|
|
443
|
+
* const result = await createRefactoringPR(
|
|
444
|
+
* '/path/to/repo',
|
|
445
|
+
* suggestion,
|
|
446
|
+
* { labels: ['refactoring'] }
|
|
447
|
+
* );
|
|
448
|
+
* ```
|
|
449
|
+
*/
|
|
450
|
+
export async function createRefactoringPR(repoPath, suggestion, options) {
|
|
451
|
+
const creator = createPRCreator(repoPath);
|
|
452
|
+
const initResult = await creator.initialize();
|
|
453
|
+
if (!initResult.success) {
|
|
454
|
+
return {
|
|
455
|
+
success: false,
|
|
456
|
+
branchName: generateBranchName(suggestion),
|
|
457
|
+
filesChanged: [],
|
|
458
|
+
linesAdded: 0,
|
|
459
|
+
linesDeleted: 0,
|
|
460
|
+
error: initResult.error,
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
return creator.create({
|
|
464
|
+
suggestion,
|
|
465
|
+
...options,
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
//# sourceMappingURL=pr-creator.js.map
|