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 は名前付きのキャッシュ(node、pip、maven、docker)を便利機能として提供しています。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 をインストール