From c7bb65ce3edbf8a723799afbc76c50b059099cb5 Mon Sep 17 00:00:00 2001 From: Matas Lauzadis Date: Sat, 21 Jun 2025 10:39:28 -0400 Subject: [PATCH 01/11] docs: fix navigation links on left sidebar --- buildSrc/src/main/kotlin/dokka-convention.gradle.kts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/main/kotlin/dokka-convention.gradle.kts b/buildSrc/src/main/kotlin/dokka-convention.gradle.kts index 4d21442b641..0fcf9d1fc5d 100644 --- a/buildSrc/src/main/kotlin/dokka-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/dokka-convention.gradle.kts @@ -97,11 +97,11 @@ tasks.register("trimNavigationFiles") { val navigation = moduleDir.resolve("navigation.html").toFile() val doc = Jsoup.parse(navigation) - // Fix navigation links - doc.select("a[href^='../../../../']").forEach { anchor -> + // Remove a single parent directory from all navigation links + doc.select("a[href^=../]").forEach { anchor -> val originalHref = anchor.attr("href") - val trimmedHref = originalHref.replace("../../../../", "") - anchor.attr("href", trimmedHref) + val updatedHref = originalHref.removePrefix("../") + anchor.attr("href", updatedHref) } // Trim side menus From abbd89162a67dd97b2695049d3058132cd3296c9 Mon Sep 17 00:00:00 2001 From: Matas Lauzadis Date: Sat, 21 Jun 2025 10:50:34 -0400 Subject: [PATCH 02/11] fix a bug in `extractModulePath` for versioned docs --- .../scripts/custom-navigation-loader.js | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/docs/dokka-presets/scripts/custom-navigation-loader.js b/docs/dokka-presets/scripts/custom-navigation-loader.js index b42f17cf41c..6d0217d3f4d 100644 --- a/docs/dokka-presets/scripts/custom-navigation-loader.js +++ b/docs/dokka-presets/scripts/custom-navigation-loader.js @@ -5,27 +5,23 @@ * https://sdk.amazonaws.com/kotlin/api/latest/index.html -> index.html * https://sdk.amazonaws.com/kotlin/api/latest/s3/index.html -> s3 * https://sdk.amazonaws.com/kotlin/api/latest/s3/aws.sdk.kotlin.services.s3/index.html -> s3 + * https://sdk.amazonaws.com/kotlin/api/1.4.109/s3/index.html -> s3 */ function extractModulePath(href) { try { - const url = new URL(href, window.location.origin); - const pathSegments = url.pathname.split('/').filter(Boolean); - - var moduleIndex = -1; - - for (let i = 1; i < pathSegments.length; i++) { - if (pathSegments[i].includes('.')) { - moduleIndex = i-1; - break; - } - } - - if (moduleIndex === -1) { - return "index.html"; - } else { - return pathSegments.slice(0, moduleIndex + 1).join("/"); - } - } catch (error) { + const segments = new URL(href, window.location.origin) + .pathname + .split('/') // break the path + .filter(Boolean); // drop empty parts + + // the URL pattern is always ".../kotlin/api//..." + const apiPos = segments.indexOf('api'); + if (apiPos === -1) return null; + + // segment after "api" is the version ("latest", "1.4.109", etc.) + // segment after _that_ is the module name (or "index.html" if we're at the root) + return segments[apiPos + 2] ?? 'index.html'; + } catch { return null; } } From 0e881a86a897f2e72a9f6099c89a19cc59c8ac85 Mon Sep 17 00:00:00 2001 From: Matas Lauzadis Date: Sat, 21 Jun 2025 10:51:18 -0400 Subject: [PATCH 03/11] remove a comment --- docs/dokka-presets/scripts/custom-navigation-loader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dokka-presets/scripts/custom-navigation-loader.js b/docs/dokka-presets/scripts/custom-navigation-loader.js index 6d0217d3f4d..943b50452e2 100644 --- a/docs/dokka-presets/scripts/custom-navigation-loader.js +++ b/docs/dokka-presets/scripts/custom-navigation-loader.js @@ -11,7 +11,7 @@ function extractModulePath(href) { try { const segments = new URL(href, window.location.origin) .pathname - .split('/') // break the path + .split('/') .filter(Boolean); // drop empty parts // the URL pattern is always ".../kotlin/api//..." From 0d6bc56798bc5325ca64445230647367e066f6d1 Mon Sep 17 00:00:00 2001 From: Matas Lauzadis Date: Sat, 21 Jun 2025 10:51:40 -0400 Subject: [PATCH 04/11] rename --- docs/dokka-presets/scripts/custom-navigation-loader.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dokka-presets/scripts/custom-navigation-loader.js b/docs/dokka-presets/scripts/custom-navigation-loader.js index 943b50452e2..4901a09b034 100644 --- a/docs/dokka-presets/scripts/custom-navigation-loader.js +++ b/docs/dokka-presets/scripts/custom-navigation-loader.js @@ -15,12 +15,12 @@ function extractModulePath(href) { .filter(Boolean); // drop empty parts // the URL pattern is always ".../kotlin/api//..." - const apiPos = segments.indexOf('api'); - if (apiPos === -1) return null; + const apiIndex = segments.indexOf('api'); + if (apiIndex === -1) return null; // segment after "api" is the version ("latest", "1.4.109", etc.) // segment after _that_ is the module name (or "index.html" if we're at the root) - return segments[apiPos + 2] ?? 'index.html'; + return segments[apiIndex + 2] ?? 'index.html'; } catch { return null; } From f45e0584bf85870d43a9389043499166ac108f2e Mon Sep 17 00:00:00 2001 From: Matas Lauzadis Date: Sat, 21 Jun 2025 11:40:18 -0400 Subject: [PATCH 05/11] Support navigation loader on localhost --- .../scripts/custom-navigation-loader.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/dokka-presets/scripts/custom-navigation-loader.js b/docs/dokka-presets/scripts/custom-navigation-loader.js index 4901a09b034..395a6d277e5 100644 --- a/docs/dokka-presets/scripts/custom-navigation-loader.js +++ b/docs/dokka-presets/scripts/custom-navigation-loader.js @@ -16,11 +16,15 @@ function extractModulePath(href) { // the URL pattern is always ".../kotlin/api//..." const apiIndex = segments.indexOf('api'); - if (apiIndex === -1) return null; - // segment after "api" is the version ("latest", "1.4.109", etc.) - // segment after _that_ is the module name (or "index.html" if we're at the root) - return segments[apiIndex + 2] ?? 'index.html'; + if (apiIndex !== -1) { + // segment after "api" is the version ("latest", "1.4.109", etc.) + // segment after _that_ is the module name (or "index.html" if we're at the root) + return segments[apiIndex + 2] ?? 'index.html'; + } + + // locally-hosted docs don't have /kotlin/api segment + return segments[0] ?? 'index.html'; } catch { return null; } From c38a2143861ab50eef6023f2afa10f265f1d4857 Mon Sep 17 00:00:00 2001 From: Matas Lauzadis Date: Sat, 21 Jun 2025 12:06:49 -0400 Subject: [PATCH 06/11] Remove all parent directory elements (`../`) from navigation --- buildSrc/src/main/kotlin/dokka-convention.gradle.kts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/main/kotlin/dokka-convention.gradle.kts b/buildSrc/src/main/kotlin/dokka-convention.gradle.kts index 0fcf9d1fc5d..585ce416c07 100644 --- a/buildSrc/src/main/kotlin/dokka-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/dokka-convention.gradle.kts @@ -97,11 +97,15 @@ tasks.register("trimNavigationFiles") { val navigation = moduleDir.resolve("navigation.html").toFile() val doc = Jsoup.parse(navigation) - // Remove a single parent directory from all navigation links + // Remove all parent directory elements from all navigation links doc.select("a[href^=../]").forEach { anchor -> - val originalHref = anchor.attr("href") - val updatedHref = originalHref.removePrefix("../") - anchor.attr("href", updatedHref) + var href = anchor.attr("href") + + while (href.startsWith("../")) { + href = href.removePrefix("../") + } + + anchor.attr("href", href) } // Trim side menus From 0a1520fedef5ccc8d4c11f0780ae936b2a9a022e Mon Sep 17 00:00:00 2001 From: Matas Lauzadis Date: Sat, 21 Jun 2025 12:09:16 -0400 Subject: [PATCH 07/11] Update a comment --- docs/dokka-presets/scripts/custom-navigation-loader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dokka-presets/scripts/custom-navigation-loader.js b/docs/dokka-presets/scripts/custom-navigation-loader.js index 395a6d277e5..9c14653826d 100644 --- a/docs/dokka-presets/scripts/custom-navigation-loader.js +++ b/docs/dokka-presets/scripts/custom-navigation-loader.js @@ -14,7 +14,7 @@ function extractModulePath(href) { .split('/') .filter(Boolean); // drop empty parts - // the URL pattern is always ".../kotlin/api//..." + // the URL pattern is always ".../kotlin/api//..." in production const apiIndex = segments.indexOf('api'); if (apiIndex !== -1) { From 66ec97b37b672f449afbae5923a9a8270026a2f7 Mon Sep 17 00:00:00 2001 From: Matas Lauzadis Date: Sat, 21 Jun 2025 12:57:34 -0400 Subject: [PATCH 08/11] TimeStream Query is no longer accepting new customers, remove E2E test --- .../e2eTest/src/EndpointDiscoveryTest.kt | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100644 services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt diff --git a/services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt b/services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt deleted file mode 100644 index 883278f1891..00000000000 --- a/services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ -package aws.sdk.kotlin.services.timestreamquery - -import aws.sdk.kotlin.services.timestreamquery.model.DescribeEndpointsResponse -import aws.sdk.kotlin.services.timestreamquery.model.ListScheduledQueriesResponse -import aws.smithy.kotlin.runtime.client.ResponseInterceptorContext -import aws.smithy.kotlin.runtime.client.operationName -import aws.smithy.kotlin.runtime.http.interceptors.HttpInterceptor -import aws.smithy.kotlin.runtime.http.request.HttpRequest -import aws.smithy.kotlin.runtime.http.response.HttpResponse -import kotlinx.coroutines.runBlocking -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotNull -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class EndpointDiscoveryTest { - @Test - fun testEndpointDiscovery() = runBlocking { - val operationLog = mutableListOf() - var discoveredHost: String? = null - - val interceptor = object : HttpInterceptor { - override fun readAfterExecution( - context: ResponseInterceptorContext, - ) { - operationLog += context.executionContext.operationName!! - - when (val response = context.response.getOrNull()) { - is DescribeEndpointsResponse -> discoveredHost = response.endpoints!!.first().address - - is ListScheduledQueriesResponse -> { - // Make sure every request _except_ DescribeEndpoints uses the discovered endpoint - assertNotNull(discoveredHost) - assertEquals(discoveredHost, context.protocolRequest!!.url.host.toString()) - } - - else -> error("Unexpected response ${context.response}") - } - } - } - - TimestreamQueryClient { - region = "us-west-2" - interceptors += interceptor - }.use { tsq -> - tsq.listScheduledQueries() - - // Have to discover the endpoint the first time - assertEquals(listOf("DescribeEndpoints", "ListScheduledQueries"), operationLog) - operationLog.clear() - - tsq.listScheduledQueries() - - // Don't have to discover the endpoint again because it's cached - assertEquals(listOf("ListScheduledQueries"), operationLog) - } - } -} From 3acc92bdb271dd45daddc38486e81b67ea59b21b Mon Sep 17 00:00:00 2001 From: Matas Lauzadis Date: Sat, 21 Jun 2025 13:20:58 -0400 Subject: [PATCH 09/11] TimeStream **Write** is no longer accepting new customers, remove E2E test --- .../e2eTest/src/EndpointDiscoveryTest.kt | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100644 services/timestreamwrite/e2eTest/src/EndpointDiscoveryTest.kt diff --git a/services/timestreamwrite/e2eTest/src/EndpointDiscoveryTest.kt b/services/timestreamwrite/e2eTest/src/EndpointDiscoveryTest.kt deleted file mode 100644 index 8beaae424e5..00000000000 --- a/services/timestreamwrite/e2eTest/src/EndpointDiscoveryTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ -package aws.sdk.kotlin.services.timestreamwrite - -import aws.sdk.kotlin.services.timestreamwrite.model.DescribeEndpointsResponse -import aws.sdk.kotlin.services.timestreamwrite.model.ListDatabasesResponse -import aws.smithy.kotlin.runtime.client.ResponseInterceptorContext -import aws.smithy.kotlin.runtime.client.operationName -import aws.smithy.kotlin.runtime.http.interceptors.HttpInterceptor -import aws.smithy.kotlin.runtime.http.request.HttpRequest -import aws.smithy.kotlin.runtime.http.response.HttpResponse -import kotlinx.coroutines.runBlocking -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotNull -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class EndpointDiscoveryTest { - @Test - fun testEndpointDiscovery() = runBlocking { - val operationLog = mutableListOf() - var discoveredHost: String? = null - - val interceptor = object : HttpInterceptor { - override fun readAfterExecution( - context: ResponseInterceptorContext, - ) { - operationLog += context.executionContext.operationName!! - - when (val response = context.response.getOrNull()) { - is DescribeEndpointsResponse -> discoveredHost = response.endpoints!!.first().address - - is ListDatabasesResponse -> { - // Make sure every request _except_ DescribeEndpoints uses the discovered endpoint - assertNotNull(discoveredHost) - assertEquals(discoveredHost, context.protocolRequest!!.url.host.toString()) - } - - else -> error("Unexpected response ${context.response}") - } - } - } - - TimestreamWriteClient { - region = "us-west-2" - interceptors += interceptor - }.use { tsw -> - tsw.listDatabases() - - // Have to discover the endpoint the first time - assertEquals(listOf("DescribeEndpoints", "ListDatabases"), operationLog) - operationLog.clear() - - tsw.listDatabases() - - // Don't have to discover the endpoint again because it's cached - assertEquals(listOf("ListDatabases"), operationLog) - } - } -} From 958657f38700f65435f019eea62041b7784c40f2 Mon Sep 17 00:00:00 2001 From: Matas Lauzadis Date: Sat, 21 Jun 2025 13:21:04 -0400 Subject: [PATCH 10/11] Revert "TimeStream Query is no longer accepting new customers, remove E2E test" This reverts commit 66ec97b37b672f449afbae5923a9a8270026a2f7. --- .../e2eTest/src/EndpointDiscoveryTest.kt | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt diff --git a/services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt b/services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt new file mode 100644 index 00000000000..883278f1891 --- /dev/null +++ b/services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt @@ -0,0 +1,63 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package aws.sdk.kotlin.services.timestreamquery + +import aws.sdk.kotlin.services.timestreamquery.model.DescribeEndpointsResponse +import aws.sdk.kotlin.services.timestreamquery.model.ListScheduledQueriesResponse +import aws.smithy.kotlin.runtime.client.ResponseInterceptorContext +import aws.smithy.kotlin.runtime.client.operationName +import aws.smithy.kotlin.runtime.http.interceptors.HttpInterceptor +import aws.smithy.kotlin.runtime.http.request.HttpRequest +import aws.smithy.kotlin.runtime.http.response.HttpResponse +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotNull +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class EndpointDiscoveryTest { + @Test + fun testEndpointDiscovery() = runBlocking { + val operationLog = mutableListOf() + var discoveredHost: String? = null + + val interceptor = object : HttpInterceptor { + override fun readAfterExecution( + context: ResponseInterceptorContext, + ) { + operationLog += context.executionContext.operationName!! + + when (val response = context.response.getOrNull()) { + is DescribeEndpointsResponse -> discoveredHost = response.endpoints!!.first().address + + is ListScheduledQueriesResponse -> { + // Make sure every request _except_ DescribeEndpoints uses the discovered endpoint + assertNotNull(discoveredHost) + assertEquals(discoveredHost, context.protocolRequest!!.url.host.toString()) + } + + else -> error("Unexpected response ${context.response}") + } + } + } + + TimestreamQueryClient { + region = "us-west-2" + interceptors += interceptor + }.use { tsq -> + tsq.listScheduledQueries() + + // Have to discover the endpoint the first time + assertEquals(listOf("DescribeEndpoints", "ListScheduledQueries"), operationLog) + operationLog.clear() + + tsq.listScheduledQueries() + + // Don't have to discover the endpoint again because it's cached + assertEquals(listOf("ListScheduledQueries"), operationLog) + } + } +} From 56f5030f197be82c307c98b808f36bf899d79462 Mon Sep 17 00:00:00 2001 From: Matas Lauzadis Date: Sat, 21 Jun 2025 14:50:25 -0400 Subject: [PATCH 11/11] Revert "Revert "TimeStream Query is no longer accepting new customers, remove E2E test"" This reverts commit 958657f38700f65435f019eea62041b7784c40f2. --- .../e2eTest/src/EndpointDiscoveryTest.kt | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100644 services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt diff --git a/services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt b/services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt deleted file mode 100644 index 883278f1891..00000000000 --- a/services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ -package aws.sdk.kotlin.services.timestreamquery - -import aws.sdk.kotlin.services.timestreamquery.model.DescribeEndpointsResponse -import aws.sdk.kotlin.services.timestreamquery.model.ListScheduledQueriesResponse -import aws.smithy.kotlin.runtime.client.ResponseInterceptorContext -import aws.smithy.kotlin.runtime.client.operationName -import aws.smithy.kotlin.runtime.http.interceptors.HttpInterceptor -import aws.smithy.kotlin.runtime.http.request.HttpRequest -import aws.smithy.kotlin.runtime.http.response.HttpResponse -import kotlinx.coroutines.runBlocking -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotNull -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class EndpointDiscoveryTest { - @Test - fun testEndpointDiscovery() = runBlocking { - val operationLog = mutableListOf() - var discoveredHost: String? = null - - val interceptor = object : HttpInterceptor { - override fun readAfterExecution( - context: ResponseInterceptorContext, - ) { - operationLog += context.executionContext.operationName!! - - when (val response = context.response.getOrNull()) { - is DescribeEndpointsResponse -> discoveredHost = response.endpoints!!.first().address - - is ListScheduledQueriesResponse -> { - // Make sure every request _except_ DescribeEndpoints uses the discovered endpoint - assertNotNull(discoveredHost) - assertEquals(discoveredHost, context.protocolRequest!!.url.host.toString()) - } - - else -> error("Unexpected response ${context.response}") - } - } - } - - TimestreamQueryClient { - region = "us-west-2" - interceptors += interceptor - }.use { tsq -> - tsq.listScheduledQueries() - - // Have to discover the endpoint the first time - assertEquals(listOf("DescribeEndpoints", "ListScheduledQueries"), operationLog) - operationLog.clear() - - tsq.listScheduledQueries() - - // Don't have to discover the endpoint again because it's cached - assertEquals(listOf("ListScheduledQueries"), operationLog) - } - } -}