diff --git a/packages/backend/src/routes/repos.ts b/packages/backend/src/routes/repos.ts index f2e38af..701fa52 100644 --- a/packages/backend/src/routes/repos.ts +++ b/packages/backend/src/routes/repos.ts @@ -9,6 +9,7 @@ import { commitFiles, push, getDiff, + validateCommitMessage, } from "../services/git.service.js"; import type { RepoName } from "../config/repos.js"; @@ -88,6 +89,12 @@ router.post("/:repo/commit", async (req, res) => { if (body) fullMessage += `\n\n${body}`; if (issueRef) fullMessage += `\n\nFixes #${issueRef}`; + const validation = validateCommitMessage(fullMessage); + if (!validation.valid) { + res.status(400).json({ error: validation.error }); + return; + } + const repoPath = getRepoPath(repoName); const result = await commitFiles(repoPath, fullMessage, files); res.json(result); diff --git a/packages/backend/src/services/git.service.ts b/packages/backend/src/services/git.service.ts index fb505bf..0a50944 100644 --- a/packages/backend/src/services/git.service.ts +++ b/packages/backend/src/services/git.service.ts @@ -52,7 +52,25 @@ export async function pull(repoPath: string) { return g.pull(); } +const COMMIT_PATTERN = /^(feat|fix|refactor|docs|chore|test|style|perf|ci|build|revert)(\(.+\))?: .{1,100}$/; + +export function validateCommitMessage(message: string): { valid: boolean; error?: string } { + const firstLine = message.split("\n")[0]; + if (!COMMIT_PATTERN.test(firstLine)) { + return { + valid: false, + error: `Invalid format. Expected: type(scope): description. Valid types: feat, fix, refactor, docs, chore, test, style, perf, ci, build, revert`, + }; + } + return { valid: true }; +} + export async function commitFiles(repoPath: string, message: string, files?: string[]) { + const validation = validateCommitMessage(message); + if (!validation.valid) { + throw new Error(validation.error); + } + const g = git(repoPath); if (files && files.length > 0) { await g.add(files);