# 画面設計書 293-Bitbucketインポート状態

## 概要

本ドキュメントは、GitLabにおけるBitbucket Cloud（bitbucket.org）からのインポート状態・リポジトリ選択画面の設計を記載したものである。

### 本画面の処理概要

Bitbucket Cloud（OAuth認証済み）からインポート可能なリポジトリの一覧を表示し、ユーザーがインポートするリポジトリを選択・実行できる画面である。OAuth2認証によりBitbucket Cloudと連携し、ユーザーがアクセス可能なリポジトリを一覧表示する。

**業務上の目的・背景**：Bitbucket Cloudは、Atlassianが提供するクラウドベースのGitホスティングサービスである。チームがBitbucket CloudからGitLabへ移行する際、既存のリポジトリをスムーズにインポートするために使用する。OAuth認証により、パスワード入力なしでセキュアにリポジトリにアクセスできる。

**画面へのアクセス方法**：
1. サイドバーまたはヘッダーから「プロジェクト新規作成」を選択
2. 「Import project」タブを選択
3. 「Bitbucket Cloud」を選択
4. OAuth認証画面でBitbucketアカウントにログイン・認可
5. 認証成功後、自動的に本画面へリダイレクト

**主要な操作・処理内容**：
1. Bitbucket Cloudのリポジトリ一覧を表示
2. リポジトリのフィルタリング・検索
3. インポート先ネームスペースの選択
4. インポート先プロジェクト名のカスタマイズ
5. 「Import」ボタンでインポート実行
6. インポート状態のリアルタイム監視

**画面遷移**：
- 遷移元：Bitbucket OAuth認証画面
- 遷移先：インポートされたプロジェクト詳細画面

**権限による表示制御**：
- プロジェクト作成権限を持つユーザーのみがインポートを実行可能
- namespace_idが指定されている場合、そのネームスペースへのインポート権限が必要
- Bitbucket側での権限に基づきリポジトリ一覧が表示される

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 107 | Bitbucketインポート | 主機能 | Bitbucket Cloudからのインポート処理・状態管理 |

## 画面種別

一覧・操作

## URL/ルーティング

```
GET /import/bitbucket/status
GET /import/bitbucket/status.json
POST /import/bitbucket
GET /import/bitbucket/realtime_changes.json
GET /users/auth/-/import/bitbucket/callback
```

ルーティング定義: `config/routes/import.rb`
```ruby
resource :bitbucket, only: [:create], controller: :bitbucket do
  get :status
  get :callback
  get :realtime_changes
end
```

## 入出力項目

### 入力項目（リポジトリ選択時）

| 項目名 | 項目ID | 型 | 必須 | 説明 |
|--------|--------|-----|------|------|
| リポジトリID | repo_id | 文字列 | 必須 | インポート対象のリポジトリ識別子（owner/repo形式、/を___に変換） |
| 新しい名前 | new_name | 文字列 | 任意 | GitLabでのプロジェクト名（デフォルトは元の名前） |
| 新しいネームスペース | new_namespace | 文字列 | 任意 | インポート先ネームスペース |
| フィルター | filter | 文字列 | 任意 | リポジトリ名での絞り込み |
| カーソル | after | 文字列 | 任意 | ページネーション用カーソル |

### 出力項目（JSON API）

| 項目名 | 説明 |
|--------|------|
| imported_projects | インポート済み/進行中のプロジェクト一覧 |
| provider_repos | インポート可能なリポジトリ一覧 |
| incompatible_repos | 互換性のないリポジトリ一覧 |
| page_info | ページネーション情報（カーソルベース） |

## 表示項目

| 項目名 | 説明 |
|--------|------|
| ページタイトル | 「Bitbucket import」 |
| Bitbucketアイコン | Bitbucketロゴアイコン（48px） |
| リポジトリ一覧 | インポート可能なリポジトリのテーブル |
| インポート状態 | 各リポジトリのインポート進捗状況 |
| フィルター入力 | リポジトリ名での絞り込み |
| ネームスペース選択 | インポート先の選択 |

## イベント仕様

### 1-OAuth認証コールバック

OAuth認証後のコールバック処理：

```ruby
# app/controllers/import/bitbucket_controller.rb (行16-35)
def callback
  auth_state = session[:bitbucket_auth_state]
  session[:bitbucket_auth_state] = nil

  if auth_state.blank? || !ActiveSupport::SecurityUtils.secure_compare(auth_state, params[:state])
    go_to_bitbucket_for_permissions
  else
    response = oauth_client.auth_code.get_token(
      params[:code],
      redirect_uri: users_import_bitbucket_callback_url(namespace_id: params[:namespace_id])
    )

    session[:bitbucket_token]         = response.token
    session[:bitbucket_expires_at]    = response.expires_at
    session[:bitbucket_expires_in]    = response.expires_in
    session[:bitbucket_refresh_token] = response.refresh_token

    redirect_to status_import_bitbucket_url(namespace_id: params[:namespace_id])
  end
end
```

### 2-インポート実行

「Import」ボタンを押下すると以下の処理が実行される：

```ruby
# app/controllers/import/bitbucket_controller.rb (行56-99)
def create
  bitbucket_client = Bitbucket::Client.new(credentials)

  repo_id = params[:repo_id].to_s
  name = repo_id.gsub('___', '/')
  repo = bitbucket_client.repo(name)
  project_name = params[:new_name].presence || repo.name

  repo_owner = repo.owner
  repo_owner = current_user.username if repo_owner == bitbucket_client.user.username
  namespace_path = params[:new_namespace].presence || repo_owner
  target_namespace = find_or_create_namespace(namespace_path, current_user)

  if current_user.can?(:import_projects, target_namespace)
    session[:bitbucket_token] = bitbucket_client.connection.token

    project = Gitlab::BitbucketImport::ProjectCreator.new(
      repo,
      project_name,
      target_namespace,
      current_user,
      credentials
    ).execute

    if project.persisted?
      render json: ProjectSerializer.new.represent(project, serializer: :import)
    else
      render json: { errors: project_save_error(project) }, status: :unprocessable_entity
    end
  else
    render json: { errors: s_('BitbucketImport|You are not allowed to import projects in this namespace.') },
      status: :unprocessable_entity
  end
end
```

### 3-リアルタイム状態更新

ポーリングによりインポート状態をリアルタイム更新（基底クラスと同様）。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| Importボタン押下 | projects | INSERT | 新規プロジェクトを作成 |
| Importボタン押下 | project_import_data | INSERT | インポートデータを保存 |
| Importボタン押下 | import_states | INSERT | インポート状態を記録 |
| Importボタン押下 | namespaces | INSERT/SELECT | インポート先ネームスペースを取得/作成 |

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

#### projects

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | new_name または リポジトリ名 | プロジェクト名 |
| INSERT | path | プロジェクト名から生成 | URLパス |
| INSERT | namespace_id | target_namespace.id | インポート先ネームスペース |
| INSERT | import_type | 'bitbucket' | インポート種別 |
| INSERT | import_url | Bitbucket リポジトリURL | インポート元URL |
| INSERT | creator_id | current_user.id | 作成者 |

## メッセージ仕様

| メッセージID | メッセージ種別 | メッセージ内容 | 表示条件 |
|-------------|---------------|---------------|---------|
| MSG001 | エラー | You are not allowed to import projects in this namespace. | ネームスペースへのインポート権限がない場合 |
| MSG002 | エラー | {project_save_error} | プロジェクト保存エラー時 |

## 例外処理

| 例外パターン | 処理内容 |
|-------------|---------|
| OAuthトークンがセッションにない | Bitbucket OAuth認証画面へリダイレクト |
| OAuth2::Error | OAuth認証画面へリダイレクトして再認証を促す |
| Bitbucket::Error::Unauthorized | OAuth認証画面へリダイレクト |
| 権限不足 | 422エラーとエラーメッセージを返却 |

## 備考

- ページネーション対応（`paginatable: true`、カーソルベース）
- Bitbucket CloudとBitbucket Serverは異なるAPIを使用
- OAuthトークンは自動更新される（refresh_token使用）
- リポジトリIDは`owner/repo`形式だが、パラメータでは`___`で区切る

---

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

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

### 推奨読解順序

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

OAuth認証情報とBitbucketリポジトリ情報の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | bitbucket_controller.rb | `app/controllers/import/bitbucket_controller.rb` | credentials（行190-197）、session変数 |

**読解のコツ**: Bitbucket CloudはOAuth2を使用するため、トークンの有効期限管理が重要。

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

OAuth認証フローとステータス画面の表示を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | bitbucket_controller.rb | `app/controllers/import/bitbucket_controller.rb` | callback（行16-35）、status（行37-54） |
| 2-2 | import.rb | `config/routes/import.rb` | Bitbucket関連ルーティング（行37-41） |

**主要処理フロー**:
1. **行16-35**: `callback`アクション - OAuth認証コールバック処理
2. **行37-54**: `status`アクション - リポジトリ一覧表示

#### Step 3: ビューレイヤーを理解する

画面表示の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | status.html.haml | `app/views/import/bitbucket/status.html.haml` | パーシャル呼び出し |
| 3-2 | _githubish_status.html.haml | `app/views/import/_githubish_status.html.haml` | 共通コンポーネント |

#### Step 4: インポート処理を理解する

インポート実行の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | bitbucket_controller.rb | `app/controllers/import/bitbucket_controller.rb` | create（行56-99）、find_or_create_namespace継承 |

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

```
OAuth認証フロー
    │
    └─ /users/auth/-/import/bitbucket/callback
           │
           └─ Import::BitbucketController#callback
                  │
                  ├─ OAuth2トークン取得
                  │
                  └─ redirect_to status_import_bitbucket_url

GET /import/bitbucket/status
    │
    └─ Import::BitbucketController#status
           │
           ├─ HTML: ステータス画面表示
           │
           └─ JSON: リポジトリ一覧返却

POST /import/bitbucket
    │
    └─ Import::BitbucketController#create
           │
           ├─ Bitbucket::Client#repo
           │
           ├─ find_or_create_namespace
           │
           └─ Gitlab::BitbucketImport::ProjectCreator#execute
```

### データフロー図

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

OAuth認証         ───▶  OAuth2::Client                 ───▶  セッション保存
(Bitbucket)              #auth_code.get_token                 (token, expires_at, etc.)
                                                              │
                                                              ▼
セッション情報    ───▶  Bitbucket::Client              ───▶  リポジトリ一覧
                        #repos                                (JSON)
                                                              │
                                                              ▼
ユーザー選択      ───▶  BitbucketImport::              ───▶  Project (作成)
(repo_id等)              ProjectCreator#execute
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| bitbucket_controller.rb | `app/controllers/import/bitbucket_controller.rb` | コントローラー | リクエスト処理 |
| status.html.haml | `app/views/import/bitbucket/status.html.haml` | テンプレート | ステータス画面表示 |
| _githubish_status.html.haml | `app/views/import/_githubish_status.html.haml` | パーシャル | インポート状態共通UI |
| base_controller.rb | `app/controllers/import/base_controller.rb` | コントローラー | 基底クラス |
| project_creator.rb | `lib/gitlab/bitbucket_import/project_creator.rb` | ライブラリ | プロジェクト作成 |
| client.rb | `lib/bitbucket/client.rb` | ライブラリ | Bitbucket API クライアント |
