# 画面設計書 164-Runner編集

## 概要

本ドキュメントはGitLabのグループRunner編集画面の設計仕様を記載したものである。

### 本画面の処理概要

グループに関連付けられた既存のCI/CD Runnerの設定を編集する画面である。Runnerの説明、タグ、保護モード、実行設定などを変更し、保存することができる。

**業務上の目的・背景**：CI/CD環境の変化に応じてRunnerの設定を調整する必要がある。本画面により、Runnerの一時停止、タグの追加・変更、保護モードの切り替え、タイムアウト設定の調整などを行い、CI/CDパイプラインの実行環境を最適化できる。

**画面へのアクセス方法**：Runner詳細画面から「Edit」ボタンをクリック、または直接URL `/{group_path}/-/runners/{runner_id}/edit` にアクセスする。

**主要な操作・処理内容**：
1. Runner説明の編集
2. Runnerタグの編集
3. アクティブ状態（一時停止/有効）の切り替え
4. 保護モード（protected branch only）の設定変更
5. 未タグジョブ実行許可の設定変更
6. ロック設定の変更
7. 最大タイムアウトの設定変更
8. 変更の保存

**画面遷移**：
- 遷移元：Runner詳細画面
- 遷移先：Runner詳細画面（保存成功時）、本画面（バリデーションエラー時）

**権限による表示制御**：
- `update_runner`権限：本画面へのアクセスが可能

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 51 | Runnerレジストレーション | 主機能 | グループRunner設定の編集 |

## 画面種別

編集

## URL/ルーティング

- パス: `/{group_path}/-/runners/{runner_id}/edit`
- コントローラー: `Groups::RunnersController#edit`
- HTTPメソッド: GET（表示）、PATCH/PUT（更新）

## 入出力項目

| 項目名 | 項目ID | 入出力 | データ型 | 必須 | 説明 |
|--------|--------|--------|----------|------|------|
| Runner ID | runner_id | 入力 | Integer | 必須 | 対象RunnerのID |
| 説明 | description | 入出力 | String | 任意 | Runnerの説明文 |
| タグ | tag_list | 入出力 | Array[String] | 任意 | Runnerに設定するタグ |
| アクティブ | active | 入出力 | Boolean | 必須 | Runnerの有効/一時停止状態 |
| 保護モード | access_level | 入出力 | String | 必須 | not_protected/ref_protected |
| 未タグジョブ実行 | run_untagged | 入出力 | Boolean | 必須 | タグなしジョブを実行するか |
| ロック | locked | 入出力 | Boolean | 必須 | プロジェクトにロックするか |
| 最大タイムアウト | maximum_timeout_human_readable | 入出力 | String | 任意 | 人間可読形式（例: "1h 30m"） |

## 表示項目

| 項目名 | データソース | 説明 |
|--------|-------------|------|
| Runner ID | ci_runners.id | Runner識別子（読み取り専用） |
| 短縮SHA | ci_runners.token | トークン短縮識別子（読み取り専用） |
| 説明 | ci_runners.description | 編集可能な説明文 |
| タグ | ci_tags | 編集可能なタグ一覧 |
| アクティブ | ci_runners.active | チェックボックス |
| 保護モード | ci_runners.access_level | チェックボックス |
| 未タグジョブ実行 | ci_runners.run_untagged | チェックボックス |
| ロック | ci_runners.locked | チェックボックス |
| 最大タイムアウト | ci_runners.maximum_timeout | テキスト入力 |

## イベント仕様

### 1-保存ボタン押下

Runner設定を保存する。

- トリガー: 「Save changes」ボタンクリック
- 処理: `Ci::Runners::UpdateRunnerService`を実行
- 成功時遷移先: `/{group_path}/-/runners/{runner_id}`
- 失敗時: 本画面でエラーメッセージを表示

### 2-キャンセルボタン押下

Runner詳細画面へ戻る。

- トリガー: 「Cancel」ボタンクリック
- 遷移先: `/{group_path}/-/runners/{runner_id}`

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 編集画面表示 | ci_runners | SELECT | 現在の設定を取得 |
| 編集画面表示 | ci_tags | SELECT | 現在のタグを取得 |
| 保存 | ci_runners | UPDATE | Runner設定を更新 |
| 保存 | ci_runner_taggings | DELETE/INSERT | タグ関連を更新 |

### テーブル別更新項目詳細

#### ci_runners

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | description | ユーザー入力値 | 説明 |
| UPDATE | active | ユーザー入力値 | 有効/一時停止 |
| UPDATE | access_level | ユーザー入力値 | 0:not_protected / 1:ref_protected |
| UPDATE | run_untagged | ユーザー入力値 | タグなしジョブ実行 |
| UPDATE | locked | ユーザー入力値 | ロック状態 |
| UPDATE | maximum_timeout | ユーザー入力値 | 秒に変換して保存 |

#### ci_runner_taggings

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | runner_id | 対象Runner ID | 既存タグ関連削除 |
| INSERT | runner_id, tag_id | 新しいタグ関連 | 新規タグ関連追加 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------|
| MSG001 | 成功 | Runner was successfully updated. | 更新成功時 |
| MSG002 | エラー | バリデーションエラーメッセージ | バリデーション失敗時 |
| MSG003 | エラー | can not be empty when runner is not allowed to pick untagged jobs | タグなし実行無効でタグ未設定時 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| 権限不足 | 404ページを表示 |
| Runner未存在 | 404ページを表示 |
| バリデーションエラー | 編集画面でエラーメッセージを表示 |
| タグ数上限超過 | エラーメッセージ表示 |
| タイムアウト値不正 | エラーメッセージ表示 |

## 備考

- 本画面はVue.jsコンポーネントによるSPA構成
- `maximum_timeout_human_readable`は`ChronicDurationAttribute`で人間可読形式と秒数を相互変換
- タグとrun_untaggedの組み合わせバリデーションに注意
- Runnerの一時停止（active=false）はジョブの新規割り当てを停止するが、実行中ジョブには影響しない

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

Runner編集時のバリデーションと許可項目を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | runner.rb | `app/models/ci/runner.rb` | FORM_EDITABLE、バリデーション、ChronicDurationAttribute |

**読解のコツ**:
- `FORM_EDITABLE`（行91）で編集可能項目を確認
- `chronic_duration_attr`（行269-270）で時間形式変換を確認
- `tag_constraints`（行642-652）でタグバリデーションを確認

#### Step 2: エントリーポイントを理解する

HAMLテンプレートとコントローラーの処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | edit.html.haml | `app/views/groups/runners/edit.html.haml` | Vueマウントポイント、runner_id設定 |
| 2-2 | runners_controller.rb | `app/controllers/groups/runners_controller.rb` | edit/updateアクション |

**主要処理フロー**:
1. **行28**: `edit`アクションは空（Vueで表示処理）
2. **行30-35**: `update`アクションでUpdateRunnerServiceを呼び出し
3. **行56-58**: `runner_params`でStrong Parametersを定義
4. **行60-64**: `authorize_update_runner!`で権限チェック

#### Step 3: 更新サービスを理解する

Runner更新のビジネスロジックを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | update_runner_service.rb | `app/services/ci/runners/update_runner_service.rb` | 更新ロジック |

#### Step 4: フロントエンド初期化を理解する

Vue.jsアプリケーションの初期化処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | index.js | `app/assets/javascripts/pages/groups/runners/edit/index.js` | エントリーポイント |
| 4-2 | runner_edit/index.js | `app/assets/javascripts/ci/runner/runner_edit/index.js` | Vueアプリ初期化 |

### プログラム呼び出し階層図

```
Groups::RunnersController#edit
    │
    ├─ authorize_update_runner! (認可チェック)
    │
    ├─ runner (Runnerデータ取得)
    │
    └─ View: edit.html.haml
           └─ JavaScript: initRunnerEdit()
                  └─ Vue: RunnerEditApp
                         │
                         └─ Form Submit
                                │
                                ▼
Groups::RunnersController#update
    │
    ├─ authorize_update_runner! (認可チェック)
    │
    ├─ Ci::Runners::UpdateRunnerService.new
    │      └─ execute(runner_params)
    │             └─ Ci::Runner#update
    │
    └─ 成功: redirect_to group_runner_path
       失敗: render 'edit'
```

### データフロー図

```
[入力]               [処理]                    [出力]

URLリクエスト ───▶ RunnersController#edit ───▶ HAMLテンプレート
(runner_id)              │
                         ▼
                  認可チェック
                         │
                         ▼
                  Runner取得 ───▶ Vue初期化 ───▶ フォーム表示

フォーム送信 ───▶ RunnersController#update
                         │
                         ▼
                  UpdateRunnerService
                         │
                         ▼
                  ci_runners UPDATE
                         │
                         ├─ 成功 ───▶ Runner詳細画面へリダイレクト
                         └─ 失敗 ───▶ 編集画面でエラー表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| edit.html.haml | `app/views/groups/runners/edit.html.haml` | テンプレート | Vueマウントポイント定義 |
| runners_controller.rb | `app/controllers/groups/runners_controller.rb` | コントローラー | リクエスト処理・認可 |
| runner.rb | `app/models/ci/runner.rb` | モデル | Runnerデータ定義・バリデーション |
| update_runner_service.rb | `app/services/ci/runners/update_runner_service.rb` | サービス | Runner更新ロジック |
| index.js | `app/assets/javascripts/ci/runner/runner_edit/index.js` | JavaScript | Vue初期化 |
