-
Notifications
You must be signed in to change notification settings - Fork 55
feat: link api ref docs to examples #1550
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| package aws.sdk.kotlin.codegen | ||
|
|
||
| import software.amazon.smithy.kotlin.codegen.KotlinSettings | ||
| import software.amazon.smithy.kotlin.codegen.core.CodegenContext | ||
| import software.amazon.smithy.kotlin.codegen.core.KotlinDelegator | ||
| import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration | ||
| import software.amazon.smithy.kotlin.codegen.model.expectShape | ||
| import software.amazon.smithy.kotlin.codegen.model.getTrait | ||
| import software.amazon.smithy.model.Model | ||
| import software.amazon.smithy.model.shapes.ServiceShape | ||
| import software.amazon.smithy.model.traits.TitleTrait | ||
|
|
||
| /** | ||
| * Maps a services SKD ID to its code examples | ||
| */ | ||
| private val currentCodeExamplesServices = mapOf( | ||
|
||
| "API Gateway" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_api-gateway_code_examples.html", | ||
| "Auto Scaling" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_auto-scaling_code_examples.html", | ||
| "Bedrock" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_bedrock_code_examples.html", | ||
| "CloudWatch" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_cloudwatch_code_examples.html", | ||
| "Comprehend" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_comprehend_code_examples.html", | ||
| "DynamoDB" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_dynamodb_code_examples.html", | ||
| "EC2" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_ec2_code_examples.html", | ||
| "ECR" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_ecr_code_examples.html", | ||
| "OpenSearch" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_opensearch_code_examples.html", | ||
| "EventBridge" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_eventbridge_code_examples.html", | ||
| "Glue" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_glue_code_examples.html", | ||
| "IAM" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_iam_code_examples.html", | ||
| "IoT" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_iot_code_examples.html ", | ||
| "Keyspaces" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_keyspaces_code_examples.html", | ||
| "KMS" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_kms_code_examples.html", | ||
| "Lambda" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_lambda_code_examples.html", | ||
| "MediaConvert" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_mediaconvert_code_examples.html", | ||
| "Pinpoint" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_pinpoint_code_examples.html", | ||
| "RDS" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_rds_code_examples.html", | ||
| "Redshift" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_redshift_code_examples.html", | ||
| "Rekognition" to "https://docs.aws.amazon.com/code-library/latest/ug/kotlin_1_rekognition_code_examples.html", | ||
| ) | ||
|
|
||
| /** | ||
| * Maps a services SKD ID to its handwritten module documentation file in the `resources` dir. | ||
|
||
| * The module documentation files MUST be markdown files. | ||
| */ | ||
| private val currentHandWrittenServices = mapOf( | ||
|
||
| "S3" to "S3.md", | ||
| ) | ||
|
|
||
| /** | ||
| * Generates an `API.md` file that will be used as module documentation in our API ref docs. | ||
| * Some services have code examples we need to link to. Others have handwritten documentation. | ||
| * The integration renders both into the `API.md` file. | ||
| * | ||
| * See: https://kotlinlang.org/docs/dokka-module-and-package-docs.html | ||
| * | ||
| * See: https://github.com/awslabs/aws-sdk-kotlin/blob/0581f5c5eeaa14dcd8af4ea0dfc088b1057f5ba5/build.gradle.kts#L68-L75 | ||
| */ | ||
| class ModuleDocumentationIntegration( | ||
| private val codeExamples: Map<String, String> = currentCodeExamplesServices, | ||
| private val handWritten: Map<String, String> = currentHandWrittenServices, | ||
| ) : KotlinIntegration { | ||
| override fun enabledForService(model: Model, settings: KotlinSettings): Boolean = | ||
| model.expectShape<ServiceShape>(settings.service).sdkId.let { | ||
| codeExamples.keys.contains(it) || handWritten.keys.contains(it) | ||
| } | ||
|
|
||
| override fun writeAdditionalFiles(ctx: CodegenContext, delegator: KotlinDelegator) { | ||
| delegator.fileManifest.writeFile( | ||
| "API.md", | ||
| generateModuleDocumentation(ctx, ctx.settings.sdkId), | ||
| ) | ||
| } | ||
|
|
||
| internal fun generateModuleDocumentation( | ||
| ctx: CodegenContext, | ||
| sdkId: String, | ||
| ) = buildString { | ||
| append( | ||
| generateBoilerPlate(ctx), | ||
| ) | ||
| if (codeExamples.keys.contains(sdkId)) { | ||
| append( | ||
| generateCodeExamplesDocs(sdkId), | ||
| ) | ||
| appendLine() | ||
| } | ||
| if (handWritten.keys.contains(sdkId)) { | ||
| append( | ||
| generateHandWrittenDocs(sdkId), | ||
| ) | ||
| } | ||
|
||
| } | ||
|
|
||
| private fun generateBoilerPlate(ctx: CodegenContext) = buildString { | ||
| // Title must me "Module" followed by the exact module name or dokka won't render it | ||
|
||
| appendLine("# Module ${ctx.settings.pkg.name.split(".").last()}") | ||
| appendLine() | ||
| ctx | ||
| .model | ||
| .expectShape<ServiceShape>(ctx.settings.service) | ||
| .getTrait<TitleTrait>() | ||
| ?.value | ||
| ?.let { | ||
| appendLine(it) | ||
| appendLine() | ||
| } | ||
| } | ||
|
|
||
| private fun generateCodeExamplesDocs(sdkId: String) = buildString { | ||
| appendLine("## Code Examples") | ||
| appendLine("To see full code examples, see the $sdkId examples in the AWS Code Library. See ${codeExamples[sdkId]}") | ||
|
||
| appendLine() | ||
| } | ||
|
|
||
| private fun generateHandWrittenDocs(sdkId: String): String = object {} | ||
| .javaClass | ||
| .classLoader | ||
| .getResourceAsStream("aws/sdk/kotlin/codegen/moduledocumentation/${handWritten[sdkId]}") | ||
|
||
| ?.bufferedReader() | ||
| ?.readText() | ||
| ?: throw Exception("Unable to read from file ${handWritten[sdkId]}") | ||
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| package aws.sdk.kotlin.codegen | ||
|
|
||
| import software.amazon.smithy.kotlin.codegen.test.newTestContext | ||
| import software.amazon.smithy.kotlin.codegen.test.shouldContainOnlyOnceWithDiff | ||
| import software.amazon.smithy.kotlin.codegen.test.toGenerationContext | ||
| import software.amazon.smithy.kotlin.codegen.test.toSmithyModel | ||
| import kotlin.test.Test | ||
| import kotlin.test.assertFalse | ||
| import kotlin.test.assertTrue | ||
|
|
||
| private val model = """ | ||
| ${"$"}version: "2" | ||
|
|
||
| namespace com.test | ||
|
|
||
| use aws.api#service | ||
|
|
||
| @service(sdkId: "Test") | ||
| @title("A test service") | ||
| service Test { | ||
| version: "1.0.0", | ||
| operations: [] | ||
| } | ||
| """.toSmithyModel() | ||
|
|
||
| val ctx = model.newTestContext("Test") | ||
|
|
||
| class ModuleDocumentationIntegrationTest { | ||
| @Test | ||
| fun integrationIsAppliedCorrectly() { | ||
| assertFalse( | ||
| ModuleDocumentationIntegration().enabledForService(model, ctx.generationCtx.settings), | ||
| ) | ||
| assertTrue( | ||
| ModuleDocumentationIntegration( | ||
| codeExamples = mapOf("Test" to "https://example.com"), | ||
| ).enabledForService(model, ctx.generationCtx.settings), | ||
| ) | ||
| assertTrue( | ||
| ModuleDocumentationIntegration( | ||
| handWritten = mapOf("Test" to "example.md"), | ||
| ).enabledForService(model, ctx.generationCtx.settings), | ||
| ) | ||
| assertTrue( | ||
| ModuleDocumentationIntegration( | ||
| codeExamples = mapOf("Test" to "https://example.com"), | ||
| handWritten = mapOf("Test" to "test.md"), | ||
| ).enabledForService(model, ctx.generationCtx.settings), | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun rendersBoilerplate() = | ||
| ModuleDocumentationIntegration() | ||
| .generateModuleDocumentation( | ||
| ctx.toGenerationContext(), | ||
| "Test", | ||
| ) | ||
| .shouldContainOnlyOnceWithDiff( | ||
| """ | ||
| # Module test | ||
|
|
||
| A test service | ||
| """.trimIndent(), | ||
| ) | ||
|
|
||
| @Test | ||
| fun rendersCodeExampleDocs() = | ||
| ModuleDocumentationIntegration( | ||
| codeExamples = mapOf("Test" to "https://example.com"), | ||
| ) | ||
| .generateModuleDocumentation( | ||
| ctx.toGenerationContext(), | ||
| "Test", | ||
| ) | ||
| .shouldContainOnlyOnceWithDiff( | ||
| """ | ||
| ## Code Examples | ||
| To see full code examples, see the Test examples in the AWS Code Library. See https://example.com | ||
| """.trimIndent(), | ||
| ) | ||
|
|
||
| @Test | ||
| fun rendersHandWrittenDocs() = | ||
| ModuleDocumentationIntegration( | ||
| handWritten = mapOf("Test" to "test.md"), | ||
| ) | ||
| .generateModuleDocumentation( | ||
| ctx.toGenerationContext(), | ||
| "Test", | ||
| ) | ||
| .shouldContainOnlyOnceWithDiff( | ||
| """ | ||
| ## Subtitle | ||
|
|
||
| Lorem Ipsum | ||
| """.trimIndent(), | ||
| ) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| ## Subtitle | ||
|
|
||
| Lorem Ipsum |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit/grammar: service's
typo: SDK