GitHub Actionsで自動テストできるようにしたメモ

GitHub Actionsは、GitHub上のリポジトリに何らかのイベント(pushされた、pull requestが行われた……など)が発生したときに、自動的にプログラムを実行してくれる仕組みです。 pushのたびにテストをして壊れていないかをチェックする、pushするたびにウェブページを自動生成する、pull requestが所定の形式に従っているかなどをチェックする、などなどいろいろな利用用途があるようです。

いままでいまいちやり方がよくわからず勉強せず放置していたのですが、機会があってやってみたらそんなに難しくはなかった(そんなに簡単でもなかった)ので、メモをまとめておきます。

やりたいこと

  • プライベートリポジトリの自動テストを行う
  • テスト対象のプライベートリポジトリは、gitのsubmoduleとして他のプライベートリポジトリを複数含む
  • テスト対象のプライベートリポジトリ直下にDockerfileが置いてあって、これを実行すればテストが走る(終了コードが0ならテスト成功、そうでなければテスト失敗)

やりかた

まず、リポジトリ.githubというディレクトリを作り、その中にworkflowsというディレクトリを作り、その中にyamlファイルを置きます(以下、GitHubが提案してきたdocker-image.ymlという名前で行きます)。 docker-image.ymlの中身は、以下のようにします。

name: Docker Image CI

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:

  build:

    runs-on: ubuntu-20.04

    steps:
    - uses: actions/checkout@v2
      with:
        submodules: recursive
        token: ${{ secrets.PERSONAL_ACCESSTOKEN }}
    - name: Build the Docker image
      run: docker build . --tag foobarbaz:$(date +%s)

次に、自分のアカウントのSettingsから、Developer settings→Personal access tokensとたどり、Generate new tokenを押します。パスワードを求められるかもしれません。 Note欄には何かわかりやすい名前を付けます(github-actions-tokenとか)。repoのところにあるチェックをつけ、Generate tokenを押します。 すると、トークン(ghp_Foo12Bar3BazHogeみたいなもの)が生成されますので、これをコピーします。 この画面から遷移すると、再び表示することはできませんので注意します(トークンの内容を忘れてしまった場合は、また作ることが可能です)。

その後、テスト対象のリポジトリのSettingsから、Secretsを選び、New repository secretを押します。 Nameには、PERSONAL_ACCESSTOKENと書きます(上記yamlファイルに記述したsecrets.PERSONAL_ACCESSTOKENの部分と同じ名前を入力するということです)。 Valueには、先ほどコピーした値をそのまま貼り付けます。 Add secretを押せば、repository secretsに追加されます。 secretの名前は後からでも確認できますが、内容はあとから確認することはできません(新しい値に書き換えることはできます)。 したがって、他者がアクセスできるリポジトリであっても、自分のアクセストークンの内容が漏れてしまうことはありません。

ハマったところなど

まず、プライベートリポジトリ複数をsubmoduleとして持つ場合にやる方法が良くわかりませんでした。 ググってみると、「submoduleはactions/checkout@v2ではうまくいかないのでactions/checkout@v1を使う」等の情報が得られますが、これは古い情報で、現在のactions/checkout@v2はsubmoduleに対応しているようです。 また、他にも「submoduleにアクセスする場合は対象となるリポジトリにデプロイキー(SSH公開鍵)を登録し、対応するSSH秘密鍵をsecretsに入れるとよい」という情報も得られましたが、複数のリポジトリに同一のSSH公開鍵をデプロイキーとして登録するとGitHubが「すでに使われています」と怒られます*1

actions/checkout@v2でtokenに何も指定しなかった場合、${{ token.github }}が使われるようです。 これはGitHub Actionsが設定された対象のリポジトリを扱うことのできる権限を持つトークンですが、他のプライベートリポジトリを見ることはできないので、submodule対象のプライベートなリポジトリをクローンすることに失敗します(remote: Repository not found.と出ます)。

プライベートリポジトリをクローンするだけなので、パーソナルトークンに必要な権限はrepo:statusだけだと思っていたのですが、それではうまくいかず、repo全体の権限が必要なようです。

その他、実行するマシンが2core・メモリ7GBの貧弱なマシンなのに手癖でmake -jとやって死んでしまったこともありました。 llvmのプロジェクトなので1000個くらいのC++ファイルをコンパイルする必要があり、自動テストだけで30分以上かかるのもやや困ったところです。 ただで実行させてもらっているのでしょうがないところもあります。

*1:鍵を使いまわせることが公開鍵暗号の利点なのに、これでは不便極まりありません。何か理由はあるのでしょうか?