Skip to content

Commit c2c8c6c

Browse files
authored
Ignore safe-logging dep if unused + replace Strings.CS usage (#1553)
Ignore safe-logging dep if unused + replace Strings.CS usage
1 parent 3c1203a commit c2c8c6c

File tree

5 files changed

+127
-32
lines changed

5 files changed

+127
-32
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* (c) Copyright 2025 Palantir Technologies Inc. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.palantir.metric.schema.gradle;
18+
19+
import com.google.common.collect.ImmutableSetMultimap;
20+
import com.google.common.collect.Multimap;
21+
import com.palantir.metric.schema.lang.LangMetricSchema;
22+
import com.palantir.metric.schema.lang.MetricSchemaCompiler;
23+
import java.io.File;
24+
import java.io.IOException;
25+
import java.util.Collection;
26+
import java.util.Optional;
27+
import javax.annotation.Nonnull;
28+
29+
public final class DependencyRequirements {
30+
31+
public static Multimap<String, String> getDependencies(@Nonnull Collection<File> metricSchemaFiles) {
32+
Collection<LangMetricSchema> rawSchemas = metricSchemaFiles.stream()
33+
.<Optional<LangMetricSchema>>map(schemaFile -> {
34+
try {
35+
return Optional.of(MetricSchemaCompiler.parseRawSchema(schemaFile));
36+
} catch (IOException e) {
37+
// for configuration purposes, ignore files that cannot be parsed as schemas
38+
return Optional.empty();
39+
}
40+
})
41+
.<LangMetricSchema>mapMulti(Optional::ifPresent)
42+
.toList();
43+
44+
if (rawSchemas.stream().allMatch(schema -> schema.namespaces().isEmpty())) {
45+
// There isn't anything to generate, so no dependencies are required.
46+
return ImmutableSetMultimap.of();
47+
}
48+
49+
ImmutableSetMultimap.Builder<String, String> dependencies = ImmutableSetMultimap.<String, String>builder()
50+
.put("api", "com.palantir.tritium:tritium-registry")
51+
.put("api", "com.palantir.safe-logging:preconditions")
52+
.put("api", "com.google.errorprone:error_prone_annotations")
53+
// Metric types like Gauge are part of the generated code's public API
54+
.put("api", "io.dropwizard.metrics:metrics-core");
55+
if (requiresSafeLogging(rawSchemas)) {
56+
dependencies.put("implementation", "com.palantir.safe-logging:safe-logging");
57+
}
58+
return dependencies.build();
59+
}
60+
61+
/**
62+
* Determines whether any of the provided schemas require the com.palantir.safe-logging:safe-logging dependency.
63+
*/
64+
private static boolean requiresSafeLogging(Collection<LangMetricSchema> schemas) {
65+
return schemas.stream()
66+
.flatMap(schema -> schema.namespaces().values().stream())
67+
.flatMap(namespace -> namespace.metrics().values().stream())
68+
.anyMatch(metric -> !metric.tags().isEmpty());
69+
}
70+
71+
private DependencyRequirements() {}
72+
}

gradle-metric-schema/src/main/java/com/palantir/metric/schema/gradle/MetricSchemaPlugin.java

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package com.palantir.metric.schema.gradle;
1818

19-
import com.google.common.collect.ImmutableSetMultimap;
19+
import com.google.common.collect.Multimap;
2020
import com.palantir.sls.versions.OrderableSlsVersion;
2121
import com.palantir.sls.versions.SlsVersion;
2222
import com.palantir.sls.versions.SlsVersionType;
@@ -26,7 +26,7 @@
2626
import org.gradle.api.Plugin;
2727
import org.gradle.api.Project;
2828
import org.gradle.api.file.Directory;
29-
import org.gradle.api.file.FileCollection;
29+
import org.gradle.api.file.FileSystemLocation;
3030
import org.gradle.api.file.RegularFile;
3131
import org.gradle.api.file.SourceDirectorySet;
3232
import org.gradle.api.plugins.JavaLibraryPlugin;
@@ -118,33 +118,20 @@ private static void configureIdea(Project project, Provider<Directory> generated
118118
});
119119
}
120120

121-
private static void configureDependencies(Project project, FileCollection metricSchemaSourceDirectorySet) {
122-
ImmutableSetMultimap<String, String> allDependencies = ImmutableSetMultimap.<String, String>builder()
123-
.put("api", "com.palantir.tritium:tritium-registry")
124-
.put("api", "com.palantir.safe-logging:preconditions")
125-
.put("api", "com.google.errorprone:error_prone_annotations")
126-
// Metric types like Gauge are part of the generated code's public API
127-
.put("api", "io.dropwizard.metrics:metrics-core")
128-
.put("implementation", "com.palantir.safe-logging:safe-logging")
129-
.build();
130-
131-
allDependencies.asMap().forEach((configurationName, dependencies) -> {
132-
project.getConfigurations().named(configurationName, configuration -> {
133-
configuration
134-
.getDependencies()
135-
.addAllLater(
136-
metricSchemaSourceDirectorySet.getElements().map(files -> {
137-
// Don't add dependencies if we're not going to generate code
138-
if (files.isEmpty()) {
139-
return List.of();
140-
}
141-
142-
return dependencies.stream()
143-
.map(project.getDependencies()::create)
144-
.toList();
145-
}));
146-
});
147-
});
121+
private static void configureDependencies(Project project, SourceDirectorySet metricSchemaSourceDirectorySet) {
122+
Provider<Multimap<String, String>> dependencies = metricSchemaSourceDirectorySet
123+
.getElements()
124+
.map(metricsFiles -> DependencyRequirements.getDependencies(
125+
metricsFiles.stream().map(FileSystemLocation::getAsFile).toList()));
126+
127+
List.of(JavaPlugin.API_CONFIGURATION_NAME, JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME)
128+
.forEach(configurationName -> project.getConfigurations().named(configurationName, configuration -> {
129+
configuration
130+
.getDependencies()
131+
.addAllLater(dependencies.map(deps -> deps.get(configurationName).stream()
132+
.map(project.getDependencies()::create)
133+
.toList()));
134+
}));
148135
}
149136

150137
private String defaultLibraryName(Project project) {

gradle-metric-schema/src/test/groovy/com/palantir/metric/schema/gradle/MetricSchemaPluginIntegrationSpec.groovy

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ class MetricSchemaPluginIntegrationSpec extends IntegrationSpec {
4444
docs: A gauge of the ratio of active workers to the number of workers.
4545
""".stripIndent()
4646

47+
public static final String METRICS_NO_TAGS = """
48+
namespaces:
49+
server:
50+
docs: General web server metrics.
51+
metrics:
52+
worker.utilization:
53+
type: gauge
54+
docs: A gauge of the ratio of active workers to the number of workers.
55+
""".stripIndent()
56+
4757
public static final String METRICS_INVALID = """
4858
namespaces:
4959
server:
@@ -376,4 +386,24 @@ class MetricSchemaPluginIntegrationSpec extends IntegrationSpec {
376386
result.wasExecuted(":checkUnusedDependenciesMain")
377387
!result.wasSkipped(":checkUnusedDependenciesMain")
378388
}
389+
390+
def 'declare exact dependencies even with metrics without safety-annotated tags'() {
391+
setup:
392+
buildFile << """
393+
apply plugin: 'com.palantir.baseline'
394+
""".stripIndent(true)
395+
file('src/main/metrics/metrics.yml') << METRICS_NO_TAGS
396+
397+
when:
398+
ExecutionResult result = runTasksSuccessfully("classes", "checkImplicitDependencies", "checkUnusedDependencies")
399+
400+
then:
401+
result.wasExecuted(':generateMetrics')
402+
fileExists("build/generated/sources/metricSchema/java/main/com/palantir/test/ServerMetrics.java")
403+
404+
result.wasExecuted(":checkImplicitDependenciesMain")
405+
!result.wasSkipped(":checkImplicitDependenciesMain")
406+
result.wasExecuted(":checkUnusedDependenciesMain")
407+
!result.wasSkipped(":checkUnusedDependenciesMain")
408+
}
379409
}

metric-schema-java/src/main/java/com/palantir/metric/schema/Javadoc.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package com.palantir.metric.schema;
1818

1919
import org.apache.commons.lang3.StringUtils;
20-
import org.apache.commons.lang3.Strings;
2120
import org.commonmark.node.Paragraph;
2221
import org.commonmark.parser.Parser;
2322
import org.commonmark.renderer.Renderer;
@@ -55,7 +54,10 @@ static String render(Documentation documentation) {
5554
return "";
5655
}
5756
String renderedHtml = renderer.render(parser.parse(rawDocumentation));
58-
return Strings.CS.appendIfMissing(renderedHtml, "\n");
57+
if (!renderedHtml.endsWith("\n")) {
58+
renderedHtml += "\n";
59+
}
60+
return renderedHtml;
5961
}
6062

6163
private Javadoc() {}

metric-schema-lang/src/main/java/com/palantir/metric/schema/lang/MetricSchemaCompiler.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,15 @@ public static MetricSchema compile(Path inputFile) {
3939

4040
private static MetricSchema readFile(File file) {
4141
try {
42-
return LangConverter.toApi(reader.readValue(file));
42+
return LangConverter.toApi(parseRawSchema(file));
4343
} catch (IOException e) {
4444
throw new SafeUncheckedIoException("Failed to deserialize file", e, SafeArg.of("file", file));
4545
}
4646
}
4747

48+
public static LangMetricSchema parseRawSchema(File inputFile) throws IOException {
49+
return reader.readValue(inputFile);
50+
}
51+
4852
private MetricSchemaCompiler() {}
4953
}

0 commit comments

Comments
 (0)