Alat Migrasi Bzlmod

Untuk menyederhanakan proses yang sering kali kompleks saat berpindah dari WORKSPACE ke Bzlmod, sebaiknya gunakan skrip migrasi. Alat helper ini mengotomatiskan banyak langkah yang terlibat dalam memigrasikan sistem pengelolaan dependensi eksternal Anda.

Catatan: Jika Anda ingin mencoba migrasi Bzlmod yang didukung AI, lihat Penyiapan Agen Migrasi Bzlmod.

Fungsi Inti

Fungsi utama skrip ini adalah:

  • Mengumpulkan informasi dependensi: Menganalisis file WORKSPACE project Anda untuk mengidentifikasi repositori eksternal yang digunakan oleh target build yang ditentukan, menggunakan flag experimental_repository_resolved_file Bazel untuk membuat file dependensi yang di-resolve yang berisi informasi ini.
  • Mengidentifikasi dependensi langsung: Menggunakan bazel query untuk menentukan repositori mana yang merupakan dependensi langsung untuk target yang ditentukan.
  • Memigrasikan ke Bzlmod: Menerjemahkan dependensi WORKSPACE yang relevan ke Bzlmod yang setara. Proses ini terdiri dari dua langkah:
    1. Memperkenalkan semua dependensi langsung yang diidentifikasi ke file MODULE.bazel.
    2. Mem-build target yang ditentukan dengan Bzlmod diaktifkan, lalu mengidentifikasi dan memperbaiki error yang dapat dikenali secara berulang. Langkah ini diperlukan karena beberapa dependensi mungkin tidak ada pada langkah pertama.
  • Membuat laporan migrasi: Membuat file migration_info.md yang mendokumentasikan proses migrasi. Laporan ini mencakup daftar dependensi langsung, deklarasi Bzlmod yang dihasilkan, dan langkah manual apa pun yang mungkin diperlukan untuk menyelesaikan migrasi.

Alat migrasi mendukung:

  • Dependensi yang tersedia di Bazel Central Registry
  • Aturan repositori kustom yang ditentukan pengguna
  • Dependensi pengelola paket
    • Maven
    • Go
    • Python

Catatan Penting:

  • Alat migrasi adalah utilitas upaya terbaik. Selalu periksa kembali rekomendasinya untuk memastikan kebenarannya.
  • Gunakan alat migrasi dengan Bazel 7 (tidak didukung dengan Bazel 8).

Cara Menggunakan Alat Migrasi

Sebelum memulai:

  • Upgrade ke rilis Bazel 7 terbaru, yang memberikan dukungan yang kuat untuk WORKSPACE dan Bzlmod.
  • Pastikan perintah berikut berhasil dijalankan untuk target build utama project Anda:

    bazel build --nobuild --enable_workspace --noenable_bzlmod <targets>
    

Perintah untuk menjalankan skrip

Setelah prasyarat terpenuhi, jalankan perintah berikut untuk menggunakan alat migrasi:

# Clone the Bazel Central Registry repository
git clone https://github.com/bazelbuild/bazel-central-registry.git
cd bazel-central-registry

# Build the migration tool
bazel build //tools:migrate_to_bzlmod

# Create a convenient alias for the tool
alias migrate2bzlmod=$(realpath ./bazel-bin/tools/migrate_to_bzlmod)

# Navigate to your project's root directory and run the tool
cd <your project root>
migrate2bzlmod -t <targets>

File yang dihasilkan oleh skrip ini

  • MODULE.bazel - File manifes pusat untuk Bzlmod, yang mendeklarasikan metadata project dan dependensi langsungnya pada modul Bazel lainnya.
  • migration_info.md - File yang memberikan petunjuk langkah demi langkah tentang cara alat migrasi dijalankan, yang dirancang untuk membantu penyelesaian proses migrasi secara manual, jika diperlukan.
  • resolved_deps.py - Berisi daftar lengkap dependensi eksternal project, yang dihasilkan dengan menganalisis file WORKSPACE project, yang berfungsi sebagai referensi selama transisi.
  • query_direct_deps - Berisi informasi yang relevan dengan migrasi terkait target yang digunakan, yang diperoleh dengan memanggil Bazel dengan --output=build pada file WORKSPACE project. File ini terutama digunakan oleh skrip migrasi.
  • extension_for_XXX - File yang berisi definisi ekstensi modul. Alat migrasi menghasilkan file ini untuk dependensi yang bukan modul Bazel standar, tetapi dapat dikelola menggunakan ekstensi modul Bzlmod.

Tanda

Tanda yang tersedia dalam skrip migrasi ini adalah:

  • --t/--target: Target yang akan dimigrasikan. Tanda ini dapat diulang, dan target akan diakumulasikan.
  • --i/--initial: Menghapus file MODULE.bazel, resolved_deps.py, migration_info.md, dan memulai dari awal - Mendeteksi dependensi langsung, mengenalkannya di MODULE.bazel, dan menjalankan kembali pembuatan dependensi yang di-resolve.

Pembersihan pascamigrasi

  • Hapus migration_info.md, resolved_deps.py, dan query_direct_deps.
  • Bersihkan komentar dari file MODULE.bazel yang digunakan untuk migrasi, seperti # -- bazel_dep definitions -- #.

Contoh Migrasi

Untuk melihat skrip migrasi beraksi, pertimbangkan skenario berikut saat dependensi Python, Maven, dan Go dideklarasikan dalam file WORKSPACE.

Klik di sini untuk melihat file WORKSPACE

workspace(name="example")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load(":my_custom_macro.bzl", "my_custom_macro")

http_archive(
    name = "rules_cc",
    sha256 = "b8b918a85f9144c01f6cfe0f45e4f2838c7413961a8ff23bc0c6cdf8bb07a3b6",
    strip_prefix = "rules_cc-0.1.5",
    urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.1.5/rules_cc-0.1.5.tar.gz"],
)

# Module dependency
# -------------------
http_archive(
    name = "rules_shell",
    sha256 = "3e114424a5c7e4fd43e0133cc6ecdfe54e45ae8affa14fadd839f29901424043",
    strip_prefix = "rules_shell-0.4.0",
    url = "https://github.com/bazelbuild/rules_shell/releases/download/v0.4.0/rules_shell-v0.4.0.tar.gz",
)

# Repo rule
# -------------------
http_archive(
    name = "com_github_cockroachdb_cockroach",
    sha256 = "6c3568ef244ce6b874694eeeecb83ed4f5d5dff6cf037c952ecde76828a6c502",
    strip_prefix = "cockroach-22.1.6",
    url = "https://github.com/cockroachdb/cockroach/archive/v22.1.6.tar.gz",
)

# Module extension
# -------------------
# Macro which invokes repository_rule
my_custom_macro(
    name = "my_custom_repo",
)

# Go dependencies
# -------------------
http_archive(
    name = "io_bazel_rules_go",
    integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip",
        "https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip",
    ],
)

http_archive(
    name = "bazel_gazelle",
    integrity = "sha256-12v3pg/YsFBEQJDfooN6Tq+YKeEWVhjuNdzspcvfWNU=",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz",
        "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz",
    ],
)

load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")

go_rules_dependencies()
go_register_toolchains(version = "1.23.1")
gazelle_dependencies()

go_repository(
    name = "org_golang_x_net",
    importpath = "golang.org/x/net",
    sum = "h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=",
    version = "v0.0.0-20190311183353-d8887717615a",
    build_file_proto_mode = "disable",
    build_naming_convention = "import",
)

# Python dependencies
# -------------------
http_archive(
    name = "rules_python",
    integrity = "sha256-qDdnnxOC8mlowe5vg5x9r5B5qlMSgGmh8oFd7KpjcwQ=",
    strip_prefix = "rules_python-1.4.0",
    url = "https://github.com/bazelbuild/rules_python/releases/download/1.4.0/rules_python-1.4.0.tar.gz",
)

load("@rules_python//python:repositories.bzl", "py_repositories")
py_repositories()

load("@rules_python//python:pip.bzl", "pip_parse")
pip_parse(
   name = "my_python_deps",
   requirements_lock = "@example//:requirements_lock.txt",
)

load("@my_python_deps//:requirements.bzl", "install_deps")
install_deps()

load("@rules_python//python:repositories.bzl", "python_register_toolchains")
python_register_toolchains(
    name = "python_3_11",
    python_version = "3.11",
)

# Maven dependencies
# __________________

RULES_JVM_EXTERNAL_TAG = "4.5"
RULES_JVM_EXTERNAL_SHA = "b17d7388feb9bfa7f2fa09031b32707df529f26c91ab9e5d909eb1676badd9a6"

http_archive(
    name = "rules_jvm_external",
    strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
    sha256 = RULES_JVM_EXTERNAL_SHA,
    url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)

load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps")
rules_jvm_external_deps()
load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup")
rules_jvm_external_setup()

load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
    name = "px_deps",
    artifacts = [
        "org.antlr:antlr4:4.11.1",
    ],
    repositories = [
        "https://repo1.maven.org/maven2",
    ],
)

Selain itu, untuk menunjukkan penggunaan ekstensi modul, makro kustom dipanggil dari WORKSPACE dan ditentukan di my_custom_macro.bzl.

Klik di sini untuk melihat file my_custom_macro.bzl

"""Repo rule and macro used for testing"""

def _test_repo_rule_impl(repository_ctx):
    repository_ctx.file(
        "BUILD",
        content = """
genrule(
    name = "foo",
    outs = ["rule_name.out"],
    cmd = "touch $@",
    visibility = ["//visibility:public"],
)
"""
    )

_test_repo_rule = repository_rule(
    implementation = _test_repo_rule_impl,
)

def my_custom_macro(name):
    _test_repo_rule(name = name)

Tujuan akhirnya adalah memiliki file MODULE.bazel dan menghapus file WORKSPACE, tanpa memengaruhi pengalaman pengguna.

Langkah pertama adalah mengikuti Cara Menggunakan Alat Migrasi, yang sebagian besar memeriksa versi bazel (harus Bazel 7) dan menambahkan alias ke skrip migrasi.

Kemudian, menjalankan migrate2bzlmod -t=//... akan menghasilkan output:

  bazel 7.6.1

  Generating ./resolved_deps.py file - It might take a while...

  RESOLVED: rules_java has been introduced as a Bazel module.
  RESOLVED: bazel_gazelle has been introduced as a Bazel module.
  RESOLVED: io_bazel_rules_go has been introduced as a Bazel module.
  RESOLVED: rules_python has been introduced as a Bazel module.
  IMPORTANT: 3.11 is used as a default python version. If you need a different version, please change it manually and then rerun the migration tool.
  RESOLVED: my_python_deps has been introduced as python extension.
  RESOLVED: org_golang_x_net has been introduced as go extension.
  RESOLVED: rules_jvm_external has been introduced as a Bazel module.
  RESOLVED: org.antlr has been introduced as maven extension.
  RESOLVED: rules_shell has been introduced as a Bazel module.

  Congratulations! All external repositories needed for building //... are available with Bzlmod!
  IMPORTANT: Fix potential build time issues by running the following command:
      bazel build --enable_bzlmod --noenable_workspace //...

  IMPORTANT: For details about the migration process, check `migration_info.md` file.

yang memberikan informasi penting berikut:

  • Membuat file ./resolved_deps.py, yang berisi info tentang semua repositori eksternal yang dideklarasikan dan dimuat menggunakan file WORKSPACE Anda.
  • Kata kunci RESOLVED menjelaskan semua dependensi yang di-resolve oleh alat dan ditambahkan ke file MODULE.bazel.
  • Kata kunci IMPORTANT menjelaskan informasi penting yang layak untuk diinvestasikan.
  • Semua dependensi telah di-resolve dalam contoh ini, setidaknya dengan tanda --nobuild.
  • Penting untuk menjalankan build lengkap (perintah yang ditentukan) dan memperbaiki potensi error secara manual (misalnya, toolchain tidak terdaftar dengan benar).
  • File migration_info.md berisi detail tentang migrasi. Periksa detail di bagian ini.

Transformasi

Bagian ini mengilustrasikan migrasi kode dari file WORKSPACE ke MODULE.bazel.

WORKSPACE - Modul Bazel

http_archive(
    name = "rules_shell",
    sha256 = "3e114424a5c7e4fd43e0133cc6ecdfe54e45ae8affa14fadd839f29901424043",
    strip_prefix = "rules_shell-0.4.0",
    url = "https://github.com/bazelbuild/rules_shell/releases/download/v0.4.0/rules_shell-v0.4.0.tar.gz",
)

MODULE.bazel - Modul Bazel

bazel_dep(name = "rules_shell", version = "0.6.1")

WORKSPACE - Ekstensi Go

http_archive(
    name = "io_bazel_rules_go",
    integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip",
        "https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip",
    ],
)
http_archive(
    name = "bazel_gazelle",
    integrity = "sha256-12v3pg/YsFBEQJDfooN6Tq+YKeEWVhjuNdzspcvfWNU=",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz",
        "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz",
    ],
)

load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")

go_rules_dependencies()
go_register_toolchains(version = "1.23.1")
gazelle_dependencies()

go_repository(
    name = "org_golang_x_net",
    importpath = "golang.org/x/net",
    sum = "h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=",
    version = "v0.0.0-20190311183353-d8887717615a",
    build_file_proto_mode = "disable",
    build_naming_convention = "import",
)

MODULE.bazel - Ekstensi Go

go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps")
go_sdk = use_extension("@io_bazel_rules_go//go:extensions.bzl", "go_sdk")

go_deps.from_file(go_mod = "//:go.mod")
use_repo(go_deps, "org_golang_x_net")
go_sdk.from_file(go_mod = "//:go.mod")

go_deps.gazelle_override(
    path = "golang.org/x/net",
    directives = [
        "gazelle:proto disable",
         "gazelle:go_naming_convention import",
    ],
)

WORKSPACE - Ekstensi Python

http_archive(
    name = "rules_python",
    integrity = "sha256-qDdnnxOC8mlowe5vg5x9r5B5qlMSgGmh8oFd7KpjcwQ=",
    strip_prefix = "rules_python-1.4.0",
    url = "https://github.com/bazelbuild/rules_python/releases/download/1.4.0/rules_python-1.4.0.tar.gz",
)

load("@rules_python//python:repositories.bzl", "py_repositories")
py_repositories()

load("@rules_python//python:pip.bzl", "pip_parse")
pip_parse(
   name = "my_python_deps",
   requirements_lock = "@example//:requirements_lock.txt",
)

load("@my_python_deps//:requirements.bzl", "install_deps")
install_deps()

load("@rules_python//python:repositories.bzl", "python_register_toolchains")
python_register_toolchains(
    name = "python_3_11",
    python_version = "3.11",
)

MODULE.bazel - Ekstensi Python

pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
pip.parse(
    hub_name = "my_python_deps",
    python_version = "3.11",
    requirements_lock = "//:requirements_lock.txt",
)
use_repo(pip, "my_python_deps")

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.defaults(python_version = "3.11")
python.toolchain(python_version = "3.11")

WORKSPACE - Ekstensi Maven

RULES_JVM_EXTERNAL_TAG = "4.5"
RULES_JVM_EXTERNAL_SHA = "b17d7388feb9bfa7f2fa09031b32707df529f26c91ab9e5d909eb1676badd9a6"

http_archive(
    name = "rules_jvm_external",
    strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
    sha256 = RULES_JVM_EXTERNAL_SHA,
    url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)

load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps")
rules_jvm_external_deps()
load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup")
rules_jvm_external_setup()

load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
    name = "px_deps",
    artifacts = [
        "org.antlr:antlr4:4.11.1",
    ],
    repositories = [
        "https://repo1.maven.org/maven2",
    ],
)

MODULE.bazel - Ekstensi Maven

bazel_dep(name = "rules_jvm_external", version = "6.8")

maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
use_repo(maven, "px_deps")

maven.artifact(
    name = "px_deps",
    group = "org.antlr",
    artifact = "antlr4",
    version = "4.11.1"
)

WORKSPACE - Aturan Repo

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "com_github_cockroachdb_cockroach",
    sha256 = "6c3568ef244ce6b874694eeeecb83ed4f5d5dff6cf037c952ecde76828a6c502",
    strip_prefix = "cockroach-22.1.6",
    url = "https://github.com/cockroachdb/cockroach/archive/v22.1.6.tar.gz",
)

MODULE.bazel - Aturan Repo

http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
  name = "com_github_cockroachdb_cockroach",
  url = "https://github.com/cockroachdb/cockroach/archive/v22.1.6.tar.gz",
  sha256 = "6c3568ef244ce6b874694eeeecb83ed4f5d5dff6cf037c952ecde76828a6c502",
  strip_prefix = "cockroach-22.1.6",
)

WORKSPACE - Ekstensi modul

load(":my_custom_macro.bzl", "my_custom_macro")

my_custom_macro(
    name = "my_custom_repo",
)

MODULE.bazel - Ekstensi modul

extension_for_my_custom_macro = use_extension("//:extension_for_my_custom_macro.bzl", "extension_for_my_custom_macro")
use_repo(extension_for_my_custom_macro, "my_custom_repo")

extension_for_my_custom_macro.bzl

load("//:my_custom_macro.bzl", "my_custom_macro")

def _extension_for_my_custom_macro_impl(ctx):
  my_custom_macro(
    name = "my_custom_repo",
  )

extension_for_my_custom_macro = module_extension(implementation = _extension_for_my_custom_macro_impl)

Tips untuk proses debug

Bagian ini memberikan perintah dan informasi yang berguna untuk membantu proses debug masalah yang mungkin muncul selama migrasi Bzlmod.

Tips berguna

  • Mengganti versi - Sering kali terjadi masalah saat mengupgrade versi dependensi. Bzlmod dapat mengubah versi dependensi karena algoritma MVS. Untuk menggunakan versi yang sama atau serupa seperti yang ada di WORKSPACE, ganti dengan single_version_override. Perhatikan bahwa hal ini berguna untuk proses debug perbedaan antara WORKSPACE dan Bzlmod, tetapi Anda tidak boleh mengandalkan fitur ini dalam jangka panjang.

    single_version_override(module_name = "{dep_name}", version = "{version}")

  • Gunakan perintah bazel mod.

    • Periksa versi repo yang ditentukan dengan perintah show_repo. Contoh:

      bazel mod show_repo @rules_python

    • Periksa informasi tentang ekstensi modul dengan perintah show_extension. Contoh:

      bazel mod show_extension @rules_python//python/extensions:pip.bzl%pip

  • Gunakan mode vendor untuk membuat salinan lokal repo saat Anda ingin memantau atau mengontrol sumber repo. Contoh:

    bazel vendor --enable_bzlmod --vendor_dir=vendor_src --repo=@protobuf

Pembuatan Laporan Migrasi

File ini diperbarui dengan setiap menjalankan skrip migrasi atau dibuat dari awal jika merupakan proses pertama atau jika tanda --i digunakan. Laporan ini berisi:

  • Perintah untuk pengujian lokal.
  • Daftar dependensi langsung (setidaknya yang digunakan langsung dalam project).
  • Untuk setiap dependensi, menu dropdown untuk memeriksa tempat repositori dideklarasikan dalam file WORKSPACE, yang sangat berguna untuk proses debug. Anda dapat melihatnya sebagai:

    > Click here to see where and how the repo was declared in the WORKSPACE
    file
  • Untuk setiap dependensi, cara implementasinya dalam file MODULE.bazel. Dari contoh Migrasi sebelumnya, tampilannya akan terlihat seperti:

    1. Dependensi modul Bazel - Migration of rules_python

      Found perfect name match in BCR: rules_python
      Found partially name matches in BCR: rules_python_gazelle_plugin
      
      It has been introduced as a Bazel module:
          `bazel_dep(name = "rules_python", version = "1.6.1")`
      • Skrip akan otomatis menggunakan perfect name match jika menemukannya. Jika terjadi error, Anda dapat memeriksa kembali apakah nama telah ditambahkan dengan benar.
    2. Ekstensi Python - Migration of my_python_deps

      pip.parse(
          hub_name = "my_python_deps",
          requirements_lock = "//:requirements_lock.txt",
          python_version = "3.11",
      )
      use_repo(pip, "my_python_deps")
    3. Ekstensi Maven - Migration of org.antlr (px_deps):

      maven.artifact(
          name = "px_deps",
          group = "org.antlr",
          artifact = "antlr4",
          version = "4.11.1"
      )
    4. Ekstensi Go - Migration of org_golang_x_net

      go_deps.from_file(go_mod = "//:go.mod")
      go_sdk.from_file(go_mod = "//:go.mod")
      
      go_deps.gazelle_override(
          path = "golang.org/x/net",
          directives = [
              "gazelle:proto disable",
              "gazelle:go_naming_convention import",
          ],
      )
      • Ekstensi ini telah diperkenalkan sebagai modul go dengan bantuan go.mod. Jika go.mod dan go.sum tidak tersedia, modul go akan ditambahkan langsung ke file MODULE.bazel.
      • gazelle_override digunakan untuk menambahkan direktif tertentu.

Masukan

Jika Anda ingin berkontribusi, lakukan dengan membuat Masalah atau PR di bazel-central-registry.