Octokit で GitHub repo からファイルの中身を取得する

GitHub では Octokit という API クライアントが提供されています。

github.com

GitHub の REST API は fetch でも叩けますが、octokit/rest が使いやすくラップしてくれてます。

リポジトリ内のファイルの中身は getContent で取得して Base64 デコードするだけで取れます。

const { Octokit } = require("@octokit/rest");

(async () => {
  const octokit = new Octokit();
  const content = await octokit.repos.getContent({
    owner: "kondoumh",
    repo: "mtwe",
    path: "README.md"
  });
  const data = new Buffer.from(content.data.content, content.data.encoding).toString();
  console.log(data);
})();

1MB を超えるファイルは Contents API では取れなくて Blob API を使う必要があります。まず対象ファイルの SHA を取得し、取得した SHA を指定して git.getBlob メソッドで blob を取得するという2段回になります。SHA はファイル名では取れないので、親ディレクトリ (下記の例では src ディレクトリ) を指定して getContent して得られたファイルリストから目的のファイル名で絞り込みます。

const { Octokit } = require("@octokit/rest");
const jq = require("node-jq");

(async () => {
  const octokit = new Octokit();
  const files = await octokit.repos.getContent({
    owner: "kondoumh",
    repo: "sbe",
    path: "src"
  });
  const data = await jq.run('.data | map(select(.name == "renderer.js")) | .[0].sha', files, {input: 'json'});
  const sha = data.replace(/['"]+/g, '');
  const blob = await octokit.git.getBlob({
    owner: "kondoumh",
    repo: "sbe",
    file_sha: sha
  });
  const content = new Buffer.from(blob.data.content, blob.data.encoding).toString();
  console.log(content);
})();

ファイルリストからの抽出に jq のラッパー node-jq を使いました。2回のクエリが必要だし、SHA 1個取るのに全ファイルのデータを取得してるので非効率ですね。

こういう用途ではやはり GraphQL を使った方がよさそうです。GraphQL 用の octokit/graphql も提供されてます。上記のファイルの中身を GraphQL で取得してみます。

const { graphql } = require("@octokit/graphql");

(async() => {
  const graphqla = graphql.defaults({
    headers: {
      authorization: `token ${process.env.GH_TOKEN}`,
    },
  });
  const { repository } = await graphqla(`
    {
      repository(owner: "kondoumh", name: "sbe") {
        content:object(expression: "master:src/renderer.js") {
          ... on Blob {
            text
          }
        }
      }
    }
  `);
  console.log(repository.content.text);
})();

GraphQL API は public repo でも認証情報が必須です。対象のファイルパスを expression で指定して一発で取れました。Base64 変換も不要。便利ですね。

GitHub リポジトリをバックエンドのデータストアとして Web アプリなどを作ることも可能ですね。