From 16b2759ad7de5583c7d1a38b9ca42ab06f1500e8 Mon Sep 17 00:00:00 2001 From: ytori Date: Thu, 26 Sep 2024 00:33:30 +0900 Subject: [PATCH] script for pr --- .github/workflows/konjacbot.yml | 3 + package.json | 3 +- scripts/konjacbot/configs.mts | 1 + scripts/konjacbot/pr.mts | 126 ++++++++++++++++++++++++++++++++ scripts/konjacbot/utils.mts | 5 +- 5 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 scripts/konjacbot/pr.mts diff --git a/.github/workflows/konjacbot.yml b/.github/workflows/konjacbot.yml index c29d4256..0d6ff887 100644 --- a/.github/workflows/konjacbot.yml +++ b/.github/workflows/konjacbot.yml @@ -20,3 +20,6 @@ jobs: env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - run: npm run kj:img + - run: npm run kj:pr + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} diff --git a/package.json b/package.json index 9f800b98..d49f0cda 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "lint:docs": "textlint --fix docs/**", "kj:diff": "tsx ./scripts/konjacbot/diff.mts -o .kj-diff.txt", "kj:ja": "tsx ./scripts/konjacbot/translate.mts -l ja .kj-diff.txt", - "kj:img": "tsx ./scripts/konjacbot/dlimg.mts .kj-diff.txt" + "kj:img": "tsx ./scripts/konjacbot/dlimg.mts .kj-diff.txt", + "kj:pr": "tsx ./scripts/konjacbot/pr.mts" }, "dependencies": { "@docusaurus/core": "^3.5.2", diff --git a/scripts/konjacbot/configs.mts b/scripts/konjacbot/configs.mts index e82bbb7c..4eabe5fc 100644 --- a/scripts/konjacbot/configs.mts +++ b/scripts/konjacbot/configs.mts @@ -1,6 +1,7 @@ import path from 'node:path' export const configs = { + botName: 'konjacbot', projectRootDir: path.normalize(`${import.meta.dirname}/../..`), submoduleName: 'next.js', docsDir: 'docs', diff --git a/scripts/konjacbot/pr.mts b/scripts/konjacbot/pr.mts new file mode 100644 index 00000000..bd52de9f --- /dev/null +++ b/scripts/konjacbot/pr.mts @@ -0,0 +1,126 @@ +import { $ } from 'zx' +import process from 'node:process' +import OpenAI from 'openai' +import * as path from 'node:path' +import { configs } from './configs.mts' +import { createLogger } from './utils.mts' +import { basename } from 'node:path' + +/* + * definitions + */ +const defaults = { + apiKey: process.env.OPENAI_API_KEY, + label: configs.botName, + branchPrefix: `${configs.botName}/sync-nextjs-docs`, + nextjs: { + github: 'https://github.com/vercel/next.js', + web: 'https://nextjs.org/docs', + }, +} as const + +const log = createLogger(basename(import.meta.url)) + +async function buildNextJsGithubUrl() { + const diff = (await $`git diff HEAD^ -- ${configs.submoduleName}`).text() + const hash = { + before: diff.match(/^-Subproject commit ([0-9a-zA-Z]+)$/m)?.[1], + after: diff.match(/^\+Subproject commit ([0-9a-zA-Z]+)$/m)?.[1], + } + + if (!hash.before || !hash.after) { + throw Error('failed to resolve submodule commit diffs.') + } + + const nextjsGithubBaseUrl = new URL(defaults.nextjs.github) + const comparePath = path.join( + nextjsGithubBaseUrl.pathname, + `compare/${hash.before.substring(0, 7)}..${hash.after.substring(0, 7)}` + ) + const treePath = path.join(nextjsGithubBaseUrl.pathname, `tree/${hash.after}`) + + const compareUrl = new URL(comparePath, nextjsGithubBaseUrl.origin).toString() + const treeUrl = new URL(treePath, nextjsGithubBaseUrl.origin).toString() + + return { + compare: { + label: `${hash.before.substring(0, 7)}..${hash.after.substring(0, 7)}`, + url: compareUrl, + }, + tree: { + label: `${hash.after}`, + url: treeUrl, + }, + } +} + +/* + * entry point + */ + +log('important', '🚀 pr creation started !') + +//変更が無かったらその時点で終了 +const status = (await $`git status -s`).text() + +if (!status.trim()) { + log('important', '✅ No update found. exit without PR.') + process.exit(0) +} + +//ブランチ切ってpush +const submodule = (await $`git submodule`).text() +const hash = { + short: submodule.trim().substring(0, 7), + long: submodule.trim().substring(0, 40), +} as const +const branch = `${defaults.branchPrefix}-${hash.short}` + +await $`git checkout -b ${branch}` +await $`git add .` +await $`git commit -a -m "translate next.js @ ${hash.short} into Japanese."` +await $`git push origin ${branch}` + +const diff = (await $`git diff HEAD^`).text() +const openai = new OpenAI({ + apiKey: defaults.apiKey, +}) + +const result = await openai.chat.completions.create({ + model: 'gpt-4o', + messages: [ + { + role: 'system', + content: + 'これから入力する内容は、Gitリポジトリのdiffコマンドの実行結果です。変更内容の要約を作成してください。', + }, + { role: 'user', content: diff }, + ], + stream: false, +}) + +if (result.choices.length !== 1) { + throw new Error( + `invalid OpenAI translation result: ${JSON.stringify(result)}` + ) +} +const diffSummary = result.choices[0].message.content + +//PR作成 +//TODO 既にPRが出ている場合の考慮 +const nextjsGitHubUrl = await buildNextJsGithubUrl() + +const title = `${configs.botName}: translated Next.js docs @ ${hash.short} into Japanese` +const body = ` +# 翻訳した公式ドキュメントバージョン +[${nextjsGitHubUrl.tree.label}](${nextjsGitHubUrl.tree.url}) + +# 翻訳した公式ドキュメントの変更点 +[${nextjsGitHubUrl.compare.label}](${nextjsGitHubUrl.compare.url}) + +# 本PRの更新内容のサマリ by ChatGPT🤖 +${diffSummary} +` +await $`gh pr create -B main -t ${title} -b ${body} -l ${defaults.label}` + +log('important', '✅ PR created successfully !') diff --git a/scripts/konjacbot/utils.mts b/scripts/konjacbot/utils.mts index 34cfcfda..dffa504b 100644 --- a/scripts/konjacbot/utils.mts +++ b/scripts/konjacbot/utils.mts @@ -151,6 +151,9 @@ export function createLogger(prefix: string) { return (type: 'normal' | 'important' | 'error', ...data: unknown[]): void => { const [message, ...others] = data - console.log(palette[type](`[konjacbot:${prefix}] ${message}`), ...others) + console.log( + palette[type](`[${configs.botName}:${prefix}] ${message}`), + ...others + ) } }