Skip to content

Commit 48f683f

Browse files
committed
BDOG-183 improve version range display in Bobby Explorer
1 parent f868064 commit 48f683f

File tree

3 files changed

+93
-12
lines changed

3 files changed

+93
-12
lines changed

app/uk/gov/hmrc/cataloguefrontend/connector/model/BobbyRule.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,18 @@ import java.time.LocalDate
2020

2121
import play.api.libs.json.{Json, Reads}
2222

23-
case class BobbyRule(organisation: String, name: String, range: String, reason: String, from: LocalDate) {
23+
case class BobbyRule(organisation: String, name: String, range: BobbyVersionRange, reason: String, from: LocalDate) {
2424
val groupArtifactName: String = {
2525
val wildcard = "*"
2626
if (organisation == wildcard && name == wildcard) "*" else s"$organisation:$name"
2727
}
2828
}
2929

3030
object BobbyRule {
31-
implicit val reader: Reads[BobbyRule] = Json.reads[BobbyRule]
31+
implicit val reader: Reads[BobbyRule] = {
32+
implicit val bvr = BobbyVersionRange.reads
33+
Json.reads[BobbyRule]
34+
}
3235

3336
}
3437

app/uk/gov/hmrc/cataloguefrontend/connector/model/Dependencies.scala

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package uk.gov.hmrc.cataloguefrontend.connector.model
1919
import java.time.LocalDate
2020

2121
import org.joda.time.DateTime
22-
import play.api.libs.json.{Format, JsError, JsObject, JsString, JsSuccess, JsValue, Json, OFormat, Reads, __}
22+
import play.api.libs.json.{Format, JsError, JsObject, JsPath, JsString, JsSuccess, JsValue, Json, OFormat, Reads, __}
2323
import play.api.libs.functional.syntax._
2424
import uk.gov.hmrc.http.controllers.RestFormats
2525

@@ -33,11 +33,6 @@ object VersionState {
3333
case object BobbyRulePending extends VersionState
3434
}
3535

36-
// TODO avoid caching LocalDate, and provide to isActive function
37-
case class BobbyRuleViolation(reason: String, range: String, from: LocalDate)(implicit now: LocalDate = LocalDate.now()) {
38-
def isActive: Boolean = now.isAfter(from)
39-
}
40-
4136
case class Dependency(
4237
name : String,
4338
currentVersion: Version,
@@ -74,12 +69,89 @@ case class Dependencies(
7469
toSeq.exists(_.isOutOfDate)
7570
}
7671

72+
case class BobbyVersion(version: Version, inclusive: Boolean)
73+
74+
object BobbyVersion {
75+
val reads: Reads[BobbyVersion] = {
76+
implicit val bvf = Version.format
77+
( (__ \ "version" ).read[Version]
78+
~ (__ \ "inclusive").read[Boolean]
79+
)(BobbyVersion.apply _)
80+
}
81+
}
82+
83+
case class BobbyVersionRange(
84+
lowerBound: Option[BobbyVersion]
85+
, upperBound: Option[BobbyVersion]
86+
, qualifier : Option[String]
87+
, range : String
88+
) {
89+
def description: String = {
90+
def comp(v: BobbyVersion) = if (v.inclusive) " <= " else " < "
91+
lowerBound.map(v => s"${v.version} ${comp(v)}").getOrElse("") +
92+
"x" +
93+
upperBound.map(v => s" ${comp(v)} ${v.version}").getOrElse("")
94+
}
95+
}
96+
97+
object BobbyVersionRange {
98+
99+
private val fixed = """^\[(\d+\.\d+.\d+)\]""".r
100+
private val fixedUpper = """^\(,?(\d+\.\d+.\d+)[\]\)]""".r
101+
private val fixedLower = """^[\[\(](\d+\.\d+.\d+),[\]\)]""".r
102+
private val rangeRegex = """^[\[\(](\d+\.\d+.\d+),(\d+\.\d+.\d+)[\]\)]""".r
103+
private val qualifier = """^\[[-\*]+(.*)\]""".r
104+
105+
def apply(range: String): BobbyVersionRange = {
106+
val trimmedRange = range.replaceAll(" ", "")
107+
108+
trimmedRange match {
109+
case fixed(v) =>
110+
val fixed = Version.parse(v).map(BobbyVersion(_, inclusive = true))
111+
BobbyVersionRange(lowerBound = fixed, upperBound = fixed, qualifier = None, range = trimmedRange)
112+
case fixedUpper(v) =>
113+
BobbyVersionRange(
114+
lowerBound = None,
115+
upperBound = Version.parse(v).map(BobbyVersion(_, inclusive = trimmedRange.endsWith("]"))),
116+
qualifier = None,
117+
range = trimmedRange)
118+
case fixedLower(v) =>
119+
BobbyVersionRange(
120+
lowerBound = Version.parse(v).map(BobbyVersion(_, inclusive = trimmedRange.startsWith("["))),
121+
upperBound = None,
122+
qualifier = None,
123+
range = trimmedRange)
124+
case rangeRegex(v1, v2) =>
125+
BobbyVersionRange(
126+
lowerBound = Version.parse(v1).map(BobbyVersion(_, inclusive = trimmedRange.startsWith("["))),
127+
upperBound = Version.parse(v2).map(BobbyVersion(_, inclusive = trimmedRange.endsWith("]"))),
128+
qualifier = None,
129+
range = trimmedRange
130+
)
131+
case qualifier(q) if q.length() > 1 =>
132+
BobbyVersionRange(lowerBound = None, upperBound = None, qualifier = Some(q), range = trimmedRange)
133+
case _ => BobbyVersionRange(lowerBound = None, upperBound = None, qualifier = None, range = trimmedRange)
134+
}
135+
}
136+
137+
val reads: Reads[BobbyVersionRange] =
138+
JsPath.read[String].map(BobbyVersionRange.apply)
139+
140+
}
141+
142+
// TODO avoid caching LocalDate, and provide to isActive function
143+
case class BobbyRuleViolation(reason: String, range: BobbyVersionRange, from: LocalDate)(implicit now: LocalDate = LocalDate.now()) {
144+
def isActive: Boolean = now.isAfter(from)
145+
}
146+
147+
77148
object Dependencies {
78149
val reads: Reads[Dependencies] = {
79150
implicit val dtr = RestFormats.dateTimeFormats
151+
implicit val bvr = BobbyVersionRange.reads
80152
implicit val brvf =
81153
( (__ \ "reason" ).read[String]
82-
~ (__ \ "range" ).read[JsValue].map(j => (j \ "range").as[String])
154+
~ (__ \ "range" ).read[BobbyVersionRange]
83155
~ (__ \ "from" ).read[LocalDate]
84156
)(BobbyRuleViolation.apply _)
85157

app/views/BobbyExplorerPage.scala.html

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ <h1>Bobby Rules</h1>
4545
<thead>
4646
<tr>
4747
<th>@artifactType</th>
48-
<th>Version</th>
48+
<th>Banned Versions</th>
4949
<th>Reason</th>
5050
<th>Active from</th>
5151
</tr>
@@ -61,8 +61,14 @@ <h1>Bobby Rules</h1>
6161
@bobbyRuleRow(rule: BobbyRule) = {
6262
<tr class="bobby-rule">
6363
<td><a name="@rule.name">@rule.groupArtifactName</a></td>
64-
<td>@rule.range</td>
64+
<td data-toggle="tooltip" data-placement="top" title="@rule.range.range">@rule.range.description</td>
6565
<td>@rule.reason</td>
6666
<td>@rule.from</td>
6767
</tr>
68-
}
68+
}
69+
70+
<script type="text/javascript">
71+
ready(function() {
72+
document.querySelector('[data-toggle="tooltip"]').tooltip();
73+
});
74+
</script>

0 commit comments

Comments
 (0)