Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
fthomas committed Jan 10, 2025
1 parent eae30d0 commit 6dbcf50
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 1 deletion.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ lazy val core = myCrossProject("core")
Dependencies.monocleCore,
Dependencies.refined,
Dependencies.scalacacheCaffeine,
Dependencies.tomlj,
Dependencies.logbackClassic % Runtime,
Dependencies.catsLaws % Test,
Dependencies.circeLiteral % Test,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.http4s.client.Client
import org.http4s.headers.`User-Agent`
import org.scalasteward.core.application.Config.ForgeCfg
import org.scalasteward.core.buildtool.BuildToolDispatcher
import org.scalasteward.core.buildtool.gradle.GradleAlg
import org.scalasteward.core.buildtool.maven.MavenAlg
import org.scalasteward.core.buildtool.mill.MillAlg
import org.scalasteward.core.buildtool.sbt.SbtAlg
Expand Down Expand Up @@ -61,6 +62,7 @@ final class Context[F[_]](implicit
val filterAlg: FilterAlg[F],
val forgeRepoAlg: ForgeRepoAlg[F],
val gitAlg: GitAlg[F],
val gradleAlg: GradleAlg[F],
val hookExecutor: HookExecutor[F],
val httpJsonClient: HttpJsonClient[F],
val logger: Logger[F],
Expand Down Expand Up @@ -176,6 +178,7 @@ object Context {
implicit val versionsCache: VersionsCache[F] =
new VersionsCache[F](config.cacheTtl, versionsStore)
implicit val updateAlg: UpdateAlg[F] = new UpdateAlg[F]
implicit val gradleAlg: GradleAlg[F] = new GradleAlg[F](config.defaultResolver)
implicit val mavenAlg: MavenAlg[F] = new MavenAlg[F](config)
implicit val sbtAlg: SbtAlg[F] = new SbtAlg[F](config)
implicit val scalaCliAlg: ScalaCliAlg[F] = new ScalaCliAlg[F]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package org.scalasteward.core.buildtool

import cats.Monad
import cats.syntax.all.*
import org.scalasteward.core.buildtool.gradle.GradleAlg
import org.scalasteward.core.buildtool.maven.MavenAlg
import org.scalasteward.core.buildtool.mill.MillAlg
import org.scalasteward.core.buildtool.sbt.SbtAlg
Expand All @@ -29,6 +30,7 @@ import org.scalasteward.core.scalafmt.ScalafmtAlg
import org.typelevel.log4cats.Logger

final class BuildToolDispatcher[F[_]](implicit
gradleAlg: GradleAlg[F],
logger: Logger[F],
mavenAlg: MavenAlg[F],
millAlg: MillAlg[F],
Expand All @@ -53,7 +55,7 @@ final class BuildToolDispatcher[F[_]](implicit
buildTools.traverse_(_.runMigration(buildRoot, migration))
})

private val allBuildTools = List(mavenAlg, millAlg, sbtAlg, scalaCliAlg)
private val allBuildTools = List(gradleAlg, mavenAlg, millAlg, sbtAlg, scalaCliAlg)
private val fallbackBuildTool = List(sbtAlg)

private def findBuildTools(buildRoot: BuildRoot): F[(BuildRoot, List[BuildToolAlg[F]])] =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2018-2025 Scala Steward contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.scalasteward.core.buildtool.gradle

import better.files.File
import cats.Monad
import cats.syntax.all.*
import org.scalasteward.core.buildtool.{BuildRoot, BuildToolAlg}
import org.scalasteward.core.data.Scope.Dependencies
import org.scalasteward.core.data.{Resolver, Scope}
import org.scalasteward.core.io.{FileAlg, WorkspaceAlg}
import org.typelevel.log4cats.Logger

final class GradleAlg[F[_]](defaultResolver: Resolver)(implicit
fileAlg: FileAlg[F],
override protected val logger: Logger[F],
workspaceAlg: WorkspaceAlg[F],
F: Monad[F]
) extends BuildToolAlg[F] {
override def name: String = "Gradle"

override def containsBuild(buildRoot: BuildRoot): F[Boolean] =
libsVersionsToml(buildRoot).flatMap(fileAlg.isRegularFile)

override def getDependencies(buildRoot: BuildRoot): F[List[Dependencies]] =
libsVersionsToml(buildRoot)
.flatMap(fileAlg.readFile)
.map(_.getOrElse(""))
.map(gradleParser.parseDependencies)
.map(ds => List(Scope(ds, List(defaultResolver))))

private def libsVersionsToml(buildRoot: BuildRoot): F[File] =
workspaceAlg.buildRootDir(buildRoot).map(_ / "gradle" / "libs.versions.toml")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2018-2025 Scala Steward contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.scalasteward.core.buildtool.gradle

import org.scalasteward.core.data.{ArtifactId, Dependency, GroupId, Version}
import org.tomlj.{Toml, TomlTable}
import scala.jdk.CollectionConverters.*

object gradleParser {
def parseDependencies(s: String): List[Dependency] = {
val parsed = Toml.parse(s)
val versions = parsed.getTable(key.versions)
val libraries = parsed.getTable(key.libraries)
libraries
.entrySet()
.asScala
.map(_.getValue)
.flatMap {
case lib: TomlTable => parseDependency(lib, versions)
case _ => None
}
.toList
}

private def parseDependency(lib: TomlTable, versions: TomlTable): Option[Dependency] =
parseVersion(lib, versions).flatMap { version =>
if (lib.contains(key.module)) {
val module = lib.getString(key.module)
module.split(':') match {
case Array(g, a) =>
val groupId = GroupId(g)
val artifactId = ArtifactId(a)
Some(Dependency(groupId, artifactId, version))
case _ => None
}
} else if (lib.contains(key.group)) {
val groupId = GroupId(lib.getString(key.group))
val artifactId = ArtifactId(lib.getString(key.name))
Some(Dependency(groupId, artifactId, version))
} else None
}

private def parseVersion(lib: TomlTable, versions: TomlTable): Option[Version] =
if (lib.isTable(key.version) && lib.contains(key.versionRef)) {
val ref = lib.getString(key.versionRef)
Option.when(versions.isString(ref))(Version(versions.getString(ref)))
} else if (lib.isString(key.version))
Some(Version(lib.getString(key.version)))
else
None

object key {
val group = "group"
val libraries = "libraries"
val module = "module"
val name = "name"
val version = "version"
val versions = "versions"
val versionRef = "version.ref"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ object UpdatesConfig {
".scala",
scalafmtConfName,
".sdkmanrc",
".toml",
".yml",
buildPropertiesName,
pomXmlName
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.scalasteward.core.buildtool.gradle

import munit.CatsEffectSuite
import org.scalasteward.core.TestSyntax.*
import org.scalasteward.core.buildtool.BuildRoot
import org.scalasteward.core.data.Repo
import org.scalasteward.core.mock.MockContext.context.*
import org.scalasteward.core.mock.{MockEffOps, MockState}

class GradleAlgTest extends CatsEffectSuite {
test("getDependencies") {
val repo = Repo("gradle-alg", "test-getDependencies")
val buildRoot = BuildRoot(repo, ".")
val buildRootDir = workspaceAlg.buildRootDir(buildRoot).unsafeRunSync()

val initial = MockState.empty.addFiles(
buildRootDir / "gradle" / "libs.versions.toml" ->
"""|[libraries]
|tomlj = { group = "org.tomlj", name = "tomlj", version = "1.1.1" }
|""".stripMargin
)
val obtained = initial.flatMap(gradleAlg.getDependencies(buildRoot).runA)
val expected = List(List("org.tomlj".g % "tomlj".a % "1.1.1").withMavenCentral)
assertIO(obtained, expected)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.scalasteward.core.buildtool.gradle

import munit.FunSuite

class gradleParserTest extends FunSuite {
test("parseDependencies") {
val input =
"""|[versions]
|groovy = "3.0.5"
|checkstyle = "8.37"
|
|[libraries]
|groovy-core = { module = "org.codehaus.groovy:groovy", version.ref = "groovy" }
|groovy-json = { module = "org.codehaus.groovy:groovy-json", version.ref = "groovy" }
|groovy-nio = { module = "org.codehaus.groovy:groovy-nio", version.ref = "groovy" }
|commons-lang3 = { group = "org.apache.commons", name = "commons-lang3", version = { strictly = "[3.8, 4.0[", prefer="3.9" } }
|tomlj = { group = "org.tomlj", name = "tomlj", version = "1.1.1" }
|
|[bundles]
|groovy = ["groovy-core", "groovy-json", "groovy-nio"]
|
|[plugins]
|versions = { id = "com.github.ben-manes.versions", version = "0.45.0" }
|""".stripMargin
gradleParser.parseDependencies(input)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,23 @@ class RewriteTest extends FunSuite {
runApplyUpdate(update, original, expected)
}

test("Gradle Version Catalog") {
val update = ("org.tomlj".g % "tomlj".a % "1.0.0" %> "1.1.1").single
val original = Map(
"gradle/libs.version.toml" ->
"""|[libraries]
|tomlj = { group = "org.tomlj", name = "tomlj", version = "1.0.0" }
|""".stripMargin
)
val expected = Map(
"gradle/libs.version.toml" ->
"""|[libraries]
|tomlj = { group = "org.tomlj", name = "tomlj", version = "1.1.1" }
|""".stripMargin
)
runApplyUpdate(update, original, expected)
}

private def runApplyUpdate(
update: Update.Single,
files: Map[String, String],
Expand Down
1 change: 1 addition & 0 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ object Dependencies {
val scalaStewardMillPluginArtifactName = "scala-steward-mill-plugin"
val scalaStewardMillPlugin =
"org.scala-steward" % s"${scalaStewardMillPluginArtifactName}_mill0.10_2.13" % "0.18.0"
val tomlj = "org.tomlj" % "tomlj" % "1.1.1"
}

0 comments on commit 6dbcf50

Please sign in to comment.