Repository: smithy-lang/smithy
Pull request #2016 (2023-10-23 17:54:37)

Bump actions/setup-node from 3 to 4
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/actions/setup-node/releases">actions/setup-node's releases</a>.</em></p>
<blockquote>
<h2>v4.0.0</h2>
<h2>What's Changed</h2>
<p>In scope of this release we changed version of node runtime for action from node16 to node20 and updated dependencies in <a href="https://redirect.github.com/actions/setup-node/pull/866">actions/setup-node#866</a></p>
<p>Besides, release contains such changes as:</p>
<ul>
<li>Upgrade actions/checkout to v4 by <a href="https://github.com/gmembre-zenika"><code>@​gmembre-zenika</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/868">actions/setup-node#868</a></li>
<li>Update actions/checkout for documentation and yaml by <a href="https://github.com/dmitry-shibanov"><code>@​dmitry-shibanov</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/876">actions/setup-node#876</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/gmembre-zenika"><code>@​gmembre-zenika</code></a> made their first contribution in <a href="https://redirect.github.com/actions/setup-node/pull/868">actions/setup-node#868</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/actions/setup-node/compare/v3...v4.0.0">https://github.com/actions/setup-node/compare/v3...v4.0.0</a></p>
<h2>v3.8.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Update semver by <a href="https://github.com/dmitry-shibanov"><code>@​dmitry-shibanov</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/861">actions/setup-node#861</a></li>
<li>Update temp directory creation by <a href="https://github.com/nikolai-laevskii"><code>@​nikolai-laevskii</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/859">actions/setup-node#859</a></li>
<li>Bump <code>@​babel/traverse</code> from 7.15.4 to 7.23.2 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/870">actions/setup-node#870</a></li>
<li>Add notice about binaries not being updated yet by <a href="https://github.com/nikolai-laevskii"><code>@​nikolai-laevskii</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/872">actions/setup-node#872</a></li>
<li>Update toolkit cache and core by <a href="https://github.com/dmitry-shibanov"><code>@​dmitry-shibanov</code></a> and <a href="https://github.com/seongwon-privatenote"><code>@​seongwon-privatenote</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/875">actions/setup-node#875</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/actions/setup-node/compare/v3...v3.8.2">https://github.com/actions/setup-node/compare/v3...v3.8.2</a></p>
<h2>v3.8.1</h2>
<h2>What's Changed</h2>
<p>In scope of this release, the filter was removed within the cache-save step by <a href="https://github.com/dmitry-shibanov"><code>@​dmitry-shibanov</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/831">actions/setup-node#831</a>. It is filtered and checked in the toolkit/cache library.</p>
<p><strong>Full Changelog</strong>: <a href="https://github.com/actions/setup-node/compare/v3...v3.8.1">https://github.com/actions/setup-node/compare/v3...v3.8.1</a></p>
<h2>v3.8.0</h2>
<h2>What's Changed</h2>
<h3>Bug fixes:</h3>
<ul>
<li>Add check for existing paths by <a href="https://github.com/dmitry-shibanov"><code>@​dmitry-shibanov</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/803">actions/setup-node#803</a></li>
<li>Resolve SymbolicLink by <a href="https://github.com/dmitry-shibanov"><code>@​dmitry-shibanov</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/809">actions/setup-node#809</a></li>
<li>Change passing logic for cache input by <a href="https://github.com/dmitry-shibanov"><code>@​dmitry-shibanov</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/816">actions/setup-node#816</a></li>
<li>Fix armv7 cache issue by <a href="https://github.com/louislam"><code>@​louislam</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/794">actions/setup-node#794</a></li>
<li>Update check-dist workflow name by <a href="https://github.com/sinchang"><code>@​sinchang</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/710">actions/setup-node#710</a></li>
</ul>
<h3>Feature implementations:</h3>
<ul>
<li>feat: handling the case where &quot;node&quot; is used for tool-versions file. by <a href="https://github.com/xytis"><code>@​xytis</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/812">actions/setup-node#812</a></li>
</ul>
<h3>Documentation changes:</h3>
<ul>
<li>Refer to semver package name in README.md by <a href="https://github.com/olleolleolle"><code>@​olleolleolle</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/808">actions/setup-node#808</a></li>
</ul>
<h3>Update dependencies:</h3>
<ul>
<li>Update toolkit cache to fix zstd by <a href="https://github.com/dmitry-shibanov"><code>@​dmitry-shibanov</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/804">actions/setup-node#804</a></li>
<li>Bump tough-cookie and <code>@​azure/ms-rest-js</code> by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/802">actions/setup-node#802</a></li>
<li>Bump semver from 6.1.2 to 6.3.1 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/807">actions/setup-node#807</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/actions/setup-node/commit/8f152de45cc393bb48ce5d89d36b731f54556e65"><code>8f152de</code></a> Update actions/checkout for documentation and yaml (<a href="https://redirect.github.com/actions/setup-node/issues/876">#876</a>)</li>
<li><a href="https://github.com/actions/setup-node/commit/23755b521f87533c8ed7f8fb13674f9021579e34"><code>23755b5</code></a> upgrade actions/checkout to v4 (<a href="https://redirect.github.com/actions/setup-node/issues/868">#868</a>)</li>
<li><a href="https://github.com/actions/setup-node/commit/54534a2a9ba7308e8a8995af3104899e6a95b681"><code>54534a2</code></a> Change node version for action to node20 (<a href="https://redirect.github.com/actions/setup-node/issues/866">#866</a>)</li>
<li>See full diff in <a href="https://github.com/actions/setup-node/compare/v3...v4">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-node&package-manager=github_actions&previous-version=3&new-version=4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/.github/workflows/sdk-codegen-ci.yml b/.github/workflows/sdk-codegen-ci.yml
index cc8551614..69a29f3d5 100644
--- a/.github/workflows/sdk-codegen-ci.yml
+++ b/.github/workflows/sdk-codegen-ci.yml
@@ -8,7 +8,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Use Node.js 14.x
-        uses: actions/setup-node@v3
+        uses: actions/setup-node@v4
         with:
           node-version: 14.x
 
diff --git a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/SmithyIntegration.java b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/SmithyIntegration.java
index 5ab5ddad2..a0a5ff9bf 100644
--- a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/SmithyIntegration.java
+++ b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/SmithyIntegration.java
@@ -19,6 +19,7 @@ import java.util.Collections;
 import java.util.List;
 import software.amazon.smithy.build.FileManifest;
 import software.amazon.smithy.model.Model;
+import software.amazon.smithy.model.node.ObjectNode;
 import software.amazon.smithy.utils.AbstractCodeWriter;
 import software.amazon.smithy.utils.CodeInterceptor;
 import software.amazon.smithy.utils.CodeSection;
@@ -70,6 +71,49 @@ public interface SmithyIntegration<S, W extends SymbolWriter<W, ?>, C extends Co
         return 0;
     }
 
+    /**
+     * Configures the integration.
+     *
+     * <p>This provides access to both the parsed settings for the generator and
+     * an unparsed {@link ObjectNode} containing settings for this particular
+     * integration.
+     *
+     * <p>The following {@code smithy-build.json} file contains an example of how
+     * this configuration will be set.
+     *
+     * <pre>{@code
+     * {
+     *     "version": "1.0",
+     *     "projections": {
+     *         "codegen-projection": {
+     *             "plugins": {
+     *                 "code-generator": {
+     *                     "service": "com.example#DocumentedService",
+     *                     "integrations": {
+     *                         "my-integration": {
+     *                             "example-setting": "foo"
+     *                         }
+     *                     }
+     *                 }
+     *             }
+     *         }
+     *     }
+     * }
+     * }</pre>
+     *
+     * <p>In this example, an integration whose {@link #name} is {@code my-integration}
+     * Would receive the extra settings from the key of the same name within the
+     * {@code integrations} node.
+     *
+     * <p>Integrations SHOULD use modeled traits as much as possible to drive
+     * configuration. This is intended for configuration that doesn't make sense
+     * as a trait, such as configuring a documentation theme.
+     *
+     * @param settings Settings used to generate code.
+     * @param integrationSettings Settings used to configure integrations.
+     */
+    default void configure(S settings, ObjectNode integrationSettings) {}
+
     /**
      * Gets the names of integrations that this integration must come before.
      *
@@ -103,7 +147,7 @@ public interface SmithyIntegration<S, W extends SymbolWriter<W, ?>, C extends Co
      * <p>By default, this method will return the given {@code model} as-is.
      *
      * @param model Model being generated.
-     * @param settings Setting used to generate code.
+     * @param settings Settings used to generate code.
      * @return Returns the updated model.
      */
     default Model preprocessModel(Model model, S settings) {
@@ -122,7 +166,7 @@ public interface SmithyIntegration<S, W extends SymbolWriter<W, ?>, C extends Co
      * <p>This integration method should be called only after {@link #preprocessModel}.
      *
      * @param model Model being generated.
-     * @param settings Setting used to generate.
+     * @param settings Settings used to generate.
      * @param symbolProvider The original {@code SymbolProvider}.
      * @return The decorated {@code SymbolProvider}.
      */
diff --git a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/directed/CodegenDirector.java b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/directed/CodegenDirector.java
index 127f746f9..81e024138 100644
--- a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/directed/CodegenDirector.java
+++ b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/directed/CodegenDirector.java
@@ -36,6 +36,7 @@ import software.amazon.smithy.model.Model;
 import software.amazon.smithy.model.neighbor.Walker;
 import software.amazon.smithy.model.node.Node;
 import software.amazon.smithy.model.node.NodeMapper;
+import software.amazon.smithy.model.node.ObjectNode;
 import software.amazon.smithy.model.shapes.EnumShape;
 import software.amazon.smithy.model.shapes.IntEnumShape;
 import software.amazon.smithy.model.shapes.OperationShape;
@@ -74,6 +75,7 @@ public final class CodegenDirector<
     private ShapeId service;
     private Model model;
     private S settings;
+    private ObjectNode integrationSettings = Node.objectNode();
     private FileManifest fileManifest;
     private Supplier<Iterable<I>> integrationFinder;
     private DirectedCodegen<C, S, I> directedCodegen;
@@ -143,6 +145,8 @@ public final class CodegenDirector<
     /**
      * Sets the required settings object used for code generation.
      *
+     * <p>{@link #integrationSettings} MUST also be set.
+     *
      * @param settings Settings object.
      */
     public void settings(S settings) {
@@ -159,6 +163,9 @@ public final class CodegenDirector<
      * You will need to manually deserialize your settings if using types that
      * are not supported by Smithy's {@link NodeMapper}.
      *
+     * <p>This will also set {@link #integrationSettings} if the {@code integrations}
+     * key is present.
+     *
      * @param settingsType Settings type to deserialize into.
      * @param settingsNode Settings node value to deserialize.
      * @return Returns the deserialized settings as this is needed to provide a service shape ID.
@@ -167,9 +174,48 @@ public final class CodegenDirector<
         LOGGER.fine(() -> "Loading codegen settings from node value: " + settingsNode.getSourceLocation());
         S deserialized = new NodeMapper().deserialize(settingsNode, settingsType);
         settings(deserialized);
+        settingsNode.asObjectNode()
+            .flatMap(node -> node.getObjectMember("integrations"))
+            .ifPresent(this::integrationSettings);
         return deserialized;
     }
 
+    /**
+     * Sets the settings node to be passed to integrations.
+     *
+     * <p>Generators MUST set this with the {@code integrations} key from their
+     * plugin settings.
+     *
+     * <pre>{@code
+     * {
+     *     "version": "1.0",
+     *     "projections": {
+     *         "codegen-projection": {
+     *             "plugins": {
+     *                 "code-generator": {
+     *                     "service": "com.example#DocumentedService",
+     *                     "integrations": {
+     *                         "my-integration": {
+     *                             "example-setting": "foo"
+     *                         }
+     *                     }
+     *                 }
+     *             }
+     *         }
+     *     }
+     * }
+     * }</pre>
+     *
+     * <p>In this example, the value of the {@code integrations} key is what must
+     * be passed to this method. The value of the {@code my-integration} key will
+     * then be provided to an integration with the name {@code my-integration}.
+     *
+     * @param integrationSettings Settings used to configure integrations.
+     */
+    public void integrationSettings(ObjectNode integrationSettings) {
+        this.integrationSettings = Objects.requireNonNull(integrationSettings);
+    }
+
     /**
      * Sets the required file manifest used to write files to disk.
      *
@@ -366,7 +412,10 @@ public final class CodegenDirector<
     private List<I> findIntegrations() {
         LOGGER.fine(() -> "Finding integration implementations of " + integrationClass.getName());
         List<I> integrations = SmithyIntegration.sort(integrationFinder.get());
-        integrations.forEach(i -> LOGGER.finest(() -> "Found integration " + i.getClass().getCanonicalName()));
+        integrations.forEach(i -> {
+            LOGGER.finest(() -> "Found integration " + i.getClass().getCanonicalName());
+            i.configure(settings, integrationSettings.getObjectMember(i.name()).orElse(Node.objectNode()));
+        });
         return integrations;
     }
 


Test patch:
diff --git a/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/directed/CapturingIntegration.java b/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/directed/CapturingIntegration.java
new file mode 100644
index 000000000..73fe5997d
--- /dev/null
+++ b/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/directed/CapturingIntegration.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package software.amazon.smithy.codegen.core.directed;
+
+import software.amazon.smithy.model.node.Node;
+import software.amazon.smithy.model.node.ObjectNode;
+
+public class CapturingIntegration implements TestIntegration {
+    public ObjectNode integrationSettings = Node.objectNode();
+
+    @Override
+    public String name() {
+        return "capturing-integration";
+    }
+
+    @Override
+    public void configure(TestSettings settings, ObjectNode integrationSettings) {
+        this.integrationSettings = integrationSettings;
+    }
+}
diff --git a/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/directed/CodegenDirectorTest.java b/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/directed/CodegenDirectorTest.java
index 295633630..df320005b 100644
--- a/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/directed/CodegenDirectorTest.java
+++ b/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/directed/CodegenDirectorTest.java
@@ -19,6 +19,9 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.notNullValue;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -33,6 +36,7 @@ import software.amazon.smithy.codegen.core.WriterDelegator;
 import software.amazon.smithy.model.Model;
 import software.amazon.smithy.model.node.ExpectationNotMetException;
 import software.amazon.smithy.model.node.Node;
+import software.amazon.smithy.model.node.ObjectNode;
 import software.amazon.smithy.model.shapes.ShapeId;
 
 public class CodegenDirectorTest {
@@ -42,6 +46,8 @@ public class CodegenDirectorTest {
         public final List<ShapeId> generatedEnumTypeEnums = new ArrayList<>();
         public final List<ShapeId> generatedStringTypeEnums = new ArrayList<>();
 
+        public final List<TestIntegration> integrations = new ArrayList<>();
+
         @Override
         public SymbolProvider createSymbolProvider(CreateSymbolProviderDirective<TestSettings> directive) {
             return shape -> Symbol.builder()
@@ -52,6 +58,8 @@ public class CodegenDirectorTest {
 
         @Override
         public TestContext createContext(CreateContextDirective<TestSettings, TestIntegration> directive) {
+            integrations.clear();
+            integrations.addAll(directive.integrations());
             WriterDelegator<TestWriter> delegator = new WriterDelegator<>(
                     directive.fileManifest(),
                     directive.symbolProvider(),
@@ -339,4 +347,42 @@ public class CodegenDirectorTest {
                 ShapeId.from("smithy.example#Foo")
         ));
     }
+
+    @Test
+    public void testConfiguresIntegrations() {
+        TestDirected testDirected = new TestDirected();
+        CodegenDirector<TestWriter, TestIntegration, TestContext, TestSettings> runner
+            = new CodegenDirector<>();
+        FileManifest manifest = new MockManifest();
+        Model model = Model.assembler()
+            .addImport(getClass().getResource("needs-sorting.smithy"))
+            .assemble()
+            .unwrap();
+
+        ObjectNode integrationSettings = Node.objectNode().withMember("spam", "eggs");
+        ObjectNode allIntegrationSettings = Node.objectNode()
+                .withMember("capturing-integration", integrationSettings);
+        ObjectNode settings = Node.objectNode()
+            .withMember("foo", "hi")
+            .withMember("integrations", allIntegrationSettings);
+        runner.settings(TestSettings.class, settings);
+        runner.directedCodegen(testDirected);
+        runner.fileManifest(manifest);
+        runner.service(ShapeId.from("smithy.example#Foo"));
+        runner.model(model);
+        runner.integrationClass(TestIntegration.class);
+        runner.performDefaultCodegenTransforms();
+        runner.shapeGenerationOrder(ShapeGenerationOrder.NONE);
+        runner.run();
+
+        assertThat(testDirected.integrations, not(empty()));
+        CapturingIntegration capturingIntegration = null;
+        for (TestIntegration integration : testDirected.integrations) {
+            if (integration instanceof CapturingIntegration) {
+                capturingIntegration = (CapturingIntegration) integration;
+            }
+        }
+        assertThat(capturingIntegration, notNullValue());
+        assertThat(capturingIntegration.integrationSettings, equalTo(integrationSettings));
+    }
 }
diff --git a/smithy-codegen-core/src/test/resources/META-INF/services/software.amazon.smithy.codegen.core.directed.TestIntegration b/smithy-codegen-core/src/test/resources/META-INF/services/software.amazon.smithy.codegen.core.directed.TestIntegration
new file mode 100644
index 000000000..7b3cf821d
--- /dev/null
+++ b/smithy-codegen-core/src/test/resources/META-INF/services/software.amazon.smithy.codegen.core.directed.TestIntegration
@@ -0,0 +1,1 @@
+software.amazon.smithy.codegen.core.directed.CapturingIntegration