Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 83 additions & 96 deletions README-ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@

ファイル変更からデプロイ対象ラベルを生成し、ラベルからデプロイメント・ターゲットを解決する層を提供します。実際の `plan`/`apply` 実行は、利用側で任意の Composite Action(Terragrunt / Helm / kustomize など)に委ねる構成です。

## コンポーネント
## 構成要素

### 1. Config Manager (`action-scripts/config-manager/`)

`workflow-config.yaml` を検証・管理。環境・サービス・ディレクトリ規約を定義します。
`workflow-config.yaml` の stack 定義を検証し、設定表示・環境一覧・実在ディレクトリのサービス診断・テンプレート生成を提供します。

**特徴:**

- 詳細なエラーレポート付きの設定検証
- 環境とサービスの管理
- ディレクトリ規約の検証
- 定義環境の一覧とサービス診断
- stack のパスと除外条件の検証
- テンプレート生成

### 2. Label Dispatcher (`label-dispatcher/`)
Expand All @@ -34,12 +34,12 @@ PR の変更ファイルを検出し、変更があったサービスに対し

### 3. Label Resolver (`label-resolver/`)

`deploy:<service>` ラベルとブランチ情報を、後続 Action が利用するデプロイメント・ターゲットの matrix に変換します。
`deploy:<service>` ラベルと指定環境を、後続 Action が利用する matrix に変換します。

**特徴:**

- ラベルからターゲットへの解決
- ブランチからの環境検出
- 定義された環境からの対象選択
- デプロイメント matrix 生成
- 安全性検証

Expand All @@ -57,71 +57,80 @@ PR の変更ファイルを検出し、変更があったサービスに対し

### Label Resolver

`environments` は任意の入力で、複数環境はカンマ区切りで指定します。省略すると全定義環境を対象にします。

```yaml
- uses: panicboat/deploy-actions/label-resolver@v1
with:
pr-number: ${{ github.event.pull_request.number }}
repository: ${{ github.repository }}
github-token: ${{ secrets.GITHUB_TOKEN }}
environments: develop # 任意。カンマ区切り (例: develop,staging)
environments: develop
```

## 設定

`workflow-config.yaml` を読み込みます。
`workflow-config.yaml` のトップレベルには、空でない `stacks` 配列を定義します。同じ stack のパス、環境属性、除外条件を一つの定義で管理します。

```yaml
environments:
- environment: develop
stacks:
aws:
stacks:
- name: terragrunt
id: aws
paths:
- "dystopia/{service}/aws/{environment}"
- "system-components/{service}/infrastructure/aws/{environment}"
- "teams/{team}/{service}/aws/{environment}"
environments:
develop:
aws_region: ap-northeast-1
iam_role_plan: arn:aws:iam::ACCOUNT:role/plan-role
iam_role_apply: arn:aws:iam::ACCOUNT:role/apply-role

stack_conventions:
- root: "{service}" # {service}/{environment} 以外の任意 placeholder
# も使用可能。抽出された値は matrix item の
# トップレベル(例: {team})に展開される。
stacks:
- name: aws
directory: "aws/{environment}"
required_attributes: [aws_region, iam_role_plan, iam_role_apply]
- name: kubernetes
directory: "kubernetes/overlays/{environment}"

services:
- name: excluded-service
exclude_from_automation: true
exclusion_config:
reason: "手動デプロイが必要"
type: "permanent"
production:
aws_region: us-west-2
exclude:
- service: demo
environment: production
- team: sandbox
- name: container
paths:
- "dystopia/{service}"
- "system-components/{service}"
attributes:
repository: registry.example.com/app
```

実行可能なサンプルは `action-scripts/workflow-config.yaml` を参照してください。
### stack の定義

### 同じ stack name の複数インスタンス
| フィールド | 指定 | 動作 |
|---|---|---|
| `name` | 必須 | stack の種類。属性名やプロバイダーを制限しない |
| `id` | 任意 | インスタンス識別子。省略時は `name`。設定全体で一意 |
| `paths` | 必須 | 空でない相対パス配列。全パスに `{service}` が必要 |
| `environments` | 任意 | 環境名をキー、環境属性を値とする空でないマップ |
| `attributes` | 任意 | 環境共通の属性。`environments` と併用できない |
| `exclude` | 任意 | 除外条件の配列。省略時は空配列 |

1つのサービスで同じ stack を2つ使う場合(AWS リソース用と Stripe 用の
Terragrunt stack など)は、各エントリに異なる `id` を指定します。
共有するプロダクトは一つの定義の `paths` に追加します。独立させる場合は、同じ `name` に異なる `id` を付けた別定義にし、それぞれにパスと属性を置きます。

```yaml
# `id` はオプションです。省略時は `name` にフォールバックします。
# 1つの convention 内では、`id || name` が一意でなければなりません。
stack_conventions:
- root: "dystopia/{service}"
stacks:
- name: terragrunt
id: aws
directory: infrastructure/aws/{environment}
required_attributes: [aws_region, iam_role_plan, iam_role_apply]
- name: terragrunt
id: stripe
directory: infrastructure/stripe/{environment}
required_attributes: [aws_region, iam_role_plan, iam_role_apply]
```
`environments` のキーがその stack の環境名です。環境一覧は全 stack の和集合になり、環境指定を省略すると全定義環境が対象になります。各 stack は自身の定義環境だけを生成し、未知の環境指定はエラーになります。属性の値と型はそのまま出力され、環境間の属性キーを揃える必要はありません。

パスに `{environment}` がなくても、`environments` があれば環境ごとの対象になります。同じディレクトリを異なる環境属性で使えます。`environments` がなければ環境共通で、`environment: null` の対象を各ディレクトリにつき一度だけ生成します。この場合の属性は `attributes` から取得し、パスに `{environment}` は指定できません。

### パスの照合

パスはリポジトリルートからの完全な相対パターンです。絶対パスと `..` 要素は拒否し、先頭の `./`、余分な `/`、`.` 要素は正規化します。すべてのパターンに一致する実在ディレクトリを列挙し、存在しないパスは対象を生成しません。サービスの登録は不要です。ドットで始まるサービスは対象外です。

`{team}` などの任意 placeholder を使えます。名前は `[a-z_][a-z0-9_]*`、値はパスの一要素です。同じ名前を繰り返した場合は、すべて同じ値に一致する必要があります。glob の記号はリテラルとして扱います。任意 placeholder と matrix の固定キー、または同じ stack のいずれかの環境属性・共通属性キーが衝突する定義は拒否します。

### 除外条件

`exclude` の各要素は空でない条件マップです。`service`、`environment`、その stack のいずれかのパスにある任意 placeholder を条件にできます。属性名は条件キーとして使えません。

一つのマップ内は AND、配列内は OR で完全一致を判定します。省略したキーは制約になりません。service のみ、environment のみ、任意 placeholder のみでも指定できます。照合したパスにない抽出値を要求する条件は一致しません。

## ワークフロー統合
条件値は空でない文字列で、`/`、`.`、`..` は使えません。service はドットで始められません。環境条件は自身の定義環境だけを指定できます。環境共通 stack では environment の省略または `null` を受け付け、environment 以外の条件値に `null` は使えません。

実行可能な設定例は [workflow-config.yaml](action-scripts/workflow-config.yaml) を参照してください。

## ワークフローへの組み込み

### 1. 変更検出

Expand All @@ -142,7 +151,7 @@ jobs:
github-token: ${{ secrets.GITHUB_TOKEN }}
```

### 2. デプロイターゲット解決
### 2. デプロイ対象の解決

```yaml
name: Deploy
Expand All @@ -161,69 +170,47 @@ jobs:
pr-number: ${{ github.event.pull_request.number }}
repository: ${{ github.repository }}
github-token: ${{ secrets.GITHUB_TOKEN }}

# 以降は ${{ steps.resolve.outputs.targets }} を任意の deploy step に流す
```

実行レイヤ(`aws`, `kubernetes` など)は意図的に本リポジトリから除外しています。メンテナーの個人用 wrapper は [`panicboat/panicboat-actions`](https://github.com/panicboat/panicboat-actions) にあります。

## Matrix Output
`${{ steps.resolve.outputs.targets }}` を利用側のデプロイ処理に渡します。

`label-resolver` は `outputs.targets`(および環境変数 `DEPLOYMENT_TARGETS`)として JSON 配列を出力します。各 matrix item はフラット構造です。
実行レイヤ(`aws`, `kubernetes` など)は意図的に本リポジトリから除外しています。メンテナーの個人用 wrapper は [`panicboat/panicboat-actions`](https://github.com/panicboat/panicboat-actions) にあります。

| Key | 由来 | 補足 |
|---|---|---|
| `service` | 固定 | `deploy:<service>` ラベルの service 名 |
| `environment` | 固定 | environment-agnostic stack では `null` |
| `stack` | 固定 | 例: `aws`, `kubernetes` |
| `stack_id` | 固定 | インスタンス識別子(`id \|\| name`)。`id` 未指定時は `stack` と同じ |
| `working_directory` | 固定 | 実在する deploy 対象ディレクトリ |
| `stack_convention_root` | 固定 | マッチした root pattern の展開後の値 |
| (attributes のキー) | 動的 | `environments[].stacks[stack].*` で定義された値 |
| (captures のキー) | 動的 | マッチした pattern 中の任意 `{placeholder}` の抽出値(`service` / `environment` を除く) |
## matrix 出力

例として、次の `workflow-config.yaml` を考えます。
`label-resolver` は `outputs.targets` と環境変数 `DEPLOYMENT_TARGETS` に JSON 配列を出力します。固定キーは次の5個で、属性と任意 placeholder の抽出値を同じ階層に展開します。

```yaml
environments:
- environment: develop
stacks:
aws:
aws_region: ap-northeast-1
iam_role_plan: arn:aws:iam::ACCOUNT:role/plan-role
iam_role_apply: arn:aws:iam::ACCOUNT:role/apply-role

stack_conventions:
- root: "{team}/{service}"
stacks:
- name: aws
directory: "aws/{environment}"
```
| キー | 出力元 |
|---|---|
| `service` | ラベルまたは `deploy:all` で探索したサービス名 |
| `environment` | 定義した環境名。環境共通なら `null` |
| `stack` | stack の `name` |
| `stack_id` | 確定した `id` |
| `working_directory` | 実在する対象ディレクトリの相対パス |
| 属性のキー | 当該環境属性、または共通 `attributes` |
| 任意 placeholder のキー | 一致したパスの抽出値 |

このとき `payments/api/aws/develop` が deploy 対象として解決されると、matrix item は次のようになります。
上記の設定例で `teams/payments/api/aws/develop` が存在する場合、次の行を生成します。

```json
{
"service": "api",
"environment": "develop",
"stack": "aws",
"stack": "terragrunt",
"stack_id": "aws",
"working_directory": "payments/api/aws/develop",
"stack_convention_root": "payments/api",
"working_directory": "teams/payments/api/aws/develop",
"aws_region": "ap-northeast-1",
"iam_role_plan": "arn:aws:iam::ACCOUNT:role/plan-role",
"iam_role_apply": "arn:aws:iam::ACCOUNT:role/apply-role",
"team": "payments"
}
```

`aws_region` / `iam_role_plan` / `iam_role_apply` は `environments[0].stacks.aws` の attributes が、`team` は `root` の `{team}` プレースホルダ抽出値がそれぞれ展開されたものです。下流の Composite Action では `${{ matrix.team }}` のように任意のキーを直接参照できます。固定キーや attributes キーと衝突する placeholder 名は `config-manager validate` の段階で拒否されます。
対象の同一性は service・stack_id・environment・working_directory で決まります。同じ対象の重複は一行にまとめます。同じ対象を異なる抽出値マップで解釈するパスは、除外条件や記載順にかかわらずエラーになります。下流では `${{ matrix.team }}` のように任意のキーを参照できます。

## 開発

### 前提条件

- Ruby 4.0.3
- Ruby ([.ruby-version](action-scripts/.ruby-version))
- Bundler
- Git

Expand All @@ -236,14 +223,14 @@ bundle install
bundle exec rspec
```

### コンポーネント別テスト
### 各コンポーネントの動作確認

```bash
bundle exec ruby config-manager/bin/config-manager validate
bundle exec ruby label-dispatcher/bin/dispatcher detect
bundle exec ruby label-dispatcher/bin/dispatcher test
bundle exec ruby label-resolver/bin/resolver resolve PR_NUMBER
```

## License
## ライセンス

MIT — `LICENSE` を参照。
Loading
Loading