Skip to content

Commit f8b3616

Browse files
authored
feat: inline disclaimer comment, use Sample/RegionTag, collect GapicClass samples (pt 2) (#970)
* chore: rename files * feat: prepare for writing samples, include comment in inline samples * chore: update test naming * test: refactor grpc golden unit tests include samples * test: integration goldens * test: unit goldens * nit refactor * formatting * refactor: move isProtoEmptyType, move handleDuplicateSamples, update sample name/file name * fix - update unit goldens dir with lowercase dir * test: SampleComposerUtilTest included * fix: include header
1 parent 0277fc1 commit f8b3616

File tree

227 files changed

+9064
-1597
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

227 files changed

+9064
-1597
lines changed

src/main/java/com/google/api/generator/engine/ast/TypeNode.java

+5
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ public boolean isProtoPrimitiveType() {
203203
return isPrimitiveType() || equals(TypeNode.STRING) || equals(TypeNode.BYTESTRING);
204204
}
205205

206+
public boolean isProtoEmptyType() {
207+
return reference().pakkage().equals("com.google.protobuf")
208+
&& reference().name().equals("Empty");
209+
}
210+
206211
public boolean isSupertypeOrEquals(TypeNode other) {
207212
boolean oneTypeIsNull = equals(TypeNode.NULL) ^ other.equals(TypeNode.NULL);
208213
return !isPrimitiveType()

src/main/java/com/google/api/generator/engine/writer/JavaWriterVisitor.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -998,7 +998,7 @@ public void visit(ClassDefinition classDefinition) {
998998

999999
// fixing region tag after formatting
10001000
// formatter splits long region tags on multiple lines and moves the end tag up - doesn't meet
1001-
// tag requirements
1001+
// tag requirements. See https://github.com/google/google-java-format/issues/137
10021002
if (classDefinition.regionTag() != null) {
10031003
formattedClazz =
10041004
formattedClazz.replaceAll(regionTagReplace, classDefinition.regionTag().generate());

src/main/java/com/google/api/generator/gapic/composer/ClientLibraryPackageInfoComposer.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
import com.google.api.generator.engine.ast.PackageInfoDefinition;
2222
import com.google.api.generator.engine.ast.TypeNode;
2323
import com.google.api.generator.engine.ast.VaporReference;
24+
import com.google.api.generator.gapic.composer.samplecode.SampleCodeWriter;
2425
import com.google.api.generator.gapic.composer.samplecode.ServiceClientHeaderSampleComposer;
2526
import com.google.api.generator.gapic.composer.utils.ClassNames;
2627
import com.google.api.generator.gapic.model.GapicContext;
2728
import com.google.api.generator.gapic.model.GapicPackageInfo;
29+
import com.google.api.generator.gapic.model.Sample;
2830
import com.google.api.generator.gapic.model.Service;
2931
import com.google.common.base.Preconditions;
3032
import com.google.common.base.Strings;
@@ -119,10 +121,11 @@ private static CommentStatement createPackageInfoJavadoc(GapicContext context) {
119121
.setPakkage(service.pakkage())
120122
.setName(ClassNames.getServiceClientClassName(service))
121123
.build());
122-
String packageInfoSampleCode =
123-
ServiceClientHeaderSampleComposer.composeClassHeaderMethodSampleCode(
124+
Sample packageInfoSampleCode =
125+
ServiceClientHeaderSampleComposer.composeClassHeaderSample(
124126
service, clientType, context.resourceNames(), context.messages());
125-
javaDocCommentBuilder.addSampleCode(packageInfoSampleCode);
127+
javaDocCommentBuilder.addSampleCode(
128+
SampleCodeWriter.writeInlineSample(packageInfoSampleCode.body()));
126129
}
127130

128131
return CommentStatement.withComment(javaDocCommentBuilder.build());

src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java

+91-47
Large diffs are not rendered by default.

src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceSettingsClassComposer.java

+20-9
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@
5050
import com.google.api.generator.engine.ast.Variable;
5151
import com.google.api.generator.engine.ast.VariableExpr;
5252
import com.google.api.generator.gapic.composer.comment.SettingsCommentComposer;
53-
import com.google.api.generator.gapic.composer.samplecode.SettingsSampleCodeComposer;
53+
import com.google.api.generator.gapic.composer.samplecode.SampleCodeWriter;
54+
import com.google.api.generator.gapic.composer.samplecode.SampleComposerUtil;
55+
import com.google.api.generator.gapic.composer.samplecode.SettingsSampleComposer;
5456
import com.google.api.generator.gapic.composer.store.TypeStore;
5557
import com.google.api.generator.gapic.composer.utils.ClassNames;
5658
import com.google.api.generator.gapic.composer.utils.PackageChecker;
@@ -59,6 +61,7 @@
5961
import com.google.api.generator.gapic.model.GapicContext;
6062
import com.google.api.generator.gapic.model.Method;
6163
import com.google.api.generator.gapic.model.Method.Stream;
64+
import com.google.api.generator.gapic.model.Sample;
6265
import com.google.api.generator.gapic.model.Service;
6366
import com.google.api.generator.gapic.utils.JavaStyle;
6467
import com.google.common.base.Preconditions;
@@ -100,12 +103,13 @@ public GapicClass generate(GapicContext context, Service service) {
100103
TypeStore typeStore = createDynamicTypes(service);
101104
String className = ClassNames.getServiceSettingsClassName(service);
102105
GapicClass.Kind kind = Kind.MAIN;
103-
106+
List<Sample> samples = new ArrayList<>();
107+
List<CommentStatement> classHeaderComments =
108+
createClassHeaderComments(service, typeStore.get(className), samples);
104109
ClassDefinition classDef =
105110
ClassDefinition.builder()
106111
.setPackageString(pakkage)
107-
.setHeaderCommentStatements(
108-
createClassHeaderComments(service, typeStore.get(className)))
112+
.setHeaderCommentStatements(classHeaderComments)
109113
.setAnnotations(createClassAnnotations(service))
110114
.setScope(ScopeNode.PUBLIC)
111115
.setName(className)
@@ -122,11 +126,11 @@ public GapicClass generate(GapicContext context, Service service) {
122126
.setMethods(createClassMethods(service, typeStore))
123127
.setNestedClasses(Arrays.asList(createNestedBuilderClass(service, typeStore)))
124128
.build();
125-
return GapicClass.create(kind, classDef);
129+
return GapicClass.create(kind, classDef, SampleComposerUtil.handleDuplicateSamples(samples));
126130
}
127131

128132
private static List<CommentStatement> createClassHeaderComments(
129-
Service service, TypeNode classType) {
133+
Service service, TypeNode classType, List<Sample> samples) {
130134
// Pick the first pure unary rpc method, if no such method exists, then pick the first in the
131135
// list.
132136
Optional<Method> methodOpt =
@@ -139,15 +143,22 @@ private static List<CommentStatement> createClassHeaderComments(
139143
.orElse(service.methods().get(0)));
140144
Optional<String> methodNameOpt =
141145
methodOpt.isPresent() ? Optional.of(methodOpt.get().name()) : Optional.empty();
142-
Optional<String> sampleCodeOpt =
143-
SettingsSampleCodeComposer.composeSampleCode(
146+
Optional<Sample> sampleCode =
147+
SettingsSampleComposer.composeSettingsSample(
144148
methodNameOpt, ClassNames.getServiceSettingsClassName(service), classType);
149+
150+
Optional<String> docSampleCode = Optional.empty();
151+
if (sampleCode.isPresent()) {
152+
samples.add(sampleCode.get());
153+
docSampleCode = Optional.of(SampleCodeWriter.writeInlineSample(sampleCode.get().body()));
154+
}
155+
145156
return SettingsCommentComposer.createClassHeaderComments(
146157
ClassNames.getServiceClientClassName(service),
147158
service.defaultHost(),
148159
service.isDeprecated(),
149160
methodNameOpt,
150-
sampleCodeOpt,
161+
docSampleCode,
151162
classType);
152163
}
153164

src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubSettingsClassComposer.java

+20-9
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@
7979
import com.google.api.generator.engine.ast.Variable;
8080
import com.google.api.generator.engine.ast.VariableExpr;
8181
import com.google.api.generator.gapic.composer.comment.SettingsCommentComposer;
82-
import com.google.api.generator.gapic.composer.samplecode.SettingsSampleCodeComposer;
82+
import com.google.api.generator.gapic.composer.samplecode.SampleCodeWriter;
83+
import com.google.api.generator.gapic.composer.samplecode.SampleComposerUtil;
84+
import com.google.api.generator.gapic.composer.samplecode.SettingsSampleComposer;
8385
import com.google.api.generator.gapic.composer.store.TypeStore;
8486
import com.google.api.generator.gapic.composer.utils.ClassNames;
8587
import com.google.api.generator.gapic.composer.utils.PackageChecker;
@@ -91,6 +93,7 @@
9193
import com.google.api.generator.gapic.model.Message;
9294
import com.google.api.generator.gapic.model.Method;
9395
import com.google.api.generator.gapic.model.Method.Stream;
96+
import com.google.api.generator.gapic.model.Sample;
9497
import com.google.api.generator.gapic.model.Service;
9598
import com.google.api.generator.gapic.utils.JavaStyle;
9699
import com.google.common.base.Preconditions;
@@ -168,6 +171,7 @@ public GapicClass generate(GapicContext context, Service service) {
168171
String pakkage = String.format("%s.stub", service.pakkage());
169172
TypeStore typeStore = createDynamicTypes(service, pakkage);
170173

174+
List<Sample> samples = new ArrayList<>();
171175
Set<String> deprecatedSettingVarNames = new HashSet<>();
172176
Map<String, VariableExpr> methodSettingsMemberVarExprs =
173177
createMethodSettingsClassMemberVarExprs(
@@ -177,12 +181,12 @@ public GapicClass generate(GapicContext context, Service service) {
177181
/* isNestedClass= */ false,
178182
deprecatedSettingVarNames);
179183
String className = ClassNames.getServiceStubSettingsClassName(service);
180-
184+
List<CommentStatement> classHeaderComments =
185+
createClassHeaderComments(service, typeStore.get(className), samples);
181186
ClassDefinition classDef =
182187
ClassDefinition.builder()
183188
.setPackageString(pakkage)
184-
.setHeaderCommentStatements(
185-
createClassHeaderComments(service, typeStore.get(className)))
189+
.setHeaderCommentStatements(classHeaderComments)
186190
.setAnnotations(createClassAnnotations(service))
187191
.setScope(ScopeNode.PUBLIC)
188192
.setName(className)
@@ -196,7 +200,8 @@ public GapicClass generate(GapicContext context, Service service) {
196200
.setNestedClasses(
197201
Arrays.asList(createNestedBuilderClass(service, serviceConfig, typeStore)))
198202
.build();
199-
return GapicClass.create(GapicClass.Kind.STUB, classDef);
203+
return GapicClass.create(
204+
GapicClass.Kind.STUB, classDef, SampleComposerUtil.handleDuplicateSamples(samples));
200205
}
201206

202207
protected MethodDefinition createDefaultCredentialsProviderBuilderMethod() {
@@ -376,7 +381,7 @@ private List<AnnotationNode> createClassAnnotations(Service service) {
376381
}
377382

378383
private static List<CommentStatement> createClassHeaderComments(
379-
Service service, TypeNode classType) {
384+
Service service, TypeNode classType, List<Sample> samples) {
380385
// Pick the first pure unary rpc method, if no such method exists, then pick the first in the
381386
// list.
382387
Optional<Method> methodOpt =
@@ -389,16 +394,22 @@ private static List<CommentStatement> createClassHeaderComments(
389394
.orElse(service.methods().get(0)));
390395
Optional<String> methodNameOpt =
391396
methodOpt.isPresent() ? Optional.of(methodOpt.get().name()) : Optional.empty();
392-
Optional<String> sampleCodeOpt =
393-
SettingsSampleCodeComposer.composeSampleCode(
397+
Optional<Sample> sampleCode =
398+
SettingsSampleComposer.composeSettingsSample(
394399
methodNameOpt, ClassNames.getServiceSettingsClassName(service), classType);
395400

401+
Optional<String> docSampleCode = Optional.empty();
402+
if (sampleCode.isPresent()) {
403+
samples.add(sampleCode.get());
404+
docSampleCode = Optional.of(SampleCodeWriter.writeInlineSample(sampleCode.get().body()));
405+
}
406+
396407
return SettingsCommentComposer.createClassHeaderComments(
397408
ClassNames.getServiceStubClassName(service),
398409
service.defaultHost(),
399410
service.isDeprecated(),
400411
methodNameOpt,
401-
sampleCodeOpt,
412+
docSampleCode,
402413
classType);
403414
}
404415

src/main/java/com/google/api/generator/gapic/composer/samplecode/SampleBodyJavaFormatter.java

-2
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@
2121
import java.util.regex.Pattern;
2222

2323
public final class SampleBodyJavaFormatter {
24-
2524
private SampleBodyJavaFormatter() {}
2625

2726
private static final Formatter FORMATTER = new Formatter();
28-
2927
private static final String FAKE_CLASS_TITLE = "public class FakeClass { void fakeMethod() {\n";
3028
private static final String FAKE_CLASS_CLOSE = "}}";
3129

src/main/java/com/google/api/generator/gapic/composer/samplecode/SampleCodeWriter.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package com.google.api.generator.gapic.composer.samplecode;
1616

1717
import com.google.api.generator.engine.ast.ClassDefinition;
18+
import com.google.api.generator.engine.ast.Expr;
19+
import com.google.api.generator.engine.ast.ExprStatement;
1820
import com.google.api.generator.engine.ast.Statement;
1921
import com.google.api.generator.engine.writer.JavaWriterVisitor;
2022
import com.google.api.generator.gapic.model.Sample;
@@ -32,6 +34,11 @@ public static String writeExecutableSample(Sample sample, String packkage) {
3234
return write(SampleComposer.composeExecutableSample(sample, packkage));
3335
}
3436

37+
@VisibleForTesting
38+
public static String write(Statement... statement) {
39+
return write(Arrays.asList(statement));
40+
}
41+
3542
@VisibleForTesting
3643
public static String write(List<Statement> statements) {
3744
JavaWriterVisitor visitor = new JavaWriterVisitor();
@@ -50,7 +57,8 @@ public static String write(ClassDefinition classDefinition) {
5057
return visitor.write();
5158
}
5259

53-
public static String write(Statement... statement) {
54-
return write(Arrays.asList(statement));
60+
@VisibleForTesting
61+
public static String write(Expr expr) {
62+
return write(ExprStatement.withExpr(expr));
5563
}
5664
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.api.generator.gapic.composer.samplecode;
16+
17+
import com.google.api.generator.engine.ast.AssignmentExpr;
18+
import com.google.api.generator.engine.ast.MethodInvocationExpr;
19+
import com.google.api.generator.engine.ast.TypeNode;
20+
import com.google.api.generator.engine.ast.VariableExpr;
21+
import com.google.api.generator.gapic.model.MethodArgument;
22+
import com.google.api.generator.gapic.model.ResourceName;
23+
import com.google.api.generator.gapic.model.Sample;
24+
import com.google.api.generator.gapic.utils.JavaStyle;
25+
import java.util.List;
26+
import java.util.Map;
27+
import java.util.stream.Collectors;
28+
29+
public class SampleComposerUtil {
30+
// Assign client variable expr with create client.
31+
// e.g EchoClient echoClient = EchoClient.create()
32+
static AssignmentExpr assignClientVariableWithCreateMethodExpr(VariableExpr clientVarExpr) {
33+
return AssignmentExpr.builder()
34+
.setVariableExpr(clientVarExpr.toBuilder().setIsDecl(true).build())
35+
.setValueExpr(
36+
MethodInvocationExpr.builder()
37+
.setStaticReferenceType(clientVarExpr.variable().type())
38+
.setReturnType(clientVarExpr.variable().type())
39+
.setMethodName("create")
40+
.build())
41+
.build();
42+
}
43+
44+
static boolean isStringTypedResourceName(
45+
MethodArgument arg, Map<String, ResourceName> resourceNames) {
46+
return arg.type().equals(TypeNode.STRING)
47+
&& arg.field().hasResourceReference()
48+
&& resourceNames.containsKey(arg.field().resourceReference().resourceTypeString());
49+
}
50+
51+
static String createOverloadDisambiguation(List<VariableExpr> methodArgVarExprs) {
52+
if (methodArgVarExprs.isEmpty()) {
53+
return "Noargs";
54+
}
55+
return methodArgVarExprs.stream()
56+
.map(
57+
arg ->
58+
JavaStyle.toUpperCamelCase(
59+
arg.variable().type().reference() == null
60+
? arg.variable().type().typeKind().name().toLowerCase()
61+
: arg.variable().type().reference().name().toLowerCase()))
62+
.collect(Collectors.joining());
63+
}
64+
65+
public static List<Sample> handleDuplicateSamples(List<Sample> samples) {
66+
// grab all distinct samples and group by sample name
67+
// ie: { "echo", ["echo(request"],
68+
// "echoString", ["echo(parent)", "echo(child)", "echo(context)"],
69+
// "echoDelete", ["echo.delete(request)"] }
70+
Map<String, List<Sample>> distinctSamplesGroupedByName =
71+
samples.stream().distinct().collect(Collectors.groupingBy(s -> s.name()));
72+
73+
// collect samples that don't have duplicates
74+
// ie: ["echo", "echoDelete"]
75+
List<Sample> uniqueSamples =
76+
distinctSamplesGroupedByName.entrySet().stream()
77+
.filter(entry -> entry.getValue().size() < 2)
78+
.map(entry -> entry.getValue().get(0))
79+
.collect(Collectors.toList());
80+
81+
if (uniqueSamples.size() == distinctSamplesGroupedByName.size()) {
82+
return uniqueSamples;
83+
}
84+
85+
// collect samples that do have duplicates
86+
// ie: ["echoString"]
87+
List<Map.Entry<String, List<Sample>>> duplicateDistinctSamples =
88+
distinctSamplesGroupedByName.entrySet().stream()
89+
.filter(entry -> entry.getValue().size() > 1)
90+
.collect(Collectors.toList());
91+
92+
// update similar samples regionTag/name so filesname/regiontag are unique
93+
// ie: ["echo", "echoDelete", "echoString", "echoString1"]
94+
for (Map.Entry<String, List<Sample>> entry : duplicateDistinctSamples) {
95+
int sampleNum = 0;
96+
for (Sample sample : entry.getValue()) {
97+
Sample uniqueSample = sample;
98+
// first sample will be "canonical", not updating name
99+
if (sampleNum != 0) {
100+
uniqueSample =
101+
sample.withRegionTag(
102+
sample
103+
.regionTag()
104+
.withOverloadDisambiguation(
105+
sample.regionTag().overloadDisambiguation() + sampleNum));
106+
}
107+
uniqueSamples.add(uniqueSample);
108+
sampleNum++;
109+
}
110+
}
111+
return uniqueSamples;
112+
}
113+
}

0 commit comments

Comments
 (0)