1. Step 1 — Adding module to reference integration#
What it unlocks
Module in the graph — Your module becomes a known part of the
integration, pinned at an exact commit, enters the Bazel module graph and
builds cleanly against every other module. This is the foundation every later
step builds on — afterwards @score_my_module//... resolves and any other
target can depend on your module.
1.1. 1.1 Register the module in known_good.json#
known_good.json is the single source of truth for which modules — and at
which commit — are part of the integration. Every other generated file is
derived from it, so this is always the first change.
Open known_good.json. It has two top-level groups
under modules:
target_sw— the S-CORE software modules that are built and shipped (baselibs, communication, persistency, logging, …). Your module goes here.tooling— supporting tooling repos (docs-as-code, process, platform, …).
Add an entry for your module under modules.target_sw:
"score_my_module": {
"repo": "https://github.com/eclipse-score/my_module.git",
"hash": "0000000000000000000000000000000000000000",
"metadata": {
"code_root_path": "//src/...",
"langs": ["rust"],
"extra_test_config": [],
"exclude_test_targets": [],
"rust_coverage_config": "ferrocene-coverage"
}
}
1.1.1. Field reference#
repo(required)HTTPS clone URL of the module repository.
hash(required, mutually exclusive withversion)Exact commit to pin. Use
versioninstead if the module is published to a Bazel registry (this emits asingle_version_overriderather than agit_override).bazel_patches(optional)List of patch labels applied on top of the checked-out commit (see 1.3 (optional) Add Bazel patches).
metadata.code_root_path(default//score/...)Bazel target pattern that points at the module’s source root. Used to scope test discovery and Rust coverage queries (e.g.
//src/...).metadata.langs(default["cpp", "rust"])Languages used by the module.
rustenables a generated Rust coverage report (see Step 7 — Add coverage and verification reports).metadata.extra_test_configExtra
--//flag=valuebuild settings injected when building/testing this module (feature flags, config selections, …).metadata.exclude_test_targetsTest targets that must not run in the integration (flaky, environment specific, or not meaningful out-of-tree). Supports wildcards such as
//score/json/examples:*.metadata.rust_coverage_config(defaultferrocene-coverage)The Bazel coverage config to use for the generated Rust coverage report.
pin_version(optional, defaultfalse)When
true, the automatic “update to latest HEAD” scripts will leave this module’s hash untouched.
Note
To bump an existing entry to the latest commit on a branch you can use
scripts/known_good/update_module_latest.py instead of editing the hash by
hand. The first integration, however, is added manually.
1.2. 1.2 Regenerate the Bazel module fragments#
Your module now enters the Bazel module graph. From now on
@score_my_module//...resolves and any other target — showcases, docs, other modules — can depend on it. (If it declaresrust, its Rust coverage target is generated here too.)
The Bazel files are generated from known_good.json — never edit them by
hand. After editing the JSON, regenerate them:
python3 scripts/known_good/update_module_from_known_good.py
This (re)writes:
bazel_common/score_modules_target_sw.MODULE.bazel — a
bazel_dep+git_overrideblock for your module. This file is pulled into the build viainclude(...)in MODULE.bazel.rust_coverage/BUILD — a
rust_coverage_reporttarget for every module that declaresrustin itslangs(skipped for C++-only modules).
Next, refresh the Bazel lockfile so it reflects the updated module graph:
bazel mod deps --lockfile_mode=update
Adding your module introduces a new bazel_dep / git_override into the
module graph, which changes the set of resolved dependencies. Running bazel
mod deps with --lockfile_mode=update re-resolves the graph and writes the
new dependencies into MODULE.bazel.lock. Committing
an up-to-date lockfile keeps the dependency resolution reproducible for everyone
and is required by the Bzlmod Lockfile Check CI job (see section 1.4), which
fails if the committed lockfile is out of sync with the module graph.
Commit the regenerated files together with the known_good.json change. CI
verifies that the generated files are in sync with the JSON (see the
known_good_correct workflow), so a manual edit that drifts from the JSON
will fail.
1.3. 1.3 (optional) Add Bazel patches#
If the module does not build cleanly out-of-tree (e.g. label visibility issues),
add patch files under patches/<module>/ and reference them from the
bazel_patches list of the module entry in known_good.json. See
patches/communication for a worked example. The
generator emits patches = [...] with patch_strip = 1 automatically.
Note
Patching a module should be the exception, not the rule. A patch keeps a local divergence from the upstream module that has to be maintained and re-based on every update. Prefer fixing the underlying issue in the module’s own repository so it builds cleanly out-of-tree, and only reach for a patch as a temporary, last-resort workaround.
1.4. 1.4 CI checks that the module was added correctly#
Once the changes above are pushed, two gating CI jobs verify that the module
was wired in consistently. They do not build your module’s code — they only
check that the generated metadata is in sync with known_good.json:
Check (workflow) |
What it verifies |
Fix if it fails |
|---|---|---|
Known Good Matches Bazel (known_good_correct.yml) |
Re-runs |
re-run step 1.2 and commit the regenerated files |
Bzlmod Lockfile Check (bzlmod-lock.yml) |
Verifies |
refresh and commit |
Both jobs run in the merge queue, so they must be green before the pull request can be merged. The full catalogue of checks is under CI checks.