JenkinsからGithub Actionsに乗り換え



# 概要

以前BitbucketからGithubへソースコード管理を移行した。
https://qiita.com/kamatat/items/efe1189d69e0a5eb0884
しかし、オンプレのJenkinsサーバ/スレーブの維持管理は日に日にストレスに…（スレーブのスペック不足、インストール済みのパッケージ管理、ストレージ管理などなど…）
そこでGithubが提供しているCI/CDワークフローエンジンであるGithub Actionsに移行することになり、Jenkinsと同等のテストを流すために調査した内容を残す。
~~初めからJenkinsではなくGithub Actionsに移行したかったな。~~

# 本題

この資料を読む際の注意点
- 基本的にJenkinsの用語を使用
- Github Actionsでの挙動を定義するworkflowの基本的な記述方法が中心
- self-hosted runnerの登録、活用方法は記載なし


## workflowの基本的な記述

workflowの基本的な記述の説明をしていく。 下記のサンプルを参考に内容を書く。
(`{xxx}` は環境に合わせて修正が必要)

``` yaml
name: workflow name
on:
  push:
    branches:
      - {target_branch_name}
  pull_request:
    branches:
      - {target_branch_name}

jobs:
  {job_name1}:
    runs-on: [{you_want_run_machine_label}]
    env:
      {ENV_NAME}: {ENV_VALUE}
    steps:
      - uses: {run_action_name}
        with: 
          {action_options}
      - name: {step_name}
        run: |
          ### runnable shell commands ###
          ### writable multi line ###
  {job_name2}:
    ...
```

- `name:`
  workflowの名前を記述
- `on:`
  workflowを実行するタイミングに関する情報を記述
  * `push:`
Push時に動作
    * `branches:`
動作対象にするブランチを指定(省略時は全ブランチが対象)
  * `pull_request:`
PRに関連して動作
    * `branches:`
動作対象にするブランチを指定(省略時は全ブランチが対象)
- `jobs:`
  * `{job_name1}`
ジョブの名前を設定
  * `runs-on: [{set_machine_label_to_run}]`
次節で個別に説明
  * `env:`
環境変数を設定
  * `steps:`
1つの処理(step)を記述
    * `- uses: {run_action_name_or_path}`
      * `with:`
        * `{action_options}`
actionの実行にパラメータを設定
    * `- name: {step_name}`
stepの名前を設定
      * `run: |`
実行する処理を記述(shell script)

### 実行環境の指定

Jenkinsは予め登録しているSlaveでジョブを実行する。
Github Actionsではruns-onでジョブが実行する環境を指定でき、また、ジョブごとにGithubが提供する環境と、開発者が用意した環境を使い分けることも出来る。
https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#choosing-github-hosted-runners

```
ex1) Githubが提供しているRunner(Github-hosted runners)の場合
runs-on: ubuntu-latest

ex2) 開発者で用意したRunner(self-hosted runner)の場合
runs-on: [self-hosted, Linux]
```
* ex1) Github-hosted runner
    * Githubが提供しているイメージを指定
        * `ubuntu-latest`だと、2023/3現在はUbuntu 22.04で実行される
    * Windows ServerやmacOS、別バージョンのUbuntu(18.04,20.04)も指定可
        * `windows-latest`/`windows-2022`/`windows-2019`
        * `macos-latest`/`macos-12`/`macos-11` ...etc
        * `ubuntu-20.04`/`ubuntu-18.04`
* ex2) self-hosted runner
    * `self-hosted`の指定は必須
    * Runnerを管理/指定するためのラベルも設定できる
        * `linux`, `mac`など、任意に設定可


## Jenkinsジョブからの移行

JenkinsジョブからGithub Actionsに移行するにあたり、Jenkinsの機能を使った処理を書き換える必要がある。

変更の内容と代替の記述の1例を紹介していく。

### レポジトリのclone

Jenkinsジョブの場合、ソースコード管理タブを適切に設定することで自動でCloneすることができるが、Github Actionsは同等の設定をworkflow内に記述する必要がある。

Cloneに関わる処理を手動で記述するのは難しいため、actionと呼ばれる予め一連の処理が設定されている関数のようなものを使用する。

今回はcheckoutアクションを使用し、普段使用するコマンドがどのように置き換わるか例を示す。
参照: https://github.com/actions/checkout

``` shell
$ git clone -b {checkout_branch} {repogitory_path} {checkout_path}
```

↓

``` yaml
- uses: actions/checkout@v3
  with:
    ref: {checkout_branch}
    path: {checkout_path}
```

他のオプションもあるので、必要に応じてREADME.mdを参照先。

### 手動ビルド

Jenkinsではプロジェクトページから`ビルド実行`を選択すると、開発者が任意のタイミングでビルドを実行することが出来る。

Github Actionsでも手動で実行するための`workflow_dispatch`イベントがあり、これを活用することで同等の環境を構築できる。
参照: https://docs.github.com/ja/actions/managing-workflow-runs/manually-running-a-workflow

```yaml
on:
  workflow_dispatch:
```

:::note warn
手動ビルドにはメインブランチにworkflowファイルの配置が必要
:::

#### パラメータビルド

workflow_dispatchの実行時にパラメータを与えることができ、Jenkinsにおけるパラメータ付きビルドと同等の処理が出来る。
必要に応じてrequired(指定必須)や、default(初期値)、type(入力値の型)などを指定出来る。

```yaml
on:
  workflow_dispatch:
    inputs:
      target_branch:
        description: 'target branch'
        required: true
        default: 'master'
```

参照: https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch

:::note warn
typeで数値型(number)を指定しても、文字列を入れることも可能で厳密な制限は難しい(2023/1 検証時)
:::

### Pipeline

JenkinsにはPipelineと呼ばれる複数のジョブで構成するジョブがあり、デプロイまでの一連の処理の関連付けや、複数のテストをまとめて実行することが出来る。

今回紹介するGithub Actionsの例では、個別に定義したworkflowを呼び出す(再利用すること)でPipelineを再現している。

#### 特定の処理の再利用

レポジトリのclone時と同様に、自身が作成したworkflowを呼び出すことが出来る。

まず呼び出されるworkflowに受け付けるパラメータを設定の例を記載した。

```yaml
on:
  workflow_call:
    inputs:
      target_branch:
        description: 'target branch'
        required: true
        default: 'master'
        type: string 
      machine:
        default: 'local'
        type: choice
        options:
          - local
          - remote
      secrets: 
        ACTIONS_SSH_KEY:
          required: true
```

* `workflow_dispatch`と異なり`type`指定必須
* 呼び出し元から秘密鍵を渡せる

呼び出しは、一部制約があるが公式のactionを使用する場合とほぼ同じ記述が可能。

```yaml
jobs:
  unit-test:
    uses: ./.github/workflows/test_unit.yaml
    with:
      target_branch: 'working_branch'
      machine: local
    secrets:
      ACTIONS_SSH_KEY: "${{ secrets.ACTIONS_SSH_KEY }}"
```

* 呼び出しはstepsに配置できない
  * 個別のjobとして記述が必要
* プライベートリポジトリの場合、別レポジトリから直接呼び出しができない

### 成果物の保存

Jenkinsにはジョブの成果物としてバイナリやログなどを保存しダウンロードできるようにする機能がある。
Github Actionsでも同様の機能([upload-artifact](https://github.com/actions/upload-artifact))が提供されており、任意のファイル/ディレクトリをアップロードすることで同等の機能を使用できる。
ワイルドカード(`*`)の使用や、特定のファイル/ディレクトリを除外することもできる。

例) tests配下のlogsディレクトリを選択
``` text:ディレクトリ構成
.
├── main.py
└── tests
    ├── logs
    |    ├── ...
    |    └── ...
    └── hogehoge
```

``` yaml
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
      - name: Run test
        run: |
          # run test
      - name: Archive production artifacts
        uses: actions/upload-artifact@v3
        with:
          name: test-logs
          path: |
            tests/logs
```


#### 作業中に気付いたこと

* `on: push`による実行の場合、workflow_dispatchやworkflow_callで設定した変数(`inputs.xxx`)は空文字になる
* step内で`env.xxx`を更新する場合は$GITHUB_ENVへ書き出す
  * `echo "target_branch=working-branch" >> $GITHUB_ENV`
* stepsで別のワークフローファイルの呼び出し
  * 再利用のためのワークフロー呼び出しはjobへの記述が必要
    ``` yaml:〇許容されている記述
    jobs:
      reuse-job:
        use: ./.github/workflows/reuse.yaml
    ```
    ``` yaml:×許容されていない記述
    jobs:
      job:
        steps:
        - name: reuse-job
          uses: ./.github/workflows/reuse.yaml
    ```
* steps以外で環境変数(`.env`)へのアクセス不可な箇所がある
  * jobs直下のwithなどで使用が出来ない
  * 詳細は下記リンクを参照(`Context`に`env`があれば参照できる)
    参照: https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability