アプリチームの松田です。
アプリのリリース時には様々な作業を行いますが、面倒な作業があったのでGitHub Actionsを使用して、一部を自動化しました。
AndroidとアプリバックエンドにKotlinを使用しているので、Kotlin Scriptを使用しました。
リリース作業の流れ
- developからバージョン番号で
release/x.x.x
のようなブランチを作成する - masterとdevelopに向けてPull Reqeustを作成する
- マージされたPull Request一覧をIssueに書き出し、検証依頼を出す
マージされたPull Requestを一覧にするのが面倒だったのでこちらを自動化しました。
このように一覧になります。
実装
YAML
Java11からの機能を使用するので、それ以上を指定します。( java.net.http.HttpClient
)
デフォルトで11ですが、以前にGitHub Actions側の間違いで、数日間デフォルトがJava8に戻った事があったので、ちゃんと指定します。
https://github.com/actions/virtual-environments/pull/4903
コメント用URL等は環境変数に入っていないので、ここで環境変数に入れます。
name: master merge pr list on: pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: fetch-depth: 0 - uses: actions/setup-java@v2 with: distribution: 'temurin' java-version: '17' - name: Run Script env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COMMENT_URL: ${{ github.event.pull_request.comments_url }} run: | git checkout $GITHUB_HEAD_REF ./.github/workflows/master-merge-pr-list.main.kts
Kotlin Script
GitHub ActionsではデフォルトでKotlin Scriptが使用できるので、 #!/usr/bin/env kotlin
を先頭に記述します。
処理は以下のような流れとなっています。
- gitコマンドを実行してmasterからPull RequestまでのマージPRを取得する
- GitHubのマージ時のコメントからPull RequestのIDを取得する
- GitHubのAPIを使用してPull Requestにコメントをする
.github/workflows/master-merge-pr-list.main.kts
#!/usr/bin/env kotlin @file:DependsOn("com.google.code.gson:gson:2.8.9") @file:OptIn(ExperimentalStdlibApi::class) import com.google.gson.Gson import java.io.File import java.net.URI import java.net.http.HttpClient import java.net.http.HttpRequest import java.net.http.HttpResponse val commentUrl = System.getenv("COMMENT_URL") val githubToken = System.getenv("GITHUB_TOKEN") val githubOwner = System.getenv("GITHUB_REPOSITORY_OWNER") val githubServerUrl = System.getenv("GITHUB_SERVER_URL") val githubRepository = System.getenv("GITHUB_REPOSITORY") val currentBranchName = System.getenv("GITHUB_HEAD_REF") val command = "git log --pretty=format:‘%s’ --first-parent --merges origin/master..${currentBranchName}" println(command) val numbers = Runtime.getRuntime().exec( command, null, File(".") ).let { process -> process.errorStream.use { stream -> stream.bufferedReader().use { reader -> reader.lineSequence() .onEach { System.err.println(it) } .toList() } } process.inputStream.use { stream -> stream.bufferedReader().use { reader -> val regex = """Merge pull request #(\d.+?) """.toRegex() val notRegex = """Merge pull request #(\d.+?) from ${githubOwner}/release""".toRegex() reader.lineSequence() .onEach { println(it) } .filterNot { notRegex.find(it) != null } .mapNotNull { regex.find(it) } .mapNotNull { it.groupValues.getOrNull(1) }.toList() } } } data class Comment(val body: String) val urls = numbers.map { number -> "${githubServerUrl}/${githubRepository}/pull/$number" } val comment = Comment( buildList { add("# Pull Request一覧") addAll(urls) add("```") addAll(urls) add("```") }.joinToString("\n") ) val json = Gson().toJson(comment) println(json) val request = HttpRequest.newBuilder() .uri(URI.create(commentUrl)) .header("Content-Type", "application/json") .header("Authorization", "token $githubToken") .POST(HttpRequest.BodyPublishers.ofString(json)) .build() val response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()) println(response)
おわりに
今はPull Requestの一覧を出すだけですが、リリース時の検証用Issueの作成まで自動化するのも良いかなと思っています。
また、このコードはiOSとAndroidのリポジトリで使用されているのですが、両方に同じコードが入っています。これらのコードは同じ場所で管理したいと思っています。以下の機能が実装されれば、privateリポジトリでMarketplaceのような機能が使用できるようになるようなのでこの機能の実装に期待しています。
https://github.com/github/roadmap/issues/74