io.chrisdavenport.log4cats.Logger Scala Examples

The following examples show how to use io.chrisdavenport.log4cats.Logger. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: ReplicaSetsApiTest.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.{ConcurrentEffect, IO}
import com.goyeau.kubernetes.client.KubernetesClient
import com.goyeau.kubernetes.client.operation._
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import io.k8s.api.apps.v1._
import io.k8s.api.core.v1._
import io.k8s.apimachinery.pkg.apis.meta.v1.{LabelSelector, ObjectMeta}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.OptionValues
import org.scalatest.matchers.should.Matchers

class ReplicaSetsApiTest
    extends AnyFlatSpec
    with Matchers
    with OptionValues
    with CreatableTests[IO, ReplicaSet]
    with GettableTests[IO, ReplicaSet]
    with ListableTests[IO, ReplicaSet, ReplicaSetList]
    with ReplaceableTests[IO, ReplicaSet]
    with DeletableTests[IO, ReplicaSet, ReplicaSetList]
    with DeletableTerminatedTests[IO, ReplicaSet, ReplicaSetList]
    with WatchableTests[IO, ReplicaSet]
    with ContextProvider {

  implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect
  implicit lazy val logger: Logger[IO]      = Slf4jLogger.getLogger[IO]
  lazy val resourceName                     = classOf[ReplicaSet].getSimpleName

  override def api(implicit client: KubernetesClient[IO]) = client.replicaSets
  override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) =
    client.replicaSets.namespace(namespaceName)

  override def sampleResource(resourceName: String, labels: Map[String, String]) = {
    val label = Option(Map("app" -> "test"))
    ReplicaSet(
      metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))),
      spec = Option(
        ReplicaSetSpec(
          selector = LabelSelector(matchLabels = label),
          template = Option(
            PodTemplateSpec(
              metadata = Option(ObjectMeta(name = Option(resourceName), labels = label)),
              spec = Option(PodSpec(containers = Seq(Container("test", image = Option("docker")))))
            )
          )
        )
      )
    )
  }
  val replicas = Option(5)
  override def modifyResource(resource: ReplicaSet) = resource.copy(
    metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name))),
    spec = resource.spec.map(_.copy(replicas = replicas))
  )
  override def checkUpdated(updatedResource: ReplicaSet) =
    updatedResource.spec.value.replicas shouldBe replicas

  override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] =
    client.replicaSets.namespace(namespaceName)

  override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, ReplicaSet] =
    client.replicaSets.namespace(namespaceName)
} 
Example 2
Source File: MinikubeClientProvider.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.operation

import cats.effect._
import cats.implicits._
import com.goyeau.kubernetes.client.api.NamespacesApiTest
import com.goyeau.kubernetes.client.{KubeConfig, KubernetesClient}
import io.chrisdavenport.log4cats.Logger
import java.io.File
import org.scalatest.{BeforeAndAfterAll, ParallelTestExecution, Suite}

trait MinikubeClientProvider[F[_]] extends BeforeAndAfterAll with ParallelTestExecution {
  this: Suite =>

  implicit def F: ConcurrentEffect[F]
  implicit def timer: Timer[F]
  implicit def contextShift: ContextShift[F]
  implicit def logger: Logger[F]

  val kubernetesClient: Resource[F, KubernetesClient[F]] = {
    val kubeConfig = KubeConfig.fromFile[F](
      new File(s"${System.getProperty("user.home")}/.kube/config"),
      sys.env.getOrElse("KUBE_CONTEXT_NAME", "minikube")
    )
    KubernetesClient(kubeConfig)
  }

  def resourceName: String

  private val createNamespace = kubernetesClient.use { implicit client =>
    for {
      _ <- client.namespaces.deleteTerminated(resourceName.toLowerCase)
      _ <- NamespacesApiTest.createChecked[F](resourceName.toLowerCase)
    } yield ()
  }

  private val deleteNamespace = kubernetesClient.use { client =>
    client.namespaces.delete(resourceName.toLowerCase).void
  }

  override def beforeAll(): Unit = ConcurrentEffect[F].toIO(createNamespace).unsafeRunSync()

  override def afterAll(): Unit = ConcurrentEffect[F].toIO(deleteNamespace).unsafeRunSync()

  def usingMinikube[T](body: KubernetesClient[F] => F[T]): T =
    ConcurrentEffect[F].toIO(kubernetesClient.use(body)).unsafeRunSync()
} 
Example 3
Source File: JobsApiTest.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.{ConcurrentEffect, IO}
import com.goyeau.kubernetes.client.operation._
import com.goyeau.kubernetes.client.KubernetesClient
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import io.k8s.api.batch.v1.{Job, JobList, JobSpec}
import io.k8s.api.core.v1._
import io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta
import org.scalatest.OptionValues
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class JobsApiTest
    extends AnyFlatSpec
    with Matchers
    with OptionValues
    with CreatableTests[IO, Job]
    with GettableTests[IO, Job]
    with ListableTests[IO, Job, JobList]
    with ReplaceableTests[IO, Job]
    with DeletableTests[IO, Job, JobList]
    with DeletableTerminatedTests[IO, Job, JobList]
    with WatchableTests[IO, Job]
    with ContextProvider {

  implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect
  implicit lazy val logger: Logger[IO]      = Slf4jLogger.getLogger[IO]
  lazy val resourceName                     = classOf[Job].getSimpleName

  override def api(implicit client: KubernetesClient[IO]) = client.jobs
  override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) =
    client.jobs.namespace(namespaceName)

  override def sampleResource(resourceName: String, labels: Map[String, String]) =
    Job(
      metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))),
      spec = Option(
        JobSpec(
          template = PodTemplateSpec(
            metadata = Option(ObjectMeta(name = Option(resourceName))),
            spec = Option(
              PodSpec(containers = Seq(Container("test", image = Option("docker"))), restartPolicy = Option("Never"))
            )
          )
        )
      )
    )
  val labels = Map("app" -> "test")
  override def modifyResource(resource: Job) = resource.copy(
    metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name), labels = Option(labels)))
  )
  override def checkUpdated(updatedResource: Job) =
    (updatedResource.metadata.value.labels.value.toSeq should contain).allElementsOf(labels.toSeq)

  override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] =
    client.jobs.namespace(namespaceName)

  override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, Job] =
    client.jobs.namespace(namespaceName)
} 
Example 4
Source File: IngressesApiTest.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect._
import com.goyeau.kubernetes.client.KubernetesClient
import com.goyeau.kubernetes.client.operation._
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import io.k8s.api.networking.v1beta1.{Ingress, IngressList, IngressRule, IngressSpec}
import io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta
import org.scalatest.OptionValues
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class IngressesApiTest
    extends AnyFlatSpec
    with Matchers
    with OptionValues
    with CreatableTests[IO, Ingress]
    with GettableTests[IO, Ingress]
    with ListableTests[IO, Ingress, IngressList]
    with ReplaceableTests[IO, Ingress]
    with DeletableTests[IO, Ingress, IngressList]
    with WatchableTests[IO, Ingress]
    with ContextProvider {

  implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect
  implicit lazy val logger: Logger[IO]      = Slf4jLogger.getLogger[IO]
  lazy val resourceName                     = classOf[Ingress].getSimpleName

  override def api(implicit client: KubernetesClient[IO]) = client.ingresses
  override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) =
    client.ingresses.namespace(namespaceName)

  override def sampleResource(resourceName: String, labels: Map[String, String]) =
    Ingress(
      metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))),
      spec = Option(
        IngressSpec(
          rules = Some(Seq(IngressRule(Some("host"))))
        )
      )
    )

  private val updatedHost: Option[IngressSpec] = Option(
    IngressSpec(
      rules = Some(Seq(IngressRule(Some("host2"))))
    )
  )

  override def modifyResource(resource: Ingress) =
    resource.copy(
      metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name))),
      spec = updatedHost
    )
  override def checkUpdated(updatedResource: Ingress) =
    updatedResource.spec should be(
      updatedHost
    )

  override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] =
    client.ingresses.namespace(namespaceName)

  override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, Ingress] =
    client.ingresses.namespace(namespaceName)
} 
Example 5
Source File: ServicesApiTest.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect._
import com.goyeau.kubernetes.client.KubernetesClient
import com.goyeau.kubernetes.client.operation._
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import io.k8s.api.core.v1._
import io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.OptionValues
import org.scalatest.matchers.should.Matchers

class ServicesApiTest
    extends AnyFlatSpec
    with Matchers
    with OptionValues
    with CreatableTests[IO, Service]
    with GettableTests[IO, Service]
    with ListableTests[IO, Service, ServiceList]
    with ReplaceableTests[IO, Service]
    with DeletableTests[IO, Service, ServiceList]
    with WatchableTests[IO, Service]
    with ContextProvider {

  implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect
  implicit lazy val logger: Logger[IO]      = Slf4jLogger.getLogger[IO]
  lazy val resourceName                     = classOf[Service].getSimpleName

  override def api(implicit client: KubernetesClient[IO]) = client.services
  override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) =
    client.services.namespace(namespaceName)

  override def sampleResource(resourceName: String, labels: Map[String, String]) = Service(
    metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))),
    spec = Option(ServiceSpec(ports = Option(Seq(ServicePort(2000)))))
  )
  val labels = Option(Map("test" -> "updated-label"))
  override def modifyResource(resource: Service) =
    resource.copy(metadata = resource.metadata.map(_.copy(labels = labels)))
  override def checkUpdated(updatedResource: Service) = updatedResource.metadata.value.labels shouldBe labels

  override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] =
    client.services.namespace(namespaceName)

  override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, Service] =
    client.services.namespace(namespaceName)
} 
Example 6
Source File: DeploymentsApiTest.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.{ConcurrentEffect, IO}
import com.goyeau.kubernetes.client.operation._
import com.goyeau.kubernetes.client.{IntValue, KubernetesClient, StringValue}
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import io.k8s.api.apps.v1._
import io.k8s.api.core.v1._
import io.k8s.apimachinery.pkg.apis.meta.v1.{LabelSelector, ObjectMeta}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.OptionValues
import org.scalatest.matchers.should.Matchers

class DeploymentsApiTest
    extends AnyFlatSpec
    with Matchers
    with OptionValues
    with CreatableTests[IO, Deployment]
    with GettableTests[IO, Deployment]
    with ListableTests[IO, Deployment, DeploymentList]
    with ReplaceableTests[IO, Deployment]
    with DeletableTests[IO, Deployment, DeploymentList]
    with DeletableTerminatedTests[IO, Deployment, DeploymentList]
    with WatchableTests[IO, Deployment]
    with ContextProvider {

  implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect
  implicit lazy val logger: Logger[IO]      = Slf4jLogger.getLogger[IO]
  lazy val resourceName                     = classOf[Deployment].getSimpleName

  override def api(implicit client: KubernetesClient[IO]) = client.deployments
  override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) =
    client.deployments.namespace(namespaceName)

  override def sampleResource(resourceName: String, labels: Map[String, String]) = {
    val label = Option(Map("app" -> "test"))
    Deployment(
      metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))),
      spec = Option(
        DeploymentSpec(
          selector = LabelSelector(matchLabels = label),
          template = PodTemplateSpec(
            metadata = Option(ObjectMeta(name = Option(resourceName), labels = label)),
            spec = Option(PodSpec(containers = Seq(Container("test", image = Option("docker")))))
          )
        )
      )
    )
  }
  val strategy = Option(
    DeploymentStrategy(
      `type` = Option("RollingUpdate"),
      rollingUpdate =
        Option(RollingUpdateDeployment(maxSurge = Option(StringValue("25%")), maxUnavailable = Option(IntValue(10))))
    )
  )
  override def modifyResource(resource: Deployment) = resource.copy(
    metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name))),
    spec = resource.spec.map(_.copy(strategy = strategy))
  )
  override def checkUpdated(updatedResource: Deployment) =
    updatedResource.spec.value.strategy shouldBe strategy

  override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] =
    client.deployments.namespace(namespaceName)

  override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, Deployment] =
    client.deployments.namespace(namespaceName)
} 
Example 7
Source File: HorizontalPodAutoscalersApiTest.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect._
import com.goyeau.kubernetes.client.KubernetesClient
import com.goyeau.kubernetes.client.operation._
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import io.k8s.api.autoscaling.v1.{
  CrossVersionObjectReference,
  HorizontalPodAutoscaler,
  HorizontalPodAutoscalerList,
  HorizontalPodAutoscalerSpec
}
import io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.OptionValues
import org.scalatest.matchers.should.Matchers

class HorizontalPodAutoscalersApiTest
    extends AnyFlatSpec
    with Matchers
    with OptionValues
    with CreatableTests[IO, HorizontalPodAutoscaler]
    with GettableTests[IO, HorizontalPodAutoscaler]
    with ListableTests[IO, HorizontalPodAutoscaler, HorizontalPodAutoscalerList]
    with ReplaceableTests[IO, HorizontalPodAutoscaler]
    with DeletableTests[IO, HorizontalPodAutoscaler, HorizontalPodAutoscalerList]
    with WatchableTests[IO, HorizontalPodAutoscaler]
    with ContextProvider {

  implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect
  implicit lazy val logger: Logger[IO]      = Slf4jLogger.getLogger[IO]
  lazy val resourceName                     = classOf[HorizontalPodAutoscaler].getSimpleName

  override def api(implicit client: KubernetesClient[IO]) = client.horizontalPodAutoscalers
  override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) =
    client.horizontalPodAutoscalers.namespace(namespaceName)

  override def sampleResource(resourceName: String, labels: Map[String, String]) = HorizontalPodAutoscaler(
    metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))),
    spec =
      Option(HorizontalPodAutoscalerSpec(scaleTargetRef = CrossVersionObjectReference("kind", "name"), maxReplicas = 2))
  )
  val maxReplicas = 3
  override def modifyResource(resource: HorizontalPodAutoscaler) =
    resource.copy(
      metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name))),
      spec = resource.spec.map(_.copy(maxReplicas = maxReplicas))
    )
  override def checkUpdated(updatedResource: HorizontalPodAutoscaler) =
    updatedResource.spec.get.maxReplicas shouldBe maxReplicas

  override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] =
    client.horizontalPodAutoscalers.namespace(namespaceName)

  override def watchApi(
      namespaceName: String
  )(implicit client: KubernetesClient[IO]): Watchable[IO, HorizontalPodAutoscaler] =
    client.horizontalPodAutoscalers.namespace(namespaceName)
} 
Example 8
Source File: ServiceAccountsApiTest.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect._
import com.goyeau.kubernetes.client.KubernetesClient
import com.goyeau.kubernetes.client.operation._
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import io.k8s.api.core.v1._
import io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.OptionValues
import org.scalatest.matchers.should.Matchers

class ServiceAccountsApiTest
    extends AnyFlatSpec
    with Matchers
    with OptionValues
    with CreatableTests[IO, ServiceAccount]
    with GettableTests[IO, ServiceAccount]
    with ListableTests[IO, ServiceAccount, ServiceAccountList]
    with ReplaceableTests[IO, ServiceAccount]
    with DeletableTests[IO, ServiceAccount, ServiceAccountList]
    with WatchableTests[IO, ServiceAccount]
    with ContextProvider {

  implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect
  implicit lazy val logger: Logger[IO]      = Slf4jLogger.getLogger[IO]
  lazy val resourceName                     = classOf[ServiceAccount].getSimpleName

  override def api(implicit client: KubernetesClient[IO]) = client.serviceAccounts
  override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) =
    client.serviceAccounts.namespace(namespaceName)

  override def sampleResource(resourceName: String, labels: Map[String, String]) = ServiceAccount(
    metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels)))
  )
  val labels = Option(Map("test" -> "updated-label"))
  override def modifyResource(resource: ServiceAccount) =
    resource.copy(metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name), labels = labels)))
  override def checkUpdated(updatedResource: ServiceAccount) = updatedResource.metadata.value.labels shouldBe labels

  override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] =
    client.serviceAccounts.namespace(namespaceName)

  override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, ServiceAccount] =
    client.serviceAccounts.namespace(namespaceName)
} 
Example 9
Source File: CronJobsApiTest.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.{ConcurrentEffect, IO}
import com.goyeau.kubernetes.client.operation._
import com.goyeau.kubernetes.client.KubernetesClient
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import io.k8s.api.batch.v1.JobSpec
import io.k8s.api.batch.v1beta1.{CronJob, CronJobList, CronJobSpec, JobTemplateSpec}
import io.k8s.api.core.v1._
import io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.OptionValues
import org.scalatest.matchers.should.Matchers

class CronJobsApiTest
    extends AnyFlatSpec
    with Matchers
    with OptionValues
    with CreatableTests[IO, CronJob]
    with GettableTests[IO, CronJob]
    with ListableTests[IO, CronJob, CronJobList]
    with ReplaceableTests[IO, CronJob]
    with DeletableTests[IO, CronJob, CronJobList]
    with DeletableTerminatedTests[IO, CronJob, CronJobList]
    with WatchableTests[IO, CronJob]
    with ContextProvider {

  implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect
  implicit lazy val logger: Logger[IO]      = Slf4jLogger.getLogger[IO]
  lazy val resourceName                     = classOf[CronJob].getSimpleName

  override def api(implicit client: KubernetesClient[IO]) = client.cronJobs
  override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) =
    client.cronJobs.namespace(namespaceName)

  override def sampleResource(resourceName: String, labels: Map[String, String]) =
    CronJob(
      metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))),
      spec = Option(
        CronJobSpec(
          schedule = "1 * * * *",
          jobTemplate = JobTemplateSpec(
            spec = Option(
              JobSpec(
                template = PodTemplateSpec(
                  metadata = Option(ObjectMeta(name = Option(resourceName))),
                  spec = Option(
                    PodSpec(
                      containers = Seq(Container("test", image = Option("docker"))),
                      restartPolicy = Option("Never")
                    )
                  )
                )
              )
            )
          )
        )
      )
    )
  val schedule = "2 * * * *"
  override def modifyResource(resource: CronJob) = resource.copy(
    metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name))),
    spec = resource.spec.map(_.copy(schedule = schedule))
  )
  override def checkUpdated(updatedResource: CronJob) =
    updatedResource.spec.value.schedule shouldBe schedule

  override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] =
    client.cronJobs.namespace(namespaceName)

  override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, CronJob] =
    client.cronJobs.namespace(namespaceName)
} 
Example 10
Source File: ConfigMapsApiTest.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect._
import com.goyeau.kubernetes.client.KubernetesClient
import com.goyeau.kubernetes.client.operation._
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import io.k8s.api.core.v1.{ConfigMap, ConfigMapList}
import io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.OptionValues
import org.scalatest.matchers.should.Matchers

class ConfigMapsApiTest
    extends AnyFlatSpec
    with Matchers
    with OptionValues
    with CreatableTests[IO, ConfigMap]
    with GettableTests[IO, ConfigMap]
    with ListableTests[IO, ConfigMap, ConfigMapList]
    with ReplaceableTests[IO, ConfigMap]
    with DeletableTests[IO, ConfigMap, ConfigMapList]
    with WatchableTests[IO, ConfigMap]
    with ContextProvider {

  implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect
  implicit lazy val logger: Logger[IO]      = Slf4jLogger.getLogger[IO]
  lazy val resourceName                     = classOf[ConfigMap].getSimpleName

  override def api(implicit client: KubernetesClient[IO]) = client.configMaps
  override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) =
    client.configMaps.namespace(namespaceName)

  override def sampleResource(resourceName: String, labels: Map[String, String]) = ConfigMap(
    metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))),
    data = Option(Map("test" -> "data"))
  )
  val data = Option(Map("test" -> "updated-data"))
  override def modifyResource(resource: ConfigMap) =
    resource.copy(metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name))), data = data)
  override def checkUpdated(updatedResource: ConfigMap) = updatedResource.data shouldBe data

  override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] =
    client.configMaps.namespace(namespaceName)

  override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, ConfigMap] =
    client.configMaps.namespace(namespaceName)
} 
Example 11
Source File: Yamls.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.util

import java.io.File

import cats.effect.Sync
import cats.implicits._
import com.goyeau.kubernetes.client.KubeConfig

import scala.io.Source
import io.chrisdavenport.log4cats.Logger
import io.circe.{Decoder, Encoder}
import io.circe.generic.semiauto._
import io.circe.yaml.parser._
import org.http4s.Uri

case class Config(
    apiVersion: String,
    clusters: Seq[NamedCluster],
    contexts: Seq[NamedContext],
    `current-context`: String,
    users: Seq[NamedAuthInfo]
)

case class NamedCluster(name: String, cluster: Cluster)
case class Cluster(
    server: String,
    `certificate-authority`: Option[String] = None,
    `certificate-authority-data`: Option[String] = None
)

case class NamedContext(name: String, context: Context)
case class Context(cluster: String, user: String, namespace: Option[String] = None)

case class NamedAuthInfo(name: String, user: AuthInfo)
case class AuthInfo(
    `client-certificate`: Option[String] = None,
    `client-certificate-data`: Option[String] = None,
    `client-key`: Option[String] = None,
    `client-key-data`: Option[String] = None
)

private[client] object Yamls {

  def fromKubeConfigFile[F[_]: Sync: Logger](kubeconfig: File, contextMaybe: Option[String]): F[KubeConfig] =
    for {
      configJson <- Sync[F].fromEither(parse(Source.fromFile(kubeconfig).mkString))
      config     <- Sync[F].fromEither(configJson.as[Config])
      contextName = contextMaybe.getOrElse(config.`current-context`)
      namedContext <-
        config.contexts
          .find(_.name == contextName)
          .liftTo[F](new IllegalArgumentException(s"Can't find context named $contextName in $kubeconfig"))
      _ <- Logger[F].debug(s"KubeConfig with context ${namedContext.name}")
      context = namedContext.context

      namedCluster <-
        config.clusters
          .find(_.name == context.cluster)
          .liftTo[F](new IllegalArgumentException(s"Can't find cluster named ${context.cluster} in $kubeconfig"))
      cluster = namedCluster.cluster

      namedAuthInfo <-
        config.users
          .find(_.name == context.user)
          .liftTo[F](new IllegalArgumentException(s"Can't find user named ${context.user} in $kubeconfig"))
      user = namedAuthInfo.user

      server <- Sync[F].fromEither(Uri.fromString(cluster.server))
    } yield KubeConfig(
      server = server,
      caCertData = cluster.`certificate-authority-data`,
      caCertFile = cluster.`certificate-authority`.map(new File(_)),
      clientCertData = user.`client-certificate-data`,
      clientCertFile = user.`client-certificate`.map(new File(_)),
      clientKeyData = user.`client-key-data`,
      clientKeyFile = user.`client-key`.map(new File(_))
    )

  implicit lazy val configDecoder: Decoder[Config]          = deriveDecoder
  implicit lazy val configEncoder: Encoder.AsObject[Config] = deriveEncoder

  implicit lazy val clusterDecoder: Decoder[Cluster]                    = deriveDecoder
  implicit lazy val clusterEncoder: Encoder.AsObject[Cluster]           = deriveEncoder
  implicit lazy val namedClusterDecoder: Decoder[NamedCluster]          = deriveDecoder
  implicit lazy val namedClusterEncoder: Encoder.AsObject[NamedCluster] = deriveEncoder

  implicit lazy val contextDecoder: Decoder[Context]                    = deriveDecoder
  implicit lazy val contextEncoder: Encoder.AsObject[Context]           = deriveEncoder
  implicit lazy val namedContextDecoder: Decoder[NamedContext]          = deriveDecoder
  implicit lazy val namedContextEncoder: Encoder.AsObject[NamedContext] = deriveEncoder

  implicit lazy val authInfoDecoder: Decoder[AuthInfo]                    = deriveDecoder
  implicit lazy val authInfoEncoder: Encoder.AsObject[AuthInfo]           = deriveEncoder
  implicit lazy val namedAuthInfoDecoder: Decoder[NamedAuthInfo]          = deriveDecoder
  implicit lazy val namedAuthInfoEncoder: Encoder.AsObject[NamedAuthInfo] = deriveEncoder
} 
Example 12
Source File: StatefulSetsApiTest.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.{ConcurrentEffect, IO}
import com.goyeau.kubernetes.client.KubernetesClient
import com.goyeau.kubernetes.client.operation._
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import io.k8s.api.apps.v1._
import io.k8s.api.core.v1._
import io.k8s.apimachinery.pkg.apis.meta.v1.{LabelSelector, ObjectMeta}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.OptionValues
import org.scalatest.matchers.should.Matchers

class StatefulSetsApiTest
    extends AnyFlatSpec
    with Matchers
    with OptionValues
    with CreatableTests[IO, StatefulSet]
    with GettableTests[IO, StatefulSet]
    with ListableTests[IO, StatefulSet, StatefulSetList]
    with ReplaceableTests[IO, StatefulSet]
    with DeletableTests[IO, StatefulSet, StatefulSetList]
    with DeletableTerminatedTests[IO, StatefulSet, StatefulSetList]
    with WatchableTests[IO, StatefulSet]
    with ContextProvider {

  implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect
  implicit lazy val logger: Logger[IO]      = Slf4jLogger.getLogger[IO]
  lazy val resourceName                     = classOf[StatefulSet].getSimpleName

  override def api(implicit client: KubernetesClient[IO]) = client.statefulSets
  override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) =
    client.statefulSets.namespace(namespaceName)

  override def sampleResource(resourceName: String, labels: Map[String, String]) = {
    val label = Option(Map("app" -> "test"))
    StatefulSet(
      metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))),
      spec = Option(
        StatefulSetSpec(
          serviceName = "service-name",
          selector = LabelSelector(matchLabels = label),
          template = PodTemplateSpec(
            metadata = Option(ObjectMeta(name = Option(resourceName), labels = label)),
            spec = Option(PodSpec(containers = Seq(Container("test", image = Option("docker")))))
          )
        )
      )
    )
  }
  val updateStrategy = Option(
    StatefulSetUpdateStrategy(
      `type` = Option("RollingUpdate"),
      rollingUpdate = Option(RollingUpdateStatefulSetStrategy(partition = Option(10)))
    )
  )
  override def modifyResource(resource: StatefulSet) = resource.copy(
    metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name))),
    spec = resource.spec.map(_.copy(updateStrategy = updateStrategy))
  )
  override def checkUpdated(updatedResource: StatefulSet) =
    updatedResource.spec.value.updateStrategy shouldBe updateStrategy

  override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] =
    client.statefulSets.namespace(namespaceName)

  override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, StatefulSet] =
    client.statefulSets.namespace(namespaceName)
} 
Example 13
Source File: OrderServiceClient.scala    From zio-saga   with MIT License 5 votes vote down vote up
package com.vladkopanev.zio.saga.example.client

import java.util.UUID

import com.vladkopanev.zio.saga.example.TaskC
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import zio.Task

trait OrderServiceClient {

  def closeOrder(userId: UUID, orderId: BigInt, traceId: String): TaskC[Unit]

  def reopenOrder(userId: UUID, orderId: BigInt, traceId: String): TaskC[Unit]
}

class OrderServiceClientStub(logger: Logger[Task], maxRequestTimeout: Int, flaky: Boolean) extends OrderServiceClient {

  override def closeOrder(userId: UUID, orderId: BigInt, traceId: String): TaskC[Unit] =
    for {
      _ <- randomSleep(maxRequestTimeout)
      _ <- randomFail("closeOrder").when(flaky)
      _ <- logger.info(s"Order #$orderId closed")
    } yield ()

  override def reopenOrder(userId: UUID, orderId: BigInt, traceId: String): TaskC[Unit] =
    for {
      _ <- randomSleep(maxRequestTimeout)
      _ <- randomFail("reopenOrder").when(flaky)
      _ <- logger.info(s"Order #$orderId reopened")
    } yield ()
}

object OrderServiceClientStub {

  import zio.interop.catz._

  def apply(maxRequestTimeout: Int, flaky: Boolean): Task[OrderServiceClientStub] =
    Slf4jLogger.create[Task].map(new OrderServiceClientStub(_, maxRequestTimeout, flaky))
} 
Example 14
Source File: LoyaltyPointsServiceClient.scala    From zio-saga   with MIT License 5 votes vote down vote up
package com.vladkopanev.zio.saga.example.client

import java.util.UUID

import com.vladkopanev.zio.saga.example.TaskC
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import zio.Task

trait LoyaltyPointsServiceClient {

  def assignLoyaltyPoints(userId: UUID, amount: Double, traceId: String): TaskC[Unit]

  def cancelLoyaltyPoints(userId: UUID, amount: Double, traceId: String): TaskC[Unit]
}

class LoyaltyPointsServiceClientStub(logger: Logger[Task], maxRequestTimeout: Int, flaky: Boolean)
    extends LoyaltyPointsServiceClient {

  override def assignLoyaltyPoints(userId: UUID, amount: Double, traceId: String): TaskC[Unit] =
    for {
      _ <- randomSleep(maxRequestTimeout)
      _ <- randomFail("assignLoyaltyPoints").when(flaky)
      _ <- logger.info(s"Loyalty points assigned to user $userId")
    } yield ()

  override def cancelLoyaltyPoints(userId: UUID, amount: Double, traceId: String): TaskC[Unit] =
    for {
      _ <- randomSleep(maxRequestTimeout)
      _ <- randomFail("cancelLoyaltyPoints").when(flaky)
      _ <- logger.info(s"Loyalty points canceled for user $userId")
    } yield ()

}

object LoyaltyPointsServiceClientStub {

  import zio.interop.catz._

  def apply(maxRequestTimeout: Int, flaky: Boolean): Task[LoyaltyPointsServiceClientStub] =
    Slf4jLogger.create[Task].map(new LoyaltyPointsServiceClientStub(_, maxRequestTimeout, flaky))
} 
Example 15
Source File: PaymentServiceClient.scala    From zio-saga   with MIT License 5 votes vote down vote up
package com.vladkopanev.zio.saga.example.client

import java.util.UUID

import com.vladkopanev.zio.saga.example.TaskC
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import zio.Task

trait PaymentServiceClient {

  def collectPayments(userId: UUID, amount: BigDecimal, traceId: String): TaskC[Unit]

  def refundPayments(userId: UUID, amount: BigDecimal, traceId: String): TaskC[Unit]
}

class PaymentServiceClientStub(logger: Logger[Task], maxRequestTimeout: Int, flaky: Boolean)
    extends PaymentServiceClient {

  override def collectPayments(userId: UUID, amount: BigDecimal, traceId: String): TaskC[Unit] =
    for {
      _ <- randomSleep(maxRequestTimeout)
      _ <- randomFail("collectPayments").when(flaky)
      _ <- logger.info(s"Payments collected from user #$userId")
    } yield ()

  override def refundPayments(userId: UUID, amount: BigDecimal, traceId: String): TaskC[Unit] =
    for {
      _ <- randomSleep(maxRequestTimeout)
      _ <- randomFail("refundPayments").when(flaky)
      _ <- logger.info(s"Payments refunded to user #$userId")
    } yield ()
}

object PaymentServiceClientStub {

  import zio.interop.catz._

  def apply(maxRequestTimeout: Int, flaky: Boolean): Task[PaymentServiceClient] =
    Slf4jLogger.create[Task].map(new PaymentServiceClientStub(_, maxRequestTimeout, flaky))
} 
Example 16
Source File: logger.scala    From pfps-shopping-cart   with Apache License 2.0 5 votes vote down vote up
package shop

import cats.effect.IO
import cats.effect.concurrent.Ref
import io.chrisdavenport.log4cats.Logger

object logger {

  implicit object NoOp extends NoLogger

  def acc(ref: Ref[IO, List[String]]): Logger[IO] =
    new NoLogger {
      override def error(message: => String): IO[Unit] =
        ref.update(xs => message :: xs)
    }

  private[logger] class NoLogger extends Logger[IO] {
    def warn(message: => String): IO[Unit]                = IO.unit
    def warn(t: Throwable)(message: => String): IO[Unit]  = IO.unit
    def debug(t: Throwable)(message: => String): IO[Unit] = IO.unit
    def debug(message: => String): IO[Unit]               = IO.unit
    def error(t: Throwable)(message: => String): IO[Unit] = IO.unit
    def error(message: => String): IO[Unit]               = IO.unit
    def info(t: Throwable)(message: => String): IO[Unit]  = IO.unit
    def info(message: => String): IO[Unit]                = IO.unit
    def trace(t: Throwable)(message: => String): IO[Unit] = IO.unit
    def trace(message: => String): IO[Unit]               = IO.unit
  }

} 
Example 17
Source File: Main.scala    From pfps-shopping-cart   with Apache License 2.0 5 votes vote down vote up
package shop

import cats.effect._
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import org.http4s.server.blaze.BlazeServerBuilder
import shop.modules._

object Main extends IOApp {

  implicit val logger = Slf4jLogger.getLogger[IO]

  override def run(args: List[String]): IO[ExitCode] =
    config.load[IO].flatMap { cfg =>
      Logger[IO].info(s"Loaded config $cfg") >>
        AppResources.make[IO](cfg).use { res =>
          for {
            security <- Security.make[IO](cfg, res.psql, res.redis)
            algebras <- Algebras.make[IO](res.redis, res.psql, cfg.cartExpiration)
            clients <- HttpClients.make[IO](cfg.paymentConfig, res.client)
            programs <- Programs.make[IO](cfg.checkoutConfig, algebras, clients)
            api <- HttpApi.make[IO](algebras, programs, security)
            _ <- BlazeServerBuilder[IO]
                  .bindHttp(
                    cfg.httpServerConfig.port.value,
                    cfg.httpServerConfig.host.value
                  )
                  .withHttpApp(api.httpApp)
                  .serve
                  .compile
                  .drain
          } yield ExitCode.Success
        }
    }

} 
Example 18
Source File: Programs.scala    From pfps-shopping-cart   with Apache License 2.0 5 votes vote down vote up
package shop.modules

import cats.effect._
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import retry.RetryPolicy
import retry.RetryPolicies._
import shop.config.data.CheckoutConfig
import shop.effects._
import shop.programs._

object Programs {
  def make[F[_]: Background: Logger: Sync: Timer](
      checkoutConfig: CheckoutConfig,
      algebras: Algebras[F],
      clients: HttpClients[F]
  ): F[Programs[F]] =
    Sync[F].delay(
      new Programs[F](checkoutConfig, algebras, clients)
    )
}

final class Programs[F[_]: Background: Logger: MonadThrow: Timer] private (
    cfg: CheckoutConfig,
    algebras: Algebras[F],
    clients: HttpClients[F]
) {

  val retryPolicy: RetryPolicy[F] =
    limitRetries[F](cfg.retriesLimit.value) |+| exponentialBackoff[F](cfg.retriesBackoff)

  val checkout: CheckoutProgram[F] = new CheckoutProgram[F](
    clients.payment,
    algebras.cart,
    algebras.orders,
    retryPolicy
  )

} 
Example 19
Source File: checkout.scala    From pfps-shopping-cart   with Apache License 2.0 5 votes vote down vote up
package shop.programs

import cats.effect.Timer
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import retry._
import retry.RetryDetails._
import scala.concurrent.duration._
import shop.algebras._
import shop.domain.auth.UserId
import shop.domain.cart._
import shop.domain.checkout._
import shop.domain.order._
import shop.domain.payment._
import shop.effects._
import shop.http.clients.PaymentClient
import squants.market.Money

final class CheckoutProgram[F[_]: Background: Logger: MonadThrow: Timer](
    paymentClient: PaymentClient[F],
    shoppingCart: ShoppingCart[F],
    orders: Orders[F],
    retryPolicy: RetryPolicy[F]
) {

  private def logError(action: String)(e: Throwable, details: RetryDetails): F[Unit] =
    details match {
      case r: WillDelayAndRetry =>
        Logger[F].error(
          s"Failed to process $action with ${e.getMessage}. So far we have retried ${r.retriesSoFar} times."
        )
      case g: GivingUp =>
        Logger[F].error(s"Giving up on $action after ${g.totalRetries} retries.")
    }

  private def processPayment(payment: Payment): F[PaymentId] = {
    val action = retryingOnAllErrors[PaymentId](
      policy = retryPolicy,
      onError = logError("Payments")
    )(paymentClient.process(payment))

    action.adaptError {
      case e =>
        PaymentError(Option(e.getMessage).getOrElse("Unknown"))
    }
  }

  private def createOrder(userId: UserId, paymentId: PaymentId, items: List[CartItem], total: Money): F[OrderId] = {
    val action = retryingOnAllErrors[OrderId](
      policy = retryPolicy,
      onError = logError("Order")
    )(orders.create(userId, paymentId, items, total))

    def bgAction(fa: F[OrderId]): F[OrderId] =
      fa.adaptError {
          case e => OrderError(e.getMessage)
        }
        .onError {
          case _ =>
            Logger[F].error(s"Failed to create order for Payment: ${paymentId}. Rescheduling as a background action") *>
                Background[F].schedule(bgAction(fa), 1.hour)
        }

    bgAction(action)
  }

  def checkout(userId: UserId, card: Card): F[OrderId] =
    shoppingCart
      .get(userId)
      .ensure(EmptyCartError)(_.items.nonEmpty)
      .flatMap {
        case CartTotal(items, total) =>
          for {
            pid <- processPayment(Payment(userId, total, card))
            order <- createOrder(userId, pid, items, total)
            _ <- shoppingCart.delete(userId).attempt.void
          } yield order
      }

} 
Example 20
Source File: resources.scala    From pfps-shopping-cart   with Apache License 2.0 5 votes vote down vote up
package shop

import cats.effect._
import cats.implicits._
import config.data._
import dev.profunktor.redis4cats.{ Redis, RedisCommands }
import dev.profunktor.redis4cats.log4cats._
import eu.timepit.refined.auto._
import io.chrisdavenport.log4cats.Logger
import natchez.Trace.Implicits.noop // needed for skunk
import org.http4s.client.Client
import org.http4s.client.blaze.BlazeClientBuilder
import scala.concurrent.ExecutionContext
import skunk._

final case class AppResources[F[_]](
    client: Client[F],
    psql: Resource[F, Session[F]],
    redis: RedisCommands[F, String, String]
)

object AppResources {

  def make[F[_]: ConcurrentEffect: ContextShift: Logger](
      cfg: AppConfig
  ): Resource[F, AppResources[F]] = {

    def mkPostgreSqlResource(c: PostgreSQLConfig): SessionPool[F] =
      Session
        .pooled[F](
          host = c.host.value,
          port = c.port.value,
          user = c.user.value,
          database = c.database.value,
          max = c.max.value
        )

    def mkRedisResource(c: RedisConfig): Resource[F, RedisCommands[F, String, String]] =
      Redis[F].utf8(c.uri.value)

    def mkHttpClient(c: HttpClientConfig): Resource[F, Client[F]] =
      BlazeClientBuilder[F](ExecutionContext.global)
        .withConnectTimeout(c.connectTimeout)
        .withRequestTimeout(c.requestTimeout)
        .resource

    (
      mkHttpClient(cfg.httpClientConfig),
      mkPostgreSqlResource(cfg.postgreSQL),
      mkRedisResource(cfg.redis)
    ).mapN(AppResources.apply[F])

  }

} 
Example 21
Source File: RepoCacheAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.repocache

import cats.Parallel
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import org.scalasteward.core.application.Config
import org.scalasteward.core.buildtool.BuildToolDispatcher
import org.scalasteward.core.data.{Dependency, DependencyInfo}
import org.scalasteward.core.git.GitAlg
import org.scalasteward.core.repoconfig.RepoConfigAlg
import org.scalasteward.core.util.MonadThrowable
import org.scalasteward.core.util.logger.LoggerOps
import org.scalasteward.core.vcs.data.{Repo, RepoOut}
import org.scalasteward.core.vcs.{VCSApiAlg, VCSRepoAlg}

final class RepoCacheAlg[F[_]](implicit
    buildToolDispatcher: BuildToolDispatcher[F],
    config: Config,
    gitAlg: GitAlg[F],
    logger: Logger[F],
    parallel: Parallel[F],
    refreshErrorAlg: RefreshErrorAlg[F],
    repoCacheRepository: RepoCacheRepository[F],
    repoConfigAlg: RepoConfigAlg[F],
    vcsApiAlg: VCSApiAlg[F],
    vcsRepoAlg: VCSRepoAlg[F],
    F: MonadThrowable[F]
) {
  def checkCache(repo: Repo): F[Unit] =
    logger.attemptLog_(s"Check cache of ${repo.show}") {
      F.ifM(refreshErrorAlg.failedRecently(repo))(
        logger.info(s"Skipping due to previous error"),
        for {
          ((repoOut, branchOut), cachedSha1) <- (
              vcsApiAlg.createForkOrGetRepoWithDefaultBranch(config, repo),
              repoCacheRepository.findSha1(repo)
          ).parTupled
          latestSha1 = branchOut.commit.sha
          refreshRequired = cachedSha1.forall(_ =!= latestSha1)
          _ <- if (refreshRequired) cloneAndRefreshCache(repo, repoOut) else F.unit
        } yield ()
      )
    }

  private def cloneAndRefreshCache(repo: Repo, repoOut: RepoOut): F[Unit] =
    for {
      _ <- logger.info(s"Refresh cache of ${repo.show}")
      _ <- vcsRepoAlg.clone(repo, repoOut)
      _ <- vcsRepoAlg.syncFork(repo, repoOut)
      _ <- refreshCache(repo)
    } yield ()

  private def refreshCache(repo: Repo): F[Unit] =
    computeCache(repo).attempt.flatMap {
      case Right(cache) =>
        repoCacheRepository.updateCache(repo, cache)
      case Left(throwable) =>
        refreshErrorAlg.persistError(repo, throwable) >> F.raiseError(throwable)
    }

  private def computeCache(repo: Repo): F[RepoCache] =
    for {
      branch <- gitAlg.currentBranch(repo)
      latestSha1 <- gitAlg.latestSha1(repo, branch)
      dependencies <- buildToolDispatcher.getDependencies(repo)
      dependencyInfos <-
        dependencies
          .traverse(_.traverse(_.traverse(gatherDependencyInfo(repo, _))))
      maybeRepoConfig <- repoConfigAlg.readRepoConfig(repo)
    } yield RepoCache(latestSha1, dependencyInfos, maybeRepoConfig)

  private def gatherDependencyInfo(repo: Repo, dependency: Dependency): F[DependencyInfo] =
    gitAlg.findFilesContaining(repo, dependency.version).map(DependencyInfo(dependency, _))
} 
Example 22
Source File: Programs.scala    From hydra   with Apache License 2.0 5 votes vote down vote up
package hydra.ingest.modules

import cats.effect._
import cats.implicits._
import hydra.ingest.app.AppConfig.AppConfig
import hydra.ingest.services.{IngestionFlow, IngestionFlowV2}
import hydra.kafka.programs.CreateTopicProgram
import io.chrisdavenport.log4cats.Logger
import retry.RetryPolicies._
import retry.RetryPolicy
import scalacache.Mode

final class Programs[F[_]: Logger: Sync: Timer: Mode] private(
    cfg: AppConfig,
    algebras: Algebras[F]
) {

  val retryPolicy: RetryPolicy[F] =
    limitRetries[F](cfg.createTopicConfig.numRetries) |+| exponentialBackoff[F](
      cfg.createTopicConfig.baseBackoffDelay
    )

  val createTopic: CreateTopicProgram[F] = new CreateTopicProgram[F](
    algebras.schemaRegistry,
    algebras.kafkaAdmin,
    algebras.kafkaClient,
    retryPolicy,
    cfg.v2MetadataTopicConfig.topicName,
    algebras.metadata
  )

  val ingestionFlow: IngestionFlow[F] = new IngestionFlow[F](
    algebras.schemaRegistry,
    algebras.kafkaClient,
    cfg.createTopicConfig.schemaRegistryConfig.fullUrl
  )

  val ingestionFlowV2: IngestionFlowV2[F] = new IngestionFlowV2[F](
    algebras.schemaRegistry,
    algebras.kafkaClient,
    cfg.createTopicConfig.schemaRegistryConfig.fullUrl
  )

}

object Programs {

  def make[F[_]: Logger: Sync: Timer: Mode](
      appConfig: AppConfig,
      algebras: Algebras[F]
  ): F[Programs[F]] = Sync[F].delay {
    new Programs[F](appConfig, algebras)
  }

} 
Example 23
Source File: Http4sTelegramClient.scala    From canoe   with MIT License 5 votes vote down vote up
package canoe.api.clients

import canoe.api.{FailedMethod, ResponseDecodingError, TelegramClient}
import canoe.methods.Method
import canoe.models.{InputFile, Response => TelegramResponse}
import cats.effect.Sync
import cats.syntax.all._
import fs2.Stream
import io.chrisdavenport.log4cats.Logger
import org.http4s._
import org.http4s.circe._
import org.http4s.client.Client
import org.http4s.client.dsl.Http4sClientDsl._
import org.http4s.multipart.{Multipart, Part}

private[api] class Http4sTelegramClient[F[_]: Sync: Logger](token: String, client: Client[F])
    extends TelegramClient[F] {

  private val botApiUri: Uri = Uri.unsafeFromString("https://api.telegram.org") / s"bot$token"

  def execute[Req, Res](request: Req)(implicit M: Method[Req, Res]): F[Res] = {

    val req = prepareRequest(botApiUri / M.name, M, request)

    implicit val decoder: EntityDecoder[F, TelegramResponse[Res]] =
      jsonOf(Sync[F], TelegramResponse.decoder(M.decoder))

    F.debug(s"Executing '${M.name}' Telegram method.") *>
      client
        .expect[TelegramResponse[Res]](req)
        .recoverWith { case error: InvalidMessageBodyFailure => handleUnknownEntity(M.name, request, error) }
        .flatMap(handleTelegramResponse(M, request))
  }

  private def handleUnknownEntity[I, A](method: String, input: I, error: InvalidMessageBodyFailure): F[A] =
    F.error(
      s"Received unknown Telegram entity during execution of '$method' method. \nInput data: $input. \n${error.details}"
    ) *>
      ResponseDecodingError(error.details.dropWhile(_ != '{')).raiseError[F, A]

  private def prepareRequest[Req, Res](url: Uri, method: Method[Req, Res], action: Req): F[Request[F]] = {
    val uploads = method.attachments(action).collect {
      case (name, InputFile.Upload(filename, contents)) =>
        Part.fileData(name, filename, Stream.emits(contents).covary[F])
    }

    if (uploads.isEmpty) jsonRequest(url, method, action)
    else multipartRequest(url, method, action, uploads)
  }

  private def jsonRequest[Req, Res](url: Uri, method: Method[Req, Res], action: Req): F[Request[F]] =
    Method.POST(action, url)(F, jsonEncoderOf(method.encoder))

  private def multipartRequest[Req, Res](url: Uri,
                                         method: Method[Req, Res],
                                         action: Req,
                                         parts: List[Part[F]]): F[Request[F]] = {
    val multipart = Multipart[F](parts.toVector)

    val params =
      method
        .encoder(action)
        .asObject
        .map(
          _.toIterable
            .filterNot(kv => kv._2.isNull || kv._2.isObject)
            .map { case (k, j) => k -> j.toString }
            .toMap
        )
        .getOrElse(Map.empty)

    val urlWithQueryParams = params.foldLeft(url) {
      case (url, (key, value)) => url.withQueryParam(key, value)
    }

    Method.POST(multipart, urlWithQueryParams).map(_.withHeaders(multipart.headers))
  }

  private def handleTelegramResponse[A, I, C](m: Method[I, A], input: I)(response: TelegramResponse[A]): F[A] =
    response match {
      case TelegramResponse(true, Some(result), _, _, _) => result.pure[F]

      case failed =>
        F.error(s"Received failed response from Telegram: $failed. Method name: ${m.name}, input data: $input") *>
          FailedMethod(m, input, failed).raiseError[F, A]
    }
} 
Example 24
Source File: Hook.scala    From canoe   with MIT License 5 votes vote down vote up
package canoe.api.sources

import canoe.api.{TelegramClient}
import canoe.methods.webhooks.{DeleteWebhook, SetWebhook}
import canoe.models.{InputFile, Update}
import canoe.syntax.methodOps
import cats.Monad
import cats.effect.{ConcurrentEffect, Resource, Timer}
import cats.syntax.all._
import fs2.Stream
import fs2.concurrent.Queue
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import org.http4s._
import org.http4s.circe.jsonOf
import org.http4s.dsl.Http4sDsl
import org.http4s.implicits._
import org.http4s.server.Server
import org.http4s.server.blaze.BlazeServerBuilder

class Hook[F[_]](queue: Queue[F, Update]) {
  def updates: Stream[F, Update] = queue.dequeue
}

object Hook {

  
  private def listenServer[F[_]: ConcurrentEffect: Timer: Logger](port: Int): Resource[F, Hook[F]] = {
    val dsl = Http4sDsl[F]
    import dsl._

    def app(queue: Queue[F, Update]): HttpApp[F] =
      HttpRoutes
        .of[F] {
          case req @ POST -> Root =>
            req
              .decodeWith(jsonOf[F, Update], strict = true)(queue.enqueue1(_) *> Ok())
              .recoverWith {
                case InvalidMessageBodyFailure(details, _) =>
                  F.error(s"Received unknown type of update. $details") *> Ok()
              }
        }
        .orNotFound

    def server(queue: Queue[F, Update]): Resource[F, Server[F]] =
      BlazeServerBuilder[F].bindHttp(port).withHttpApp(app(queue)).resource

    Resource.suspend(Queue.unbounded[F, Update].map(q => server(q).map(_ => new Hook[F](q))))
  }
} 
Example 25
Source File: EditAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.edit

import better.files.File
import cats.Traverse
import cats.implicits._
import fs2.Stream
import io.chrisdavenport.log4cats.Logger
import org.scalasteward.core.buildtool.BuildToolDispatcher
import org.scalasteward.core.data.Update
import org.scalasteward.core.io.{isSourceFile, FileAlg, WorkspaceAlg}
import org.scalasteward.core.scalafix.MigrationAlg
import org.scalasteward.core.util._
import org.scalasteward.core.vcs.data.Repo

final class EditAlg[F[_]](implicit
    buildToolDispatcher: BuildToolDispatcher[F],
    fileAlg: FileAlg[F],
    logger: Logger[F],
    migrationAlg: MigrationAlg,
    streamCompiler: Stream.Compiler[F, F],
    workspaceAlg: WorkspaceAlg[F],
    F: MonadThrowable[F]
) {
  def applyUpdate(repo: Repo, update: Update, fileExtensions: Set[String]): F[Unit] =
    for {
      _ <- applyScalafixMigrations(repo, update).handleErrorWith(e =>
        logger.warn(s"Could not apply ${update.show} : $e")
      )
      repoDir <- workspaceAlg.repoDir(repo)
      files <- fileAlg.findFilesContaining(
        repoDir,
        update.currentVersion,
        isSourceFile(update, fileExtensions)
      )
      noFilesFound = logger.warn("No files found that contain the current version")
      _ <- files.toNel.fold(noFilesFound)(applyUpdateTo(_, update))
    } yield ()

  def applyUpdateTo[G[_]: Traverse](files: G[File], update: Update): F[Unit] = {
    val actions = UpdateHeuristic.all.map { heuristic =>
      logger.info(s"Trying heuristic '${heuristic.name}'") >>
        fileAlg.editFiles(files, heuristic.replaceVersion(update))
    }
    bindUntilTrue(actions).void
  }

  def applyScalafixMigrations(repo: Repo, update: Update): F[Unit] =
    Nel.fromList(migrationAlg.findMigrations(update)).traverse_ { migrations =>
      logger.info(s"Applying migrations: $migrations") >>
        buildToolDispatcher.runMigrations(repo, migrations)
    }
} 
Example 26
Source File: StewardAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.application

import better.files.File
import cats.Monad
import cats.effect.ExitCode
import cats.implicits._
import fs2.Stream
import io.chrisdavenport.log4cats.Logger
import org.scalasteward.core.buildtool.sbt.SbtAlg
import org.scalasteward.core.git.GitAlg
import org.scalasteward.core.io.{FileAlg, WorkspaceAlg}
import org.scalasteward.core.nurture.NurtureAlg
import org.scalasteward.core.repocache.RepoCacheAlg
import org.scalasteward.core.update.PruningAlg
import org.scalasteward.core.util
import org.scalasteward.core.util.DateTimeAlg
import org.scalasteward.core.util.logger.LoggerOps
import org.scalasteward.core.vcs.data.Repo

final class StewardAlg[F[_]](implicit
    config: Config,
    dateTimeAlg: DateTimeAlg[F],
    fileAlg: FileAlg[F],
    gitAlg: GitAlg[F],
    logger: Logger[F],
    nurtureAlg: NurtureAlg[F],
    pruningAlg: PruningAlg[F],
    repoCacheAlg: RepoCacheAlg[F],
    sbtAlg: SbtAlg[F],
    selfCheckAlg: SelfCheckAlg[F],
    streamCompiler: Stream.Compiler[F, F],
    workspaceAlg: WorkspaceAlg[F],
    F: Monad[F]
) {
  private def printBanner: F[Unit] = {
    val banner =
      """|  ____            _         ____  _                             _
         | / ___|  ___ __ _| | __ _  / ___|| |_ _____      ____ _ _ __ __| |
         | \___ \ / __/ _` | |/ _` | \___ \| __/ _ \ \ /\ / / _` | '__/ _` |
         |  ___) | (_| (_| | | (_| |  ___) | ||  __/\ V  V / (_| | | | (_| |
         | |____/ \___\__,_|_|\__,_| |____/ \__\___| \_/\_/ \__,_|_|  \__,_|""".stripMargin
    val msg = List(" ", banner, s" v${org.scalasteward.core.BuildInfo.version}", " ")
      .mkString(System.lineSeparator())
    logger.info(msg)
  }

  private def readRepos(reposFile: File): F[List[Repo]] =
    fileAlg.readFile(reposFile).map { maybeContent =>
      val regex = """-\s+(.+)/([^/]+)""".r
      val content = maybeContent.getOrElse("")
      content.linesIterator.collect {
        case regex(owner, repo) => Repo(owner.trim, repo.trim)
      }.toList
    }

  private def steward(repo: Repo): F[Either[Throwable, Unit]] = {
    val label = s"Steward ${repo.show}"
    logger.infoTotalTime(label) {
      for {
        _ <- logger.info(util.string.lineLeftRight(label))
        _ <- repoCacheAlg.checkCache(repo)
        (attentionNeeded, updates) <- pruningAlg.needsAttention(repo)
        result <- {
          if (attentionNeeded) nurtureAlg.nurture(repo, updates)
          else gitAlg.removeClone(repo).as(().asRight[Throwable])
        }
      } yield result
    }
  }

  def runF: F[ExitCode] =
    logger.infoTotalTime("run") {
      for {
        _ <- printBanner
        _ <- selfCheckAlg.checkAll
        exitCode <- sbtAlg.addGlobalPlugins {
          for {
            _ <- workspaceAlg.cleanWorkspace
            repos <- readRepos(config.reposFile)
            result <- Stream.emits(repos).evalMap(steward).compile.foldMonoid
          } yield result.fold(_ => ExitCode.Error, _ => ExitCode.Success)
        }
      } yield exitCode
    }
} 
Example 27
Source File: SelfCheckAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.application

import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import org.http4s.Uri
import org.scalasteward.core.util.{HttpExistenceClient, MonadThrowable}

final class SelfCheckAlg[F[_]](implicit
    httpExistenceClient: HttpExistenceClient[F],
    logger: Logger[F],
    F: MonadThrowable[F]
) {
  def checkAll: F[Unit] =
    for {
      _ <- logger.info("Run self checks")
      _ <- checkHttpExistenceClient
    } yield ()

  private def checkHttpExistenceClient: F[Unit] =
    for {
      url <- F.fromEither(Uri.fromString("https://github.com"))
      res <- httpExistenceClient.exists(url)
      msg = s"Self check of HttpExistenceClient failed: checking that $url exists failed"
      _ <- if (!res) logger.warn(msg) else F.unit
    } yield ()
} 
Example 28
Source File: Context.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.application

import cats.Parallel
import cats.effect._
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import org.http4s.client.Client
import org.http4s.client.asynchttpclient.AsyncHttpClient
import org.scalasteward.core.buildtool.BuildToolDispatcher
import org.scalasteward.core.buildtool.maven.MavenAlg
import org.scalasteward.core.buildtool.mill.MillAlg
import org.scalasteward.core.buildtool.sbt.SbtAlg
import org.scalasteward.core.coursier.{CoursierAlg, VersionsCache}
import org.scalasteward.core.edit.EditAlg
import org.scalasteward.core.git.GitAlg
import org.scalasteward.core.io.{FileAlg, ProcessAlg, WorkspaceAlg}
import org.scalasteward.core.nurture.{NurtureAlg, PullRequestRepository}
import org.scalasteward.core.persistence.JsonKeyValueStore
import org.scalasteward.core.repocache.{RefreshErrorAlg, RepoCacheAlg, RepoCacheRepository}
import org.scalasteward.core.repoconfig.RepoConfigAlg
import org.scalasteward.core.scalafix.MigrationAlg
import org.scalasteward.core.scalafmt.ScalafmtAlg
import org.scalasteward.core.update.{FilterAlg, GroupMigrations, PruningAlg, UpdateAlg}
import org.scalasteward.core.util._
import org.scalasteward.core.util.uri._
import org.scalasteward.core.vcs.data.AuthenticatedUser
import org.scalasteward.core.vcs.{VCSApiAlg, VCSExtraAlg, VCSRepoAlg, VCSSelection}

object Context {
  def create[F[_]: ConcurrentEffect: ContextShift: Parallel: Timer](
      args: List[String]
  ): Resource[F, StewardAlg[F]] =
    for {
      blocker <- Blocker[F]
      cliArgs_ <- Resource.liftF(new Cli[F].parseArgs(args))
      implicit0(config: Config) <- Resource.liftF(Config.create[F](cliArgs_))
      implicit0(client: Client[F]) <- AsyncHttpClient.resource[F]()
      implicit0(logger: Logger[F]) <- Resource.liftF(Slf4jLogger.create[F])
      implicit0(httpExistenceClient: HttpExistenceClient[F]) <- HttpExistenceClient.create[F]
      implicit0(user: AuthenticatedUser) <- Resource.liftF(config.vcsUser[F])
      implicit0(fileAlg: FileAlg[F]) = FileAlg.create[F]
      implicit0(migrationAlg: MigrationAlg) <- Resource.liftF(
        MigrationAlg.create[F](config.scalafixMigrations)
      )
      implicit0(groupMigration: GroupMigrations) <- Resource.liftF(GroupMigrations.create[F])
    } yield {
      val kvsPrefix = Some(config.vcsType.asString)
      implicit val dateTimeAlg: DateTimeAlg[F] = DateTimeAlg.create[F]
      implicit val processAlg: ProcessAlg[F] = ProcessAlg.create[F](blocker)
      implicit val workspaceAlg: WorkspaceAlg[F] = WorkspaceAlg.create[F]
      implicit val repoConfigAlg: RepoConfigAlg[F] = new RepoConfigAlg[F]
      implicit val filterAlg: FilterAlg[F] = new FilterAlg[F]
      implicit val gitAlg: GitAlg[F] = GitAlg.create[F]
      implicit val httpJsonClient: HttpJsonClient[F] = new HttpJsonClient[F]
      implicit val repoCacheRepository: RepoCacheRepository[F] =
        new RepoCacheRepository[F](new JsonKeyValueStore("repo_cache", "1", kvsPrefix))
      implicit val selfCheckAlg: SelfCheckAlg[F] = new SelfCheckAlg[F]
      val vcsSelection = new VCSSelection[F]
      implicit val vcsApiAlg: VCSApiAlg[F] = vcsSelection.getAlg(config)
      implicit val vcsRepoAlg: VCSRepoAlg[F] = VCSRepoAlg.create[F](config, gitAlg)
      implicit val vcsExtraAlg: VCSExtraAlg[F] = VCSExtraAlg.create[F]
      implicit val pullRequestRepository: PullRequestRepository[F] =
        new PullRequestRepository[F](new JsonKeyValueStore("pull_requests", "2", kvsPrefix))
      implicit val scalafmtAlg: ScalafmtAlg[F] = ScalafmtAlg.create[F]
      implicit val coursierAlg: CoursierAlg[F] = CoursierAlg.create[F]
      implicit val versionsCache: VersionsCache[F] =
        new VersionsCache[F](config.cacheTtl, new JsonKeyValueStore("versions", "2"))
      implicit val updateAlg: UpdateAlg[F] = new UpdateAlg[F]
      implicit val mavenAlg: MavenAlg[F] = MavenAlg.create[F]
      implicit val sbtAlg: SbtAlg[F] = SbtAlg.create[F]
      implicit val millAlg: MillAlg[F] = MillAlg.create[F]
      implicit val buildToolDispatcher: BuildToolDispatcher[F] = BuildToolDispatcher.create[F]
      implicit val refreshErrorAlg: RefreshErrorAlg[F] =
        new RefreshErrorAlg[F](new JsonKeyValueStore("refresh_error", "1", kvsPrefix))
      implicit val repoCacheAlg: RepoCacheAlg[F] = new RepoCacheAlg[F]
      implicit val editAlg: EditAlg[F] = new EditAlg[F]
      implicit val nurtureAlg: NurtureAlg[F] = new NurtureAlg[F]
      implicit val pruningAlg: PruningAlg[F] = new PruningAlg[F]
      new StewardAlg[F]
    }
} 
Example 29
Source File: RepoConfigAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.repoconfig

import better.files.File
import cats.data.OptionT
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import io.circe.config.parser
import org.scalasteward.core.application.Config
import org.scalasteward.core.data.Update
import org.scalasteward.core.io.{FileAlg, WorkspaceAlg}
import org.scalasteward.core.repoconfig.RepoConfigAlg._
import org.scalasteward.core.util.MonadThrowable
import org.scalasteward.core.vcs.data.Repo

final class RepoConfigAlg[F[_]](implicit
    config: Config,
    fileAlg: FileAlg[F],
    logger: Logger[F],
    workspaceAlg: WorkspaceAlg[F],
    F: MonadThrowable[F]
) {
  def readRepoConfigOrDefault(repo: Repo): F[RepoConfig] =
    readRepoConfig(repo).flatMap { config =>
      config.map(F.pure).getOrElse(defaultRepoConfig)
    }

  
  val defaultRepoConfig: F[RepoConfig] =
    OptionT
      .fromOption[F](config.defaultRepoConfigFile)
      .flatMap(readRepoConfigFromFile)
      .getOrElse(RepoConfig.empty)

  def readRepoConfig(repo: Repo): F[Option[RepoConfig]] =
    workspaceAlg
      .repoDir(repo)
      .flatMap(dir => readRepoConfigFromFile(dir / repoConfigBasename).value)

  private def readRepoConfigFromFile(configFile: File): OptionT[F, RepoConfig] =
    OptionT(fileAlg.readFile(configFile)).map(parseRepoConfig).flatMapF {
      case Right(repoConfig) => logger.info(s"Parsed $repoConfig").as(repoConfig.some)
      case Left(errorMsg)    => logger.info(errorMsg).as(none[RepoConfig])
    }
}

object RepoConfigAlg {
  val repoConfigBasename: String = ".scala-steward.conf"

  def parseRepoConfig(input: String): Either[String, RepoConfig] =
    parser.decode[RepoConfig](input).leftMap { error =>
      s"Failed to parse $repoConfigBasename: ${error.getMessage}"
    }

  def configToIgnoreFurtherUpdates(update: Update): String =
    update match {
      case s: Update.Single =>
        s"""updates.ignore = [ { groupId = "${s.groupId}", artifactId = "${s.artifactId.name}" } ]"""
      case g: Update.Group =>
        s"""updates.ignore = [ { groupId = "${g.groupId}" } ]"""
    }
} 
Example 30
Source File: JsonKeyValueStore.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.persistence

import better.files.File
import cats.Monad
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import io.circe.parser.decode
import io.circe.syntax._
import io.circe.{Decoder, Encoder, KeyEncoder}
import org.scalasteward.core.io.{FileAlg, WorkspaceAlg}

final class JsonKeyValueStore[F[_], K, V](
    name: String,
    schemaVersion: String,
    maybePrefix: Option[String] = None
)(implicit
    fileAlg: FileAlg[F],
    keyEncoder: KeyEncoder[K],
    logger: Logger[F],
    valueDecoder: Decoder[V],
    valueEncoder: Encoder[V],
    workspaceAlg: WorkspaceAlg[F],
    F: Monad[F]
) extends KeyValueStore[F, K, V] {
  override def get(key: K): F[Option[V]] =
    jsonFile(key).flatMap { file =>
      fileAlg.readFile(file).flatMap {
        case Some(content) =>
          decode[Option[V]](content) match {
            case Right(maybeValue) => F.pure(maybeValue)
            case Left(error) =>
              logger.error(error)(s"Failed to parse or decode JSON from $file").as(Option.empty[V])
          }
        case None => F.pure(Option.empty[V])
      }
    }

  override def put(key: K, value: V): F[Unit] =
    write(key, Some(value))

  override def modifyF(key: K)(f: Option[V] => F[Option[V]]): F[Option[V]] =
    get(key).flatMap(maybeValue => f(maybeValue).flatTap(write(key, _)))

  private def jsonFile(key: K): F[File] = {
    val keyPath = maybePrefix.fold("")(_ + "/") + keyEncoder(key)
    workspaceAlg.rootDir.map(_ / "store" / name / s"v$schemaVersion" / keyPath / s"$name.json")
  }

  private def write(key: K, value: Option[V]): F[Unit] =
    jsonFile(key).flatMap(fileAlg.writeFile(_, value.asJson.toString))
} 
Example 31
Source File: HttpExistenceClient.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.util

import cats.effect.{Async, Resource}
import cats.implicits._
import com.github.benmanes.caffeine.cache.Caffeine
import io.chrisdavenport.log4cats.Logger
import org.http4s.client.Client
import org.http4s.{Method, Request, Status, Uri}
import org.scalasteward.core.application.Config
import scalacache.CatsEffect.modes._
import scalacache.caffeine.CaffeineCache
import scalacache.{Async => _, _}

final class HttpExistenceClient[F[_]](statusCache: Cache[Status])(implicit
    client: Client[F],
    logger: Logger[F],
    mode: Mode[F],
    F: MonadThrowable[F]
) {
  def exists(uri: Uri): F[Boolean] =
    status(uri).map(_ === Status.Ok).handleErrorWith { throwable =>
      logger.debug(throwable)(s"Failed to check if $uri exists").as(false)
    }

  private def status(uri: Uri): F[Status] =
    statusCache.cachingForMemoizeF(uri.renderString)(None) {
      client.status(Request[F](method = Method.HEAD, uri = uri))
    }
}

object HttpExistenceClient {
  def create[F[_]](implicit
      config: Config,
      client: Client[F],
      logger: Logger[F],
      F: Async[F]
  ): Resource[F, HttpExistenceClient[F]] = {
    val buildCache = F.delay {
      CaffeineCache(
        Caffeine
          .newBuilder()
          .maximumSize(16384L)
          .expireAfterWrite(config.cacheTtl.length, config.cacheTtl.unit)
          .build[String, Entry[Status]]()
      )
    }
    Resource.make(buildCache)(_.close().void).map(new HttpExistenceClient[F](_))
  }
} 
Example 32
Source File: logger.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.util

import cats.implicits._
import cats.{Foldable, Functor, Monad}
import io.chrisdavenport.log4cats.Logger
import org.scalasteward.core.data.Update
import scala.concurrent.duration.FiniteDuration

object logger {
  implicit final class LoggerOps[F[_]](private val logger: Logger[F]) extends AnyVal {
    def attemptLog[A](message: String)(fa: F[A])(implicit
        F: MonadThrowable[F]
    ): F[Either[Throwable, A]] =
      logger.info(message) >> fa.attempt.flatTap {
        case Left(t)  => logger.error(t)(s"$message failed")
        case Right(_) => F.unit
      }

    def attemptLog_[A](message: String)(fa: F[A])(implicit F: MonadThrowable[F]): F[Unit] =
      attemptLog(message)(fa).void

    def infoTimed[A](msg: FiniteDuration => String)(fa: F[A])(implicit
        dateTimeAlg: DateTimeAlg[F],
        F: Monad[F]
    ): F[A] =
      dateTimeAlg.timed(fa).flatMap {
        case (a, duration) => logger.info(msg(duration)) >> F.pure(a)
      }

    def infoTotalTime[A](label: String)(fa: F[A])(implicit
        dateTimeAlg: DateTimeAlg[F],
        F: Monad[F]
    ): F[A] = {
      val label1 = if (label.nonEmpty) s" $label:" else ""
      infoTimed { duration =>
        string.lineLeftRight(s"Total time:$label1 ${dateTime.showDuration(duration)}")
      }(fa)
    }
  }

  def showUpdates[F[_]: Foldable: Functor](updates: F[Update]): String = {
    val list = string.indentLines(updates.map(_.show))
    updates.size match {
      case 0 => s"Found 0 updates"
      case 1 => s"Found 1 update:\n$list"
      case n => s"Found $n updates:\n$list"
    }
  }
} 
Example 33
Source File: WorkspaceAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.io

import better.files.File
import cats.FlatMap
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import org.scalasteward.core.application.Config
import org.scalasteward.core.vcs.data.Repo

trait WorkspaceAlg[F[_]] {
  def cleanWorkspace: F[Unit]

  def rootDir: F[File]

  def repoDir(repo: Repo): F[File]
}

object WorkspaceAlg {
  def create[F[_]](implicit
      fileAlg: FileAlg[F],
      logger: Logger[F],
      config: Config,
      F: FlatMap[F]
  ): WorkspaceAlg[F] =
    new WorkspaceAlg[F] {
      private[this] val reposDir = config.workspace / "repos"

      override def cleanWorkspace: F[Unit] =
        for {
          _ <- logger.info(s"Clean workspace ${config.workspace}")
          _ <- fileAlg.deleteForce(reposDir)
          _ <- rootDir
        } yield ()

      override def rootDir: F[File] =
        fileAlg.ensureExists(config.workspace)

      override def repoDir(repo: Repo): F[File] =
        fileAlg.ensureExists(reposDir / repo.owner / repo.repo)
    }
} 
Example 34
Source File: ProcessAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.io

import better.files.File
import cats.effect.{Blocker, Concurrent, ContextShift, Timer}
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import org.scalasteward.core.application.Cli.EnvVar
import org.scalasteward.core.application.Config
import org.scalasteward.core.util.Nel

trait ProcessAlg[F[_]] {
  def exec(command: Nel[String], cwd: File, extraEnv: (String, String)*): F[List[String]]

  def execSandboxed(command: Nel[String], cwd: File): F[List[String]]
}

object ProcessAlg {
  abstract class UsingFirejail[F[_]](config: Config) extends ProcessAlg[F] {
    override def execSandboxed(command: Nel[String], cwd: File): F[List[String]] = {
      val envVars = config.envVars.map(EnvVar.unapply(_).get)
      if (config.disableSandbox)
        exec(command, cwd, envVars: _*)
      else {
        val whitelisted = (cwd.pathAsString :: config.whitelistedDirectories)
          .map(dir => s"--whitelist=$dir")
        val readOnly = config.readOnlyDirectories
          .map(dir => s"--read-only=$dir")
        exec(Nel("firejail", whitelisted ++ readOnly) ::: command, cwd, envVars: _*)
      }
    }
  }

  def create[F[_]](blocker: Blocker)(implicit
      config: Config,
      contextShift: ContextShift[F],
      logger: Logger[F],
      timer: Timer[F],
      F: Concurrent[F]
  ): ProcessAlg[F] =
    new UsingFirejail[F](config) {
      override def exec(
          command: Nel[String],
          cwd: File,
          extraEnv: (String, String)*
      ): F[List[String]] =
        logger.debug(s"Execute ${command.mkString_(" ")}") >>
          process.slurp[F](
            command,
            Some(cwd.toJava),
            extraEnv.toMap,
            config.processTimeout,
            logger.trace(_),
            blocker
          )
    }
} 
Example 35
Source File: log4cats.scala    From http4s-tracer   with Apache License 2.0 5 votes vote down vote up
package dev.profunktor.tracer

import dev.profunktor.tracer.Trace._
import io.chrisdavenport.log4cats.Logger

import scala.reflect.ClassTag

object log4cats {

  implicit def log4CatsInstance[F[_]](implicit L: Logger[F]): TracerLog[Trace[F, ?]] =
    new TracerLog[Trace[F, ?]] {
      override def info[A: ClassTag](value: => String): Trace[F, Unit] = Trace { id =>
        L.info(s"$id - $value")
      }
      override def error[A: ClassTag](value: => String): Trace[F, Unit] = Trace { id =>
        L.error(s"$id - $value")
      }
      override def warn[A: ClassTag](value: => String): Trace[F, Unit] = Trace { id =>
        L.warn(s"$id - $value")
      }
    }

} 
Example 36
Source File: ProjectionFlow.scala    From ticket-booking-aecor   with Apache License 2.0 5 votes vote down vote up
package ru.pavkin.booking.common.view

import aecor.data.{Committable, EntityEvent}
import cats.effect.Sync
import io.chrisdavenport.log4cats.Logger
import cats.implicits._


object ProjectionFlow {

  def apply[F[_], K, E, S](log: Logger[F],
                           aggregateProjection: Projection[F, EntityEvent[K, E], S],
  )(implicit F: Sync[F]): fs2.Pipe[F, Committable[F, EntityEvent[K, E]], Unit] = {

    def foldEvent(event: EntityEvent[K, E], state: Option[S]): F[Option[S]] = {
      val newVersion = aggregateProjection.applyEvent(state)(event)
      log.debug(s"New version [$newVersion]") >>
        newVersion
          .fold(
            F.raiseError[Option[S]](
              new IllegalStateException(s"Projection failed for state = [$state], event = [$event]")
            )
          )(_.pure[F])
    }

    def runProjection(event: EntityEvent[K, E]): F[Unit] =
      for {
        (currentVersion, currentState) <- aggregateProjection.fetchVersionAndState(event)
        _ <- log.debug(s"Current $currentVersion [$currentState]")
        _ <- F.whenA(currentVersion.value < event.sequenceNr) {
              foldEvent(event, currentState).flatMap {
                case None => F.unit

                case Some(state) =>
                  aggregateProjection.saveNewVersion(state, currentVersion.next)
              }
            }
      } yield ()

    _.evalMap(_.traverse(runProjection)).evalMap(_.commit)
  }
} 
Example 37
Source File: BookingPaymentProcess.scala    From ticket-booking-aecor   with Apache License 2.0 5 votes vote down vote up
package ru.pavkin.booking.booking.process

import cats.Monad
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import ru.pavkin.booking.booking.booking.Bookings
import ru.pavkin.payment.event.PaymentReceived

class BookingPaymentProcess[F[_]: Monad](bookings: Bookings[F], logger: Logger[F])
    extends (PaymentReceived => F[Unit]) {

  def apply(evt: PaymentReceived): F[Unit] =
    evt.bookingId match {
      case None => ().pure[F] // not booking related payment, ignoring
      case Some(id) =>
        bookings(id).receivePayment(evt.paymentId).flatMap {
          case Right(_) =>
            logger.info(s"Payment received successfully for booking $id of client ${evt.clientId}")
          case Left(rej) =>
            logger
              .warn(
                s"Failed to apply received payment for booking $id of client ${evt.clientId}. Reason: $rej"
              )

        }
    }
} 
Example 38
Source File: BookingConfirmationProcess.scala    From ticket-booking-aecor   with Apache License 2.0 5 votes vote down vote up
package ru.pavkin.booking.booking.process

import cats.Monad
import ru.pavkin.booking.booking.booking.Bookings
import ru.pavkin.booking.booking.entity.BookingPlaced
import ru.pavkin.booking.booking.service.TicketReservationService
import ru.pavkin.booking.common.models.BookingKey
import cats.implicits._
import io.chrisdavenport.log4cats.Logger

class BookingConfirmationProcess[F[_]: Monad](bookings: Bookings[F],
                                              reservationService: TicketReservationService[F],
                                              logger: Logger[F])
    extends ((BookingKey, BookingPlaced) => F[Unit]) {

  def apply(key: BookingKey, event: BookingPlaced): F[Unit] =
    for {
      reservation <- reservationService.reserve(key, event.concertId, event.seats)
      commandResult <- reservation.fold(
                        err => bookings(key).deny(err.toString),
                        reservation => bookings(key).confirm(reservation.tickets, reservation.expiresAt)
                      )
      res <- commandResult.fold(
              r => logger.error(s"Booking confirmation process got unexpected rejection for $key: $r"),
              _.pure[F]
            )
    } yield res
} 
Example 39
Source File: KubeConfig.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client

import java.io.File

import cats.effect.Sync
import com.goyeau.kubernetes.client.util.Yamls
import io.chrisdavenport.log4cats.Logger
import org.http4s.Uri
import org.http4s.headers.Authorization

case class KubeConfig(
    server: Uri,
    authorization: Option[Authorization] = None,
    caCertData: Option[String] = None,
    caCertFile: Option[File] = None,
    clientCertData: Option[String] = None,
    clientCertFile: Option[File] = None,
    clientKeyData: Option[String] = None,
    clientKeyFile: Option[File] = None,
    clientKeyPass: Option[String] = None
) {
  require(caCertData.isEmpty || caCertFile.isEmpty, "caCertData and caCertFile can't be set at the same time")
  require(
    clientCertData.isEmpty || clientCertFile.isEmpty,
    "clientCertData and clientCertFile can't be set at the same time"
  )
}

object KubeConfig {

  @deprecated(message = "Use fromFile instead", since = "0.4.1")
  def apply[F[_]: Sync: Logger](kubeconfig: File): F[KubeConfig]    = fromFile(kubeconfig)
  def fromFile[F[_]: Sync: Logger](kubeconfig: File): F[KubeConfig] = Yamls.fromKubeConfigFile(kubeconfig, None)

  @deprecated(message = "Use fromFile instead", since = "0.4.1")
  def apply[F[_]: Sync: Logger](kubeconfig: File, contextName: String): F[KubeConfig] =
    fromFile(kubeconfig, contextName)
  def fromFile[F[_]: Sync: Logger](kubeconfig: File, contextName: String): F[KubeConfig] =
    Yamls.fromKubeConfigFile(kubeconfig, Option(contextName))
} 
Example 40
Source File: Algebras.scala    From hydra   with Apache License 2.0 4 votes vote down vote up
package hydra.ingest.modules

import cats.effect.{Async, ConcurrentEffect, ContextShift, Timer}
import cats.implicits._
import hydra.avro.registry.SchemaRegistry
import hydra.ingest.app.AppConfig.AppConfig
import hydra.kafka.algebras.{KafkaAdminAlgebra, KafkaClientAlgebra, MetadataAlgebra}
import io.chrisdavenport.log4cats.Logger

final class Algebras[F[_]] private (
    val schemaRegistry: SchemaRegistry[F],
    val kafkaAdmin: KafkaAdminAlgebra[F],
    val kafkaClient: KafkaClientAlgebra[F],
    val metadata: MetadataAlgebra[F]
)

object Algebras {

  def make[F[_]: Async: ConcurrentEffect: ContextShift: Timer: Logger](config: AppConfig): F[Algebras[F]] =
    for {
      schemaRegistry <- SchemaRegistry.live[F](
        config.createTopicConfig.schemaRegistryConfig.fullUrl,
        config.createTopicConfig.schemaRegistryConfig.maxCacheSize
      )
      kafkaAdmin <- KafkaAdminAlgebra.live[F](config.createTopicConfig.bootstrapServers)
      kafkaClient <- KafkaClientAlgebra.live[F](config.createTopicConfig.bootstrapServers, schemaRegistry, config.ingestConfig.recordSizeLimitBytes)
      metadata <- MetadataAlgebra.make[F](config.v2MetadataTopicConfig.topicName.value,
        config.v2MetadataTopicConfig.consumerGroup, kafkaClient, schemaRegistry, config.v2MetadataTopicConfig.createOnStartup)
    } yield new Algebras[F](schemaRegistry, kafkaAdmin, kafkaClient, metadata)
}