org.http4s.Uri Scala Examples

The following examples show how to use org.http4s.Uri. 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: DeploymentsApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe._
import io.k8s.api.apps.v1.{Deployment, DeploymentList}
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.implicits._

private[client] case class DeploymentsApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[DeploymentList],
    encoder: Encoder[Deployment],
    decoder: Decoder[Deployment]
) extends Listable[F, DeploymentList] {
  val resourceUri: Uri = uri"/apis" / "apps" / "v1" / "deployments"

  def namespace(namespace: String): NamespacedDeploymentsApi[F] =
    NamespacedDeploymentsApi(httpClient, config, namespace)
}

private[client] case class NamespacedDeploymentsApi[F[_]](
    httpClient: Client[F],
    config: KubeConfig,
    namespace: String
)(implicit
    val F: Sync[F],
    val resourceEncoder: Encoder[Deployment],
    val resourceDecoder: Decoder[Deployment],
    val listDecoder: Decoder[DeploymentList]
) extends Creatable[F, Deployment]
    with Replaceable[F, Deployment]
    with Gettable[F, Deployment]
    with Listable[F, DeploymentList]
    with Deletable[F]
    with DeletableTerminated[F]
    with GroupDeletable[F]
    with Watchable[F, Deployment] {
  val resourceUri: Uri = uri"/apis" / "apps" / "v1" / "namespaces" / namespace / "deployments"
} 
Example 2
Source File: StatefulSetsApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe._
import io.k8s.api.apps.v1.{StatefulSet, StatefulSetList}
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.implicits._

private[client] case class StatefulSetsApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[StatefulSetList],
    encoder: Encoder[StatefulSet],
    decoder: Decoder[StatefulSet]
) extends Listable[F, StatefulSetList] {
  val resourceUri: Uri = uri"/apis" / "apps" / "v1" / "statefulsets"

  def namespace(namespace: String): NamespacedStatefulSetsApi[F] =
    NamespacedStatefulSetsApi(httpClient, config, namespace)
}

private[client] case class NamespacedStatefulSetsApi[F[_]](
    httpClient: Client[F],
    config: KubeConfig,
    namespace: String
)(implicit
    val F: Sync[F],
    val resourceEncoder: Encoder[StatefulSet],
    val resourceDecoder: Decoder[StatefulSet],
    val listDecoder: Decoder[StatefulSetList]
) extends Creatable[F, StatefulSet]
    with Replaceable[F, StatefulSet]
    with Gettable[F, StatefulSet]
    with Listable[F, StatefulSetList]
    with Deletable[F]
    with DeletableTerminated[F]
    with GroupDeletable[F]
    with Watchable[F, StatefulSet] {
  val resourceUri: Uri = uri"/apis" / "apps" / "v1" / "namespaces" / namespace / "statefulsets"
} 
Example 3
Source File: SecretsApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import java.util.Base64
import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe._
import io.k8s.api.core.v1.{Secret, SecretList}
import org.http4s.{Status, Uri}
import org.http4s.client.Client
import org.http4s.implicits._
import scala.collection.compat._

private[client] case class SecretsApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[SecretList],
    encoder: Encoder[Secret],
    decoder: Decoder[Secret]
) extends Listable[F, SecretList] {
  val resourceUri = uri"/api" / "v1" / "secrets"

  def namespace(namespace: String) = NamespacedSecretsApi(httpClient, config, namespace)
}

private[client] case class NamespacedSecretsApi[F[_]](
    httpClient: Client[F],
    config: KubeConfig,
    namespace: String
)(implicit
    val F: Sync[F],
    val resourceEncoder: Encoder[Secret],
    val resourceDecoder: Decoder[Secret],
    val listDecoder: Decoder[SecretList]
) extends Creatable[F, Secret]
    with Replaceable[F, Secret]
    with Gettable[F, Secret]
    with Listable[F, SecretList]
    with Deletable[F]
    with GroupDeletable[F]
    with Watchable[F, Secret] {
  val resourceUri: Uri = uri"/api" / "v1" / "namespaces" / namespace / "secrets"

  def createEncode(resource: Secret): F[Status] = create(encode(resource))

  def createOrUpdateEncode(resource: Secret): F[Status] =
    createOrUpdate(encode(resource))

  private def encode(resource: Secret) =
    resource.copy(data = resource.data.map(_.view.mapValues(v => Base64.getEncoder.encodeToString(v.getBytes)).toMap))
} 
Example 4
Source File: ConfigMapsApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe._
import io.k8s.api.core.v1.{ConfigMap, ConfigMapList}
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.implicits._

private[client] case class ConfigMapsApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[ConfigMapList],
    encoder: Encoder[ConfigMap],
    decoder: Decoder[ConfigMap]
) extends Listable[F, ConfigMapList] {
  val resourceUri: Uri = uri"/api" / "v1" / "configmaps"

  def namespace(namespace: String): NamespacedConfigMapsApi[F] = NamespacedConfigMapsApi(httpClient, config, namespace)
}

private[client] case class NamespacedConfigMapsApi[F[_]](
    httpClient: Client[F],
    config: KubeConfig,
    namespace: String
)(implicit
    val F: Sync[F],
    val resourceEncoder: Encoder[ConfigMap],
    val resourceDecoder: Decoder[ConfigMap],
    val listDecoder: Decoder[ConfigMapList]
) extends Creatable[F, ConfigMap]
    with Replaceable[F, ConfigMap]
    with Gettable[F, ConfigMap]
    with Listable[F, ConfigMapList]
    with Deletable[F]
    with GroupDeletable[F]
    with Watchable[F, ConfigMap] {
  val resourceUri: Uri = uri"/api" / "v1" / "namespaces" / namespace / "configmaps"
} 
Example 5
Source File: NamespacesApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe.{Decoder, Encoder}
import io.k8s.api.core.v1.{Namespace, NamespaceList}
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.implicits._

private[client] case class NamespacesApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[NamespaceList],
    val resourceEncoder: Encoder[Namespace],
    val resourceDecoder: Decoder[Namespace]
) extends Creatable[F, Namespace]
    with Replaceable[F, Namespace]
    with Gettable[F, Namespace]
    with Listable[F, NamespaceList]
    with Deletable[F]
    with DeletableTerminated[F]
    with Watchable[F, Namespace] {
  protected val resourceUri: Uri = uri"/api" / "v1" / "namespaces"
} 
Example 6
Source File: PodDisruptionBudgetsApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe._
import io.k8s.api.policy.v1beta1.{PodDisruptionBudget, PodDisruptionBudgetList}
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.implicits._

private[client] case class PodDisruptionBudgetsApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[PodDisruptionBudgetList],
    encoder: Encoder[PodDisruptionBudget],
    decoder: Decoder[PodDisruptionBudget]
) extends Listable[F, PodDisruptionBudgetList] {
  val resourceUri: Uri = uri"/apis" / "policy" / "v1beta1" / "poddisruptionbudgets"

  def namespace(namespace: String): NamespacedPodDisruptionBudgetApi[F] =
    NamespacedPodDisruptionBudgetApi(httpClient, config, namespace)
}

private[client] case class NamespacedPodDisruptionBudgetApi[F[_]](
    httpClient: Client[F],
    config: KubeConfig,
    namespace: String
)(implicit
    val F: Sync[F],
    val resourceEncoder: Encoder[PodDisruptionBudget],
    val resourceDecoder: Decoder[PodDisruptionBudget],
    val listDecoder: Decoder[PodDisruptionBudgetList]
) extends Creatable[F, PodDisruptionBudget]
    with Replaceable[F, PodDisruptionBudget]
    with Gettable[F, PodDisruptionBudget]
    with Listable[F, PodDisruptionBudgetList]
    with Deletable[F]
    with GroupDeletable[F]
    with Watchable[F, PodDisruptionBudget] {
  val resourceUri: Uri = uri"/apis" / "policy" / "v1beta1" / "namespaces" / namespace / "poddisruptionbudgets"
} 
Example 7
Source File: CustomResourceDefinitionsApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe.{Decoder, Encoder}
import io.k8s.apiextensionsapiserver.pkg.apis.apiextensions.v1.{CustomResourceDefinition, CustomResourceDefinitionList}
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.implicits._

private[client] case class CustomResourceDefinitionsApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[CustomResourceDefinitionList],
    val resourceEncoder: Encoder[CustomResourceDefinition],
    val resourceDecoder: Decoder[CustomResourceDefinition]
) extends Creatable[F, CustomResourceDefinition]
    with Replaceable[F, CustomResourceDefinition]
    with Gettable[F, CustomResourceDefinition]
    with Listable[F, CustomResourceDefinitionList]
    with Deletable[F]
    with DeletableTerminated[F]
    with GroupDeletable[F]
    with Watchable[F, CustomResourceDefinition] { self =>
  val resourceUri: Uri = uri"/apis" / "apiextensions.k8s.io" / "v1" / "customresourcedefinitions"
  override val watchResourceUri: Uri =
    uri"/apis" / "apiextensions.k8s.io" / "v1" / "watch" / "customresourcedefinitions"
} 
Example 8
Source File: ServiceAccountsApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe._
import io.k8s.api.core.v1.{ServiceAccount, ServiceAccountList}
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.implicits._

private[client] case class ServiceAccountsApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[ServiceAccountList],
    encoder: Encoder[ServiceAccount],
    decoder: Decoder[ServiceAccount]
) extends Listable[F, ServiceAccountList] {
  val resourceUri: Uri = uri"/api" / "v1" / "serviceaccounts"

  def namespace(namespace: String): NamespacedServiceAccountsApi[F] =
    NamespacedServiceAccountsApi(httpClient, config, namespace)
}

private[client] case class NamespacedServiceAccountsApi[F[_]](
    httpClient: Client[F],
    config: KubeConfig,
    namespace: String
)(implicit
    val F: Sync[F],
    val resourceEncoder: Encoder[ServiceAccount],
    val resourceDecoder: Decoder[ServiceAccount],
    val listDecoder: Decoder[ServiceAccountList]
) extends Creatable[F, ServiceAccount]
    with Replaceable[F, ServiceAccount]
    with Gettable[F, ServiceAccount]
    with Listable[F, ServiceAccountList]
    with Deletable[F]
    with GroupDeletable[F]
    with Watchable[F, ServiceAccount] {
  val resourceUri: Uri = uri"/api" / "v1" / "namespaces" / namespace / "serviceaccounts"
} 
Example 9
Source File: HorizontalPodAutoscalersApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe._
import io.k8s.api.autoscaling.v1.{HorizontalPodAutoscaler, HorizontalPodAutoscalerList}
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.implicits._

private[client] case class HorizontalPodAutoscalersApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[HorizontalPodAutoscalerList],
    encoder: Encoder[HorizontalPodAutoscaler],
    decoder: Decoder[HorizontalPodAutoscaler]
) extends Listable[F, HorizontalPodAutoscalerList] {
  val resourceUri: Uri = uri"/apis" / "autoscaling" / "v1" / "horizontalpodautoscalers"

  def namespace(namespace: String): NamespacedHorizontalPodAutoscalersApi[F] =
    NamespacedHorizontalPodAutoscalersApi(httpClient, config, namespace)
}

private[client] case class NamespacedHorizontalPodAutoscalersApi[F[_]](
    httpClient: Client[F],
    config: KubeConfig,
    namespace: String
)(implicit
    val F: Sync[F],
    val resourceEncoder: Encoder[HorizontalPodAutoscaler],
    val resourceDecoder: Decoder[HorizontalPodAutoscaler],
    val listDecoder: Decoder[HorizontalPodAutoscalerList]
) extends Creatable[F, HorizontalPodAutoscaler]
    with Replaceable[F, HorizontalPodAutoscaler]
    with Gettable[F, HorizontalPodAutoscaler]
    with Listable[F, HorizontalPodAutoscalerList]
    with Deletable[F]
    with GroupDeletable[F]
    with Watchable[F, HorizontalPodAutoscaler] {
  val resourceUri: Uri = uri"/apis" / "autoscaling" / "v1" / "namespaces" / namespace / "horizontalpodautoscalers"
} 
Example 10
Source File: ServicesApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe._
import io.k8s.api.core.v1.{Service, ServiceList}
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.implicits._

private[client] case class ServicesApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[ServiceList],
    encoder: Encoder[Service],
    decoder: Decoder[Service]
) extends Listable[F, ServiceList] {
  val resourceUri: Uri = uri"/api" / "v1" / "services"

  def namespace(namespace: String): NamespacedServicesApi[F] = NamespacedServicesApi(httpClient, config, namespace)
}

private[client] case class NamespacedServicesApi[F[_]](
    httpClient: Client[F],
    config: KubeConfig,
    namespace: String
)(implicit
    val F: Sync[F],
    val resourceEncoder: Encoder[Service],
    val resourceDecoder: Decoder[Service],
    val listDecoder: Decoder[ServiceList]
) extends Creatable[F, Service]
    with Replaceable[F, Service]
    with Gettable[F, Service]
    with Listable[F, ServiceList]
    with Proxy[F]
    with Deletable[F]
    with GroupDeletable[F]
    with Watchable[F, Service] {
  val resourceUri: Uri = uri"/api" / "v1" / "namespaces" / namespace / "services"
} 
Example 11
Source File: ReplicaSetsApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe._
import io.k8s.api.apps.v1.{ReplicaSet, ReplicaSetList}
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.implicits._

private[client] case class ReplicaSetsApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[ReplicaSetList],
    encoder: Encoder[ReplicaSet],
    decoder: Decoder[ReplicaSet]
) extends Listable[F, ReplicaSetList] {
  val resourceUri: Uri = uri"/apis" / "apps" / "v1" / "replicasets"

  def namespace(namespace: String): NamespacedReplicaSetsApi[F] =
    NamespacedReplicaSetsApi(httpClient, config, namespace)
}

private[client] case class NamespacedReplicaSetsApi[F[_]](
    httpClient: Client[F],
    config: KubeConfig,
    namespace: String
)(implicit
    val F: Sync[F],
    val resourceEncoder: Encoder[ReplicaSet],
    val resourceDecoder: Decoder[ReplicaSet],
    val listDecoder: Decoder[ReplicaSetList]
) extends Creatable[F, ReplicaSet]
    with Replaceable[F, ReplicaSet]
    with Gettable[F, ReplicaSet]
    with Listable[F, ReplicaSetList]
    with Deletable[F]
    with DeletableTerminated[F]
    with GroupDeletable[F]
    with Watchable[F, ReplicaSet] {
  val resourceUri = uri"/apis" / "apps" / "v1" / "namespaces" / namespace / "replicasets"
} 
Example 12
Source File: IngressesApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe._
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.implicits._
import io.k8s.api.networking.v1beta1.{Ingress, IngressList}

private[client] case class IngressessApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[IngressList],
    encoder: Encoder[Ingress],
    decoder: Decoder[Ingress]
) extends Listable[F, IngressList] {
  val resourceUri: Uri = uri"/apis" / "extensions" / "v1beta1" / "ingresses"

  def namespace(namespace: String): NamespacedIngressesApi[F] = NamespacedIngressesApi(httpClient, config, namespace)
}

private[client] case class NamespacedIngressesApi[F[_]](
    httpClient: Client[F],
    config: KubeConfig,
    namespace: String
)(implicit
    val F: Sync[F],
    val resourceEncoder: Encoder[Ingress],
    val resourceDecoder: Decoder[Ingress],
    val listDecoder: Decoder[IngressList]
) extends Creatable[F, Ingress]
    with Replaceable[F, Ingress]
    with Gettable[F, Ingress]
    with Listable[F, IngressList]
    with Deletable[F]
    with GroupDeletable[F]
    with Watchable[F, Ingress] {
  val resourceUri: Uri = uri"/apis" / "extensions" / "v1beta1" / "namespaces" / namespace / "ingresses"
} 
Example 13
Source File: TestSparqlClient.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.cli.dummies

import java.io.ByteArrayOutputStream

import cats.effect.Sync
import cats.implicits._
import ch.epfl.bluebrain.nexus.cli.CliError.ClientError.SerializationError
import ch.epfl.bluebrain.nexus.cli.ClientErrOr
import ch.epfl.bluebrain.nexus.cli.clients.{SparqlClient, SparqlResults}
import ch.epfl.bluebrain.nexus.cli.sse.{Event, OrgLabel, ProjectLabel}
import io.circe.Json
import org.http4s.Uri

class TestSparqlClient[F[_]](events: List[Event])(implicit F: Sync[F]) extends SparqlClient[F] {

  import io.circe.parser._
  import org.apache.jena.query.{Dataset, DatasetFactory, QueryFactory, ReadWrite, ResultSetFormatter, _}
  import org.apache.jena.rdf.model.{Model, ModelFactory}
  import org.apache.jena.riot.system.StreamRDFLib
  import org.apache.jena.riot.{Lang, RDFParser}

  private def toJenaModel(j: Json): Model = {
    val model  = ModelFactory.createDefaultModel()
    val stream = StreamRDFLib.graph(model.getGraph)
    RDFParser.create.fromString(j.noSpaces).lang(Lang.JSONLD).parse(stream)
    model
  }

  val ds: Dataset = DatasetFactory.createTxnMem()
  events.foreach { event =>
    val jsonGraph = event.raw.hcursor.get[Json]("_source").getOrElse(Json.obj())
    val graphUri  = event.resourceId.addSegment("graph").renderString
    val model     = toJenaModel(jsonGraph)
    ds.begin(ReadWrite.WRITE)
    try {
      ds.removeNamedModel(graphUri)
      ds.commit()
    } finally {
      ds.end()
    }
    ds.begin(ReadWrite.WRITE)
    try {
      ds.addNamedModel(graphUri, model)
      ds.commit()
    } finally {
      ds.end()
    }
  }
  ds.setDefaultModel(ds.getUnionModel)

  override def query(
      org: OrgLabel,
      proj: ProjectLabel,
      view: Option[Uri],
      queryStr: String
  ): F[ClientErrOr[SparqlResults]] = {
    F.delay {
      ds.begin(ReadWrite.READ)
      try {
        val query   = QueryFactory.create(queryStr)
        val qexec   = QueryExecutionFactory.create(query, ds.asDatasetGraph())
        val results = qexec.execSelect

        val outputStream = new ByteArrayOutputStream()
        ResultSetFormatter.outputAsJSON(outputStream, results)
        val json         = new String(outputStream.toByteArray)
        decode[SparqlResults](json).leftMap(_ =>
          SerializationError("Unable to decode sparql results", classOf[SparqlResults].getSimpleName, Some(json))
        )
      } finally {
        ds.end()
      }
    }
  }
}

object TestSparqlClient {

  final def apply[F[_]](events: List[Event])(implicit F: Sync[F]): F[TestSparqlClient[F]] =
    F.delay(new TestSparqlClient[F](events))

} 
Example 14
Source File: SparqlResultsSpec.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.cli.clients

import ch.epfl.bluebrain.nexus.cli.clients.SparqlResults.{Binding, Bindings, Head}
import ch.epfl.bluebrain.nexus.cli.utils.Resources
import org.http4s.Uri
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpecLike

class SparqlResultsSpec extends AnyWordSpecLike with Matchers with Resources {

  "A Sparql Json result" should {
    val json    = jsonContentOf("/templates/sparql-results.json")
    val askJson = jsonContentOf("/templates/sparql-results-ask.json")

    val constrainedBy = Map(
      "s" -> Binding("uri", "https://example.com/subject"),
      "p" -> Binding("uri", "https://bluebrain.github.io/nexus/vocabulary/constrainedBy"),
      "o" -> Binding("uri", "https://bluebrain.github.io/nexus/schemas/resolver.json")
    )

    val deprecated = Map(
      "s" -> Binding("uri", "https://example.com/subject"),
      "p" -> Binding("uri", "https://bluebrain.github.io/nexus/vocabulary/deprecated"),
      "o" -> Binding(`type` = "literal", value = "false", datatype = Some("http://www.w3.org/2001/XMLSchema#boolean"))
    )

    val label = Map(
      "s" -> Binding("uri", "https://example.com/subject"),
      "p" -> Binding("uri", "https://bluebrain.github.io/nexus/vocabulary/label"),
      "o" -> Binding(`type` = "literal", value = "myText")
    )

    val head = Head(List("s", "p", "o"))

    val qr    = SparqlResults(head, Bindings(constrainedBy, deprecated, label))
    val qrAsk = SparqlResults(Head(), Bindings(), Some(true))

    "be decoded" in {
      json.as[SparqlResults] shouldEqual Right(qr)
      askJson.as[SparqlResults] shouldEqual Right(qrAsk)
    }

    "add head" in {
      val link = Uri.unsafeFromString("http://www.w3.org/TR/rdf-sparql-XMLres/example.rq")
      head ++ Head(List("s", "p", "name"), Some(List(link))) shouldEqual
        Head(List("s", "p", "o", "name"), Some(List(link)))
    }

    "add binding" in {
      (Bindings(constrainedBy) ++ Bindings(deprecated) ++ Bindings(label)) shouldEqual qr.results
    }
  }
} 
Example 15
Source File: SparqlClientSpec.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.cli.clients

import cats.effect.IO
import cats.implicits._
import ch.epfl.bluebrain.nexus.cli.{AbstractCliSpec, Console}
import ch.epfl.bluebrain.nexus.cli.CliError.ClientError.{ClientStatusError, ServerStatusError}
import ch.epfl.bluebrain.nexus.cli.config.{AppConfig, EnvConfig}
import ch.epfl.bluebrain.nexus.cli.sse._
import ch.epfl.bluebrain.nexus.cli.utils.Http4sExtras
import izumi.distage.model.definition.ModuleDef
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.client.Client
import org.http4s.dsl.io._
import org.http4s.headers.`Content-Type`
import org.http4s.{HttpApp, Response, Status, Uri}
import org.scalatest.OptionValues

class SparqlClientSpec extends AbstractCliSpec with Http4sExtras with OptionValues {

  private val sparqlResultsJson = jsonContentOf("/templates/sparql-results.json")
  private val sparqlResults     = sparqlResultsJson.as[SparqlResults].toOption.value
  private val query             = "SELECT * {?s ?p ?o} LIMIT 10"

  override def overrides: ModuleDef =
    new ModuleDef {
      include(defaultModules)
      make[Client[IO]].from { cfg: AppConfig =>
        val token   = cfg.env.token
        val ct      = `Content-Type`(SparqlClient.`application/sparql-query`)
        val view    = cfg.env.defaultSparqlView.renderString
        val httpApp = HttpApp[IO] {
          // success
          case req @ POST -> `v1` / "views" / OrgLabelVar(`orgLabel`) / ProjectLabelVar(
                `projectLabel`
              ) / `view` / "sparql" contentType `ct` optbearer `token` =>
            req.as[String].flatMap {
              case `query` => Response[IO](Status.Ok).withEntity(sparqlResultsJson).pure[IO]
              case _       => Response[IO](Status.BadRequest).pure[IO]
            }
          // unknown view id
          case req @ POST -> `v1` / "views" / OrgLabelVar(`orgLabel`) / ProjectLabelVar(
                `projectLabel`
              ) / (_: String) / "sparql" contentType `ct` optbearer `token` =>
            req.as[String].flatMap {
              case `query` => Response[IO](Status.NotFound).withEntity(notFoundJson).pure[IO]
              case _       => Response[IO](Status.BadRequest).pure[IO]
            }
          // unknown token
          case req @ POST -> `v1` / "views" / OrgLabelVar(`orgLabel`) / ProjectLabelVar(
                `projectLabel`
              ) / `view` / "sparql" contentType `ct` optbearer (_: Option[
                BearerToken
              ]) =>
            req.as[String].flatMap {
              case `query` => Response[IO](Status.Forbidden).withEntity(authFailedJson).pure[IO]
              case _       => Response[IO](Status.BadRequest).pure[IO]
            }
          // other - internal error
          case req @ POST -> "v1" /: (_: Path) contentType `ct` optbearer `token` =>
            req.as[String].flatMap {
              case `query` => Response[IO](Status.InternalServerError).withEntity(internalErrorJson).pure[IO]
              case _       => Response[IO](Status.BadRequest).pure[IO]
            }
        }
        Client.fromHttpApp(httpApp)
      }
    }

  "A SparqlClient" should {
    "return sparql results" in { (client: Client[IO], console: Console[IO], env: EnvConfig) =>
      val cl = SparqlClient(client, env, console)
      for {
        results <- cl.query(orgLabel, projectLabel, query)
        _        = results shouldEqual Right(sparqlResults)
      } yield ()
    }
    "return not found" in { (client: Client[IO], console: Console[IO], env: EnvConfig) =>
      val cl = SparqlClient(client, env, console)
      for {
        results <- cl.query(orgLabel, projectLabel, Uri.unsafeFromString(genString()), query)
        _        = results shouldEqual Left(ClientStatusError(Status.NotFound, notFoundJson.noSpaces))
      } yield ()
    }
    "return internal error" in { (client: Client[IO], console: Console[IO], env: EnvConfig) =>
      val cl = SparqlClient(client, env, console)
      for {
        results <- cl.query(orgLabel, ProjectLabel(genString()), Uri.unsafeFromString(genString()), query)
        _        = results shouldEqual Left(ServerStatusError(Status.InternalServerError, internalErrorJson.noSpaces))
      } yield ()
    }
    "return bad token" in { (client: Client[IO], console: Console[IO], env: EnvConfig) =>
      val cl = SparqlClient(client, env.copy(token = Some(BearerToken("bad"))), console)
      for {
        results <- cl.query(orgLabel, projectLabel, query)
        _        = results shouldEqual Left(ClientStatusError(Status.Forbidden, authFailedJson.noSpaces))
      } yield ()
    }

  }
} 
Example 16
Source File: InfluxDocker.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.cli.influx

import cats.effect.{ConcurrentEffect, ContextShift, Timer}
import distage.TagK
import izumi.distage.docker.Docker.{ContainerConfig, DockerPort}
import izumi.distage.docker.modules.DockerSupportModule
import izumi.distage.docker.{ContainerDef, Docker}
import izumi.distage.model.definition.ModuleDef
import org.http4s.Uri

object InfluxDocker extends ContainerDef {

  val primaryPort: DockerPort = DockerPort.TCP(8086)

  override def config: InfluxDocker.Config =
    ContainerConfig(
      image = "library/influxdb:1.8.0",
      ports = Seq(primaryPort),
      env = Map("INFLUXDB_REPORTING_DISABLED" -> "true", "INFLUXDB_HTTP_FLUX_ENABLED" -> "true"),
      reuse = true
    )

  class Module[F[_]: ConcurrentEffect: ContextShift: Timer: TagK] extends ModuleDef {
    make[InfluxDocker.Container].fromResource {
      InfluxDocker.make[F]
    }

    make[InfluxHostConfig].from { docker: InfluxDocker.Container =>
      val knownAddress = docker.availablePorts.availablePorts(primaryPort).head
      InfluxHostConfig(knownAddress.hostV4, knownAddress.port)
    }

    // add docker dependencies and override default configuration
    include(new DockerSupportModule[F] overridenBy new ModuleDef {
      make[Docker.ClientConfig].from {
        Docker.ClientConfig(
          readTimeoutMs = 60000, // long timeout for gh actions
          connectTimeoutMs = 500,
          allowReuse = false,
          useRemote = false,
          useRegistry = true,
          remote = None,
          registry = None
        )
      }
    })
  }

  final case class InfluxHostConfig(host: String, port: Int) {
    def endpoint: Uri = Uri.unsafeFromString(s"http://$host:$port")
  }
} 
Example 17
Source File: InfluxConfig.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.cli.config.influx

import java.nio.file.Path

import ch.epfl.bluebrain.nexus.cli.config.PrintConfig
import ch.epfl.bluebrain.nexus.cli.sse.{OrgLabel, ProjectLabel}
import ch.epfl.bluebrain.nexus.cli.utils.Codecs._
import org.http4s.Uri
import pureconfig.configurable.{genericMapReader, genericMapWriter}
import pureconfig.error.CannotConvert
import pureconfig.generic.semiauto._
import pureconfig.{ConfigConvert, ConfigReader, ConfigWriter}

import scala.annotation.nowarn
import scala.concurrent.duration.FiniteDuration


final case class InfluxConfig(
    endpoint: Uri,
    database: String,
    dbCreationCommand: String,
    offsetFile: Path,
    offsetSaveInterval: FiniteDuration,
    print: PrintConfig,
    projects: Map[(OrgLabel, ProjectLabel), ProjectConfig]
)

object InfluxConfig {

  @nowarn("cat=unused")
  implicit final val influxConfigConvert: ConfigConvert[InfluxConfig] = {
    implicit val labelTupleMapReader: ConfigReader[Map[(OrgLabel, ProjectLabel), ProjectConfig]] =
      genericMapReader[(OrgLabel, ProjectLabel), ProjectConfig] { key =>
        key.split('/') match {
          case Array(org, proj) if !org.isBlank && !proj.isBlank => Right(OrgLabel(org.trim) -> ProjectLabel(proj.trim))
          case _                                                 => Left(CannotConvert(key, "project reference", "the format does not match {org}/{project}"))
        }
      }
    implicit val labelTupleMapWriter: ConfigWriter[Map[(OrgLabel, ProjectLabel), ProjectConfig]] =
      genericMapWriter { case (OrgLabel(org), ProjectLabel(proj)) => s"$org/$proj" }
    deriveConvert[InfluxConfig]
  }
} 
Example 18
Source File: Event.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.cli.sse

import java.time.Instant
import java.util.UUID

import ch.epfl.bluebrain.nexus.cli.utils.Codecs
import io.circe.generic.semiauto.deriveDecoder
import io.circe.{Decoder, Json}
import org.http4s.Uri


final case class Event(
    eventType: EventType,
    resourceId: Uri,
    rev: Long,
    organization: OrgUuid,
    project: ProjectUuid,
    resourceTypes: Set[Uri],
    instant: Instant,
    raw: Json
)

object Event extends Codecs {

  final private[Event] case class APIEvent(
      `_organizationUuid`: UUID,
      `_projectUuid`: UUID,
      `@type`: EventType,
      `_types`: Option[Set[Uri]],
      `_resourceId`: Uri,
      `_rev`: Option[Long],
      `_instant`: Instant
  ) {
    def asEvent(raw: Json): Event =
      Event(
        `@type`,
        `_resourceId`,
        `_rev`.getOrElse(1L),
        OrgUuid(`_organizationUuid`),
        ProjectUuid(`_projectUuid`),
        `_types`.getOrElse(Set.empty[Uri]),
        `_instant`,
        raw
      )
  }

  private[Event] object APIEvent {
    implicit val apiEventDecoder: Decoder[APIEvent] = deriveDecoder[APIEvent]
  }

  implicit final val eventDecoder: Decoder[Event] =
    Decoder.instance { cursor => cursor.as[APIEvent].map(_.asEvent(cursor.value)) }

} 
Example 19
Source File: CliOpts.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.cli

import java.nio.file.{Path, Paths}

import cats.data.{Validated, ValidatedNel}
import cats.implicits._
import ch.epfl.bluebrain.nexus.cli.sse.{BearerToken, Offset}
import com.monovore.decline.{Argument, Opts}
import org.http4s.Uri

import scala.util.Try


object CliOpts extends OptsInstances {

  val token: Opts[Option[BearerToken]] = Opts
    .option[String](
      long = "token",
      help = "The token to use when interacting with the Nexus API; " +
        "a 'none' string value will remove any preconfigured token."
    )
    .validate("Token must be a non empty string") { !_.isBlank }
    .map {
      case "none" => None
      case value  => Some(BearerToken(value))
    }

  val offset: Opts[Option[Offset]] = Opts
    .option[String](
      long = "offset",
      help = "The offset to use when starting the event replay; " +
        "a 'none' string value will discard any saved offset."
    )
    .map(_.trim)
    .mapValidated {
      case "none" => Validated.validNel(None)
      case value  => Offset(value).toRight("Offset is not valid").map(o => Some(o)).toValidatedNel
    }

  val endpoint: Opts[Uri] = Opts
    .option[Uri](
      long = "endpoint",
      help = "The base address of the Nexus API"
    )

  val envConfig: Opts[Path] = Opts
    .option[Path](
      long = "env",
      help = "The environment configuration file"
    )

  val postgresConfig: Opts[Path] = Opts
    .option[Path](
      long = "config",
      help = "The postgres configuration file"
    )

  val influxConfig: Opts[Path] = Opts
    .option[Path](
      long = "config",
      help = "The influx configuration file"
    )

}

trait OptsInstances {
  implicit protected val uriArgument: Argument[Uri] = new Argument[Uri] {
    override def read(string: String): ValidatedNel[String, Uri] =
      Uri
        .fromString(string)
        .leftMap(_ => s"Invalid Uri: '$string'")
        .ensure(s"Invalid Uri: '$string'")(uri => uri.scheme.isDefined)
        .toValidatedNel
    override val defaultMetavar: String                          = "http://..."
  }

  implicit protected val pathArgument: Argument[Path] = new Argument[Path] {
    override def read(string: String): ValidatedNel[String, Path] =
      Try(Paths.get(string)).toOption.toRight(s"Invalid file path '$string'").toValidatedNel
    override val defaultMetavar: String                           = "../file.conf"
  }
} 
Example 20
Source File: Utils.scala    From pizza-auth-3   with MIT License 5 votes vote down vote up
package moe.pizza.auth.webapp

import moe.pizza.auth.interfaces.UserDatabase
import moe.pizza.auth.models.Pilot
import moe.pizza.auth.webapp.Types.{HydratedSession, Session2, Session}
import moe.pizza.auth.webapp.Utils.Alerts.Alerts
import org.http4s.{Uri, Response, Request}
import org.http4s.dsl.{Root, _}

import scalaz.concurrent.Task

object Utils {
  object Alerts extends Enumeration {
    type Alerts = Value
    val success = Value("success")
    val info = Value("info")
    val warning = Value("warning")
    val danger = Value("danger")
  }

  implicit class PimpedSession2(s: Session2) {
    def hydrate(u: UserDatabase): HydratedSession = {
      new HydratedSession(s.alerts, s.redirect, s.uid.flatMap(u.getUser), s.signupData)
    }
  }

  implicit class PimpedHydratedSession(hs: HydratedSession) {
    def dehydrate(): Session2 = {
      new Session2(hs.alerts, hs.redirect, hs.pilot.map(_.uid), hs.signupData)
    }
  }

  implicit class PimpedRequest(r: Request) {
    def flash(level: Alerts, message: String): Option[HydratedSession] = {
      getSession.map(s =>
        s.copy(alerts = s.alerts :+ Types.Alert(level.toString, message)))
    }
    def getSession = r.attributes.get(SessionManager.HYDRATEDSESSION)
    def setSession(s: Types.HydratedSession): Unit =
      r.attributes.put(SessionManager.HYDRATEDSESSION, s)
    def sessionResponse(
        f: ((HydratedSession, Pilot) => Task[Response]),
        error: String = "You must be signed in to do that"): Task[Response] = {
      (getSession, getSession.flatMap(_.pilot)) match {
        case (Some(s), Some(p)) =>
          f(s, p)
        case _ =>
          TemporaryRedirect(Uri(path = "/"))
      }
    }
  }

  implicit class PimpedResponse(r: Response) {
    def withSession(s: HydratedSession): Response =
      r.withAttribute(SessionManager.HYDRATEDSESSION, s)
    def getSession(): Option[HydratedSession] =
      r.attributes.get(SessionManager.HYDRATEDSESSION)
    def withNoSession(): Response = r.withAttribute(SessionManager.LOGOUT, "")
  }

  implicit class PimpedTaskResponse(r: Task[Response]) {
    def attachSessionifDefined(s: Option[HydratedSession]): Task[Response] =
      r.map(res =>
        s.foldLeft(res) { (resp, sess) =>
          resp.withSession(sess)
      })
    def clearSession(): Task[Response] =
      r.map(res => res.withNoSession())
  }

  def sanitizeUserName(name: String) =
    name.toLowerCase.replace("'", "").replace(" ", "_")

} 
Example 21
Source File: CountriesHttpEndpointSpec.scala    From core   with Apache License 2.0 5 votes vote down vote up
package com.smartbackpackerapp.http

import cats.effect.IO
import com.smartbackpackerapp.common.IOAssertion
import com.smartbackpackerapp.http.Http4sUtils._
import com.smartbackpackerapp.model.{Country, CountryCode, CountryName, Currency}
import com.smartbackpackerapp.repository.algebra.CountryRepository
import com.smartbackpackerapp.service.CountryService
import org.http4s.{HttpService, Query, Request, Status, Uri}
import org.scalatest.{FlatSpecLike, Matchers}

class CountriesHttpEndpointSpec extends FlatSpecLike with Matchers with CountriesHttpEndpointFixture {

  it should s"find all the countries" in IOAssertion {
    val request = Request[IO](uri = Uri(path = s"/$ApiVersion/countries"))

    httpService(request).value.map { task =>
      task.fold(fail("Empty response")){ response =>
        response.status should be (Status.Ok)
        assert(response.body.asString.contains("Argentina"))
      }
    }
  }

  it should s"find all the schengen countries" in IOAssertion {
    val request = Request[IO](uri = Uri(path = s"/$ApiVersion/countries", query = Query(("query", Some("schengen")))))

    httpService(request).value.map { task =>
      task.fold(fail("Empty response")){ response =>
        response.status should be (Status.Ok)
        assert(response.body.asString.contains("Poland"))
      }
    }
  }

}

trait CountriesHttpEndpointFixture {

  private val testCountries = List(
    Country(CountryCode("AR"), CountryName("Argentina"), Currency("ARS"))
  )

  private val testSchengenCountries = List(
    Country(CountryCode("PL"), CountryName("Poland"), Currency("PLN"))
  )

  private val repo = new CountryRepository[IO] {
    override def findAll: IO[List[Country]] = IO(testCountries)
    override def findSchengen: IO[List[Country]] = IO(testSchengenCountries)
  }

  private implicit val errorHandler = new HttpErrorHandler[IO]

  val httpService: HttpService[IO] =
    ioMiddleware(
      new CountriesHttpEndpoint[IO](
        new CountryService[IO](repo)
      ).service
    )

} 
Example 22
Source File: S3ServiceCommand.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.s3

import cats.effect.Effect
import cats.implicits._
import fs2._
import org.aws4s.PayloadSigning
import org.aws4s.core.{Command, Param, RenderedParam, ServiceName}
import org.http4s.headers.Host
import org.http4s.{EntityDecoder, Headers, Method, Request, Uri}

private[aws4s] abstract class S3ServiceCommand[F[_]: Effect, R: EntityDecoder[F, ?]] extends Command[F, Nothing, R] {

  override final val serviceName: ServiceName = ServiceName.S3

  val action:  Method
  val payload: F[Stream[F, Byte]]

  override final val payloadSigning: PayloadSigning              = PayloadSigning.Signed
  override final val params:         List[Param[Nothing]]       = List.empty
  override final val validator:      Command.Validator[Nothing] = _ => None

  override final val requestGenerator: List[RenderedParam[Nothing]] => F[Request[F]] = { _ =>
    val host = s"s3.${region.name}.amazonaws.com"
    val uri  = Uri.unsafeFromString(s"https://$host/").withPath("/")
    payload map { p =>
      Request[F](action, uri, headers = Headers(Host(host))).withBodyStream(p)
    }
  }
} 
Example 23
Source File: S3ObjectCommand.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.s3

import cats.effect.Effect
import org.aws4s.core.{Command, Param, RenderedParam, ServiceName}
import org.http4s.{EntityDecoder, Headers, Method, Request, Uri}
import fs2._
import org.http4s.headers.Host
import cats.implicits._

private[aws4s] abstract class S3ObjectCommand[F[_]: Effect, R: EntityDecoder[F, ?]] extends Command[F, Nothing, R] {

  override final val serviceName: ServiceName = ServiceName.S3

  val action:     Method
  val bucketName: BucketName
  val objectPath: ObjectPath
  val payload:    F[Stream[F, Byte]]

  override final val params:    List[Param[Nothing]]       = List.empty
  override final val validator: Command.Validator[Nothing] = _ => None

  override final val requestGenerator: List[RenderedParam[Nothing]] => F[Request[F]] = { _ =>
    val host = s"${bucketName.value}.s3.${region.name}.amazonaws.com"
    val uri  = Uri.unsafeFromString(s"https://$host/").withPath(objectPath.value)
    for {
      pStream <- payload
      pBytes <- pStream.compile.toVector
      r <- Request[F](action, uri, headers = Headers(Host(host))).withBody(pBytes.toArray)
    } yield r
  }
} 
Example 24
Source File: DynamoDbCommand.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.dynamodb

import cats.effect.Effect
import io.circe.{Decoder, Json}
import org.aws4s.PayloadSigning
import org.http4s.headers.{Host, `Content-Type`}
import org.http4s.{Header, Headers, MediaType, Method, Request, Uri}
import org.http4s.circe._
import cats.implicits._
import org.aws4s.core.ExtraEntityDecoderInstances._
import org.aws4s.core.{Command, CommandPayload, RenderedParam, ServiceName}

private[dynamodb] abstract class DynamoDbCommand[F[_]: Effect, R: Decoder] extends Command[F, Json, R] {
  override def serviceName:    ServiceName    = ServiceName.DynamoDb
  override def payloadSigning: PayloadSigning = PayloadSigning.Signed

  def action: String

  override final val requestGenerator: List[RenderedParam[Json]] => F[Request[F]] = params => {
    val host = s"dynamodb.${region.name}.amazonaws.com"
    val payload: Json = CommandPayload.jsonObject(params)
    Request[F](
      Method.POST,
      Uri.unsafeFromString(s"https://$host/"),
      headers = Headers(Header("X-Amz-Target", s"DynamoDB_20120810.$action"), Host(host))
    ).withBody(payload).map(_.withContentType(`Content-Type`.apply(MediaType.fromKey(("application", "x-amz-json-1.0")))))
  }
} 
Example 25
Source File: Queue.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.sqs

import cats.implicits._
import org.aws4s.{Failure, Region}
import org.http4s.Uri

case class Queue private (uri: Uri, host: String, region: Region)

object Queue {

  def fromString(uriS: String): Either[Failure, Queue] = {
    Uri
      .fromString(uriS)
      .leftMap(err => Failure.invalidParam("q", err.message): Failure)
      .flatMap { uri =>
        uri.host match {
          case Some(host) =>
            host.value.split('.').drop(1).headOption match {
              case Some(region) => Either.right(Queue(uri, host.value, Region(region)))
              case None         => Either.left(Failure.invalidParam("q", "No region present in the queue URI"))
            }
          case None =>
            Either.left(Failure.invalidParam("q", "Missing host in the queue URI"))
        }
      }
  }

  def unsafeFromString(uri: String): Queue =
    fromString(uri).fold(err => throw err, identity)
} 
Example 26
Source File: KmsCommand.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.kms

import cats.effect.Effect
import cats.implicits._
import io.circe.{Decoder, Json}
import org.aws4s.core.ExtraEntityDecoderInstances._
import org.aws4s._
import org.aws4s.core.{Command, CommandPayload, RenderedParam, ServiceName}
import org.http4s.circe._
import org.http4s.headers.{Host, `Content-Type`}
import org.http4s.{Header, Headers, MediaType, Method, Request, Uri}

private[kms] abstract class KmsCommand[F[_]: Effect, R: Decoder] extends Command[F, Json, R] {
  override def serviceName:    ServiceName    = ServiceName.Kms
  override def payloadSigning: PayloadSigning = PayloadSigning.Signed

  def action: String

  override final val requestGenerator: List[RenderedParam[Json]] => F[Request[F]] = { params =>
    val host = s"kms.${region.name}.amazonaws.com"
    val payload: Json = CommandPayload.jsonObject(params)
    Request[F](
      Method.POST,
      Uri.unsafeFromString(s"https://$host/"),
      headers = Headers(Header("X-Amz-Target", s"TrentService.$action"), Host(host))
    ).withBody(payload).map(_.withContentType(`Content-Type`.apply(MediaType.fromKey(("application", "x-amz-json-1.1")))))
  }
} 
Example 27
Source File: CorrelationIdMiddlewareTest.scala    From scala-server-toolkit   with MIT License 5 votes vote down vote up
package com.avast.sst.http4s.server.middleware

import java.net.InetSocketAddress

import cats.effect.{ContextShift, IO, Resource, Timer}
import com.avast.sst.http4s.server.Http4sRouting
import org.http4s.client.blaze.BlazeClientBuilder
import org.http4s.dsl.Http4sDsl
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.util.CaseInsensitiveString
import org.http4s.{Header, HttpRoutes, Request, Uri}
import org.scalatest.funsuite.AsyncFunSuite

import scala.concurrent.ExecutionContext

@SuppressWarnings(Array("scalafix:Disable.get", "scalafix:Disable.toString", "scalafix:Disable.createUnresolved"))
class CorrelationIdMiddlewareTest extends AsyncFunSuite with Http4sDsl[IO] {

  implicit private val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
  implicit private val timer: Timer[IO] = IO.timer(ExecutionContext.global)

  test("CorrelationIdMiddleware fills Request attributes and HTTP response header") {
    val test = for {
      middleware <- Resource.liftF(CorrelationIdMiddleware.default[IO])
      routes = Http4sRouting.make {
        middleware.wrap {
          HttpRoutes.of[IO] {
            case req @ GET -> Root / "test" =>
              val id = middleware.retrieveCorrelationId(req)
              Ok("test").map(_.withHeaders(Header("Attribute-Value", id.toString)))
          }
        }
      }
      server <- BlazeServerBuilder[IO](ExecutionContext.global)
        .bindSocketAddress(InetSocketAddress.createUnresolved("127.0.0.1", 0))
        .withHttpApp(routes)
        .resource
      client <- BlazeClientBuilder[IO](ExecutionContext.global).resource
    } yield (server, client)

    test
      .use {
        case (server, client) =>
          client
            .run(
              Request[IO](uri = Uri.unsafeFromString(s"http://${server.address.getHostString}:${server.address.getPort}/test"))
                .withHeaders(Header("Correlation-Id", "test-value"))
            )
            .use { response =>
              IO.delay {
                assert(response.headers.get(CaseInsensitiveString("Correlation-Id")).get.value === "test-value")
                assert(response.headers.get(CaseInsensitiveString("Attribute-Value")).get.value === "Some(CorrelationId(test-value))")
              }
            }
      }
      .unsafeToFuture()
  }

} 
Example 28
Source File: SwaggerHttp4s.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.swagger.http4s

import java.util.Properties

import cats.effect.{Blocker, ContextShift, Sync}
import org.http4s.{HttpRoutes, StaticFile, Uri}
import org.http4s.dsl.Http4sDsl
import org.http4s.headers.Location

import scala.concurrent.ExecutionContext


class SwaggerHttp4s(
    yaml: String,
    contextPath: String = "docs",
    yamlName: String = "docs.yaml",
    redirectQuery: Map[String, Seq[String]] = Map.empty
) {
  private val swaggerVersion = {
    val p = new Properties()
    val pomProperties = getClass.getResourceAsStream("/META-INF/maven/org.webjars/swagger-ui/pom.properties")
    try p.load(pomProperties)
    finally pomProperties.close()
    p.getProperty("version")
  }

  def routes[F[_]: ContextShift: Sync]: HttpRoutes[F] = {
    val dsl = Http4sDsl[F]
    import dsl._

    HttpRoutes.of[F] {
      case path @ GET -> Root / `contextPath` =>
        val queryParameters = Map("url" -> Seq(s"${path.uri}/$yamlName")) ++ redirectQuery
        Uri
          .fromString(s"${path.uri}/index.html")
          .map(uri => uri.setQueryParams(queryParameters))
          .map(uri => PermanentRedirect(Location(uri)))
          .getOrElse(NotFound())
      case GET -> Root / `contextPath` / `yamlName` =>
        Ok(yaml)
      case GET -> Root / `contextPath` / swaggerResource =>
        StaticFile
          .fromResource(
            s"/META-INF/resources/webjars/swagger-ui/$swaggerVersion/$swaggerResource",
            Blocker.liftExecutionContext(ExecutionContext.global)
          )
          .getOrElseF(NotFound())
    }
  }
} 
Example 29
Source File: Paginate.scala    From github   with MIT License 5 votes vote down vote up
package io.chrisdavenport.github.endpoints.utils

import org.http4s.{Header, Uri}
import cats.implicits._


  def paginate(uri: Uri, numPages: Int): Map[Int, Header] = {
    (1 to numPages).map { currentPage =>
      currentPage -> Header(
        "Link",
        List(
          prevPage(uri, currentPage),
          nextPage(uri, numPages, currentPage),
          lastPage(uri, numPages, currentPage),
          firstPage(uri, currentPage)
        )
          .flatten
          .map { case (uri, rel) =>
            s""" <${uri.toString}>; rel="$rel""""
          }. mkString(",")
      )
    }.toMap
  }

  private def firstPage(uri: Uri, page: Int): Option[(Uri, String)] =
    Option(page)
      .filterNot(_ == 1)
      .as((uri.withQueryParam[String, String]("page", "1"), "first"))

  private def prevPage(uri: Uri, page: Int): Option[(Uri, String)] =
    Option(page)
      .filterNot(_ == 1)
      .map { p =>
        (uri.withQueryParam[String, String]("page", (p - 1).toString), "prev")
      }

  private def nextPage(uri: Uri, numPages: Int, page: Int): Option[(Uri, String)] =
    Option(page)
      .filterNot(_ == numPages)
      .map { p =>
        (uri.withQueryParam[String, String]("page", (p + 1).toString), "next")
      }

  private def lastPage(uri: Uri, numPages: Int, page: Int): Option[(Uri, String)] =
    Option(page)
      .filterNot(_ == numPages)
      .as((uri.withQueryParam[String, String]("page", numPages.toString), "last"))

} 
Example 30
Source File: AdserverHttpClientBuilder.scala    From scala-openrtb   with Apache License 2.0 5 votes vote down vote up
package com.powerspace.openrtb.examples.rtb.http4s.adserver

import com.google.openrtb.{BidRequest, BidResponse}
import com.powerspace.openrtb.examples.rtb.http4s.common.ExampleSerdeModule
import com.powerspace.openrtb.json.SerdeModule
import io.circe.{Decoder, Encoder}
import monix.eval.Task
import org.http4s.Uri.{Authority, RegName, Scheme}
import org.http4s.client.Client
import org.http4s.{EntityDecoder, EntityEncoder, Method, Request, Uri}

object AdserverHttpClientBuilder {

  import org.http4s.circe._

  val serdeModule: SerdeModule = ExampleSerdeModule

  implicit val bidRequestEncoder: Encoder[BidRequest] = serdeModule.bidRequestEncoder
  implicit val bidRequestEntityEncoder: EntityEncoder[Task, BidRequest] = jsonEncoderOf[Task, BidRequest]

  implicit val bidResponseDecoder: Decoder[BidResponse] = serdeModule.bidResponseDecoder
  implicit val bidResponseEntityDecoder: EntityDecoder[Task, BidResponse] = jsonOf[Task, BidResponse]

  def bid(client: Client[Task], bidRequest: BidRequest): Task[Option[BidResponse]] = {
    val url = Uri(
      scheme = Some(Scheme.http),
      authority = Some(Authority(host = RegName("localhost"), port = Some(9000))),
      path = "/bid"
    )

    val httpRequest = Request[Task](
      method = Method.POST,
      uri = url
    ).withEntity[BidRequest](bidRequest)

    client.expectOption[BidResponse](httpRequest)
  }
} 
Example 31
Source File: UserRegistry.scala    From http4s-tracer   with Apache License 2.0 5 votes vote down vote up
package dev.profunktor.tracer.http
package client

import cats.effect.Sync
import cats.syntax.functor._
import dev.profunktor.tracer.model.user.User
import io.circe.syntax._
import org.http4s.Method._
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.client.dsl.Http4sClientDsl

trait UserRegistry[F[_]] {
  def register(user: User): F[Unit]
}

final case class LiveUserRegistry[F[_]: Sync](
    client: Client[F]
) extends UserRegistry[F]
    with Http4sClientDsl[F] {

  private val uri = Uri.uri("https://jsonplaceholder.typicode.com/posts")

  def register(user: User): F[Unit] =
    client.successful(POST(user.asJson, uri)).void
} 
Example 32
Source File: AirlinesHttpEndpointSpec.scala    From core   with Apache License 2.0 5 votes vote down vote up
package com.smartbackpackerapp.http

import cats.effect.IO
import com.smartbackpackerapp.common.IOAssertion
import com.smartbackpackerapp.http.Http4sUtils._
import com.smartbackpackerapp.model._
import com.smartbackpackerapp.repository.algebra.AirlineRepository
import com.smartbackpackerapp.service.AirlineService
import org.http4s.{HttpService, Query, Request, Status, Uri}
import org.scalatest.prop.PropertyChecks
import org.scalatest.{FlatSpecLike, Matchers}

class AirlinesHttpEndpointSpec extends FlatSpecLike with Matchers with AirlinesHttpEndpointFixture {

  forAll(examples) { (airline, expectedStatus, expectedBody) =>
    it should s"find the airline $airline" in IOAssertion {
      val request = Request[IO](uri = Uri(path = s"/$ApiVersion/airlines", query = Query(("name", Some(airline)))))

      httpService(request).value.map { task =>
        task.fold(fail("Empty response")){ response =>
          response.status should be (expectedStatus)
          assert(response.body.asString.contains(expectedBody))
        }
      }
    }
  }

}

trait AirlinesHttpEndpointFixture extends PropertyChecks {

  private val airlines: List[Airline] = List(
    Airline(AirlineName("Aer Lingus"), BaggagePolicy(
      allowance = List(
        BaggageAllowance(CabinBag, Some(10), BaggageSize(55, 40, 24)),
        BaggageAllowance(SmallBag, None, BaggageSize(25, 33, 20))
      ),
      extra = None,
      website = Some("https://www.aerlingus.com/travel-information/baggage-information/cabin-baggage/"))
    ),
    Airline(AirlineName("Transavia"), BaggagePolicy(
      allowance = List(
        BaggageAllowance(CabinBag, None, BaggageSize(55, 40, 25))
      ),
      extra = None,
      website = Some("https://www.transavia.com/en-EU/service/hand-luggage/"))
    )
  )

  private val testAirlineRepo = new AirlineRepository[IO] {
    override def findAirline(airlineName: AirlineName): IO[Option[Airline]] = IO {
      airlines.find(_.name.value == airlineName.value)
    }
  }

  private implicit val errorHandler = new HttpErrorHandler[IO]

  val httpService: HttpService[IO] =
    ioMiddleware(
      new AirlinesHttpEndpoint(
        new AirlineService[IO](testAirlineRepo)
      ).service
    )

  val examples = Table(
    ("airline", "expectedStatus", "expectedBody"),
    ("Aer Lingus", Status.Ok, "baggagePolicy"),
    ("Transavia", Status.Ok, "baggagePolicy"),
    ("Ryan Air", Status.NotFound, """{"code":"100","error":"Airline not found Ryan Air"}""")
  )

} 
Example 33
Source File: HealthInfoHttpEndpointSpec.scala    From core   with Apache License 2.0 5 votes vote down vote up
package com.smartbackpackerapp.http

import cats.effect.IO
import com.smartbackpackerapp.common.IOAssertion
import com.smartbackpackerapp.model.{CountryCode, Health, HealthAlert, HealthNotices, LevelOne, Vaccinations, Vaccine}
import com.smartbackpackerapp.repository.algebra.HealthRepository
import com.smartbackpackerapp.service.HealthService
import org.http4s.{HttpService, Request, Status, Uri}
import org.scalatest.prop.PropertyChecks
import org.scalatest.{FlatSpecLike, Matchers}

class HealthInfoHttpEndpointSpec extends FlatSpecLike with Matchers with HealthInfoFixture {

  forAll(examples) { (countryCode, expectedStatus) =>
    it should s"try to retrieve health information for $countryCode" in IOAssertion {
      val request = Request[IO](uri = Uri(path = s"/$ApiVersion/health/$countryCode"))

      httpService(request).value.map { task =>
        task.fold(fail("Empty response")){ response =>
          response.status should be (expectedStatus)
        }
      }
    }
  }

}

trait HealthInfoFixture extends PropertyChecks {

  import Http4sUtils._

  private val testHealth = Health(
    vaccinations = Vaccinations(List.empty[Vaccine], List.empty[Vaccine], List.empty[Vaccine]),
    notices = HealthNotices(
      alertLevel = LevelOne,
      alerts = List.empty[HealthAlert]
    )
  )

  private val repo = new HealthRepository[IO] {
    override def findHealthInfo(countryCode: CountryCode): IO[Option[Health]] = IO {
      if (countryCode.value == "AR") Some(testHealth)
      else None
    }
  }

  private implicit val errorHandler = new HttpErrorHandler[IO]

  val httpService: HttpService[IO] =
    ioMiddleware(
      new HealthInfoHttpEndpoint(
        new HealthService[IO](repo)
      ).service
    )

  val examples = Table(
    ("countryCode", "expectedStatus"),
    ("AR", Status.Ok),
    ("XX", Status.NotFound)
  )

} 
Example 34
Source File: VisaRestrictionIndexHttpEndpointSpec.scala    From core   with Apache License 2.0 5 votes vote down vote up
package com.smartbackpackerapp.http

import cats.effect.IO
import com.smartbackpackerapp.common.IOAssertion
import com.smartbackpackerapp.model.{Count, CountryCode, Ranking, Sharing, VisaRestrictionsIndex}
import com.smartbackpackerapp.repository.algebra.VisaRestrictionsIndexRepository
import com.smartbackpackerapp.service.VisaRestrictionIndexService
import org.http4s.{HttpService, Request, Status, Uri}
import org.scalatest.prop.PropertyChecks
import org.scalatest.{FlatSpecLike, Matchers}

class VisaRestrictionIndexHttpEndpointSpec extends FlatSpecLike with Matchers with VisaRestrictionIndexFixture {

  forAll(examples) { (countryCode, expectedStatus) =>
    it should s"try to retrieve visa restriction index for $countryCode" in IOAssertion {
      val request = Request[IO](uri = Uri(path = s"/$ApiVersion/ranking/$countryCode"))

      httpService(request).value.map { task =>
        task.fold(fail("Empty response")){ response =>
          response.status should be (expectedStatus)
        }
      }
    }
  }

}

trait VisaRestrictionIndexFixture extends PropertyChecks {

  import Http4sUtils._

  private val repo = new VisaRestrictionsIndexRepository[IO] {
    override def findRestrictionsIndex(countryCode: CountryCode): IO[Option[VisaRestrictionsIndex]] =
      IO {
        if (countryCode.value == "AR") Some(VisaRestrictionsIndex(Ranking(0), Count(0), Sharing(0)))
        else None
      }
  }

  private implicit val errorHandler = new HttpErrorHandler[IO]

  val httpService: HttpService[IO] =
    ioMiddleware(
      new VisaRestrictionIndexHttpEndpoint(
        new VisaRestrictionIndexService[IO](repo)
      ).service
    )

  val examples = Table(
    ("countryCode", "expectedStatus"),
    ("AR", Status.Ok),
    ("XX", Status.NotFound)
  )

} 
Example 35
Source File: DestinationInfoHttpEndpointSpec.scala    From core   with Apache License 2.0 5 votes vote down vote up
package com.smartbackpackerapp.http

import cats.Parallel
import cats.syntax.option._
import com.smartbackpackerapp.common.TaskAssertion
import com.smartbackpackerapp.config.SBConfiguration
import com.smartbackpackerapp.http.Http4sUtils._
import com.smartbackpackerapp.model.{Country, CountryCode, CountryName, Currency, VisaNotRequired, VisaRequirementsData}
import com.smartbackpackerapp.repository.algebra.VisaRequirementsRepository
import com.smartbackpackerapp.service.{AbstractExchangeRateService, CurrencyExchangeDTO, DestinationInfoService}
import monix.eval.Task
import org.http4s.{HttpService, Query, Request, Status, Uri}
import org.scalatest.prop.PropertyChecks
import org.scalatest.{FlatSpecLike, Matchers}

class DestinationInfoHttpEndpointSpec extends FlatSpecLike with Matchers with DestinationInfoHttpEndpointFixture {

  forAll(examples) { (from, to, expectedStatus, expectedCountry, expectedVisa) =>
    it should s"retrieve visa requirements from $from to $to" in TaskAssertion {
      val request = Request[Task](uri = Uri(path = s"/$ApiVersion/traveling/$from/to/$to", query = Query(("baseCurrency", Some("EUR")))))

      httpService(request).value.map { task =>
        task.fold(fail("Empty response")){ response =>
          response.status should be (expectedStatus)

          val body = response.body.asString
          assert(body.contains(expectedCountry))
          assert(body.contains(expectedVisa))
        }
      }
    }
  }

}

trait DestinationInfoHttpEndpointFixture extends PropertyChecks {

  val examples = Table(
    ("from", "code", "expectedStatus","expectedCountry", "expectedVisa"),
    ("AR", "GB", Status.Ok, "United Kingdom", "VisaNotRequired"),
    ("AR", "KO", Status.NotFound, "Country not found", """{"code":"100","error":"Country not found KO"}"""),
    ("AR", "AR", Status.BadRequest, "Countries must be different", """{"code":"101","error":"Countries must be different!"}""")
  )

  private val repo = new VisaRequirementsRepository[Task] {
    override def findVisaRequirements(from: CountryCode, to: CountryCode): Task[Option[VisaRequirementsData]] = Task {
      if (to.value == "KO") none[VisaRequirementsData]
      else
      VisaRequirementsData(
        from = Country(CountryCode("AR"), CountryName("Argentina"), Currency("ARS")),
        to   = Country(CountryCode("GB"), CountryName("United Kingdom"), Currency("GBP")),
        visaCategory = VisaNotRequired,
        description = "90 days within any 180 day period"
      ).some
    }
  }

  private lazy val sbConfig = new SBConfiguration[Task]

  private val rateService = new AbstractExchangeRateService[Task](sbConfig) {
    override protected def retrieveExchangeRate(uri: String): Task[CurrencyExchangeDTO] = Task {
      CurrencyExchangeDTO("EUR", "", Map("RON" -> 4.59))
    }
  }

  private implicit val errorHandler = new HttpErrorHandler[Task]

  private implicit val parallel: Parallel[Task, Task] =
    Parallel[Task, Task.Par].asInstanceOf[Parallel[Task, Task]]

  val httpService: HttpService[Task] =
    taskMiddleware(
      new DestinationInfoHttpEndpoint(
        new DestinationInfoService[Task](sbConfig, repo, rateService)
      ).service
    )

} 
Example 36
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 37
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 38
Source File: CustomResourcesApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.crd.{CrdContext, CustomResource, CustomResourceList}
import com.goyeau.kubernetes.client.operation._
import com.goyeau.kubernetes.client.util.CirceEntityCodec._
import com.goyeau.kubernetes.client.util.EnrichedStatus
import io.circe._
import org.http4s.Method._
import org.http4s.client.Client
import org.http4s.implicits._
import org.http4s.{Status, Uri}

private[client] case class CustomResourcesApi[F[_], A, B](
    httpClient: Client[F],
    config: KubeConfig,
    context: CrdContext
)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[CustomResourceList[A, B]],
    encoder: Encoder[CustomResource[A, B]],
    decoder: Decoder[CustomResource[A, B]]
) extends Listable[F, CustomResourceList[A, B]] {

  val resourceUri: Uri = uri"/apis" / context.group / context.version / context.plural

  def namespace(namespace: String): NamespacedCustomResourcesApi[F, A, B] =
    NamespacedCustomResourcesApi(httpClient, config, context, namespace)
}

private[client] case class NamespacedCustomResourcesApi[F[_], A, B](
    httpClient: Client[F],
    config: KubeConfig,
    context: CrdContext,
    namespace: String
)(implicit
    val F: Sync[F],
    val resourceEncoder: Encoder[CustomResource[A, B]],
    val resourceDecoder: Decoder[CustomResource[A, B]],
    val listDecoder: Decoder[CustomResourceList[A, B]]
) extends Creatable[F, CustomResource[A, B]]
    with Replaceable[F, CustomResource[A, B]]
    with Gettable[F, CustomResource[A, B]]
    with Listable[F, CustomResourceList[A, B]]
    with Deletable[F]
    with GroupDeletable[F]
    with Watchable[F, CustomResource[A, B]] {

  val resourceUri: Uri = uri"/apis" / context.group / context.version / "namespaces" / namespace / context.plural

  def updateStatus(name: String, resource: CustomResource[A, B]): F[Status] =
    httpClient.fetch(
      PUT(resource, config.server.resolve(resourceUri / name / "status"), config.authorization.toSeq: _*)
    )(
      EnrichedStatus[F]
    )
} 
Example 39
Source File: CronJobsApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe._
import io.k8s.api.batch.v1beta1.{CronJob, CronJobList}
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.implicits._

private[client] case class CronJobsApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[CronJobList],
    encoder: Encoder[CronJob],
    decoder: Decoder[CronJob]
) extends Listable[F, CronJobList] {
  val resourceUri: Uri = uri"/apis" / "batch" / "v1beta1" / "cronjobs"

  def namespace(namespace: String): NamespacedCronJobsApi[F] = NamespacedCronJobsApi(httpClient, config, namespace)
}

private[client] case class NamespacedCronJobsApi[F[_]](httpClient: Client[F], config: KubeConfig, namespace: String)(
    implicit
    val F: Sync[F],
    val resourceEncoder: Encoder[CronJob],
    val resourceDecoder: Decoder[CronJob],
    val listDecoder: Decoder[CronJobList]
) extends Creatable[F, CronJob]
    with Replaceable[F, CronJob]
    with Gettable[F, CronJob]
    with Listable[F, CronJobList]
    with Deletable[F]
    with DeletableTerminated[F]
    with GroupDeletable[F]
    with Watchable[F, CronJob] {
  val resourceUri: Uri = uri"/apis" / "batch" / "v1beta1" / "namespaces" / namespace / "cronjobs"
} 
Example 40
Source File: JobsApi.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.api

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import com.goyeau.kubernetes.client.operation._
import io.circe._
import io.k8s.api.batch.v1.{Job, JobList}
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.implicits._

private[client] case class JobsApi[F[_]](httpClient: Client[F], config: KubeConfig)(implicit
    val F: Sync[F],
    val listDecoder: Decoder[JobList],
    encoder: Encoder[Job],
    decoder: Decoder[Job]
) extends Listable[F, JobList] {
  val resourceUri: Uri = uri"/apis" / "batch" / "v1" / "jobs"

  def namespace(namespace: String): NamespacedJobsApi[F] = NamespacedJobsApi(httpClient, config, namespace)
}

private[client] case class NamespacedJobsApi[F[_]](
    httpClient: Client[F],
    config: KubeConfig,
    namespace: String
)(implicit
    val F: Sync[F],
    val resourceEncoder: Encoder[Job],
    val resourceDecoder: Decoder[Job],
    val listDecoder: Decoder[JobList]
) extends Creatable[F, Job]
    with Replaceable[F, Job]
    with Gettable[F, Job]
    with Listable[F, JobList]
    with Deletable[F]
    with DeletableTerminated[F]
    with GroupDeletable[F]
    with Watchable[F, Job] {
  val resourceUri: Uri = uri"/apis" / "batch" / "v1" / "namespaces" / namespace / "jobs"
} 
Example 41
Source File: HttpUpload.scala    From temperature-machine   with Apache License 2.0 5 votes vote down vote up
package bad.robot.temperature.client

import java.net.{InetAddress, NetworkInterface}

import bad.robot.temperature.IpAddress._
import bad.robot.temperature._
import cats.effect.IO
import org.http4s.Status.Successful
import org.http4s.Uri.{Authority, IPv4, Scheme}
import org.http4s.client.dsl.Http4sClientDsl.WithBodyOps
import org.http4s.client.{Client => Http4sClient}
import org.http4s.dsl.io._
import org.http4s.headers.`X-Forwarded-For`
import org.http4s.{Uri, _}
import scalaz.{-\/, \/, \/-}

import scala.collection.JavaConverters._

case class HttpUpload(address: InetAddress, client: Http4sClient[IO]) extends TemperatureWriter {

  private implicit val encoder = jsonEncoder[Measurement]

  private val decoder = EntityDecoder.text[IO]
  
  def write(measurement: Measurement): Error \/ Unit = {
    val uri = Uri(
      scheme = Some(Scheme.http),
      authority = Some(Authority(host = IPv4(address.getHostAddress), port = Some(11900))),
      path = "/temperature"
    )

    val request: IO[Request[IO]] = PUT.apply(uri, measurement, `X-Forwarded-For`(currentIpAddress))

    val fetch: IO[Error \/ Unit] = client.fetch(request) {
      case Successful(_) => IO.pure(\/-(()))
      case error @ _     => IO(-\/(UnexpectedError(s"Failed to PUT temperature data to ${uri.renderString}, response was ${error.status}: ${error.as[String](implicitly, decoder).attempt.unsafeRunSync}")))
    }

    // why no leftMap?
    fetch.attempt.map {
      case Left(t)      => -\/(UnexpectedError(s"Failed attempting to connect to $address to send $measurement\n\nError was: $t"))
      case Right(value) => value
    }.unsafeRunSync()
  }
}

object HttpUpload {

  val allNetworkInterfaces: List[NetworkInterface] = {
    NetworkInterface.getNetworkInterfaces
      .asScala
      .toList
      .filter(_.isUp)
      .filterNot(_.isLoopback)
  }

} 
Example 42
Source File: Http4sGitHubApiAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.github.http4s

import org.http4s.{Request, Uri}
import org.scalasteward.core.git.Branch
import org.scalasteward.core.github._
import org.scalasteward.core.util.HttpJsonClient
import org.scalasteward.core.vcs.VCSApiAlg
import org.scalasteward.core.vcs.data._

final class Http4sGitHubApiAlg[F[_]](
    gitHubApiHost: Uri,
    modify: Repo => Request[F] => F[Request[F]]
)(implicit
    client: HttpJsonClient[F]
) extends VCSApiAlg[F] {
  private val url = new Url(gitHubApiHost)

  override def createFork(repo: Repo): F[RepoOut] =
    client.post(url.forks(repo), modify(repo))

  override def createPullRequest(repo: Repo, data: NewPullRequestData): F[PullRequestOut] =
    client.postWithBody(url.pulls(repo), data, modify(repo))

  override def getBranch(repo: Repo, branch: Branch): F[BranchOut] =
    client.get(url.branches(repo, branch), modify(repo))

  override def getRepo(repo: Repo): F[RepoOut] =
    client.get(url.repos(repo), modify(repo))

  override def listPullRequests(repo: Repo, head: String, base: Branch): F[List[PullRequestOut]] =
    client.get(url.listPullRequests(repo, head, base), modify(repo))
} 
Example 43
Source File: Cli.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.application

import caseapp._
import caseapp.core.Error.MalformedValue
import caseapp.core.argparser.{ArgParser, SimpleArgParser}
import cats.implicits._
import org.http4s.Uri
import org.http4s.syntax.literals._
import org.scalasteward.core.application.Cli._
import org.scalasteward.core.util.ApplicativeThrowable
import scala.concurrent.duration._

final class Cli[F[_]](implicit F: ApplicativeThrowable[F]) {
  def parseArgs(args: List[String]): F[Args] =
    F.fromEither {
      CaseApp.parse[Args](args).bimap(e => new Throwable(e.message), { case (parsed, _) => parsed })
    }
}

object Cli {
  final case class Args(
      workspace: String,
      reposFile: String,
      defaultRepoConf: Option[String] = None,
      gitAuthorName: String = "Scala Steward",
      gitAuthorEmail: String,
      vcsType: SupportedVCS = SupportedVCS.GitHub,
      vcsApiHost: Uri = uri"https://api.github.com",
      vcsLogin: String,
      gitAskPass: String,
      signCommits: Boolean = false,
      whitelist: List[String] = Nil,
      readOnly: List[String] = Nil,
      disableSandbox: Boolean = false,
      doNotFork: Boolean = false,
      ignoreOptsFiles: Boolean = false,
      envVar: List[EnvVar] = Nil,
      processTimeout: FiniteDuration = 10.minutes,
      scalafixMigrations: Option[String] = None,
      groupMigrations: Option[String] = None,
      cacheTtl: FiniteDuration = 2.hours,
      cacheMissDelay: FiniteDuration = 0.milliseconds,
      bitbucketServerUseDefaultReviewers: Boolean = false
  )

  final case class EnvVar(name: String, value: String)

  implicit val envVarArgParser: SimpleArgParser[EnvVar] =
    SimpleArgParser.from[EnvVar]("env-var") { s =>
      s.trim.split('=').toList match {
        case name :: (value @ _ :: _) =>
          Right(EnvVar(name.trim, value.mkString("=").trim))
        case _ =>
          val error = "The value is expected in the following format: NAME=VALUE."
          Left(MalformedValue("EnvVar", error))
      }
    }

  implicit val finiteDurationArgParser: ArgParser[FiniteDuration] =
    ArgParser[String].xmapError(
      _.toString(),
      s =>
        parseFiniteDuration(s).leftMap { throwable =>
          val error = s"The value is expected in the following format: <length><unit>. ($throwable)"
          MalformedValue("FiniteDuration", error)
        }
    )

  private def parseFiniteDuration(s: String): Either[Throwable, FiniteDuration] =
    Either.catchNonFatal(Duration(s)).flatMap {
      case fd: FiniteDuration => Right(fd)
      case d                  => Left(new Throwable(s"$d is not a FiniteDuration"))
    }

  implicit val uriArgParser: ArgParser[Uri] =
    ArgParser[String].xmapError(
      _.renderString,
      s => Uri.fromString(s).leftMap(pf => MalformedValue("Uri", pf.message))
    )
} 
Example 44
Source File: Config.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.application

import better.files._
import cats.effect.Sync
import org.http4s.Uri
import org.http4s.Uri.UserInfo
import org.scalasteward.core.application.Cli.EnvVar
import org.scalasteward.core.git.Author
import org.scalasteward.core.util
import org.scalasteward.core.vcs.data.AuthenticatedUser
import scala.concurrent.duration.FiniteDuration
import scala.sys.process.Process


final case class Config(
    workspace: File,
    reposFile: File,
    defaultRepoConfigFile: Option[File],
    gitAuthor: Author,
    vcsType: SupportedVCS,
    vcsApiHost: Uri,
    vcsLogin: String,
    gitAskPass: File,
    signCommits: Boolean,
    whitelistedDirectories: List[String],
    readOnlyDirectories: List[String],
    disableSandbox: Boolean,
    doNotFork: Boolean,
    ignoreOptsFiles: Boolean,
    envVars: List[EnvVar],
    processTimeout: FiniteDuration,
    scalafixMigrations: Option[File],
    groupMigrations: Option[File],
    cacheTtl: FiniteDuration,
    cacheMissDelay: FiniteDuration,
    bitbucketServerUseDefaultReviewers: Boolean
) {
  def vcsUser[F[_]](implicit F: Sync[F]): F[AuthenticatedUser] = {
    val urlWithUser = util.uri.withUserInfo.set(UserInfo(vcsLogin, None))(vcsApiHost).renderString
    val prompt = s"Password for '$urlWithUser': "
    F.delay {
      val password = Process(List(gitAskPass.pathAsString, prompt)).!!.trim
      AuthenticatedUser(vcsLogin, password)
    }
  }
}

object Config {
  def create[F[_]](args: Cli.Args)(implicit F: Sync[F]): F[Config] =
    F.delay {
      Config(
        workspace = args.workspace.toFile,
        reposFile = args.reposFile.toFile,
        defaultRepoConfigFile = args.defaultRepoConf.map(_.toFile),
        gitAuthor = Author(args.gitAuthorName, args.gitAuthorEmail),
        vcsType = args.vcsType,
        vcsApiHost = args.vcsApiHost,
        vcsLogin = args.vcsLogin,
        gitAskPass = args.gitAskPass.toFile,
        signCommits = args.signCommits,
        whitelistedDirectories = args.whitelist,
        readOnlyDirectories = args.readOnly,
        disableSandbox = args.disableSandbox,
        doNotFork = args.doNotFork,
        ignoreOptsFiles = args.ignoreOptsFiles,
        envVars = args.envVar,
        processTimeout = args.processTimeout,
        scalafixMigrations = args.scalafixMigrations.map(_.toFile),
        groupMigrations = args.groupMigrations.map(_.toFile),
        cacheTtl = args.cacheTtl,
        cacheMissDelay = args.cacheMissDelay,
        bitbucketServerUseDefaultReviewers = args.bitbucketServerUseDefaultReviewers
      )
    }
} 
Example 45
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 46
Source File: Json.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.bitbucketserver.http4s

import cats.data.NonEmptyList
import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder}
import io.circe.{Decoder, Encoder}
import org.http4s.Uri
import org.scalasteward.core.git.Sha1
import org.scalasteward.core.vcs.data.PullRequestState

object Json {
  case class Page[A](values: List[A])

  case class Repo(id: Int, name: String, forkable: Boolean, project: Project, links: Links)

  case class Project(key: String)

  type Links = Map[String, NonEmptyList[Link]]

  case class Link(href: Uri, name: Option[String])

  case class PR(title: String, state: PullRequestState, links: Links)

  case class NewPR(
      title: String,
      description: String,
      state: PullRequestState,
      open: Boolean,
      closed: Boolean,
      fromRef: Ref,
      toRef: Ref,
      locked: Boolean,
      reviewers: List[Reviewer]
  )

  case class Ref(id: String, repository: Repository)

  case class Repository(slug: String, project: Project)

  case class Condition(reviewers: List[DefaultReviewer])

  case class DefaultReviewer(name: String)

  case class Reviewer(user: User)

  case class User(name: String)

  case class Branches(values: NonEmptyList[Branch])

  case class Branch(id: String, latestCommit: Sha1)

  implicit def pageDecode[A: Decoder]: Decoder[Page[A]] = deriveDecoder
  implicit val repoDecode: Decoder[Repo] = deriveDecoder
  implicit val projectDecode: Decoder[Project] = deriveDecoder
  implicit val linkDecoder: Decoder[Link] = deriveDecoder
  implicit val uriDecoder: Decoder[Uri] = Decoder.decodeString.map(Uri.unsafeFromString)
  implicit val prDecoder: Decoder[PR] = deriveDecoder
  implicit val reviewerDecoder: Decoder[Reviewer] = deriveDecoder
  implicit val userDecoder: Decoder[User] = deriveDecoder
  implicit val defaultReviewerDecoder: Decoder[DefaultReviewer] = deriveDecoder
  implicit val conditionDecoder: Decoder[Condition] = deriveDecoder
  implicit val branchDecoder: Decoder[Branch] = deriveDecoder
  implicit val branchesDecoder: Decoder[Branches] = deriveDecoder

  implicit val encodeNewPR: Encoder[NewPR] = deriveEncoder
  implicit val encodeRef: Encoder[Ref] = deriveEncoder
  implicit val encodeRepository: Encoder[Repository] = deriveEncoder
  implicit val encodeProject: Encoder[Project] = deriveEncoder
  implicit val encodeReviewer: Encoder[Reviewer] = deriveEncoder
  implicit val encodeUser: Encoder[User] = deriveEncoder
} 
Example 47
Source File: ServerInterpreterTest.scala    From endpoints4s   with MIT License 5 votes vote down vote up
package endpoints4s.http4s.server

import java.net.ServerSocket

import cats.effect.{ContextShift, IO, Timer}
import endpoints4s.{Invalid, Valid}
import endpoints4s.algebra.server.{
  BasicAuthenticationTestSuite,
  DecodedUrl,
  EndpointsTestSuite,
  JsonEntitiesFromSchemasTestSuite,
  SumTypedEntitiesTestSuite,
  TextEntitiesTestSuite
}
import org.http4s.server.Router
import org.http4s.{HttpRoutes, Uri}
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.syntax.kleisli._

import scala.concurrent.ExecutionContext

class ServerInterpreterTest
    extends EndpointsTestSuite[EndpointsTestApi]
    with BasicAuthenticationTestSuite[EndpointsTestApi]
    with JsonEntitiesFromSchemasTestSuite[EndpointsTestApi]
    with TextEntitiesTestSuite[EndpointsTestApi]
    with SumTypedEntitiesTestSuite[EndpointsTestApi] {

  val serverApi = new EndpointsTestApi()

  def decodeUrl[A](url: serverApi.Url[A])(rawValue: String): DecodedUrl[A] = {
    val uri =
      Uri.fromString(rawValue).getOrElse(sys.error(s"Illegal URI: $rawValue"))

    url.decodeUrl(uri) match {
      case None                  => DecodedUrl.NotMatched
      case Some(Invalid(errors)) => DecodedUrl.Malformed(errors)
      case Some(Valid(a))        => DecodedUrl.Matched(a)
    }
  }

  private def serveGeneralEndpoint[Req, Resp](
      endpoint: serverApi.Endpoint[Req, Resp],
      request2response: Req => Resp
  )(runTests: Int => Unit): Unit = {
    val port = {
      val socket = new ServerSocket(0)
      try socket.getLocalPort
      finally if (socket != null) socket.close()
    }
    implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
    implicit val timer: Timer[IO] = IO.timer(ExecutionContext.global)
    val service = HttpRoutes.of[IO](endpoint.implementedBy(request2response))
    val httpApp = Router("/" -> service).orNotFound
    val server =
      BlazeServerBuilder[IO](ExecutionContext.global)
        .bindHttp(port, "localhost")
        .withHttpApp(httpApp)
    server.resource.use(_ => IO(runTests(port))).unsafeRunSync()
  }

  def serveEndpoint[Resp](
      endpoint: serverApi.Endpoint[_, Resp],
      response: => Resp
  )(runTests: Int => Unit): Unit =
    serveGeneralEndpoint(endpoint, (_: Any) => response)(runTests)

  def serveIdentityEndpoint[Resp](
      endpoint: serverApi.Endpoint[Resp, Resp]
  )(runTests: Int => Unit): Unit =
    serveGeneralEndpoint(endpoint, identity[Resp])(runTests)
} 
Example 48
Source File: Http4sClientEndpointsJsonSchemaTest.scala    From endpoints4s   with MIT License 5 votes vote down vote up
package endpoints4s.http4s.client

import endpoints4s.algebra
import endpoints4s.algebra.client

import cats.effect.Sync
import org.http4s.client.Client
import cats.effect.IO
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.global
import org.http4s.client.asynchttpclient.AsyncHttpClient
import cats.effect.ContextShift
import endpoints4s.algebra.circe
import org.http4s.Uri

class TestJsonSchemaClient[F[_]: Sync](host: Uri, client: Client[F])
    extends Endpoints[F](host, client)
    with BasicAuthentication
    with JsonEntitiesFromCodecs
    with algebra.BasicAuthenticationTestApi
    with algebra.EndpointsTestApi
    with algebra.JsonFromCodecTestApi
    with algebra.SumTypedEntitiesTestApi
    with circe.JsonFromCirceCodecTestApi
    with circe.JsonEntitiesFromCodecs

class Http4sClientEndpointsJsonSchemaTest
    extends client.EndpointsTestSuite[TestJsonSchemaClient[IO]]
    with client.BasicAuthTestSuite[TestJsonSchemaClient[IO]]
    with client.JsonFromCodecTestSuite[TestJsonSchemaClient[IO]]
    with client.SumTypedEntitiesTestSuite[TestJsonSchemaClient[IO]] {

  implicit val ctx: ContextShift[IO] = IO.contextShift(global)

  val (ahc, shutdown) =
    AsyncHttpClient.allocate[IO]().unsafeRunSync()

  val client = new TestJsonSchemaClient[IO](
    Uri.unsafeFromString(s"http://localhost:$wiremockPort"),
    ahc
  )

  def call[Req, Resp](
      endpoint: client.Endpoint[Req, Resp],
      args: Req
  ): Future[Resp] = {
    Thread.sleep(50)
    val eventualResponse = endpoint(args)
    Thread.sleep(50)
    eventualResponse.unsafeToFuture()
  }

  def encodeUrl[A](url: client.Url[A])(a: A): String =
    url.encodeUrl(a).toOption.get.renderString

  clientTestSuite()
  basicAuthSuite()
  jsonFromCodecTestSuite()

  override def afterAll(): Unit = {
    shutdown.unsafeRunSync()
    super.afterAll()
  }

} 
Example 49
Source File: ServerSpec.scala    From Learn-Scala-Programming   with MIT License 5 votes vote down vote up
import ch14.{Config, Server}
import cats.effect.IO
import cats.implicits._
import io.circe.Json
import io.circe.literal._
import org.http4s.circe._
import org.http4s.client.blaze.Http1Client
import org.http4s.{Method, Request, Status, Uri}
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpec}
import org.http4s.server.{Server => Http4sServer}

class ServerSpec extends WordSpec with Matchers with BeforeAndAfterAll {
  private lazy val client = Http1Client[IO]().unsafeRunSync()

  private lazy val configIO = Config.load("test.conf")
  private lazy val config = configIO.unsafeRunSync()

  private lazy val rootUrl = s"http://${config.server.host}:${config.server.port}"

  private val server: Option[Http4sServer[IO]] = (for {
    builder <- Server.createServer(configIO)
  } yield builder.start.unsafeRunSync()).compile.last.unsafeRunSync()


  override def afterAll(): Unit = {
    client.shutdown.unsafeRunSync()
    server.foreach(_.shutdown.unsafeRunSync())
  }

  "The server" should {
    "get an empty inventory" in {
      val json = client.expect[Json](s"$rootUrl/inventory").unsafeRunSync()
      json shouldBe json"""{}"""
    }
    "create articles" in {
      val eggs = Request[IO](method = Method.POST, uri = Uri.unsafeFromString(s"$rootUrl/articles/eggs"))
      client.status(eggs).unsafeRunSync() shouldBe Status.NoContent
      val chocolate = Request[IO](method = Method.POST, uri = Uri.unsafeFromString(s"$rootUrl/articles/chocolate"))
      client.status(chocolate).unsafeRunSync() shouldBe Status.NoContent
      val json = client.expect[Json](s"$rootUrl/inventory").unsafeRunSync()
      json shouldBe json"""{"eggs" : 0,"chocolate" : 0}"""
    }
    "update inventory" in {
      val restock = Request[IO](method = Method.POST, uri = Uri.unsafeFromString(s"$rootUrl/restock")).withBody(json"""{ "inventory" : { "eggs": 10, "chocolate": 20 }}""")
      client.expect[Json](restock).unsafeRunSync() shouldBe json"""{ "eggs" : 10, "chocolate" : 20 }"""
      client.expect[Json](restock).unsafeRunSync() shouldBe json"""{ "eggs" : 20, "chocolate" : 40 }"""
    }
    "deliver purchase if there is enough inventory" in {
      val purchase = Request[IO](method = Method.POST, uri = Uri.unsafeFromString(s"$rootUrl/purchase")).withBody(json"""{ "order" : { "eggs": 5, "chocolate": 5 }}""")
      client.expect[Json](purchase).unsafeRunSync() shouldBe json"""{ "eggs" : 5, "chocolate" : 5 }"""
    }
    "not deliver purchase if there is not enough inventory" in {
      val purchase = Request[IO](method = Method.POST, uri = Uri.unsafeFromString(s"$rootUrl/purchase")).withBody(json"""{ "order" : { "eggs": 5, "chocolate": 45 }}""")
      client.expect[Json](purchase).unsafeRunSync() shouldBe json"""{ "eggs" : 0, "chocolate" : 0 }"""
    }
  }

} 
Example 50
Source File: ExportEndpointTest.scala    From temperature-machine   with Apache License 2.0 5 votes vote down vote up
package bad.robot.temperature.server

import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle.SHORT
import java.util.Locale._

import cats.effect.IO
import org.http4s.Method.GET
import org.http4s.Status.Ok
import org.http4s.implicits._
import org.http4s.{Request, Uri}
import org.specs2.mutable.Specification

import scalaz.syntax.either._

class ExportEndpointTest extends Specification {

  sequential

  "convert json to csv" >> {
    val exampleJson =
      """
        |[
        |  {
        |    "label": "bedroom1-sensor-1",
        |    "data": [
        |      {
        |        "x": 1507709610000,
        |        "y": "NaN"
        |      },
        |      {
        |        "x": 1507709640000,
        |        "y": "+2.2062500000E01"
        |      },
        |      {
        |        "x": 1507709680000,
        |        "y": "+2.2262500000E01"
        |      }
        |    ]
        |  }
        |]
      """.stripMargin
    
    val expectedCsv = """"Sensor","Time","Temperature","Difference"
                        |"bedroom1-sensor-1","11/10/17 08:13","NaN","0"
                        |"bedroom1-sensor-1","11/10/17 08:14","22.0625","NaN"
                        |"bedroom1-sensor-1","11/10/17 08:14","22.2625","0.20"""".stripMargin

    val UkDateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(SHORT).withLocale(UK).withZone(ZoneId.of("GMT"))
    
    val request = Request[IO](GET, Uri.uri("/temperatures.csv"))
    val service = ExportEndpoint(exampleJson.right, UkDateTimeFormatter)
    val response = service.orNotFound.run(request).unsafeRunSync()
    response.as[String].unsafeRunSync must_== expectedCsv
    response.status must_== Ok
  }

} 
Example 51
Source File: Url.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.github

import org.http4s.Uri
import org.scalasteward.core.git.Branch
import org.scalasteward.core.vcs.data.Repo

class Url(apiHost: Uri) {
  def branches(repo: Repo, branch: Branch): Uri =
    repos(repo) / "branches" / branch.name

  def forks(repo: Repo): Uri =
    repos(repo) / "forks"

  def listPullRequests(repo: Repo, head: String, base: Branch): Uri =
    pulls(repo)
      .withQueryParam("head", head)
      .withQueryParam("base", base.name)
      .withQueryParam("state", "all")

  def pulls(repo: Repo): Uri =
    repos(repo) / "pulls"

  def repos(repo: Repo): Uri =
    apiHost / "repos" / repo.owner / repo.repo
} 
Example 52
Source File: MarkdownSpec.scala    From sonar-scala   with GNU Lesser General Public License v3.0 5 votes vote down vote up
package com.mwz.sonar.scala.pr

import org.http4s.Uri
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import org.sonar.api.batch.fs.InputFile
import org.sonar.api.batch.fs.internal.TestInputFileBuilder
import org.sonar.api.batch.rule.Severity
import org.sonar.api.rule.RuleKey

class MarkdownSpec extends AnyFlatSpec with Matchers {
  it should "create a markdown comment" in {
    val uri: Uri = Uri.uri("https://test.com")
    val file: InputFile = TestInputFileBuilder
      .create("", "src/main/scala/Other.scala")
      .setLanguage("scala")
      .setLines(10)
      .setType(InputFile.Type.MAIN)
      .build()
    val issue: Issue = Issue(
      RuleKey.of("repo", "rule"),
      file,
      10,
      Severity.MINOR,
      "message"
    )

    val expected: Markdown =
      Markdown(
        "![minor](https://static.sonar-scala.com/img/severity-minor.svg 'Severity: minor') message " +
        "([more](https://test.com/coding_rules?open=repo%3Arule&rule_key=repo%3Arule))"
      )

    Markdown.inline(uri, issue) shouldBe expected
  }
} 
Example 53
Source File: Generators.scala    From sonar-scala   with GNU Lesser General Public License v3.0 5 votes vote down vote up
package com.mwz.sonar.scala.pr

import com.mwz.sonar.scala.pr.github.File
import org.http4s.Uri
import org.scalacheck._
import org.sonar.api.batch.fs.InputFile
import org.sonar.api.batch.fs.internal.TestInputFileBuilder
import org.sonar.api.rule.RuleKey

object Generators {
  implicit val arbInputFile: Arbitrary[InputFile] =
    Arbitrary(
      Gen
        .nonEmptyListOf(Gen.alphaNumChar)
        .map { s =>
          TestInputFileBuilder
            .create("", s"${s.mkString}.scala")
            .build()
        }
    )

  implicit val arbFile: Arbitrary[File] = {
    Arbitrary(
      for {
        fileName <- Gen.nonEmptyListOf(Gen.alphaNumChar)
        status   <- Gen.alphaLowerStr
        patch    <- Gen.alphaNumStr
      } yield File(fileName.mkString, status, patch)
    )
  }

  implicit val arbRuleKey: Arbitrary[RuleKey] =
    Arbitrary(
      for {
        repo <- Gen.nonEmptyListOf(Gen.alphaNumChar)
        rule <- Gen.nonEmptyListOf(Gen.alphaNumChar)
      } yield RuleKey.of(repo.mkString, rule.mkString)
    )

  implicit val arbUri: Arbitrary[Uri] =
    Arbitrary(
      Gen.nonEmptyListOf(Gen.alphaLowerChar).map(s => Uri.unsafeFromString(s.mkString))
    )
} 
Example 54
Source File: model.scala    From sonar-scala   with GNU Lesser General Public License v3.0 5 votes vote down vote up
package com.mwz.sonar.scala
package pr

import org.http4s.Uri

@SuppressWarnings(Array("IncorrectlyNamedExceptions"))
sealed trait ReviewError extends Exception
final case object NoFilesInPR extends ReviewError

sealed trait PrReviewStatus extends Product with Serializable
final case object Pending extends PrReviewStatus
final case object Success extends PrReviewStatus
final case class Error(reviewStatus: ReviewStatus) extends PrReviewStatus
final case class Failure(error: Throwable) extends PrReviewStatus

final case class ReviewStatus(blocker: Int, critical: Int)
object ReviewStatus {

  
  def inline(baseUrl: Uri, issue: Issue): Markdown = {
    val severity: String = issue.severity.name.toLowerCase
    val img: String = s"https://static.sonar-scala.com/img/severity-${severity}.svg"
    val ruleUri: Uri =
      (baseUrl / "coding_rules")
        .withQueryParam("open", issue.key.toString)
        .withQueryParam("rule_key", issue.key.toString)
    Markdown(s"![$severity]($img 'Severity: $severity') ${issue.message} ([more]($ruleUri))")
  }
} 
Example 55
Source File: Github.scala    From sonar-scala   with GNU Lesser General Public License v3.0 5 votes vote down vote up
package com.mwz.sonar.scala
package pr
package github

import cats.effect.Sync
import cats.syntax.flatMap._
import com.mwz.sonar.scala.pr.github.Codec._
import io.circe.generic.auto._
import mouse.boolean._
import org.http4s.client.Client
import org.http4s.{Header, Headers, Method, Request, Uri}

trait Github[F[_]] {
  def authenticatedUser: F[User]
  def pullRequest: F[PullRequest]
  def comments: F[List[Comment]]
  def createComment(comment: NewComment): F[Unit]
  def files: F[List[File]]
  def createStatus(sha: String, status: NewStatus): F[Unit]
}

object Github {
  def apply[F[_]: Sync](client: Client[F], pr: GlobalConfig.PullRequest): Github[F] =
    new Github[F] {
      val auth: Header = Header("Authorization", s"token ${pr.github.oauth}")
      val userUri: Uri = pr.github.apiuri / "user"
      val prUri: Uri =
        (pr.github.apiuri / "repos").addPath(pr.github.repository) / "pulls" / pr.prNumber
      val commentsUri: Uri = prUri / "comments"
      val filesUri: Uri = prUri / "files"
      def newStatusUri(sha: String): Uri =
        (pr.github.apiuri / "repos").addPath(pr.github.repository) / "statuses" / sha
      def request(uri: Uri): Request[F] = {
        Request[F](
          uri = uri,
          headers = Headers.of(auth)
        )
      }
      def authenticatedUser: F[User] = client.expect[User](request(userUri))
      def pullRequest: F[PullRequest] = client.expect[PullRequest](request(prUri))
      def comments: F[List[Comment]] = client.expect[List[Comment]](request(commentsUri))
      def createComment(comment: NewComment): F[Unit] = {
        val request: F[Request[F]] = Sync[F].pure(
          Request(Method.POST, commentsUri, headers = Headers.of(auth))
            .withEntity(comment)
        )
        pr.dryRun.fold(Sync[F].unit, client.expect[Comment](request) >> Sync[F].unit)
      }
      def files: F[List[File]] = client.expect[List[File]](request(filesUri))
      def createStatus(sha: String, status: NewStatus): F[Unit] = {
        val request: F[Request[F]] = Sync[F].pure(
          Request(Method.POST, newStatusUri(sha), headers = Headers.of(auth))
            .withEntity(status)
        )
        pr.dryRun.fold(Sync[F].unit, client.expect[Status](request) >> Sync[F].unit)
      }
    }
} 
Example 56
Source File: GlobalConfig.scala    From sonar-scala   with GNU Lesser General Public License v3.0 5 votes vote down vote up
package com.mwz.sonar.scala

import cats.data.EitherT
import cats.instances.option._
import cats.instances.string._
import cats.syntax.alternative._
import cats.syntax.either._
import cats.syntax.eq._
import cats.syntax.functor._
import com.mwz.sonar.scala.GlobalConfig._
import com.mwz.sonar.scala.util.syntax.Optionals._
import com.mwz.sonar.scala.util.syntax.SonarConfig._
import org.http4s.{ParseFailure, ParseResult, Uri}
import org.sonar.api.CoreProperties
import org.sonar.api.batch.{InstantiationStrategy, ScannerSide}
import org.sonar.api.config.Configuration

@SuppressWarnings(Array("IncorrectlyNamedExceptions"))
final case class ConfigError(error: String) extends Exception

// TODO: Both @ScannerSide and @InstantiationStrategy are deprecated, we should switch
//  to the org.sonar.api.scanner.ScannerSide in the future.
@ScannerSide
@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
final class GlobalConfig(config: Configuration) {

  val baseUrl: ConfigErrorOr[Uri] =
    config
      .get(CoreProperties.SERVER_BASE_URL)
      .toOption
      .orElse(config.get("sonar.host.url").toOption)
      .fold[ParseResult[Uri]](
        Left(
          ParseFailure(
            "Missing SonarQube base URI - please configure the server base URL in your SonarQube instance or set the 'sonar.host.url' property.",
            ""
          )
        )
      )(Uri.fromString)
      .leftMap(f => ConfigError(f.sanitized))

  val pullRequest: EitherT[Option, ConfigError, PullRequest] = getPullRequest

  
  final case class PullRequest(
    provider: String,
    prNumber: String,
    github: Github,
    disableIssues: Boolean,
    disableInlineComments: Boolean,
    disableCoverage: Boolean,
    dryRun: Boolean
  )
  final case class Github(
    apiuri: Uri = DEFAULT_GITHUB_API_URI,
    repository: String,
    oauth: String
  )
} 
Example 57
Source File: Http4sAttributesSpec.scala    From opencensus-scala   with Apache License 2.0 5 votes vote down vote up
package io.opencensus.scala.http4s

import cats.Id
import io.opencensus.scala.http.HttpAttributesSpec
import org.http4s.{Header, Headers, Request, Response, Status, Uri}

class Http4sAttributesSpec extends HttpAttributesSpec {
  import HttpAttributes._

  "Http4s attributes extraction" should behave like httpAttributes(
    request,
    response
  )

  def request: BuildRequest => Request[Id] =
    (request: BuildRequest) =>
      Request[Id](
        uri = Uri.unsafeFromString(request.host ++ request.path),
        headers = Headers(
          List(Header("User-Agent", request.userAgent)) ++ request.hostHeader
            .map(Header("Host", _))
        )
      )

  def response: Int => Response[Id] =
    (code: Int) => Response[Id](Status(code))
} 
Example 58
Source File: MavenCentralClient.scala    From zorechka-bot   with MIT License 5 votes vote down vote up
package com.wix.zorechka.clients

import com.wix.zorechka.Dep
import org.http4s.{EntityDecoder, Header, Headers, Method, Request, Uri}
import zio.{Task, ZIO}
import zio.interop.catz._
import io.circe.generic.auto._
import org.http4s.circe.jsonOf
import org.http4s.client.Client

trait MavenCentralClient {
  val client: MavenCentralClient.Service
}

object MavenCentralClient {
  trait Service {
    def allVersions(dep: Dep): Task[List[Dep]]
  }

  trait Live extends MavenCentralClient {
    protected val httpClient: Client[Task]

    val client = new MavenCentralClient.Service {
      case class Response(response: InnerResponse)
      case class InnerResponse(docs: Seq[Document])
      case class Document(v: String)

      implicit val decoder: EntityDecoder[Task, Response] = jsonOf[Task, Response]

      override def allVersions(dep: Dep): Task[List[Dep]] = {
        ZIO.accessM {
          client =>
            val uri = Uri
              .unsafeFromString("http://search.maven.org/solrsearch/select")
              .withQueryParam("rows", "10")
              .withQueryParam("core", "gav")
              .withQueryParam("q", s""" g:"${dep.groupId}" AND a:"${dep.artifactId}" """)
            println(s"Maven search: ${uri.renderString}")

            val request = Request[Task](Method.GET, uri, headers = Headers.of(Header("Accept", "application/json")))

            httpClient.fetch(request)(response => response.as[Response]).map {
              _.response.docs.map(_.v).map(v => Dep(dep.groupId, dep.artifactId, v)).toList
            }
        }
      }
    }
  }
} 
Example 59
Source File: HmacAuthMiddlewareSpec.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.network.http.server.middleware

import java.time.Instant

import cats.Id
import cats.effect.IO
import cats.implicits._
import jbok.common.CommonSpec
import jbok.network.http.server.authentication.HMAC
import org.http4s.dsl.io._
import org.http4s.headers.Authorization
import org.http4s.implicits._
import org.http4s.{AuthScheme, Credentials, Header, HttpRoutes, Request, Status, Uri}
import scodec.bits.ByteVector
import tsec.mac.jca.{HMACSHA256, MacSigningKey}

import scala.concurrent.duration._

class HmacAuthMiddlewareSpec extends CommonSpec {
  "HmacAuthMiddleware" should {
    val key = HMACSHA256.buildKey[Id](
      ByteVector.fromValidHex("70ea14ac30939a972b5a67cab952d6d7d474727b05fe7f9283abc1e505919e83").toArray
    )

    def sign(url: String): (String, String) = {
      val datetime  = Instant.now().toString
      val signature = HMAC.http.signForHeader("GET", url, datetime, key).unsafeRunSync()
      (signature, datetime)
    }

    val routes = HttpRoutes.of[IO] {
      case GET -> Root / "ping" => Ok("pong")
    }

    val service = routes.orNotFound
    val req     = Request[IO](uri = Uri.uri("/ping"))
    service.run(req).unsafeRunSync().status shouldBe Status.Ok
    val authedService = HmacAuthMiddleware(key)(routes).orNotFound

    "403 if no Authorization header" in {
      val resp = authedService.run(req).unsafeRunSync()
      val text = resp.bodyAsText.compile.foldMonoid.unsafeRunSync()
      resp.status shouldBe Status.Forbidden
      text shouldBe HmacAuthError.NoAuthHeader.message
    }

    "403 if no X-Datetime header" in {
      val signature = HMAC.http.signForHeader("GET", "/ping", Instant.now().toString, key).unsafeRunSync()
      val req =
        Request[IO](uri = Uri.uri("/ping")).putHeaders(Authorization(Credentials.Token(AuthScheme.Bearer, signature)))
      val resp = authedService.run(req).unsafeRunSync()
      val text = resp.bodyAsText.compile.foldMonoid.unsafeRunSync()
      resp.status shouldBe Status.Forbidden
      text shouldBe HmacAuthError.NoDatetimeHeader.message
    }

    "403 if time window is closed" in {
      val authedService = HmacAuthMiddleware(key, 2.seconds)(routes).orNotFound
      val now           = Instant.now()
      val signature     = HMAC.http.signForHeader("GET", "/ping", now.toString, key).unsafeRunSync()
      val req =
        Request[IO](uri = Uri.uri("/ping"))
          .putHeaders(
            Authorization(Credentials.Token(AuthScheme.Bearer, signature)),
            Header("X-Datetime", now.toString)
          )

      val resp = authedService.run(req).unsafeRunSync()
      resp.status shouldBe Status.Ok

      IO.sleep(3.seconds).unsafeRunSync()
      val resp2 = authedService.run(req).unsafeRunSync()
      val text  = resp2.bodyAsText.compile.foldMonoid.unsafeRunSync()
      resp2.status shouldBe Status.Forbidden
      text shouldBe HmacAuthError.Timeout.message
    }

    "helper" in {
      val (sig, date) = sign("/v1/blocks")
      println(("Authorization", s"Bearer $sig"))
      println(("X-Datetime", date))
      println(("Random key", ByteVector(MacSigningKey.toJavaKey[HMACSHA256](HMACSHA256.generateKey[Id]).getEncoded).toHex))
    }
  }
} 
Example 60
Source File: Http4sRpcSpec.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.network.rpc

import cats.effect.IO
import io.circe.Json
import jbok.common.CommonSpec
import jbok.network.rpc.http.{Http4sRpcServer, Http4sRpcTransport}
import org.http4s.Uri
import cats.implicits._
import org.http4s.circe.CirceEntityCodec._
import org.scalatest.Assertion
import jbok.codec.impl.circe._
import io.circe.generic.auto._

class Http4sRpcSpec extends CommonSpec {
  val impl    = new TestApiImpl
  val service = RpcService[IO, Json].mount[TestAPI[IO]](impl)
  val server  = Http4sRpcServer.server[IO](service)

  def transport(uri: Uri) = new Http4sRpcTransport[IO, Json](uri)

  def client(uri: Uri) = RpcClient[IO, Json](transport(uri)).use[TestAPI[IO]]

  def assertIO[A](io1: IO[A], io2: IO[A]): IO[Assertion] =
    (io1, io2).mapN(_ shouldBe _)

  "Http4sRpcService" should {
    "impl service and client" in {
      val p = server.use { s =>
        val c = client(s.baseUri)
        assertIO(c.foo, impl.foo) >>
          assertIO(c.bar, impl.bar) >>
          assertIO(c.qux("oho", 42), impl.qux("oho", 42))
      }
      p.unsafeRunSync()
    }
  }
} 
Example 61
Source File: Http4sBitbucketApiAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.bitbucket.http4s

import cats.effect.Sync
import cats.implicits._
import org.http4s.{Request, Status, Uri}
import org.scalasteward.core.bitbucket.Url
import org.scalasteward.core.bitbucket.http4s.json._
import org.scalasteward.core.git.Branch
import org.scalasteward.core.util.{HttpJsonClient, UnexpectedResponse}
import org.scalasteward.core.vcs.VCSApiAlg
import org.scalasteward.core.vcs.data._

class Http4sBitbucketApiAlg[F[_]: Sync](
    bitbucketApiHost: Uri,
    user: AuthenticatedUser,
    modify: Repo => Request[F] => F[Request[F]],
    doNotFork: Boolean
)(implicit client: HttpJsonClient[F])
    extends VCSApiAlg[F] {
  private val url = new Url(bitbucketApiHost)

  override def createFork(repo: Repo): F[RepoOut] =
    for {
      fork <- client.post[RepositoryResponse](url.forks(repo), modify(repo)).recoverWith {
        case UnexpectedResponse(_, _, _, Status.BadRequest, _) =>
          client.get(url.repo(repo.copy(owner = user.login)), modify(repo))
      }
      maybeParent <-
        fork.parent
          .map(n => client.get[RepositoryResponse](url.repo(n), modify(n)))
          .sequence[F, RepositoryResponse]
    } yield mapToRepoOut(fork, maybeParent)

  private def mapToRepoOut(
      repo: RepositoryResponse,
      maybeParent: Option[RepositoryResponse]
  ): RepoOut =
    RepoOut(
      repo.name,
      repo.owner,
      maybeParent.map(p => mapToRepoOut(p, None)),
      repo.httpsCloneUrl,
      repo.mainBranch
    )

  override def createPullRequest(repo: Repo, data: NewPullRequestData): F[PullRequestOut] = {
    val sourceBranchOwner = if (doNotFork) repo.owner else user.login

    val payload = CreatePullRequestRequest(
      data.title,
      Branch(data.head),
      Repo(sourceBranchOwner, repo.repo),
      data.base,
      data.body
    )
    client.postWithBody(url.pullRequests(repo), payload, modify(repo))
  }

  override def getBranch(repo: Repo, branch: Branch): F[BranchOut] =
    client.get(url.branch(repo, branch), modify(repo))

  override def getRepo(repo: Repo): F[RepoOut] =
    for {
      repo <- client.get[RepositoryResponse](url.repo(repo), modify(repo))
      maybeParent <-
        repo.parent
          .map(n => client.get[RepositoryResponse](url.repo(n), modify(n)))
          .sequence[F, RepositoryResponse]
    } yield mapToRepoOut(repo, maybeParent)

  override def listPullRequests(repo: Repo, head: String, base: Branch): F[List[PullRequestOut]] =
    client
      .get[Page[PullRequestOut]](url.listPullRequests(repo, head), modify(repo))
      .map(_.values)
} 
Example 62
Source File: TestClient.scala    From franklin   with Apache License 2.0 5 votes vote down vote up
package com.azavea.franklin.api

import cats.effect.Resource
import cats.effect.Sync
import cats.implicits._
import com.azavea.franklin.api.services.{CollectionItemsService, CollectionsService}
import com.azavea.stac4s.{StacCollection, StacItem}
import eu.timepit.refined.auto._
import io.circe.syntax._
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.implicits._
import org.http4s.{Method, Request, Uri}

import java.net.URLEncoder
import java.nio.charset.StandardCharsets


class TestClient[F[_]: Sync](
    collectionsService: CollectionsService[F],
    collectionItemsService: CollectionItemsService[F]
) {

  private def createCollection(collection: StacCollection): F[StacCollection] =
    collectionsService.routes.orNotFound.run(
      Request(
        method = Method.POST,
        uri = Uri.unsafeFromString("/collections")
      ).withEntity(collection.asJson)
    ) flatMap { _.as[StacCollection] }

  private def deleteCollection(collection: StacCollection): F[Unit] = {
    val encodedCollectionId = URLEncoder.encode(collection.id, StandardCharsets.UTF_8.toString)
    collectionsService.routes.orNotFound
      .run(
        Request(
          method = Method.DELETE,
          uri = Uri.unsafeFromString(s"/collections/$encodedCollectionId")
        )
      )
      .void
  }

  private def createItemInCollection(collection: StacCollection, item: StacItem): F[StacItem] = {
    val encodedCollectionId = URLEncoder.encode(collection.id, StandardCharsets.UTF_8.toString)
    collectionItemsService.routes.orNotFound.run(
      Request(
        method = Method.POST,
        uri = Uri.unsafeFromString(s"/collections/$encodedCollectionId/items")
      ).withEntity(item)
    ) flatMap { _.as[StacItem] }
  }

  private def deleteItemInCollection(collection: StacCollection, item: StacItem): F[Unit] = {
    val encodedCollectionId = URLEncoder.encode(collection.id, StandardCharsets.UTF_8.toString)
    val encodedItemId       = URLEncoder.encode(item.id, StandardCharsets.UTF_8.toString)
    collectionItemsService.routes.orNotFound
      .run(
        Request(
          method = Method.DELETE,
          uri = Uri.unsafeFromString(s"/collections/$encodedCollectionId/items/$encodedItemId")
        )
      )
      .void
  }

  def getItemResource(collection: StacCollection, item: StacItem): Resource[F, StacItem] =
    Resource.make(createItemInCollection(collection, item.copy(collection = Some(collection.id))))(
      item => deleteItemInCollection(collection, item)
    )

  def getCollectionResource(collection: StacCollection): Resource[F, StacCollection] =
    Resource.make(createCollection(collection))(collection => deleteCollection(collection))

  def getCollectionItemResource(
      item: StacItem,
      collection: StacCollection
  ): Resource[F, (StacItem, StacCollection)] =
    (getItemResource(collection, item), getCollectionResource(collection)).tupled
} 
Example 63
Source File: CollectionsServiceSpec.scala    From franklin   with Apache License 2.0 5 votes vote down vote up
package com.azavea.franklin.api.services

import cats.data.OptionT
import cats.effect.IO
import cats.implicits._
import com.azavea.franklin.Generators
import com.azavea.franklin.api.{TestClient, TestServices}
import com.azavea.franklin.database.TestDatabaseSpec
import com.azavea.franklin.datamodel.CollectionsResponse
import com.azavea.stac4s.StacCollection
import com.azavea.stac4s.testing._
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.{Method, Request, Uri}
import org.specs2.{ScalaCheck, Specification}

import java.net.URLEncoder
import java.nio.charset.StandardCharsets

class CollectionsServiceSpec
    extends Specification
    with ScalaCheck
    with TestDatabaseSpec
    with Generators {
  def is = s2"""
  This specification verifies that the collections service can run without crashing

  The collections service should:
    - create and delete collections $createDeleteCollectionExpectation
    - list collections              $listCollectionsExpectation
    - get collections by id         $getCollectionsExpectation
"""

  val testServices: TestServices[IO] = new TestServices[IO](transactor)

  val testClient: TestClient[IO] =
    new TestClient[IO](testServices.collectionsService, testServices.collectionItemsService)

  def listCollectionsExpectation = prop {
    (stacCollectionA: StacCollection, stacCollectionB: StacCollection) =>
      {
        val listIO = (
          testClient.getCollectionResource(stacCollectionA),
          testClient.getCollectionResource(stacCollectionB)
        ).tupled use { _ =>
          val request = Request[IO](method = Method.GET, Uri.unsafeFromString(s"/collections"))
          (for {
            resp    <- testServices.collectionsService.routes.run(request)
            decoded <- OptionT.liftF { resp.as[CollectionsResponse] }
          } yield decoded).value
        }

        val result = listIO.unsafeRunSync.get.collections map { _.id }

        (result must contain(stacCollectionA.id)) and (result must contain(stacCollectionB.id))
      }
  }

  def getCollectionsExpectation = prop { (stacCollection: StacCollection) =>
    val fetchIO =
      testClient.getCollectionResource(stacCollection) use { collection =>
        val encodedId = URLEncoder.encode(collection.id, StandardCharsets.UTF_8.toString)
        val request =
          Request[IO](method = Method.GET, Uri.unsafeFromString(s"/collections/$encodedId"))
        (for {
          resp    <- testServices.collectionsService.routes.run(request)
          decoded <- OptionT.liftF { resp.as[StacCollection] }
        } yield (decoded, collection)).value
      }

    val (fetched, inserted) = fetchIO.unsafeRunSync.get

    fetched must beTypedEqualTo(inserted)
  }

  // since creation / deletion is a part of the collection resource, and accurate creation is checked
  // in getCollectionsExpectation, this test just makes sure that if other tests are failing, it's
  // not because create/delete are broken
  def createDeleteCollectionExpectation = prop { (stacCollection: StacCollection) =>
    (testClient
      .getCollectionResource(stacCollection) use { _ => IO.unit }).unsafeRunSync must beTypedEqualTo(
      ()
    )
  }

} 
Example 64
Source File: JoexClient.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.joexapi.client

import scala.concurrent.ExecutionContext

import cats.effect._
import cats.implicits._

import docspell.common.syntax.all._
import docspell.common.{Ident, LenientUri}
import docspell.joexapi.model.BasicResult

import org.http4s.circe.CirceEntityDecoder._
import org.http4s.client.Client
import org.http4s.client.blaze.BlazeClientBuilder
import org.http4s.{Method, Request, Uri}
import org.log4s.getLogger

trait JoexClient[F[_]] {

  def notifyJoex(base: LenientUri): F[Unit]

  def notifyJoexIgnoreErrors(base: LenientUri): F[Unit]

  def cancelJob(base: LenientUri, job: Ident): F[BasicResult]

}

object JoexClient {

  private[this] val logger = getLogger

  def apply[F[_]: Sync](client: Client[F]): JoexClient[F] =
    new JoexClient[F] {
      def notifyJoex(base: LenientUri): F[Unit] = {
        val notifyUrl = base / "api" / "v1" / "notify"
        val req       = Request[F](Method.POST, uri(notifyUrl))
        logger.fdebug(s"Notify joex at ${notifyUrl.asString}") *>
          client.expect[String](req).map(_ => ())
      }

      def notifyJoexIgnoreErrors(base: LenientUri): F[Unit] =
        notifyJoex(base).attempt.map {
          case Right(()) => ()
          case Left(ex) =>
            logger.warn(
              s"Notifying Joex instance '${base.asString}' failed: ${ex.getMessage}"
            )
            ()
        }

      def cancelJob(base: LenientUri, job: Ident): F[BasicResult] = {
        val cancelUrl = base / "api" / "v1" / "job" / job.id / "cancel"
        val req       = Request[F](Method.POST, uri(cancelUrl))
        client.expect[BasicResult](req)
      }

      private def uri(u: LenientUri): Uri =
        Uri.unsafeFromString(u.asString)
    }

  def resource[F[_]: ConcurrentEffect](ec: ExecutionContext): Resource[F, JoexClient[F]] =
    BlazeClientBuilder[F](ec).resource.map(apply[F])
} 
Example 65
Source File: MockContext.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.mock

import better.files.File
import cats.Parallel
import cats.effect.Sync
import org.http4s.Uri
import org.scalasteward.core.TestInstances.ioContextShift
import org.scalasteward.core.application.Cli.EnvVar
import org.scalasteward.core.application.{Config, SupportedVCS}
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.{Author, GitAlg}
import org.scalasteward.core.io.{MockFileAlg, MockProcessAlg, MockWorkspaceAlg}
import org.scalasteward.core.nurture.PullRequestRepository
import org.scalasteward.core.persistence.JsonKeyValueStore
import org.scalasteward.core.repocache.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.uri._
import org.scalasteward.core.util.{BracketThrowable, DateTimeAlg}
import org.scalasteward.core.vcs.VCSRepoAlg
import org.scalasteward.core.vcs.data.AuthenticatedUser

import scala.concurrent.duration._

object MockContext {
  implicit val config: Config = Config(
    workspace = File.temp / "ws",
    reposFile = File.temp / "repos.md",
    defaultRepoConfigFile = Some(File.temp / "default.scala-steward.conf"),
    gitAuthor = Author("Bot Doe", "[email protected]"),
    vcsType = SupportedVCS.GitHub,
    vcsApiHost = Uri(),
    vcsLogin = "bot-doe",
    gitAskPass = File.temp / "askpass.sh",
    signCommits = false,
    whitelistedDirectories = Nil,
    readOnlyDirectories = Nil,
    disableSandbox = false,
    doNotFork = false,
    ignoreOptsFiles = false,
    envVars = List(
      EnvVar("TEST_VAR", "GREAT"),
      EnvVar("ANOTHER_TEST_VAR", "ALSO_GREAT")
    ),
    processTimeout = 10.minutes,
    scalafixMigrations = None,
    groupMigrations = None,
    cacheTtl = 1.hour,
    cacheMissDelay = 0.milliseconds,
    bitbucketServerUseDefaultReviewers = false
  )

  implicit val mockEffBracketThrowable: BracketThrowable[MockEff] = Sync[MockEff]
  implicit val mockEffParallel: Parallel[MockEff] = Parallel.identity

  implicit val fileAlg: MockFileAlg = new MockFileAlg
  implicit val mockLogger: MockLogger = new MockLogger
  implicit val processAlg: MockProcessAlg = new MockProcessAlg
  implicit val workspaceAlg: MockWorkspaceAlg = new MockWorkspaceAlg

  implicit val coursierAlg: CoursierAlg[MockEff] = CoursierAlg.create
  implicit val dateTimeAlg: DateTimeAlg[MockEff] = DateTimeAlg.create
  implicit val gitAlg: GitAlg[MockEff] = GitAlg.create
  implicit val user: AuthenticatedUser = AuthenticatedUser("scala-steward", "token")
  implicit val vcsRepoAlg: VCSRepoAlg[MockEff] = VCSRepoAlg.create(config, gitAlg)
  implicit val scalafmtAlg: ScalafmtAlg[MockEff] = ScalafmtAlg.create
  implicit val migrationAlg: MigrationAlg =
    MigrationAlg.create[MockEff](config.scalafixMigrations).runA(MockState.empty).unsafeRunSync()
  implicit val cacheRepository: RepoCacheRepository[MockEff] =
    new RepoCacheRepository[MockEff](new JsonKeyValueStore("repo_cache", "1"))
  implicit val filterAlg: FilterAlg[MockEff] = new FilterAlg[MockEff]
  implicit val versionsCache: VersionsCache[MockEff] =
    new VersionsCache[MockEff](config.cacheTtl, new JsonKeyValueStore("versions", "1"))
  implicit val groupMigrations: GroupMigrations =
    GroupMigrations.create[MockEff].runA(MockState.empty).unsafeRunSync()
  implicit val updateAlg: UpdateAlg[MockEff] = new UpdateAlg[MockEff]
  implicit val mavenAlg: MavenAlg[MockEff] = MavenAlg.create
  implicit val sbtAlg: SbtAlg[MockEff] = SbtAlg.create
  implicit val millAlg: MillAlg[MockEff] = MillAlg.create
  implicit val buildToolDispatcher: BuildToolDispatcher[MockEff] = BuildToolDispatcher.create
  implicit val editAlg: EditAlg[MockEff] = new EditAlg[MockEff]
  implicit val repoConfigAlg: RepoConfigAlg[MockEff] = new RepoConfigAlg[MockEff]
  implicit val pullRequestRepository: PullRequestRepository[MockEff] =
    new PullRequestRepository[MockEff](new JsonKeyValueStore("pull_requests", "1"))
  implicit val pruningAlg: PruningAlg[MockEff] = new PruningAlg[MockEff]
} 
Example 66
Source File: uri.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.util

import cats.implicits._
import io.circe.{Decoder, KeyDecoder, KeyEncoder}
import monocle.Optional
import org.http4s.Uri
import org.http4s.Uri.{Authority, UserInfo}

object uri {
  implicit val uriDecoder: Decoder[Uri] =
    Decoder[String].emap(s => Uri.fromString(s).leftMap(_.getMessage))

  implicit val uriKeyDecoder: KeyDecoder[Uri] =
    KeyDecoder.instance(Uri.fromString(_).toOption)

  implicit val uriKeyEncoder: KeyEncoder[Uri] =
    KeyEncoder.instance(_.renderString)

  val withAuthority: Optional[Uri, Authority] =
    Optional[Uri, Authority](_.authority)(authority => _.copy(authority = Some(authority)))

  val authorityWithUserInfo: Optional[Authority, UserInfo] =
    Optional[Authority, UserInfo](_.userInfo)(userInfo => _.copy(userInfo = Some(userInfo)))

  val withUserInfo: Optional[Uri, UserInfo] =
    authorityWithUserInfo.compose(withAuthority)
} 
Example 67
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 68
Source File: Url.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.bitbucket

import org.http4s.Uri
import org.scalasteward.core.git.Branch
import org.scalasteward.core.vcs.data.Repo

private[bitbucket] class Url(apiHost: Uri) {
  def forks(rep: Repo): Uri =
    repo(rep) / "forks"

  def listPullRequests(rep: Repo, head: String): Uri =
    pullRequests(rep).withQueryParam("q", s"""source.branch.name = "$head" """)

  def pullRequests(rep: Repo): Uri =
    repo(rep) / "pullrequests"

  def branch(rep: Repo, branch: Branch): Uri =
    repo(rep) / "refs" / "branches" / branch.name

  def repo(repo: Repo): Uri =
    apiHost / "repositories" / repo.owner / repo.repo
} 
Example 69
Source File: json.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.bitbucket.http4s

import io.circe.Decoder
import org.http4s.Uri
import org.scalasteward.core.git.{Branch, Sha1}
import org.scalasteward.core.util.uri.uriDecoder
import org.scalasteward.core.vcs.data.{BranchOut, CommitOut, PullRequestOut, PullRequestState}

private[http4s] object json {
  implicit val branchOutDecoder: Decoder[BranchOut] = Decoder.instance { c =>
    for {
      branch <- c.downField("name").as[Branch]
      commitHash <- c.downField("target").downField("hash").as[Sha1]
    } yield BranchOut(branch, CommitOut(commitHash))
  }

  implicit val pullRequestStateDecoder: Decoder[PullRequestState] =
    Decoder[String].emap {
      case "OPEN"                               => Right(PullRequestState.Open)
      case "MERGED" | "SUPERSEDED" | "DECLINED" => Right(PullRequestState.Closed)
      case unknown                              => Left(s"Unexpected string '$unknown'")
    }

  implicit val pullRequestOutDecoder: Decoder[PullRequestOut] = Decoder.instance { c =>
    for {
      title <- c.downField("title").as[String]
      state <- c.downField("state").as[PullRequestState]
      html_url <- c.downField("links").downField("self").downField("href").as[Uri]
    } yield (PullRequestOut(html_url, state, title))
  }
} 
Example 70
Source File: RepositoryResponse.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.bitbucket.http4s

import cats.implicits._
import io.circe.{ACursor, Decoder, DecodingFailure, Json}
import org.http4s.Uri
import org.scalasteward.core.git.Branch
import org.scalasteward.core.util.uri._
import org.scalasteward.core.vcs.data.{Repo, UserOut}
import scala.annotation.tailrec

final private[http4s] case class RepositoryResponse(
    name: String,
    mainBranch: Branch,
    owner: UserOut,
    httpsCloneUrl: Uri,
    parent: Option[Repo]
)

private[http4s] object RepositoryResponse {
  implicit private val repoDecoder: Decoder[Repo] = Decoder.instance { c =>
    c.as[String].map(_.split('/')).flatMap { parts =>
      parts match {
        case Array(owner, name) => Repo(owner, name).asRight
        case _                  => DecodingFailure("Repo", c.history).asLeft
      }
    }
  }

  implicit val decoder: Decoder[RepositoryResponse] = Decoder.instance { c =>
    for {
      name <- c.downField("name").as[String]
      owner <-
        c.downField("owner")
          .downField("username")
          .as[String]
          .orElse(c.downField("owner").downField("nickname").as[String])
      cloneUrl <-
        c.downField("links")
          .downField("clone")
          .downAt { p =>
            p.asObject
              .flatMap(o => o("name"))
              .flatMap(_.asString)
              .contains("https")
          }
          .downField("href")
          .as[Uri]
      defaultBranch <- c.downField("mainbranch").downField("name").as[Branch]
      maybeParent <- c.downField("parent").downField("full_name").as[Option[Repo]]
    } yield RepositoryResponse(name, defaultBranch, UserOut(owner), cloneUrl, maybeParent)
  }

  
    def downAt(p: Json => Boolean): ACursor = {
      @tailrec
      def find(c: ACursor): ACursor =
        if (c.succeeded)
          if (c.focus.exists(p)) c else find(c.right)
        else c

      find(cursor.downArray)
    }
  }
} 
Example 71
Source File: Http4sRpcTransport.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.network.rpc.http

import cats.effect.ConcurrentEffect
import jbok.network.rpc.{RpcRequest, RpcResponse, RpcTransport}
import org.http4s.client.blaze.BlazeClientBuilder
import org.http4s.{EntityDecoder, EntityEncoder, Method, Request, Uri}

import scala.concurrent.ExecutionContext

final class Http4sRpcTransport[F[_], P](
    baseUri: Uri
)(implicit F: ConcurrentEffect[F], entityEncoder: EntityEncoder[F, P], entityDecoder: EntityDecoder[F, RpcResponse[P]])
    extends RpcTransport[F, P] {

  override def fetch(request: RpcRequest[P]): F[RpcResponse[P]] = {
    val uri = request.path.foldLeft(baseUri)(_ / _)

    val req = Request[F](Method.POST, uri = uri).withEntity(request.payload)

    BlazeClientBuilder[F](ExecutionContext.global).resource.use { client =>
      client.fetchAs[RpcResponse[P]](req)
    }
  }
} 
Example 72
Source File: PullRequestRepository.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.nurture

import cats.Monad
import cats.implicits._
import org.http4s.Uri
import org.scalasteward.core.data.{CrossDependency, Update}
import org.scalasteward.core.git.Sha1
import org.scalasteward.core.persistence.KeyValueStore
import org.scalasteward.core.update.UpdateAlg
import org.scalasteward.core.util.{DateTimeAlg, Timestamp}
import org.scalasteward.core.vcs.data.{PullRequestState, Repo}

final class PullRequestRepository[F[_]](
    kvStore: KeyValueStore[F, Repo, Map[Uri, PullRequestData]]
)(implicit
    dateTimeAlg: DateTimeAlg[F],
    F: Monad[F]
) {
  def createOrUpdate(
      repo: Repo,
      url: Uri,
      baseSha1: Sha1,
      update: Update,
      state: PullRequestState
  ): F[Unit] =
    kvStore
      .modifyF(repo) { maybePullRequests =>
        val pullRequests = maybePullRequests.getOrElse(Map.empty)
        pullRequests.get(url) match {
          case Some(found) =>
            val data = found.copy(baseSha1, update, state)
            pullRequests.updated(url, data).some.pure[F]
          case None =>
            dateTimeAlg.currentTimestamp.map { now =>
              val data = PullRequestData(baseSha1, update, state, now)
              pullRequests.updated(url, data).some
            }
        }
      }
      .void

  def findPullRequest(
      repo: Repo,
      crossDependency: CrossDependency,
      newVersion: String
  ): F[Option[(Uri, Sha1, PullRequestState)]] =
    kvStore.get(repo).map {
      _.getOrElse(Map.empty).collectFirst {
        case (url, data)
            if UpdateAlg.isUpdateFor(data.update, crossDependency) &&
              data.update.nextVersion === newVersion =>
          (url, data.baseSha1, data.state)
      }
    }

  def lastPullRequestCreatedAt(repo: Repo): F[Option[Timestamp]] =
    kvStore.get(repo).map(_.flatMap(_.values.map(_.entryCreatedAt).maxOption))
} 
Example 73
Source File: package.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core

import cats.implicits._
import org.http4s.Uri
import org.scalasteward.core.application.SupportedVCS
import org.scalasteward.core.application.SupportedVCS.{Bitbucket, BitbucketServer, GitHub, Gitlab}
import org.scalasteward.core.data.ReleaseRelatedUrl.VersionDiff
import org.scalasteward.core.data.{ReleaseRelatedUrl, Update}
import org.scalasteward.core.vcs.data.Repo

package object vcs {

  
  def createBranch(vcsType: SupportedVCS, fork: Repo, update: Update): String =
    vcsType match {
      case GitHub =>
        s"${fork.owner}:${git.branchFor(update).name}"

      case Gitlab | Bitbucket | BitbucketServer =>
        git.branchFor(update).name
    }

  def possibleTags(version: String): List[String] =
    List(s"v$version", version, s"release-$version")

  val possibleChangelogFilenames: List[String] = {
    val baseNames = List(
      "CHANGELOG",
      "Changelog",
      "changelog",
      "CHANGES"
    )
    possibleFilenames(baseNames)
  }

  val possibleReleaseNotesFilenames: List[String] = {
    val baseNames = List(
      "ReleaseNotes",
      "RELEASES",
      "Releases",
      "releases"
    )
    possibleFilenames(baseNames)
  }

  def possibleCompareUrls(repoUrl: Uri, update: Update): List[VersionDiff] = {
    val host = repoUrl.host.map(_.value)
    val from = update.currentVersion
    val to = update.nextVersion

    if (host.exists(Set("github.com", "gitlab.com")))
      possibleTags(from).zip(possibleTags(to)).map {
        case (from1, to1) => VersionDiff(repoUrl / "compare" / s"$from1...$to1")
      }
    else if (host.contains_("bitbucket.org"))
      possibleTags(from).zip(possibleTags(to)).map {
        case (from1, to1) =>
          VersionDiff((repoUrl / "compare" / s"$to1..$from1").withFragment("diff"))
      }
    else
      List.empty
  }

  def possibleReleaseRelatedUrls(repoUrl: Uri, update: Update): List[ReleaseRelatedUrl] = {
    val host = repoUrl.host.map(_.value)
    val github =
      if (host.contains_("github.com"))
        possibleTags(update.nextVersion).map(tag =>
          ReleaseRelatedUrl.GitHubReleaseNotes(repoUrl / "releases" / "tag" / tag)
        )
      else
        List.empty
    def files(fileNames: List[String]): List[Uri] = {
      val maybeSegments =
        if (host.exists(Set("github.com", "gitlab.com")))
          Some(List("blob", "master"))
        else if (host.contains_("bitbucket.org"))
          Some(List("master"))
        else
          None
      maybeSegments.toList.flatMap { segments =>
        val base = segments.foldLeft(repoUrl)(_ / _)
        fileNames.map(name => base / name)
      }
    }
    val customChangelog = files(possibleChangelogFilenames).map(ReleaseRelatedUrl.CustomChangelog)
    val customReleaseNotes =
      files(possibleReleaseNotesFilenames).map(ReleaseRelatedUrl.CustomReleaseNotes)

    github ++ customReleaseNotes ++ customChangelog ++ possibleCompareUrls(repoUrl, update)
  }

  private def possibleFilenames(baseNames: List[String]): List[String] = {
    val extensions = List("md", "markdown", "rst")
    (baseNames, extensions).mapN { case (base, ext) => s"$base.$ext" }
  }
} 
Example 74
Source File: VCSExtraAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.vcs

import cats.Monad
import cats.implicits._
import org.http4s.Uri
import org.scalasteward.core.data.{ReleaseRelatedUrl, Update}
import org.scalasteward.core.util.HttpExistenceClient
import org.scalasteward.core.vcs

trait VCSExtraAlg[F[_]] {
  def getReleaseRelatedUrls(repoUrl: Uri, update: Update): F[List[ReleaseRelatedUrl]]
}

object VCSExtraAlg {
  def create[F[_]](implicit
      existenceClient: HttpExistenceClient[F],
      F: Monad[F]
  ): VCSExtraAlg[F] =
    new VCSExtraAlg[F] {
      override def getReleaseRelatedUrls(repoUrl: Uri, update: Update): F[List[ReleaseRelatedUrl]] =
        vcs
          .possibleReleaseRelatedUrls(repoUrl, update)
          .filterA(releaseRelatedUrl => existenceClient.exists(releaseRelatedUrl.url))

    }
} 
Example 75
Source File: VCSRepoAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.vcs

import cats.implicits._
import org.http4s.Uri
import org.http4s.Uri.UserInfo
import org.scalasteward.core.application.Config
import org.scalasteward.core.git.{Branch, GitAlg}
import org.scalasteward.core.util
import org.scalasteward.core.util.MonadThrowable
import org.scalasteward.core.vcs.data.{Repo, RepoOut}

trait VCSRepoAlg[F[_]] {
  def clone(repo: Repo, repoOut: RepoOut): F[Unit]

  def defaultBranch(repoOut: RepoOut): F[Branch]

  def syncFork(repo: Repo, repoOut: RepoOut): F[Unit]
}

object VCSRepoAlg {
  def create[F[_]: MonadThrowable](config: Config, gitAlg: GitAlg[F]): VCSRepoAlg[F] =
    new VCSRepoAlg[F] {
      override def clone(repo: Repo, repoOut: RepoOut): F[Unit] =
        for {
          _ <- gitAlg.clone(repo, withLogin(repoOut.clone_url))
          _ <- gitAlg.setAuthor(repo, config.gitAuthor)
        } yield ()

      override def defaultBranch(repoOut: RepoOut): F[Branch] =
        if (config.doNotFork) repoOut.default_branch.pure[F]
        else repoOut.parentOrRaise[F].map(_.default_branch)

      override def syncFork(repo: Repo, repoOut: RepoOut): F[Unit] =
        if (config.doNotFork) ().pure[F]
        else
          for {
            parent <- repoOut.parentOrRaise[F]
            _ <- gitAlg.syncFork(repo, withLogin(parent.clone_url), parent.default_branch)
          } yield ()

      val withLogin: Uri => Uri =
        util.uri.withUserInfo.set(UserInfo(config.vcsLogin, None))
    }
} 
Example 76
Source File: RepoOut.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.vcs.data

import io.circe.Decoder
import io.circe.generic.semiauto._
import org.http4s.Uri
import org.scalasteward.core.git.Branch
import org.scalasteward.core.util.ApplicativeThrowable
import org.scalasteward.core.util.uri.uriDecoder

final case class RepoOut(
    name: String,
    owner: UserOut,
    parent: Option[RepoOut],
    clone_url: Uri,
    default_branch: Branch
) {
  def parentOrRaise[F[_]](implicit F: ApplicativeThrowable[F]): F[RepoOut] =
    parent.fold(F.raiseError[RepoOut](new Throwable(s"repo $name has no parent")))(F.pure)

  def repo: Repo =
    Repo(owner.login, name)
}

object RepoOut {
  implicit val repoOutDecoder: Decoder[RepoOut] =
    deriveDecoder

  // prevent IntelliJ from removing the import of uriDecoder
  locally(uriDecoder)
} 
Example 77
Source File: PullRequestOut.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.vcs.data

import cats.implicits._
import io.circe.Decoder
import io.circe.generic.semiauto._
import org.http4s.Uri
import org.scalasteward.core.util.uri.uriDecoder
import org.scalasteward.core.vcs.data.PullRequestState.Closed

final case class PullRequestOut(
    html_url: Uri,
    state: PullRequestState,
    title: String
) {
  def isClosed: Boolean =
    state === Closed
}

object PullRequestOut {
  implicit val pullRequestOutDecoder: Decoder[PullRequestOut] =
    deriveDecoder

  // prevent IntelliJ from removing the import of uriDecoder
  locally(uriDecoder)
} 
Example 78
Source File: UpdateState.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.update.data

import org.http4s.Uri
import org.scalasteward.core.data.{CrossDependency, Update}

sealed trait UpdateState extends Product with Serializable {
  def crossDependency: CrossDependency
}

object UpdateState {
  final case class DependencyUpToDate(
      crossDependency: CrossDependency
  ) extends UpdateState

  final case class DependencyOutdated(
      crossDependency: CrossDependency,
      update: Update.Single
  ) extends UpdateState

  final case class PullRequestUpToDate(
      crossDependency: CrossDependency,
      update: Update.Single,
      pullRequest: Uri
  ) extends UpdateState

  final case class PullRequestOutdated(
      crossDependency: CrossDependency,
      update: Update.Single,
      pullRequest: Uri
  ) extends UpdateState

  final case class PullRequestClosed(
      crossDependency: CrossDependency,
      update: Update.Single,
      pullRequest: Uri
  ) extends UpdateState

  def show(updateState: UpdateState): String = {
    val groupId = updateState.crossDependency.head.groupId
    val artifacts = updateState.crossDependency.showArtifactNames
    val version = updateState.crossDependency.head.version
    val gav = s"$groupId:$artifacts : $version"
    updateState match {
      case DependencyUpToDate(_) =>
        s"up-to-date: $gav"
      case DependencyOutdated(_, update) =>
        s"new version: $gav -> ${update.newerVersions.head}"
      case PullRequestUpToDate(_, update, pullRequest) =>
        s"PR opened: $gav -> ${update.newerVersions.head} ($pullRequest)"
      case PullRequestOutdated(_, update, pullRequest) =>
        s"PR outdated: $gav -> ${update.newerVersions.head} ($pullRequest)"
      case PullRequestClosed(_, update, pullRequest) =>
        s"PR closed: $gav -> ${update.newerVersions.head} ($pullRequest)"
    }
  }
} 
Example 79
Source File: Url.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.gitlab

import org.http4s.Uri
import org.scalasteward.core.git.Branch
import org.scalasteward.core.vcs.data.Repo

class Url(apiHost: Uri) {
  def encodedProjectId(repo: Repo): String = s"${repo.owner}%2F${repo.repo}"

  def getBranch(repo: Repo, branch: Branch): Uri =
    repos(repo) / "repository" / "branches" / branch.name

  def createFork(repo: Repo): Uri =
    repos(repo) / "fork"

  def forks(repo: Repo): Uri =
    repos(repo) / "forks"

  def mergeRequest(repo: Repo): Uri =
    repos(repo) / "merge_requests"

  def listMergeRequests(repo: Repo, source: String, target: String): Uri =
    mergeRequest(repo)
      .withQueryParam("source_branch", source)
      .withQueryParam("target_branch", target)

  def repos(repo: Repo): Uri =
    apiHost / "projects" / s"${repo.owner}/${repo.repo}"
}