見出し画像

JenkinsのPipelineからGithubのREST APIを実行する

SCMはGithub、CIにJenkinsという組み合わせで使っている方は多いのではないでしょうか。
我々も最近オンプレBitbucketからGithubに移行して、上記の組み合わせで運用しています。
今回は、JenkinsのPipelineからGithubのREST APIを実行する方法を紹介します。

背景

私の所属しているグループでは、Pull Request(以下、PRと呼称します)前にJenkinsでビルドやE2Eレベルの回帰テストを行い、それらが成功したものをレビューするようにしています。
これによって、PRマージでdevelopブランチがビルドできなくなったり、デグレードが発生することを防いでいます。

Jenkinsでのビルドやテスト結果は、Bitbcuket Server NotifierというJenkinsプラグインを用いて、Bitbucketに通知していました。

Bitbucketのコミット一覧
Jenkinsでのビルド、テスト結果が表示されている

Githubでも同じような運用を行うためJenkinsプラグインを調査したのですが、全てをカバーできるものが見つかりませんでした。

調査したJenkinsプラグイン

Github

このプラグインでは、コミットステータスを設定することができます。Bitbcuket Server Notifierに近しい使い勝手で、Pipelineの任意のタイミングでコミットステータスの設定が行えます。

ただ、このプラグインはGithub Appの認証に対応しておらず、Personal Access Tokenによる認証となってしまうのがネックです。
Personal Access Tokenはその名の通り、特定の個人アカウントに紐づくトークンです。

例えば、Aさんのアカウントに紐づくPersonal Access Tokenでコミットステータスを設定した場合、Jenkinsという非個人ではなくAさんがそのステータスを設定したことになります。
また、Jenkinsに特定個人に紐づく情報を保持するのも望ましくありません。

Github Checks

このプラグインでは、ビルドステータスをGithub Checks APIで設定します。
認証にはGithub Appを使用します。
ステータスの設定も、特定個人ではなく、Jenkins自体(Github App)が行ったことになります。

一方で、このプラグインはMultibranch PipelineやOrganization FolderでBranch SourceとしてGithubを指定した場合にのみ使えるようです。
※私が確認した限りでは上記の認識ですが、もし誤りがあるようでしたらコメントで指摘いただけると幸甚です。

我々のJenkinsには通常のPipelineジョブもあるため、このプラグインだけでは全てをカバーできないことがわかりました。

PipelineからGithubのREST APIを実行してみよう

改めてやりたいことを整理すると、以下の3点になります。

  • Jenkinsのビルド結果、テスト結果をGithubに通知したい

  • 通知元のJenkinsジョブには、Multibranch Pipelineも通常のPipelineもある

  • Githubへの認証にはGithub Appを使いたい

既存Jenkinsプラグインでは上記を満たすものはありませんでした。
ここで考え方を変えて、Github Checksプラグインと同等の通知は以下のREST APIで実現できるので、PipelineからこのREST APIを呼び出してみましょう。

事前準備

1.Jenkinsプラグインのインストール
以下のJenkinsプラグインをインストールします。

  • Github Branch Source

  • Credential Binding

  • HTTP Request

    • WindowsのAgentだとcurlが使えず、powershellのInvoke-WebRequestも癖があるため導入していますが、LinuxのAgentの場合はshでcurlを呼び出すように後段のPipelineを読み替えていただいても構いません

2.Github Appの作成、JenkinsのCredentialへの追加
詳細な手順はここでは述べません。以下を参照してください。

Pipelineの例

実際のPipelineの例は以下のようになります。
※REPO_OWNER、REPO_NAME、credentialsIdは自身の環境に合わせて変更してください。

pipeline {
    agent any
    environment {
        REPO_OWNER = 'your-username' // 実際のオーナー名に変更
        REPO_NAME = 'your-repo' // 実際のレポジトリ名に変更
    }
    stages {
        stage('Build') {
            steps {
                withCredentials([
                    usernamePassword(
                        credentialsId: 'github-app', // JenkinsのCredentialに追加したGithub AppのIDに変更 
                        usernameVariable: 'GITHUB_APP',
                        passwordVariable: 'GITHUB_ACCESS_TOKEN'
                    )
                ]) {                   
                    script {
                        def commitSha = env.GIT_COMMIT
                        def response = httpRequest httpMode: 'POST', quiet: false,
                                        customHeaders: [
                                            [name: 'Authorization', value: 'Bearer ' + GITHUB_ACCESS_TOKEN],
                                            [name: 'Accept', value: 'application/vnd.github+json'],
                                            [name: 'X-Github-Api-Version', value: '2022-11-28']
                                        ],
                                        requestBody: """{
                                            "name": "check_run",
                                            "head_sha": "${commitSha}",
                                            "status": "in_progress",
                                            "output": {
                                                "title": "Check run from Jenkins!",
                                                "summary": "This is a check run which has been generated from Jenkins as GitHub App",
                                                "text": "...and that is awesome"
                                            }
                                        }""",
                                        url: "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/check-runs"
                        echo response.content
                    }
                }
            }
        }
    }
}

ポイント1:withCredentialsでアクセストークンを取り出す
withCredentialsにGithub AppのCredentialを指定して、アクセストークンを取り出すことができます。
ただし、このアクセストークンの有効期限は1時間であることに注意してください。

ポイント2:HTTPリクエストへのGITHUB_ACCESS_TOKENの指定方法
GITHUB_ACCESS_TOKENはパスワードなので、Pipeline上はセキュアなオブジェクトとして取り扱われるため、Groovyの文字列補完(PipelineはGroovyで書かれたDSLです)を適用すると警告がでたりします。
以下のstackoverflowで言及されている通り、そのまま取り扱う必要があります。


ここでは、チェック実行用REST APIを実行していますが、他のREST APIも実行可能です。ただ、APIによってはGithub Appに割り当てる権限が変わってくる可能性がありますので、詳しくはGithub REST APIのドキュメントを参照してください。

まとめ

JenkinsのPipelineからGithubのREST APIを実行する方法を説明しました。
JenkinsにはShared Librariesという機能もあるので、それを定義すればプラグインを自作しなくても、複数のPipelineから使うこともできそうです。

このように使い手側に自由度があるところが、Jenkinsの魅力の一つでもありますね。

#エンジニア#ITエンジニア#開発#ウイングアーク#ウイングアーク1st#テックブログ#エンジニア転職#エンジニア採用 ​#Jenkins #Github #REST #Pipeline


いいなと思ったら応援しよう!