Herramienta de migración de Bzlmod

Para simplificar el proceso, a menudo complejo, de pasar de WORKSPACE a Bzlmod, se recomienda usar la secuencia de comandos de migración. Esta herramienta auxiliar automatiza muchos de los pasos involucrados en la migración de tu sistema externo de administración de dependencias.

Nota: Si quieres probar la migración a Bzlmod basada en IA, consulta Configuración del agente de migración a Bzlmod.

Funcionalidad principal

Las funciones principales de la secuencia de comandos son las siguientes:

  • Recopilación de información de dependencias: Analiza el archivo WORKSPACE de tu proyecto para identificar los repositorios externos que usan los destinos de compilación especificados, con la marca experimental_repository_resolved_file de Bazel para generar un archivo de dependencias resueltas que contenga esta información.
  • Identificación de dependencias directas: Usa bazel query para determinar qué repositorios son dependencias directas de los destinos especificados.
  • Migración a Bzlmod: Traduce las dependencias relevantes de WORKSPACE a sus equivalentes de Bzlmod. Este es un proceso de dos pasos:
    1. Introduce todas las dependencias directas identificadas en el MODULE.bazel archivo.
    2. Compila los destinos especificados con Bzlmod habilitado y, luego, identifica y corrige de forma iterativa los errores reconocibles. Este paso es necesario, ya que es posible que falten algunas dependencias en el primer paso.
  • Generación de un informe de migración: Crea un archivo migration_info.md que documente el proceso de migración. Este informe incluye una lista de dependencias directas , las declaraciones de Bzlmod generadas y los pasos manuales que pueden ser necesarios para completar la migración.

La herramienta de migración admite lo siguiente:

  • Dependencias disponibles en el Registro central de Bazel
  • Reglas de repositorio personalizadas definidas por el usuario
  • Dependencias del administrador de paquetes
    • Maven
    • Go
    • Python

Notas importantes:

  • La herramienta de migración es una utilidad de mejor esfuerzo. Siempre vuelve a verificar sus recomendaciones para confirmar la exactitud.
  • Usa la herramienta de migración con Bazel 7 (no es compatible con Bazel 8).

Cómo usar la herramienta de migración

Antes de comenzar:

  • Actualiza a la versión más reciente de Bazel 7, que proporciona una compatibilidad sólida con WORKSPACE y Bzlmod.
  • Verifica que el siguiente comando se ejecute correctamente para los destinos de compilación principales de tu proyecto:

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

Comando para ejecutar la secuencia de comandos

Una vez que se cumplan los requisitos previos, ejecuta los siguientes comandos para usar la herramienta de migración:

# 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>

Archivos generados por esta secuencia de comandos

  • MODULE.bazel - Es el archivo de manifiesto central para Bzlmod, que declara los metadatos del proyecto y sus dependencias directas en otros módulos de Bazel.
  • migration_info.md - Es un archivo que proporciona instrucciones paso a paso sobre cómo se ejecutó la herramienta de migración, diseñada para ayudar a completar manualmente el proceso de migración, si es necesario.
  • resolved_deps.py - Contiene una lista completa de las dependencias externas del proyecto, generada mediante el análisis del archivo WORKSPACE del proyecto, que sirve como referencia durante la transición.
  • query_direct_deps - Contiene información relevante para la migración sobre los destinos utilizados, que se obtiene invocando a Bazel con --output=build en el archivo WORKSPACE del proyecto. Esta secuencia de comandos de migración consume principalmente este archivo.
  • extension_for_XXX - Es un archivo que contiene una definición de extensión de módulo. La herramienta de migración genera estos archivos para dependencias que no son módulos estándar de Bazel, pero que se pueden administrar con las extensiones de módulo de Bzlmod.

Marcas

Las marcas disponibles en estas secuencias de comandos de migración son las siguientes:

  • --t/--target: Destinos para migrar. Esta marca se puede repetir y los destinos se acumulan.
  • --i/--initial: Borra los archivos MODULE.bazel, resolved_deps.py, migration_info.md y comienza desde cero. Detecta dependencias directas, las introduce en MODULE.bazel y vuelve a ejecutar la generación de dependencias resueltas.

Limpieza después de la migración

  • Borra migration_info.md, resolved_deps.py y query_direct_deps.
  • Limpia los comentarios del archivo MODULE.bazel que se usaron para la migración, como # -- bazel_dep definitions -- #.

Ejemplo de migración

Para ver la secuencia de comandos de migración en acción, considera la siguiente situación cuando se declaran las dependencias de Python, Maven y Go en el archivo WORKSPACE.

Haz clic aquí para ver el archivo 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",
    ],
)

Además, para demostrar el uso de la extensión del módulo, se invoca una macro personalizada desde WORKSPACE y se define en my_custom_macro.bzl.

Haz clic aquí para ver el archivo 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)

El objetivo final es tener el archivo MODULE.bazel y borrar el archivo WORKSPACE, sin afectar la experiencia del usuario.

El primer paso es seguir Cómo usar la herramienta de migración, que consiste principalmente en verificar la versión de Bazel (debe ser Bazel 7) y agregar un alias a la secuencia de comandos de migración.

Luego, la ejecución de migrate2bzlmod -t=//... genera lo siguiente:

  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.

que proporciona la siguiente información importante:

  • Genera el archivo ./resolved_deps.py, que contiene información sobre todos los repositorios externos declarados y cargados con tu archivo WORKSPACE.
  • La palabra clave RESOLVED describe todas las dependencias que resuelve la herramienta y que se agregan al archivo MODULE.bazel.
  • La palabra clave IMPORTANT describe información importante que vale la pena invertir tiempo.
  • En este ejemplo, se resolvieron todas las dependencias, al menos con --nobuild marca.
  • Es importante ejecutar la compilación completa (comando especificado) y corregir manualmente los posibles errores (p.ej., la cadena de herramientas no se registró correctamente).
  • El archivo migration_info.md contiene detalles sobre la migración. Consulta los detalles en esta sección.

Transformaciones

En esta sección, se ilustra la migración de código del archivo WORKSPACE a MODULE.bazel.

WORKSPACE: Módulo de 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: Módulo de Bazel

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

WORKSPACE: Extensión de 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: Extensión de 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: Extensión de 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: Extensión de 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: Extensión de 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: Extensión de 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: Regla de repositorio

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: Regla de repositorio

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: Extensión de módulo

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

my_custom_macro(
    name = "my_custom_repo",
)

MODULE.bazel: Extensión de módulo

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)

Sugerencias para la depuración

En esta sección, se proporcionan comandos e información útiles para ayudar a depurar los problemas que pueden surgir durante la migración a Bzlmod.

Sugerencias útiles

  • Anular la versión: No es raro que la actualización de la versión de una dependencia cause problemas. Bzlmod podría cambiar la versión de la dependencia debido al algoritmo MVS. Para usar la misma versión o una similar a la que estaba en WORKSPACE, anúlala con single_version_override. Ten en cuenta que esto es útil para depurar las diferencias entre WORKSPACE y Bzlmod, pero no debes depender de esta función a largo plazo.

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

  • Usa el comando bazel mod.

    • Verifica la versión de un repositorio especificado con show_repo comando. Por ejemplo:

      bazel mod show_repo @rules_python

    • Verifica la información sobre una extensión de módulo con el show_extension comando. Por ejemplo:

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

  • Usa el modo de proveedor para crear una copia local de un repositorio cuando quieras supervisar o controlar la fuente del repositorio. Por ejemplo:

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

Generación de informes de migración

Este archivo se actualiza con cada ejecución de la secuencia de comandos de migración o se genera desde cero si es la primera ejecución o si se usa la --i marca. El informe contiene lo siguiente:

  • Comando para pruebas locales
  • Lista de dependencias directas (al menos las que se usan directamente en el proyecto)
  • Para cada dependencia, un menú desplegable para verificar dónde se declaró el repositorio en el archivo WORKSPACE, lo que es particularmente útil para la depuración. Puedes verlo de la siguiente manera:

    > Click here to see where and how the repo was declared in the WORKSPACE
    file
  • Para cada dependencia, cómo se implementó en el archivo MODULE.bazel. En el ejemplo de migración anterior, se vería de la siguiente manera:

    1. Dependencia del módulo de 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")`
      • La secuencia de comandos usará automáticamente la perfect name match si la encuentra. En caso de error, puedes volver a verificar si el nombre se agregó correctamente.
    2. Extensión de 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. Extensión de Maven: Migration of org.antlr (px_deps):

      maven.artifact(
          name = "px_deps",
          group = "org.antlr",
          artifact = "antlr4",
          version = "4.11.1"
      )
    4. Extensión de 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",
          ],
      )
      • Se introdujo como un módulo de Go con la ayuda de go.mod. Si go.mod y go.sum no están disponibles, el módulo de Go se agrega directamente al archivo MODULE.bazel.
      • gazelle_override se usa para agregar directivas específicas.

Comentarios

Si quieres contribuir, crea un problema o una solicitud de extracción en bazel-central-registry.