Repository: smithy-lang/smithy (java)

Issue:
Smithy models with subdirectories no-longer resolve correctly
After the changes in 5e864a12239c2df89e51980512a0b937c2b9b815, when using a directory as the source (ie. via the gradle plugin), any smithy files that were in subdirectories are no longer resolved.

Is this an intended removal of this behaviour, as I'm unsure if the recursive resolution was intended/documented originally?

We are relying on this behaviour for organisational purposes in our repo here for example: https://github.com/opensearch-project/opensearch-api-specification/tree/main/model

Pull request description:
Fix building models in subdirs
*Issue #, if available:*

Fixes #1859 

*Description of changes:*

Modifies the changes in https://github.com/smithy-lang/smithy/pull/1851, specifically `SmithyBuild::addSources`, to not check subdirectories for Smithy files. The previous behavior was to just add whatever path was given to the method, *not* everything in subdirectories. However, the change didn't recursively search subdirectores, so you could get build errors due to missing shapes when running the sources plugin.

This change reverts the behavior of `SmithyBuild::addSource` to only add whichever path it was given, but still checks to see if the path is a valid Smithy model.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.


Patch:
diff --git a/smithy-build/src/main/java/software/amazon/smithy/build/SmithyBuild.java b/smithy-build/src/main/java/software/amazon/smithy/build/SmithyBuild.java
index 136b03f77..6c6429eca 100644
--- a/smithy-build/src/main/java/software/amazon/smithy/build/SmithyBuild.java
+++ b/smithy-build/src/main/java/software/amazon/smithy/build/SmithyBuild.java
@@ -15,8 +15,6 @@
 
 package software.amazon.smithy.build;
 
-import java.io.IOException;
-import java.io.UncheckedIOException;
 import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -199,23 +197,10 @@ public final class SmithyBuild {
     //
     // Ignores and logs when an unsupported model file is encountered.
     private void addSource(Path path) {
-        try {
-            if (Files.isDirectory(path)) {
-                // Pre-emptively crawl the given models to filter them up front into a flat, file-only, list.
-                Files.list(path).filter(Files::isRegularFile).forEach(this::addSourceFile);
-            } else {
-                addSourceFile(path);
-            }
-        } catch (IOException e) {
-            throw new UncheckedIOException(e);
-        }
-    }
-
-    private void addSourceFile(Path file) {
-        if (!VALID_MODELS.matches(file.getFileName())) {
-            LOGGER.warning("Omitting unsupported Smithy model file from model sources: " + file);
+        if (Files.isRegularFile(path) && !VALID_MODELS.matches(path.getFileName())) {
+            LOGGER.warning("Omitting unsupported Smithy model file from model sources: " + path);
         } else {
-            sources.add(file.toAbsolutePath());
+            sources.add(path.toAbsolutePath());
         }
     }
 
diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpMethodSemanticsValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpMethodSemanticsValidator.java
index e34024072..69f38b383 100644
--- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpMethodSemanticsValidator.java
+++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpMethodSemanticsValidator.java
@@ -30,6 +30,7 @@ import software.amazon.smithy.model.traits.ReadonlyTrait;
 import software.amazon.smithy.model.validation.AbstractValidator;
 import software.amazon.smithy.model.validation.ValidationEvent;
 import software.amazon.smithy.model.validation.ValidationUtils;
+import software.amazon.smithy.utils.ListUtils;
 import software.amazon.smithy.utils.MapUtils;
 
 /**
@@ -94,10 +95,19 @@ public final class HttpMethodSemanticsValidator extends AbstractValidator {
             HttpTrait trait
     ) {
         String method = trait.getMethod().toUpperCase(Locale.US);
-        List<ValidationEvent> events = new ArrayList<>();
 
+        // We don't have a standard method, so we can't validate it.
         if (!EXPECTED.containsKey(method)) {
-            return events;
+            return ListUtils.of();
+        }
+
+        List<ValidationEvent> events = new ArrayList<>();
+
+        // Emit a warning if the method is standard, but doesn't match standard casing.
+        if (!EXPECTED.containsKey(trait.getMethod())) {
+            events.add(warning(shape, trait, String.format(
+                    "This operation uses the `%s` method in the `http` trait, but expected `%s`.",
+                    trait.getMethod(), method)));
         }
 
         HttpMethodSemantics semantics = EXPECTED.get(method);


Test patch:
diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/http-method-semantics-validator.errors b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/http-method-semantics-validator.errors
index e63b8308a..47fe47a07 100644
--- a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/http-method-semantics-validator.errors
+++ b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/http-method-semantics-validator.errors
@@ -5,3 +5,4 @@
 [WARNING] ns.foo#H: This operation uses the `DELETE` method in the `http` trait, but is not marked with the idempotent trait | HttpMethodSemantics.MissingIdempotentTrait
 [WARNING] ns.foo#I: This operation uses the `GET` method in the `http` trait, but is not marked with the readonly trait | HttpMethodSemantics.MissingReadonlyTrait
 [WARNING] ns.foo#Options: OPTIONS requests are typically used as part of CORS and should not be modeled explicitly. They are an implementation detail that should not appear in generated client or server code. Instead, tooling should use the `cors` trait on a service to automatically configure CORS on clients and servers. It is the responsibility of service frameworks and API gateways to automatically manage OPTIONS requests. For example, OPTIONS requests are automatically created when using Smithy models with Amazon API Gateway. | HttpMethodSemantics.OPTIONS
+[WARNING] ns.foo#A: This operation uses the `Get` method in the `http` trait, but expected `GET`. | HttpMethodSemantics
diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/http-method-semantics-validator.json b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/http-method-semantics-validator.json
index d55c1449a..b457df117 100644
--- a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/http-method-semantics-validator.json
+++ b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/http-method-semantics-validator.json
@@ -6,7 +6,7 @@
             "traits": {
                 "smithy.api#readonly": {},
                 "smithy.api#http": {
-                    "method": "GET",
+                    "method": "Get",
                     "uri": "/A"
                 }
             }