Add support for stamping (#205)
Provides `$stamping.stable.key_name` and `$stamping.volatile.key_name` in the header template.
diff --git a/docs/stardoc_rule.md b/docs/stardoc_rule.md
index cf79770..580298d 100644
--- a/docs/stardoc_rule.md
+++ b/docs/stardoc_rule.md
@@ -10,7 +10,7 @@
stardoc(<a href="#stardoc-name">name</a>, <a href="#stardoc-input">input</a>, <a href="#stardoc-out">out</a>, <a href="#stardoc-deps">deps</a>, <a href="#stardoc-format">format</a>, <a href="#stardoc-symbol_names">symbol_names</a>, <a href="#stardoc-semantic_flags">semantic_flags</a>, <a href="#stardoc-stardoc">stardoc</a>, <a href="#stardoc-renderer">renderer</a>,
<a href="#stardoc-aspect_template">aspect_template</a>, <a href="#stardoc-func_template">func_template</a>, <a href="#stardoc-header_template">header_template</a>, <a href="#stardoc-table_of_contents_template">table_of_contents_template</a>,
<a href="#stardoc-provider_template">provider_template</a>, <a href="#stardoc-rule_template">rule_template</a>, <a href="#stardoc-repository_rule_template">repository_rule_template</a>, <a href="#stardoc-module_extension_template">module_extension_template</a>,
- <a href="#stardoc-use_starlark_doc_extract">use_starlark_doc_extract</a>, <a href="#stardoc-render_main_repo_name">render_main_repo_name</a>, <a href="#stardoc-kwargs">kwargs</a>)
+ <a href="#stardoc-use_starlark_doc_extract">use_starlark_doc_extract</a>, <a href="#stardoc-render_main_repo_name">render_main_repo_name</a>, <a href="#stardoc-stamp">stamp</a>, <a href="#stardoc-kwargs">kwargs</a>)
</pre>
Generates documentation for exported starlark rule definitions in a target starlark file.
@@ -39,6 +39,7 @@
| <a id="stardoc-module_extension_template"></a>module_extension_template | The input file template for generating documentation of module extensions. This template is used only when using the native `starlark_doc_extract` rule. | `Label("@io_bazel_stardoc//stardoc:templates/markdown_tables/module_extension.vm")` |
| <a id="stardoc-use_starlark_doc_extract"></a>use_starlark_doc_extract | Use the native `starlark_doc_extract` rule if available. | `True` |
| <a id="stardoc-render_main_repo_name"></a>render_main_repo_name | Render labels in the main repository with a repo component (either the module name or workspace name). This parameter is used only when using the native `starlark_doc_extract` rule. | `True` |
+| <a id="stardoc-stamp"></a>stamp | Whether to provide stamping information to templates. | `False` |
| <a id="stardoc-kwargs"></a>kwargs | Further arguments to pass to stardoc. | none |
diff --git a/src/main/java/com/google/devtools/build/skydoc/renderer/RendererMain.java b/src/main/java/com/google/devtools/build/skydoc/renderer/RendererMain.java
index 9bf7cf7..20c5845 100644
--- a/src/main/java/com/google/devtools/build/skydoc/renderer/RendererMain.java
+++ b/src/main/java/com/google/devtools/build/skydoc/renderer/RendererMain.java
@@ -23,6 +23,7 @@
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.skydoc.rendering.MarkdownRenderer;
import com.google.devtools.build.skydoc.rendering.MarkdownRenderer.Renderer;
+import com.google.devtools.build.skydoc.rendering.Stamping;
import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.AspectInfo;
import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.AttributeInfo;
import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.ModuleExtensionInfo;
@@ -61,6 +62,17 @@
String inputPath = rendererOptions.inputPath;
String outputPath = rendererOptions.outputFilePath;
+ Stamping stamping;
+ if (rendererOptions.stampingStableStatusFilePath != null
+ && rendererOptions.stampingVolatileStatusFilePath != null) {
+ stamping =
+ Stamping.read(
+ rendererOptions.stampingStableStatusFilePath,
+ rendererOptions.stampingVolatileStatusFilePath);
+ } else {
+ stamping = Stamping.empty();
+ }
+
try (PrintWriter printWriter =
new PrintWriter(outputPath, UTF_8) {
// Use consistent line endings on all platforms.
@@ -83,7 +95,8 @@
rendererOptions.aspectTemplateFilePath,
rendererOptions.repositoryRuleTemplateFilePath,
rendererOptions.moduleExtensionTemplateFilePath,
- !moduleInfo.getFile().isEmpty() ? moduleInfo.getFile() : "...");
+ !moduleInfo.getFile().isEmpty() ? moduleInfo.getFile() : "...",
+ stamping);
// rules are printed sorted by their qualified name, and their attributes are sorted by name,
// with ATTRIBUTE_ORDERING specifying a fixed sort order for some standard attributes.
diff --git a/src/main/java/com/google/devtools/build/skydoc/renderer/RendererOptions.java b/src/main/java/com/google/devtools/build/skydoc/renderer/RendererOptions.java
index 004c428..e015372 100644
--- a/src/main/java/com/google/devtools/build/skydoc/renderer/RendererOptions.java
+++ b/src/main/java/com/google/devtools/build/skydoc/renderer/RendererOptions.java
@@ -81,6 +81,16 @@
String moduleExtensionTemplateFilePath;
@Parameter(
+ names = "--stamping_stable_status_file",
+ description = "The file path to the stable status file for stamping")
+ String stampingStableStatusFilePath;
+
+ @Parameter(
+ names = "--stamping_volatile_status_file",
+ description = "The file path to the volatile status file for stamping")
+ String stampingVolatileStatusFilePath;
+
+ @Parameter(
names = {"--help", "-h"},
description = "Print help and exit",
help = true)
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownRenderer.java b/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownRenderer.java
index ca07c34..e91da0c 100644
--- a/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownRenderer.java
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownRenderer.java
@@ -54,6 +54,7 @@
private final String repositoryRuleTemplateFilename;
private final String moduleExtensionTemplateFilename;
private final String extensionBzlFile;
+ private final Stamping stamping;
public MarkdownRenderer(
String headerTemplate,
@@ -64,7 +65,8 @@
String aspectTemplate,
String repositoryRuleTemplate,
String moduleExtensionTemplate,
- String extensionBzlFile) {
+ String extensionBzlFile,
+ Stamping stamping) {
this.headerTemplateFilename = headerTemplate;
this.tableOfContentsTemplateFilename = tableOfContentsTemplateFilename;
this.ruleTemplateFilename = ruleTemplate;
@@ -74,6 +76,7 @@
this.repositoryRuleTemplateFilename = repositoryRuleTemplate;
this.moduleExtensionTemplateFilename = moduleExtensionTemplate;
this.extensionBzlFile = extensionBzlFile;
+ this.stamping = stamping;
}
/**
@@ -86,7 +89,9 @@
"util",
new MarkdownUtil(extensionBzlFile),
"moduleDocstring",
- moduleInfo.getModuleDocstring());
+ moduleInfo.getModuleDocstring(),
+ "stamping",
+ stamping);
Reader reader = readerFromPath(headerTemplateFilename);
try {
return Template.parseFrom(reader).evaluate(vars);
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownUtil.java b/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownUtil.java
index afb2b5e..c486f57 100644
--- a/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownUtil.java
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownUtil.java
@@ -31,6 +31,9 @@
import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.RepositoryRuleInfo;
import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.RuleInfo;
import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.StarlarkFunctionInfo;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
@@ -440,4 +443,16 @@
}
throw new IllegalArgumentException("Unhandled type " + attributeType);
}
+
+ /**
+ * Formats a build timestamp from stamping with the given format. For example:
+ *
+ * <p>`$util.formatBuildTimestamp($stamping.volatile.BUILD_TIMESTAMP, "UTC", "yyyy MMM dd, HH:mm")
+ * UTC`
+ */
+ public String formatBuildTimestamp(String buildTimestampSeconds, String zoneId, String format) {
+ return Instant.ofEpochMilli(Long.parseLong(buildTimestampSeconds) * 1000)
+ .atZone(ZoneId.of(zoneId))
+ .format(DateTimeFormatter.ofPattern(format));
+ }
}
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/Stamping.java b/src/main/java/com/google/devtools/build/skydoc/rendering/Stamping.java
new file mode 100644
index 0000000..be7f5f3
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/Stamping.java
@@ -0,0 +1,61 @@
+// Copyright 2024 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.skydoc.rendering;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+/** Reads and stores stamping information. */
+public final class Stamping {
+
+ public static Stamping read(String stableStatusFile, String volatileStatusFile)
+ throws IOException {
+ return new Stamping(parse(stableStatusFile), parse(volatileStatusFile));
+ }
+
+ public static Stamping empty() {
+ return new Stamping(ImmutableMap.of(), ImmutableMap.of());
+ }
+
+ private final ImmutableMap<String, String> stableInfo;
+ private final ImmutableMap<String, String> volatileInfo;
+
+ private static ImmutableMap<String, String> parse(String path) throws IOException {
+ ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+ List<String> lines = Files.readAllLines(Path.of(path));
+ for (String line : lines) {
+ String[] kv = line.split(" ", 2); // split on first space only
+ builder.put(kv[0], kv[1]);
+ }
+ return builder.build();
+ }
+
+ private Stamping(
+ ImmutableMap<String, String> stableInfo, ImmutableMap<String, String> volatileInfo) {
+ this.stableInfo = stableInfo;
+ this.volatileInfo = volatileInfo;
+ }
+
+ public ImmutableMap<String, String> getStable() {
+ return stableInfo;
+ }
+
+ public ImmutableMap<String, String> getVolatile() {
+ return volatileInfo;
+ }
+}
diff --git a/stardoc/private/stardoc.bzl b/stardoc/private/stardoc.bzl
index 1101524..9ebe142 100644
--- a/stardoc/private/stardoc.bzl
+++ b/stardoc/private/stardoc.bzl
@@ -28,6 +28,9 @@
renderer_args.add("--rule_template=" + str(ctx.file.rule_template.path))
renderer_args.add("--repository_rule_template=" + str(ctx.file.repository_rule_template.path))
renderer_args.add("--module_extension_template=" + str(ctx.file.module_extension_template.path))
+ if ctx.attr.stamp:
+ renderer_args.add("--stamping_stable_status_file=" + str(ctx.info_file.path))
+ renderer_args.add("--stamping_volatile_status_file=" + str(ctx.version_file.path))
inputs = [
proto_file,
@@ -41,6 +44,10 @@
]
if ctx.attr.table_of_contents_template:
inputs.append(ctx.file.table_of_contents_template)
+ if ctx.attr.stamp:
+ inputs.append(ctx.info_file)
+ inputs.append(ctx.version_file)
+
renderer = ctx.executable.renderer
ctx.actions.run(
arguments = [renderer_args],
@@ -155,6 +162,10 @@
allow_single_file = [".vm"],
mandatory = True,
),
+ "stamp": attr.bool(
+ doc = "Whether to provide stamping information to templates",
+ default = False,
+ ),
}
# TODO(arostovtsev): replace with ... attrs = { ... } | _common_renderer_attrs
diff --git a/stardoc/stardoc.bzl b/stardoc/stardoc.bzl
index ac312aa..dd350d8 100644
--- a/stardoc/stardoc.bzl
+++ b/stardoc/stardoc.bzl
@@ -39,6 +39,7 @@
module_extension_template = Label("//stardoc:templates/markdown_tables/module_extension.vm"),
use_starlark_doc_extract = True,
render_main_repo_name = True,
+ stamp = False,
**kwargs):
"""Generates documentation for exported starlark rule definitions in a target starlark file.
@@ -76,6 +77,7 @@
the module name or workspace name). This parameter is used only when using the native
`starlark_doc_extract` rule.
use_starlark_doc_extract: Use the native `starlark_doc_extract` rule if available.
+ stamp: Whether to provide stamping information to templates.
**kwargs: Further arguments to pass to stardoc.
"""
@@ -123,6 +125,7 @@
rule_template = rule_template,
repository_rule_template = repository_rule_template,
module_extension_template = module_extension_template,
+ stamp = stamp,
**kwargs
)
elif format == "proto" and not extractor_is_main_target:
diff --git a/test/BUILD b/test/BUILD
index 9f151e5..1f5c2f4 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -292,6 +292,15 @@
deps = [":table_of_contents_test_deps"],
)
+stardoc_test(
+ name = "stamping_test",
+ golden_file = "testdata/stamping_test/golden.md",
+ header_template = "testdata/stamping_test/stamping_header.vm",
+ input_file = "testdata/stamping_test/input.bzl",
+ stamp = True,
+ test_legacy_extractor = False,
+)
+
sh_test(
name = "local_repository_test_e2e_test",
srcs = ["diff_test_runner.sh"],
diff --git a/test/testdata/stamping_test/golden.md b/test/testdata/stamping_test/golden.md
new file mode 100644
index 0000000..4432e95
--- /dev/null
+++ b/test/testdata/stamping_test/golden.md
@@ -0,0 +1,7 @@
+This Stardoc was built in the `AD` era.
+
+Host empty: false
+
+This key does not exist:
+
+
diff --git a/test/testdata/stamping_test/input.bzl b/test/testdata/stamping_test/input.bzl
new file mode 100644
index 0000000..fd56550
--- /dev/null
+++ b/test/testdata/stamping_test/input.bzl
@@ -0,0 +1 @@
+# nothing needed, only uses header
diff --git a/test/testdata/stamping_test/stamping_header.vm b/test/testdata/stamping_test/stamping_header.vm
new file mode 100644
index 0000000..b58dc79
--- /dev/null
+++ b/test/testdata/stamping_test/stamping_header.vm
@@ -0,0 +1,11 @@
+## "G" in the format below is for "Era". So long as we don't go back in time ~2000 years, this should always be "AD",
+## and we don't have to fiddle with handling varying timestamps in the test.
+This Stardoc was built in the `$util.formatBuildTimestamp($stamping.volatile.BUILD_TIMESTAMP, "UTC", "G")` era.
+
+## Should test a stable value, but stable contains quasi sensitive info, so don't print that in the test output
+Host empty: $stamping.stable.BUILD_HOST.isEmpty()
+
+## Sometimes Stardoc is built without --workspace_status_command (e.g. in build tests), luckily "$!foo" will tell
+## Velocity to ignore null values:
+This key does not exist: $!stamping.stable.STABLE_GIT_COMMIT
+