eclipse-score / eclipse-score/docs-as-code
Named documentation target families
- Dominant language
- Python
- Stars
- 10
- Forks
- 32
- Avg merge
- 23h 52m
- Merged PRs (30d)
- 52
Description
# Named documentation target families
Status: proposed. This is an independent prerequisite for
[sharing project configuration with bundles](concept.md). It changes naming and
target references without introducing shared configuration or changing what the
documentation builds contain.
## Earlier approach: PR #648
[PR #648](https://github.com/eclipse-score/docs-as-code/pull/648) explored named
`docs()` invocations by deriving target names in one helper, updating internal
references, and distinguishing virtual environments and metrics outputs. It also
updated external-inventory parsing, non-Bazel discovery, and PlantUML runfiles
lookup. These are useful implementation touchpoints for this prerequisite.
The earlier approach kept default targets unprefixed and used underscore prefixes
for custom names. This proposal instead uses dotted canonical targets for every
invocation and aliases for old public labels. Its suffix-based inventory lookup
and target-derived path reconstruction do not solve alias-to-artifact resolution;
use the artifact metadata described below. Its former `docs_sources` and combo
targets also predate the current bundle composition model and are not restored.
The PR required custom names to be repeated as `docs_target_name` in `conf.py` for
IDE execution. This proposal keeps the invocation identity in Bazel and carries
it into generated runtime/IDE metadata. That identity must include the package
and repository, not just the target name, so subdirectory projects work as well.
The [review discussion](https://github.com/eclipse-score/docs-as-code/pull/648#discussion_r3613037208)
distinguishes multiple independent documentation builds from publishing multiple
sites. This prerequisite enables those builds and provides stable invocation
identities. It does not change publishing policy or replace `docs_bundle()` for
composing one documentation site.
## Goal and public API
`docs()` currently declares a collection of targets with unrelated names, such as
`docs`, `docs_bundle`, `needs_json`, and `live_preview`. Give the invocation a
stable identity and put its generated targets in one namespace:
```python
load("@score_docs_as_code//:docs.bzl", "docs")
docs(
name = "docs",
source_dir = "docs",
project = "Example",
project_url = "https://example.org/example",
)
```
Add optional `name = "docs"` after the existing parameters to preserve positional
calls. `name` is the Bazel identity; `project` remains the human-readable Sphinx
project name. Use a single target-name component without `/` for `name` so the
namespace and its generated directories stay within the declaring package.
All generated implementation targets use either `.` for supported
entry points or `.__internal__.` for implementation details. The
default invocation uses the same dotted scheme as any custom invocation.
The unqualified `:` is an alias to `:.incremental`. It remains a convenient
run command and provides the public label identifying the abstract `docs()`
invocation for future APIs. Thus `//project:site` identifies
`docs(name = "site", ...)`, while `//project:site.bundle` selects its mountable
source bundle. This naming prerequisite does not add an owner argument to
`docs_bundle()`.
Run incremental documentation generation with `bazel run //:docs.incremental`.
Reserve `.build` for a future, separate documentation target intended for
`bazel build`; this prerequisite does not introduce that target.
## Canonical targets and compatibility aliases
For `docs(name = "docs")`, generate these canonical entry points and aliases:
| Role | Canonical target | Compatibility alias |
| --- | --- | --- |
| Incremental documentation command | `:docs.incremental` | `:docs` |
| Root source bundle | `:docs.bundle` | `:docs_bundle` |
| Project-wide Needs inventory | `:docs.needs_json` | `:needs_json` |
| Single Needs JSON file | `:docs.needs_json_file` | `:needs_json_file` |
| Metrics JSON file | `:docs.metrics_json` | `:metrics_json` |
| Source links | `:docs.sourcelinks_json` | `:sourcelinks_json` |
| Documentation checks | `:docs.check` | `:docs_check` |
| Link checks | `:docs.link_check` | `:docs_link_check` |
| Live preview | `:docs.live_preview` | `:live_preview` |
| IDE environment | `:docs.ide_support` | `:ide_support` |
| Traceability gate | `:docs.traceability_gate` | `:traceability_gate` |
Use `native.alias` for compatibility; aliases forward to canonical targets and
do not declare duplicate build actions. Preserve the existing public visibility
and manual-tag policy on aliases and the corresponding canonical targets. Keep
the traceability gate's existing delegation to the shared tool under its new
canonical name.
A custom invocation, such as `docs(name = "site")`, produces `:site.incremental`,
`:site.bundle`, `:site.needs_json`, and the other roles from the same table. It
also produces the owner alias `:site`. Only the default `name = "docs"` invocation
creates the legacy aliases, so named invocations can coexist without claiming
the same compatibility labels. Keep those aliases for this migration without
adding a removal deadline.
Use canonical labels for all generated dependencies, `$(location ...)`
expressions, environment values, and examples added as part of the implementation.
Compatibility aliases serve existing callers; generated rules must not depend
on them.
### Internal targets
Move fixed private helpers such as `_docs_generated_config`, `_docs_mounts`, and
`_external_docs_runfiles` beneath the invocation's `.__internal__.` namespace.
For example, use `docs.__internal__.generated_config` and
`docs.__internal__.mounts_manifest`. The build executable can itself be
`docs.incremental`; it no longer needs the fixed `_score_docs_cli` name to avoid a
filesystem collision with the `docs/` source directory.
Bundle-local and Needs-build helpers retain their existing owner-relative naming
convention, now based on the canonical owning target. For example:
```text
docs.bundle.__internal__.needs_local
docs.bundle.__internal__.needs_sources
docs.needs_json.__internal__.sphinx_build
```
Private helpers do not receive compatibility aliases. Existing direct references
to internal target names, including repository tests, migrate to the new names.
Standalone `docs_bundle(name = ...)` declarations retain their current naming;
only the root bundle generated by `docs()` receives the new canonical name.
## Output paths and integration
Namespace every invocation-owned helper, action output, and runtime environment,
not just public labels. Two named invocations with distinct source directories
must coexist in one package without target, generated-file, or virtual-environment
collisions. Duplicate names or collisions with user-declared targets remain Bazel
errors; do not invent alternate names automatically.
There is no compatibility requirement for existing output paths, including
generated configuration, extracted JSON files, build directories, runfiles, or
IDE environments. Compatibility aliases preserve target entry points only.
Use the same invocation-scoped layout for default and custom names, without
legacy-path exceptions or copies created solely to retain old paths.
Put generated configuration and extracted files under each invocation's
`.__internal__/` output directory, use `.venv_` for IDE support, and
use `_build_` for interactive builds, including separate stale-build
sentinels. Cleaning one invocation must not remove another invocation's outputs.
Pass the selected directories to runtime and traceability tools explicitly.
Ensure generated configuration is still staged at the Sphinx source-root location
expected by the existing source adapters. A source-provided `conf.py` keeps its
existing precedence and location.
An alias preserves a target reference, but it does not recreate an old target's
physical output directory or runfiles tree. In particular, renaming the Needs
build changes its target-derived output directory. Inventory consumers currently
recognize fixed target names and reconstruct paths from those names; adding
aliases alone would leave these consumers broken.
As part of this prerequisite, resolve inventory artifact locations from Bazel
files and carry those locations into runtime input metadata. Preserve the
repository/runfiles identity and distinguish directory-valued Needs exports from
single-file exports. Do not reconstruct an artifact path from the supplied alias
name. Support canonical and legacy labels, including cross-repository producers
that still use the previous target naming scheme. Update the legacy inventory
classification used by `docs(data = ...)` as well, so a canonical Needs target
does not become mounted bundle data accidentally.
Update runtime discovery, IDE setup, traceability tooling, and test helpers that
assume fixed targets or output directories. Keep commands through compatibility
aliases working, but migrate internal path-based assumptions to canonical outputs
or artifact discovery. Update documentation and scripts that refer to output
paths to the new layout. Direct Sphinx execution and the content of
Needs exports remain unchanged.
For IDE/Esbonio and direct Sphinx execution in a generated IDE environment, emit
metadata alongside that environment identifying the full owner label, its
canonical incremental target, and the corresponding runfiles location. Runtime
discovery must use the selected environment's metadata when Bazel runfiles are
not already available, rather than assuming root-package `ide_support.runfiles`
or asking authors to repeat the name in `conf.py`. Update PlantUML's use of that
discovery path too.
Any remaining fallback query for documentation data must address the owner's
canonical incremental target in its actual package, rather than querying
`labels(data, //:docs)` or another alias without a `data` attribute. These runtime
changes belong to the naming prerequisite and must not rely on the later shared
configuration proposal.
## Delivery and acceptance
Implement this prerequisite independently of `concept.md`: first centralize
target-name derivation, move targets and helper references, add compatibility
aliases, and update artifact resolution and affected consumers. Do not add
`docs_config`, shared `deps`, or new publication metadata in this change.
Validate these behaviors:
- An existing `docs()` declaration still works through every legacy public label;
each alias resolves to its canonical counterpart and schedules no duplicate
documentation action.
- Canonical incremental/check commands, mounted root bundles, and both Needs export
forms work for default and custom names.
- The owner and legacy run aliases execute the incremental target. No
`.build` target is introduced by this prerequisite.
- Two named invocations with distinct source directories in one package have
independent targets, generated configurations, exports, and IDE environments.
- Canonical and compatibility inventory labels resolve the same actual artifact,
including external repositories and producers using the previous naming scheme.
- IDE/Esbonio and direct Sphinx execution in a named project's IDE environment
locate that project's runfiles, PlantUML, and external inventories without a
duplicated `conf.py` name. Cover a project outside the repository root and a
fallback query against the canonical incremental target.
- Legacy `data` inventory handling, generated sources, metamodel inputs, source
links, and traceability commands retain their behavior after names change.
- Default and custom invocations use the same output-layout rules. Runtime tools,
tests, and documentation use the new paths or artifact discovery without
requiring any old output path to remain available.
- Positional calls remain valid, and existing `conf.py` precedence and standalone
`docs_bundle()` names remain unchanged.
Run the relevant public macro integration scenarios sequentially and focused
inventory/runtime tests when implementing this prerequisite. For this
document-only change, check links, example syntax, and whitespace.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.