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

Add tutorial project for smithy gradle plugins #80

Merged
merged 3 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
25 changes: 25 additions & 0 deletions gradle-plugin-examples/integ/tutorial/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

plugins {
id("java-library")
}

// The test project doesn't produce a JAR.
tasks["jar"].enabled = false

tasks.named<Test>("test") {
useJUnitPlatform()
systemProperty("buildFolder",
gradle.includedBuild("tutorial").projectDir.resolve("service").resolve("build").absolutePath)
}

tasks["test"].dependsOn(gradle.includedBuild("tutorial").task(":service:build"))

dependencies {
val smithyVersion: String by project

testImplementation("software.amazon.smithy:smithy-model:$smithyVersion")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.4.0")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.4.0")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.4.0")
hpmellema marked this conversation as resolved.
Show resolved Hide resolved
testImplementation("org.hamcrest:hamcrest:2.1")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package io.smithy.examples.plugins;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.validation.Severity;
import software.amazon.smithy.model.validation.ValidationEvent;

public class PluginTutorialTest {

static File smithyBuildInfo;
static List<ValidationEvent> validationEvents;

@BeforeAll
static void setup() throws FileNotFoundException {
Path buildFolderPath = Paths.get(System.getProperty("buildFolder"));
System.out.println(buildFolderPath);
smithyBuildInfo = buildFolderPath.resolve("smithyprojections")
.resolve("service")
.resolve("source")
.resolve("build-info")
.resolve("smithy-build-info.json")
.toFile();
var jsonOutput = Node.parse(new FileInputStream(smithyBuildInfo)).expectObjectNode();
validationEvents = jsonOutput.expectMember("validationEvents")
.expectArrayNode()
.getElementsAs(ValidationEvent::fromNode);
}

@Test
public void correctNumberOfValidations() {
var expectedMatches = 1;
assertEquals(validationEvents.size(), expectedMatches);
}

@Test
public void correctSeverityOfValidations() {
assertTrue(validationEvents.stream()
.allMatch(event -> event.getSeverity().equals(Severity.WARNING))
);
}

@Test
public void correctTypesOfValidations() {
assertEquals(validationEvents.stream()
.peek(System.out::println)
.filter(event -> event.getId().equals("DocUrl")).count(), 1);
}
}
26 changes: 26 additions & 0 deletions gradle-plugin-examples/tutorial/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
### Smithy Gradle Plugin Tutorial

An example Smithy project that demonstrates how to use the [Smithy Gradle plugins](https://github.com/smithy-lang/smithy-gradle-plugin)
hpmellema marked this conversation as resolved.
Show resolved Hide resolved
by creating a simple Cafe service model.

This project:
1. Sets up a `lib` project containing Smithy models that are shared across other Smithy projects.
2. Uses these shared models as a dependency of the `service` package to create a Cafe service model.
3. Create a custom linter in the `lib` package that can be used by consumers of the `lib` package to
check for `externalDocumentation` links that do not match an expected site address.

For more information on the use of the Smithy Gradle plugins see the [plugin guide](https://smithy.io/2.0/guides/gradle-plugin/index.html).

## Building
To build this package run the following from the root of the package:

```
./gradlew clean build
```

This will generate a `build` directory in both the `lib` and `service` subprojects
containing the build artifacts generated by gradle.

## Distribution
If you want to distribute either of the JAR files created by this package, consider adding the
[maven-publish](https://docs.gradle.org/current/userguide/publishing_maven.html) plugin to the project to publish the JAR to a maven repository.
9 changes: 9 additions & 0 deletions gradle-plugin-examples/tutorial/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[versions]
commons-math3 = "3.6.1"
guava = "32.1.2-jre"
junit-jupiter = "5.10.0"

[libraries]
commons-math3 = { module = "org.apache.commons:commons-math3", version.ref = "commons-math3" }
guava = { module = "com.google.guava:guava", version.ref = "guava" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }
45 changes: 45 additions & 0 deletions gradle-plugin-examples/tutorial/lib/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java library project to get you started.
* For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.5/userguide/building_java_projects.html in the Gradle documentation.
*/

plugins {
// Apply the java-library plugin for API and implementation separation.
`java-library`
// Build Smithy models and add them to the generated library JAR.
id("software.amazon.smithy.gradle.smithy-jar").version("0.10.1")
}

repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}

dependencies {
// Use JUnit Jupiter for testing.
testImplementation(libs.junit.jupiter)

testRuntimeOnly("org.junit.platform:junit-platform-launcher")

// This dependency is exported to consumers, that is to say found on their compile classpath.
api(libs.commons.math3)

// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation(libs.guava)

implementation("software.amazon.smithy:smithy-model:1.45.0")
}

// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}

tasks.named<Test>("test") {
// Use JUnit Platform for unit tests.
useJUnitPlatform()
}
23 changes: 23 additions & 0 deletions gradle-plugin-examples/tutorial/lib/model/common.smithy
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
$version: "2.0"

namespace com.example.cafe.common

/// The price of a menu item should be a positive number
@range(min: 0.0)
bigDecimal Price

enum Style {
ICED
HOT
}

enum Type {
COFFEE
TEA
COCOA
}

/// ID used to Identify a menu item
@length(min: 1, max: 64)
@pattern("^[a-zA-Z0-9_]$")
string MenuItemId
3 changes: 3 additions & 0 deletions gradle-plugin-examples/tutorial/lib/smithy-build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"version": "1.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.example.cafe;

import java.util.List;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.traits.ExternalDocumentationTrait;
import software.amazon.smithy.model.validation.AbstractValidator;
import software.amazon.smithy.model.validation.ValidationEvent;
import software.amazon.smithy.model.validation.ValidatorService;

public final class DocUrlValidator extends AbstractValidator {
private static final String CAFE_SITE_NAME = "cafe.example.smithy.io";

public static final class Provider extends ValidatorService.Provider {
public Provider() {
super(DocUrlValidator.class, DocUrlValidator::new);
}
}

@Override
public List<ValidationEvent> validate(Model model) {
// Find every shape that violates the linter and return a list
// of ValidationEvents.
return model.shapes()
.filter(shape -> shape.hasTrait(ExternalDocumentationTrait.class))
.flatMap(shape -> shape.expectTrait(ExternalDocumentationTrait.class)
// Get a stream of Name -> URL entries
.getUrls().entrySet().stream()
// Get all URLs that do not match expected internal site name
.filter(entry -> !entry.getValue().contains(CAFE_SITE_NAME))
// Emit a helpful warning message for each invalid URL
.map(entry -> warning(shape, String.format("External url `%s` for `%s` is invalid."
+ " Expected URL to start with " + CAFE_SITE_NAME, entry.getValue(), entry.getKey())))
).toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
com.example.cafe.DocUrlValidator$Provider

15 changes: 15 additions & 0 deletions gradle-plugin-examples/tutorial/service/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

plugins {
`java-library`
id("software.amazon.smithy.gradle.smithy-jar").version("0.10.1")
}

repositories {
mavenCentral()
}

dependencies {
// Use common models
implementation(project(":lib"))
}

58 changes: 58 additions & 0 deletions gradle-plugin-examples/tutorial/service/model/service.smithy
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
$version: "2.0"

metadata validators = [
{
name: "DocUrl"
}
]

namespace com.example.cafe.service

// Add common shapes from `lib` subproject
use com.example.cafe.common#MenuItemId

use com.example.cafe.common#Price
use com.example.cafe.common#Style
use com.example.cafe.common#Type

/// Provides an API for ordering coffee
service CoffeeService {
version: "2024-03-30"
resources: [
Order
]
}

@externalDocumentation(wikipedia: "https://en.wikipedia.org/wiki/Order")
resource Order {
identifiers: { id: MenuItemId }
properties: { price: Price, style: Style, type: Type }
create: CreateOrder
read: GetOrder
}

operation CreateOrder {
input := for Order {
$style
$type
}

output := for Order {
@required
$id
}
}

@readonly
operation GetOrder {
input := for Order {
@required
$id
}

output := for Order {
$price
$style
$type
}
}
3 changes: 3 additions & 0 deletions gradle-plugin-examples/tutorial/service/smithy-build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"version": "1.0"
}
15 changes: 15 additions & 0 deletions gradle-plugin-examples/tutorial/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* This file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
* For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.5/userguide/building_swift_projects.html in the Gradle documentation.
*/

plugins {
// Apply the foojay-resolver plugin to allow automatic download of JDKs
id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0"
}

rootProject.name = "smithy-gradle-tutorial"
include("lib")
include("service")
7 changes: 7 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,10 @@ include(":linting-and-validation-examples:integ:common-linting-configuration-tes
include(":linting-and-validation-examples:integ:custom-linter-test")
include(":linting-and-validation-examples:integ:custom-validator-test")
include(":linting-and-validation-examples:integ:decorators-test")

// ---- Gradle Plugin Examples -----
// Templates
includeBuild("gradle-plugin-examples/tutorial")

// Integ test
include(":gradle-plugin-examples:integ:tutorial")
13 changes: 13 additions & 0 deletions smithy-templates.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,19 @@
".gitignore",
".gitattributes"
]
},
"smithy-gradle-tutorial": {
"documentation": "Tutorial project that demonstrates how to use the Smithy Gradle plugins.",
"path": "gradle-plugin-examples/tutorial",
"include": [
"config/",
"gradle/",
"gradlew",
"gradlew.bat",
"gradle.properties",
".gitignore",
".gitattributes"
]
}
}
}
Loading