Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix migration to PSH #357

Merged
merged 1 commit into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions .github/workflows/standard-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ jobs:
working-directory: examples/akka-persistence-app

# <PEKKO-REMOVE-START>
patch-and-push-to-ash:
patch-and-push-to-psh:
if: github.event_name != 'pull_request'
needs: [code-style-check, test-212, test-213-1, test-213-2, test-sbt-plugin, run-examples]
runs-on: ubuntu-latest
Expand All @@ -145,20 +145,15 @@ jobs:
# Fetch all history so that a push to pekko-serialization-helper succeeds.
# See https://stackoverflow.com/q/76470864
fetch-depth: 0
- uses: coursier/cache-action@v6
- uses: coursier/setup-action@v1
- run: git status
- run: git checkout -b chore/from-ash
- run: git checkout -b TEMP/from-ash
- run: curl -sL https://raw.githubusercontent.com/ap/rename/master/rename | sudo tee /usr/local/bin/rename
- run: sudo chmod +x /usr/local/bin/rename
- run: ./scripts/akka-to-pekko
- run: git add .
- run: git config user.email "psh@virtuslab.com"
- run: git config user.name "Pekko Serialization Helper Bot"
- run: git commit -m 'Migrate `main` branch from from akka-serialization-helper'
- run: git clean -dxf
- run: ./scripts/format-code
- run: git commit -a --amend --no-edit
- env:
# 2.1 Generate an SSH key in terminal (Leave the passphrase empty)
# 2.2 Add public key in the external repository: <external repository>/Settings/Deploy keys/Add deploy key
Expand All @@ -167,7 +162,7 @@ jobs:
# Paste the private key.
PSH_SSH_PRIVATE_KEY: ${{ secrets.PSH_SSH_PRIVATE_KEY }}
run: mkdir -p ~/.ssh/ && echo "$PSH_SSH_PRIVATE_KEY" > ~/.ssh/psh && chmod 400 ~/.ssh/psh
- run: git config --add --local core.sshCommand 'ssh -i ~/.ssh/psh'
- run: git config core.sshCommand "ssh -i $HOME/.ssh/psh"
- run: git push --force git@github.com:VirtusLab/pekko-serialization-helper.git HEAD:main
# <PEKKO-REMOVE-END>

Expand Down
1 change: 0 additions & 1 deletion .scala-steward.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ buildRoots = [
]

# <PEKKO-UNCOMMENT> updates.allow = [ { groupId = "org.apache.pekko" } ]

# <PEKKO-REMOVE-START>
updates.pin = [
# * org.scala-lang.modules:scala-xml_2.12:2.1.0 (early-semver) is selected over 1.2.0
Expand Down
21 changes: 12 additions & 9 deletions .scalafix.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ rules = [
OrganizeImports
]

OrganizeImports.expandRelative = true
OrganizeImports.removeUnused = true
OrganizeImports.groupedImports = Explode
OrganizeImports.groups = [
"java.",
"scala.",
"*",
"org.virtuslab.ash"
]
OrganizeImports {
expandRelative = true
removeUnused = true
groupedImports = Explode
groups = [
"java.",
"scala.",
"akka.",
"*",
"org.virtuslab.ash"
]
}
2 changes: 1 addition & 1 deletion .scalafmt.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ style = defaultWithAlign
runner.dialect = scala213
docstrings.style = Asterisk
indentOperator.preset = spray
maxColumn = 120
maxColumn = 128
rewrite.rules = [RedundantParens, AvoidInfix]
align.tokens = [{code = "=>", owner = "Case"}]
align.openParenDefnSite = false
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Akka Serialization Helper

[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.virtuslab.ash/sbt-akka-serialization-helper/badge.svg)](https://mvnrepository.com/artifact/org.virtuslab.ash)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.virtuslab.ash/annotation_2.13/badge.svg)](https://mvnrepository.com/artifact/org.virtuslab.ash)
[![GitHub Actions](https://github.com/VirtusLab/akka-serialization-helper/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/VirtusLab/akka-serialization-helper/actions)
[![License: MIT](https://img.shields.io/github/license/VirtusLab/akka-serialization-helper)](LICENSE)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.virtuslab.ash.annotation

/**
* This annotation is used as a marker for Codec Registration Checker and Serializability Checker. Annotate Akka
* serialization marker-trait, and the rest is done by compiler plugins.
* This annotation is used as a marker for Codec Registration Checker and Serializability Checker. Annotate Akka serialization
* marker-trait, and the rest is done by compiler plugins.
*
* {{{
* @SerializabilityTrait
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import scala.annotation.nowarn
/**
* This annotation is used by Codec Registration Checker for marking serializers.
*
* Compiler plugin takes the body of a marked class, collects all types that are present, filters them with provided
* regex and extracts type parameters. Then filtered types and extracted type parameters are checked against all direct
* subtypes of `clazz`.
* Compiler plugin takes the body of a marked class, collects all types that are present, filters them with provided regex and
* extracts type parameters. Then filtered types and extracted type parameters are checked against all direct subtypes of
* `clazz`.
*
* Sometimes types appear unexpectedly during type class derivation leading to false negatives, i.e. a codec reported as
* registered even though it's NOT registered. The role of `typeRegexPattern` is to filter detected types, ensuring they
* are used in the right context.
* registered even though it's NOT registered. The role of `typeRegexPattern` is to filter detected types, ensuring they are
* used in the right context.
*
* For example, if we want to serialize `trait Command`, then type `Registration[Command]` is relevant, while
* `Option[Command]` is not.
* For example, if we want to serialize `trait Command`, then type `Registration[Command]` is relevant, while `Option[Command]`
* is not.
*
* If you are using `circe-akka-serializer`, set `typeRegexPattern` to `Register.REGISTRATION_REGEX`
*
Expand Down
9 changes: 2 additions & 7 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,10 @@ ThisBuild / organization := "org.virtuslab.ash"
ThisBuild / organizationName := "VirtusLab"
ThisBuild / versionScheme := Some("early-semver")
ThisBuild / homepage := Some(url("https://github.com/VirtusLab/akka-serialization-helper"))
ThisBuild / licenses := List(
"MIT License" -> url("https://github.com/VirtusLab/akka-serialization-helper/blob/main/LICENSE"))
ThisBuild / licenses := List("MIT License" -> url("https://github.com/VirtusLab/akka-serialization-helper/blob/main/LICENSE"))
ThisBuild / developers := List(
Developer("MarconZet", "Marcin Złakowski", "mzlakowski@virtuslab.com", url("https://github.com/MarconZet")),
Developer(
"LukaszKontowski",
"Łukasz Kontowski",
"lkontowski@virtuslab.com",
url("https://github.com/LukaszKontowski")),
Developer("LukaszKontowski", "Łukasz Kontowski", "lkontowski@virtuslab.com", url("https://github.com/LukaszKontowski")),
Developer("PawelLipski", "Paweł Lipski", "plipski@virtuslab.com", url("https://github.com/PawelLipski")))

sonatypeProfileName := "org.virtuslab"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import scala.reflect.ClassTag
import akka.actor.ExtendedActorSystem
import akka.event.Logging
import akka.serialization.SerializerWithStringManifest

import io.circe._
import io.circe.jawn.JawnParser

Expand Down Expand Up @@ -98,19 +99,17 @@ abstract class CirceAkkaSerializer[Ser <: AnyRef: ClassTag](system: ExtendedActo
/**
* The intended usage of this method is to provide any form of support for generic classes.
*
* Because of type erasure, it's impossible to [[org.virtuslab.ash.circe.Register]] one generic class two times with
* different type parameters.
* Because of type erasure, it's impossible to [[org.virtuslab.ash.circe.Register]] one generic class two times with different
* type parameters.
*
* The trick for combating type erasure is to register generic class only once with type parameter being its upper
* bound, and provide custom made [[io.circe.Codec]] that can serialize/deserialize all classes that are used as a
* type parameter.
* The trick for combating type erasure is to register generic class only once with type parameter being its upper bound, and
* provide custom made [[io.circe.Codec]] that can serialize/deserialize all classes that are used as a type parameter.
*
* For example, if the upper bound is `Any`, but you know that only `Int` and `String` are used as a type parameter,
* then you can create a custom [[io.circe.Codec]] for `Any` that handles `Int` and `String` and throws `Exception`
* otherwise.
* For example, if the upper bound is `Any`, but you know that only `Int` and `String` are used as a type parameter, then you
* can create a custom [[io.circe.Codec]] for `Any` that handles `Int` and `String` and throws `Exception` otherwise.
*
* To use this method correctly, set the upper bound for the type parameter of generic class to `Ser` and put the
* returned Codec as implicit in a place that can be seen by type derivation.
* To use this method correctly, set the upper bound for the type parameter of generic class to `Ser` and put the returned
* Codec as implicit in a place that can be seen by type derivation.
*
* Example of generic class:
* {{{
Expand All @@ -129,12 +128,7 @@ abstract class CirceAkkaSerializer[Ser <: AnyRef: ClassTag](system: ExtendedActo
private def logDuration(action: String, obj: AnyRef, startTime: Long, bytes: Array[Byte]): Unit = {
if (isDebugEnabled) {
val durationMicros = (System.nanoTime - startTime) / 1000
log.debug(
"{} of [{}] took [{}] microsecond, size [{}] bytes",
action,
obj.getClass.getName,
durationMicros,
bytes.length)
log.debug("{} of [{}] took [{}] microsecond, size [{}] bytes", action, obj.getClass.getName, durationMicros, bytes.length)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,21 @@ trait CirceTraitCodec[Ser <: AnyRef] extends Codec[Ser] {
/**
* Sequence that must contain [[org.virtuslab.ash.circe.Registration]] for all direct subclasses of Ser.
*
* Each `Registration` is created using [[org.virtuslab.ash.circe.Register]]s
* [[org.virtuslab.ash.circe.Register#apply]] method.
* Each `Registration` is created using [[org.virtuslab.ash.circe.Register]]s [[org.virtuslab.ash.circe.Register#apply]]
* method.
*
* To check if all needed classes are registered, use Codec Registration Checker.
*
* @see
* [[org.virtuslab.ash.circe.Register]][[org.virtuslab.ash.circe.Register#apply]] for more information about type
* derivation
* [[org.virtuslab.ash.circe.Register]][[org.virtuslab.ash.circe.Register#apply]] for more information about type derivation
*/
val codecs: Seq[Registration[_ <: Ser]]

/**
* A sequence containing information used in type migration.
*
* If you ever change the name of a class that is a direct descendant of `Ser` and is persisted in any way, you must
* append new pair to this field.
* If you ever change the name of a class that is a direct descendant of `Ser` and is persisted in any way, you must append
* new pair to this field.
* - The first element of the pair is a String with the value of old FQCN.
* - The second element of the pair is a Class that had its name changed
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ object Compression {
// TODO (#159): add support for LZ4 java compression
// case class LZ4(greaterThan: Long) extends Algorithm

private[circe] def compressIfNeeded(
bytes: Array[Byte],
bufferSize: Int,
compressionAlgorithm: Algorithm): Array[Byte] =
private[circe] def compressIfNeeded(bytes: Array[Byte], bufferSize: Int, compressionAlgorithm: Algorithm): Array[Byte] =
compressionAlgorithm match {
case Compression.Off => bytes
case Compression.GZip(largerThan) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ object Register {

/**
* This method takes three implicit arguments: [[scala.reflect.api.TypeTags.TypeTag]], [[io.circe.Encoder]] and
* [[io.circe.Decoder]]. TypeTag is provided by the compiler, Encoder and Decoder are derived using Shapeless. There
* are several scenarios, in which derivation may fail, requiring defining custom codecs in a separate trait.
* [[io.circe.Decoder]]. TypeTag is provided by the compiler, Encoder and Decoder are derived using Shapeless. There are
* several scenarios, in which derivation may fail, requiring defining custom codecs in a separate trait.
*
* Type class derivation will fail if the type or any of its fields don't have custom-defined Encoder/Decoder and at
* least one of the following statements about any of them is true:
* Type class derivation will fail if the type or any of its fields don't have custom-defined Encoder/Decoder and at least one
* of the following statements about any of them is true:
* - is a non-sealed trait
* - is a sealed trait but two or more subtypes have the same name (in different packages)
* - is a non-case class
Expand All @@ -35,14 +35,14 @@ object Register {
def REGISTRATION_REGEX: String = macro regexImpl

/**
* `circeRegex` is the preferred typeRegexPattern for Circe Akka Serializer usage. It contains leading and trailing
* `.*` - so that it matches both single Registration and multiple Registrations in a collection. It is used by the
* `circeRegex` is the preferred typeRegexPattern for Circe Akka Serializer usage. It contains leading and trailing `.*` - so
* that it matches both single Registration and multiple Registrations in a collection. It is used by the
* codec-registration-checker-compiler-plugin to collect properly registered codecs.
*
* As codec-registration-checker-compiler-plugin searches for `circeRegex` occurrences in the generated AST - and
* detects proper registrations if detected type contains the regex - there might be some rare corner cases, where
* something like `Option[Register[User_Defined_Type]]` is in the AST and codec-registration-checker-compiler-plugin
* would still treat it as proper registration. However, such situations have not been encountered in real usages.
* As codec-registration-checker-compiler-plugin searches for `circeRegex` occurrences in the generated AST - and detects
* proper registrations if detected type contains the regex - there might be some rare corner cases, where something like
* `Option[Register[User_Defined_Type]]` is in the AST and codec-registration-checker-compiler-plugin would still treat it as
* proper registration. However, such situations have not been encountered in real usages.
*/
private val circeRegex = """.*org\.virtuslab\.ash\.circe\.Registration\[.*\].*"""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import scala.io.Source
import akka.actor.testkit.typed.scaladsl.ActorTestKit
import akka.actor.testkit.typed.scaladsl.SerializationTestKit
import akka.actor.typed.ActorSystem

import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigValueFactory
import org.scalatest.matchers.should
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import scala.annotation.nowarn
import scala.reflect.runtime.{universe => ru}

import akka.actor.ExtendedActorSystem

import io.circe._
import io.circe.generic.auto._

import org.virtuslab.ash.circe.data.ModifiedCodec._
import org.virtuslab.ash.circe.data._

class CustomSerializer(actorSystem: ExtendedActorSystem)
extends CirceAkkaSerializer[CirceSerializabilityTrait](actorSystem) {
class CustomSerializer(actorSystem: ExtendedActorSystem) extends CirceAkkaSerializer[CirceSerializabilityTrait](actorSystem) {

@nowarn implicit private val serializabilityCodec: Codec[CirceSerializabilityTrait] = genericCodec

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import java.io.File
*
* @param directClassDescendantsCacheFile
* \- CSV file where all Fully Qualified Class Names (FQCNs) for: a) detected classes/traits annotated with the
* 'serializability trait' and b) their direct descendants are saved as pairs of comma-separated values (two values
* per row) according to following pattern: <PARENT_FQCN>,<DESCENDANT_FQCN>
* 'serializability trait' and b) their direct descendants are saved as pairs of comma-separated values (two values per row)
* according to following pattern: <PARENT_FQCN>,<DESCENDANT_FQCN>
*
* @param oldParentChildFQCNPairs
* \- collection that holds String pairs representing the content of the `directClassDescendantsCacheFile`. Each
* String pair is wrapped inside `ParentChildFQCNPair` instance. `oldParentChildFQCNPairs` variable is needed to catch
* missing codec registrations when using sbt incremental compilation (so - these are FQCNs that were found during
* previous compilation). Without using `oldParentChildFQCNPairs` we wouldn't be able to detect situations, where
* codec registration for a serializable type has been removed from the code (when `sbt compile` was incremental). And
* if we can't detect it - this would lead to runtime errors (see README for more details). `oldParentChildFQCNPairs`
* gets declared on the plugin's init by invoking the `CodecRegistrationCheckerCompilerPlugin.parseCacheFile` method.
* \- collection that holds String pairs representing the content of the `directClassDescendantsCacheFile`. Each String pair
* is wrapped inside `ParentChildFQCNPair` instance. `oldParentChildFQCNPairs` variable is needed to catch missing codec
* registrations when using sbt incremental compilation (so - these are FQCNs that were found during previous compilation).
* Without using `oldParentChildFQCNPairs` we wouldn't be able to detect situations, where codec registration for a
* serializable type has been removed from the code (when `sbt compile` was incremental). And if we can't detect it - this
* would lead to runtime errors (see README for more details). `oldParentChildFQCNPairs` gets declared on the plugin's init by
* invoking the `CodecRegistrationCheckerCompilerPlugin.parseCacheFile` method.
*/
case class CodecRegistrationCheckerOptions(
var directClassDescendantsCacheFile: File = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class SerializerCheckCompilerPluginComponent(
val typeRegexPatternOption =
regexTree match {
case Select(_, TermName("$lessinit$greater$default$2")) => Some(".*")
case other => extractValueOfLiteralConstantFromTree[String](other)
case other => extractValueOfLiteralConstantFromTree[String](other)
}

(fqcnOption, typeRegexPatternOption) match {
Expand Down Expand Up @@ -129,9 +129,7 @@ class SerializerCheckCompilerPluginComponent(
.filter(_.toString.matches(typeRegexPattern))
} catch {
case e: PatternSyntaxException =>
reporter.error(
serializerImplDef.pos,
"Exception throw during the use of type regex pattern: " + e.getMessage)
reporter.error(serializerImplDef.pos, "Exception throw during the use of type regex pattern: " + e.getMessage)
return
}
}
Expand All @@ -157,8 +155,7 @@ class SerializerCheckCompilerPluginComponent(
if (possibleMissingFullyQualifiedClassNames.nonEmpty) {
// Due to the way how incremental compilation works - `possibleMissingFullyQualifiedClassNames` could contain
// "false-positives" - that's why additional check in `collectMissingClassNames` is needed.
val actuallyMissingFullyQualifiedClassNames = collectMissingClassNames(
possibleMissingFullyQualifiedClassNames)
val actuallyMissingFullyQualifiedClassNames = collectMissingClassNames(possibleMissingFullyQualifiedClassNames)
if (actuallyMissingFullyQualifiedClassNames.nonEmpty) {
reporter.error(
serializerImplDef.pos,
Expand Down Expand Up @@ -188,9 +185,7 @@ class SerializerCheckCompilerPluginComponent(
None
}
case other =>
reporter.error(
other.pos,
s"Annotation argument must be a literal constant. Currently: ${other.summaryString}")
reporter.error(other.pos, s"Annotation argument must be a literal constant. Currently: ${other.summaryString}")
None
}
}
Expand Down
Loading