Skip to content

Commit

Permalink
Drop patch from package version suffix (#366)
Browse files Browse the repository at this point in the history
* Drop patch from package version suffix
- A.B.C-core.X.Y.Z -> A.B.C-core.X.Y
* Update dependencies
  • Loading branch information
pawelprazak authored Feb 2, 2024
1 parent 15bc1a0 commit a24e738
Show file tree
Hide file tree
Showing 27 changed files with 254 additions and 47 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ just test-all
### Working with published dependencies

Release builds of the Besom SDK are published to Maven Central, and snapshots to GitHub Packages
as `org.virtuslab::besom-core:X.Y.Z` and `org.virtuslab::besom-[package]:A.B.C-core.X.Y.Z`.
as `org.virtuslab::besom-core:X.Y.Z` and `org.virtuslab::besom-<package>:A.B.C-core.X.Y`.

Language host provider is published to GitHub Packages as `pulumi-language-scala-vX.Y.Z-OS-ARCH.tar.gz`.

Expand Down
6 changes: 3 additions & 3 deletions codegen/project.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//> using scala 3.3.1
//> using options -release:11 -deprecation -Werror -Wunused:all -Wvalue-discard -Wnonunit-statement -language:noAutoTupling

//> using dep org.scalameta:scalameta_2.13:4.8.14
//> using dep com.lihaoyi::upickle:3.1.3
//> using dep com.lihaoyi::os-lib:0.9.2
//> using dep org.scalameta:scalameta_2.13:4.8.15
//> using dep com.lihaoyi::upickle:3.1.4
//> using dep com.lihaoyi::os-lib:0.9.3
//> using test.dep org.scalameta::munit::1.0.0-M10

//> using publish.name "besom-codegen"
Expand Down
31 changes: 19 additions & 12 deletions codegen/src/CodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class CodeGen(implicit
schemaProvider: SchemaProvider,
logger: Logger
) {
import CodeGen.*

def sourcesFromPulumiPackage(
pulumiPackage: PulumiPackage,
Expand Down Expand Up @@ -47,17 +48,12 @@ class CodeGen(implicit
}

def projectConfigFile(schemaName: String, packageVersion: PackageVersion): SourceFile = {
val besomVersion = codegenConfig.besomVersion
val scalaVersion = codegenConfig.scalaVersion
val javaVersion = codegenConfig.javaVersion
val besomVersion = codegenConfig.besomVersion
val scalaVersion = codegenConfig.scalaVersion
val javaVersion = codegenConfig.javaVersion
val coreShortVersion = codegenConfig.coreShortVersion

val dependencies = schemaProvider
.dependencies(schemaName, packageVersion)
.map { case (name, version) =>
s"""|//> using dep "org.virtuslab::besom-${name}:${version}-core.${besomVersion}"
|""".stripMargin
}
.mkString("\n")
val dependencies = packageDependencies(schemaProvider.dependencies(schemaName, packageVersion))

val fileContent =
s"""|//> using scala "$scalaVersion"
Expand All @@ -70,7 +66,7 @@ class CodeGen(implicit
|
|//> using publish.name "besom-${schemaName}"
|//> using publish.organization "org.virtuslab"
|//> using publish.version "${packageVersion}-core.${besomVersion}"
|//> using publish.version "${packageVersion}-core.${coreShortVersion}"
|//> using publish.url "https://github.com/VirtusLab/besom"
|//> using publish.vcs "github:VirtusLab/besom"
|//> using publish.license "Apache-2.0"
Expand Down Expand Up @@ -175,7 +171,7 @@ class CodeGen(implicit
val caseRawName = valueDefinition.name.getOrElse {
valueDefinition.value match {
case StringConstValue(value) => value
case const => throw GeneralCodegenException(s"The name of enum cannot be derived from value ${const}")
case const => throw GeneralCodegenException(s"The name of enum cannot be derived from value ${const}")
}
}
val caseName = Term.Name(caseRawName)
Expand Down Expand Up @@ -1001,6 +997,17 @@ class CodeGen(implicit
}
}

object CodeGen:
def packageDependency(name: SchemaName, version: SchemaVersion)(implicit codegenConfig: CodegenConfig): String =
packageDependencies(List((name, version)))
def packageDependencies(dependencies: List[(SchemaName, SchemaVersion)])(implicit codegenConfig: CodegenConfig): String =
dependencies
.map { case (name, version) =>
s"""|//> using dep "org.virtuslab::besom-${name}:${version}-core.${codegenConfig.coreShortVersion}"
|""".stripMargin
}
.mkString("\n")

case class FilePath(pathParts: Seq[String]) {
require(
pathParts.forall(!_.contains('/')),
Expand Down
10 changes: 9 additions & 1 deletion codegen/src/Config.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package besom.codegen

import besom.model.SemanticVersion

// noinspection ScalaWeakerAccess
object Config {

Expand Down Expand Up @@ -28,7 +30,13 @@ object Config {
scalaVersion: String = DefaultScalaVersion,
javaVersion: String = DefaultJavaVersion,
logLevel: Logger.Level = Logger.Level.Info
)
):
val coreShortVersion: String = SemanticVersion
.parseTolerant(besomVersion)
.fold(
e => throw GeneralCodegenException(s"Invalid besom version: ${besomVersion}", e),
_.copy(patch = 0).toShortString
)

case class ProviderConfig(
noncompiledModules: Seq[String] = Seq.empty
Expand Down
3 changes: 1 addition & 2 deletions codegen/src/PackageMetadata.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import besom.codegen.UpickleApi.*

type SchemaName = String
type SchemaVersion = String
type SchemaFile = os.Path

private case class PackageMetadataProtocol(
name: String,
Expand Down Expand Up @@ -68,7 +67,7 @@ object PackageMetadata {
def toJson(ms: Vector[PackageMetadata]): String = write[Vector[PackageMetadata]](ms)
}

opaque type PackageVersion = SchemaVersion
opaque type PackageVersion <: String = SchemaVersion
object PackageVersion {

private val DefaultVersion = "0.0.0"
Expand Down
2 changes: 2 additions & 0 deletions codegen/src/SchemaProvider.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import besom.codegen.{PackageVersion, SchemaFile, SchemaName}

import scala.collection.mutable.ListBuffer

type SchemaFile = os.Path

trait SchemaProvider {
def packageInfo(metadata: PackageMetadata, schema: Option[SchemaFile] = None): (PulumiPackage, PulumiPackageInfo)
def packageInfo(metadata: PackageMetadata, pulumiPackage: PulumiPackage): (PulumiPackage, PulumiPackageInfo)
Expand Down
118 changes: 118 additions & 0 deletions codegen/src/model/SemanticVersion.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package besom.model

// TODO: move to separate module

/** A semantic version as defined by https://semver.org/
*
* @param major
* Major version number
* @param minor
* Minor version number
* @param patch
* Patch version number
* @param preRelease
* Pre-release version identifier
* @param buildMetadata
* Build metadata version identifier
*/
case class SemanticVersion(
major: Int,
minor: Int,
patch: Int,
preRelease: Option[String] = None,
buildMetadata: Option[String] = None
) extends Ordered[SemanticVersion]:
require(major >= 0, "major version must be non-negative")
require(minor >= 0, "minor version must be non-negative")
require(patch >= 0, "patch version must be non-negative")

override def compare(that: SemanticVersion): Int =
import math.Ordered.orderingToOrdered

val mainCompared = (major, minor, patch).compare((that.major, that.minor, that.patch))

// for pre release compare each dot separated identifier from left to right
lazy val thisPreRelease: Vector[Option[String]] = preRelease.map(_.split('.')).getOrElse(Array.empty[String]).toVector.map(Some(_))
lazy val thatPreRelease: Vector[Option[String]] = that.preRelease.map(_.split('.')).getOrElse(Array.empty[String]).toVector.map(Some(_))

def comparePreReleaseIdentifier(thisIdentifeir: Option[String], thatIdentifier: Option[String]): Int =
(thisIdentifeir, thatIdentifier) match
case (Some(thisId), Some(thatId)) =>
val thisIsNumeric = thisId.forall(_.isDigit)
val thatIsNumeric = thatId.forall(_.isDigit)
(thisIsNumeric, thatIsNumeric) match
case (true, true) => thisId.toInt.compare(thatId.toInt)
case (false, false) => thisId.compare(thatId)
case (true, false) => -1 // numeric identifiers have always lower precedence than non-numeric identifiers
case (false, true) => 1 // numeric identifiers have always lower precedence than non-numeric identifiers
/* A larger set of pre-release fields has a higher precedence than a smaller set, if all of the preceding identifiers are equal. */
case (Some(_), None) => 1 // larger set of pre-release fields has higher precedence
case (None, Some(_)) => -1 // larger set of pre-release fields has higher precedence
case (None, None) => 0

lazy val preCompared: Int =
thisPreRelease
.zipAll(thatPreRelease, None, None)
.map(comparePreReleaseIdentifier.tupled)
.find(_ != 0)
.getOrElse(thisPreRelease.length.compare(thatPreRelease.length)) // if all identifiers are equal, the version with fewer fields has lower precedence

// ignore build metadata when comparing versions per semver spec https://semver.org/#spec-item-10

if mainCompared != 0
then mainCompared
else if thisPreRelease.isEmpty && thatPreRelease.nonEmpty
then 1 // normal version has higher precedence than a pre-release version
else if thisPreRelease.nonEmpty && thatPreRelease.isEmpty
then -1 // normal version has higher precedence than a pre-release version
else preCompared // pre-release version has lower precedence than a normal version
end compare

lazy val preReleaseString: String = preRelease.map("-" + _).getOrElse("")
lazy val buildMetadataString: String = buildMetadata.map("+" + _).getOrElse("")

override def toString: String = s"$major.$minor.$patch$preReleaseString$buildMetadataString"
def toShortString: String =
val xyz = List(major) ++ Option.when(minor > 0)(minor) ++ Option.when(patch > 0)(patch)
xyz.mkString(".") + preReleaseString + buildMetadataString
end SemanticVersion

//noinspection ScalaFileName
object SemanticVersion {
// https://semver.org/spec/v2.0.0.html#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
private val versionRegex =
"""^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$""".r

def apply(major: Int, minor: Int, patch: Int): SemanticVersion =
new SemanticVersion(major, minor, patch, None, None)

def apply(major: Int, minor: Int, patch: Int, preRelease: String): SemanticVersion =
new SemanticVersion(major, minor, patch, Some(preRelease), None)

def apply(major: Int, minor: Int, patch: Int, preRelease: String, buildMetadata: String): SemanticVersion =
new SemanticVersion(major, minor, patch, Some(preRelease), Some(buildMetadata))

def parse(version: String): Either[Exception, SemanticVersion] = {
version match {
case versionRegex(major, minor, patch, preRelease, buildMetadata) =>
Right(SemanticVersion(major.toInt, minor.toInt, patch.toInt, Option(preRelease), Option(buildMetadata)))
case _ => Left(Exception(s"Cannot parse as semantic version: '$version'"))
}
}

/** ParseTolerant allows for certain version specifications that do not strictly adhere to semver specs to be parsed by this library. It
* does so by normalizing versions before passing them to [[parse]]. It currently trims spaces, removes a "v" prefix, and adds a 0 patch
* number to versions with only major and minor components specified.
*/
def parseTolerant(version: String): Either[Exception, SemanticVersion] = {
val str = version.trim.stripPrefix("v")

// Split into major.minor.(patch+pr+meta)
val parts = str.split("\\.", 3)
if parts.length < 3 then
if parts.last.contains("+") || parts.last.contains("-") then
Left(Exception("Short version cannot contain PreRelease/Build meta data"))
else parse((parts.toList ::: List.fill(3 - parts.length)("0")).mkString("."))
else parse(str)
}
}
63 changes: 63 additions & 0 deletions codegen/src/model/SemanticVersion.test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package besom.model

//noinspection ScalaFileName
class SemanticVersionTest extends munit.FunSuite:

Map(
"1.0.0" -> SemanticVersion(1, 0, 0),
"v1.0.0" -> SemanticVersion(1, 0, 0),
"1.0.0-alpha" -> SemanticVersion(1, 0, 0, "alpha"),
"1.0.0-rc.1" -> SemanticVersion(1, 0, 0, "rc.1"),
"0.0.1-SNAPSHOT" -> SemanticVersion(0, 0, 1, "SNAPSHOT"),
"v0.0.1-SNAPSHOT" -> SemanticVersion(0, 0, 1, "SNAPSHOT"),
"1.0.0-alpha+001" -> SemanticVersion(1, 0, 0, "alpha", "001"),
"1.0.0+20130313144700" -> SemanticVersion(1, 0, 0, None, Some("20130313144700")),
"1.0.0-beta+exp.sha.5114f85" -> SemanticVersion(1, 0, 0, "beta", "exp.sha.5114f85"),
"1.0.0+21AF26D3----117B344092BD" -> SemanticVersion(1, 0, 0, None, Some("21AF26D3----117B344092BD")),
).foreachEntry((input, expected) =>
test(s"parse $input") {
assertEquals(SemanticVersion.parseTolerant(input), Right(expected))
}
)

Map(
SemanticVersion(0, 0, 1, "SNAPSHOT") -> "0.0.1-SNAPSHOT",
).foreachEntry((input, expected) =>
test(s"format $input") {
assertEquals(input.toString, expected)
}
)
Map(
SemanticVersion(0, 1, 1, "SNAPSHOT") -> "0.1.1-SNAPSHOT",
SemanticVersion(1, 1, 0, "SNAPSHOT") -> "1.1-SNAPSHOT",
SemanticVersion(1, 0, 0, "SNAPSHOT", "deadbeef") -> "1-SNAPSHOT+deadbeef",
).foreachEntry((input, expected) =>
test(s"short format $input") {
assertEquals(input.toShortString, expected)
}
)

Map(
"0.0.0" -> "0.0.1",
"0.0.1" -> "0.1.0",
"0.1.0" -> "0.1.1",
"1.0.0" -> "2.0.0",
"1.0.0-alpha" -> "1.0.0",
"1.0.0-alpha" -> "1.0.0-alpha.1",
"1.0.0-alpha.1" -> "1.0.0-alpha.beta",
"1.0.0-alpha.beta" -> "1.0.0-beta",
"1.0.0-beta" -> "1.0.0-beta.2",
"1.0.0-beta.2" -> "1.0.0-beta.11",
"1.0.0-beta.11" -> "1.0.0-rc.1",
"1.0.0-rc.1" -> "1.0.0",
"1.0.0-alpha+001" -> "1.0.0-alpha.1",
"1.0.0-alpha.1" -> "1.0.0-alpha.beta"
).foreachEntry((left, right) =>
test(s"$left < $right") {
assertEquals(SemanticVersion.parse(left).toTry.get < SemanticVersion.parse(right).toTry.get, true)
}
)

test("1.0.0 == 1.0.0") {
assertEquals(SemanticVersion.parse("1.0.0").toTry.get == SemanticVersion.parse("1.0.0").toTry.get, true)
}
2 changes: 1 addition & 1 deletion examples/aws-s3-folder/project.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//> using scala "3.3.1"
//> using plugin "org.virtuslab::besom-compiler-plugin:0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-core:0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-aws:6.18.2-core.0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-aws:6.19.0-core.0.1-SNAPSHOT"
//> using options -Werror -Wunused:all -Wvalue-discard -Wnonunit-statement
2 changes: 1 addition & 1 deletion examples/aws-secrets-manager/project.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//> using scala "3.3.1"
//> using plugin "org.virtuslab::besom-compiler-plugin:0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-core:0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-aws:6.18.2-core.0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-aws:6.19.0-core.0.1-SNAPSHOT"
//> using options -Werror -Wunused:all -Wvalue-discard -Wnonunit-statement
4 changes: 2 additions & 2 deletions examples/aws-webserver/project.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
//> using options -Werror -Wunused:all -Wvalue-discard -Wnonunit-statement
//> using plugin org.virtuslab::besom-compiler-plugin:0.1.1-SNAPSHOT
//> using dep org.virtuslab::besom-core:0.1.1-SNAPSHOT
//> using dep org.virtuslab::besom-aws:6.18.2-core.0.1.1-SNAPSHOT
//> using dep org.virtuslab::besom-tls:5.0.0-core.0.1.1-SNAPSHOT
//> using dep org.virtuslab::besom-aws:6.19.0-core.0.1-SNAPSHOT
//> using dep org.virtuslab::besom-tls:5.0.0-core.0.1-SNAPSHOT
2 changes: 1 addition & 1 deletion examples/docker-multi-container-app/infra/project.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//> using scala "3.3.1"
//> using plugin "org.virtuslab::besom-compiler-plugin:0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-core:0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-docker:4.5.1-core.0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-docker:4.5.1-core.0.1-SNAPSHOT"
//> using options -Werror -Wunused:all -Wvalue-discard -Wnonunit-statement
2 changes: 1 addition & 1 deletion examples/gcp-static-page/project.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//> using scala "3.3.1"
//> using plugin "org.virtuslab::besom-compiler-plugin:0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-core:0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-gcp:7.7.0-core.0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-gcp:7.7.0-core.0.1-SNAPSHOT"
//> using options -Werror -Wunused:all -Wvalue-discard -Wnonunit-statement
2 changes: 1 addition & 1 deletion examples/kubernetes-nginx/project.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//> using scala "3.3.1"
//> using plugin "org.virtuslab::besom-compiler-plugin:0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-core:0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-kubernetes:4.7.1-core.0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-kubernetes:4.7.1-core.0.1-SNAPSHOT"
//> using options -Werror -Wunused:all -Wvalue-discard -Wnonunit-statement
2 changes: 1 addition & 1 deletion experimental/project.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//> using scala "3.3.0"
//> using plugin "org.virtuslab::besom-compiler-plugin:0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-core:0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-kubernetes:4.7.1-core.0.1.1-SNAPSHOT"
//> using dep "org.virtuslab::besom-kubernetes:4.7.1-core.0.1-SNAPSHOT"
//> using dep "io.github.iltotore::iron:2.4.0"
Loading

0 comments on commit a24e738

Please sign in to comment.