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 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..163265d --- /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=${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=${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") 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..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 @@ -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}?buildTypeId=xxx&personal=true", 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 = "")) }