atlassian-cli はコミュニティによる独立したオープンソースプロジェクトです。Atlassian と提携・関連しておらず、Atlassian による承認、推奨、後援のいずれも受けておらず、Atlassian が提供する公式 CLI(acli)でもありません。製品名は互換性を示す目的でのみ使用しています。

全体像

Bitbucket Pipelines を GitHub Actions に移行するには、リポジトリ直下の bitbucket-pipelines.yml という 1 つのファイルを .github/workflows/ 以下の 1 つ以上のワークフローファイルに移し、4 つのものを変換します。pipelines: セクションは on: トリガーに、各 step はジョブに、各 script: のリストは run: コマンドに、ステップの image:container: またはランナーとセットアップアクションの組み合わせになります。作業はこれだけです。キャッシュ、サービス、シークレット、デプロイなど、それ以外はすべてこの 4 つの応用です。

2 つのシステムは、宣言的な YAML、コンテナ化されたステップ、環境変数として注入されるシークレットという思想を共有していますが、構造が異なります。Bitbucket は CI をすべて 1 つのファイルに置き、ビルドは暗黙です。GitHub Actions は、イベントの集合ごとにスコープを絞った小さなワークフローファイルを多数用意することを想定しています。この違いが混乱のほとんどの原因であり、同時に、移行がモノリシックなパイプラインを目的別のワークフローに分割する好機である理由でもあります。

このガイドでは、各構成要素を YAML の左右比較で変換し、さらに atlassian-cli というコマンドラインツールで数十のリポジトリのパイプラインを棚卸しし、ワークフローファイルに手を付ける前に移行対象の全体像を把握する方法を示します。

Atlassian 自身の CLI との違い: atlassian-cli はコミュニティによる独立したオープンソースプロジェクトです。Atlassian と提携・関連しておらず、Atlassian による承認、推奨、後援、保守のいずれも受けておらず、Atlassian が提供する公式 CLI(acli)でもありません。ベンダーによる一次サポートが必要なら公式の acli を、Jira、Confluence、Bitbucket、JSM をまたぐ無料の Rust バイナリが 1 つ欲しいなら atlassian-cli を使ってください。ここでは、すべてのリポジトリをクローンせずに Bitbucket API からパイプライン設定を読める点が役立ちます。

概念の対応表

変換の作業中は、この表を別タブに開いておいてください。各行は、実際の bitbucket-pipelines.yml で出会う構成要素と、それに最も近い GitHub Actions の対応物です。

Bitbucket Pipelines GitHub Actions 備考
bitbucket-pipelines.yml .github/workflows/*.yml 1 つのファイルが 1 つまたは複数のワークフローファイルになる。
pipelines: default on: [push] より具体的な指定に一致しないすべてのブランチで実行される。
pipelines: branches: main on: push: branches: [main] ブランチ単位のトリガー。
pipelines: pull-requests on: pull_request PR をきっかけにしたチェック。
pipelines: tags on: push: tags リリースタグのビルド。
pipelines: custom on: workflow_dispatch 手動で起動するパイプライン。
step job (or a step in a job) Bitbucket の各ステップは、それぞれ独立した新しい環境。
image: container: or runs-on + setup イメージを固定するか、ubuntu-latest 上でセットアップアクションを使う。
script: run: シェルコマンドを 1 行に 1 つ。
caches: actions/cache またはセットアップアクションに内蔵されたキャッシュのオプション。
artifacts: upload-artifact / download-artifact ジョブ間で明示的にアップロードとダウンロードを行う。
definitions: services: services: ジョブ単位のサイドカーコンテナ。
parallel: separate jobs / matrix needs: でつながない限り、ジョブは並列に実行される。
deployment: production environment: production 環境には承認とスコープを絞ったシークレットが紐づく。
repository / deployment variables secrets / vars / environment secrets シークレットの値は再入力が必要。エクスポートはできない。
clone: depth actions/checkout fetch-depth チェックアウトは Bitbucket では暗黙、Actions では明示。
max-time timeout-minutes ステップ単位とジョブ単位のタイムアウトの違い。

トリガー: pipelines から on: へ

Bitbucket では、すべてのトリガーが 1 つの pipelines: キーの下にあり、ビルドは暗黙です。GitHub Actions では、各ワークフローファイルが自分の on: イベントを宣言し、すべてのジョブに名前を付けます。両者の最小構成のデフォルトビルドを示します。

# bitbucket-pipelines.yml
image: node:20
pipelines:
  default:
    - step:
        name: Build and test
        caches:
          - node
        script:
          - npm ci
          - npm test
# .github/workflows/ci.yml
name: CI
on: [push]
jobs:
  build-and-test:
    runs-on: ubuntu-latest
    container: node:20
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm test

重要な違いが 2 つあります。1 つ目は、GitHub Actions がコードを自動でクローンしないことです。Bitbucket が暗黙にクローンするのに対し、actions/checkout ステップが必須になります。2 つ目は、caches: node という省略記法に GitHub 側の直接の対応物がないことです。setup-node のステップに cache: npm を追加するか、actions/cache を自分で組み立てます(後述)。

ブランチ単位のパイプラインとプルリクエストのパイプラインは、スコープを絞ったトリガーにきれいに分かれます。

# bitbucket-pipelines.yml
pipelines:
  pull-requests:
    '**':
      - step:
          script:
            - npm run lint
  branches:
    main:
      - step:
          name: Deploy
          deployment: production
          script:
            - ./deploy.sh
# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - run: ./deploy.sh

lint のチェックが pull_request をトリガーとする別のワークフローに移っている点に注目してください。このように関心を分けるのは Actions では定石で、各ワークフローのログも読みやすくなります。

ステップ、スクリプト、イメージ

Bitbucket の step は、独自の image を持つ新しいコンテナです。最も近いのは GitHub Actions の job で、こちらも独立して実行され、container を固定できます。Bitbucket のステップの内側にある処理は run: の行に対応し、別々の Bitbucket ステップは別々のジョブに対応します。順序が重要な場合は needs: でつなぎます。

2 つ目が 1 つ目に依存する、2 つの Bitbucket ステップの例です。

# bitbucket-pipelines.yml
pipelines:
  default:
    - step:
        name: Build
        script:
          - npm ci
          - npm run build
        artifacts:
          - dist/**
    - step:
        name: Publish
        script:
          - ./publish.sh dist/
# .github/workflows/release.yml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/
  publish:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: dist
          path: dist/
      - run: ./publish.sh dist/

移行で最もよくつまずくのがここです。Bitbucket は連続するステップ間でアーティファクトを自動的に受け渡しますが、GitHub Actions のジョブは既定で何も共有しません。生成側のジョブで upload-artifact を、利用側のジョブで download-artifact を実行し、needs: でつなぐ必要があります。アップロードを忘れると、2 つ目のジョブは空のワークスペースで始まり、分かりにくい形で失敗します。

キャッシュ、アーティファクト、サービス

Bitbucket は名前付きのキャッシュ(nodepipmavendocker)を便利機能として提供しています。Actions ではキャッシュのキーとパスを自分で書くか、各言語のセットアップアクションが備えるキャッシュ機能に任せます。

# GitHub Actions: explicit cache
      - uses: actions/cache@v4
        with:
          path: ~/.npm
          key: npm-${{ hashFiles('package-lock.json') }}

# or, simpler, let setup-node manage it
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

サービスコンテナ(テストが必要とするデータベース、キュー、その他のバックエンドサービス)は、ほぼ 1 対 1 で対応します。Bitbucket のサービス定義は、ジョブ上の services: ブロックになり、変数は env: に移し、ジョブから到達できるように ports: のマッピングを追加します。

# bitbucket-pipelines.yml
pipelines:
  default:
    - step:
        script:
          - npm test
        services:
          - postgres
definitions:
  services:
    postgres:
      image: postgres:16
      variables:
        POSTGRES_DB: test
        POSTGRES_PASSWORD: secret
# .github/workflows/ci.yml
jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_DB: test
          POSTGRES_PASSWORD: secret
        ports:
          - 5432:5432
    steps:
      - uses: actions/checkout@v4
      - run: npm test

シークレットはセキュリティ上の理由から、プラットフォーム間でエクスポートできません。Bitbucket のリポジトリ変数とデプロイ変数は、GitHub のリポジトリシークレット、組織シークレット、環境シークレットとして入力し直す必要があります。この手順は手作業になるため、計画に入れてください。「Bitbucket では緑、Actions では赤」という初回実行の最も多い原因です。

並列ステップとカスタムパイプライン

Bitbucket は、parallel: ブロックで囲まない限りステップを順番に実行します。GitHub Actions は逆で、ジョブは既定で並列に実行され、順序を付けるときだけ needs: を使います。したがって parallel のブロックは、間に needs: を持たない 2 つの独立したジョブになります。

# bitbucket-pipelines.yml
pipelines:
  default:
    - parallel:
        - step:
            name: Lint
            script: [npm run lint]
        - step:
            name: Unit tests
            script: [npm test]
# .github/workflows/ci.yml
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm run lint
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm test

push ではなく手動で起動するカスタムパイプラインは、on: workflow_dispatch に対応します。Bitbucket では、名前付きのカスタムパイプラインを CLI から次のように起動します。

# Trigger a named custom pipeline in Bitbucket
atlassian-cli bitbucket --workspace myteam pipeline trigger api-service \
  --ref-name main --custom-pipeline s3-access-test

GitHub Actions での対応物は workflow_dispatch トリガーを持つワークフローです。入力を公開しておけば、実行する人がパラメーターを渡せるため、バリエーションごとに別のパイプラインをハードコードせずに済みます。移行の前に、実際に存在するカスタムパイプラインの名前を一覧し、取りこぼしを防いでください。

# See every pipeline (incl. custom) configured for a repo
atlassian-cli bitbucket --workspace myteam pipeline list api-service

大規模な移行

1 つのリポジトリの変換は 20 分の作業です。60 のリポジトリとなると 1 つのプロジェクトになり、難しいのは YAML ではありません。そもそもどのリポジトリにパイプラインがあるのか、どれがサービスを使っているのか、どのカスタムパイプラインが業務上重要なのかを把握することです。ここで CLI が力を発揮します。設定を読むためにすべてのリポジトリをクローンする代わりに、各 bitbucket-pipelines.yml を API 経由でデフォルトブランチから直接取得します。

まず、認証済みであることを確認し、ワークスペース内のリポジトリを列挙します。

# Verify the active Bitbucket identity
atlassian-cli bitbucket whoami

# List repositories as JSON for scripting
atlassian-cli bitbucket --workspace myteam repo list --format json

次に、すべてのリポジトリをループし、commit browse でパイプラインファイルを読みます。これはクローンなしで、指定した ref のファイルを出力します。何も出力されないリポジトリには、移行すべきパイプラインがないということです。

# Audit the migration surface across a whole workspace
atlassian-cli bitbucket --workspace myteam repo list --format json \
  | jq -r '.[].slug' \
  | while read -r repo; do
      echo "== $repo =="
      atlassian-cli bitbucket --workspace myteam commit browse "$repo" \
        --commit main --path bitbucket-pipelines.yml 2>/dev/null \
        || echo "  (no bitbucket-pipelines.yml)"
    done

この出力をファイルにリダイレクトすれば、ワークスペース内のすべてのパイプライン設定を 1 つの文書にまとめられます。services: を検索すればデータベースコンテナが必要なリポジトリが、parallel: を検索すればファンアウトするビルドが、deployment: を検索すれば本番に触れるものが見つかります。この棚卸しが、リスク順に並んだ移行のバックログになります。

大規模移行のもう 1 つのコツです。リポジトリを Actions に切り替える前に、Bitbucket のパイプラインを 1 回実行して結果を記録し、正常に動いた状態のベースラインを取っておくと、最初の GitHub Actions の実行と比較できます。

# Kick a baseline run, then confirm it finished
atlassian-cli bitbucket --workspace myteam pipeline trigger api-service --ref-name main
atlassian-cli bitbucket --workspace myteam pipeline list api-service

より詳しい起動オプションは、姉妹記事のCLI から Bitbucket Pipelines を起動するが ref、変数、カスタムパイプラインを詳しく扱っています。CI だけでなくリポジトリ自体を移す場合はBitbucket から GitHub への移行を参照してください。上で使ったフラグはすべてコマンドリファレンスに記載があり、繰り返し使える棚卸しスクリプトは Bitbucket リポジトリ監査のランブックにあります。

よくある質問

bitbucket-pipelines.yml を GitHub Actions のワークフローに変換するには?

対応づけは機械的な作業で、魔法ではありません。bitbucket-pipelines.yml をリポジトリ直下から .github/workflows/ci.yml に移します。各 pipelines: セクションを on: トリガーに、各ステップをジョブまたはジョブ内のステップに、各 script: のリストを run: コマンドに変換します。ステップの image:container:(またはランナーの runs-on とセットアップアクションの組み合わせ)になります。1 コマンドで書き換える方法はありませんが、1 つのリポジトリを変換すれば、あとは同じパターンの繰り返しです。

Bitbucket のカスタムパイプラインに相当する GitHub Actions の機能は何ですか?

Bitbucket のカスタムパイプライン(push ではなく手動で起動するもの)は、GitHub Actions の on: workflow_dispatch に対応します。名前付きのカスタムパイプラインはそれぞれ、workflow_dispatch トリガーを持つ独立したワークフローファイルになるか、共通のディスパッチ用ワークフローの入力になります。移行の前にすべてのカスタムパイプライン名を洗い出すには、atlassian-cli bitbucket --workspace myteam pipeline list api-service で一覧します。

Bitbucket Pipelines のサービスは GitHub Actions のどれに対応しますか?

Bitbucket で definitions: services: の下に定義したサービスは、GitHub Actions のジョブ上の services: ブロックになります。サービスのイメージはそのまま引き継がれ、サービスの変数はサービスの env: マップになり、ジョブから到達できるように通常は ports: のマッピングを追加します。たとえば Bitbucket の postgres サービスは、services: postgres: image: postgres:16 に env ブロックと ports: 5432:5432 を加えた形になります。

Bitbucket Pipelines を GitHub Actions に自動変換するツールはありますか?

1 対 1 の変換を保証する自動コンバーターはありません。キャッシュ、サービス、デプロイ環境、シークレットの設定方法が、それぞれのシステムで異なるからです。atlassian-cli は YAML を書き換えませんが、移行対象の棚卸しはできます。どのリポジトリにパイプラインがあるかを一覧し、各 bitbucket-pipelines.yml をデフォルトブランチから直接読み、カスタムパイプライン名を列挙するため、着手前に何を変換する必要があるかを正確に把握できます。

移行の前にパイプラインを棚卸しする

無料でオープンソースの atlassian-cli をインストールすれば、ワークスペース内のすべての bitbucket-pipelines.yml をコマンド 1 つで読み取れます。

atlassian-cli をインストール

関連リソース