-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathdocs.bzl
More file actions
329 lines (296 loc) · 11.8 KB
/
docs.bzl
File metadata and controls
329 lines (296 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# *******************************************************************************
# Copyright (c) 2025 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************
"""
Easy streamlined way for S-CORE docs-as-code.
"""
# Multiple approaches are available to build the same documentation output:
#
# 1. **Esbonio via IDE support (`ide_support` target)**:
# - Listed first as it offers the least flexibility in implementation.
# - Designed for live previews and quick iterations when editing documentation.
# - Integrates with IDEs like VS Code but requires the Esbonio extension.
# - Requires a virtual environment with consistent dependencies (see 2).
#
# 2. **Directly running Sphinx in the virtual environment**:
# - As mentioned above, a virtual environment is required for running esbonio.
# - Therefore, the same environment can be used to run Sphinx directly.
# - Option 1: Run Sphinx manually via `.venv_docs/bin/python -m sphinx docs _build --jobs auto`.
# - Option 2: Use the `incremental` target, which simplifies this process.
# - Usable in CI pipelines to validate the virtual environment used by Esbonio.
# - Ideal for quickly generating documentation during development.
#
# 3. **Bazel-based build (`docs` target)**:
# - Runs the documentation build in a Bazel sandbox, ensuring clean, isolated builds.
# - Less convenient for frequent local edits but ensures build reproducibility.
#
# **Consistency**:
# When modifying Sphinx extensions or configuration, ensure all three methods
# (Esbonio, incremental, and Bazel) work as expected to avoid discrepancies.
#
# For user-facing documentation, refer to `/README.md`.
load("@aspect_rules_py//py:defs.bzl", "py_binary")
load("@docs_as_code_hub_env//:requirements.bzl", "all_requirements")
load("@rules_python//sphinxdocs:sphinx.bzl", "sphinx_build_binary", "sphinx_docs")
load("@score_tooling//:defs.bzl", "score_virtualenv")
load("@score_tooling//bazel/rules/rules_score:rules_score.bzl", "sphinx_module")
def _rewrite_needs_json_to_docs_sources(labels):
"""Replace '@repo//:needs_json' -> '@repo//:docs_sources' for every item."""
out = []
for x in labels:
s = str(x)
if s.endswith("//:needs_json"):
out.append(s.replace("//:needs_json", "//:docs_sources"))
else:
out.append(s)
return out
def _rewrite_needs_json_to_sourcelinks(labels):
"""Replace '@repo//:needs_json' -> '@repo//:sourcelinks_json' for every item."""
out = []
for x in labels:
s = str(x)
if s.endswith("//:needs_json"):
out.append(s.replace("//:needs_json", "//:sourcelinks_json"))
else:
out.append(s)
return out
def _merge_sourcelinks(name, sourcelinks):
"""Merge multiple sourcelinks JSON files into a single file.
Args:
name: Name for the merged sourcelinks target
sourcelinks: List of sourcelinks JSON file targets
"""
native.genrule(
name = name,
srcs = sourcelinks,
outs = [name + ".json"],
cmd = """
$(location @score_docs_as_code//scripts_bazel:merge_sourcelinks) \
--output $@ \
$(SRCS)
""",
tools = ["@score_docs_as_code//scripts_bazel:merge_sourcelinks"],
)
def _missing_requirements(deps):
"""Add Python hub dependencies if they are missing."""
found = []
missing = []
def _target_to_packagename(target):
return target.split("/")[-1].split(":")[0]
all_packages = [_target_to_packagename(pkg) for pkg in all_requirements]
def _find(pkg):
for dep in deps:
dep_pkg = _target_to_packagename(dep)
if dep_pkg == pkg:
return True
return False
for pkg in all_packages:
if _find(pkg):
found.append(pkg)
else:
missing.append(pkg)
if len(missing) == len(all_requirements):
#print("All docs-as-code dependencies are missing, adding all of them.")
return all_requirements
if len(missing) == 0:
#print("All docs-as-code dependencies are already included, no need to add any.")
return []
if len(found) > 0:
msg = "Some docs-as-code dependencies are in deps: " + ", ".join(found) + \
"\n ... but others are missing: " + ", ".join(missing) + \
"\nInconsistent deps for docs(): either include all dependencies or none of them."
fail(msg)
fail("This case should be unreachable?!")
def docs(source_dir = "docs", data = [], deps = [], scan_code = []):
"""Creates all targets related to documentation.
By using this function, you'll get any and all updates for documentation targets in one place.
Args:
source_dir: The source directory containing documentation files. Defaults to "docs".
data: Additional data files to include in the documentation build.
deps: Additional dependencies for the documentation build.
scan_code: List of code targets to scan for source code links.
"""
call_path = native.package_name()
if call_path != "":
fail("docs() must be called from the root package. Current package: " + call_path)
module_deps = deps
deps = deps + _missing_requirements(deps)
deps = deps + [
"@score_docs_as_code//src:plantuml_for_python",
"@score_docs_as_code//src/extensions/score_sphinx_bundle:score_sphinx_bundle",
]
sphinx_build_binary(
name = "sphinx_build",
visibility = ["//visibility:private"],
data = data,
deps = deps,
)
native.filegroup(
name = "docs_sources",
srcs = native.glob([
source_dir + "/**/*.png",
source_dir + "/**/*.svg",
source_dir + "/**/*.md",
source_dir + "/**/*.rst",
source_dir + "/**/*.html",
source_dir + "/**/*.css",
source_dir + "/**/*.puml",
source_dir + "/**/*.need",
source_dir + "/**/*.yaml",
source_dir + "/**/*.json",
source_dir + "/**/*.csv",
source_dir + "/**/*.inc",
"more_docs/**/*.rst",
], allow_empty = True),
visibility = ["//visibility:public"],
)
_sourcelinks_json(name = "sourcelinks_json", srcs = scan_code)
data_with_docs_sources = _rewrite_needs_json_to_docs_sources(data)
additional_combo_sourcelinks = _rewrite_needs_json_to_sourcelinks(data)
_merge_sourcelinks(name = "merged_sourcelinks", sourcelinks = [":sourcelinks_json"] + additional_combo_sourcelinks)
py_binary(
name = "docs",
tags = ["cli_help=Build documentation:\nbazel run //:docs"],
srcs = ["@score_docs_as_code//src:incremental.py"],
data = data + [":sourcelinks_json"],
deps = deps,
env = {
"SOURCE_DIRECTORY": source_dir,
"DATA": str(data),
"ACTION": "incremental",
"SCORE_SOURCELINKS": "$(location :sourcelinks_json)",
},
)
py_binary(
name = "docs_combo",
tags = ["cli_help=Build full documentation with all dependencies:\nbazel run //:docs_combo"],
srcs = ["@score_docs_as_code//src:incremental.py"],
data = data_with_docs_sources + [":merged_sourcelinks"],
deps = deps,
env = {
"SOURCE_DIRECTORY": source_dir,
"DATA": str(data_with_docs_sources),
"ACTION": "incremental",
"SCORE_SOURCELINKS": "$(location :merged_sourcelinks)",
},
)
native.alias(
name = "docs_combo_experimental",
actual = ":docs_combo",
deprecation = "Target '//:docs_combo_experimental' is deprecated. Use '//:docs_combo' instead.",
)
py_binary(
name = "docs_link_check",
tags = ["cli_help=Verify Links inside Documentation:\nbazel run //:link_check\n (Note: this could take a long time)"],
srcs = ["@score_docs_as_code//src:incremental.py"],
data = data,
deps = deps,
env = {
"SOURCE_DIRECTORY": source_dir,
"DATA": str(data),
"ACTION": "linkcheck",
},
)
py_binary(
name = "docs_check",
tags = ["cli_help=Verify documentation:\nbazel run //:docs_check"],
srcs = ["@score_docs_as_code//src:incremental.py"],
data = data + [":sourcelinks_json"],
deps = deps,
env = {
"SOURCE_DIRECTORY": source_dir,
"DATA": str(data),
"ACTION": "check",
"SCORE_SOURCELINKS": "$(location :sourcelinks_json)",
},
)
py_binary(
name = "live_preview",
tags = ["cli_help=Live preview documentation in the browser:\nbazel run //:live_preview"],
srcs = ["@score_docs_as_code//src:incremental.py"],
data = data + [":sourcelinks_json"],
deps = deps,
env = {
"SOURCE_DIRECTORY": source_dir,
"DATA": str(data),
"ACTION": "live_preview",
"SCORE_SOURCELINKS": "$(location :sourcelinks_json)",
},
)
py_binary(
name = "live_preview_combo_experimental",
tags = ["cli_help=Live preview full documentation with all dependencies in the browser:\nbazel run //:live_preview_combo_experimental"],
srcs = ["@score_docs_as_code//src:incremental.py"],
data = data_with_docs_sources + [":merged_sourcelinks"],
deps = deps,
env = {
"SOURCE_DIRECTORY": source_dir,
"DATA": str(data_with_docs_sources),
"ACTION": "live_preview",
"SCORE_SOURCELINKS": "$(location :merged_sourcelinks)",
},
)
score_virtualenv(
name = "ide_support",
tags = ["cli_help=Create virtual environment (.venv_docs) for documentation support:\nbazel run //:ide_support"],
venv_name = ".venv_docs",
reqs = deps,
# Add dependencies to ide_support, so esbonio has access to them.
data = data,
)
sphinx_docs(
name = "needs_json",
srcs = [":docs_sources"],
config = ":" + source_dir + "/conf.py",
extra_opts = [
"-W",
"--keep-going",
"-T", # show more details in case of errors
"--jobs",
"auto",
"--define=external_needs_source=" + str(data),
],
formats = ["needs"],
sphinx = ":sphinx_build",
tools = data,
visibility = ["//visibility:public"],
)
sphinx_module(
name = native.module_name() + "_module",
srcs = [":docs_sources"],
# config = ":" + source_dir + "/conf.py",
index = source_dir + "/index.rst",
sphinx = "@score_tooling//bazel/rules/rules_score:score_build",
deps = module_deps,
visibility = ["//visibility:public"],
)
def _sourcelinks_json(name, srcs):
"""
Creates a target that generates a JSON file with source code links.
See https://eclipse-score.github.io/docs-as-code/main/how-to/source_to_doc_links.html
Args:
name: Name of the target
srcs: Source files to scan for traceability tags
"""
output_file = name + ".json"
native.genrule(
name = name,
srcs = srcs,
outs = [output_file],
cmd = """
$(location @score_docs_as_code//scripts_bazel:generate_sourcelinks) \
--output $@ \
$(SRCS)
""",
tools = ["@score_docs_as_code//scripts_bazel:generate_sourcelinks"],
visibility = ["//visibility:public"],
)