Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions bazel/rules/rules_score/private/dependable_element.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1807,6 +1807,9 @@ def dependable_element(
dependable_element's `deps` are resolved against `<dep>_index`
(see `processed_deps`), not against `<dep>` itself.
<name>: Main dependable element target (sphinx_module) with HTML documentation
<name>.serve: Alias to <name>_doc.serve, a binary that locally serves
<name>'s HTML output for previewing docs during development
(`bazel run //:<name>.serve`).
<name>_needs: Sphinx-needs JSON target (created by sphinx_module for cross-referencing)

"""
Expand Down Expand Up @@ -1875,3 +1878,14 @@ def dependable_element(
testonly = testonly,
visibility = ["//visibility:public"],
)

# Step 5: Alias the internal "<name>_doc.serve" preview binary to
# "<name>.serve" so callers can preview docs without knowing about the
# internal _doc split (mirrors the sphinx_module_dep facade in Step 3).
native.alias(
name = name + ".serve",
actual = ":" + name + "_doc.serve",
tags = ["manual"],
testonly = testonly,
visibility = kwargs.get("visibility"),
)
46 changes: 43 additions & 3 deletions bazel/rules/rules_score/private/sphinx_module.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,21 @@
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************
# Copyright 2023 The Bazel Authors. All rights reserved.
# https://github.com/bazel-contrib/rules_python/blob/release/1.8/sphinxdocs/private/sphinx.bzl

# ======================================================================================
# Helpers
# ======================================================================================
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@rules_python//python:py_binary.bzl", "py_binary")
load("@rules_python//sphinxdocs:sphinx_docs_library.bzl", "sphinx_docs_library")
load("@rules_python//sphinxdocs/private:sphinx_docs_library_info.bzl", "SphinxDocsLibraryInfo")
load("//bazel/rules/rules_score:providers.bzl", "FilteredExecpathInfo", "SphinxIndexFileInfo", "SphinxModuleInfo", "SphinxNeedsInfo")
load("//bazel/rules/rules_score/private:verbosity.bzl", "VERBOSITY_ATTR", "get_log_level")

_SPHINX_SERVE_MAIN_SRC = Label("@rules_python//sphinxdocs/private:sphinx_server.py")

# Maps the //bazel/rules/rules_score:verbosity build setting (see
# verbosity.bzl) to the sphinx-build CLI flags that achieve it. Lives here in
# Starlark rather than in a wrapper script: the Sphinx build binary is
Expand Down Expand Up @@ -628,6 +634,20 @@ _score_html = rule(
# ======================================================================================
# Rule wrappers
# ======================================================================================
def _copy_propagating_kwargs(from_kwargs):
"""Return the subset of macro kwargs that must stay consistent across
sibling targets with a dependency relationship.

Deliberately excludes `visibility`: callers of this helper want their
generated sub-target to NOT inherit the macro's own (often public)
visibility.
"""
into_kwargs = {}
for attr in ("testonly", "tags", "compatible_with", "restricted_to", "target_compatible_with"):
if attr in from_kwargs:
into_kwargs[attr] = from_kwargs[attr]
return into_kwargs

def sphinx_module(
name,
srcs,
Expand All @@ -646,6 +666,14 @@ def sphinx_module(
transitive dependency collection. Each dependency's HTML is copied into a
<dep_name>/ subdirectory of the merged site for intersphinx/sphinx-needs
cross-referencing.

Generates targets:
* `<name>`: The merged HTML site (this module's own HTML plus every
transitive dependency's HTML, each under a `<dep_name>/` subdirectory).
* `<name>.serve`: A binary that locally serves `<name>`'s HTML output,
for previewing docs during development (`bazel run //:<name>.serve`).
* `<name>_needs`: This module's `needs.json` build (see SphinxNeedsInfo).

Args:
name: Name of the target
srcs: List of source files (.rst, .md) with index file first
Expand Down Expand Up @@ -679,9 +707,9 @@ def sphinx_module(

# conf.py generation is a private implementation detail consumed only by
# the sibling _score_needs/_score_html targets below (same package) --
# must not inherit the macro's own (often public) visibility via kwargs.
conf_kwargs = dict(kwargs)
conf_kwargs.pop("visibility", None)
# _copy_propagating_kwargs both drops visibility and narrows to the
# attrs that must actually stay consistent across the two.
conf_kwargs = _copy_propagating_kwargs(kwargs)

_score_conf(
name = name + "_needs_conf",
Expand Down Expand Up @@ -727,3 +755,15 @@ def sphinx_module(
testonly = testonly,
**kwargs
)

serve_kwargs = _copy_propagating_kwargs(kwargs)
serve_kwargs["tags"] = list(serve_kwargs.get("tags") or []) + ["manual"]
py_binary(
name = name + ".serve",
srcs = [_SPHINX_SERVE_MAIN_SRC],
main = _SPHINX_SERVE_MAIN_SRC,
data = [name],
args = ["$(execpath {})".format(name)],
testonly = testonly,
**serve_kwargs
)
14 changes: 14 additions & 0 deletions bazel/rules/rules_score/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ load(
"needs_generation_test",
"needs_transitive_test",
"providers_test",
"serve_target_test",
"sphinx_module_test_suite",
)
load(
Expand Down Expand Up @@ -95,6 +96,7 @@ load(
"seooc_index_generation_test",
"seooc_multi_index_files_exist_test",
"seooc_needs_provider_test",
"seooc_serve_alias_test",
"seooc_sphinx_entry_point_is_root_index_test",
"seooc_sphinx_module_generated_test",
)
Expand Down Expand Up @@ -969,6 +971,11 @@ explicit_config_test(
target_under_test = ":module_a_lib",
)

serve_target_test(
name = "serve_target_test",
target_under_test = ":module_a_lib.serve",
)

# ============================================================================
# HTML Content Validation Tests
# ============================================================================
Expand Down Expand Up @@ -1144,6 +1151,12 @@ seooc_sphinx_module_generated_test(
target_under_test = ":seooc_test_lib",
)

# Test that the <name>.serve alias resolves to a runnable preview binary
seooc_serve_alias_test(
name = "seooc_tests_serve_alias",
target_under_test = ":seooc_test_lib.serve",
)

# Test that needs provider exists for cross-referencing
seooc_needs_provider_test(
name = "seooc_tests_needs_provider",
Expand Down Expand Up @@ -1273,6 +1286,7 @@ test_suite(
":seooc_tests_index_generation",
":seooc_tests_multi_index_files_exist",
":seooc_tests_needs_provider",
":seooc_tests_serve_alias",
":seooc_tests_sphinx_entry_point_is_root_index",
":seooc_tests_sphinx_module_generated",
],
Expand Down
22 changes: 22 additions & 0 deletions bazel/rules/rules_score/test/html_generation_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,25 @@ def _explicit_config_test_impl(ctx):

explicit_config_test = analysistest.make(_explicit_config_test_impl)

# ============================================================================
# Serve Target Tests
# ============================================================================

def _serve_target_test_impl(ctx):
"""Test that sphinx_module generates a runnable <name>.serve py_binary."""
env = analysistest.begin(ctx)
target_under_test = analysistest.target_under_test(env)

asserts.true(
env,
target_under_test[DefaultInfo].files_to_run.executable != None,
"<name>.serve should be an executable py_binary",
)

return analysistest.end(env)

serve_target_test = analysistest.make(_serve_target_test_impl)

# ============================================================================
# Test Suite
# ============================================================================
Expand Down Expand Up @@ -228,5 +247,8 @@ def sphinx_module_test_suite(name):
# Config generation
":auto_config_generation_test",
":explicit_config_test",

# Local preview binary
":serve_target_test",
],
)
17 changes: 17 additions & 0 deletions bazel/rules/rules_score/test/seooc_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,23 @@ seooc_sphinx_module_generated_test = analysistest.make(
impl = _seooc_sphinx_module_generated_test_impl,
)

def _seooc_serve_alias_test_impl(ctx):
"""Test that dependable_element aliases <name>_doc.serve to <name>.serve."""
env = analysistest.begin(ctx)
target_under_test = analysistest.target_under_test(env)

asserts.true(
env,
target_under_test[DefaultInfo].files_to_run.executable != None,
"Expected dependable_element's <name>.serve alias to resolve to a runnable py_binary",
)

return analysistest.end(env)

seooc_serve_alias_test = analysistest.make(
impl = _seooc_serve_alias_test_impl,
)

def _seooc_needs_provider_test_impl(ctx):
"""Test that dependable_element generates needs provider for cross-referencing."""
env = analysistest.begin(ctx)
Expand Down
Loading