Github Actionsの利用メモ

最近`Github Actions`を業務で使い始めたので色々と随時メモしていきます｡

なお現時点で参考にしている資料を以下に記載します｡
- [GitHub CI/CD実践ガイド](https://amzn.asia/d/5HtGoSL)

## 環境構築
### GitHub CLI
GitHub CLIをインストールすることでコンソールからプルリクエストの作成などの作業ができるようになるので便利です｡

また､GitHub Actionsの中でプルリクエストなどを作成するのにも同じコマンドを利用するため慣れておくと色々便利になりそうです｡

インストール方法

- Windows
    ```shell
    winget install --id GitHub.cli
    ```
- mac
    ```shell
    brew install gh
    ```

インストール確認
```shell
gh --version
```

ログイン
```shell
gh auth login

? Where do you use GitHub?  [Use arrows to move, type to filter]
> GitHub.com
  Other
? What is your preferred protocol for Git operations on this host?  [Use arrows to move, type to filter]
> HTTPS
  SSH
? Authenticate Git with your GitHub credentials? (Y/n) Y
? How would you like to authenticate GitHub CLI?  [Use arrows to move, type to filter]
> Login with a web browser
  Paste an authentication token
! First copy your one-time code: 0000-0000
Press Enter to open https://github.com/login/device in your browser...
```

実行すると色々と聞かれますが私は上記の設定で設定を実施しました｡`! First copy your one-time code...`の部分でブラウザーに遷移します｡ CLIに表示された`one-time code`をWebブラウザー上に入力すると先に認証が完了します｡

ログイン後に例えば下記のコマンドを実行すると自身のリポジトリのリストが表示されます｡
```shell
gh repo list
```

またその他のコマンドは以下で確認可能です｡

```
gh --help
```

## GitHub Actionsの実行
とりあえずGitHub Actionsを実行してみます｡

まず任意の方法でリポジトリを作成します｡筆者は`GitHub Cli`を利用して`Public`リポジトリを作成しました｡
```shell
gh repo create hello-github-actions-20241103 --public --clone --add-readme
```

その後Github Actionsに必要なディレクトリとファイルを作成します｡

```powershell
New-Item -ItemType Directory .github/workflows
New-Item -ItemType File ./.github/workflows/hello.yml
```

`.github/workflows`に配置したYmlファイル(.yml, .yaml)が`Github Actions`で実行されます｡

現時点のファイルツリー
```
└─.github
    └─workflows
            hello.yml
```

以下をYamlに記載しプッシュします｡

```yaml
name: Hello World                      # ワークフローの名前
on: push                               # ワークフローのトリガー(今回はpush)

jobs:                                  # ジョブの定義
  hello-world-job:                     # ジョブの名前
    runs-on: ubuntu-latest             # ジョブが実行されるランナーの環境
    steps:                             # ジョブのステップの定義
      - name: Checkout repository      # ステップの名前
        uses: actions/checkout@v4      # GitHub Actionsのアクションを使用
      - name: Hello World              # ステップの名前
        run: echo "Hello World"        # ステップの実行内容(Hello Worldを出力)
      - name: Hello World              # 複数行実行
        run: |
          echo "Hello"
          echo "World"
```

`Actions` > `Hello World` > `任意のruns` を選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223700/b46f5174-5a58-3d93-696d-4cf6d2bf0fcc.png)

`hello-world-job`が実行されていることが確認できます｡
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223700/3669e809-b364-1730-1be1-9dafa1c0d4e2.png)

`hello-world-job`をクリックするとより詳細な内容を確認できます｡
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223700/c30f5e65-8378-7920-3d88-9e0b1717bd20.png)

## GitHubイベント
`on: push`には様々なトリガーを設定できます｡

以下はGitHubイベントの例です｡

| イベント名         | 説明                                                                 |
|--------------------|----------------------------------------------------------------------|
| `push`             | リポジトリにコードがプッシュされたときにトリガーされます。           |
| `pull_request`     | プルリクエストが作成、更新、またはマージされたときにトリガーされます。|
| `issues`           | イシューが作成、更新、またはクローズされたときにトリガーされます。   |
| `release`          | リリースが公開、下書き、または削除されたときにトリガーされます。     |
| `workflow_dispatch`| 手動でワークフローをトリガーするために使用されます。                 |
| `schedule`         | 定期的にワークフローをトリガーするために使用されます。               |
| `fork`             | リポジトリがフォークされたときにトリガーされます。                   |
| `star`             | リポジトリにスターが付けられたときにトリガーされます。               |
| `watch`            | リポジトリがウォッチされたときにトリガーされます。                   |
| `delete`           | ブランチやタグが削除されたときにトリガーされます。                   |
| `create`           | ブランチやタグが作成されたときにトリガーされます。                   |

:::note warn
`schedule`のタイムゾーンは`UTC`です｡また`schedule`は指定した時間ピッタリに実行されません｡そのためある程度ズレが許されるタスクにのみ利用するのが望ましいです｡
:::

## アクション
`GitHub Actions`内で再利用可能なアクションが多数存在します｡

任意のアクションを探す際は[GitHub Marketplace](https://github.com/marketplace)を利用すのが便利です｡

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223700/5baea78a-e4a7-7b0a-25f9-0e4943594318.png)

またアクションの中には悪意のあるアクションが含まれている可能性があります｡そのため`Verified Creators`が付与されているアクションを選ぶと､付与されていないアクションに比べると多少安全です｡ただし絶対安全な訳ではないためアクションを利用する際は注意が必要です｡

## 課金モデル
公式を確認すると以下のような記載があります｡

>　GitHub Actions の使用は、パブリック リポジトリの標準の GitHub ホステッド ランナーとセルフホステッド ランナーの場合は無料です。 プライベート リポジトリの場合、アカウントのプランに応じて、GitHub ホステッド ランナーでの使用を対象として、一定量の無料の使用時間 (分) とストレージが各 GitHub アカウントに付与されます。 含まれる量を超える使用は、使用制限によって制御されます。

今回はPublicリポジトリで検証を実施しているので課金は発生しません｡

またPrivateのランナーのOSによって大きく料金が変わります｡2024/11/03時点ではLinuxとMacOsでは料金に10倍の差があります｡

詳細な料金は公式のページを確認してください｡

https://docs.github.com/ja/billing/managing-billing-for-your-products/managing-billing-for-github-actions/about-billing-for-github-actions

## ワークフロー構文
この章ではワークフローの構文についての説明を記載していきます｡

### コンテキスト
コンテキストでは実行中のリポジトリ名などの様々な情報を得ることができます｡

例えば以下のように記載するとリポジトリ名を取得することができます｡

```yaml
jobs:
  context-job:
    runs-on: ubuntu-latest
    steps:
      - name: Show context
        run: echo "GITHUB_REPOSITORY $GITHUB_REPOSITORY"
        env:
          GITHUB_REPOSITORY: ${{ github.repository }}
```

上記の通り`${{ github.repository }}`のように記載することでコンテキストにアクセスできます｡

その他のコンテキストについては公式のページを確認してください｡

https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs

### 環境変数
GitHub Actionsの中で利用される環境変数を自身で定義することも可能です｡環境変数を定義する際は`env:`セクションに記入します｡以下に例を示します｡

```yaml
name: Env Test
on: push

jobs:
  env-test-job:
    runs-on: ubuntu-latest
    env:
      JOB_ENV: "This is a job environment variable" # Job レベルの環境変数
    steps:
      - name: Show environment variables
        run: |
          echo "GITHUB_REPOSITORY $GITHUB_REPOSITORY"
          echo "JOB_ENV: $JOB_ENV"
        env:
          GITHUB_REPOSITORY: ${{ github.repository }} # Step レベルの環境変数
```

なお公式の以下の記載の通り変数は低いレベルの変数が優先されます｡

>複数のレベルで同じ名前の変数が存在する場合、最も低いレベルの変数が優先されます。 たとえば、Organization レベルの変数名がリポジトリレベルの変数名と同じ場合、リポジトリレベルの変数が優先されます。 同様に、Organization、リポジトリ、環境がすべて同じ名前の変数を持つ場合、環境レベルの変数が優先されます。
>
>再利用可能なワークフローの場合は、呼び出し元ワークフローのリポジトリの変数が使用されます。 呼び出されたワークフローを含むリポジトリの変数は、呼び出し元ワークフローでは使用できません。
>
>[構成変数の優先順位](https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#configuration-variable-precedence)

またデフォルトの環境変数がいくつか定義されています｡どんな環境変数が定義されているかは公式ページを参照してください

[既定の環境変数](https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables)


また上記の例では環境変数を直接コードに埋め込んでいます(JOB_ENVを直接echoしている)｡この記載方法だと意図しないスクリプトが埋め込まれてしまう可能性があります｡そのため以下のように変更を実施して意図しないスクリプトの埋め込みを防ぐことが重要です｡

```yaml

name: Env Test
on: push

jobs:
  env-test-job:
    runs-on: ubuntu-latest
    env:
      JOB_ENV: "This is a job environment variable" # Job レベルの環境変数
    steps:
      - name: Show environment variables
        run: |
          echo "GITHUB_REPOSITORY $GITHUB_REPOSITORY"
          echo "JOB_ENV: $JOB_ENV"
        env:
          GITHUB_REPOSITORY: ${{ github.repository }} # Step レベルの環境変数
```

中間環境変数については公式にも記載されています｡

[中間環境変数の使用](https://docs.github.com/ja/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions?learn=getting_started&learnProduct=actions#using-an-intermediate-environment-variable)

### Variables
複数のワークフローで使いまわしたい変数はVariablesで定義することが可能です｡

Variablesは`Settings` > `Secrets and variables` > `Actions` > `New repository variable`から作成可能です｡
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223700/07ff768c-9887-421c-96bc-21614893872f.png)

`VAR1`を追加  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223700/3364c485-30da-44d2-92df-86b95d644d7a.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223700/9455836a-01ca-21b5-2dc7-02ab9e55f427.png)

なおGitHub Cliから追加する際は以下のコマンドを実行します｡

```shell
gh variable set VAR2 --body 'VAR2'
```

追加したVariableを参照する際は`${{vars.VAR1}}`のように指定します｡

```
name: Variable Test
on: push
jobs: 
  var-test-job:
    runs-on: ubuntu-latest
    steps:
      - name: Show Variables
        env: 
          VAR1 : ${{vars.VAR1}}
          VAR2 : ${{vars.VAR2}}
        run: |
          echo "${{ env.VAR1 }}"
          echo "${{ env.VAR2 }}"
```