はじめに
前回は自己署名証明書を使ってkubernetesのingressでTLS通信ができるようにしました。
今回はkubernetesからは一旦逸れて、GithubAppを使ってコードを自動更新する仕組みを作っていこうと思います。
GithubAPIでブランチを作成してコミットするのは少し手順が複雑だったので、記事に手順を残します。
手順
GithubAppを作成
公式ドキュメントに従ってGithub Appを作成します。
GithubのSettings > Developer settings > Github Apps
から作成できます。設定は適当でいいですが、App名はGithub上で一意でなくてはなりません。
GithubAppの設定画面からClientSecretとPrivate Keyを作成し、メモしておきます。
Github Appをインストール
Settings > Developer Settings > Github Apps
から作成したGithub Appを選択し、Install AppからGithub Appをインストールします。
Octokitをセットアップ
まず、Octkit(https://github.com/octokit/octokit.js/?tab=readme-ov-file )をインストールします。
yarn add octkit
環境変数にAPP_ID
, PRIVATE_KEY
, CLIENT_ID
, CLIENT_SECRET
を設定し、次のように書きます。Githubではデフォルトでダウンロードできる秘密鍵がpkcs1形式のためpkcs8形式に変換する必要があります。
また、dotenvを使うと改行文字が\nという文字列に変換されてしまうため、replaceで元に戻しています。
const appId = process.env.APP_ID as string
const privateKey = (process.env.PRIVATE_KEY as string).replace(
/\\n/g,
'\n'
)
// octokitはpkcs8形式の秘密鍵を要求する
const privateKeyPkcs8 = crypto.createPrivateKey(privateKey).export({
type: 'pkcs8',
format: 'pem',
}) as string
const _octokit = new Octokit({
authStrategy: createAppAuth,
auth: {
appId,
privateKey: privateKeyPkcs8,
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
},
})
PullRequestの作成などにはInstallationとして認証をする必要があります。そのため、公式ドキュメントに従ってトークンを取得します。
const { data: installationData } = await _octokit.request(
'GET /repos/{owner}/{repo}/installation',
{
owner: process.env.REPOSITORY_OWNER,
repo: process.env.REPOSITORY_NAME,
}
)
const app = new App({
appId,
privateKey: privateKeyPkcs8,
})
const octokit = await app.getInstallationOctokit(installationData.id)
Commit, PRの作成
まず、分岐元のcommitを取得します。
const { data: branchesData } = await octokit.request(
'GET /repos/{owner}/{repo}/branches',
{
owner,
repo,
}
)
const masterBranch = branchesData.find((branch) => branch.name === process.env.BRANCH_NAME)
if (!masterBranch) throw new Error(`Branch ${process.env.BRANCH_NAME} not found`)
Commitを作成します。CommitはTreeを作成した後にCommitを作成します。
const { data: tree } = await octokit.request(
'POST /repos/{owner}/{repo}/git/trees',
{
owner,
repo,
tree: [
{
path: 'test.txt',
mode: '100644',
type: 'blob',
content: 'test',
},
],
base_tree: masterBranch.commit.sha,
}
)
const { data: commit } = await octokit.request(
'POST /repos/{owner}/{repo}/git/commits',
{
owner,
repo,
message: 'test',
tree: tree.sha,
parents: [masterBranch.commit.sha],
}
)
ブランチの作成
ブランチは、実体はCommitへのポインタなので、先ほど作成したCommitのハッシュを指定してrefを作成します。
const { data: ref } = await octokit.request(
'POST /repos/{owner}/{repo}/git/refs',
{
owner,
repo,
ref: `refs/heads/branch-${Date.now()}`,
sha: commit.sha,
}
)
Pull Requestの作成
最後にPull Requestを作成します。
const { data: pr } = await octokit.request(
'POST /repos/{owner}/{repo}/pulls',
{
owner,
repo,
title: 'test',
head: ref.ref,
base: branchName,
}
)
以上でPullRequestが作成されます。
最後に
今回はGithub Appを用いてコードを書き換えるPullRequestを作りました。次回は今回作ったGithubAppを用いて、Qiitaから記事をAPIで読み取ってポートフォリオを自動で更新する仕組みを作っていこうと思います。
参考資料