Skip to content

Commit f17d24a

Browse files
committed
Load artifact migrations from this repository
This splits `ArtifactMigrations` into a loader and finder class. The former loads the latest artifact migrations from this repository instead of using the static list of migrations that is shipped as resource in the JAR. That means that all Scala Steward instances use the artifact migrations from this repository as soon as they are added here. The following changes with this PR: * The `--artifact-migrations` option can now be used multiple times to load extra migrations not only from one but multiple files. * Arguments to the `--artifact-migrations` cannot only be local files but also remote URLs. * Scala Steward prints how many artifact migrations it loaded at start-up. The same has been done for Scalafix migrations in #1650. Closes: #1963
1 parent a890c3d commit f17d24a

File tree

15 files changed

+336
-271
lines changed

15 files changed

+336
-271
lines changed

docs/artifact-migrations.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
Scala Steward can look for newer versions of artifacts with different group Ids, artifact ids, or both different.
44

5-
## Adding artifact migration rules to Scala Steward
5+
## Adding artifact migrations to Scala Steward
66

7-
By default, scala-steward applies the artifact migrations rules defined in the [default list][migrations]. When running
8-
Scala Steward you can also specify a file (via the `--artifact-migrations` command-line option) that contains
9-
additional migrations.
10-
11-
These files are in [HOCON][HOCON] format and should look like this:
7+
By default, Scala Steward applies the artifact migrations defined in the
8+
[default list][migrations]. When running Scala Steward you can also specify
9+
files or URLs (via the `--artifact-migrations` command-line option) that
10+
contain additional migrations. These files are in [HOCON][HOCON] format and
11+
should look like this:
1212
```hocon
1313
changes = [
1414
{
@@ -28,5 +28,8 @@ The fields `groupIdBefore` and `artifactIdBefore` are optional. If just `groupId
2828
example, then only the group id will get renamed. If just `artifactIdBefore` is specified, then only the artifact id
2929
will get renamed. Specifying both `groupIdBefore` and `artifactIdBefore` will rename both.
3030

31+
Pull requests that added artifact migrations can be found [here][migration-prs].
32+
3133
[migrations]: https://github.com/scala-steward-org/scala-steward/blob/master/modules/core/src/main/resources/artifact-migrations.conf
32-
[HOCON]: https://github.com/lightbend/config/blob/master/HOCON.md
34+
[migration-prs]: https://github.com/scala-steward-org/scala-steward/pulls?q=label%3Aartifact-migration
35+
[HOCON]: https://github.com/lightbend/config/blob/master/HOCON.md

modules/core/src/main/scala/org/scalasteward/core/application/Cli.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ object Cli {
5151
maxBufferSize: Int = 8192,
5252
scalafixMigrations: List[Uri] = Nil,
5353
disableDefaultScalafixMigrations: Boolean = false,
54-
artifactMigrations: Option[File] = None,
54+
artifactMigrations: List[Uri] = Nil,
5555
cacheTtl: FiniteDuration = 2.hours,
5656
bitbucketServerUseDefaultReviewers: Boolean = false,
5757
gitlabMergeWhenPipelineSucceeds: Boolean = false,

modules/core/src/main/scala/org/scalasteward/core/application/Config.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ final case class Config(
7070
ignoreOptsFiles: Boolean,
7171
processCfg: ProcessCfg,
7272
scalafixCfg: ScalafixCfg,
73-
artifactMigrations: Option[File],
73+
artifactMigrations: List[Uri],
7474
cacheTtl: FiniteDuration,
7575
bitbucketServerCfg: BitbucketServerCfg,
7676
gitLabCfg: GitLabCfg,

modules/core/src/main/scala/org/scalasteward/core/application/Context.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ import org.scalasteward.core.persistence.{CachingKeyValueStore, JsonKeyValueStor
3737
import org.scalasteward.core.repocache._
3838
import org.scalasteward.core.repoconfig.RepoConfigAlg
3939
import org.scalasteward.core.scalafmt.ScalafmtAlg
40-
import org.scalasteward.core.update.{ArtifactMigrations, FilterAlg, PruningAlg, UpdateAlg}
40+
import org.scalasteward.core.update.artifact.{ArtifactMigrationsFinder, ArtifactMigrationsLoader}
41+
import org.scalasteward.core.update.{FilterAlg, PruningAlg, UpdateAlg}
4142
import org.scalasteward.core.util._
4243
import org.scalasteward.core.util.uri._
4344
import org.scalasteward.core.vcs.data.Repo
@@ -96,7 +97,8 @@ object Context {
9697
for {
9798
_ <- printBanner[F]
9899
vcsUser <- config.vcsUser[F]
99-
artifactMigrations0 <- ArtifactMigrations.create[F](config)
100+
artifactMigrationsLoader0 = new ArtifactMigrationsLoader[F]
101+
artifactMigrationsFinder0 <- artifactMigrationsLoader0.createFinder(config.artifactMigrations)
100102
scalafixMigrationsLoader0 = new ScalafixMigrationsLoader[F]
101103
scalafixMigrationsFinder0 <- scalafixMigrationsLoader0.createFinder(config.scalafixCfg)
102104
urlChecker0 <- UrlChecker.create[F](config)
@@ -111,7 +113,7 @@ object Context {
111113
versionsStore <- JsonKeyValueStore
112114
.create[F, VersionsCache.Key, VersionsCache.Value]("versions", "2")
113115
} yield {
114-
implicit val artifactMigrations: ArtifactMigrations = artifactMigrations0
116+
implicit val artifactMigrationsFinder: ArtifactMigrationsFinder = artifactMigrationsFinder0
115117
implicit val scalafixMigrationsLoader: ScalafixMigrationsLoader[F] = scalafixMigrationsLoader0
116118
implicit val scalafixMigrationsFinder: ScalafixMigrationsFinder = scalafixMigrationsFinder0
117119
implicit val urlChecker: UrlChecker[F] = urlChecker0

modules/core/src/main/scala/org/scalasteward/core/update/ArtifactMigrations.scala

Lines changed: 0 additions & 117 deletions
This file was deleted.

modules/core/src/main/scala/org/scalasteward/core/update/UpdateAlg.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ import cats.syntax.all._
2121
import org.scalasteward.core.coursier.VersionsCache
2222
import org.scalasteward.core.data._
2323
import org.scalasteward.core.repoconfig.RepoConfig
24+
import org.scalasteward.core.update.artifact.ArtifactMigrationsFinder
2425
import org.scalasteward.core.util.Nel
2526
import scala.concurrent.duration.FiniteDuration
2627

2728
final class UpdateAlg[F[_]](implicit
29+
artifactMigrationsFinder: ArtifactMigrationsFinder,
2830
filterAlg: FilterAlg[F],
2931
versionsCache: VersionsCache[F],
30-
artifactMigrations: ArtifactMigrations,
3132
F: Monad[F]
3233
) {
3334
def findUpdate(
@@ -40,7 +41,7 @@ final class UpdateAlg[F[_]](implicit
4041
maybeNewerVersions = Nel.fromList(versions.filter(_ > current))
4142
maybeUpdate = maybeNewerVersions
4243
.map(vs => Update.Single(CrossDependency(dependency.value), vs.map(_.value)))
43-
.orElse(artifactMigrations.findUpdateWithRenamedArtifact(dependency.value))
44+
.orElse(artifactMigrationsFinder.findUpdateWithRenamedArtifact(dependency.value))
4445
} yield maybeUpdate
4546

4647
def findUpdates(
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2018-2021 Scala Steward contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.scalasteward.core.update.artifact
18+
19+
import io.circe.Decoder
20+
import io.circe.generic.extras.{semiauto, Configuration}
21+
import org.scalasteward.core.data.GroupId
22+
23+
final case class ArtifactChange(
24+
groupIdBefore: Option[GroupId],
25+
groupIdAfter: GroupId,
26+
artifactIdBefore: Option[String],
27+
artifactIdAfter: String,
28+
initialVersion: String
29+
)
30+
31+
object ArtifactChange {
32+
implicit val configuration: Configuration =
33+
Configuration.default.withDefaults
34+
35+
implicit val decoder: Decoder[ArtifactChange] =
36+
semiauto.deriveConfiguredDecoder
37+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2018-2021 Scala Steward contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.scalasteward.core.update.artifact
18+
19+
import io.circe.Decoder
20+
import io.circe.generic.extras.{semiauto, Configuration}
21+
22+
final case class ArtifactChanges(changes: List[ArtifactChange])
23+
24+
object ArtifactChanges {
25+
implicit val configuration: Configuration =
26+
Configuration.default.withDefaults
27+
28+
implicit val artifactChangesDecoder: Decoder[ArtifactChanges] =
29+
semiauto.deriveConfiguredDecoder
30+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2018-2021 Scala Steward contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.scalasteward.core.update.artifact
18+
19+
import cats.syntax.all._
20+
import org.scalasteward.core.data.{CrossDependency, Dependency, Update}
21+
import org.scalasteward.core.util.Nel
22+
23+
final class ArtifactMigrationsFinder(migrations: List[ArtifactChange]) {
24+
def findUpdateWithRenamedArtifact(dependency: Dependency): Option[Update.Single] =
25+
migrations
26+
.find { migration =>
27+
(migration.groupIdBefore, migration.artifactIdBefore) match {
28+
case (Some(groupId), Some(artifactId)) =>
29+
groupId === dependency.groupId &&
30+
artifactId === dependency.artifactId.name
31+
case (Some(groupId), None) =>
32+
groupId === dependency.groupId &&
33+
migration.artifactIdAfter === dependency.artifactId.name
34+
case (None, Some(artifactId)) =>
35+
migration.groupIdAfter === dependency.groupId &&
36+
artifactId === dependency.artifactId.name
37+
case (None, None) => false
38+
}
39+
}
40+
.map { migration =>
41+
Update.Single(
42+
CrossDependency(dependency),
43+
Nel.one(migration.initialVersion),
44+
Some(migration.groupIdAfter),
45+
Some(migration.artifactIdAfter)
46+
)
47+
}
48+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2018-2021 Scala Steward contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.scalasteward.core.update.artifact
18+
19+
import cats.MonadThrow
20+
import cats.syntax.all._
21+
import io.circe.config.parser.decode
22+
import org.http4s.Uri
23+
import org.http4s.implicits.http4sLiteralsSyntax
24+
import org.scalasteward.core.io.FileAlg
25+
import org.scalasteward.core.update.artifact.ArtifactMigrationsLoader.defaultArtifactMigrationsUrl
26+
import org.typelevel.log4cats.Logger
27+
28+
final class ArtifactMigrationsLoader[F[_]](implicit
29+
fileAlg: FileAlg[F],
30+
logger: Logger[F],
31+
F: MonadThrow[F]
32+
) {
33+
def createFinder(artifactMigrations: List[Uri]): F[ArtifactMigrationsFinder] =
34+
loadAll(artifactMigrations).map(new ArtifactMigrationsFinder(_))
35+
36+
def loadAll(artifactMigrations: List[Uri]): F[List[ArtifactChange]] =
37+
(defaultArtifactMigrationsUrl :: artifactMigrations)
38+
.flatTraverse(loadMigrations)
39+
.flatTap(migrations => logger.info(s"Loaded ${migrations.size} artifact migrations"))
40+
41+
private def loadMigrations(uri: Uri): F[List[ArtifactChange]] =
42+
logger.debug(s"Loading artifact migrations from $uri") >>
43+
fileAlg.readUri(uri).flatMap(decodeMigrations(_, uri)).map(_.changes)
44+
45+
private def decodeMigrations(content: String, uri: Uri): F[ArtifactChanges] =
46+
F.fromEither(decode[ArtifactChanges](content))
47+
.adaptErr(new Throwable(s"Failed to load artifact migrations from ${uri.renderString}", _))
48+
}
49+
50+
object ArtifactMigrationsLoader {
51+
val defaultArtifactMigrationsUrl: Uri =
52+
uri"https://raw.githubusercontent.com/scala-steward-org/scala-steward/master/modules/core/src/main/resources/artifact-migrations.conf"
53+
}

0 commit comments

Comments
 (0)