Files
ts-scripts/single-scripts/commit.ts

128 lines
4.0 KiB
TypeScript
Executable File

#!/usr/bin/env runts -- --allow-all
import {parseArgs} from "jsr:@std/cli/parse-args";
import {execCommandShell, log, ProcessBar, term,} from "https://script.hatter.ink/@61/deno-commons-mod.ts";
import {summarizeGitStatusDiff} from "https://script.hatter.ink/@4/deno-ai-mod.ts";
import {getGitLocalRev, getGitRemoteRev, getGitStatus,} from "https://script.hatter.ink/@2/deno-git-mod.ts";
async function checkRev(): Promise<boolean> {
const localRev = await getGitLocalRev();
const remoteRev = await new ProcessBar("Checking rev").call(
async (): Promise<string> => {
return await getGitRemoteRev();
},
);
if (localRev === remoteRev) {
console.log(term.green(`Check rev successfully, rev: ${localRev}`));
} else {
throw `Check rev failed, local rev: ${localRev} vs remote rev: ${remoteRev}`;
}
}
async function main() {
const flags = parseArgs(Deno.args, {
boolean: ["help", "check-only", "auto-commit"],
string: ["timeout-ms"],
alias: {
h: "help",
C: "check-only",
A: "auto-commit",
t: "timeout-ms",
},
});
const checkOnly = flags["check-only"];
const autoCommit = flags["auto-commit"];
const argTimeoutMs = flags["timeout-ms"];
const timeoutMillis: number | undefined = argTimeoutMs
? parseInt(argTimeoutMs)
: undefined;
if (flags.help) {
console.log(`commit.ts
commit.ts [-h|--help] - show help message
commit.ts [-C|--check-only] - check rev and status only
commit.ts [-A|--auto-commit] - auto commit with AI summarize
`);
return;
}
await checkRev(); // check local rev <--> remote rev equals
const gitStatus = await getGitStatus();
if (gitStatus === null) {
log.warn("No git status found");
return;
}
log.info("Git status:", gitStatus);
if (checkOnly) {
log.info("Check only, skip commit.");
return;
}
const summary = await new ProcessBar("AI summarizing").call(
async (): Promise<string> => {
return await summarizeGitStatusDiff(timeoutMillis ?? 60000);
},
);
if (summary != null) {
log.success(`AI summarized git commit message: ${summary}`);
}
let emptyCount = 0;
let message = "empty message";
if (autoCommit && summary) {
message = summary;
} else {
do {
if (emptyCount++ === 3) {
readline.close();
console.log("Too many empty messages, then exit");
return;
}
message = prompt(
"Input your commit message (Enter for AI summary) > ",
);
if (message.trim().length == 0) {
message = summary ?? "";
}
} while (message.length == 0);
}
const gitCommitArgs: string[] = [];
gitCommitArgs.push("commit");
for (const file of gitStatus.modified) {
gitCommitArgs.push(file);
}
for (const file of gitStatus.deleted) {
gitCommitArgs.push(file);
}
for (const file of gitStatus.untracked) {
gitCommitArgs.push(file);
}
gitCommitArgs.push("-m");
gitCommitArgs.push(message);
if (gitStatus.untracked.length > 0) {
const gitAddArgs = ["add"];
for (const file of gitStatus.untracked) {
gitAddArgs.push(file);
}
log.info(">>>>>", ["git", gitAddArgs]);
await execCommandShell("git", gitAddArgs);
}
log.info(">>>>>", ["git", gitCommitArgs]);
await execCommandShell("git", gitCommitArgs);
log.info(">>>>>", ["git", "push"]);
await new ProcessBar("Git pushing").call(async (): Promise<void> => {
await execCommandShell("git", ["push"]);
});
}
main().catch((err) => {
log.error(err);
process.exit(0);
}).then(() => process.exit(0));
// @SCRIPT-SIGNATURE-V1: yk-r1.ES256.20260427T004243+08:00.MEUCICgYmTET6yvrTnmBhYTk
// nNyYQbwTvbf4CHHx0MaRAeYPAiEAxycT0JiWsxRdAl3BcuIld8nwFvwkEh+eT51qEaY23zk=