Skip to content

Commit c107078

Browse files
authored
Merge pull request #485 from frauniki/add-prettier-ci
chore: Add Prettier format check to CI and format code
2 parents 1f0f44e + 45aed93 commit c107078

File tree

13 files changed

+153
-112
lines changed

13 files changed

+153
-112
lines changed

.github/workflows/test.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,21 @@ jobs:
5151
run: npm run build
5252
- name: Run E2E Tests
5353
run: npm run test:e2e
54+
prettier:
55+
runs-on: ubuntu-latest
56+
steps:
57+
- uses: actions/checkout@v4
58+
- name: Use Node.js
59+
uses: actions/setup-node@v4
60+
with:
61+
node-version: '20.x'
62+
cache: 'npm'
63+
- name: Install dependencies
64+
run: npm ci
65+
- name: Run Prettier
66+
run: npm run format:check
67+
- name: Prettier Output
68+
if: failure()
69+
run: |
70+
echo "Prettier check failed. Please run 'npm run format' to fix formatting issues."
71+
exit 1

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"deploy:patch": "npm version patch && npm run deploy:build",
5252
"lint": "eslint src --ext ts && tsc --noEmit",
5353
"format": "prettier --write src",
54+
"format:check": "prettier --check src",
5455
"test": "node --no-warnings --experimental-vm-modules $( [ -f ./node_modules/.bin/jest ] && echo ./node_modules/.bin/jest || which jest ) test/unit",
5556
"test:all": "npm run test:unit:docker && npm run test:e2e:docker",
5657
"test:docker-build": "docker build -t oco-test -f test/Dockerfile .",

src/engine/azure.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export class AzureEngine implements AiEngine {
5353
if (message?.content === null) {
5454
return undefined;
5555
}
56-
56+
5757
let content = message?.content;
5858
return removeContentTags(content, 'think');
5959
} catch (error) {

src/engine/groq.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ export class GroqEngine extends OpenAiEngine {
77
config.baseURL = 'https://api.groq.com/openai/v1';
88
super(config);
99
}
10-
}
10+
}

src/engine/mistral.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ export class MistralAiEngine implements AiEngine {
2323
if (!config.baseURL) {
2424
this.client = new Mistral({ apiKey: config.apiKey });
2525
} else {
26-
this.client = new Mistral({ apiKey: config.apiKey, serverURL: config.baseURL });
26+
this.client = new Mistral({
27+
apiKey: config.apiKey,
28+
serverURL: config.baseURL
29+
});
2730
}
2831
}
2932

@@ -50,13 +53,12 @@ export class MistralAiEngine implements AiEngine {
5053

5154
const completion = await this.client.chat.complete(params);
5255

53-
if (!completion.choices)
54-
throw Error('No completion choice available.')
55-
56+
if (!completion.choices) throw Error('No completion choice available.');
57+
5658
const message = completion.choices[0].message;
5759

5860
if (!message || !message.content)
59-
throw Error('No completion choice available.')
61+
throw Error('No completion choice available.');
6062

6163
let content = message.content as string;
6264
return removeContentTags(content, 'think');

src/engine/mlx.ts

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,42 +6,42 @@ import { AiEngine, AiEngineConfig } from './Engine';
66
interface MLXConfig extends AiEngineConfig {}
77

88
export class MLXEngine implements AiEngine {
9-
config: MLXConfig;
10-
client: AxiosInstance;
9+
config: MLXConfig;
10+
client: AxiosInstance;
1111

12-
constructor(config) {
13-
this.config = config;
14-
this.client = axios.create({
15-
url: config.baseURL
16-
? `${config.baseURL}/${config.apiKey}`
17-
: 'http://localhost:8080/v1/chat/completions',
18-
headers: { 'Content-Type': 'application/json' }
19-
});
20-
}
12+
constructor(config) {
13+
this.config = config;
14+
this.client = axios.create({
15+
url: config.baseURL
16+
? `${config.baseURL}/${config.apiKey}`
17+
: 'http://localhost:8080/v1/chat/completions',
18+
headers: { 'Content-Type': 'application/json' }
19+
});
20+
}
21+
22+
async generateCommitMessage(
23+
messages: Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>
24+
): Promise<string | undefined> {
25+
const params = {
26+
messages,
27+
temperature: 0,
28+
top_p: 0.1,
29+
repetition_penalty: 1.5,
30+
stream: false
31+
};
32+
try {
33+
const response = await this.client.post(
34+
this.client.getUri(this.config),
35+
params
36+
);
2137

22-
async generateCommitMessage(
23-
messages: Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>):
24-
Promise<string | undefined> {
25-
const params = {
26-
messages,
27-
temperature: 0,
28-
top_p: 0.1,
29-
repetition_penalty: 1.5,
30-
stream: false
31-
};
32-
try {
33-
const response = await this.client.post(
34-
this.client.getUri(this.config),
35-
params
36-
);
37-
38-
const choices = response.data.choices;
39-
const message = choices[0].message;
40-
let content = message?.content;
41-
return removeContentTags(content, 'think');
42-
} catch (err: any) {
43-
const message = err.response?.data?.error ?? err.message;
44-
throw new Error(`MLX provider error: ${message}`);
45-
}
46-
}
38+
const choices = response.data.choices;
39+
const message = choices[0].message;
40+
let content = message?.content;
41+
return removeContentTags(content, 'think');
42+
} catch (err: any) {
43+
const message = err.response?.data?.error ?? err.message;
44+
throw new Error(`MLX provider error: ${message}`);
45+
}
46+
}
4747
}

src/engine/ollama.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ export class OllamaEngine implements AiEngine {
1111

1212
constructor(config) {
1313
this.config = config;
14-
14+
1515
// Combine base headers with custom headers
16-
const headers = {
16+
const headers = {
1717
'Content-Type': 'application/json',
18-
...config.customHeaders
18+
...config.customHeaders
1919
};
20-
20+
2121
this.client = axios.create({
2222
url: config.baseURL
2323
? `${config.baseURL}/${config.apiKey}`

src/engine/openAi.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@ export class OpenAiEngine implements AiEngine {
1818
const clientOptions: OpenAI.ClientOptions = {
1919
apiKey: config.apiKey
2020
};
21-
21+
2222
if (config.baseURL) {
2323
clientOptions.baseURL = config.baseURL;
2424
}
25-
25+
2626
if (config.customHeaders) {
2727
const headers = parseCustomHeaders(config.customHeaders);
2828
if (Object.keys(headers).length > 0) {
2929
clientOptions.defaultHeaders = headers;
3030
}
3131
}
32-
32+
3333
this.client = new OpenAI(clientOptions);
3434
}
3535

@@ -54,7 +54,7 @@ export class OpenAiEngine implements AiEngine {
5454
this.config.maxTokensInput - this.config.maxTokensOutput
5555
)
5656
throw new Error(GenerateCommitMessageErrorEnum.tooMuchTokens);
57-
57+
5858
const completion = await this.client.chat.completions.create(params);
5959

6060
const message = completion.choices[0].message;

src/generateCommitMessageFromGitDiff.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ const generateCommitMessageChatCompletionPrompt = async (
1414
fullGitMojiSpec: boolean,
1515
context: string
1616
): Promise<Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>> => {
17-
const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec, context);
17+
const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(
18+
fullGitMojiSpec,
19+
context
20+
);
1821

1922
const chatContextAsCompletionRequest = [...INIT_MESSAGES_PROMPT];
2023

@@ -38,7 +41,7 @@ const ADJUSTMENT_FACTOR = 20;
3841
export const generateCommitMessageByDiff = async (
3942
diff: string,
4043
fullGitMojiSpec: boolean = false,
41-
context: string = ""
44+
context: string = ''
4245
): Promise<string> => {
4346
try {
4447
const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(
@@ -75,7 +78,7 @@ export const generateCommitMessageByDiff = async (
7578
const messages = await generateCommitMessageChatCompletionPrompt(
7679
diff,
7780
fullGitMojiSpec,
78-
context,
81+
context
7982
);
8083

8184
const engine = getEngine();

src/modules/commitlint/prompts.ts

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -56,28 +56,30 @@ const llmReadableRules: {
5656
blankline: (key, applicable) =>
5757
`There should ${applicable} be a blank line at the beginning of the ${key}.`,
5858
caseRule: (key, applicable, value: string | Array<string>) =>
59-
`The ${key} should ${applicable} be in ${Array.isArray(value)
60-
? `one of the following case:
59+
`The ${key} should ${applicable} be in ${
60+
Array.isArray(value)
61+
? `one of the following case:
6162
- ${value.join('\n - ')}.`
62-
: `${value} case.`
63+
: `${value} case.`
6364
}`,
6465
emptyRule: (key, applicable) => `The ${key} should ${applicable} be empty.`,
6566
enumRule: (key, applicable, value: string | Array<string>) =>
6667
`The ${key} should ${applicable} be one of the following values:
6768
- ${Array.isArray(value) ? value.join('\n - ') : value}.`,
6869
enumTypeRule: (key, applicable, value: string | Array<string>, prompt) =>
6970
`The ${key} should ${applicable} be one of the following values:
70-
- ${Array.isArray(value)
71+
- ${
72+
Array.isArray(value)
7173
? value
72-
.map((v) => {
73-
const description = getTypeRuleExtraDescription(v, prompt);
74-
if (description) {
75-
return `${v} (${description})`;
76-
} else return v;
77-
})
78-
.join('\n - ')
74+
.map((v) => {
75+
const description = getTypeRuleExtraDescription(v, prompt);
76+
if (description) {
77+
return `${v} (${description})`;
78+
} else return v;
79+
})
80+
.join('\n - ')
7981
: value
80-
}.`,
82+
}.`,
8183
fullStopRule: (key, applicable, value: string) =>
8284
`The ${key} should ${applicable} end with '${value}'.`,
8385
maxLengthRule: (key, applicable, value: string) =>
@@ -214,16 +216,20 @@ const STRUCTURE_OF_COMMIT = config.OCO_OMIT_SCOPE
214216
const GEN_COMMITLINT_CONSISTENCY_PROMPT = (
215217
prompts: string[]
216218
): OpenAI.Chat.Completions.ChatCompletionMessageParam[] => [
217-
{
218-
role: 'system',
219-
content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages for two different changes in a single codebase and output them in the provided JSON format: one for a bug fix and another for a new feature.
219+
{
220+
role: 'system',
221+
content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages for two different changes in a single codebase and output them in the provided JSON format: one for a bug fix and another for a new feature.
220222
221223
Here are the specific requirements and conventions that should be strictly followed:
222224
223225
Commit Message Conventions:
224226
- The commit message consists of three parts: Header, Body, and Footer.
225227
- Header:
226-
- Format: ${config.OCO_OMIT_SCOPE ? '`<type>: <subject>`' : '`<type>(<scope>): <subject>`'}
228+
- Format: ${
229+
config.OCO_OMIT_SCOPE
230+
? '`<type>: <subject>`'
231+
: '`<type>(<scope>): <subject>`'
232+
}
227233
- ${prompts.join('\n- ')}
228234
229235
JSON Output Format:
@@ -246,9 +252,9 @@ Additional Details:
246252
- Allowing the server to listen on a port specified through the environment variable is considered a new feature.
247253
248254
Example Git Diff is to follow:`
249-
},
250-
INIT_DIFF_PROMPT
251-
];
255+
},
256+
INIT_DIFF_PROMPT
257+
];
252258

253259
/**
254260
* Prompt to have LLM generate a message using @commitlint rules.
@@ -262,25 +268,30 @@ const INIT_MAIN_PROMPT = (
262268
prompts: string[]
263269
): OpenAI.Chat.Completions.ChatCompletionMessageParam => ({
264270
role: 'system',
265-
content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages in the given @commitlint convention and explain WHAT were the changes ${config.OCO_WHY ? 'and WHY the changes were done' : ''
266-
}. I'll send you an output of 'git diff --staged' command, and you convert it into a commit message.
267-
${config.OCO_EMOJI
268-
? 'Use GitMoji convention to preface the commit.'
269-
: 'Do not preface the commit with anything.'
270-
}
271-
${config.OCO_DESCRIPTION
272-
? 'Add a short description of WHY the changes are done after the commit message. Don\'t start it with "This commit", just describe the changes.'
273-
: "Don't add any descriptions to the commit, only commit message."
274-
}
271+
content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages in the given @commitlint convention and explain WHAT were the changes ${
272+
config.OCO_WHY ? 'and WHY the changes were done' : ''
273+
}. I'll send you an output of 'git diff --staged' command, and you convert it into a commit message.
274+
${
275+
config.OCO_EMOJI
276+
? 'Use GitMoji convention to preface the commit.'
277+
: 'Do not preface the commit with anything.'
278+
}
279+
${
280+
config.OCO_DESCRIPTION
281+
? 'Add a short description of WHY the changes are done after the commit message. Don\'t start it with "This commit", just describe the changes.'
282+
: "Don't add any descriptions to the commit, only commit message."
283+
}
275284
Use the present tense. Use ${language} to answer.
276-
${config.OCO_ONE_LINE_COMMIT
277-
? 'Craft a concise commit message that encapsulates all changes made, with an emphasis on the primary updates. If the modifications share a common theme or scope, mention it succinctly; otherwise, leave the scope out to maintain focus. The goal is to provide a clear and unified overview of the changes in a one single message, without diverging into a list of commit per file change.'
278-
: ''
279-
}
280-
${config.OCO_OMIT_SCOPE
281-
? 'Do not include a scope in the commit message format. Use the format: <type>: <subject>'
282-
: ''
283-
}
285+
${
286+
config.OCO_ONE_LINE_COMMIT
287+
? 'Craft a concise commit message that encapsulates all changes made, with an emphasis on the primary updates. If the modifications share a common theme or scope, mention it succinctly; otherwise, leave the scope out to maintain focus. The goal is to provide a clear and unified overview of the changes in a one single message, without diverging into a list of commit per file change.'
288+
: ''
289+
}
290+
${
291+
config.OCO_OMIT_SCOPE
292+
? 'Do not include a scope in the commit message format. Use the format: <type>: <subject>'
293+
: ''
294+
}
284295
You will strictly follow the following conventions to generate the content of the commit message:
285296
- ${prompts.join('\n- ')}
286297

src/modules/commitlint/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const getJSONBlock = (input: string): string => {
2121
if (jsonIndex > -1) {
2222
input = input.slice(jsonIndex + 8);
2323
const endJsonIndex = input.search('```');
24-
input = input.slice(0, endJsonIndex);
24+
input = input.slice(0, endJsonIndex);
2525
}
2626
return input;
2727
};

0 commit comments

Comments
 (0)