Skip to content

Commit

Permalink
Merge pull request #214 from hmrc/BDOG-2315
Browse files Browse the repository at this point in the history
BDOG-2315: adds performance test job results and fallback for old builds
  • Loading branch information
Tyrpix authored Nov 21, 2024
2 parents 4d4a26c + 8748686 commit 0081c70
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,20 @@ class JenkinsConnector @Inject()(

def getTestJobResults(jenkinsUrl: String)(using ExecutionContext): Future[Option[LatestBuild.TestJobResults]] =
// Prevents Server-Side Request Forgery
assert(jenkinsUrl.startsWith(config.BuildJobs.baseUrl), s"$jenkinsUrl was requested for invalid host")

given HeaderCarrier = HeaderCarrier()
assert(
List(config.BuildJobs.baseUrl, config.PerformanceJobs.baseUrl).exists(jenkinsUrl.startsWith),
s"$jenkinsUrl was requested for invalid host"
)

val url = url"${jenkinsUrl}lastBuild/artifact/test-results.json"
given HeaderCarrier = HeaderCarrier()

val url = url"${jenkinsUrl}lastBuild/artifact/test-results.json"
val authHeader = if url.toString.startsWith("https://build.tax.service.gov.uk") then config.BuildJobs.authorizationHeader
else config.PerformanceJobs.authorizationHeader

httpClientV2
.get(url)
.setHeader("Authorization" -> config.BuildJobs.authorizationHeader)
.setHeader("Authorization" -> authHeader)
.execute[Option[LatestBuild.TestJobResults]]
.recoverWithLogging(url)

Expand Down Expand Up @@ -255,19 +260,19 @@ object JenkinsConnector:
Format.of[String].inmap(parse, _.asString)

case class TestJobResults(
securityAlerts : String,
accessibilityViolations: Option[String]
numAccessibilityViolations: Option[Int],
numSecurityAlerts : Option[Int]
)

object TestJobResults:
val apiWrites: Writes[TestJobResults] =
( (__ \ "securityAlerts" ).write[String]
~ (__ \ "accessibilityViolations").writeNullable[String]
( (__ \ "numAccessibilityViolations").writeNullable[Int]
~ (__ \ "numSecurityAlerts" ).writeNullable[Int]
)(t => Tuple.fromProductTyped(t))

val jenkinsReads: Reads[TestJobResults] =
( (__ \ "securityAlerts" ).read[String]
~ (__ \ "accessibilityViolations").readNullable[String]
( (__ \ "accessibilityViolations").readNullable[String].map(_.flatMap(_.toIntOption))
~ (__ \ "securityAlerts" ).readNullable[String].map(_.flatMap(_.toIntOption))
)(TestJobResults.apply _)

val apiWrites: Writes[LatestBuild] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ object JenkinsJobsPersistence:
val mongoFormat: Format[Job] =

given OFormat[JenkinsConnector.LatestBuild.TestJobResults] =
( (__ \ "securityAlerts" ).format[String]
~ (__ \ "accessibilityViolations").formatNullable[String]
( (__ \ "numAccessibilityViolations").formatNullable[Int]
~ (__ \ "numSecurityAlerts" ).formatNullable[Int]
)(JenkinsConnector.LatestBuild.TestJobResults.apply, t => Tuple.fromProductTyped(t))

given OFormat[JenkinsConnector.LatestBuild] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
package uk.gov.hmrc.teamsandrepositories.services

import uk.gov.hmrc.teamsandrepositories.connectors.{BuildDeployApiConnector, JenkinsConnector}
import uk.gov.hmrc.teamsandrepositories.connectors.JenkinsConnector.LatestBuild.TestJobResults
import uk.gov.hmrc.teamsandrepositories.persistence.{JenkinsJobsPersistence, RepositoriesPersistence}
import uk.gov.hmrc.teamsandrepositories.models.RepoType

import cats.implicits._

import cats.implicits.*
import javax.inject.{Inject, Singleton}
import scala.concurrent.{ExecutionContext, Future}

Expand All @@ -34,6 +34,14 @@ class JenkinsReloadService @Inject()(
):

private val RepoNameRegex = """.*hmrc/([^/]+)\.git""".r

private def extractTestJobResults(description: String): Option[TestJobResults] =
val securityAlerts = """Security alerts: (\d+)""" .r.findFirstMatchIn(description).map(_.group(1).toInt)
val accessibilityIssues = """Accessibility issues: (\d+)""".r.findFirstMatchIn(description).map(_.group(1).toInt)

if securityAlerts.isEmpty && accessibilityIssues.isEmpty then None
else Some(TestJobResults(numAccessibilityViolations = accessibilityIssues, numSecurityAlerts = securityAlerts))

def updateBuildAndPerformanceJobs()(using ExecutionContext): Future[Unit] =
for
buildJobs <- jenkinsConnector.findBuildJobs()
Expand All @@ -46,9 +54,9 @@ class JenkinsReloadService @Inject()(
JenkinsJobsPersistence.Job(
repoName = repo.name
, jobName = job.name
, jobType = if job.name.endsWith("-pr-builder") then JenkinsJobsPersistence.JobType.PullRequest
else if repo.repoType == RepoType.Test then JenkinsJobsPersistence.JobType.Test
else JenkinsJobsPersistence.JobType.Job
, jobType = if job.name.endsWith("-pr-builder") then JenkinsJobsPersistence.JobType.PullRequest
else if repo.repoType == RepoType.Test then JenkinsJobsPersistence.JobType.Test
else JenkinsJobsPersistence.JobType.Job
, testType = repo.testType
, jenkinsUrl = job.jenkinsUrl
, repoType = Some(repo.repoType)
Expand All @@ -57,10 +65,15 @@ class JenkinsReloadService @Inject()(
))
}
updatedJobs <- jobs.foldLeftM[Future, List[JenkinsJobsPersistence.Job]](List.empty): (acc, job) =>
if job.jobType == JenkinsJobsPersistence.JobType.Test then
jenkinsConnector.getTestJobResults(job.jenkinsUrl).map: testJobResults =>
acc :+ job.copy(latestBuild = job.latestBuild.map(_.copy(testJobResults = testJobResults)))
else Future.successful(acc :+ job)
job.jobType match
case JenkinsJobsPersistence.JobType.Test =>
jenkinsConnector.getTestJobResults(job.jenkinsUrl).map:
case Some(results) => acc :+ job.copy(latestBuild = job.latestBuild.map(_.copy(testJobResults = Some(results))))
case None => // used for old builds that publish test results in the description instead of as json
val extractedResults = job.latestBuild.flatMap(_.description).flatMap(extractTestJobResults)
acc :+ job.copy(latestBuild = job.latestBuild.map(_.copy(testJobResults = extractedResults)))
case _ =>
Future.successful(acc :+ job)
pipelineDetails <- buildDeployApiConnector
.getBuildJobsDetails()
.map(_.map(x => (x.repoName, x.buildJobs.find(_.jobType == BuildDeployApiConnector.JobType.Pipeline))))
Expand Down

0 comments on commit 0081c70

Please sign in to comment.