From f0f99b436245e389034764c06c0fb1086e0ff762 Mon Sep 17 00:00:00 2001 From: Julia Plewa <34098778+jplewa@users.noreply.github.com> Date: Wed, 26 Jul 2023 11:17:04 +0200 Subject: [PATCH] Add provider name to provider resource (#241) ## Task Resolves: #228 ## Description Disclaimer: for providers with complex names (such as `aws-native`), the names have the following format: `AzurenativeProviderResource`. I'll try to figure out if there's an easy way to make the name `AzureNativeProviderResource` instead, but the easiest way was to ignore the capitalization of complex names. ### TODO - [x] ~~Add tests~~ Fix existing tests - [x] If the current solution is determined to be not good enough, figure out a way to capitalize complex names --- .../src/main/kotlin/project/Main.kt | 8 +- .../IntermediateRepresentationGenerator.kt | 28 ++- .../codegen/step2intermediate/PulumiName.kt | 75 ++++-- .../org/virtuslab/pulumikotlin/TestUtils.kt | 17 +- .../pulumikotlin/codegen/CodegenTest.kt | 194 ++++++++++----- .../step2intermediate/PulumiNameTest.kt | 231 ++++++++++++++++-- .../CodeGeneratorGenerateTypesTest.kt | 4 +- .../step3codegen/TypeNameClashResolverTest.kt | 2 +- .../scripts/ComputeSchemaSubsetScriptTest.kt | 4 +- ...aws-classic-5.15.0-subset-with-index.json} | 0 ...ve-1.104.0-subset-with-ip-allocation.json} | 0 ...native-1.104.0-subset-with-recursion.json} | 0 ...-equinix-metal-3.3.0-alpha-with-index.json | 223 +++++++++++++++++ ...cp-classic-6.39.0-subset-lb-ip-ranges.json | 136 +++++------ 14 files changed, 730 insertions(+), 192 deletions(-) rename src/test/resources/{schema-aws-classic-5.15.2-subset-with-index.json => schema-aws-classic-5.15.0-subset-with-index.json} (100%) rename src/test/resources/{schema-azure-native-3.44.2-subset-with-ip-allocation.json => schema-azure-native-1.104.0-subset-with-ip-allocation.json} (100%) rename src/test/resources/{schema-azure-native-3.44.2-subset-with-recursion.json => schema-azure-native-1.104.0-subset-with-recursion.json} (100%) create mode 100644 src/test/resources/schema-equinix-metal-3.3.0-alpha-with-index.json diff --git a/examples/gcp-provider-sample-project/src/main/kotlin/project/Main.kt b/examples/gcp-provider-sample-project/src/main/kotlin/project/Main.kt index ec4aa6ed..1a381522 100644 --- a/examples/gcp-provider-sample-project/src/main/kotlin/project/Main.kt +++ b/examples/gcp-provider-sample-project/src/main/kotlin/project/Main.kt @@ -2,8 +2,8 @@ package project import com.pulumi.core.Output import com.pulumi.gcp.compute.kotlin.instance -import com.pulumi.gcp.kotlin.Provider -import com.pulumi.gcp.kotlin.provider +import com.pulumi.gcp.kotlin.GcpProvider +import com.pulumi.gcp.kotlin.gcpProvider import com.pulumi.kotlin.Pulumi private val commonTags = listOf("gcp-provider-sample-project", "foo", "bar") @@ -51,7 +51,7 @@ fun main() { } private suspend fun createProvider(resourceName: String, projectName: String, region: String, zone: String) = - provider(resourceName) { + gcpProvider(resourceName) { args { project(projectName) region(region) @@ -59,7 +59,7 @@ private suspend fun createProvider(resourceName: String, projectName: String, re } } -private suspend fun createInstanceWithProvider(resourceName: String, provider: Provider, tags: List) = +private suspend fun createInstanceWithProvider(resourceName: String, provider: GcpProvider, tags: List) = instance(resourceName) { args { machineType("e2-micro") diff --git a/src/main/kotlin/org/virtuslab/pulumikotlin/codegen/step2intermediate/IntermediateRepresentationGenerator.kt b/src/main/kotlin/org/virtuslab/pulumikotlin/codegen/step2intermediate/IntermediateRepresentationGenerator.kt index ae7fa267..6d0bff0d 100644 --- a/src/main/kotlin/org/virtuslab/pulumikotlin/codegen/step2intermediate/IntermediateRepresentationGenerator.kt +++ b/src/main/kotlin/org/virtuslab/pulumikotlin/codegen/step2intermediate/IntermediateRepresentationGenerator.kt @@ -61,7 +61,8 @@ object IntermediateRepresentationGenerator { createResource(DEFAULT_PROVIDER_TOKEN, schema.provider, context, typeMap, isProvider = true) } else { createResources(typeMap, context) - }.filterNotNull() + } + .filterNotNull() return IntermediateRepresentation( types = types, @@ -76,12 +77,13 @@ object IntermediateRepresentationGenerator { fun createTypes( map: Map, usageKind: UsageKind? = null, + isProvider: Boolean = false, propertyExtractor: (V) -> RootTypeProperty?, ) = map .mapValues { propertyExtractor(it.value) } .filterNotNullValues() .flatMap { (name, value) -> - createRootTypes(context, name, value, listOfNotNull(usageKind)) + createRootTypes(context, name, value, listOfNotNull(usageKind), isProvider) } val syntheticTypes = listOf( @@ -98,6 +100,7 @@ object IntermediateRepresentationGenerator { createTypes( mapOf(DEFAULT_PROVIDER_TOKEN to schema.provider), UsageKind(Root, Resource, Input), + isProvider = true, ) { resource -> ObjectProperty( properties = resource.inputProperties, @@ -105,7 +108,8 @@ object IntermediateRepresentationGenerator { deprecationMessage = resource.deprecationMessage, ) } - }.orEmpty(), + } + .orEmpty(), ) val regularTypes = listOf( @@ -117,7 +121,7 @@ object IntermediateRepresentationGenerator { private fun createResources(types: Map, context: Context): List { return context.schema.resources.mapNotNull { (typeToken, resource) -> - createResource(typeToken, resource, context, types) + createResource(typeToken, resource, context, types, isProvider = false) } } @@ -126,7 +130,7 @@ object IntermediateRepresentationGenerator { resource: SchemaModel.Resource, context: Context, types: Map, - isProvider: Boolean = false, + isProvider: Boolean, ): ResourceType? { val resultFields = resource.properties .letIf(isProvider, ::filterStringProperties) @@ -143,7 +147,7 @@ object IntermediateRepresentationGenerator { } return try { - val pulumiName = PulumiName.from(typeToken, context.namingConfiguration) + val pulumiName = PulumiName.from(typeToken, context.namingConfiguration, isProvider = isProvider) val inputUsageKind = UsageKind(Root, Resource, Input) val argumentType = findTypeAsReference( @@ -160,7 +164,7 @@ object IntermediateRepresentationGenerator { private fun createFunctions(types: Map, context: Context): List { return context.schema.functions.mapNotNull { (typeName, function) -> try { - val pulumiName = PulumiName.from(typeName, context.namingConfiguration) + val pulumiName = PulumiName.from(typeName, context.namingConfiguration, isProvider = false) val inputUsageKind = UsageKind(Root, Function, Input) val argumentType = findTypeOrEmptyComplexType( @@ -201,6 +205,7 @@ object IntermediateRepresentationGenerator { typeName: String, rootType: RootTypeProperty, forcedUsageKinds: List = emptyList(), + isProvider: Boolean, ): List { val usages = forcedUsageKinds.ifEmpty { val allUsagesForTypeName = context.referenceFinder.getUsages(typeName) @@ -214,7 +219,7 @@ object IntermediateRepresentationGenerator { } try { - val pulumiName = PulumiName.from(typeName, context.namingConfiguration) + val pulumiName = PulumiName.from(typeName, context.namingConfiguration, isProvider) return usages.map { usage -> when (rootType) { is ObjectProperty -> ComplexType( @@ -302,7 +307,7 @@ object IntermediateRepresentationGenerator { } else if (context.referencedStringTypesResolver.shouldGenerateStringType(referencedTypeName)) { StringType } else { - val pulumiName = PulumiName.from(referencedTypeName, context.namingConfiguration) + val pulumiName = PulumiName.from(referencedTypeName, context.namingConfiguration, isProvider = false) when (context.referenceFinder.resolve(referencedTypeName)) { is ObjectProperty -> ReferencedComplexType( TypeMetadata(pulumiName, usageKind, getKDoc(property)), @@ -396,8 +401,11 @@ object IntermediateRepresentationGenerator { name = with(name) { PulumiName( providerName.lowercase(), - namespace.map { it.lowercase() }, + providerNameOverride?.lowercase(), + baseNamespace.map { it.lowercase() }, + moduleName?.lowercase(), name.lowercase(), + isProvider = isProvider, ) }, ) diff --git a/src/main/kotlin/org/virtuslab/pulumikotlin/codegen/step2intermediate/PulumiName.kt b/src/main/kotlin/org/virtuslab/pulumikotlin/codegen/step2intermediate/PulumiName.kt index 1dadf1be..f7ab4bf1 100644 --- a/src/main/kotlin/org/virtuslab/pulumikotlin/codegen/step2intermediate/PulumiName.kt +++ b/src/main/kotlin/org/virtuslab/pulumikotlin/codegen/step2intermediate/PulumiName.kt @@ -16,9 +16,21 @@ import org.virtuslab.pulumikotlin.codegen.utils.decapitalize data class PulumiName( val providerName: String, - val namespace: List, + val providerNameOverride: String?, + val baseNamespace: List, + val moduleName: String?, val name: String, + val isProvider: Boolean, ) { + val namespace: List + get() { + val effectiveProviderName = (providerNameOverride ?: providerName) + val namespaceSections = baseNamespace + effectiveProviderName + moduleName + return namespaceSections + .filterNotNull() + .filter { it.isNotBlank() } + .map { it.replace("-", "") } + } private data class Modifiers( val nameSuffix: String, @@ -175,19 +187,19 @@ data class PulumiName( } fun toFunctionGroupObjectName(namingFlags: NamingFlags): String { - return when (namingFlags.language) { - Kotlin, Java -> { - if (namespace.isEmpty()) { - providerName.capitalize() + "Functions" - } else { - namespace.last().replace(".", "_").capitalize() + "Functions" - } - } + return if (moduleName != null) { + moduleName.replace(".", "_").capitalize() + "Functions" + } else { + getProviderPrefix(namingFlags.language).replace(".", "_").capitalize() + "Functions" } } fun toResourceName(namingFlags: NamingFlags): String { - return name.capitalize() + return if (namingFlags.language == Kotlin && isProvider) { + "${getProviderPrefix(namingFlags.language)}${name.capitalize()}" + } else { + name.capitalize() + } } fun toClassName(namingFlags: NamingFlags): String { @@ -212,6 +224,14 @@ data class PulumiName( } } + private fun getProviderPrefix(languageType: LanguageType): String { + val splitProviderName = providerName.split("-") + return when (languageType) { + Kotlin -> splitProviderName.joinToString("") { it.capitalize() } + Java -> splitProviderName.joinToString("").capitalize() + } + } + private fun packageToString(packageList: List): String { return packageList.joinToString(".") } @@ -248,44 +268,57 @@ data class PulumiName( companion object { private const val EXPECTED_NUMBER_OF_SEGMENTS_IN_TOKEN = 3 - fun from(token: String, namingConfiguration: PulumiNamingConfiguration): PulumiName { + fun from( + token: String, + namingConfiguration: PulumiNamingConfiguration, + isProvider: Boolean = false, + ): PulumiName { // token = pkg ":" module ":" member val segments = token.split(":") require(segments.size == EXPECTED_NUMBER_OF_SEGMENTS_IN_TOKEN) { "Malformed token $token" } - fun substituteWithOverride(name: String) = namingConfiguration.packageOverrides[name] ?: name + fun substituteWithOverride(name: String) = namingConfiguration.packageOverrides[name] val module = when (segments[1]) { - "providers" -> "" + "providers" -> null else -> { val moduleMatches = namingConfiguration.moduleFormatRegex.matchEntire(segments[1]) ?.groupValues .orEmpty() if (moduleMatches.size < 2 || moduleMatches[1].startsWith("index")) { - "" + null } else { moduleMatches[1] } } } - val providerName = substituteWithOverride(namingConfiguration.providerName) - val moduleName = substituteWithOverride(module) - - val namespace = (namingConfiguration.baseNamespace + providerName + moduleName) - .filter { it.isNotBlank() } - .map { it.replace("-", "") } + val providerNameOverride = substituteWithOverride(namingConfiguration.providerName) + val moduleName = module?.let { substituteWithOverride(it) } ?: module val name = segments[2] if (name.contains("/")) { + val namespace = ( + namingConfiguration.baseNamespace + + (providerNameOverride ?: namingConfiguration.providerName) + + moduleName + ) + .filterNotNull() throw InvalidPulumiName(name, namespace) } - return PulumiName(providerName, namespace, name) + return PulumiName( + namingConfiguration.providerName, + providerNameOverride, + namingConfiguration.baseNamespace, + moduleName, + name, + isProvider, + ) } } } diff --git a/src/test/kotlin/org/virtuslab/pulumikotlin/TestUtils.kt b/src/test/kotlin/org/virtuslab/pulumikotlin/TestUtils.kt index 96a9fbc8..ca1088bd 100644 --- a/src/test/kotlin/org/virtuslab/pulumikotlin/TestUtils.kt +++ b/src/test/kotlin/org/virtuslab/pulumikotlin/TestUtils.kt @@ -15,14 +15,15 @@ internal fun extractOutputValue(output: Output?): T? { return value } -internal fun concat(iterableOfIterables: Iterable>?): List = - iterableOfIterables?.flatten().orEmpty() - -internal fun concat(vararg iterables: Iterable?): List = - concat(iterables.filterNotNull().asIterable()) - -internal fun namingConfigurationWithSlashInModuleFormat(providerName: String) = - PulumiNamingConfiguration.create(providerName = providerName, moduleFormat = "(.*)(?:/[^/]*)") +internal fun namingConfigurationWithSlashInModuleFormat( + providerName: String, + packageOverrides: Map = emptyMap(), +) = + PulumiNamingConfiguration.create( + providerName = providerName, + moduleFormat = "(.*)(?:/[^/]*)", + packageOverrides = packageOverrides, + ) private fun messagePrefix(message: String?) = if (message == null) "" else "$message. " diff --git a/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/CodegenTest.kt b/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/CodegenTest.kt index 77c6cecc..cb163c2c 100644 --- a/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/CodegenTest.kt +++ b/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/CodegenTest.kt @@ -25,14 +25,6 @@ class CodegenTest { private val dependencies = listOf( "com.pulumi:pulumi:0.9.4", - "com.pulumi:aws:5.16.2", - "com.pulumi:gcp:6.38.0", - "com.pulumi:slack:0.3.0", - "com.pulumi:github:4.17.0", - "com.pulumi:google-native:0.27.0", - "com.pulumi:kubernetes:3.22.1", - "com.pulumi:azure-native:1.85.0", - "com.pulumi:google-native:0.27.0", "com.google.code.findbugs:jsr305:3.0.2", "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.2", "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.2", @@ -247,8 +239,8 @@ class CodegenTest { fun `aws provider resource can be created`() { // language=kotlin val code = """ + import com.pulumi.aws.kotlin.awsProvider import com.pulumi.aws.acm.kotlin.certificate - import com.pulumi.aws.kotlin.provider suspend fun main() { certificate("name") { @@ -260,7 +252,7 @@ class CodegenTest { } opts { provider( - provider("custom-aws-provider") { + awsProvider("custom-aws-provider") { args { accessKey("123") assumeRoleWithWebIdentity { @@ -404,6 +396,22 @@ class CodegenTest { assertGeneratedCodeAndSourceFileCompile(SCHEMA_AWS_CLASSIC_SUBSET_WITH_INDEX, code) } + @Test + fun `equinix-metal functions from index namespace can be invoked`() { + // language=kotlin + val code = """ + import com.pulumi.equinixmetal.kotlin.EquinixMetalFunctions + + suspend fun main() { + EquinixMetalFunctions.getVolume { + name("volume") + } + } + """ + + assertGeneratedCodeAndSourceFileCompile(SCHEMA_EQUINIX_METAL_WITH_INDEX, code) + } + @Test fun `slack resources from index namespace can be created`() { // language=kotlin @@ -783,21 +791,24 @@ class CodegenTest { assertGeneratedCodeAndSourceFileCompile(SCHEMA_GOOGLE_CLASSIC_SUBSET_WITH_INSTANCE, code) } - private fun assertGeneratedCodeCompiles(schemaPath: String) { - assertGeneratedCodeAndSourceFilesCompile(schemaPath, emptyMap()) + private fun assertGeneratedCodeCompiles(testSchema: TestSchema) { + assertGeneratedCodeAndSourceFilesCompile(testSchema, emptyMap()) } - private fun assertGeneratedCodeAndSourceFileCompile(schemaPath: String, sourceFile: String) { - assertGeneratedCodeAndSourceFilesCompile(schemaPath, mapOf("Main.kt" to sourceFile)) + private fun assertGeneratedCodeAndSourceFileCompile(testSchema: TestSchema, sourceFile: String) { + assertGeneratedCodeAndSourceFilesCompile(testSchema, mapOf("Main.kt" to sourceFile)) } - private fun assertGeneratedCodeAndSourceFileDoNotCompile(schemaPath: String, sourceFile: String) { - assertGeneratedCodeAndSourceFilesDoNotCompile(schemaPath, mapOf("Main.kt" to sourceFile)) + private fun assertGeneratedCodeAndSourceFileDoNotCompile(testSchema: TestSchema, sourceFile: String) { + assertGeneratedCodeAndSourceFilesDoNotCompile(testSchema, mapOf("Main.kt" to sourceFile)) } - private fun assertGeneratedCodeAndSourceFilesDoNotCompile(schemaPath: String, sourceFiles: Map) { + private fun assertGeneratedCodeAndSourceFilesDoNotCompile( + testSchema: TestSchema, + sourceFiles: Map, + ) { val compilationResult = - generateCodeAndCompileAsSeparateModules(schemaPath, sourceFiles, ejectIfStatusIsNot = COMPILATION_ERROR) + generateCodeAndCompileAsSeparateModules(testSchema, sourceFiles, ejectIfStatusIsNot = COMPILATION_ERROR) if (compilationResult.exitCode == COMPILATION_ERROR) { logger.info("Code did not compile (as expected). Encountered problems:\n${compilationResult.messages}") @@ -809,9 +820,9 @@ class CodegenTest { ) } - private fun assertGeneratedCodeAndSourceFilesCompile(schemaPath: String, sourceFiles: Map) { + private fun assertGeneratedCodeAndSourceFilesCompile(testSchema: TestSchema, sourceFiles: Map) { val compilationResult = - generateCodeAndCompileAsSeparateModules(schemaPath, sourceFiles, ejectIfStatusIsNot = OK) + generateCodeAndCompileAsSeparateModules(testSchema, sourceFiles, ejectIfStatusIsNot = OK) assertEquals( OK, @@ -858,18 +869,18 @@ class CodegenTest { * */ private fun generateCodeAndCompileAsSeparateModules( - schemaPath: String, + testSchema: TestSchema, sourceFiles: Map, ejectIfStatusIsNot: KotlinCompilation.ExitCode = COMPILATION_ERROR, ): AggregateCompilationResult { - val outputDirectory = Codegen.codegen(loadResource("/$schemaPath")) + val outputDirectory = Codegen.codegen(loadResource("/${testSchema.path}")) val generatedSourceFiles = readFilesRecursively(outputDirectory) .map { (fileName, contents) -> SourceFile.kotlin(fileName, contents) } val additionalSourceFiles = sourceFiles .map { (fileName, source) -> SourceFile.new(fileName, source.trimIndent()) } - val classPathWithDependencies = dependencies.map { downloadedDependency(it) } + val classPathWithDependencies = (dependencies + testSchema.dependency).map { downloadedDependency(it) } val compilationForGeneratedCode = KotlinCompilation().apply { sources = generatedSourceFiles @@ -930,38 +941,105 @@ class CodegenTest { } } -private const val SCHEMA_GCP_CLASSIC_SUBSET_MEDIUM_SIZE = "schema-gcp-classic-subset-medium-size.json" -private const val SCHEMA_GCP_CLASSIC_SUBSET_LB_IP_RANGES = "schema-gcp-classic-6.39.0-subset-lb-ip-ranges.json" -private const val SCHEMA_AWS_CLASSIC_SUBSET_SMALL_SIZE = "schema-aws-classic-subset-small-size.json" -private const val SCHEMA_AWS_CLASSIC_SUBSET_BIG_SIZE = "schema-aws-classic-subset-big-size.json" -private const val SCHEMA_AWS_CLASSIC_SUBSET_WITH_ONE_OF = "schema-aws-classic-5.15.0-subset-with-one-of.json" -private const val SCHEMA_AWS_CLASSIC_SUBSET_WITH_ARCHIVE = "schema-aws-classic-5.16.2-subset-with-archive.json" -private const val SCHEMA_AWS_CLASSIC_SUBSET_WITH_ASSET = "schema-aws-classic-5.16.2-subset-with-asset.json" -private const val SCHEMA_AWS_CLASSIC_SUBSET_WITH_INDEX = "schema-aws-classic-5.15.2-subset-with-index.json" -private const val SCHEMA_AWS_CLASSIC_SUBSET_WITH_PROVIDER_AND_CERTIFICATE = - "schema-aws-classic-5.16.2-subset-with-certificate-and-provider.json" -private const val SCHEMA_SLACK_SUBSET_WITH_INDEX = "schema-slack-0.3.0-subset-with-index.json" -private const val SCHEMA_AZURE_NATIVE_SUBSET_WITH_IP_ALLOCATION = - "schema-azure-native-3.44.2-subset-with-ip-allocation.json" -private const val SCHEMA_GITHUB_SUBSET_WITH_NAME_COLLISION = "schema-github-4.17.0-subset-with-name-collision.json" -private const val SCHEMA_GOOGLE_NATIVE_SUBSET_WITH_INVALID_NAME = - "schema-google-native-0.27.0-subset-with-invalid-name.json" -private const val SCHEMA_GOOGLE_NATIVE_SUBSET_WITH_KEYWORD_TYPE_PROPERTY = - "schema-google-native-0.27.0-subset-with-keyword-type-property.json" -private const val SCHEMA_GOOGLE_NATIVE_SUBSET_NAMESPACE_WITH_SLASH = - "schema-google-native-0.27.0-subset-namespace-with-slash.json" -private const val SCHEMA_GOOGLE_NATIVE_SUBSET_TYPE_WITH_NO_PROPERTIES = - "schema-google-native-0.27.0-subset-type-with-no-properties.json" -private const val SCHEMA_KUBERNETES_SUBSET_WITH_JSON = "schema-kubernetes-3.22.1-subset-with-json.json" -private const val SCHEMA_KUBERNETES_SUBSET_WITH_IS_OVERLAY = "schema-kubernetes-3.22.1-subset-with-is-overlay.json" -private const val SCHEMA_KUBERNETES_SUBSET_WITH_DOLLAR_IN_PROPERTY_NAME = - "schema-kubernetes-3.22.1-subset-with-dollar-in-property-name.json" -private const val SCHEMA_KUBERNETES_SUBSET_WITH_JAVA_KEYWORD_IN_PROPERTY_NAME = - "schema-kubernetes-3.22.1-subset-with-java-keyword-in-property-name.json" -private const val SCHEMA_KUBERNETES_SUBSET_WITH_KOTLIN_KEYWORD_IN_PROPERTY_NAME = - "schema-kubernetes-3.22.1-subset-with-kotlin-keyword-in-property-name.json" -private const val SCHEMA_AZURE_NATIVE_SUBSET_WITH_LOWERCASE_RESOURCE = - "schema-azure-native-1.85.0-subset-with-lowercase-resource.json" -private const val SCHEMA_GOOGLE_NATIVE_SUBSET_WITH_OUTPUT_LIST = - "schema-google-native-0.27.0-subset-with-output-list.json" -private const val SCHEMA_GOOGLE_CLASSIC_SUBSET_WITH_INSTANCE = "schema-gcp-classic-6.39.0-subset-with-instance.json" +data class TestSchema(val path: String, val dependency: String) + +private val SCHEMA_GCP_CLASSIC_SUBSET_MEDIUM_SIZE = TestSchema( + "schema-gcp-classic-subset-medium-size.json", + "com.pulumi:gcp:6.38.0", // unsure which version this was generated from +) +private val SCHEMA_GCP_CLASSIC_SUBSET_LB_IP_RANGES = TestSchema( + "schema-gcp-classic-6.39.0-subset-lb-ip-ranges.json", + "com.pulumi:gcp:6.39.0", +) +private val SCHEMA_AWS_CLASSIC_SUBSET_SMALL_SIZE = TestSchema( + "schema-aws-classic-subset-small-size.json", + "com.pulumi:aws:5.16.2", // unsure which version this was generated from +) +private val SCHEMA_AWS_CLASSIC_SUBSET_BIG_SIZE = TestSchema( + "schema-aws-classic-subset-big-size.json", + "com.pulumi:aws:5.16.2", // unsure which version this was generated from +) +private val SCHEMA_AWS_CLASSIC_SUBSET_WITH_ONE_OF = TestSchema( + "schema-aws-classic-5.15.0-subset-with-one-of.json", + "com.pulumi:aws:5.15.0", +) +private val SCHEMA_AWS_CLASSIC_SUBSET_WITH_ARCHIVE = TestSchema( + "schema-aws-classic-5.16.2-subset-with-archive.json", + "com.pulumi:aws:5.16.2", +) +private val SCHEMA_AWS_CLASSIC_SUBSET_WITH_ASSET = TestSchema( + "schema-aws-classic-5.16.2-subset-with-asset.json", + "com.pulumi:aws:5.16.2", +) +private val SCHEMA_AWS_CLASSIC_SUBSET_WITH_INDEX = TestSchema( + "schema-aws-classic-5.15.0-subset-with-index.json", + "com.pulumi:aws:5.15.0", +) +private val SCHEMA_AWS_CLASSIC_SUBSET_WITH_PROVIDER_AND_CERTIFICATE = TestSchema( + "schema-aws-classic-5.16.2-subset-with-certificate-and-provider.json", + "com.pulumi:aws:5.16.2", +) +private val SCHEMA_SLACK_SUBSET_WITH_INDEX = TestSchema( + "schema-slack-0.3.0-subset-with-index.json", + "com.pulumi:slack:0.3.0", +) +private val SCHEMA_AZURE_NATIVE_SUBSET_WITH_IP_ALLOCATION = TestSchema( + "schema-azure-native-1.104.0-subset-with-ip-allocation.json", + "com.pulumi:azure-native:1.104.0", +) +private val SCHEMA_GITHUB_SUBSET_WITH_NAME_COLLISION = TestSchema( + "schema-github-4.17.0-subset-with-name-collision.json", + "com.pulumi:github:4.17.0", +) +private val SCHEMA_GOOGLE_NATIVE_SUBSET_WITH_INVALID_NAME = TestSchema( + "schema-google-native-0.27.0-subset-with-invalid-name.json", + "com.pulumi:google-native:0.27.0", +) +private val SCHEMA_GOOGLE_NATIVE_SUBSET_WITH_KEYWORD_TYPE_PROPERTY = TestSchema( + "schema-google-native-0.27.0-subset-with-keyword-type-property.json", + "com.pulumi:google-native:0.27.0", +) +private val SCHEMA_GOOGLE_NATIVE_SUBSET_NAMESPACE_WITH_SLASH = TestSchema( + "schema-google-native-0.27.0-subset-namespace-with-slash.json", + "com.pulumi:google-native:0.27.0", +) +private val SCHEMA_GOOGLE_NATIVE_SUBSET_TYPE_WITH_NO_PROPERTIES = TestSchema( + "schema-google-native-0.27.0-subset-type-with-no-properties.json", + "com.pulumi:google-native:0.27.0", +) +private val SCHEMA_KUBERNETES_SUBSET_WITH_JSON = TestSchema( + "schema-kubernetes-3.22.1-subset-with-json.json", + "com.pulumi:kubernetes:3.22.1", +) +private val SCHEMA_KUBERNETES_SUBSET_WITH_IS_OVERLAY = TestSchema( + "schema-kubernetes-3.22.1-subset-with-is-overlay.json", + "com.pulumi:kubernetes:3.22.1", +) +private val SCHEMA_KUBERNETES_SUBSET_WITH_DOLLAR_IN_PROPERTY_NAME = TestSchema( + "schema-kubernetes-3.22.1-subset-with-dollar-in-property-name.json", + "com.pulumi:kubernetes:3.22.1", +) +private val SCHEMA_KUBERNETES_SUBSET_WITH_JAVA_KEYWORD_IN_PROPERTY_NAME = TestSchema( + "schema-kubernetes-3.22.1-subset-with-java-keyword-in-property-name.json", + "com.pulumi:kubernetes:3.22.1", +) +private val SCHEMA_KUBERNETES_SUBSET_WITH_KOTLIN_KEYWORD_IN_PROPERTY_NAME = TestSchema( + "schema-kubernetes-3.22.1-subset-with-kotlin-keyword-in-property-name.json", + "com.pulumi:kubernetes:3.22.1", +) +private val SCHEMA_AZURE_NATIVE_SUBSET_WITH_LOWERCASE_RESOURCE = TestSchema( + "schema-azure-native-1.85.0-subset-with-lowercase-resource.json", + "com.pulumi:azure-native:1.85.0", +) +private val SCHEMA_GOOGLE_NATIVE_SUBSET_WITH_OUTPUT_LIST = TestSchema( + "schema-google-native-0.27.0-subset-with-output-list.json", + "com.pulumi:google-native:0.27.0", +) +private val SCHEMA_GOOGLE_CLASSIC_SUBSET_WITH_INSTANCE = TestSchema( + "schema-gcp-classic-6.39.0-subset-with-instance.json", + "com.pulumi:gcp:6.39.0", +) +private val SCHEMA_EQUINIX_METAL_WITH_INDEX = TestSchema( + "schema-equinix-metal-3.3.0-alpha-with-index.json", + "com.pulumi:equinix-metal:3.3.0-alpha.1687671105+a2a938cd", +) diff --git a/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/step2intermediate/PulumiNameTest.kt b/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/step2intermediate/PulumiNameTest.kt index 37cf4461..60ee69d5 100644 --- a/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/step2intermediate/PulumiNameTest.kt +++ b/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/step2intermediate/PulumiNameTest.kt @@ -14,6 +14,7 @@ import org.virtuslab.pulumikotlin.codegen.step2intermediate.LanguageType.Java import org.virtuslab.pulumikotlin.codegen.step2intermediate.LanguageType.Kotlin import org.virtuslab.pulumikotlin.codegen.step2intermediate.Subject.Function import org.virtuslab.pulumikotlin.codegen.step2intermediate.Subject.Resource +import org.virtuslab.pulumikotlin.codegen.utils.DEFAULT_PROVIDER_TOKEN import org.virtuslab.pulumikotlin.namingConfigurationWithSlashInModuleFormat internal class PulumiNameTest { @@ -27,25 +28,28 @@ internal class PulumiNameTest { TypeName( "aws:acm/CertificateOptions:CertificateOptions", namingConfigurationWithSlashInModuleFormat("aws"), - PulumiName("aws", listOf("com", "pulumi", "aws", "acm"), "CertificateOptions"), + PulumiName("aws", null, listOf("com", "pulumi"), "acm", "CertificateOptions", false), ), ResourceName( "aws:acm/certificate:Certificate", namingConfigurationWithSlashInModuleFormat("aws"), - PulumiName("aws", listOf("com", "pulumi", "aws", "acm"), "Certificate"), + PulumiName("aws", null, listOf("com", "pulumi"), "acm", "Certificate", false), ), FunctionName( "aws:acmpca/getCertificateAuthority:getCertificateAuthority", namingConfigurationWithSlashInModuleFormat("aws"), - PulumiName("aws", listOf("com", "pulumi", "aws", "acmpca"), "getCertificateAuthority"), + PulumiName("aws", null, listOf("com", "pulumi"), "acmpca", "getCertificateAuthority", false), ), LongFunctionName( "aws:acmpca/getCertificateAuthorityRevocationConfigurationCrlConfiguration:getCertificateAuthorityRevocationConfigurationCrlConfiguration", namingConfigurationWithSlashInModuleFormat("aws"), PulumiName( "aws", - listOf("com", "pulumi", "aws", "acmpca"), + null, + listOf("com", "pulumi"), + "acmpca", "getCertificateAuthorityRevocationConfigurationCrlConfiguration", + false, ), ), } @@ -65,43 +69,43 @@ internal class PulumiNameTest { val expectedPackageWithModifiers: String, ) { KotlinResourceInput( - PulumiName("aws", listOf("com", "pulumi", "aws", "acm"), "CertificateOptions"), + PulumiName("aws", null, listOf("com", "pulumi"), "acm", "CertificateOptions", false), NamingFlags(Nested, Resource, Input, Kotlin, GeneratedClass.EnumClass), "com.pulumi.aws.acm.kotlin.enums", ), KotlinResourceOutput( - PulumiName("aws", listOf("com", "pulumi", "aws", "acm"), "CertificateOptions"), + PulumiName("aws", null, listOf("com", "pulumi"), "acm", "CertificateOptions", false), NamingFlags(Nested, Resource, Output, Kotlin, GeneratedClass.EnumClass), "com.pulumi.aws.acm.kotlin.enums", ), KotlinFunctionInput( - PulumiName("aws", listOf("com", "pulumi", "aws", "acm"), "CertificateOptions"), + PulumiName("aws", null, listOf("com", "pulumi"), "acm", "CertificateOptions", false), NamingFlags(Nested, Function, Input, Kotlin, GeneratedClass.EnumClass), "com.pulumi.aws.acm.kotlin.enums", ), KotlinFunctionOutput( - PulumiName("aws", listOf("com", "pulumi", "aws", "acm"), "CertificateOptions"), + PulumiName("aws", null, listOf("com", "pulumi"), "acm", "CertificateOptions", false), NamingFlags(Nested, Function, Output, Kotlin, GeneratedClass.EnumClass), "com.pulumi.aws.acm.kotlin.enums", ), JavaResourceInput( - PulumiName("aws", listOf("com", "pulumi", "aws", "acm"), "CertificateOptions"), + PulumiName("aws", null, listOf("com", "pulumi"), "acm", "CertificateOptions", false), NamingFlags(Nested, Resource, Input, Java, GeneratedClass.EnumClass), "com.pulumi.aws.acm.enums", ), JavaResourceOutput( - PulumiName("aws", listOf("com", "pulumi", "aws", "acm"), "CertificateOptions"), + PulumiName("aws", null, listOf("com", "pulumi"), "acm", "CertificateOptions", false), NamingFlags(Nested, Resource, Output, Java, GeneratedClass.EnumClass), "com.pulumi.aws.acm.enums", ), JavaFunctionInput( - PulumiName("aws", listOf("com", "pulumi", "aws", "acm"), "CertificateOptions"), + PulumiName("aws", null, listOf("com", "pulumi"), "acm", "CertificateOptions", false), NamingFlags(Nested, Function, Input, Java, GeneratedClass.EnumClass), "com.pulumi.aws.acm.enums", ), JavaFunctionOutput( - PulumiName("aws", listOf("com", "pulumi", "aws", "acm"), "CertificateOptions"), + PulumiName("aws", null, listOf("com", "pulumi"), "acm", "CertificateOptions", false), NamingFlags(Nested, Function, Output, Java, GeneratedClass.EnumClass), "com.pulumi.aws.acm.enums", ), @@ -118,7 +122,7 @@ internal class PulumiNameTest { } @Test - fun `toFunctionGroupObjectName should return a proper object name when targeting Java`() { + fun `function class name is correct when targeting Java`() { val name = PulumiName.from( "aws:acmpca/getCertificateAuthority:getCertificateAuthority", namingConfigurationWithSlashInModuleFormat("aws"), @@ -130,7 +134,7 @@ internal class PulumiNameTest { } @Test - fun `toFunctionGroupObjectName should return a proper object name when targeting Kotlin`() { + fun `function class name is correct when targeting Kotlin`() { val name = PulumiName.from( "aws:acmpca/getCertificateAuthority:getCertificateAuthority", namingConfigurationWithSlashInModuleFormat("aws"), @@ -142,7 +146,97 @@ internal class PulumiNameTest { } @Test - fun `toFunctionGroupObjectPackage should return a proper object name when targeting Java`() { + fun `function class and package in index namespace are correct for Kotlin`() { + val name = PulumiName.from( + "aws:index/getElasticIpFilter:getElasticIpFilter", + namingConfigurationWithSlashInModuleFormat("aws"), + ) + + val namingFlags = NamingFlags(Root, Function, Input, Kotlin) + val className = name.toFunctionGroupObjectName(namingFlags) + val packageName = name.toPackage(namingFlags) + + assertEquals("AwsFunctions", className) + assertEquals("com.pulumi.aws.kotlin.inputs", packageName) + } + + @Test + fun `function class and package in index namespace are correct for Java`() { + val name = PulumiName.from( + "aws:index/getElasticIpFilter:getElasticIpFilter", + namingConfigurationWithSlashInModuleFormat("aws"), + ) + + val namingFlags = NamingFlags(Root, Function, Input, Java) + val className = name.toFunctionGroupObjectName(namingFlags) + val packageName = name.toPackage(namingFlags) + + assertEquals("AwsFunctions", className) + assertEquals("com.pulumi.aws.inputs", packageName) + } + + @Test + fun `function class and package in index namespace with dash in provider name are correct for Kotlin`() { + val name = PulumiName.from( + "equinix-metal:index/getVolumeSnapshotPolicy:getVolumeSnapshotPolicy", + namingConfigurationWithSlashInModuleFormat("equinix-metal"), + ) + + val namingFlags = NamingFlags(Root, Function, Input, Kotlin) + val className = name.toFunctionGroupObjectName(namingFlags) + val packageName = name.toPackage(namingFlags) + + assertEquals("EquinixMetalFunctions", className) + assertEquals("com.pulumi.equinixmetal.kotlin.inputs", packageName) + } + + @Test + fun `function class and package in index namespace with dash in provider name are correct for Java`() { + val name = PulumiName.from( + "equinix-metal:index/getVolumeSnapshotPolicy:getVolumeSnapshotPolicy", + namingConfigurationWithSlashInModuleFormat("equinix-metal"), + ) + + val namingFlags = NamingFlags(Root, Function, Input, Java) + val className = name.toFunctionGroupObjectName(namingFlags) + val packageName = name.toPackage(namingFlags) + + assertEquals("EquinixmetalFunctions", className) + assertEquals("com.pulumi.equinixmetal.inputs", packageName) + } + + @Test + fun `function class and package in index namespace with overridden provider name are correct for Kotlin`() { + val name = PulumiName.from( + "equinix-metal:index/getVolumeSnapshotPolicy:getVolumeSnapshotPolicy", + namingConfigurationWithSlashInModuleFormat("equinix-metal", mapOf("equinix-metal" to "equinixmetal")), + ) + + val namingFlags = NamingFlags(Root, Function, Input, Kotlin) + val className = name.toFunctionGroupObjectName(namingFlags) + val packageName = name.toPackage(namingFlags) + + assertEquals("EquinixMetalFunctions", className) + assertEquals("com.pulumi.equinixmetal.kotlin.inputs", packageName) + } + + @Test + fun `function class and package in index namespace with overridden provider name are correct for Java`() { + val name = PulumiName.from( + "equinix-metal:index/getVolumeSnapshotPolicy:getVolumeSnapshotPolicy", + namingConfigurationWithSlashInModuleFormat("equinix-metal", mapOf("equinix-metal" to "equinixmetal")), + ) + + val namingFlags = NamingFlags(Root, Function, Input, Java) + val className = name.toFunctionGroupObjectName(namingFlags) + val packageName = name.toPackage(namingFlags) + + assertEquals("EquinixmetalFunctions", className) + assertEquals("com.pulumi.equinixmetal.inputs", packageName) + } + + @Test + fun `function package is correct when targeting Java`() { val name = PulumiName.from( "aws:acmpca/getCertificateAuthority:getCertificateAuthority", namingConfigurationWithSlashInModuleFormat("aws"), @@ -154,7 +248,7 @@ internal class PulumiNameTest { } @Test - fun `toFunctionGroupObjectPackage should return a proper object name when targeting Kotlin`() { + fun `function package is correct when targeting Kotlin`() { val name = PulumiName.from( "aws:acmpca/getCertificateAuthority:getCertificateAuthority", namingConfigurationWithSlashInModuleFormat("aws"), @@ -304,8 +398,13 @@ internal class PulumiNameTest { // then assertAll( - { assertEquals("overrideProvider", pulumiName.providerName) }, - { assertEquals(listOf("org", "example", "overrideProvider", "overrideModule"), pulumiName.namespace) }, + { assertEquals("provider", pulumiName.providerName) }, + { + assertEquals( + listOf("org", "example", "overrideProvider", "overrideModule"), + pulumiName.namespace, + ) + }, { assertEquals("ObjectName", pulumiName.name) }, ) } @@ -360,4 +459,100 @@ internal class PulumiNameTest { exception.message, ) } + + @Test + fun `provider class and package are correct when targeting Kotlin`() { + val name = PulumiName.from( + DEFAULT_PROVIDER_TOKEN, + namingConfigurationWithSlashInModuleFormat("aws"), + isProvider = true, + ) + + val namingFlags = NamingFlags(Root, Resource, Input, Kotlin) + val className = name.toResourceName(namingFlags) + val packageName = name.toResourcePackage(namingFlags) + + assertEquals("AwsProvider", className) + assertEquals("com.pulumi.aws.kotlin", packageName) + } + + @Test + fun `provider class and package are correct when targeting Java`() { + val name = PulumiName.from( + DEFAULT_PROVIDER_TOKEN, + namingConfigurationWithSlashInModuleFormat("aws"), + isProvider = true, + ) + + val namingFlags = NamingFlags(Root, Resource, Input, Java) + val className = name.toResourceName(namingFlags) + val packageName = name.toResourcePackage(namingFlags) + + assertEquals("Provider", className) + assertEquals("com.pulumi.aws", packageName) + } + + @Test + fun `provider class and package with dash in provider name are correct when targeting Kotlin`() { + val name = PulumiName.from( + DEFAULT_PROVIDER_TOKEN, + namingConfigurationWithSlashInModuleFormat("equinix-metal"), + isProvider = true, + ) + + val namingFlags = NamingFlags(Root, Resource, Input, Kotlin) + val className = name.toResourceName(namingFlags) + val packageName = name.toResourcePackage(namingFlags) + + assertEquals("EquinixMetalProvider", className) + assertEquals("com.pulumi.equinixmetal.kotlin", packageName) + } + + @Test + fun `provider class and package with dash in provider name are correct when targeting Java`() { + val name = PulumiName.from( + DEFAULT_PROVIDER_TOKEN, + namingConfigurationWithSlashInModuleFormat("equinix-metal"), + isProvider = true, + ) + + val namingFlags = NamingFlags(Root, Resource, Input, Java) + val className = name.toResourceName(namingFlags) + val packageName = name.toResourcePackage(namingFlags) + + assertEquals("Provider", className) + assertEquals("com.pulumi.equinixmetal", packageName) + } + + @Test + fun `provider class and package with overriden provider name are correct when targeting Kotlin`() { + val name = PulumiName.from( + DEFAULT_PROVIDER_TOKEN, + namingConfigurationWithSlashInModuleFormat("equinix-metal", mapOf("equinix-metal" to "equinixmetal")), + isProvider = true, + ) + + val namingFlags = NamingFlags(Root, Resource, Input, Kotlin) + val className = name.toResourceName(namingFlags) + val packageName = name.toResourcePackage(namingFlags) + + assertEquals("EquinixMetalProvider", className) + assertEquals("com.pulumi.equinixmetal.kotlin", packageName) + } + + @Test + fun `provider class and package with overriden provider name are correct when targeting Java`() { + val name = PulumiName.from( + DEFAULT_PROVIDER_TOKEN, + namingConfigurationWithSlashInModuleFormat("equinix-metal", mapOf("equinix-metal" to "equinixmetal")), + isProvider = true, + ) + + val namingFlags = NamingFlags(Root, Resource, Input, Java) + val className = name.toResourceName(namingFlags) + val packageName = name.toResourcePackage(namingFlags) + + assertEquals("Provider", className) + assertEquals("com.pulumi.equinixmetal", packageName) + } } diff --git a/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/step3codegen/CodeGeneratorGenerateTypesTest.kt b/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/step3codegen/CodeGeneratorGenerateTypesTest.kt index 98d364f0..19f58453 100644 --- a/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/step3codegen/CodeGeneratorGenerateTypesTest.kt +++ b/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/step3codegen/CodeGeneratorGenerateTypesTest.kt @@ -24,7 +24,7 @@ internal class CodeGeneratorGenerateTypesTest { fun `generated kotlin files for some handcrafted types should compile`() { val firstType = ComplexType( TypeMetadata( - PulumiName("aws", listOf("aws"), "FirstType"), + PulumiName("aws", null, emptyList(), null, "FirstType", false), UsageKind(Nested, Resource, Input), KDoc(null, null), ), @@ -38,7 +38,7 @@ internal class CodeGeneratorGenerateTypesTest { ) val secondType = ComplexType( TypeMetadata( - PulumiName("aws", listOf("aws"), "SecondType"), + PulumiName("aws", null, emptyList(), "aws", "SecondType", false), UsageKind(Nested, Resource, Input), KDoc(null, null), ), diff --git a/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/step3codegen/TypeNameClashResolverTest.kt b/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/step3codegen/TypeNameClashResolverTest.kt index 1dbae128..4f0f4454 100644 --- a/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/step3codegen/TypeNameClashResolverTest.kt +++ b/src/test/kotlin/org/virtuslab/pulumikotlin/codegen/step3codegen/TypeNameClashResolverTest.kt @@ -195,7 +195,7 @@ internal class TypeNameClashResolverTest { } private fun createMetadata(name: String, depth: Depth, subject: Subject, direction: Direction) = TypeMetadata( - PulumiName("provider", listOf("some", "package"), name), + PulumiName("package", null, listOf("some"), null, name, true), UsageKind(depth, subject, direction), KDoc(null, null), ) diff --git a/src/test/kotlin/org/virtuslab/pulumikotlin/scripts/ComputeSchemaSubsetScriptTest.kt b/src/test/kotlin/org/virtuslab/pulumikotlin/scripts/ComputeSchemaSubsetScriptTest.kt index 5f837622..efcb5aa4 100644 --- a/src/test/kotlin/org/virtuslab/pulumikotlin/scripts/ComputeSchemaSubsetScriptTest.kt +++ b/src/test/kotlin/org/virtuslab/pulumikotlin/scripts/ComputeSchemaSubsetScriptTest.kt @@ -287,9 +287,9 @@ internal class ComputeSchemaSubsetScriptTest { } private const val SCHEMA_PATH_AZURE_NATIVE_SUBSET_WITH_IP_ALLOCATION = - "src/test/resources/schema-azure-native-3.44.2-subset-with-ip-allocation.json" + "src/test/resources/schema-azure-native-1.104.0-subset-with-ip-allocation.json" private const val SCHEMA_PATH_AZURE_NATIVE_SUBSET_WITH_RECURSION = - "src/test/resources/schema-azure-native-3.44.2-subset-with-recursion.json" + "src/test/resources/schema-azure-native-1.104.0-subset-with-recursion.json" private const val SCHEMA_PATH_AWS_SUBSET_FOR_COMPUTE = "src/test/resources/schema-aws-classic-5.16.2-subset-for-compute-schema-subset-script-test.json" private const val SCHEMA_PATH_AWS_SUBSET_WITH_PROVIDER_AND_SOME_TYPES = diff --git a/src/test/resources/schema-aws-classic-5.15.2-subset-with-index.json b/src/test/resources/schema-aws-classic-5.15.0-subset-with-index.json similarity index 100% rename from src/test/resources/schema-aws-classic-5.15.2-subset-with-index.json rename to src/test/resources/schema-aws-classic-5.15.0-subset-with-index.json diff --git a/src/test/resources/schema-azure-native-3.44.2-subset-with-ip-allocation.json b/src/test/resources/schema-azure-native-1.104.0-subset-with-ip-allocation.json similarity index 100% rename from src/test/resources/schema-azure-native-3.44.2-subset-with-ip-allocation.json rename to src/test/resources/schema-azure-native-1.104.0-subset-with-ip-allocation.json diff --git a/src/test/resources/schema-azure-native-3.44.2-subset-with-recursion.json b/src/test/resources/schema-azure-native-1.104.0-subset-with-recursion.json similarity index 100% rename from src/test/resources/schema-azure-native-3.44.2-subset-with-recursion.json rename to src/test/resources/schema-azure-native-1.104.0-subset-with-recursion.json diff --git a/src/test/resources/schema-equinix-metal-3.3.0-alpha-with-index.json b/src/test/resources/schema-equinix-metal-3.3.0-alpha-with-index.json new file mode 100644 index 00000000..f671254a --- /dev/null +++ b/src/test/resources/schema-equinix-metal-3.3.0-alpha-with-index.json @@ -0,0 +1,223 @@ +{ + "name": "equinix-metal", + "meta": { + "moduleFormat": "(.*)(?:/[^/]*)" + }, + "config": { + "variables": { + "authToken": { + "type": "string", + "description": "The API auth key for API operations.\n" + }, + "maxRetries": { + "type": "integer" + }, + "maxRetryWaitSeconds": { + "type": "integer" + } + }, + "defaults": [ + "authToken" + ] + }, + "language": { + "csharp": { + "compatibility": "tfbridge20", + "namespaces": { + "equinix-metal": "EquinixMetal", + "index": "index" + }, + "packageReferences": { + "Pulumi": "3.*" + } + }, + "go": { + "generateExtraInputTypes": true, + "generateResourceContainerTypes": true, + "importBasePath": "github.com/pulumi/pulumi-equinix-metal/sdk/v3/go/equinix" + }, + "nodejs": { + "compatibility": "tfbridge20", + "dependencies": { + "@pulumi/pulumi": "^3.0.0" + }, + "devDependencies": { + "@types/mime": "^2.0.0", + "@types/node": "^10.0.0" + }, + "disableUnionOutputTypes": true, + "packageDescription": "A Pulumi package for creating and managing equinix-metal cloud resources.", + "packageName": "", + "readme": "> This provider is a derived work of the [Terraform Provider](https://github.com/equinix/terraform-provider-metal)\n> distributed under [MPL 2.0](https://www.mozilla.org/en-US/MPL/2.0/). If you encounter a bug or missing feature,\n> first check the [`pulumi/pulumi-equinix-metal` repo](https://github.com/pulumi/pulumi-equinix-metal/issues); however, if that doesn't turn up anything,\n> please consult the source [`equinix/terraform-provider-metal` repo](https://github.com/equinix/terraform-provider-metal/issues).", + "typescriptVersion": "" + }, + "python": { + "compatibility": "tfbridge20", + "readme": "> This provider is a derived work of the [Terraform Provider](https://github.com/equinix/terraform-provider-metal)\n> distributed under [MPL 2.0](https://www.mozilla.org/en-US/MPL/2.0/). If you encounter a bug or missing feature,\n> first check the [`pulumi/pulumi-equinix-metal` repo](https://github.com/pulumi/pulumi-equinix-metal/issues); however, if that doesn't turn up anything,\n> please consult the source [`equinix/terraform-provider-metal` repo](https://github.com/equinix/terraform-provider-metal/issues).", + "requires": { + "pulumi": ">=3.0.0,<4.0.0" + } + } + }, + "provider": { + "description": "The provider type for the metal package. By default, resources use package-wide configuration\nsettings, however an explicit `Provider` instance may be created and passed during resource\nconstruction to achieve fine-grained programmatic control over provider settings. See the\n[documentation](https://www.pulumi.com/docs/reference/programming-model/#providers) for more information.\n", + "properties": { + "authToken": { + "type": "string", + "description": "The API auth key for API operations.\n" + }, + "maxRetries": { + "type": "integer" + }, + "maxRetryWaitSeconds": { + "type": "integer" + } + }, + "required": [ + "authToken" + ], + "inputProperties": { + "authToken": { + "type": "string", + "description": "The API auth key for API operations.\n" + }, + "maxRetries": { + "type": "integer" + }, + "maxRetryWaitSeconds": { + "type": "integer" + } + }, + "requiredInputs": [ + "authToken" + ] + }, + "types": { + "equinix-metal:index/getVolumeSnapshotPolicy:getVolumeSnapshotPolicy": { + "properties": { + "snapshotCount": { + "type": "integer", + "language": { + "python": { + "mapCase": false + } + } + }, + "snapshotFrequency": { + "type": "string", + "language": { + "python": { + "mapCase": false + } + } + } + }, + "type": "object", + "required": [ + "snapshotCount", + "snapshotFrequency" + ], + "language": { + "nodejs": { + "requiredInputs": [] + } + } + } + }, + "resources": {}, + "functions": { + "equinix-metal:index/getVolume:getVolume": { + "description": "Datasource `equinix-metal.Volume` was removed in version 3.0.0, and the API support was deprecated on June 1st 2021. See https://metal.equinix.com/developers/docs/storage/elastic-block-storage/#elastic-block-storage for more details.\n", + "inputs": { + "description": "A collection of arguments for invoking getVolume.\n", + "properties": { + "name": { + "type": "string" + }, + "projectId": { + "type": "string" + }, + "volumeId": { + "type": "string" + } + }, + "type": "object" + }, + "outputs": { + "description": "A collection of values returned by getVolume.\n", + "properties": { + "billingCycle": { + "type": "string" + }, + "created": { + "type": "string" + }, + "description": { + "type": "string" + }, + "deviceIds": { + "type": "array", + "items": { + "type": "string" + } + }, + "facility": { + "type": "string" + }, + "id": { + "type": "string", + "description": "The provider-assigned unique ID for this managed resource.\n" + }, + "locked": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "plan": { + "type": "string" + }, + "projectId": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "snapshotPolicies": { + "type": "array", + "items": { + "$ref": "#/types/equinix-metal:index/getVolumeSnapshotPolicy:getVolumeSnapshotPolicy" + } + }, + "state": { + "type": "string" + }, + "updated": { + "type": "string" + }, + "volumeId": { + "type": "string" + } + }, + "type": "object", + "required": [ + "billingCycle", + "created", + "description", + "deviceIds", + "facility", + "locked", + "name", + "plan", + "projectId", + "size", + "snapshotPolicies", + "state", + "updated", + "volumeId", + "id" + ] + } + } + } +} diff --git a/src/test/resources/schema-gcp-classic-6.39.0-subset-lb-ip-ranges.json b/src/test/resources/schema-gcp-classic-6.39.0-subset-lb-ip-ranges.json index 533b50bd..2e7574ad 100644 --- a/src/test/resources/schema-gcp-classic-6.39.0-subset-lb-ip-ranges.json +++ b/src/test/resources/schema-gcp-classic-6.39.0-subset-lb-ip-ranges.json @@ -1,73 +1,73 @@ { - "name": "gcp", - "meta": { - "moduleFormat": "(.*)(?:/[^/]*)" - }, - "resources": { - }, - "functions": { - "gcp:compute/getLBIPRanges:getLBIPRanges": { - "inputs": null, - "outputs": { - "type": "object", - "properties": { - "httpSslTcpInternals": { - "type": "array", - "items": { - "type": "string", - "description": null, - "willReplaceOnChanges": false, - "deprecationMessage": null, - "language": null, - "default": null - }, - "willReplaceOnChanges": false, - "deprecationMessage": null, - "description": "The IP ranges used for health checks when **HTTP(S), SSL proxy, TCP proxy, and Internal load balancing** is used\n", - "language": null, - "default": null - }, - "id": { - "type": "string", - "description": "The provider-assigned unique ID for this managed resource.\n", - "willReplaceOnChanges": false, - "deprecationMessage": null, - "language": null, - "default": null - }, - "networks": { - "type": "array", - "items": { - "type": "string", - "description": null, - "willReplaceOnChanges": false, - "deprecationMessage": null, - "language": null, - "default": null - }, - "willReplaceOnChanges": false, - "deprecationMessage": null, - "description": "The IP ranges used for health checks when **Network load balancing** is used\n", - "language": null, - "default": null - } - }, - "deprecationMessage": null, - "willReplaceOnChanges": false, - "additionalProperties": null, - "required": [ - "httpSslTcpInternals", - "networks", - "id" - ], - "description": "A collection of values returned by getLBIPRanges.\n", - "language": null, - "default": null + "name": "gcp", + "meta": { + "moduleFormat": "(.*)(?:/[^/]*)" + }, + "resources": { + }, + "functions": { + "gcp:compute/getLBIPRanges:getLBIPRanges": { + "inputs": null, + "outputs": { + "type": "object", + "properties": { + "httpSslTcpInternals": { + "type": "array", + "items": { + "type": "string", + "description": null, + "willReplaceOnChanges": false, + "deprecationMessage": null, + "language": null, + "default": null }, + "willReplaceOnChanges": false, "deprecationMessage": null, - "description": "Use this data source to access IP ranges in your firewall rules.\n\nhttps://cloud.google.com/compute/docs/load-balancing/health-checks#health_check_source_ips_and_firewall_rules\n\n{{% examples %}}\n## Example Usage\n{{% example %}}\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as gcp from \"@pulumi/gcp\";\n\nconst ranges = gcp.compute.getLBIPRanges({});\nconst lb = new gcp.compute.Firewall(\"lb\", {\n network: google_compute_network.main.name,\n allows: [{\n protocol: \"tcp\",\n ports: [\"80\"],\n }],\n sourceRanges: ranges.then(ranges => ranges.networks),\n targetTags: [\"InstanceBehindLoadBalancer\"],\n});\n```\n```python\nimport pulumi\nimport pulumi_gcp as gcp\n\nranges = gcp.compute.get_lbip_ranges()\nlb = gcp.compute.Firewall(\"lb\",\n network=google_compute_network[\"main\"][\"name\"],\n allows=[gcp.compute.FirewallAllowArgs(\n protocol=\"tcp\",\n ports=[\"80\"],\n )],\n source_ranges=ranges.networks,\n target_tags=[\"InstanceBehindLoadBalancer\"])\n```\n```csharp\nusing System.Collections.Generic;\nusing Pulumi;\nusing Gcp = Pulumi.Gcp;\n\nreturn await Deployment.RunAsync(() => \n{\n var ranges = Gcp.Compute.GetLBIPRanges.Invoke();\n\n var lb = new Gcp.Compute.Firewall(\"lb\", new()\n {\n Network = google_compute_network.Main.Name,\n Allows = new[]\n {\n new Gcp.Compute.Inputs.FirewallAllowArgs\n {\n Protocol = \"tcp\",\n Ports = new[]\n {\n \"80\",\n },\n },\n },\n SourceRanges = ranges.Apply(getLBIPRangesResult => getLBIPRangesResult.Networks),\n TargetTags = new[]\n {\n \"InstanceBehindLoadBalancer\",\n },\n });\n\n});\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-gcp/sdk/v6/go/gcp/compute\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\tranges, err := compute.GetLBIPRanges(ctx, nil, nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = compute.NewFirewall(ctx, \"lb\", &compute.FirewallArgs{\n\t\t\tNetwork: pulumi.Any(google_compute_network.Main.Name),\n\t\t\tAllows: compute.FirewallAllowArray{\n\t\t\t\t&compute.FirewallAllowArgs{\n\t\t\t\t\tProtocol: pulumi.String(\"tcp\"),\n\t\t\t\t\tPorts: pulumi.StringArray{\n\t\t\t\t\t\tpulumi.String(\"80\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tSourceRanges: interface{}(ranges.Networks),\n\t\t\tTargetTags: pulumi.StringArray{\n\t\t\t\tpulumi.String(\"InstanceBehindLoadBalancer\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.gcp.compute.ComputeFunctions;\nimport com.pulumi.gcp.compute.Firewall;\nimport com.pulumi.gcp.compute.FirewallArgs;\nimport com.pulumi.gcp.compute.inputs.FirewallAllowArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n final var ranges = ComputeFunctions.getLBIPRanges();\n\n var lb = new Firewall(\"lb\", FirewallArgs.builder() \n .network(google_compute_network.main().name())\n .allows(FirewallAllowArgs.builder()\n .protocol(\"tcp\")\n .ports(\"80\")\n .build())\n .sourceRanges(ranges.applyValue(getLBIPRangesResult -> getLBIPRangesResult.networks()))\n .targetTags(\"InstanceBehindLoadBalancer\")\n .build());\n\n }\n}\n```\n```yaml\nresources:\n lb:\n type: gcp:compute:Firewall\n properties:\n network: ${google_compute_network.main.name}\n allows:\n - protocol: tcp\n ports:\n - 80\n sourceRanges: ${ranges.networks}\n targetTags:\n - InstanceBehindLoadBalancer\nvariables:\n ranges:\n Fn::Invoke:\n Function: gcp:compute:getLBIPRanges\n Arguments: {}\n```\n{{% /example %}}\n{{% /examples %}}" - } - }, - "types": { + "description": "The IP ranges used for health checks when **HTTP(S), SSL proxy, TCP proxy, and Internal load balancing** is used\n", + "language": null, + "default": null + }, + "id": { + "type": "string", + "description": "The provider-assigned unique ID for this managed resource.\n", + "willReplaceOnChanges": false, + "deprecationMessage": null, + "language": null, + "default": null + }, + "networks": { + "type": "array", + "items": { + "type": "string", + "description": null, + "willReplaceOnChanges": false, + "deprecationMessage": null, + "language": null, + "default": null + }, + "willReplaceOnChanges": false, + "deprecationMessage": null, + "description": "The IP ranges used for health checks when **Network load balancing** is used\n", + "language": null, + "default": null + } + }, + "deprecationMessage": null, + "willReplaceOnChanges": false, + "additionalProperties": null, + "required": [ + "httpSslTcpInternals", + "networks", + "id" + ], + "description": "A collection of values returned by getLBIPRanges.\n", + "language": null, + "default": null + }, + "deprecationMessage": null, + "description": "Use this data source to access IP ranges in your firewall rules.\n\nhttps://cloud.google.com/compute/docs/load-balancing/health-checks#health_check_source_ips_and_firewall_rules\n\n{{% examples %}}\n## Example Usage\n{{% example %}}\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as gcp from \"@pulumi/gcp\";\n\nconst ranges = gcp.compute.getLBIPRanges({});\nconst lb = new gcp.compute.Firewall(\"lb\", {\n network: google_compute_network.main.name,\n allows: [{\n protocol: \"tcp\",\n ports: [\"80\"],\n }],\n sourceRanges: ranges.then(ranges => ranges.networks),\n targetTags: [\"InstanceBehindLoadBalancer\"],\n});\n```\n```python\nimport pulumi\nimport pulumi_gcp as gcp\n\nranges = gcp.compute.get_lbip_ranges()\nlb = gcp.compute.Firewall(\"lb\",\n network=google_compute_network[\"main\"][\"name\"],\n allows=[gcp.compute.FirewallAllowArgs(\n protocol=\"tcp\",\n ports=[\"80\"],\n )],\n source_ranges=ranges.networks,\n target_tags=[\"InstanceBehindLoadBalancer\"])\n```\n```csharp\nusing System.Collections.Generic;\nusing Pulumi;\nusing Gcp = Pulumi.Gcp;\n\nreturn await Deployment.RunAsync(() => \n{\n var ranges = Gcp.Compute.GetLBIPRanges.Invoke();\n\n var lb = new Gcp.Compute.Firewall(\"lb\", new()\n {\n Network = google_compute_network.Main.Name,\n Allows = new[]\n {\n new Gcp.Compute.Inputs.FirewallAllowArgs\n {\n Protocol = \"tcp\",\n Ports = new[]\n {\n \"80\",\n },\n },\n },\n SourceRanges = ranges.Apply(getLBIPRangesResult => getLBIPRangesResult.Networks),\n TargetTags = new[]\n {\n \"InstanceBehindLoadBalancer\",\n },\n });\n\n});\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-gcp/sdk/v6/go/gcp/compute\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\tranges, err := compute.GetLBIPRanges(ctx, nil, nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = compute.NewFirewall(ctx, \"lb\", &compute.FirewallArgs{\n\t\t\tNetwork: pulumi.Any(google_compute_network.Main.Name),\n\t\t\tAllows: compute.FirewallAllowArray{\n\t\t\t\t&compute.FirewallAllowArgs{\n\t\t\t\t\tProtocol: pulumi.String(\"tcp\"),\n\t\t\t\t\tPorts: pulumi.StringArray{\n\t\t\t\t\t\tpulumi.String(\"80\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tSourceRanges: interface{}(ranges.Networks),\n\t\t\tTargetTags: pulumi.StringArray{\n\t\t\t\tpulumi.String(\"InstanceBehindLoadBalancer\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.gcp.compute.ComputeFunctions;\nimport com.pulumi.gcp.compute.Firewall;\nimport com.pulumi.gcp.compute.FirewallArgs;\nimport com.pulumi.gcp.compute.inputs.FirewallAllowArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n final var ranges = ComputeFunctions.getLBIPRanges();\n\n var lb = new Firewall(\"lb\", FirewallArgs.builder() \n .network(google_compute_network.main().name())\n .allows(FirewallAllowArgs.builder()\n .protocol(\"tcp\")\n .ports(\"80\")\n .build())\n .sourceRanges(ranges.applyValue(getLBIPRangesResult -> getLBIPRangesResult.networks()))\n .targetTags(\"InstanceBehindLoadBalancer\")\n .build());\n\n }\n}\n```\n```yaml\nresources:\n lb:\n type: gcp:compute:Firewall\n properties:\n network: ${google_compute_network.main.name}\n allows:\n - protocol: tcp\n ports:\n - 80\n sourceRanges: ${ranges.networks}\n targetTags:\n - InstanceBehindLoadBalancer\nvariables:\n ranges:\n Fn::Invoke:\n Function: gcp:compute:getLBIPRanges\n Arguments: {}\n```\n{{% /example %}}\n{{% /examples %}}" } + }, + "types": { + } }