From fbbd3da4cfe73fcbaa3cb4cf8ff7356a77a78473 Mon Sep 17 00:00:00 2001 From: "Andrey.Kokorev" Date: Fri, 29 Nov 2024 17:03:13 +0100 Subject: [PATCH 1/5] Return links to a new UI which is now a default. --- .../rest/coroutines/implementation.kt | 66 +++---------------- .../teamcity/rest/coroutines/webLinks.kt | 38 +++++++++++ 2 files changed, 48 insertions(+), 56 deletions(-) create mode 100644 teamcity-rest-client-impl/src/main/kotlin/org/jetbrains/teamcity/rest/coroutines/webLinks.kt diff --git a/teamcity-rest-client-impl/src/main/kotlin/org/jetbrains/teamcity/rest/coroutines/implementation.kt b/teamcity-rest-client-impl/src/main/kotlin/org/jetbrains/teamcity/rest/coroutines/implementation.kt index e5a03e9..51c88c7 100644 --- a/teamcity-rest-client-impl/src/main/kotlin/org/jetbrains/teamcity/rest/coroutines/implementation.kt +++ b/teamcity-rest-client-impl/src/main/kotlin/org/jetbrains/teamcity/rest/coroutines/implementation.kt @@ -23,7 +23,6 @@ import retrofit2.converter.gson.GsonConverterFactory import java.io.* import java.net.HttpURLConnection import java.net.URI -import java.net.URLEncoder import java.time.Duration import java.time.Instant import java.time.ZoneOffset @@ -224,6 +223,8 @@ internal class TeamCityCoroutinesInstanceImpl( .cookieJar(nodeSelector.toCookieJar()) .build() + internal val webLinks = WebLinks(serverUrl) + internal val service = Retrofit.Builder() .client(client) .baseUrl("$serverUrl$serverUrlBase") @@ -1043,14 +1044,10 @@ private class ProjectImpl( if (isFullBean) runBlocking { "Project(id=$idString,name=${getName()})" } else "Project(id=$idString)" override fun getHomeUrl(branch: String?): String = - getUserUrlPage(instance.serverUrl, "project.html", projectId = id, branch = branch) + instance.webLinks.projectPage(id, branch = branch) - override fun getTestHomeUrl(testId: TestId): String = getUserUrlPage( - instance.serverUrl, "project.html", - projectId = id, - testNameId = testId, - tab = "testDetails" - ) + override fun getTestHomeUrl(testId: TestId): String = + instance.webLinks.testHistoryPage(testId, id) override fun getMutes(): Flow = lazyPagingFlow( instance = instance, @@ -1179,9 +1176,8 @@ private class BuildConfigurationImpl( override fun toString(): String = if (isFullBean) runBlocking { "BuildConfiguration(id=$idString,name=${getName()})" } else "BuildConfiguration(id=$idString)" - override fun getHomeUrl(branch: String?): String = getUserUrlPage( - instance.serverUrl, "viewType.html", buildTypeId = id, branch = branch - ) + override fun getHomeUrl(branch: String?): String = + instance.webLinks.buildConfigurationPage(id, branch = branch) override val id = BuildConfigurationId(idString) private val name = SuspendingLazy { notnull { it.name } } @@ -1332,12 +1328,7 @@ private class ChangeImpl( override fun getHomeUrl( specificBuildConfigurationId: BuildConfigurationId?, includePersonalBuilds: Boolean? - ): String = getUserUrlPage( - instance.serverUrl, "viewModification.html", - modId = id, - buildTypeId = specificBuildConfigurationId, - personal = includePersonalBuilds - ) + ): String = instance.webLinks.changePage(id, specificBuildConfigurationId, includePersonalBuilds) override suspend fun firstBuilds(): List = instance.service @@ -1436,10 +1427,7 @@ private class UserImpl( override suspend fun getName(): String? = name.getValue() - override fun getHomeUrl(): String = getUserUrlPage( - instance.serverUrl, "admin/editUser.html", - userId = id - ) + override fun getHomeUrl(): String = instance.webLinks.userPage(id) override fun toString(): String = if (isFullBean) runBlocking { "User(id=${id.stringId}, username=${getUsername()})" } else "User(id=${id.stringId})" @@ -1807,10 +1795,7 @@ private class BuildImpl( ?.map(::PropertyImpl) ?: emptyList() } - override fun getHomeUrl(): String = getUserUrlPage( - instance.serverUrl, "viewLog.html", - buildId = id - ) + override fun getHomeUrl(): String = instance.webLinks.buildPage(id) override suspend fun getStatusText(): String? = statusText.getValue() @@ -2559,37 +2544,6 @@ private fun convertToJavaRegexp(pattern: String): Regex { return pattern.replace(".", "\\.").replace("*", ".*").replace("?", ".").toRegex() } -private fun String.urlencode(): String = URLEncoder.encode(this, "UTF-8") - -private fun getUserUrlPage( - serverUrl: String, - pageName: String, - tab: String? = null, - projectId: ProjectId? = null, - buildId: BuildId? = null, - testNameId: TestId? = null, - userId: UserId? = null, - modId: ChangeId? = null, - personal: Boolean? = null, - buildTypeId: BuildConfigurationId? = null, - branch: String? = null -): String { - val params = mutableListOf() - - tab?.let { params.add("tab=" + tab.urlencode()) } - projectId?.let { params.add("projectId=" + projectId.stringId.urlencode()) } - buildId?.let { params.add("buildId=" + buildId.stringId.urlencode()) } - testNameId?.let { params.add("testNameId=" + testNameId.stringId.urlencode()) } - userId?.let { params.add("userId=" + userId.stringId.urlencode()) } - modId?.let { params.add("modId=" + modId.stringId.urlencode()) } - personal?.let { params.add("personal=" + if (personal) "true" else "false") } - buildTypeId?.let { params.add("buildTypeId=" + buildTypeId.stringId.urlencode()) } - branch?.let { params.add("branch=" + branch.urlencode()) } - - return "$serverUrl/$pageName" + - if (params.isNotEmpty()) "?${params.joinToString("&")}" else "" -} - private fun saveToFile(body: ResponseBody, file: File) { file.parentFile?.mkdirs() body.byteStream().use { input -> diff --git a/teamcity-rest-client-impl/src/main/kotlin/org/jetbrains/teamcity/rest/coroutines/webLinks.kt b/teamcity-rest-client-impl/src/main/kotlin/org/jetbrains/teamcity/rest/coroutines/webLinks.kt new file mode 100644 index 0000000..a251c6b --- /dev/null +++ b/teamcity-rest-client-impl/src/main/kotlin/org/jetbrains/teamcity/rest/coroutines/webLinks.kt @@ -0,0 +1,38 @@ +package org.jetbrains.teamcity.rest.coroutines + +import org.jetbrains.teamcity.rest.* +import java.net.URLEncoder + +class WebLinks(private val serverUrl: String) { + fun buildConfigurationPage(id: BuildConfigurationId, branch: String? = null) = + "$serverUrl/buildConfiguration/$id" + if (branch != null) "?${branch.urlencode()}" else "" + + fun buildPage(id: BuildId, configurationId: BuildConfigurationId? = null) = + if (configurationId != null) { + "$serverUrl/buildConfiguration/$configurationId/$id" + } else { + "$serverUrl/build/$id" + } + + fun changePage(id: ChangeId, configurationId: BuildConfigurationId? = null, personal: Boolean? = null): String { + val params = mutableListOf() + if (configurationId != null) + params.add("buildTypeId=$configurationId") + if (personal != null) + params.add("personal=$personal") + + return "$serverUrl/change/$id" + + if (params.isNotEmpty()) params.joinToString("&", prefix = "?") else "" + } + + fun projectPage(id: ProjectId, branch: String? = null) = + "$serverUrl/project/$id" + if (branch != null) "?${branch.urlencode()}" else "" + + fun testHistoryPage(id: TestId, projectId: ProjectId) = + "$serverUrl/test/$id?currentProjectId=$projectId" + + fun userPage(id: UserId) = + "$serverUrl/admin/editUser.html?userId=$id" +} + +private fun String.urlencode(): String = URLEncoder.encode(this, "UTF-8") From e5f0c66025aac9bc37fd909042084396f4882f66 Mon Sep 17 00:00:00 2001 From: "Andrey.Kokorev" Date: Mon, 2 Dec 2024 10:31:31 +0100 Subject: [PATCH 2/5] Fix tests --- .../org/jetbrains/teamcity/rest/BuildConfigurationTest.kt | 4 ++-- .../src/test/kotlin/org/jetbrains/teamcity/rest/BuildTest.kt | 2 +- .../src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt | 4 ++-- .../test/kotlin/org/jetbrains/teamcity/rest/ProjectTest.kt | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/BuildConfigurationTest.kt b/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/BuildConfigurationTest.kt index 557228d..a73f34f 100644 --- a/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/BuildConfigurationTest.kt +++ b/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/BuildConfigurationTest.kt @@ -29,7 +29,7 @@ class BuildConfigurationTest { fun `webUrl with default parameters`() { val conf = publicInstance().buildConfiguration(changesBuildConfiguration) assertEquals( - "$publicInstanceUrl/viewType.html?buildTypeId=${changesBuildConfiguration.stringId}", + "$publicInstanceUrl/buildConfiguration/${changesBuildConfiguration.stringId}", conf.getHomeUrl()) } @@ -37,7 +37,7 @@ class BuildConfigurationTest { fun `webUrl with branch`() { val conf = publicInstance().buildConfiguration(changesBuildConfiguration) assertEquals( - "$publicInstanceUrl/viewType.html?buildTypeId=${changesBuildConfiguration.stringId}&branch=%3Cdefault%3E", + "$publicInstanceUrl/buildConfiguration/${changesBuildConfiguration.stringId}?branch=%3Cdefault%3E", conf.getHomeUrl(branch = "")) } diff --git a/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/BuildTest.kt b/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/BuildTest.kt index 8b296fb..a3c071c 100644 --- a/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/BuildTest.kt +++ b/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/BuildTest.kt @@ -141,7 +141,7 @@ class BuildTest { .limitResults(1) .all().first() - assertEquals("$publicInstanceUrl/viewLog.html?buildId=${build.id.stringId}", build.getHomeUrl()) + assertEquals("$publicInstanceUrl/build/${build.id.stringId}", build.getHomeUrl()) } @Test diff --git a/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt b/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt index d073074..7d05589 100644 --- a/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt +++ b/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt @@ -43,11 +43,11 @@ class ChangeTest { build!!.changes.first() } assertEquals( - "$publicInstanceUrl/viewModification.html?modId=${change.id.stringId}", + "$publicInstanceUrl/change/${change.id.stringId}", change.getHomeUrl() ) assertEquals( - "$publicInstanceUrl/viewModification.html?modId=${change.id.stringId}&personal=true&buildTypeId=xxx", + "$publicInstanceUrl/change/${change.id.stringId}&personal=true&buildTypeId=xxx", change.getHomeUrl(specificBuildConfigurationId = BuildConfigurationId("xxx"), includePersonalBuilds = true) ) } diff --git a/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ProjectTest.kt b/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ProjectTest.kt index d575cc3..7992f67 100644 --- a/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ProjectTest.kt +++ b/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ProjectTest.kt @@ -32,7 +32,7 @@ class ProjectTest { fun `webUrl with default parameters`() { val proj = publicInstance().project(reportProject) kotlin.test.assertEquals( - "$publicInstanceUrl/project.html?projectId=${reportProject.stringId}", + "$publicInstanceUrl/project/${reportProject.stringId}", proj.getHomeUrl()) } @@ -40,7 +40,7 @@ class ProjectTest { fun `webUrl with branch`() { val proj = publicInstance().project(reportProject) kotlin.test.assertEquals( - "$publicInstanceUrl/project.html?projectId=${reportProject.stringId}&branch=%3Cdefault%3E", + "$publicInstanceUrl/project/${reportProject.stringId}?branch=%3Cdefault%3E", proj.getHomeUrl(branch = "")) } From bc87d7ad437c24cac042ef3b30c711aad5cf19e4 Mon Sep 17 00:00:00 2001 From: "Andrey.Kokorev" Date: Mon, 2 Dec 2024 10:38:42 +0100 Subject: [PATCH 3/5] Fix project version, add changelog entry and add dependency on tests before publishing --- .teamcity/settings.kts | 9 +++++++-- CHANGELOG.md | 3 +++ gradle.properties | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.teamcity/settings.kts b/.teamcity/settings.kts index f39aafa..378ecb3 100644 --- a/.teamcity/settings.kts +++ b/.teamcity/settings.kts @@ -11,9 +11,9 @@ import jetbrains.buildServer.configs.kotlin.triggers.vcs project { description = "REST API client written in Kotlin" - buildType { + val buildAndTest = buildType { id("Build") - name = "Build" + name = "Build and test" triggers { vcs { branchFilter = "+:" @@ -244,6 +244,11 @@ project { dependencies { snapshot(securityCheck) { onDependencyFailure = FailureAction.FAIL_TO_START + reuseBuilds = ReuseBuilds.NO + } + snapshot(buildAndTest) { + onDependencyFailure = FailureAction.FAIL_TO_START + reuseBuilds = ReuseBuilds.SUCCESSFUL } } diff --git a/CHANGELOG.md b/CHANGELOG.md index d8da908..d6bac27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ All notable changes to teamcity-rest-client library will be documented in this file. +## [3.0.2] +- Fix web links so they don't link to deprecated pages. + ## [3.0.1] Stop using deprecated `tags` dimension to filter builds, use `tag` instead. diff --git a/gradle.properties b/gradle.properties index edd0e54..a10bfba 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -projectVersion=1.22 +projectVersion=3.0.2 From ff3fd4423e9de0b4ff7d2093bca03bd4e6644e7a Mon Sep 17 00:00:00 2001 From: "Andrey.Kokorev" Date: Mon, 2 Dec 2024 13:07:52 +0100 Subject: [PATCH 4/5] Fix bugs and test --- .../kotlin/org/jetbrains/teamcity/rest/coroutines/webLinks.kt | 4 ++-- .../src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/teamcity-rest-client-impl/src/main/kotlin/org/jetbrains/teamcity/rest/coroutines/webLinks.kt b/teamcity-rest-client-impl/src/main/kotlin/org/jetbrains/teamcity/rest/coroutines/webLinks.kt index a251c6b..163265d 100644 --- a/teamcity-rest-client-impl/src/main/kotlin/org/jetbrains/teamcity/rest/coroutines/webLinks.kt +++ b/teamcity-rest-client-impl/src/main/kotlin/org/jetbrains/teamcity/rest/coroutines/webLinks.kt @@ -5,7 +5,7 @@ import java.net.URLEncoder class WebLinks(private val serverUrl: String) { fun buildConfigurationPage(id: BuildConfigurationId, branch: String? = null) = - "$serverUrl/buildConfiguration/$id" + if (branch != null) "?${branch.urlencode()}" else "" + "$serverUrl/buildConfiguration/$id" + if (branch != null) "?branch=${branch.urlencode()}" else "" fun buildPage(id: BuildId, configurationId: BuildConfigurationId? = null) = if (configurationId != null) { @@ -26,7 +26,7 @@ class WebLinks(private val serverUrl: String) { } fun projectPage(id: ProjectId, branch: String? = null) = - "$serverUrl/project/$id" + if (branch != null) "?${branch.urlencode()}" else "" + "$serverUrl/project/$id" + if (branch != null) "?branch=${branch.urlencode()}" else "" fun testHistoryPage(id: TestId, projectId: ProjectId) = "$serverUrl/test/$id?currentProjectId=$projectId" diff --git a/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt b/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt index 7d05589..c0cc68d 100644 --- a/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt +++ b/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt @@ -47,7 +47,7 @@ class ChangeTest { change.getHomeUrl() ) assertEquals( - "$publicInstanceUrl/change/${change.id.stringId}&personal=true&buildTypeId=xxx", + "$publicInstanceUrl/change/${change.id.stringId}?personal=true&buildTypeId=xxx", change.getHomeUrl(specificBuildConfigurationId = BuildConfigurationId("xxx"), includePersonalBuilds = true) ) } From 32b9634450263e6f5c17cf2f994b5071b57de2fa Mon Sep 17 00:00:00 2001 From: "Andrey.Kokorev" Date: Mon, 2 Dec 2024 13:15:02 +0100 Subject: [PATCH 5/5] Fix test --- .../src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt b/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt index c0cc68d..855d0c3 100644 --- a/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt +++ b/teamcity-rest-client-impl/src/test/kotlin/org/jetbrains/teamcity/rest/ChangeTest.kt @@ -47,7 +47,7 @@ class ChangeTest { change.getHomeUrl() ) assertEquals( - "$publicInstanceUrl/change/${change.id.stringId}?personal=true&buildTypeId=xxx", + "$publicInstanceUrl/change/${change.id.stringId}?buildTypeId=xxx&personal=true", change.getHomeUrl(specificBuildConfigurationId = BuildConfigurationId("xxx"), includePersonalBuilds = true) ) }