From a7ad89906dcf577e21681ecd583f4641ab68373a Mon Sep 17 00:00:00 2001 From: Chase Coalwell <782571+srchase@users.noreply.github.com> Date: Fri, 8 Sep 2023 17:02:30 -0600 Subject: [PATCH] Automate versioning of @smithy packages (#832) --- scripts/update-codegen-package-versions.js | 46 ------ smithy-typescript-codegen/build.gradle.kts | 33 ++++ .../codegen/TypeScriptDependency.java | 145 ++++++++++++------ .../codegen/TypeScriptDependencyTest.java | 19 +++ 4 files changed, 153 insertions(+), 90 deletions(-) delete mode 100644 scripts/update-codegen-package-versions.js diff --git a/scripts/update-codegen-package-versions.js b/scripts/update-codegen-package-versions.js deleted file mode 100644 index 0205f629d24..00000000000 --- a/scripts/update-codegen-package-versions.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * - * This script rewrites the TypeScriptDepdendency.java file - * with the current versions present in the packages/__/package.json files. - * - * This script can be deleted after moving to an automated method - * of updating the package version numbers in code generation. - * - */ - -const fs = require("node:fs"); -const path = require("node:path"); - -const root = path.join(__dirname, ".."); -const packages = path.join(root, "packages"); - -const javaFile = path.join( - root, - "smithy-typescript-codegen", - "src", - "main", - "java", - "software", - "amazon", - "smithy", - "typescript", - "codegen", - "TypeScriptDependency.java" -); - -let javaSrc = fs.readFileSync(javaFile, "utf-8"); - -for (const folder of fs.readdirSync(packages)) { - const pkgJson = require(path.join(packages, folder, "package.json")); - const { version, name } = pkgJson; - - const find = new RegExp(`"@smithy\\/${name.replace("@smithy/", "")}",(\\s)*"\\^\\d+\\.\\d+\\.\\d+"`); - - const replace = `"${name}", "^${version}"`; - - console.log(find, replace, find.test(javaSrc)); - - javaSrc = javaSrc.replace(find, replace); -} - -fs.writeFileSync(javaFile, javaSrc, "utf-8"); diff --git a/smithy-typescript-codegen/build.gradle.kts b/smithy-typescript-codegen/build.gradle.kts index 8a1680dec29..2f58fd46cc4 100644 --- a/smithy-typescript-codegen/build.gradle.kts +++ b/smithy-typescript-codegen/build.gradle.kts @@ -13,6 +13,8 @@ * permissions and limitations under the License. */ +import software.amazon.smithy.model.node.Node + description = "Generates TypeScript code from Smithy models" extra["displayName"] = "Smithy :: Typescript :: Codegen" extra["moduleName"] = "software.amazon.smithy.typescript.codegen" @@ -37,3 +39,34 @@ dependencies { api("software.amazon.smithy:smithy-waiters:$smithyVersion") implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion") } + +sourceSets { + main { + resources { + setSrcDirs(listOf("src/main/resources", "$buildDir/generated/resources")) + } + } +} + +tasks.register("set-dependency-versions") { + doLast { + mkdir("$buildDir/generated/resources/software/amazon/smithy/typescript/codegen") + var versionsFile = + file("$buildDir/generated/resources/software/amazon/smithy/typescript/codegen/dependencyVersions.properties") + var roots = project.file("../packages").listFiles().toMutableList() + project.file("../smithy-typescript-ssdk-libs").listFiles().toList() + roots.forEach { packageDir -> + var packageJsonFile = File(packageDir, "package.json") + if (packageJsonFile.isFile()) { + var packageJson = Node.parse(packageJsonFile.readText()).expectObjectNode() + var packageName = packageJson.expectStringMember("name").getValue() + var packageVersion = packageJson.expectStringMember("version").getValue() + var isPrivate = packageJson.getBooleanMemberOrDefault("private", false) + if (!isPrivate) { + versionsFile.appendText("$packageName=$packageVersion\n") + } + } + } + } +} + +tasks["processResources"].dependsOn(tasks["set-dependency-versions"]) diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/TypeScriptDependency.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/TypeScriptDependency.java index 11878e5ed7e..4dd6b914076 100644 --- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/TypeScriptDependency.java +++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/TypeScriptDependency.java @@ -38,95 +38,96 @@ @SmithyUnstableApi public enum TypeScriptDependency implements Dependency { - AWS_SDK_CLIENT_DOCGEN("devDependencies", "@smithy/service-client-documentation-generator", "^2.0.0", true), + AWS_SDK_CLIENT_DOCGEN("devDependencies", "@smithy/service-client-documentation-generator", true), AWS_SDK_TYPES("dependencies", "@aws-sdk/types", true), - SMITHY_TYPES("dependencies", "@smithy/types", "^2.3.0", true), - AWS_SMITHY_CLIENT("dependencies", "@smithy/smithy-client", "^2.1.3", true), - INVALID_DEPENDENCY("dependencies", "@smithy/invalid-dependency", "^2.0.6", true), - CONFIG_RESOLVER("dependencies", "@smithy/config-resolver", "^2.0.7", true), + SMITHY_TYPES("dependencies", "@smithy/types", true), + AWS_SMITHY_CLIENT("dependencies", "@smithy/smithy-client", true), + INVALID_DEPENDENCY("dependencies", "@smithy/invalid-dependency", true), + CONFIG_RESOLVER("dependencies", "@smithy/config-resolver", true), TYPES_NODE("devDependencies", "@types/node", "^14.14.31", true), - MIDDLEWARE_CONTENT_LENGTH("dependencies", "@smithy/middleware-content-length", "^2.0.8", true), - MIDDLEWARE_SERDE("dependencies", "@smithy/middleware-serde", "^2.0.6", true), - MIDDLEWARE_RETRY("dependencies", "@smithy/middleware-retry", "^2.0.9", true), - UTIL_RETRY("dependencies", "@smithy/util-retry", "^2.0.0", false), - MIDDLEWARE_STACK("dependencies", "@smithy/middleware-stack", "^2.0.0", true), - MIDDLEWARE_ENDPOINTS_V2("dependencies", "@smithy/middleware-endpoint", "^2.0.6", false), + MIDDLEWARE_CONTENT_LENGTH("dependencies", "@smithy/middleware-content-length", true), + MIDDLEWARE_SERDE("dependencies", "@smithy/middleware-serde", true), + MIDDLEWARE_RETRY("dependencies", "@smithy/middleware-retry", true), + UTIL_RETRY("dependencies", "@smithy/util-retry", false), + MIDDLEWARE_STACK("dependencies", "@smithy/middleware-stack", true), + MIDDLEWARE_ENDPOINTS_V2("dependencies", "@smithy/middleware-endpoint", false), AWS_SDK_UTIL_ENDPOINTS("dependencies", "@aws-sdk/util-endpoints", false), AWS_CRYPTO_SHA256_BROWSER("dependencies", "@aws-crypto/sha256-browser", "3.0.0", true), AWS_CRYPTO_SHA256_JS("dependencies", "@aws-crypto/sha256-js", "3.0.0", true), - AWS_SDK_HASH_NODE("dependencies", "@smithy/hash-node", "^2.0.6", true), - AWS_SDK_URL_PARSER("dependencies", "@smithy/url-parser", "^2.0.6", true), + AWS_SDK_HASH_NODE("dependencies", "@smithy/hash-node", true), - @Deprecated AWS_SDK_UTIL_BASE64_BROWSER("dependencies", "@smithy/util-base64-browser", "^1.0.1", false), - @Deprecated AWS_SDK_UTIL_BASE64_NODE("dependencies", "@smithy/util-base64-node", "^1.0.1", false), - AWS_SDK_UTIL_BASE64("dependencies", "@smithy/util-base64", "^2.0.0", true), + AWS_SDK_URL_PARSER("dependencies", "@smithy/url-parser", true), - AWS_SDK_UTIL_BODY_LENGTH_BROWSER("dependencies", "@smithy/util-body-length-browser", "^2.0.0", true), - AWS_SDK_UTIL_BODY_LENGTH_NODE("dependencies", "@smithy/util-body-length-node", "^2.1.0", true), + @Deprecated AWS_SDK_UTIL_BASE64_BROWSER("dependencies", "@aws-sdk/util-base64-browser", false), + @Deprecated AWS_SDK_UTIL_BASE64_NODE("dependencies", "@aws-sdk/util-base64-node", false), + AWS_SDK_UTIL_BASE64("dependencies", "@smithy/util-base64", true), - AWS_SDK_UTIL_UTF8("dependencies", "@smithy/util-utf8", "^2.0.0", true), + AWS_SDK_UTIL_BODY_LENGTH_BROWSER("dependencies", "@smithy/util-body-length-browser", true), + AWS_SDK_UTIL_BODY_LENGTH_NODE("dependencies", "@smithy/util-body-length-node", true), - AWS_SDK_UTIL_WAITERS("dependencies", "@smithy/util-waiter", "^2.0.6", false), + AWS_SDK_UTIL_UTF8("dependencies", "@smithy/util-utf8", true), - AWS_SDK_UTIL_DEFAULTS_MODE_NODE("dependencies", "@smithy/util-defaults-mode-node", "^2.0.9", true), - AWS_SDK_UTIL_DEFAULTS_MODE_BROWSER("dependencies", "@smithy/util-defaults-mode-browser", "^2.0.7", true), + AWS_SDK_UTIL_WAITERS("dependencies", "@smithy/util-waiter", false), - NODE_CONFIG_PROVIDER("dependencies", "@smithy/node-config-provider", "^2.0.9", false), + AWS_SDK_UTIL_DEFAULTS_MODE_NODE("dependencies", "@smithy/util-defaults-mode-node", true), + AWS_SDK_UTIL_DEFAULTS_MODE_BROWSER("dependencies", "@smithy/util-defaults-mode-browser", true), + + NODE_CONFIG_PROVIDER("dependencies", "@smithy/node-config-provider", false), UUID("dependencies", "uuid", "^8.3.2", false), // Conditionally added when httpChecksumRequired trait exists - MD5_BROWSER("dependencies", "@smithy/md5-js", "^2.0.6", false), - STREAM_HASHER_NODE("dependencies", "@smithy/hash-stream-node", "^2.0.6", false), - STREAM_HASHER_BROWSER("dependencies", "@smithy/hash-blob-browser", "^2.0.6", false), - BODY_CHECKSUM("dependencies", "@smithy/middleware-apply-body-checksum", "^2.0.8", false), + MD5_BROWSER("dependencies", "@smithy/md5-js", false), + STREAM_HASHER_NODE("dependencies", "@smithy/hash-stream-node", false), + STREAM_HASHER_BROWSER("dependencies", "@smithy/hash-blob-browser", false), + BODY_CHECKSUM("dependencies", "@smithy/middleware-apply-body-checksum", false), // Conditionally added when using an HTTP application protocol. - PROTOCOL_HTTP("dependencies", "@smithy/protocol-http", "^3.0.2", false), - AWS_SDK_FETCH_HTTP_HANDLER("dependencies", "@smithy/fetch-http-handler", "^2.1.2", false), - AWS_SDK_NODE_HTTP_HANDLER("dependencies", "@smithy/node-http-handler", "^2.1.2", false), + PROTOCOL_HTTP("dependencies", "@smithy/protocol-http", false), + AWS_SDK_FETCH_HTTP_HANDLER("dependencies", "@smithy/fetch-http-handler", false), + AWS_SDK_NODE_HTTP_HANDLER("dependencies", "@smithy/node-http-handler", false), // Conditionally added when setting the auth middleware. - UTIL_MIDDLEWARE("dependencies", "@smithy/util-middleware", "^2.0.0", false), - @Deprecated AWS_SDK_UTIL_MIDDLEWARE("dependencies", "@smithy/util-middleware", "^2.0.0", false), + UTIL_MIDDLEWARE("dependencies", "@smithy/util-middleware", false), + @Deprecated AWS_SDK_UTIL_MIDDLEWARE("dependencies", "@smithy/util-middleware", false), // Conditionally added if a event stream shape is found anywhere in the model - AWS_SDK_EVENTSTREAM_SERDE_CONFIG_RESOLVER( - "dependencies", "@smithy/eventstream-serde-config-resolver", "^2.0.6", false), - AWS_SDK_EVENTSTREAM_SERDE_NODE("dependencies", "@smithy/eventstream-serde-node", "^2.0.6", false), - AWS_SDK_EVENTSTREAM_SERDE_BROWSER("dependencies", "@smithy/eventstream-serde-browser", "^2.0.6", false), + AWS_SDK_EVENTSTREAM_SERDE_CONFIG_RESOLVER("dependencies", "@smithy/eventstream-serde-config-resolver", + false), + AWS_SDK_EVENTSTREAM_SERDE_NODE("dependencies", "@smithy/eventstream-serde-node", false), + AWS_SDK_EVENTSTREAM_SERDE_BROWSER("dependencies", "@smithy/eventstream-serde-browser", false), // Conditionally added if a big decimal shape is found in a model. BIG_JS("dependencies", "big.js", "^6.0.0", false), TYPES_BIG_JS("devDependencies", "@types/big.js", "^6.0.0", false), // Conditionally added when interacting with specific protocol test bodyMediaType values. - AWS_SDK_QUERYSTRING_BUILDER("dependencies", "@smithy/querystring-builder", "^2.0.6", false), + AWS_SDK_QUERYSTRING_BUILDER("dependencies", "@smithy/querystring-builder", false), // Conditionally added when XML parser needs to be used. XML_PARSER("dependencies", "fast-xml-parser", "4.2.5", false), HTML_ENTITIES("dependencies", "entities", "2.2.0", false), // Conditionally added when streaming blob response payload exists. - @Deprecated UTIL_STREAM_NODE("dependencies", "@smithy/util-stream-node", "^2.0.8", false), - @Deprecated UTIL_STREAM_BROWSER("dependencies", "@smithy/util-stream-browser", "^2.0.8", false), - UTIL_STREAM("dependencies", "@smithy/util-stream", "^2.0.9", false), + @Deprecated UTIL_STREAM_NODE("dependencies", "@smithy/util-stream-node", false), + @Deprecated UTIL_STREAM_BROWSER("dependencies", "@smithy/util-stream-browser", false), + UTIL_STREAM("dependencies", "@smithy/util-stream", false), // Conditionally added when @aws.auth#sigv4 is used - SIGNATURE_V4("dependencies", "@smithy/signature-v4", "^2.0.6", false), + SIGNATURE_V4("dependencies", "@smithy/signature-v4", false), // feat(experimentalIdentityAndAuth): Conditionally added dependencies for `experimentalIdentityAndAuth`. // This package should never have a major version, and should only use minor and patch versions in development. - EXPERIMENTAL_IDENTITY_AND_AUTH("dependencies", "@smithy/experimental-identity-and-auth", "~0.0.4", false), + EXPERIMENTAL_IDENTITY_AND_AUTH("dependencies", "@smithy/experimental-identity-and-auth", false), // Conditionally added when specs have been generated. VITEST("devDependencies", "vitest", "^0.33.0", false), // Server dependency for SSDKs - SERVER_COMMON("dependencies", "@aws-smithy/server-common", "1.0.0-alpha.10", false); + SERVER_COMMON("dependencies", "@aws-smithy/server-common", false); public static final String NORMAL_DEPENDENCY = "dependencies"; public static final String DEV_DEPENDENCY = "devDependencies"; @@ -139,7 +140,25 @@ public enum TypeScriptDependency implements Dependency { public final SymbolDependency dependency; TypeScriptDependency(String type, String name, boolean unconditional) { - this(type, name, SdkVersion.getVersion(name), unconditional); + String version; + if (name.startsWith("@aws-sdk/")) { + version = SdkVersion.getVersion(name); + } else { + version = DependencyVersion.getVersion(name); + } + + if (name.startsWith("@smithy/")) { + version = "^" + version; + } + this.dependency = SymbolDependency.builder() + .dependencyType(type) + .packageName(name) + .version(version) + .putProperty("unconditional", unconditional) + .build(); + this.packageName = name; + this.version = version; + } TypeScriptDependency(String type, String name, String version, boolean unconditional) { @@ -244,4 +263,42 @@ private static String getVersion(String packageName) { return VERSIONS.getOrDefault(packageName, "latest"); } } + + /** + * Reads the version of smithy-typescript published libraries. + */ + private static final class DependencyVersion { + private static final Logger LOGGER = Logger.getLogger(DependencyVersion.class.getName()); + private static final Map VERSIONS; + + static { + Map tmpVersions; + try { + URL versionsUrl = DependencyVersion.class.getResource("dependencyVersions.properties"); + if (versionsUrl == null) { + throw new IOException(); + } + Properties p = new Properties(); + try (Reader r = + new BufferedReader(new InputStreamReader(versionsUrl.openStream(), StandardCharsets.UTF_8))) { + p.load(r); + } + final Map versions = new HashMap<>(p.size()); + p.forEach((k, v) -> { + if (versions.put(k.toString(), v.toString()) != null) { + throw new IllegalArgumentException(String.format("Multiple versions defined for %s", k)); + } + }); + tmpVersions = Collections.unmodifiableMap(versions); + } catch (IOException e) { + LOGGER.info("Could not read dependency versions from smithy-typescript-codegen"); + tmpVersions = Collections.emptyMap(); + } + VERSIONS = tmpVersions; + } + + private static String getVersion(String packageName) { + return VERSIONS.get(packageName); + } + } } diff --git a/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/TypeScriptDependencyTest.java b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/TypeScriptDependencyTest.java index d9e0efe0ba4..c1b23afe61d 100644 --- a/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/TypeScriptDependencyTest.java +++ b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/TypeScriptDependencyTest.java @@ -4,9 +4,14 @@ import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.startsWith; + +import java.util.List; import org.junit.jupiter.api.Test; import software.amazon.smithy.codegen.core.Symbol; +import software.amazon.smithy.codegen.core.SymbolDependency; public class TypeScriptDependencyTest { @Test @@ -23,4 +28,18 @@ public void getsUnconditionalDependencies() { assertThat(TypeScriptDependency.getUnconditionalDependencies(), hasItem(TypeScriptDependency.AWS_SDK_CLIENT_DOCGEN.dependency)); } + + @Test + public void getsVendedDependencyVersions() { + List smithyTypes = TypeScriptDependency.SMITHY_TYPES.getDependencies(); + List serverCommon = TypeScriptDependency.SERVER_COMMON.getDependencies(); + + assertThat(smithyTypes.size(), equalTo(1)); + assertThat(smithyTypes.get(0).getVersion(), startsWith("^")); + assertThat(smithyTypes.get(0).getPackageName(), equalTo("@smithy/types")); + + assertThat(serverCommon.size(), equalTo(1)); + assertThat(serverCommon.get(0).getVersion(), not(startsWith("^"))); + assertThat(serverCommon.get(0).getPackageName(), equalTo("@aws-smithy/server-common")); + } }