Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bdog 82 dependency explorer #42

Merged
merged 6 commits into from
Jan 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions app/uk/gov/hmrc/cataloguefrontend/DependenciesController.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2019 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package uk.gov.hmrc.cataloguefrontend

import javax.inject.{Inject, Singleton}
import play.api.mvc.{Action, AnyContent, MessagesControllerComponents}
import uk.gov.hmrc.cataloguefrontend.service.{DependenciesService, DeploymentsService}
import uk.gov.hmrc.play.bootstrap.controller.FrontendController
import views.html.DependenciesPage
import scala.concurrent.ExecutionContext.Implicits.global

@Singleton
class DependenciesController @Inject()(mcc: MessagesControllerComponents,
dependenciesService: DependenciesService,
deploymentsService: DeploymentsService,
dependenciesPage: DependenciesPage
) extends FrontendController(mcc) {

def service(name: String): Action[AnyContent] = Action.async { implicit request =>
for {
deployments <- deploymentsService.getWhatsRunningWhere(name)
serviceDependencies <- dependenciesService.search(name, deployments)
} yield
deployments match {
case Left(t) => ServiceUnavailable(t.getMessage)
case _ => Ok(dependenciesPage(name, serviceDependencies.sortBy(_.version)(Ordering[Option[String]].reverse)))
}
}
}
2 changes: 2 additions & 0 deletions app/uk/gov/hmrc/cataloguefrontend/FeatureSwitch.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ object CatalogueFrontendSwitches {

def routingRules = FeatureSwitch.forName("urlRoutingRules")

def dependencyExplorer = FeatureSwitch.forName("dependencyExplorer")

def allSwitches: Seq[FeatureSwitch] = Seq(configExplorer)

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,21 @@

package uk.gov.hmrc.cataloguefrontend.connector

/*
* Copyright 2016 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import javax.inject.{Inject, Singleton}
import play.api.Logger
import uk.gov.hmrc.cataloguefrontend.connector.model.Dependencies
import uk.gov.hmrc.cataloguefrontend.service.ServiceDependencies
import uk.gov.hmrc.http.HeaderCarrier
import uk.gov.hmrc.play.bootstrap.config.ServicesConfig
import uk.gov.hmrc.play.bootstrap.http.HttpClient
import uk.gov.hmrc.play.http.logging.MdcLoggingExecutionContext.fromLoggingDetails

import scala.concurrent.Future
import scala.util.control.NonFatal

@Singleton
class ServiceDependenciesConnector @Inject()(
http: HttpClient,
servicesConfig: ServicesConfig
) {
class ServiceDependenciesConnector @Inject()(http: HttpClient,
servicesConfig: ServicesConfig) {

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

Expand All @@ -70,4 +54,21 @@ class ServiceDependenciesConnector @Inject()(

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

def getSlugDependencies(serviceName: String, version: Option[String] = None)
(implicit hc: HeaderCarrier): Future[Seq[ServiceDependencies]] = {
val queryParams = buildQueryParams(("name", Some(serviceName)), ("version", version))

http
.GET[Seq[ServiceDependencies]](s"$servicesDependenciesBaseUrl/sluginfos", queryParams)
.recover {
case NonFatal(ex) =>
Logger.error(s"An error occurred when connecting to $servicesDependenciesBaseUrl: ${ex.getMessage}", ex)
Nil
}
}

private def buildQueryParams(queryParams: (String, Option[String])*) =
queryParams.flatMap(param => param._2.map(v => (param._1, v)))

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2019 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package uk.gov.hmrc.cataloguefrontend.service

import javax.inject._
import play.api.libs.json.{Json, Reads}
import uk.gov.hmrc.cataloguefrontend.{DeploymentVO, ServiceDeploymentInformation}
import uk.gov.hmrc.cataloguefrontend.connector.ServiceDependenciesConnector
import uk.gov.hmrc.http.HeaderCarrier
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

@Singleton
class DependenciesService @Inject()(serviceDependenciesConnector: ServiceDependenciesConnector) {

def search(serviceName: String, serviceDeploymentInformation: Either[Throwable, ServiceDeploymentInformation])
(implicit hc: HeaderCarrier): Future[Seq[ServiceDependencies]] = {
val deployments = getDeployments(serviceDeploymentInformation)

serviceDependenciesConnector.getSlugDependencies(serviceName).map { item =>
item.map { serviceDependency =>
val environmentMappingName = deployments.find {
deploymentVO => serviceDependency.version.nonEmpty && deploymentVO.version == serviceDependency.version.get
} .map {
deploymentVO => deploymentVO.environmentMapping.name
}

environmentMappingName match {
case Some(_) => serviceDependency.copy(environment = environmentMappingName)
case None => serviceDependency
}
}
}
}

private def getDeployments(serviceDeploymentInformation: Either[Throwable, ServiceDeploymentInformation]): Seq[DeploymentVO] =
serviceDeploymentInformation match {
case Left(t) => Nil
case Right(sdi) => sdi.deployments
}

}

case class ServiceDependency(path: String, group: String, artifact: String, version: String, meta: String = "")
case class ServiceDependencies(uri: String,
name: String,
version: Option[String],
runnerVersion: String,
classpath: String,
dependencies: Seq[ServiceDependency],
environment: Option[String] = None) {
val isEmpty: Boolean = dependencies.isEmpty
val nonEmpty: Boolean = dependencies.nonEmpty
}

object ServiceDependencies {

implicit val dependencyReads: Reads[ServiceDependency] = Json.using[Json.WithDefaultValues].reads[ServiceDependency]
implicit val serviceDependenciesReads: Reads[ServiceDependencies] = Json.using[Json.WithDefaultValues].reads[ServiceDependencies]

}
66 changes: 66 additions & 0 deletions app/views/DependenciesPage.scala.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
@*
* Copyright 2019 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*@

@import uk.gov.hmrc.cataloguefrontend.ViewMessages
@import uk.gov.hmrc.cataloguefrontend.service.ServiceDependencies

@this(viewMessages: ViewMessages)
@(serviceName: String, serviceDependencies: Seq[ServiceDependencies])(implicit request: Request[_])
@standard_layout(s"Dependencies: $serviceName", "dependencies") {
<header>
<h1 id="dependencies-header">Dependencies: @serviceName</h1>
</header>
<div>
@serviceDependencies.zipWithIndex.map { case (serviceDependency, index) =>
<div class="hand-pointer accordion-toggle collapsed" data-toggle="collapse" data-target="#collapsible-area-@index" aria-expanded="false" aria-controls="collapsible-area">
<label class="hand-pointer">@{serviceVersion(serviceDependency.version)} @{environment(serviceDependency.environment)}</label>
</div>
<div id="collapsible-area-@index" class="collapse">
<table id="dependencies-list" class="table table-condensed">
<tr>
<th class="col-lg-4">Group ID</th>
<th class="col-lg-4">Artifact ID</th>
<th class="col-lg-4">Version</th>
</tr>
<tbody class="list">
@for(dependency <- serviceDependency.dependencies) {
<tr>
<td><span>@dependency.group</span></td>
<td><span>@dependency.artifact</span></td>
<td><span>@dependency.version</span></td>
</tr>
}
</tbody>
</table>
</div>
}
@if(serviceDependencies.isEmpty) {
<p id="dependencies-empty">This search did not return any results.</p>
}
</div>
}

@serviceVersion(version: Option[String]) = {
@version.map { v =>
Version: @v
}
}

@environment(environment: Option[String]) = {
@environment.map { env =>
(@env)
}
}
1 change: 0 additions & 1 deletion app/views/ServiceInfoPage.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
@import uk.gov.hmrc.cataloguefrontend.ViewMessages
@import play.twirl.api.Html
@import java.time.LocalDateTime

@import uk.gov.hmrc.cataloguefrontend.service.RouteRulesService.ServiceRoutes
@import uk.gov.hmrc.cataloguefrontend.DeploymentVO
@import uk.gov.hmrc.cataloguefrontend.ChartDataRows
Expand Down
3 changes: 3 additions & 0 deletions app/views/partials/code_and_builds.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ <h3 class="board__heading">Code and Build</h3>
@for(ciLink <- repo.ci) {
<li class="list-item"><a id="link-to-@{ciLink.id}" href="@{ciLink.url}" target="_blank">@{ciLink.displayName}<span class="glyphicon glyphicon-new-window"/></a></li>
}
@if(CatalogueFrontendSwitches.dependencyExplorer.isEnabled) {
<li class="list-item"><a id="link-to-dependency-explorer" href="/dependencies/@{repo.name}" target="_blank">Service Dependencies<span class="glyphicon glyphicon-new-window"/></a></li>
}
</ul>
</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions conf/app.routes
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ GET /sign-out @uk.gov.hmrc.cataloguefr

GET /search uk.gov.hmrc.cataloguefrontend.SearchByUrlController.searchLanding
POST /search uk.gov.hmrc.cataloguefrontend.SearchByUrlController.searchUrl

GET /dependencies/:name uk.gov.hmrc.cataloguefrontend.DependenciesController.service(name)
5 changes: 5 additions & 0 deletions public/catalogue-frontend.css
Original file line number Diff line number Diff line change
Expand Up @@ -12042,4 +12042,9 @@ section span.other-teams-message {
.accordion-toggle.collapsed:after {
/* symbol for "collapsed" panels */
content: "\e080";
}

.hand-pointer {
cursor: pointer;
cursor: hand;
}