Skip to content

Commit 88238e5

Browse files
committed
RemovedShape events from ERROR -> NOTE if the shape is safe to remove from a model.
1 parent 0ba148d commit 88238e5

File tree

3 files changed

+79
-5
lines changed

3 files changed

+79
-5
lines changed

smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/RemovedShape.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,23 @@
1919
import java.util.stream.Collectors;
2020
import software.amazon.smithy.diff.Differences;
2121
import software.amazon.smithy.model.shapes.Shape;
22+
import software.amazon.smithy.model.traits.EnumTrait;
2223
import software.amazon.smithy.model.traits.PrivateTrait;
2324
import software.amazon.smithy.model.validation.ValidationEvent;
2425

2526
/**
26-
* Creates an ERROR event when a non-private shape is removed.
27+
* Creates an ERROR event when a non-private non-scalar shape is removed.
28+
* Creates a NOTE event when a non-private scalar shape is removed.
2729
*/
2830
public final class RemovedShape extends AbstractDiffEvaluator {
2931
@Override
3032
public List<ValidationEvent> evaluate(Differences differences) {
3133
return differences.removedShapes()
3234
.filter(shape -> !shape.hasTrait(PrivateTrait.class))
3335
.filter(shape -> !isMemberOfRemovedShape(shape, differences))
34-
.map(shape -> error(shape, String.format("Removed %s `%s`", shape.getType(), shape.getId())))
36+
.map(shape -> isScalarType(shape)
37+
? note(shape, String.format("Removed %s `%s`", shape.getType(), shape.getId()))
38+
: error(shape, String.format("Removed %s `%s`", shape.getType(), shape.getId())))
3539
.collect(Collectors.toList());
3640
}
3741

@@ -40,4 +44,19 @@ private boolean isMemberOfRemovedShape(Shape shape, Differences differences) {
4044
.filter(member -> !differences.getNewModel().getShapeIds().contains(member.getContainer()))
4145
.isPresent();
4246
}
47+
48+
private boolean isScalarType(Shape shape) {
49+
return shape.isIntegerShape()
50+
|| shape.isBigDecimalShape()
51+
|| shape.isBigIntegerShape()
52+
|| shape.isBlobShape()
53+
|| shape.isBooleanShape()
54+
|| shape.isByteShape()
55+
|| shape.isDoubleShape()
56+
|| shape.isFloatShape()
57+
|| shape.isShortShape()
58+
|| shape.isTimestampShape()
59+
|| shape.isLongShape()
60+
|| (shape.isStringShape() && !shape.hasTrait(EnumTrait.class));
61+
}
4362
}

smithy-diff/src/test/java/software/amazon/smithy/diff/ModelDiffTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import software.amazon.smithy.model.Model;
1212
import software.amazon.smithy.model.node.Node;
1313
import software.amazon.smithy.model.shapes.StringShape;
14+
import software.amazon.smithy.model.shapes.StructureShape;
1415
import software.amazon.smithy.model.traits.SensitiveTrait;
1516
import software.amazon.smithy.model.validation.Severity;
1617
import software.amazon.smithy.model.validation.ValidatedResult;
@@ -77,7 +78,7 @@ public void testsEquality() {
7778
@Test
7879
public void findsBreakingChanges() {
7980
Model oldModel = Model.builder()
80-
.addShape(StringShape.builder().id("smithy.example#Str").build())
81+
.addShape(StructureShape.builder().id("smithy.example#Str").build())
8182
.build();
8283
Model newModel = Model.builder().build();
8384
ModelDiff.Result result = ModelDiff.builder().oldModel(oldModel).newModel(newModel).compare();

smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/RemovedShapeTest.java

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,33 @@
2323
import org.junit.jupiter.api.Test;
2424
import software.amazon.smithy.diff.ModelDiff;
2525
import software.amazon.smithy.model.Model;
26+
import software.amazon.smithy.model.shapes.BigDecimalShape;
27+
import software.amazon.smithy.model.shapes.BigIntegerShape;
28+
import software.amazon.smithy.model.shapes.BlobShape;
29+
import software.amazon.smithy.model.shapes.BooleanShape;
30+
import software.amazon.smithy.model.shapes.ByteShape;
31+
import software.amazon.smithy.model.shapes.DoubleShape;
32+
import software.amazon.smithy.model.shapes.FloatShape;
33+
import software.amazon.smithy.model.shapes.IntegerShape;
2634
import software.amazon.smithy.model.shapes.ListShape;
35+
import software.amazon.smithy.model.shapes.LongShape;
2736
import software.amazon.smithy.model.shapes.MemberShape;
2837
import software.amazon.smithy.model.shapes.Shape;
38+
import software.amazon.smithy.model.shapes.ShortShape;
2939
import software.amazon.smithy.model.shapes.StringShape;
40+
import software.amazon.smithy.model.shapes.StructureShape;
41+
import software.amazon.smithy.model.shapes.TimestampShape;
42+
import software.amazon.smithy.model.traits.EnumDefinition;
43+
import software.amazon.smithy.model.traits.EnumTrait;
3044
import software.amazon.smithy.model.traits.PrivateTrait;
3145
import software.amazon.smithy.model.validation.Severity;
3246
import software.amazon.smithy.model.validation.ValidationEvent;
3347

3448
public class RemovedShapeTest {
3549
@Test
3650
public void detectsShapeRemoval() {
37-
Shape shapeA1 = StringShape.builder().id("foo.baz#Baz").build();
38-
Shape shapeB1 = StringShape.builder().id("foo.baz#Bam").build();
51+
Shape shapeA1 = StructureShape.builder().id("foo.baz#Baz").build();
52+
Shape shapeB1 = StructureShape.builder().id("foo.baz#Bam").build();
3953
Model modelA = Model.assembler().addShapes(shapeA1, shapeB1).assemble().unwrap();
4054
Model modelB = Model.assembler().addShapes(shapeB1).assemble().unwrap();
4155
List<ValidationEvent> events = ModelDiff.compare(modelA, modelB);
@@ -45,6 +59,46 @@ public void detectsShapeRemoval() {
4559
assertThat(TestHelper.findEvents(events, Severity.ERROR).size(), equalTo(1));
4660
}
4761

62+
@Test
63+
public void emitsNotesForScalarShapes() {
64+
Shape[] scalarShapes = new Shape[] {
65+
IntegerShape.builder().id("foo.baz#BazOne").build(),
66+
BigDecimalShape.builder().id("foo.baz#BazTwo").build(),
67+
BigIntegerShape.builder().id("foo.baz#BazThree").build(),
68+
BlobShape.builder().id("foo.baz#BazFour").build(),
69+
BooleanShape.builder().id("foo.baz#BazFive").build(),
70+
ByteShape.builder().id("foo.baz#BazSix").build(),
71+
DoubleShape.builder().id("foo.baz#BazSeven").build(),
72+
FloatShape.builder().id("foo.baz#BazEight").build(),
73+
ShortShape.builder().id("foo.baz#BazNine").build(),
74+
TimestampShape.builder().id("foo.baz#BazTen").build(),
75+
LongShape.builder().id("foo.baz#BazEleven").build(),
76+
StringShape.builder().id("foo.baz#BazTwelve").build()
77+
};
78+
Model modelA = Model.assembler().addShapes(scalarShapes).assemble().unwrap();
79+
Model modelB = Model.assembler().assemble().unwrap();
80+
List<ValidationEvent> events = ModelDiff.compare(modelA, modelB);
81+
82+
assertThat(TestHelper.findEvents(events, "RemovedShape").size(), equalTo(12));
83+
assertThat("Scalar removals should be NOTE severity",
84+
events.stream().allMatch(event -> Severity.NOTE.equals(event.getSeverity())));
85+
}
86+
87+
@Test
88+
public void emitsErrorForEnumString() {
89+
Shape shapeA1 = StringShape.builder()
90+
.id("foo.baz#Baz")
91+
.addTrait(EnumTrait.builder().addEnum(EnumDefinition.builder().value("val").build()).build())
92+
.build();
93+
Model modelA = Model.assembler().addShapes(shapeA1).assemble().unwrap();
94+
Model modelB = Model.assembler().addShapes().assemble().unwrap();
95+
List<ValidationEvent> events = ModelDiff.compare(modelA, modelB);
96+
97+
assertThat(TestHelper.findEvents(events, "RemovedShape").size(), equalTo(1));
98+
assertThat(TestHelper.findEvents(events, shapeA1.getId()).size(), equalTo(1));
99+
assertThat(TestHelper.findEvents(events, Severity.ERROR).size(), equalTo(1));
100+
}
101+
48102
@Test
49103
public void doesNotEmitForPrivateShapes() {
50104
Shape shape = StringShape.builder().id("foo.baz#Baz").addTrait(new PrivateTrait()).build();

0 commit comments

Comments
 (0)