Skip to content

Commit

Permalink
Merge pull request #15 from commercetools/site/bootstrap
Browse files Browse the repository at this point in the history
Bootstrap website
  • Loading branch information
satabin authored Apr 30, 2024
2 parents 0d4db6a + c5242a1 commit 6fa84ff
Show file tree
Hide file tree
Showing 32 changed files with 715 additions and 194 deletions.
54 changes: 52 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ jobs:

- name: Make target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: mkdir -p project/target
run: mkdir -p unidocs/target project/target

- name: Compress target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: tar cf targets.tar project/target
run: tar cf targets.tar unidocs/target project/target

- name: Upload target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
Expand Down Expand Up @@ -160,3 +160,53 @@ jobs:
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
SONATYPE_CREDENTIAL_HOST: ${{ secrets.SONATYPE_CREDENTIAL_HOST }}
run: sbt tlCiRelease

site:
name: Generate Site
strategy:
matrix:
os: [ubuntu-latest]
java: [temurin@11]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout current branch (full)
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Java (temurin@8)
id: setup-java-temurin-8
if: matrix.java == 'temurin@8'
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 8
cache: sbt

- name: sbt update
if: matrix.java == 'temurin@8' && steps.setup-java-temurin-8.outputs.cache-hit == 'false'
run: sbt +update

- name: Setup Java (temurin@11)
id: setup-java-temurin-11
if: matrix.java == 'temurin@11'
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 11
cache: sbt

- name: sbt update
if: matrix.java == 'temurin@11' && steps.setup-java-temurin-11.outputs.cache-hit == 'false'
run: sbt +update

- name: Generate site
run: sbt docs/tlSite

- name: Publish site
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
uses: peaceiris/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: site/target/docs/site
keep_files: true
2 changes: 1 addition & 1 deletion CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ Everyone is expected to follow the [Scala Code of Conduct] when discussing the p

If you have any questions, concerns, or moderation requests, please contact a member of the project.

- [Lucas Satabin](mailto:lucas.satabin@commercetools.com)
- [Commercetools Open-Source](mailto:opensource@commercetools.com)

[Scala Code of Conduct]: https://scala-lang.org/conduct/
12 changes: 6 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing to `cloud-queues`
# Contributing to `fs2-queues`

There a several ways you can contribute to `cloud-queues`:
There a several ways you can contribute to `fs2-queues`:
- You found a bug? You can [open an issue][open-issue].
- If you have an idea, found something missing, or just a question, you can also [open an issue][open-issue].
- Code contributions are also welcome, you can [open a pull request][open-pr].
Expand Down Expand Up @@ -28,7 +28,7 @@ $ sbt readme/mdoc

## Code formatting

`cloud-queues` uses [scalafmt][scalafmt] to format its code and defines some [scalafix][scalafix] rules. Before submitting code contribution, be sure to have proper formatting by running
`fs2-queues` uses [scalafmt][scalafmt] to format its code and defines some [scalafix][scalafix] rules. Before submitting code contribution, be sure to have proper formatting by running

```shell
$ sbt prePR
Expand All @@ -38,10 +38,10 @@ and check the result.

## Licensing

`cloud-queues` is licensed under the Apache Software License 2.0. Opening a pull request is to be considered affirmative consent to incorporate your changes into the project, granting an unrestricted license to the Commercetools GmbH to distribute and derive new work from your changes, as per the contribution terms of ASL 2.0. You also affirm that you own the rights to the code you are contributing. All contributors retain the copyright to their own work.
`fs2-queues` is licensed under the Apache Software License 2.0. Opening a pull request is to be considered affirmative consent to incorporate your changes into the project, granting an unrestricted license to the Commercetools GmbH to distribute and derive new work from your changes, as per the contribution terms of ASL 2.0. You also affirm that you own the rights to the code you are contributing. All contributors retain the copyright to their own work.

[open-issue]: https://github.com/commercetools/cloud-queues/issues/new/choose
[open-pr]: https://github.com/commercetools/cloud-queues/pull/new/main
[open-issue]: https://github.com/commercetools/fs2-queues/issues/new/choose
[open-pr]: https://github.com/commercetools/fs2-queues/pull/new/main
[scalafmt]: https://scalameta.org/scalafmt/
[scalafix]: https://scalacenter.github.io/scalafix/
[mdoc]: https://scalameta.org/mdoc/
4 changes: 2 additions & 2 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
cloud-queues
Copyright 2023 Commercetools GmbH
fs2-queues
Copyright 2024 Commercetools GmbH
Licensed under Apache License 2.0 (see LICENSE)
88 changes: 10 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,84 +1,16 @@
# Common Cloud Client Tools
[![Continuous Integration](https://github.com/commercetools/fs2-queues/actions/workflows/ci.yml/badge.svg)](https://github.com/commercetools/fs2-queues/actions/workflows/ci.yml)

Aims at providing a unified way of working with cloud queues (SQS, PubSub, Service Bus, ...) across all CT scala services.
Aims at providing a unified way of working with cloud queues (SQS, PubSub, Service Bus, ...).

## Common queue interface
All the abstractions are defined in the [`core`](core/) module. Other modules implement the abstraction for various queue systems and integration with other libraries.

The library offers both low and high level possibilities, making it possible to have fine grained control over queue pulling, or just focusing on processing, delegating message management to the library.
For more documentation, head over to the [documentation website](https://commercetools.github.io/fs2-queues).

The design of the API is the result of the common usage patterns at CT and how the various client SDKs are designed.
There are several views possible on a queue:
- as a `QueuePublisher` when you only need to publish messages to an existing queue.
- as a `QueueSubscriber` when you only need to subscribe to an existing queue.
- as a `QueueAdministration` when you need to manage queues (creation, deletion, ...).
## Development

The entry point is the `QueueClient` factory for each underlying queue system.

In the examples below, we will use the following publisher and subscriber streams:

```scala
import fs2.Stream
import cats.effect.IO
import cats.effect.std.Random
import scala.concurrent.duration._

import com.commercetools.queue._

def publishStream(publisher: QueuePublisher[IO, String]): Stream[IO, Nothing] =
Stream.eval(Random.scalaUtilRandom[IO]).flatMap { random =>
Stream
// repeatedly emit a random string of length 10
.repeatEval(random.nextString(10))
// every 100 milliseconds
.metered(100.millis)
// and publish in batch of 10
.through(publisher.sink(batchSize = 10))
}

def subscribeStream(subscriber: QueueSubscriber[IO, String]): Stream[IO, Nothing] =
subscriber
// receives messages in batches of 5,
// waiting max for 20 seconds
// print every received message,
// and ack automatically
.processWithAutoAck(5, 20.seconds)(msg => IO.println(msg.payload))
// results are non important
.drain

def program(client: QueueClient[IO]): IO[Unit] = {
val queueName = "my-queue"
// subscribe and publish concurrently
subscribeStream(client.subscribe[String](queueName))
// concurrently publish messages
.concurrently(publishStream(client.publish[String](queueName)))
.compile
// runs forever
.drain
}
```

## Working with Azure Service Bus queues

```scala
import com.commercetools.queue.azure.servicebus._
import com.azure.identity.DefaultAzureCredentialBuilder

val namespace = "{namespace}.servicebus.windows.net" // your namespace
val credentials = new DefaultAzureCredentialBuilder().build() // however you want to authenticate

ServiceBusClient[IO](namespace, credentials).use(program(_))
```

## Working with AWS SQS


```scala
import com.commercetools.queue.aws.sqs._
import software.amazon.awssdk.regions.Region
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider

val region = Region.US_EAST_1 // your region
val credentials = DefaultCredentialsProvider.create() // however you want to authenticate

SQSClient[IO](region, credentials).use(program(_))
```
Following commands are useful when developing:
- `sbt compile` compiles all the modules.
- `sbt test` runs all the tests.
- `sbt prePR` prepares the current branch before pushing and opening a PR. It ensures various static checks will pass.
- `sbt docs/tlSitePreview` starts a local server with the built documentation site.
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ package com.commercetools.queue.aws.sqs
import cats.effect.Async
import cats.syntax.all._
import com.commercetools.queue.QueueAdministration
import com.commercetools.queue.aws.sqs.makeQueueException
import software.amazon.awssdk.services.sqs.SqsAsyncClient
import software.amazon.awssdk.services.sqs.model.{CreateQueueRequest, DeleteQueueRequest, QueueAttributeName, QueueDoesNotExistException}
import software.amazon.awssdk.services.sqs.model.{CreateQueueRequest, DeleteQueueRequest, QueueAttributeName, QueueDoesNotExistException, SetQueueAttributesRequest}

import scala.concurrent.duration.FiniteDuration
import scala.jdk.CollectionConverters._
Expand All @@ -43,6 +44,25 @@ class SQSAdministration[F[_]](client: SqsAsyncClient, getQueueUrl: String => F[S
}.void
.adaptError(makeQueueException(_, name))

override def update(name: String, messageTTL: Option[FiniteDuration], lockTTL: Option[FiniteDuration]): F[Unit] =
getQueueUrl(name)
.flatMap { queueUrl =>
F.fromCompletableFuture {
F.delay {
client.setQueueAttributes(
SetQueueAttributesRequest
.builder()
.queueUrl(queueUrl)
.attributes(Map(
QueueAttributeName.MESSAGE_RETENTION_PERIOD -> messageTTL.map(_.toSeconds.toString()),
QueueAttributeName.VISIBILITY_TIMEOUT -> lockTTL.map(_.toSeconds.toString())
).flattenOption.asJava)
.build())
}
}.void
}
.adaptError(makeQueueException(_, name))

override def delete(name: String): F[Unit] =
getQueueUrl(name)
.flatMap { queueUrl =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ class ServiceBusAdministration[F[_]](client: ServiceBusAdministrationClient)(imp
.void
.adaptError(makeQueueException(_, name))

override def update(name: String, messageTTL: Option[FiniteDuration], lockTTL: Option[FiniteDuration]): F[Unit] =
F.blocking {
val properties = client.getQueue(name)
messageTTL.foreach(ttl => properties.setDefaultMessageTimeToLive(Duration.ofMillis(ttl.toMillis)))
lockTTL.foreach(ttl => properties.setLockDuration(Duration.ofMillis(ttl.toMillis)))
val _ = client.updateQueue(properties)
}

override def delete(name: String): F[Unit] =
F.blocking(client.deleteQueue(name))
.void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,11 @@ object ServiceBusClient {
}
} yield new ServiceBusClient(clientBuilder, adminBuilder)

def unmanaged[F[_]](
clientBuilder: ServiceBusClientBuilder,
adminBuilder: ServiceBusAdministrationClientBuilder
)(implicit F: Async[F]
): ServiceBusClient[F] =
new ServiceBusClient(clientBuilder, adminBuilder)

}
60 changes: 45 additions & 15 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import laika.config.PrettyURLs
import laika.config.LinkConfig
import laika.config.ApiLinks
import laika.config.SourceLinks

ThisBuild / tlBaseVersion := "0.0"

ThisBuild / organization := "com.commercetools"
ThisBuild / organizationName := "Commercetools GmbH"
ThisBuild / startYear := Some(2024)
ThisBuild / licenses := Seq(License.Apache2)
ThisBuild / tlCiDependencyGraphJob := false
ThisBuild / developers := List(
tlGitHubDev("satabin", "Lucas Satabin")
)

val Scala213 = "2.13.12"
ThisBuild / crossScalaVersions := Seq(Scala213, "3.3.3")
ThisBuild / scalaVersion := Scala213

lazy val root = tlCrossRootProject.aggregate(core, azureServiceBus, awsSQS, circe, otel4s)
lazy val root = tlCrossRootProject.aggregate(core, azureServiceBus, awsSQS, circe, otel4s, unidocs)

ThisBuild / tlSitePublishBranch := Some("main")

val commonSettings = List(
libraryDependencies ++= Seq(
Expand All @@ -35,7 +39,7 @@ lazy val core = crossProject(JVMPlatform)
.enablePlugins(NoPublishPlugin)
.settings(commonSettings)
.settings(
name := "cloud-queues-core"
name := "fs2-queues-core"
)

lazy val otel4s = crossProject(JVMPlatform)
Expand All @@ -44,7 +48,7 @@ lazy val otel4s = crossProject(JVMPlatform)
.enablePlugins(NoPublishPlugin)
.settings(commonSettings)
.settings(
name := "cloud-queues-otel4s",
name := "fs2-queues-otel4s",
description := "Support for metrics and tracing using otel4s",
libraryDependencies ++= List(
"org.typelevel" %%% "otel4s-core" % "0.4.0"
Expand All @@ -58,7 +62,7 @@ lazy val circe = crossProject(JVMPlatform)
.enablePlugins(NoPublishPlugin)
.settings(commonSettings)
.settings(
name := "cloud-queues-circe",
name := "fs2-queues-circe",
libraryDependencies ++= List(
"io.circe" %%% "circe-parser" % Versions.circe
)
Expand All @@ -71,7 +75,7 @@ lazy val azureServiceBus = crossProject(JVMPlatform)
.enablePlugins(NoPublishPlugin)
.settings(commonSettings)
.settings(
name := "cloud-queues-azure-service-bus",
name := "fs2-queues-azure-service-bus",
libraryDependencies ++= List(
"com.azure" % "azure-messaging-servicebus" % "7.15.1"
)
Expand All @@ -84,19 +88,45 @@ lazy val awsSQS = crossProject(JVMPlatform)
.enablePlugins(NoPublishPlugin)
.settings(commonSettings)
.settings(
name := "cloud-queues-aws-sqs",
name := "fs2-queues-aws-sqs",
libraryDependencies ++= List(
"software.amazon.awssdk" % "sqs" % "2.18.35"
)
)
.dependsOn(core)

lazy val readme = project
.in(file("readme"))
.enablePlugins(MdocPlugin, NoPublishPlugin)
lazy val docs = project
.in(file("site"))
.enablePlugins(TypelevelSitePlugin)
.settings(
mdocOut := file("."),
tlSiteApiPackage := Some("com.commercetools.queue"),
tlSiteHelium := CTTheme(tlSiteHelium.value),
laikaConfig := tlSiteApiUrl.value
.fold(laikaConfig.value) { apiUrl =>
laikaConfig.value.withConfigValue(
LinkConfig.empty
.addApiLinks(ApiLinks(baseUri = apiUrl.toString().dropRight("index.html".size)))
.addSourceLinks(
SourceLinks(baseUri = "https://github.com/commercetools/fs2-queues", suffix = "scala")
))
},
laikaExtensions += PrettyURLs,
tlFatalWarnings := false,
libraryDependencies ++= List(
"com.azure" % "azure-identity" % "1.11.1"
))
.dependsOn(azureServiceBus.jvm, awsSQS.jvm)
)
)
.dependsOn(circe.jvm, azureServiceBus.jvm, awsSQS.jvm, otel4s.jvm)

lazy val unidocs = project
.in(file("unidocs"))
.enablePlugins(TypelevelUnidocPlugin)
.settings(
name := "fs2-queues-docs",
ScalaUnidoc / unidoc / unidocProjectFilter := inProjects(
core.jvm,
circe.jvm,
azureServiceBus.jvm,
awsSQS.jvm,
otel4s.jvm)
)
Loading

0 comments on commit 6fa84ff

Please sign in to comment.