Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make internal a trait and not just a tag #531

Merged
merged 2 commits into from
Aug 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions docs/source/1.0/guides/building-models/build-config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ The following is an example ``smithy-build.json`` configuration:
}
},
{
"name": "excludeTraitsByTag",
"name": "excludeShapesByTrait",
"args": {
"tags": ["internal"]
"traits": ["internal"]
}
}
],
Expand Down Expand Up @@ -287,6 +287,48 @@ the :ref:`tags trait <tags-trait>`.
This transformer does not remove shapes from the prelude.


.. _excludeShapesByTrait-transform:

excludeShapesByTrait
--------------------

Removes shapes if they are marked with one or more specific traits.

.. list-table::
:header-rows: 1
:widths: 10 20 70

* - Property
- Type
- Description
* - traits
- ``[string]``
- A list of trait :ref:`shape IDs <shape-id>`. If any of these traits
are found on a shape, the shape is removed from the model. Relative
shape IDs are assumed to be in the ``smithy.api``
:ref:`prelude <prelude>` namespace.

.. tabs::

.. code-tab:: json

{
"version": "1.0",
"projections": {
"exampleProjection": {
"transforms": [
{
"name": "excludeShapesByTrait",
"args": {
"traits": ["internal"]
}
}
]
}
}
}


.. _includeShapesByTag-transform:

includeShapesByTag
Expand Down
4 changes: 2 additions & 2 deletions docs/source/1.0/guides/building-models/gradle-plugin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ projection. For example:
}
},
{
"name": "excludeTraitsByTag",
"name": "excludeShapesByTrait",
"args": {
"tags": ["internal"]
"traits": ["internal"]
}
},
{
Expand Down
32 changes: 32 additions & 0 deletions docs/source/1.0/spec/core/documentation-traits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,38 @@ Value type
}


.. _internal-trait:

------------------
``internal`` trait
------------------

Summary
Shapes marked with the internal trait are meant only for internal use.
Tooling can use the ``internal`` trait to filter out shapes from models
that are not intended for external customers.
Trait selector
``*``
Value type
Annotation trait

As an example, a service team may wish to use a version of a model that
includes features that are only available to internal customers within the
same company, whereas clients for external customers could be built from a
filtered version of the model.

.. tabs::

.. code-tab:: smithy

structure MyStructure {
foo: String,

@internal
bar: String,
}


.. _sensitive-trait:

-------------------
Expand Down
2 changes: 1 addition & 1 deletion docs/source/1.0/spec/core/idl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1336,7 +1336,7 @@ members.
name: smithy.api#String,

@length(min: 0)
@tags(["internal"])
@tags(["private-beta"])
age: smithy.api#Integer,
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@
"smithy.api#externalDocumentation": {
"Developer Guide": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-api-key-source.html"
},
"smithy.api#tags": [
"internal"
]
"smithy.api#internal": {},
"smithy.api#tags": ["internal"]
}
},
"aws.apigateway#authorizers": {
Expand All @@ -29,9 +28,8 @@
"selector": "service"
},
"smithy.api#documentation": "A list of API Gateway authorizers to augment the service's declared authentication mechanisms.",
"smithy.api#tags": [
"internal"
]
"smithy.api#internal": {},
"smithy.api#tags": ["internal"]
}
},
"aws.apigateway#AuthorizerDefinition": {
Expand Down Expand Up @@ -104,9 +102,8 @@
"selector": ":test(service, resource, operation)"
},
"smithy.api#documentation": "Attaches an authorizer to a service, resource, or operation.",
"smithy.api#tags": [
"internal"
]
"smithy.api#internal": {},
"smithy.api#tags": ["internal"]
}
},
"aws.apigateway#requestValidator": {
Expand All @@ -116,9 +113,8 @@
"selector": ":test(service, operation)"
},
"smithy.api#documentation": "Selects which request validation strategy to use. One of: 'full', 'params-only', 'body-only'",
"smithy.api#tags": [
"internal"
]
"smithy.api#internal": {},
"smithy.api#tags": ["internal"]
}
},
"aws.apigateway#integration": {
Expand Down Expand Up @@ -187,9 +183,8 @@
]
},
"smithy.api#documentation": "Defines an API Gateway integration.",
"smithy.api#tags": [
"internal"
]
"smithy.api#internal": {},
"smithy.api#tags": ["internal"]
}
},
"aws.apigateway#mockIntegration": {
Expand All @@ -216,9 +211,8 @@
]
},
"smithy.api#documentation": "Defines an API Gateway mock integration.",
"smithy.api#tags": [
"internal"
]
"smithy.api#internal": {},
"smithy.api#tags": ["internal"]
}
},
"aws.apigateway#IntegrationType": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@
},
"smithy.api#authDefinition": {},
"smithy.api#documentation": "Configures an Amazon Cognito User Pools auth scheme.",
"smithy.api#tags": [
"internal"
]
"smithy.api#internal": {},
"smithy.api#tags": ["internal"]
}
},
"aws.auth#StringList": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. 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.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 software.amazon.smithy.build.transforms;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import software.amazon.smithy.build.TransformContext;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.loader.Prelude;
import software.amazon.smithy.model.shapes.ShapeId;

/**
* Removes shapes from the model if they are marked with a specific trait.
*/
public final class ExcludeShapesByTrait extends ConfigurableProjectionTransformer<ExcludeShapesByTrait.Config> {

public static final class Config {
private Set<String> traits = Collections.emptySet();

/**
* Gets the shape IDs of the traits to filter shapes by.
*
* <p>Relative shape IDs are assumed to be in the smithy.api namespace.
*
* @return Returns the trait shape IDs.
*/
public Set<String> getTraits() {
return traits;
}

/**
* Sets the shape IDs of the traits to filter shapes by.
*
* @param traits The shape IDs of the traits that if present causes a shape to be removed.
*/
public void setTraits(Set<String> traits) {
this.traits = traits;
}
}

@Override
public String getName() {
return "excludeShapesByTrait";
}

@Override
public Class<Config> getConfigType() {
return Config.class;
}

protected Model transformWithConfig(TransformContext context, Config config) {
// Resolve relative IDs by defaulting to smithy.api# if the given trait ID is relative.
Set<ShapeId> ids = new HashSet<>(config.getTraits().size());
for (String id : config.getTraits()) {
ids.add(ShapeId.fromOptionalNamespace(Prelude.NAMESPACE, id));
}

return context.getTransformer().removeShapesIf(context.getModel(), shape -> {
return ids.stream().anyMatch(shape::hasTrait);
});
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
software.amazon.smithy.build.transforms.ExcludeMetadata
software.amazon.smithy.build.transforms.ExcludeShapesByTag
software.amazon.smithy.build.transforms.ExcludeShapesByTrait
software.amazon.smithy.build.transforms.ExcludeTags
software.amazon.smithy.build.transforms.ExcludeTraits
software.amazon.smithy.build.transforms.ExcludeTraitsByTag
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package software.amazon.smithy.build.transforms;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;

import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import software.amazon.smithy.build.TransformContext;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.shapes.ShapeId;

public class ExcludeShapesByTraitTest {
@ParameterizedTest
@MethodSource("traitValues")
public void removesShapesByTrait(String trait) {
Model model = Model.assembler()
.addImport(getClass().getResource("internal-shapes.smithy"))
.assemble()
.unwrap();
TransformContext context = TransformContext.builder()
.model(model)
.settings(Node.objectNode().withMember("traits", Node.fromStrings(trait)))
.build();
Model result = new ExcludeShapesByTrait().transform(context);

// Structure removal also removes members.
assertThat(result.getShapeIds(), not(hasItem(ShapeId.from("smithy.example#InternalStructure"))));
assertThat(result.getShapeIds(), not(hasItem(ShapeId.from("smithy.example#InternalStructure$foo"))));

// Can remove specific members from structures.
assertThat(result.getShapeIds(), hasItem(ShapeId.from("smithy.example#ExternalStructure")));
assertThat(result.getShapeIds(), hasItem(ShapeId.from("smithy.example#ExternalStructure$external")));
assertThat(result.getShapeIds(), not(hasItem(ShapeId.from("smithy.example#ExternalStructure$internal"))));
}

public static List<String> traitValues() {
return Arrays.asList(
// Relative IDs are assumed to be in "smithy.api".
"internal",
// Absolute IDs are used as-is.
"smithy.api#internal"
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace smithy.example

@internal
structure InternalStructure {
foo: String,
}

structure ExternalStructure {
@internal
internal: String,

external: String,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. 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.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 software.amazon.smithy.model.traits;

import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.node.ObjectNode;
import software.amazon.smithy.model.shapes.ShapeId;

/**
* Shapes marked with the internal trait are meant only for internal use and
* must not be exposed to customers.
*/
public final class InternalTrait extends AnnotationTrait {
public static final ShapeId ID = ShapeId.from("smithy.api#internal");

public InternalTrait(ObjectNode node) {
super(ID, node);
}

public InternalTrait() {
this(Node.objectNode());
}

public static final class Provider extends AnnotationTrait.Provider<InternalTrait> {
public Provider() {
super(ID, InternalTrait::new);
}
}
}
Loading