Github ActionsでDataformをデプロイする方法

# はじめに
DataformはGitリポジトリと連携してバージョン管理や共同開発が可能です。
この記事では、Github Actionsを使用してDataformをGCP環境にデプロイする方法について紹介します。

主にGithub Actions実装方法の紹介でおり、デプロイの戦術や運用方針などは話しておりません。

# 1.Dataform CLIを使う方法
Github Actionsワークフローで[Dataform CLI](https://cloud.google.com/dataform/docs/reference/dataform-cli-reference)を使う実装です。

CI/CDを組み立てることが可能です。
```yaml
name: CI

on:
  pull_request:
    branches:
      - main

jobs:
  integration:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code into workspace directory
        uses: actions/checkout@v4
      - name: Install project dependencies
        uses: docker://dataformco/dataform:latest
        with:
          args: install --track=false
      - name: Decrypt df credentials
        run: gpg --quiet --batch --yes --decrypt --passphrase="$CREDENTIALS_GPG_PASSPHRASE" --output .df-credentials.json .df-credentials.json.gpg
        env:
          CREDENTIALS_GPG_PASSPHRASE: ${{ secrets.CREDENTIALS_GPG_PASSPHRASE }}
      - name: Compile
        uses: docker://dataformco/dataform:latest
        with:
          args: compile --track=false
      - name: Test
        uses: docker://dataformco/dataform:latest
        with:
          args: test --track=false
      - name: Dry run
        uses: docker://dataformco/dataform:latest
        with:
          args: run --dry-run --track=false
```
```yaml
name: CD

on:
  pull_request:
    branches:
      - main

jobs:
  deployment:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code into workspace directory
        uses: actions/checkout@v4
      - name: Install project dependencies
        uses: docker://dataformco/dataform:latest
        with:
          args: install --track=false
      - name: Decrypt dataform credentials
        run: gpg --quiet --batch --yes --decrypt --passphrase="$CREDENTIALS_GPG_PASSPHRASE" --output .df-credentials.json .df-credentials.json.gpg
        env:
          CREDENTIALS_GPG_PASSPHRASE: ${{ secrets.CREDENTIALS_GPG_PASSPHRASE }}
      - name: Dataform run
        uses: docker://dataformco/dataform:latest
        with:
          args: run --run-tests
```
ブランチ名やコミットメッセージによって、
incrementalなテーブルの更新方法を変えることやテーブル作成をスキップするなどの運用が可能です。

## 特徴
ユニットテストから実テーブルの作成まで、一連の流れを通じてCI/CDパイプラインを構成することが可能です。
BigQueryテーブルの更新までの自動化が必要な時に採用します。

## 注意
Dataform CLIを使用するにはウェアハウスに接続が必要し、
接続に必要な認証情報は`.df-credentials.json`を参照して取得します。

`df-credentials.json`ファイルをそのままリポジトリに保存するのは大変危険ですので、暗号化されたファイルをリポジトリに保存します。
複合パスワードをリポジトリのsecretに登録することで、Github Actions上で複合します。
```bash
# BigQuery接続用のCredential作成(.df-credentials.json)
dataform init-creds bigquery

# .df-credentials.jsonを暗号化
gpg --symmetric --cipher-algo AES256 .df-credentials.json
```
ref. https://docs.dataform.co/guides/ci-cd
（現在はページが消えています）

また、Dataformを実行することでBigQuery側にコストが発生します。
余計なSQLワークフローが実行されないように注意が必要です。

# 2.Dataform APIを使う方法
Github ActionsワークフローでDataform APIを呼び出す方法です。
まだgcloud CLIにDataform関連コマンドが用意されていないので、curlで[GCP Dataform API](https://cloud.google.com/dataform/reference/rest)にアクセスします。

```yaml
name: Deploy Dataform

on:
  pull_request:
    branches:
      - main

env:
  RELEASE_NAME: "hoge"

jobs:
  compile-and-deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: "read"
      id-token: "write"

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - id: auth
        uses: google-github-actions/auth@v2
        with:
          token_format: "access_token"
          workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER}}
          service_account: ${{ secrets.SERVICE_ACCOUNT }}
      - name: Create Compilation
        id: compilation
        run: |
          echo "name=$(curl -fs -X POST \
            'https://dataform.googleapis.com/v1beta1/${{ secrets.REPOSITORY }}/compilationResults' \
            -H "Authorization: Bearer ${{ steps.auth.outputs.access_token }}" \
            -H 'Content-Type: application/json' \
            -d '{
                  "releaseConfig": "${{ secrets.REPOSITORY }}/releaseConfigs/${{ env.RELEASE_NAME }}"
                }' | jq -c '.name')" >> $GITHUB_OUTPUT
      - name: Update Release Config
        run: |
          curl -fs -X PATCH \
          'https://dataform.googleapis.com/v1beta1/${{ secrets.REPOSITORY }}/releaseConfigs/${{ env.RELEASE_NAME }}' \
          -H "Authorization: Bearer $(echo ${{ steps.auth.outputs.access_token }})" \
          -H 'Content-Type: application/json' \
          -d '{
                "gitCommitish": "main",
                "timeZone": "Asia/Tokyo",
                "releaseCompilationResult": ${{ steps.compilation.outputs.name }}
              }'
```
コンパイル結果の作成とリリース構成の更新を実行して、リポジトリ状態をGCP上のリリース構成に反映します。

## 特徴
GCP Workload Identityでリソースのアクセイス権限を取得するので、セキュリティ的により安全です。

コンパイル結果の作成からリリース構成の更新など、Dataform APIで対応できるところまでしか設計できません。
上記yamlにはいないですが、`projects.locations.repositories.workflowInvocations`を叩くことでワークフロー構成を実行することも可能です。

DataformがGCPに結合さたのが結構最近ですので、今後できるものは増えると思います。

# まとめ
２つの実装で最も大きな違いはユニットテストの存在です。
ユニットテスト以外は２つともコンパイルからテーブル更新まで対応できします。

ただし、さすがにDataform CLIはやや危険性ありますので、
ユニットテストが必須ではない限り、Dataform APIを使う方がベターかなと思います。