Skip to content
This repository has been archived by the owner on Mar 11, 2020. It is now read-only.

Use circe, upgrade http4s and cats #20

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
11 changes: 8 additions & 3 deletions core/build.sbt
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
val circeVersion = "0.11.1"

libraryDependencies ++= Seq(
"io.argonaut" %% "argonaut" % "6.2.1",
"org.typelevel" %% "cats-free" % "1.1.0",
"org.typelevel" %% "cats-effect" % "0.10"
"io.circe" %% "circe-core" % circeVersion,
"io.circe" %% "circe-generic" % circeVersion,
"io.circe" %% "circe-parser" % circeVersion,
"org.scalacheck" %% "scalacheck" % "1.14.0" % "test",
"org.scalatest" %% "scalatest" % "3.0.8" % "test",
"org.typelevel" %% "cats-free" % "1.3.0",
"org.typelevel" %% "cats-effect" % "1.3.0"
)

addCompilerPlugin("org.spire-math" % "kind-projector" % "0.9.5" cross CrossVersion.binary)
37 changes: 20 additions & 17 deletions core/src/main/scala/HealthCheckParameter.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package helm

import argonaut._, Argonaut._
import io.circe._
import io.circe.syntax._

/** Case class representing a health check as defined in the Register Service API calls */
final case class HealthCheckParameter(
Expand All @@ -20,20 +21,22 @@ final case class HealthCheckParameter(
)

object HealthCheckParameter {
implicit def HealthCheckParameterEncoder: EncodeJson[HealthCheckParameter] =
EncodeJson((h: HealthCheckParameter) =>
("Name" := h.name) ->:
("CheckID" :=? h.id) ->?:
("Interval" :=? h.interval) ->?:
("Notes" :=? h.notes) ->?:
("DeregisterCriticalServiceAfter" :=? h.deregisterCriticalServiceAfter) ->?:
("ServiceID" :=? h.serviceId) ->?:
("Status" :=? h.initialStatus) ->?:
("HTTP" :=? h.http) ->?:
("TLSSkipVerify" :=? h.tlsSkipVerify) ->?:
("Script" :=? h.script) ->?:
("DockerContainerID" :=? h.dockerContainerId) ->?:
("TCP" :=? h.tcp) ->?:
("TTL" :=? h.ttl) ->?:
jEmptyObject)
implicit def HealthCheckParameterEncoder: Encoder[HealthCheckParameter] =
Encoder.encodeJsonObject.contramapObject { h =>
JsonObject(
"Name" := h.name ,
"CheckID" := h.id ,
"Interval" := h.interval ,
"Notes" := h.notes ,
"DeregisterCriticalServiceAfter" := h.deregisterCriticalServiceAfter ,
"ServiceID" := h.serviceId ,
"Status" := h.initialStatus ,
"HTTP" := h.http ,
"TLSSkipVerify" := h.tlsSkipVerify ,
"Script" := h.script ,
"DockerContainerID" := h.dockerContainerId ,
"TCP" := h.tcp ,
"TTL" := h.ttl
)
}
}
28 changes: 14 additions & 14 deletions core/src/main/scala/HealthCheckResponse.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package helm

import argonaut._, Argonaut._
import io.circe._

/** Case class representing a health check as returned from an API call to Consul */
final case class HealthCheckResponse(
Expand All @@ -18,20 +18,20 @@ final case class HealthCheckResponse(
)

object HealthCheckResponse {
implicit def HealthCheckResponseDecoder: DecodeJson[HealthCheckResponse] =
DecodeJson(j =>
implicit def HealthCheckResponseDecoder: Decoder[HealthCheckResponse] =
Decoder.instance(c =>
for {
node <- (j --\ "Node").as[String]
checkId <- (j --\ "CheckID").as[String]
name <- (j --\ "Name").as[String]
status <- (j --\ "Status").as[HealthStatus]
notes <- (j --\ "Notes").as[String]
output <- (j --\ "Output").as[String]
serviceId <- (j --\ "ServiceID").as[String]
serviceName <- (j --\ "ServiceName").as[String]
serviceTags <- (j --\ "ServiceTags").as[List[String]]
createIndex <- (j --\ "CreateIndex").as[Long]
modifyIndex <- (j --\ "ModifyIndex").as[Long]
node <- c.downField("Node").as[String]
checkId <- c.downField("CheckID").as[String]
name <- c.downField("Name").as[String]
status <- c.downField("Status").as[HealthStatus]
notes <- c.downField("Notes").as[String]
output <- c.downField("Output").as[String]
serviceId <- c.downField("ServiceID").as[String]
serviceName <- c.downField("ServiceName").as[String]
serviceTags <- c.downField("ServiceTags").as[List[String]]
createIndex <- c.downField("CreateIndex").as[Long]
modifyIndex <- c.downField("ModifyIndex").as[Long]
} yield HealthCheckResponse(
node,
checkId,
Expand Down
12 changes: 6 additions & 6 deletions core/src/main/scala/HealthNodesForServiceResponse.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package helm

import argonaut._, Argonaut._
import io.circe._

/** Case class representing the response to the Health API's List Nodes For Service function */
final case class HealthNodesForServiceResponse(
Expand All @@ -10,12 +10,12 @@ final case class HealthNodesForServiceResponse(
)

object HealthNodesForServiceResponse {
implicit def HealthNodesForServiceResponseDecoder: DecodeJson[HealthNodesForServiceResponse] =
DecodeJson(j =>
implicit def HealthNodesForServiceResponseDecoder: Decoder[HealthNodesForServiceResponse] =
Decoder.instance(c =>
for {
node <- (j --\ "Node").as[NodeResponse]
service <- (j --\ "Service").as[ServiceResponse]
checks <- (j --\ "Checks").as[List[HealthCheckResponse]]
node <- c.downField("Node").as[NodeResponse]
service <- c.downField("Service").as[ServiceResponse]
checks <- c.downField("Checks").as[List[HealthCheckResponse]]
} yield HealthNodesForServiceResponse(node, service, checks)
)
}
14 changes: 7 additions & 7 deletions core/src/main/scala/HealthStatus.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package helm

import argonaut._, Argonaut._
import io.circe._

sealed abstract class HealthStatus extends Product with Serializable

Expand Down Expand Up @@ -28,16 +28,16 @@ object HealthStatus {
case Unknown => "unknown"
}

implicit val HealthStatusDecoder: DecodeJson[HealthStatus] =
DecodeJson[HealthStatus] { c =>
implicit val HealthStatusDecoder: Decoder[HealthStatus] =
Decoder.instance { c =>
c.as[String].flatMap { s =>
fromString(s) match {
case Some(r) => DecodeResult.ok(r)
case None => DecodeResult.fail(s"invalid health status: $s", c.history)
case Some(r) => Right(r)
case None => Left(DecodingFailure(s"invalid health status: $s", c.history))
}
}
}

implicit val HealthStatusEncoder: EncodeJson[HealthStatus] =
EncodeJson[HealthStatus] { hs => jString(toString(hs)) }
implicit val HealthStatusEncoder: Encoder[HealthStatus] =
Encoder.encodeString.contramap { hs => toString(hs) }
}
13 changes: 7 additions & 6 deletions core/src/main/scala/HelmOp.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package helm

import scala.collection.immutable.{Set => SSet}
import argonaut.{DecodeJson, EncodeJson, StringWrap}, StringWrap.StringToParseWrap
import io.circe._, io.circe.parser._
import cats.data.NonEmptyList
import cats.free.Free
import cats.free.Free.liftF
Expand Down Expand Up @@ -104,15 +104,16 @@ object ConsulOp {
): ConsulOpF[QueryResponse[Option[Array[Byte]]]] =
liftF(KVGetRaw(key, index, maxWait))

def kvGetJson[A:DecodeJson](
def kvGetJson[A](
key: Key,
index: Option[Long],
maxWait: Option[Interval]
): ConsulOpF[Either[Err, QueryResponse[Option[A]]]] =
)(implicit decoder: Decoder[A]): ConsulOpF[Either[Error, QueryResponse[Option[A]]]] =
kvGetRaw(key, index, maxWait).map { response =>
response.value match {
case Some(bytes) =>
new String(bytes, "UTF-8").decodeEither[A].right.map(decoded => response.copy(value = Some(decoded)))
parse(new String(bytes, "UTF-8")).flatMap(decoder.decodeJson)
.right.map(decoded => response.copy(value = Option(decoded)))
case None =>
Right(response.copy(value = None))
}
Expand All @@ -121,8 +122,8 @@ object ConsulOp {
def kvSet(key: Key, value: Array[Byte]): ConsulOpF[Unit] =
liftF(KVSet(key, value))

def kvSetJson[A](key: Key, value: A)(implicit A: EncodeJson[A]): ConsulOpF[Unit] =
kvSet(key, A.encode(value).toString.getBytes("UTF-8"))
def kvSetJson[A](key: Key, value: A)(implicit encoder: Encoder[A]): ConsulOpF[Unit] =
kvSet(key, encoder(value).toString.getBytes("UTF-8"))

def kvDelete(key: Key): ConsulOpF[Unit] =
liftF(KVDelete(key))
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/scala/Interval.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package helm

import argonaut._, Argonaut._
import io.circe._

sealed abstract class Interval

Expand Down Expand Up @@ -30,6 +30,6 @@ object Interval {
}
}

implicit val IntervalEncoder: EncodeJson[Interval] =
EncodeJson[Interval] { i => jString(toString(i)) }
implicit val IntervalEncoder: Encoder[Interval] =
Encoder.encodeString.contramap { i => toString(i) }
}
20 changes: 10 additions & 10 deletions core/src/main/scala/KVGetResult.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package helm

import argonaut._, Argonaut._
import io.circe._

/** Case class representing the response to a KV "Read Key" API call to Consul */
final case class KVGetResult(
Expand All @@ -14,16 +14,16 @@ final case class KVGetResult(
)

object KVGetResult {
implicit def KVGetResultDecoder: DecodeJson[KVGetResult] =
DecodeJson(j =>
implicit def KVGetResultDecoder: Decoder[KVGetResult] =
Decoder.instance(c =>
for {
key <- (j --\ "Key").as[String]
value <- (j --\ "Value").as[Option[String]]
flags <- (j --\ "Flags").as[Long]
session <- (j --\ "Session").as[Option[String]]
lockIndex <- (j --\ "LockIndex").as[Long]
createIndex <- (j --\ "CreateIndex").as[Long]
modifyIndex <- (j --\ "ModifyIndex").as[Long]
key <- c.downField("Key").as[String]
value <- c.downField("Value").as[Option[String]]
flags <- c.downField("Flags").as[Long]
session <- c.downField("Session").as[Option[String]]
lockIndex <- c.downField("LockIndex").as[Long]
createIndex <- c.downField("CreateIndex").as[Long]
modifyIndex <- c.downField("ModifyIndex").as[Long]
} yield KVGetResult(
key,
value,
Expand Down
30 changes: 15 additions & 15 deletions core/src/main/scala/NodeResponse.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package helm

import argonaut._, Argonaut._
import io.circe._

/** Case class representing a health check as returned from an API call to Consul */
final case class NodeResponse(
Expand All @@ -15,17 +15,17 @@ final case class NodeResponse(
)

object NodeResponse {
implicit def NodeResponseDecoder: DecodeJson[NodeResponse] =
DecodeJson(j =>
implicit def NodeResponseDecoder: Decoder[NodeResponse] =
Decoder.instance(c =>
for {
id <- (j --\ "ID").as[String]
node <- (j --\ "Node").as[String]
address <- (j --\ "Address").as[String]
datacenter <- (j --\ "Datacenter").as[String]
meta <- (j --\ "Meta").as[Map[String, String]]
taggedAddresses <- (j --\ "TaggedAddresses").as[TaggedAddresses]
createIndex <- (j --\ "CreateIndex").as[Long]
modifyIndex <- (j --\ "ModifyIndex").as[Long]
id <- c.downField("ID").as[String]
node <- c.downField("Node").as[String]
address <- c.downField("Address").as[String]
datacenter <- c.downField("Datacenter").as[String]
meta <- c.downField("Meta").as[Map[String, String]]
taggedAddresses <- c.downField("TaggedAddresses").as[TaggedAddresses]
createIndex <- c.downField("CreateIndex").as[Long]
modifyIndex <- c.downField("ModifyIndex").as[Long]
} yield NodeResponse(
id,
node,
Expand All @@ -41,11 +41,11 @@ object NodeResponse {
final case class TaggedAddresses(lan: String, wan: String)

object TaggedAddresses {
implicit def TaggedAddressesDecoder: DecodeJson[TaggedAddresses] =
DecodeJson(j =>
implicit def TaggedAddressesDecoder: Decoder[TaggedAddresses] =
Decoder.instance(c =>
for {
lan <- (j --\ "lan").as[String]
wan <- (j --\ "wan").as[String]
lan <- c.downField("lan").as[String]
wan <- c.downField("wan").as[String]
} yield TaggedAddresses(lan, wan)
)
}
24 changes: 12 additions & 12 deletions core/src/main/scala/ServiceResponse.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package helm

import argonaut._, Argonaut._
import io.circe._

/** Case class representing a service as returned from an API call to Consul */
final case class ServiceResponse(
Expand All @@ -15,17 +15,17 @@ final case class ServiceResponse(
)

object ServiceResponse {
implicit def ServiceResponseDecoder: DecodeJson[ServiceResponse] =
DecodeJson(j =>
implicit def ServiceResponseDecoder: Decoder[ServiceResponse] =
Decoder.instance { c =>
for {
id <- (j --\ "ID").as[String]
address <- (j --\ "Address").as[String]
enableTagOverride <- (j --\ "EnableTagOverride").as[Boolean]
createIndex <- (j --\ "CreateIndex").as[Long]
modifyIndex <- (j --\ "ModifyIndex").as[Long]
port <- (j --\ "Port").as[Int]
service <- (j --\ "Service").as[String]
tags <- (j --\ "Tags").as[List[String]]
id <- c.downField("ID").as[String]
address <- c.downField("Address").as[String]
enableTagOverride <- c.downField("EnableTagOverride").as[Boolean]
createIndex <- c.downField("CreateIndex").as[Long]
modifyIndex <- c.downField("ModifyIndex").as[Long]
port <- c.downField("Port").as[Int]
service <- c.downField("Service").as[String]
tags <- c.downField("Tags").as[List[String]]
} yield ServiceResponse(service, id, tags, address, port, enableTagOverride, createIndex, modifyIndex)
)
}
}
6 changes: 3 additions & 3 deletions core/src/test/scala/ConsulOpTests.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package helm

import argonaut._, Argonaut._
import io.circe._
import cats.effect.IO
import org.scalatest.{FlatSpec, Matchers}
import org.scalactic.TypeCheckedTripleEquals
Expand All @@ -24,7 +24,7 @@ class ConsulOpTests extends FlatSpec with Matchers with TypeCheckedTripleEquals
case ConsulOp.KVGetRaw("foo", None, None) => IO.pure(QueryResponse(Some("42".getBytes), -1, true, -1))
}
} yield ()
interp.run(kvGetJson[Json]("foo", None, None)).unsafeRunSync should equal(Right(QueryResponse(Some(jNumber(42)), -1, true, -1)))
interp.run(kvGetJson[Json]("foo", None, None)).unsafeRunSync should equal(Right(QueryResponse(Some(Json.fromInt(42)), -1, true, -1)))
}

it should "return an error when get returns a non-decodeable value" in {
Expand All @@ -33,6 +33,6 @@ class ConsulOpTests extends FlatSpec with Matchers with TypeCheckedTripleEquals
case ConsulOp.KVGetRaw("foo", None, None) => IO.pure(QueryResponse(Some("{".getBytes), -1, true, -1))
}
} yield ()
interp.run(kvGetJson[Json]("foo", None, None)).unsafeRunSync should equal(Left("JSON terminates unexpectedly."))
interp.run(kvGetJson[Json]("foo", None, None)).unsafeRunSync.left.map(_.getMessage) should equal(Left("exhausted input"))
}
}
10 changes: 5 additions & 5 deletions http4s/build.sbt
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@

val http4sOrg = "org.http4s"
val http4sVersion = "0.18.11"
val http4sVersion = "0.20.9"
val dockeritVersion = "0.9.0"

scalaTestVersion := "3.0.1"
scalaCheckVersion := "1.13.4"

libraryDependencies ++= Seq(
"io.verizon.journal" %% "core" % "3.0.18",
http4sOrg %% "http4s-blaze-client" % http4sVersion,
http4sOrg %% "http4s-argonaut" % http4sVersion,
http4sOrg %% "http4s-circe" % http4sVersion,
"org.scalactic" %% "scalactic" % "3.0.8",
"org.scalatest" %% "scalatest" % "3.0.8" % "test",
"org.scalacheck" %% "scalacheck" % "1.14.0" % "test",
"com.whisk" %% "docker-testkit-scalatest" % dockeritVersion % "test",
"com.whisk" %% "docker-testkit-impl-docker-java" % dockeritVersion % "test"
)
Expand Down
Loading