| --- | |
| title: 'Bzlmod Migration Tool' | |
| --- | |
| [migration_script]: https://github.com/bazelbuild/bazel-central-registry/blob/main/tools/migrate_to_bzlmod.py | |
| [gemini_cli_setup]: https://github.com/bazelbuild/bazel-central-registry/tree/main/tools/code-agent | |
| To simplify the often complex process of moving from `WORKSPACE` to Bzlmod, it's | |
| highly recommended to use the [migration script][migration_script]. This helper | |
| tool automates many of the steps involved in migrating your external dependency | |
| management system. | |
| **Note**: If you want to try out the AI driven Bzlmod migration, check [Bzlmod Migration Agent Setup][gemini_cli_setup]. | |
| ## Core Functionality {#migration-tool-core-functionality} | |
| The script's primary functions are: | |
| * **Collecting dependency information:** Analyzing your project's `WORKSPACE` | |
| file to identify external repositories used by specified build targets, | |
| using Bazel's | |
| [experimental_repository_resolved_file](https://bazel.build/versions/9.2.0/versions/8.2.0/reference/command-line-reference#flag--experimental_repository_resolved_file) | |
| flag to generate a resolved dependencies file containing this information. | |
| * **Identifying direct dependencies:** Using `bazel query` to determine which | |
| repositories are direct dependencies for the specified targets. | |
| * **Migrating to Bzlmod:** Translating relevant `WORKSPACE` dependencies into | |
| their Bzlmod equivalents. This is a two-step process: | |
| 1. Introduce all identified direct dependencies to the | |
| `MODULE.bazel` file. | |
| 2. Build specified targets with Bzlmod enabled, then | |
| iteratively identify and fix recognizable errors. This step is | |
| needed since some dependencies might be missing in the first step. | |
| * **Generating a migration report:** Creating a `migration_info.md` file that | |
| documents the migration process. This report includes a list of direct | |
| dependencies, the generated Bzlmod declarations, and any manual steps that | |
| may be required to complete the migration. | |
| The migration tool supports: | |
| * Dependencies available in the Bazel Central Registry | |
| * User-defined custom repository rules | |
| * Package manager dependencies | |
| * Maven | |
| * Go | |
| * Python | |
| **Important Notes**: | |
| * The migration tool is a best-effort utility. Always double-check its | |
| recommendations for correctness. | |
| * Use the migration tool with Bazel 7 (not supported with Bazel 8). | |
| ## How to Use the Migration Tool {#migration-tool-how-to-use} | |
| Before you begin: | |
| * Upgrade to the latest Bazel 7 release, which provides robust support for | |
| both WORKSPACE and Bzlmod. | |
| * Verify the following command runs successfully for your project's main build | |
| targets: | |
| ```shell | |
| bazel build --nobuild --enable_workspace --noenable_bzlmod <targets> | |
| ``` | |
| ### Command for running the script {#migration-script-command} | |
| Once the prerequisites are met, run the following commands to use the migration | |
| tool: | |
| ``` | |
| # 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> | |
| ``` | |
| ### Files generated by this script {#migration-script-files} | |
| * `MODULE.bazel` - The central manifest file for Bzlmod, which declares the | |
| project's metadata and its direct dependencies on other Bazel modules. | |
| * `migration_info.md` - A file providing step-by-step instructions on how the | |
| migration tool was executed, designed to assist in the manual completion of | |
| the migration process, if necessary. | |
| * `resolved_deps.py` - Contains a comprehensive list of the project's external | |
| dependencies, generated by analyzing the project's `WORKSPACE` file, serving | |
| as a reference during the transition. | |
| * `query_direct_deps` - Contains migration-relevant information regarding the | |
| utilized targets, obtained by invoking Bazel with `--output=build` on the | |
| project's `WORKSPACE` file. This file is primarily consumed by the migration | |
| script. | |
| * `extension_for_XXX` - A file containing a module extension | |
| definition. The migration tool generates these files for dependencies that | |
| are not standard Bazel modules but can be managed using Bzlmod's [module | |
| extensions](/versions/9.2.0/external/extension). | |
| ### Flags {#migration-script-flags} | |
| Flags available in this migration scripts are: | |
| * `--t`/`--target`: Targets to migrate. This flag is repeatable, and the | |
| targets are accumulated. | |
| * `--i`/`--initial`: Deletes `MODULE.bazel`, `resolved_deps.py`, | |
| `migration_info.md` files and starts from scratch - Detect direct | |
| dependencies, introduce them in MODULE.bazel and rerun generation of | |
| resolved dependencies. | |
| ### Post-migration cleanup {#post-migration-cleanup} | |
| * Delete `migration_info.md`, `resolved_deps.py` and `query_direct_deps`. | |
| * Clean up comments from `MODULE.bazel` file which were used for the | |
| migration, such as `# -- bazel_dep definitions -- #`. | |
| ## Migration Example {#migration-tool-example} | |
| To see the migration script in action, consider the following scenario when | |
| Python, Maven and Go dependencies are declared in `WORKSPACE` file. | |
| <details> | |
| <summary style="padding: 16px"> | |
| Click here to see `WORKSPACE` file | |
| </summary> | |
| ```python | |
| 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", | |
| ], | |
| ) | |
| ``` | |
| </details> | |
| Moreover, to demonstrate usage of module extension, custom macro is invoked from | |
| `WORKSPACE` and it is defined in `my_custom_macro.bzl`. | |
| <details> | |
| <summary style="padding: 16px"> | |
| Click here to see `my_custom_macro.bzl` file | |
| </summary> | |
| ```python | |
| """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) | |
| ``` | |
| </details> | |
| The end goal is to have `MODULE.bazel` file and delete the `WORKSPACE` file, | |
| without impacting the user experience. | |
| The first step is to follow [How to Use the Migration | |
| Tool](#migration-tool-how-to-use), which mostly is checking the bazel version | |
| (it must be Bazel 7) and adding an alias to the migration script. | |
| Then, running `migrate2bzlmod -t=//...` outputs: | |
| ``` | |
| bazel 7.6.1 | |
| Generating ./resolved_deps.py file - It might take a while... | |
| <span style="color:green;">RESOLVED:</span> <code>rules_java</code> has been introduced as a Bazel module. | |
| <span style="color:green;">RESOLVED:</span> <code>bazel_gazelle</code> has been introduced as a Bazel module. | |
| <span style="color:green;">RESOLVED:</span> <code>io_bazel_rules_go</code> has been introduced as a Bazel module. | |
| <span style="color:green;">RESOLVED:</span> <code>rules_python</code> has been introduced as a Bazel module. | |
| <span style="color:orange;">IMPORTANT:</span> 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. | |
| <span style="color:green;">RESOLVED:</span> <code>my_python_deps</code> has been introduced as python extension. | |
| <span style="color:green;">RESOLVED:</span> <code>org_golang_x_net</code> has been introduced as go extension. | |
| <span style="color:green;">RESOLVED:</span> <code>rules_jvm_external</code> has been introduced as a Bazel module. | |
| <span style="color:green;">RESOLVED:</span> <code>org.antlr</code> has been introduced as maven extension. | |
| <span style="color:green;">RESOLVED:</span> <code>rules_shell</code> has been introduced as a Bazel module. | |
| Congratulations! All external repositories needed for building //... are available with Bzlmod! | |
| <span style="color:orange;">IMPORTANT:</span> Fix potential build time issues by running the following command: | |
| <span style="font-weight: 700;">bazel build --enable_bzlmod --noenable_workspace //...</span> | |
| <span style="color:orange;">IMPORTANT:</span> <code>For details about the migration process, check `migration_info.md` file.</code> | |
| ``` | |
| which gives the following important information: | |
| * Generates `./resolved_deps.py` file, which contains info about all external | |
| repositories declared and loaded using your `WORKSPACE` file. | |
| * `RESOLVED` keyword describes all dependencies which are resolved by the tool | |
| and added to the `MODULE.bazel` file. | |
| * `IMPORTANT` keyword describes significant information worth investing time. | |
| * All dependencies have been resolved in this example, at least with | |
| `--nobuild` flag. | |
| * It is important to run the full build (command specified) and manually fix | |
| potential errors (e.g. toolchain not registered correctly). | |
| * `migration_info.md` file contains details about the migration. Check details | |
| [at this section](#migration-tool-report-generation). | |
| ### Transformations {#migration-tool-transformations} | |
| This section illustrates the migration of code from the `WORKSPACE` file to | |
| `MODULE.bazel`. | |
| <div style="display: flex; flex-wrap: wrap; gap: 16px;"> | |
| <div style="flex: 1; min-width: 300px;"> | |
| <p><strong>WORKSPACE - Bazel Module</strong></p> | |
| ``` | |
| 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", | |
| ) | |
| ``` | |
| </div> | |
| <div style="flex: 1; min-width: 300px;"> | |
| <p><strong>MODULE.bazel - Bazel Module</strong></p> | |
| ``` | |
| bazel_dep(name = "rules_shell", version = "0.6.1") | |
| ``` | |
| </div> | |
| </div> | |
| <hr style="height: 1px; background-color: black; border: none;"/> | |
| <div style="display: flex; flex-wrap: wrap; gap: 16px;"> | |
| <div style="flex: 1; min-width: 300px;"> | |
| <p><strong>WORKSPACE - Go Extension</strong></p> | |
| ``` | |
| 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", | |
| ) | |
| ``` | |
| </div> | |
| <div style="flex: 1; min-width: 300px;"> | |
| <p><strong>MODULE.bazel - Go Extension</strong></p> | |
| ``` | |
| 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", | |
| ], | |
| ) | |
| ``` | |
| </div> | |
| </div> | |
| <hr style="height: 1px; background-color: black; border: none;"/> | |
| <div style="display: flex; flex-wrap: wrap; gap: 16px;"> | |
| <div style="flex: 1; min-width: 300px;"> | |
| <p><strong>WORKSPACE - Python Extension</strong></p> | |
| ``` | |
| 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", | |
| ) | |
| ``` | |
| </div> | |
| <div style="flex: 1; min-width: 300px;"> | |
| <p><strong>MODULE.bazel - Python Extension</strong></p> | |
| ``` | |
| 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") | |
| ``` | |
| </div> | |
| </div> | |
| <hr style="height: 1px; background-color: black; border: none;"/> | |
| <div style="display: flex; flex-wrap: wrap; gap: 16px;"> | |
| <div style="flex: 1; min-width: 300px;"> | |
| <p><strong>WORKSPACE - Maven Extension</strong></p> | |
| ``` | |
| 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", | |
| ], | |
| ) | |
| ``` | |
| </div> | |
| <div style="flex: 1; min-width: 300px;"> | |
| <p><strong>MODULE.bazel - Maven Extension</strong></p> | |
| ``` | |
| 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" | |
| ) | |
| ``` | |
| </div> | |
| </div> | |
| <hr style="height: 1px; background-color: black; border: none;"/> | |
| <div style="display: flex; flex-wrap: wrap; gap: 16px;"> | |
| <div style="flex: 1; min-width: 300px;"> | |
| <p><strong>WORKSPACE - Repo rule</strong></p> | |
| ``` | |
| 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", | |
| ) | |
| ``` | |
| </div> | |
| <div style="flex: 1; min-width: 300px;"> | |
| <p><strong>MODULE.bazel - Repo rule</strong></p> | |
| ``` | |
| 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", | |
| ) | |
| ``` | |
| </div> | |
| </div> | |
| <hr style="height: 1px; background-color: black; border: none;"/> | |
| <div style="display: flex; flex-wrap: wrap; gap: 16px;"> | |
| <div style="flex: 1; min-width: 300px;"> | |
| <p><strong>WORKSPACE - Module extension</strong></p> | |
| ``` | |
| load(":my_custom_macro.bzl", "my_custom_macro") | |
| my_custom_macro( | |
| name = "my_custom_repo", | |
| ) | |
| ``` | |
| </div> | |
| <div style="flex: 1; min-width: 300px;"> | |
| <p><strong>MODULE.bazel - Module extension</strong></p> | |
| ``` | |
| 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") | |
| ``` | |
| <p><strong>extension_for_my_custom_macro.bzl</strong></p> | |
| ``` | |
| 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) | |
| ``` | |
| </div> | |
| </div> | |
| <hr style="height: 1px; background-color: black; border: none;"/> | |
| ## Tips with debugging {#migration-tool-tips} | |
| This section provides useful commands and information to help debug issues that | |
| may arise during the Bzlmod migration. | |
| ### Useful tips {#debugging-useful-tips} | |
| * Override version - Not rarely it happens that upgrading the version of a | |
| dependency causes troubles. Bzlmod could change the version of the | |
| dependency due to the [MVS algorithm](/versions/9.2.0/external/module#version-selection). | |
| In order to use the same or similar version as it was in the WORKSPACE, | |
| override it with | |
| [single_version_override](/versions/9.2.0/rules/lib/globals/module#single_version_override). | |
| Note that this is useful for debugging differences between WORKSPACE and | |
| Bzlmod, but you shouldn't rely on this feature in the long term. | |
| `single_version_override(module_name = "{dep_name}", version = "{version}")` | |
| * Use [bazel mod](/versions/9.2.0/external/mod-command#syntax) command. | |
| * Check the version of a specified repo with `show_repo` | |
| command. For example: | |
| `bazel mod show_repo @rules_python` | |
| * Check information about a module extension with the `show_extension` | |
| command. For example: | |
| `bazel mod show_extension @rules_python//python/extensions:pip.bzl%pip` | |
| * Use [vendor mode](/versions/9.2.0/external/vendor) to create a local copy of a repo when | |
| you want to monitor or control the source of the repo. For example: | |
| `bazel vendor --enable_bzlmod --vendor_dir=vendor_src --repo=@protobuf` | |
| ### Migration Report Generation {#migration-tool-report-generation} | |
| This file is updated with each run of the migration script or it's generated | |
| from scratch if it's the first run or if the [`--i` | |
| flag](#migration-script-flags) is used. The report contains: | |
| * Command for local testing. | |
| * List of direct dependencies (at least the ones which are directly used in | |
| the project). | |
| * For each dependency, a drop-down menu for checking where the repository was | |
| declared in the `WORKSPACE` file, which is particularly useful for the | |
| debugging. You can see it as: | |
| ``` | |
| > Click here to see where and how the repo was declared in the WORKSPACE | |
| file | |
| ``` | |
| * For each dependency, how it was implemented in `MODULE.bazel` file. From the | |
| earlier [Migration Example](#migration-tool-example), that would look as: | |
| 1. Bazel module Dependency - `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")` | |
| ``` | |
| * The script will automatically use the `perfect name match` if it finds | |
| it. In case of an error, you can double check if the name was correctly | |
| added. | |
| 2. Python extension - `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. Maven extension - `Migration of org.antlr (px_deps):` | |
| ``` | |
| maven.artifact( | |
| name = "px_deps", | |
| group = "org.antlr", | |
| artifact = "antlr4", | |
| version = "4.11.1" | |
| ) | |
| ``` | |
| 4. Go extension - `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", | |
| ], | |
| ) | |
| ``` | |
| * It has been introduced as a go module with the help of `go.mod`. If | |
| `go.mod` and `go.sum` are not available, go module is added directly | |
| to the `MODULE.bazel` file. | |
| * `gazelle_override` is used for adding specific directives. | |
| ## Useful links {#useful-links} | |
| * Official pages for the external extensions | |
| * [rules_jvm_external](https://github.com/bazelbuild/rules_jvm_external/blob/master/docs/bzlmod.md) | |
| * [rules_go](https://github.com/bazelbuild/rules_go/blob/master/docs/go/core/bzlmod.md) | |
| * [rules_python](https://rules-python.readthedocs.io/en/latest/pypi/download.html) | |
| * Community posts and videos | |
| * [Migrating to Bazel Modules](https://blog.engflow.com/2025/01/16/migrating-to-bazel-modules-aka-bzlmod---module-extensions/index.html#migrating-to-bazel-modules-aka-bzlmod-module-extensions). | |
| * [Moving to Bzlmod](https://www.youtube.com/watch?v=W9uXRYLVHUk). | |
| * [How Uber Manages Go Dependencies with Bzlmod](https://www.youtube.com/watch?v=hIqzkUE_pSY). | |
| ## Feedback {#feedback} | |
| If you would like to contribute, do so by creating an Issue or PR at | |
| [bazel-central-registry](https://github.com/bazelbuild/bazel-central-registry). |