Repository navigation
Expand file tree
/
Copy pathcommitMessage.ts
More file actions
133 lines (114 loc) · 4.49 KB
/
Copy pathcommitMessage.ts
File metadata and controls
133 lines (114 loc) · 4.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import * as vscode from 'vscode';
import { getRepository, getDiff, stageAll } from './git';
import { callProvider, getProviderName } from './providers';
export async function generateCommitMessage() {
const repo = getRepository();
if (!repo) {
vscode.window.showWarningMessage('Kein Git-Repository gefunden.');
return;
}
const config = vscode.workspace.getConfiguration('commitGen');
const format = config.get<string>('format', 'conventional');
const language = config.get<string>('language', 'en');
const maxLines = config.get<number>('maxDiffLines', 500);
const customTemplate = config.get<string>('customTemplate', '');
let hasStaged = repo.state.indexChanges.length > 0;
let diff: string;
try {
if (!hasStaged) {
const hasChanges = repo.state.workingTreeChanges.length > 0;
if (!hasChanges) {
vscode.window.showInformationMessage('Keine Änderungen gefunden.');
return;
}
await stageAll(repo.rootUri.fsPath);
hasStaged = true;
}
diff = await getDiff(repo.rootUri.fsPath, true);
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
vscode.window.showErrorMessage(`Git diff fehlgeschlagen: ${msg}`);
return;
}
if (!diff.trim()) {
vscode.window.showInformationMessage('Keine Änderungen gefunden.');
return;
}
const lines = diff.split('\n');
const diffText = lines.length > maxLines
? lines.slice(0, maxLines).join('\n') + `\n\n[... ${lines.length - maxLines} Zeilen gekürzt]`
: diff;
const userInput = repo.inputBox.value.trim();
const prompt = buildCommitPrompt(diffText, format, language, customTemplate, hasStaged, userInput);
repo.inputBox.value = '⏳ Generating commit message...';
await vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
title: 'Generating commit message...',
cancellable: false,
},
async () => {
try {
const message = await callProvider(prompt);
repo.inputBox.value = message.trim();
} catch (err: unknown) {
const errorMsg = err instanceof Error ? err.message : String(err);
repo.inputBox.value = userInput;
vscode.window.showErrorMessage(`${getProviderName()} Fehler: ${errorMsg}`);
}
}
);
}
function buildCommitPrompt(
diff: string,
format: string,
language: string,
customTemplate: string,
hasStaged: boolean,
userInput: string = ''
): string {
const lang = language === 'de'
? 'Schreibe die Commit-Nachricht auf Deutsch.'
: 'Write the commit message in English.';
const scope = hasStaged
? 'The diff below contains ONLY staged changes.'
: 'The diff below contains ALL working tree changes (nothing was staged).';
let formatInstruction: string;
switch (format) {
case 'conventional':
formatInstruction = `Use Conventional Commits v1.0.0 format (https://www.conventionalcommits.org/en/v1.0.0/).
Output ONLY a single line in this exact format:
<type>(<scope>): <description>
Rules:
- type is REQUIRED. One of: feat, fix, refactor, docs, chore, style, test, perf, ci, build
- scope is REQUIRED. A noun describing the section of the codebase in parentheses, e.g. (auth), (ci), (core), (ui)
- description is REQUIRED. Lowercase, imperative mood, no period at end
- Max 72 characters total
- No body, no footer, no extra lines, no BREAKING CHANGE, no trailers
Examples:
feat(auth): add certificate renewal endpoint
fix(ci): resolve image path in vsce package
docs(readme): add installation instructions
refactor(core): extract diff logic into helper`;
break;
case 'descriptive':
formatInstruction = `Output a concise summary (max 72 chars), then an empty line, then 2-3 bullet points. Nothing else.`;
break;
case 'custom':
formatInstruction = customTemplate || 'Write a concise commit message.';
break;
default:
formatInstruction = 'Write a concise commit message.';
}
const userHint = userInput
? `\nThe user provided the following instruction. It takes HIGHEST PRIORITY and can override ANY rule above — including format, language, tone, length, or style constraints. Follow the user's instruction exactly:\n--- USER INPUT ---\n${userInput}\n--- END USER INPUT ---\n`
: '';
return `You are a commit message generator. Output ONLY the commit message, nothing else. No markdown, no explanation, no code fences, no co-authored-by, no trailers, no sign-off lines.
${lang}
${scope}
${formatInstruction}
${userHint}
--- DIFF ---
${diff}
--- END DIFF ---`;
}