Jenkins で Pull 型 の CI/CD 環境を構築

本記事では Jenkins の SCM ポーリング機能を用いて、 Pull型 の CI/CD 環境 を構築する方法を説明する。
この方法は、ビルド・テスト用サーバが制限されたネットワーク内にあり、かつサーバの認証情報を CI/CD に渡したくないケースに対して有効である。

サンプルコード：

https://github.com/sawa2d2/pull-jenkins-sample

## 手順

### レポジトリの用意
次のスクリプトを作成し、GitHub repository に push する。

1. ビルド用スクリプト `build.sh`
2. Jenkinsfile `./jenkins/pipeline.groovy`

#### Build script を作成する
build スクリプトを作成する。
```build.sh
$ cat << EOF > build.sh
echo "Hello"
EOF

$ chmod +x ./build.sh
```

#### Jenkinsfile (groovy) を作成する
Jenkins 用スクリプト `pipeline.groovy` を次の内容で作成し、GitHub repository の `./.jenkins/pipeline.groovy` に配置する。
下記のスクリプトでは、Build のフェーズに応じて GitHub API によりコミットステータスを変更するようにしている。

```groovy:./.jenkins/pipeline.groovy
pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                updateGitHubStatus('pending', 'Test build.sh')
                echo 'Starting build'
                sh './build.sh'
            }
        }
    }

    post {
        success {
            script {
                echo 'Build succeed'
                updateGitHubStatus('success', 'Succeed build.sh')
            }
        }
        failure {
            script {
                echo 'Build failed'
                updateGitHubStatus('failure', 'Failed build.sh')
            }
        }
    }
}

def updateGitHubStatus(String status, String description) {
    withCredentials([usernamePassword(credentialsId: 'github', passwordVariable: 'GITHUB_TOKEN', usernameVariable: 'GITHUB_USER')]) {
        def commitSha = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
        echo "$commitSha"

        def scmUrl = scm.userRemoteConfigs[0].url
        echo "SCM URL: ${scmUrl}"
        def urlParts = scmUrl.split('/')
        orgName = urlParts[-2]
        repoName = urlParts[-1].split('\\.')[0]
        echo "Org name: ${orgName}"
        echo "Repo name: ${repoName}"

        sh """
        curl -u $GITHUB_USER:$GITHUB_TOKEN -X POST \
            -d '{"state": "$status", "description": "$description", "context": "continuous-integration/jenkins"}' \
            https://api.github.com/repos/$orgName/$repoName/statuses/$commitSha
        """
    }
}
```

### Jenkins の設定

#### GitHub Credential を登録する

ダッシュボード -> Jenkins の管理 -> Credentials
から新規の credential を作成し、ユーザ名には GitHub のユーザ名、パスワードには [GitHub token](https://github.com/settings/tokens) を入れる。ID および説明は適当に設定する。

![jenkins-credential.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261727/b827e639-f7cb-06ae-1c11-8d95343790c5.png)

#### Pipeline を作成する
ダッシュボードから 新規ジョブ作成 -> パイプライン に遷移し、ジョブを新規に作成する。

設定項目の `SCMをポーリング` にチェックを入れ、スケジュールを次の例のように設定する。

```
H/5 * * * *
```
この設定では、Jenkins は GitHub に対して 5分ごとにポーリングを行い、レポジトリの変更を検知する。

![Screenshot from 2024-08-22 08-41-26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261727/c7e4f1f4-5bf8-e185-3738-318fed486f5b.png)

「パイプラインの設定」項目では、`定義`を `Piepline script from SCM`、`SCM` を `Git` として、レポジトリのURL、認証情報、ブランチ、Script Path を指定する。

![Screenshot from 2024-08-22 08-45-48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261727/1a0b225b-6a74-fe27-d04b-c8d0baf5c2d4.png)

### Polling の動作確認
Piepline を作成してしばらく待つとポーリングが走り、レポジトリの変更が検知されると build がトリガされる。Build が正常に終了すると、GitHub の最新コミットハッシュの横に成功のコミットステータス (緑のチェックマーク) が表示される。

![Screenshot from 2024-08-22 08-59-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261727/4134cd59-e816-5966-92ce-bfdf87018de4.png)


## まとめ
本記事では Jenkins を用いて Pull型の CI/CD 環境 を構築した。この方法はビルド・テスト用サーバが制限されたネットワーク内にあり、かつサーバの認証情報を CI/CD に渡したくないケースに対して有効である。ただし、通常の Push 型と比較して SCM に負荷がかかる点には注意すべきである。

## 参考資料
- [JenkinsのSCMボーリングを極める！](http://holiday-programmer.net/jenkins_scm_polling/)
- [コミットのステータス - GitHub Docs](https://docs.github.com/ja/rest/commits/statuses?apiVersion=2022-11-28) ... GitHub API から指定可能な commit status のリファレンス