From 25c8a01052a07a525fc88087f6cff767e04b58d4 Mon Sep 17 00:00:00 2001 From: Craig Atkinson Date: Mon, 1 Apr 2024 08:36:25 -0500 Subject: [PATCH] Add redirect to latest test run in badge (#1217) --- README.md | 10 +-- .../src/main/kotlin/projektor/Application.kt | 2 +- .../projektor/route/RepositoryRoutes.kt | 36 ++++++++- .../RepositoryLatestRunApplicationTest.kt | 81 +++++++++++++++++++ 4 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 server/server-app/src/test/kotlin/projektor/repository/testrun/RepositoryLatestRunApplicationTest.kt diff --git a/README.md b/README.md index 52c64a6c7..476397b1d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Projektor -| Project | Tests | Coverage | -|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Server & Gradle plugin | [![Test results](https://projektorlive.herokuapp.com/repo/craigatk/projektor/badge/tests)](https://projektorlive.herokuapp.com/repository/craigatk/projektor/) | [![Code coverage percentage](https://projektorlive.herokuapp.com/repo/craigatk/projektor/badge/coverage)](https://projektorlive.herokuapp.com/repository/craigatk/projektor/coverage) | -| UI | [![Test results](https://projektorlive.herokuapp.com/repo/craigatk/projektor/project/ui-jest/badge/tests)](https://projektorlive.herokuapp.com/repository/craigatk/projektor/project/ui-jest/) | [![Code coverage percentage](https://projektorlive.herokuapp.com/repo/craigatk/projektor/project/ui-jest/badge/coverage)](https://projektorlive.herokuapp.com/repository/craigatk/projektor/project/ui-jest/coverage) | -| Node publisher | [![Test results](https://projektorlive.herokuapp.com/repo/craigatk/projektor/project/node-script/badge/tests)](https://projektorlive.herokuapp.com/repository/craigatk/projektor/project/node-script/) | [![Code coverage percentage](https://projektorlive.herokuapp.com/repo/craigatk/projektor/project/node-script/badge/coverage)](https://projektorlive.herokuapp.com/repository/craigatk/projektor/project/node-script/coverage) | +| Project | Tests | Coverage | +|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Server & Gradle plugin | [![Test results](https://projektorlive.herokuapp.com/repo/craigatk/projektor/badge/tests)](https://projektorlive.herokuapp.com/repo/craigatk/projektor/run/latest) | [![Code coverage percentage](https://projektorlive.herokuapp.com/repo/craigatk/projektor/badge/coverage)](https://projektorlive.herokuapp.com/repository/craigatk/projektor/coverage) | +| UI | [![Test results](https://projektorlive.herokuapp.com/repo/craigatk/projektor/project/ui-jest/badge/tests)](https://projektorlive.herokuapp.com/repo/craigatk/projektor/project/ui-jest/run/latest) | [![Code coverage percentage](https://projektorlive.herokuapp.com/repo/craigatk/projektor/project/ui-jest/badge/coverage)](https://projektorlive.herokuapp.com/repository/craigatk/projektor/project/ui-jest/coverage) | +| Node publisher | [![Test results](https://projektorlive.herokuapp.com/repo/craigatk/projektor/project/node-script/badge/tests)](https://projektorlive.herokuapp.com/repo/craigatk/projektor/project/node-script/run/latest) | [![Code coverage percentage](https://projektorlive.herokuapp.com/repo/craigatk/projektor/project/node-script/badge/coverage)](https://projektorlive.herokuapp.com/repository/craigatk/projektor/project/node-script/coverage) | For detailed instructions to get started with Projektor, please see the full project documentation at https://projektor.dev diff --git a/server/server-app/src/main/kotlin/projektor/Application.kt b/server/server-app/src/main/kotlin/projektor/Application.kt index 68e678c60..3db57ae07 100644 --- a/server/server-app/src/main/kotlin/projektor/Application.kt +++ b/server/server-app/src/main/kotlin/projektor/Application.kt @@ -212,7 +212,7 @@ fun Application.main(meterRegistry: MeterRegistry? = null) { organization(organizationCoverageService) performance(performanceResultsService) previousRuns(previousTestRunService) - repository(repositoryTestRunService) + repository(previousTestRunService, repositoryTestRunService) repositoryCoverage(repositoryCoverageService) repositoryPerformance(repositoryPerformanceService) results(testResultsService, groupedTestResultsService, testResultsProcessingService, authService, metricRegistry, metricsService) diff --git a/server/server-app/src/main/kotlin/projektor/route/RepositoryRoutes.kt b/server/server-app/src/main/kotlin/projektor/route/RepositoryRoutes.kt index 217db08b6..78d8e3698 100644 --- a/server/server-app/src/main/kotlin/projektor/route/RepositoryRoutes.kt +++ b/server/server-app/src/main/kotlin/projektor/route/RepositoryRoutes.kt @@ -3,15 +3,18 @@ package projektor.route import io.ktor.http.HttpStatusCode import io.ktor.server.application.ApplicationCall import io.ktor.server.application.call -import io.ktor.server.response.respond +import io.ktor.server.response.* import io.ktor.server.routing.Route import io.ktor.server.routing.get import io.ktor.server.util.getOrFail +import projektor.compare.PreviousTestRunService import projektor.repository.testrun.RepositoryTestRunService +import projektor.server.api.repository.BranchSearch import projektor.server.api.repository.BranchType import projektor.server.api.repository.RepositoryFlakyTests fun Route.repository( + previousTestRunService: PreviousTestRunService, repositoryTestRunService: RepositoryTestRunService ) { get("/repo/{orgPart}/{repoPart}/timeline") { @@ -106,4 +109,35 @@ fun Route.repository( call ) } + + get("/repo/{orgPart}/{repoPart}/run/latest") { + val orgPart = call.parameters.getOrFail("orgPart") + val repoPart = call.parameters.getOrFail("repoPart") + val fullRepoName = "$orgPart/$repoPart" + + val latestTestRun = previousTestRunService.findMostRecentRun( + fullRepoName, + null, + BranchSearch(branchType = BranchType.MAINLINE) + ) + + latestTestRun?.let { call.respondRedirect("/tests/${latestTestRun.publicId.id}", permanent = false) } + ?: call.respond(HttpStatusCode.NoContent) + } + + get("/repo/{orgPart}/{repoPart}/project/{projectName}/run/latest") { + val orgPart = call.parameters.getOrFail("orgPart") + val repoPart = call.parameters.getOrFail("repoPart") + val projectName = call.parameters.getOrFail("projectName") + val fullRepoName = "$orgPart/$repoPart" + + val latestTestRun = previousTestRunService.findMostRecentRun( + fullRepoName, + projectName, + BranchSearch(branchType = BranchType.MAINLINE) + ) + + latestTestRun?.let { call.respondRedirect("/tests/${latestTestRun.publicId.id}", permanent = false) } + ?: call.respond(HttpStatusCode.NoContent) + } } diff --git a/server/server-app/src/test/kotlin/projektor/repository/testrun/RepositoryLatestRunApplicationTest.kt b/server/server-app/src/test/kotlin/projektor/repository/testrun/RepositoryLatestRunApplicationTest.kt new file mode 100644 index 000000000..7c06d8fe6 --- /dev/null +++ b/server/server-app/src/test/kotlin/projektor/repository/testrun/RepositoryLatestRunApplicationTest.kt @@ -0,0 +1,81 @@ +package projektor.repository.testrun + +import io.ktor.http.* +import io.ktor.server.testing.* +import org.apache.commons.lang3.RandomStringUtils +import org.junit.jupiter.api.Test +import projektor.ApplicationTestCase +import projektor.incomingresults.randomPublicId +import strikt.api.expectThat +import strikt.assertions.isEqualTo + +class RepositoryLatestRunApplicationTest : ApplicationTestCase() { + @Test + fun `when repo with no project has test run should redirect to latest test run`() { + val orgName = RandomStringUtils.randomAlphabetic(12) + val repoName = "$orgName/repo" + val projectName = null + + val olderRunPublicId = randomPublicId() + val newerRunPublicId = randomPublicId() + + withTestApplication(::createTestApplication) { + handleRequest(HttpMethod.Get, "/repo/$repoName/run/latest") { + testRunDBGenerator.createSimpleTestRunInRepo(olderRunPublicId, repoName, true, projectName) + testRunDBGenerator.createSimpleTestRunInRepo(newerRunPublicId, repoName, true, projectName) + }.apply { + expectThat(response.status()).isEqualTo(HttpStatusCode.Found) + + expectThat(response.headers["Location"]).isEqualTo("/tests/$newerRunPublicId") + } + } + } + + @Test + fun `when repo with with project has test run should redirect to latest test run`() { + val orgName = RandomStringUtils.randomAlphabetic(12) + val repoName = "$orgName/repo" + val projectName = "my-proj" + + val olderRunPublicId = randomPublicId() + val newerRunPublicId = randomPublicId() + + withTestApplication(::createTestApplication) { + handleRequest(HttpMethod.Get, "/repo/$repoName/project/$projectName/run/latest") { + testRunDBGenerator.createSimpleTestRunInRepo(olderRunPublicId, repoName, true, projectName) + testRunDBGenerator.createSimpleTestRunInRepo(newerRunPublicId, repoName, true, projectName) + }.apply { + expectThat(response.status()).isEqualTo(HttpStatusCode.Found) + + expectThat(response.headers["Location"]).isEqualTo("/tests/$newerRunPublicId") + } + } + } + + @Test + fun `when repo with no project has no test runs should return no-content response`() { + val orgName = RandomStringUtils.randomAlphabetic(12) + val repoName = "$orgName/repo" + + withTestApplication(::createTestApplication) { + handleRequest(HttpMethod.Get, "/repo/$repoName/run/latest") { + }.apply { + expectThat(response.status()).isEqualTo(HttpStatusCode.NoContent) + } + } + } + + @Test + fun `when repo with project has no test runs should return no-content response`() { + val orgName = RandomStringUtils.randomAlphabetic(12) + val repoName = "$orgName/repo" + val projectName = "my-proj" + + withTestApplication(::createTestApplication) { + handleRequest(HttpMethod.Get, "/repo/$repoName/project/$projectName/run/latest") { + }.apply { + expectThat(response.status()).isEqualTo(HttpStatusCode.NoContent) + } + } + } +}