Skip to content

Commit

Permalink
Merge pull request #65 from hmrc/BDOG-183
Browse files Browse the repository at this point in the history
Bdog 183 Add Bobby Rules banner to Repository, Team and Team build monitor views
  • Loading branch information
colin-lamed authored May 2, 2019
2 parents a2e45fe + 000846d commit 81584bc
Show file tree
Hide file tree
Showing 33 changed files with 753 additions and 276 deletions.
122 changes: 54 additions & 68 deletions app/uk/gov/hmrc/cataloguefrontend/CatalogueController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

package uk.gov.hmrc.cataloguefrontend

import cats.implicits._
import java.time.{LocalDateTime, ZoneOffset}

import javax.inject.{Inject, Singleton}
import play.api.data.Forms._
import play.api.data.{Form, Mapping}
Expand Down Expand Up @@ -107,10 +107,10 @@ class CatalogueController @Inject()(
.map { payload =>
val serviceOwnerSaveEventData: ServiceOwnerSaveEventData = payload.as[ServiceOwnerSaveEventData]
val serviceOwnerDisplayName: String = serviceOwnerSaveEventData.displayName
val maybeTeamMember: Option[TeamMember] =
val optTeamMember: Option[TeamMember] =
readModelService.getAllUsers.find(_.displayName.getOrElse("") == serviceOwnerDisplayName)

maybeTeamMember.fold {
optTeamMember.fold {
Future.successful(NotAcceptable(toJson(s"Invalid user: $serviceOwnerDisplayName")))
} { member =>
member.username.fold(
Expand Down Expand Up @@ -230,7 +230,7 @@ class CatalogueController @Inject()(
umpMyTeamsUrl = umpMyTeamsPageUrl(team.name),
leaksFoundForTeam = leakDetectionService.teamHasLeaks(team, reposWithLeaks),
hasLeaks = leakDetectionService.hasLeaks(reposWithLeaks),
dependencies = teamDependencies.filter(_.hasOutOfDateDependencies)
teamDependencies = teamDependencies
)
)
case _ => NotFound(error_404_template())
Expand All @@ -240,7 +240,7 @@ class CatalogueController @Inject()(
def outOfDateTeamDependencies(teamName: String) = Action.async { implicit request =>
for {
teamDependencies <- serviceDependencyConnector.dependenciesForTeam(teamName)
} yield Ok(outOfDateTeamDependenciesPage(teamName, teamDependencies.filter(_.hasOutOfDateDependencies)))
} yield Ok(outOfDateTeamDependenciesPage(teamName, teamDependencies))
}

def serviceConfig(serviceName: String): Action[AnyContent] = Action.async { implicit request =>
Expand All @@ -258,65 +258,50 @@ class CatalogueController @Inject()(
def service(name: String): Action[AnyContent] = Action.async { implicit request =>
def getDeployedEnvs(
deployedToEnvs: Seq[DeploymentVO],
maybeRefEnvironments: Option[Seq[TargetEnvironment]]): Option[Seq[TargetEnvironment]] = {

val deployedEnvNames = deployedToEnvs.map(_.environmentMapping.name)

maybeRefEnvironments.map {
_
.map(e => (e.name.toLowerCase, e))
.map {
case (lwrCasedRefEnvName, refEnvironment)
if deployedEnvNames.contains(lwrCasedRefEnvName) || lwrCasedRefEnvName == "dev" =>
refEnvironment
case (_, refEnvironment) =>
refEnvironment.copy(services = Nil)
}
}

optRefEnvironments: Option[Seq[TargetEnvironment]]): Option[Seq[TargetEnvironment]] = {
val deployedEnvNames = deployedToEnvs.map(_.environmentMapping.name)

optRefEnvironments.map {
_
.map(e => (e.name.toLowerCase, e))
.map {
case (lwrCasedRefEnvName, refEnvironment)
if deployedEnvNames.contains(lwrCasedRefEnvName) || lwrCasedRefEnvName == "dev" =>
refEnvironment
case (_, refEnvironment) =>
refEnvironment.copy(services = Nil)
}
}
}

val repositoryDetailsF = teamsAndRepositoriesConnector.repositoryDetails(name)
val deploymentIndicatorsForServiceF: Future[Option[DeploymentIndicators]] =
indicatorsConnector.deploymentIndicatorsForService(name)
val serviceDeploymentInformationF: Future[Either[Throwable, ServiceDeploymentInformation]] =
deploymentsService.getWhatsRunningWhere(name)
val dependenciesF = serviceDependencyConnector.getDependencies(name)
val serviceUrlF = routeRulesService.serviceUrl(name)
val serviceRoutesF = routeRulesService.serviceRoutes(name)

for {
service <- repositoryDetailsF
maybeDataPoints <- deploymentIndicatorsForServiceF
serviceDeploymentInformation <- serviceDeploymentInformationF
mayBeDependencies <- dependenciesF
urlIfLeaksFound <- leakDetectionService.urlIfLeaksFound(name)
serviceUrl <- serviceUrlF
serviceRoutes <- serviceRoutesF
} yield
(service, serviceDeploymentInformation) match {
case (_, Left(t)) =>
t.printStackTrace()
ServiceUnavailable(t.getMessage)
case (Some(repositoryDetails), Right(sdi: ServiceDeploymentInformation))
if repositoryDetails.repoType == RepoType.Service =>
val maybeDeployedEnvironments =
getDeployedEnvs(sdi.deployments, repositoryDetails.environments)
( teamsAndRepositoriesConnector.repositoryDetails(name)
, indicatorsConnector.deploymentIndicatorsForService(name)
, deploymentsService.getWhatsRunningWhere(name).map(_.deployments)
, serviceDependencyConnector.getDependencies(name)
, leakDetectionService.urlIfLeaksFound(name)
, routeRulesService.serviceUrl(name)
, routeRulesService.serviceRoutes(name)
).mapN { case (service, optDataPoints, deployments, optDependencies, urlIfLeaksFound, serviceUrl, serviceRoutes) =>
service match {
case Some(repositoryDetails) if repositoryDetails.repoType == RepoType.Service =>
val optDeployedEnvironments =
getDeployedEnvs(deployments, repositoryDetails.environments)

val deploymentsByEnvironmentName: Map[String, Seq[DeploymentVO]] =
sdi.deployments
.map(
deployment =>
deployment.environmentMapping.name -> sdi.deployments
.filter(_.environmentMapping.name == deployment.environmentMapping.name))
deployments
.map(deployment =>
( deployment.environmentMapping.name
, deployments.filter(_.environmentMapping.name == deployment.environmentMapping.name)
)
)
.toMap

Ok(
serviceInfoPage(
repositoryDetails.copy(environments = maybeDeployedEnvironments),
mayBeDependencies,
ServiceChartData.deploymentThroughput(repositoryDetails.name, maybeDataPoints.map(_.throughput)),
ServiceChartData.deploymentStability(repositoryDetails.name, maybeDataPoints.map(_.stability)),
repositoryDetails.copy(environments = optDeployedEnvironments),
optDependencies,
ServiceChartData.deploymentThroughput(repositoryDetails.name, optDataPoints.map(_.throughput)),
ServiceChartData.deploymentStability(repositoryDetails.name, optDataPoints.map(_.stability)),
repositoryDetails.createdAt,
deploymentsByEnvironmentName,
urlIfLeaksFound,
Expand All @@ -326,17 +311,18 @@ class CatalogueController @Inject()(
)
case _ => NotFound(error_404_template())
}
}
}

def library(name: String): Action[AnyContent] = Action.async { implicit request =>
for {
library <- teamsAndRepositoriesConnector.repositoryDetails(name)
mayBeDependencies <- serviceDependencyConnector.getDependencies(name)
urlIfLeaksFound <- leakDetectionService.urlIfLeaksFound(name)
library <- teamsAndRepositoriesConnector.repositoryDetails(name)
optDependencies <- serviceDependencyConnector.getDependencies(name)
urlIfLeaksFound <- leakDetectionService.urlIfLeaksFound(name)
} yield
library match {
case Some(s) if s.repoType == Library =>
Ok(libraryInfoPage(s, mayBeDependencies, urlIfLeaksFound))
Ok(libraryInfoPage(s, optDependencies, urlIfLeaksFound))
case _ =>
NotFound(error_404_template())
}
Expand All @@ -362,17 +348,17 @@ class CatalogueController @Inject()(
owners.sorted ++ other.sorted
})))
indicators <- indicatorsConnector.buildIndicatorsForRepository(name)
mayBeDependencies <- serviceDependencyConnector.getDependencies(name)
maybeUrlIfLeaksFound <- leakDetectionService.urlIfLeaksFound(name)
optDependencies <- serviceDependencyConnector.getDependencies(name)
optUrlIfLeaksFound <- leakDetectionService.urlIfLeaksFound(name)
} yield
(repository, indicators) match {
case (Some(repositoryDetails), maybeDataPoints) =>
case (Some(repositoryDetails), optDataPoints) =>
Ok(
repositoryInfoPage(
repositoryDetails,
mayBeDependencies,
ServiceChartData.jobExecutionTime(repositoryDetails.name, maybeDataPoints),
maybeUrlIfLeaksFound
optDependencies,
ServiceChartData.jobExecutionTime(repositoryDetails.name, optDataPoints),
optUrlIfLeaksFound
)
)
case _ => NotFound(error_404_template())
Expand Down Expand Up @@ -441,9 +427,9 @@ class CatalogueController @Inject()(
}
}

private implicit class OptionOps(maybeString: Option[String]) {
private implicit class OptionOps(optString: Option[String]) {
lazy val blankToNone: Option[String] =
maybeString.map(_.trim).filterNot(_.isEmpty)
optString.map(_.trim).filterNot(_.isEmpty)
}

private def convertToDisplayableTeamMembers(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,8 @@ class DependenciesController @Inject()(

def service(name: String): Action[AnyContent] = Action.async { implicit request =>
for {
deployments <- deploymentsService.getWhatsRunningWhere(name)
deployments <- deploymentsService.getWhatsRunningWhere(name).map(_.deployments)
serviceDependencies <- dependenciesService.search(name, deployments)
} yield
deployments match {
case Left(t) => ServiceUnavailable(t.getMessage)
case _ => Ok(dependenciesPage(name, serviceDependencies.sortBy(_.semanticVersion)(Ordering[Option[Version]].reverse)))
}
} yield Ok(dependenciesPage(name, serviceDependencies.sortBy(_.semanticVersion)(Ordering[Option[Version]].reverse)))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ class DependencyReportController @Inject()(
case Some(VersionState.MinorVersionOutOfDate) => "amber"
case Some(VersionState.MajorVersionOutOfDate) => "red"
case Some(VersionState.Invalid) => "N/A"
case Some(VersionState.BobbyRuleViolated) => "verybad"
case Some(VersionState.BobbyRulePending) => "pending"
case None => "grey"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class SearchByUrlConnector @Inject()(

def search(term: String)(implicit hc: HeaderCarrier): Future[Seq[FrontendRoutes]] =
http
.GET[Seq[FrontendRoutes]](s"$url", Seq("frontendPath" -> term))
.GET[Seq[FrontendRoutes]](url, Seq("frontendPath" -> term))
.recover {
case NonFatal(ex) =>
Logger.error(s"An error occurred when connecting to $url: ${ex.getMessage}", ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,32 @@ class ServiceDependenciesConnector @Inject()(

private val servicesDependenciesBaseUrl: String = servicesConfig.baseUrl("service-dependencies") + "/api"

def getDependencies(repositoryName: String)(implicit hc: HeaderCarrier): Future[Option[Dependencies]] =
def getDependencies(repositoryName: String)(implicit hc: HeaderCarrier): Future[Option[Dependencies]] = {
implicit val reads = Dependencies.reads
http
.GET[Option[Dependencies]](s"$servicesDependenciesBaseUrl/dependencies/$repositoryName")
.recover {
case ex =>
Logger.error(s"An error occurred when connecting to $servicesDependenciesBaseUrl: ${ex.getMessage}", ex)
None
}
}

def getAllDependencies()(implicit hc: HeaderCarrier): Future[Seq[Dependencies]] =
def getAllDependencies()(implicit hc: HeaderCarrier): Future[Seq[Dependencies]] = {
implicit val reads = Dependencies.reads
http
.GET[Seq[Dependencies]](s"$servicesDependenciesBaseUrl/dependencies")
.recover {
case ex =>
Logger.error(s"An error occurred when connecting to $servicesDependenciesBaseUrl: ${ex.getMessage}", ex)
Nil
}
}

def dependenciesForTeam(team: String)(implicit hc: HeaderCarrier): Future[Seq[Dependencies]] =
def dependenciesForTeam(team: String)(implicit hc: HeaderCarrier): Future[Seq[Dependencies]] = {
implicit val reads = Dependencies.reads
http.GET[Seq[Dependencies]](s"$servicesDependenciesBaseUrl/teams/$team/dependencies")
}

def getSlugDependencies(serviceName: String, version: Option[String] = None)
(implicit hc: HeaderCarrier): Future[Seq[ServiceDependencies]] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,23 +112,22 @@ class ServiceDeploymentsConnector @Inject()(
}

def getWhatIsRunningWhere(serviceName: String)(
implicit hc: HeaderCarrier): Future[Either[Throwable, ServiceDeploymentInformation]] = {
implicit hc: HeaderCarrier): Future[ServiceDeploymentInformation] = {
val url = s"$serviceUrl/api/whatsrunningwhere/$serviceName"

http
.GET[HttpResponse](url)
.map { r =>
r.status match {
case 200 =>
Try(r.json.as[ServiceDeploymentInformation]).transform(s => Success(Right(s)), f => Success(Left(f))).get
case 200 => r.json.as[ServiceDeploymentInformation]
}
}
.recover {
case _: NotFoundException =>
Right(ServiceDeploymentInformation(serviceName, Nil)) // 404 if the service has had no deployments
ServiceDeploymentInformation(serviceName, Nil) // 404 if the service has had no deployments
case ex =>
Logger.error(s"An error occurred when connecting to $url: ${ex.getMessage}", ex)
Left(ex)
throw ex
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ case class BobbyRule(organisation: String, name: String, range: String, reason:
if (organisation == wildcard && name == wildcard) "*" else s"$organisation:$name"
}
}

object BobbyRule {
implicit val reader: Reads[BobbyRule] = Json.reads[BobbyRule]

}

case class BobbyRuleSet(libraries: Seq[BobbyRule], plugins: Seq[BobbyRule])
Expand Down
Loading

0 comments on commit 81584bc

Please sign in to comment.