diff --git a/docs/help.md b/docs/help.md index a8c501bcd8..86dff335e2 100644 --- a/docs/help.md +++ b/docs/help.md @@ -37,4 +37,5 @@ All command line arguments for the `scala-steward` application. --github-app-key-file FILE Github application key file --github-app-id ID Github application id --refresh-backoff-period DURATION Period of time a failed build won't be triggered again, default: "7 days" + --default-branch BRANCH A fixed branch name to use as default instead of the repository's default branch ``` diff --git a/modules/core/src/main/scala/org/scalasteward/core/application/Cli.scala b/modules/core/src/main/scala/org/scalasteward/core/application/Cli.scala index 6ec5044712..cca00a32cf 100644 --- a/modules/core/src/main/scala/org/scalasteward/core/application/Cli.scala +++ b/modules/core/src/main/scala/org/scalasteward/core/application/Cli.scala @@ -59,7 +59,8 @@ object Cli { githubAppId: Option[Long] = None, urlCheckerTestUrl: Option[Uri] = None, defaultMavenRepo: Option[String] = None, - refreshBackoffPeriod: FiniteDuration = 7.days + refreshBackoffPeriod: FiniteDuration = 7.days, + defaultBranch: Option[String] = None ) final case class EnvVar(name: String, value: String) diff --git a/modules/core/src/main/scala/org/scalasteward/core/application/Config.scala b/modules/core/src/main/scala/org/scalasteward/core/application/Config.scala index ead4eae5c4..74b2f25473 100644 --- a/modules/core/src/main/scala/org/scalasteward/core/application/Config.scala +++ b/modules/core/src/main/scala/org/scalasteward/core/application/Config.scala @@ -33,6 +33,7 @@ import org.scalasteward.core.vcs.VCSType import org.scalasteward.core.vcs.data.AuthenticatedUser import org.scalasteward.core.vcs.github.GitHubApp import scala.concurrent.duration.FiniteDuration +import org.scalasteward.core.git.Branch /** Configuration for scala-steward. * @@ -77,7 +78,8 @@ final case class Config( githubApp: Option[GitHubApp], urlCheckerTestUrl: Uri, defaultResolver: Resolver, - refreshBackoffPeriod: FiniteDuration + refreshBackoffPeriod: FiniteDuration, + defaultBranch: Option[Branch] ) { def vcsUser[F[_]](implicit processAlg: ProcessAlg[F], @@ -167,6 +169,7 @@ object Config { defaultResolver = args.defaultMavenRepo .map(url => Resolver.MavenRepository("default", url, None)) .getOrElse(Resolver.mavenCentral), - refreshBackoffPeriod = args.refreshBackoffPeriod + refreshBackoffPeriod = args.refreshBackoffPeriod, + defaultBranch = args.defaultBranch.map(Branch(_)) ) } diff --git a/modules/core/src/main/scala/org/scalasteward/core/repocache/RepoCacheAlg.scala b/modules/core/src/main/scala/org/scalasteward/core/repocache/RepoCacheAlg.scala index 9c69adde67..a08633dd20 100644 --- a/modules/core/src/main/scala/org/scalasteward/core/repocache/RepoCacheAlg.scala +++ b/modules/core/src/main/scala/org/scalasteward/core/repocache/RepoCacheAlg.scala @@ -43,7 +43,11 @@ final class RepoCacheAlg[F[_]](config: Config)(implicit logger.info(s"Check cache of ${repo.show}") >> refreshErrorAlg.skipIfFailedRecently(repo) { ( - vcsApiAlg.createForkOrGetRepoWithDefaultBranch(repo, config.doNotFork), + vcsApiAlg.createForkOrGetRepoWithDefaultBranch( + repo, + config.doNotFork, + config.defaultBranch + ), repoCacheRepository.findCache(repo) ).parTupled.flatMap { case ((repoOut, branchOut), maybeCache) => val latestSha1 = branchOut.commit.sha diff --git a/modules/core/src/main/scala/org/scalasteward/core/vcs/VCSApiAlg.scala b/modules/core/src/main/scala/org/scalasteward/core/vcs/VCSApiAlg.scala index 0abc9ffe27..048621b0ad 100644 --- a/modules/core/src/main/scala/org/scalasteward/core/vcs/VCSApiAlg.scala +++ b/modules/core/src/main/scala/org/scalasteward/core/vcs/VCSApiAlg.scala @@ -42,13 +42,26 @@ trait VCSApiAlg[F[_]] { final def createForkOrGetRepo(repo: Repo, doNotFork: Boolean): F[RepoOut] = if (doNotFork) getRepo(repo) else createFork(repo) - final def createForkOrGetRepoWithDefaultBranch(repo: Repo, doNotFork: Boolean)(implicit + final def createForkOrGetRepoWithDefaultBranch( + repo: Repo, + doNotFork: Boolean, + defaultBranch: Option[Branch] + )(implicit F: MonadThrow[F] ): F[(RepoOut, BranchOut)] = for { forkOrRepo <- createForkOrGetRepo(repo, doNotFork) - defaultBranch <- getDefaultBranchOfParentOrRepo(forkOrRepo, doNotFork) - } yield (forkOrRepo, defaultBranch) + forkOrRepoWithDefaultBranch = applyDefaultBranch(forkOrRepo, defaultBranch) + defaultBranch <- getDefaultBranchOfParentOrRepo(forkOrRepoWithDefaultBranch, doNotFork) + } yield (forkOrRepoWithDefaultBranch, defaultBranch) + + final def applyDefaultBranch(repoOut: RepoOut, defaultBranch: Option[Branch]): RepoOut = + defaultBranch.fold(repoOut) { branch => + repoOut.copy( + default_branch = branch, + parent = repoOut.parent.map(_.copy(default_branch = branch)) + ) + } final def getDefaultBranchOfParentOrRepo(repoOut: RepoOut, doNotFork: Boolean)(implicit F: MonadThrow[F] diff --git a/modules/core/src/main/scala/org/scalasteward/core/vcs/VCSRepoAlg.scala b/modules/core/src/main/scala/org/scalasteward/core/vcs/VCSRepoAlg.scala index d34bbe4ac7..b2203faab2 100644 --- a/modules/core/src/main/scala/org/scalasteward/core/vcs/VCSRepoAlg.scala +++ b/modules/core/src/main/scala/org/scalasteward/core/vcs/VCSRepoAlg.scala @@ -40,7 +40,9 @@ final class VCSRepoAlg[F[_]](config: Config)(implicit private def clone(repo: Repo, repoOut: RepoOut): F[Unit] = logger.info(s"Clone ${repoOut.repo.show}") >> gitAlg.clone(repo, withLogin(repoOut.clone_url)) >> - gitAlg.setAuthor(repo, config.gitCfg.gitAuthor) + gitAlg.setAuthor(repo, config.gitCfg.gitAuthor) >> config.defaultBranch.fold(F.unit)( + gitAlg.checkoutBranch(repo, _) + ) private def syncFork(repo: Repo, repoOut: RepoOut): F[Unit] = repoOut.parentOrRaise[F].flatMap { parent => diff --git a/modules/core/src/test/scala/org/scalasteward/core/application/CliTest.scala b/modules/core/src/test/scala/org/scalasteward/core/application/CliTest.scala index 4fe50b5b23..f8d4fc7e84 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/application/CliTest.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/application/CliTest.scala @@ -29,7 +29,8 @@ class CliTest extends FunSuite { List("--artifact-migrations", "/opt/scala-steward/extra-artifact-migrations.conf"), List("--github-app-id", "12345678"), List("--github-app-key-file", "example_app_key"), - List("--refresh-backoff-period", "1 day") + List("--refresh-backoff-period", "1 day"), + List("--default-branch", "1.x") ).flatten ) val expected = Success( @@ -50,7 +51,8 @@ class CliTest extends FunSuite { artifactMigrations = Some(File("/opt/scala-steward/extra-artifact-migrations.conf")), githubAppId = Some(12345678), githubAppKeyFile = Some(File("example_app_key")), - refreshBackoffPeriod = 1.day + refreshBackoffPeriod = 1.day, + defaultBranch = Some("1.x") ) ) assertEquals(obtained, expected) diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucket/BitbucketApiAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucket/BitbucketApiAlgTest.scala index bae9fa3d69..a51205b4bf 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucket/BitbucketApiAlgTest.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucket/BitbucketApiAlgTest.scala @@ -71,6 +71,15 @@ class BitbucketApiAlgTest extends FunSuite { } }""" ) + case GET -> Root / "repositories" / "fthomas" / "base.g8" / "refs" / "branches" / "custom" => + Ok( + json"""{ + "name": "custom", + "target": { + "hash": "12ea4559063c74184861afece9eeff5ca9d33db3" + } + }""" + ) case POST -> Root / "repositories" / "fthomas" / "base.g8" / "forks" => Ok( json"""{ @@ -161,6 +170,7 @@ class BitbucketApiAlgTest extends FunSuite { private val prUrl = uri"https://bitbucket.org/fthomas/base.g8/pullrequests/2" private val repo = Repo("fthomas", "base.g8") private val master = Branch("master") + private val custom = Branch("custom") private val parent = RepoOut( "base.g8", UserOut("fthomas"), @@ -169,6 +179,14 @@ class BitbucketApiAlgTest extends FunSuite { master ) + private val parentWithCustomDefaultBranch = RepoOut( + "base.g8", + UserOut("fthomas"), + None, + uri"https://scala-steward@bitbucket.org/fthomas/base.g8.git", + custom + ) + private val fork = RepoOut( "base.g8", UserOut("scala-steward"), @@ -177,11 +195,24 @@ class BitbucketApiAlgTest extends FunSuite { master ) + private val forkWithCustomDefaultBranch = RepoOut( + "base.g8", + UserOut("scala-steward"), + Some(parentWithCustomDefaultBranch), + uri"https://scala-steward@bitbucket.org/scala-steward/base.g8.git", + custom + ) + private val defaultBranch = BranchOut( master, CommitOut(Sha1(HexString.unsafeFrom("07eb2a203e297c8340273950e98b2cab68b560c1"))) ) + private val defaultCustomBranch = BranchOut( + custom, + CommitOut(Sha1(HexString.unsafeFrom("12ea4559063c74184861afece9eeff5ca9d33db3"))) + ) + private val pullRequest = PullRequestOut(prUrl, PullRequestState.Open, PullRequestNumber(2), "scala-steward-pr") @@ -197,18 +228,40 @@ class BitbucketApiAlgTest extends FunSuite { test("createForkOrGetRepoWithDefaultBranch") { val (repoOut, branchOut) = - bitbucketApiAlg.createForkOrGetRepoWithDefaultBranch(repo, doNotFork = false).unsafeRunSync() + bitbucketApiAlg + .createForkOrGetRepoWithDefaultBranch(repo, doNotFork = false, defaultBranch = None) + .unsafeRunSync() assertEquals(repoOut, fork) assertEquals(branchOut, defaultBranch) } + test("createForkOrGetRepoWithDefaultBranch with custom default branch") { + val (repoOut, branchOut) = + bitbucketApiAlg + .createForkOrGetRepoWithDefaultBranch(repo, doNotFork = false, defaultBranch = Some(custom)) + .unsafeRunSync() + assertEquals(repoOut, forkWithCustomDefaultBranch) + assertEquals(branchOut, defaultCustomBranch) + } + test("createForkOrGetRepoWithDefaultBranch without forking") { val (repoOut, branchOut) = - bitbucketApiAlg.createForkOrGetRepoWithDefaultBranch(repo, doNotFork = true).unsafeRunSync() + bitbucketApiAlg + .createForkOrGetRepoWithDefaultBranch(repo, doNotFork = true, defaultBranch = None) + .unsafeRunSync() assertEquals(repoOut, parent) assertEquals(branchOut, defaultBranch) } + test("createForkOrGetRepoWithDefaultBranch without forking with custom default branch") { + val (repoOut, branchOut) = + bitbucketApiAlg + .createForkOrGetRepoWithDefaultBranch(repo, doNotFork = true, defaultBranch = Some(custom)) + .unsafeRunSync() + assertEquals(repoOut, parentWithCustomDefaultBranch) + assertEquals(branchOut, defaultCustomBranch) + } + test("createPullRequest") { val data = NewPullRequestData( "scala-steward-pr", diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/github/GitHubApiAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/github/GitHubApiAlgTest.scala index a338fcf889..8a6b5edc1c 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/vcs/github/GitHubApiAlgTest.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/github/GitHubApiAlgTest.scala @@ -36,6 +36,14 @@ class GitHubApiAlgTest extends FunSuite { } """ ) + case GET -> Root / "repos" / "fthomas" / "base.g8" / "branches" / "custom" => + Ok( + json""" { + "name": "custom", + "commit": { "sha": "12ea4559063c74184861afece9eeff5ca9d33db3" } + } """ + ) + case GET -> Root / "repos" / "fthomas" / "base.g8" / "pulls" => Ok( json"""[{ @@ -96,6 +104,14 @@ class GitHubApiAlgTest extends FunSuite { Branch("master") ) + private val parentWithCustomDefaultBranch = RepoOut( + "base.g8", + UserOut("fthomas"), + None, + uri"https://github.com/fthomas/base.g8.git", + Branch("custom") + ) + private val fork = RepoOut( "base.g8-1", UserOut("scala-steward"), @@ -104,11 +120,24 @@ class GitHubApiAlgTest extends FunSuite { Branch("master") ) + private val forkWithCustomDefaultBranch = RepoOut( + "base.g8-1", + UserOut("scala-steward"), + Some(parentWithCustomDefaultBranch), + uri"https://github.com/scala-steward/base.g8-1.git", + Branch("custom") + ) + private val defaultBranch = BranchOut( Branch("master"), CommitOut(Sha1(HexString("07eb2a203e297c8340273950e98b2cab68b560c1"))) ) + private val defaultCustomBranch = BranchOut( + Branch("custom"), + CommitOut(Sha1(HexString("12ea4559063c74184861afece9eeff5ca9d33db3"))) + ) + test("createForkOrGetRepo") { val repoOut = gitHubApiAlg.createForkOrGetRepo(repo, doNotFork = false).unsafeRunSync() assertEquals(repoOut, fork) @@ -121,18 +150,48 @@ class GitHubApiAlgTest extends FunSuite { test("createForkOrGetRepoWithDefaultBranch") { val (repoOut, branchOut) = - gitHubApiAlg.createForkOrGetRepoWithDefaultBranch(repo, doNotFork = false).unsafeRunSync() + gitHubApiAlg + .createForkOrGetRepoWithDefaultBranch(repo, doNotFork = false, defaultBranch = None) + .unsafeRunSync() assertEquals(repoOut, fork) assertEquals(branchOut, defaultBranch) } + test("createForkOrGetRepoWithDefaultBranch") { + val (repoOut, branchOut) = + gitHubApiAlg + .createForkOrGetRepoWithDefaultBranch( + repo, + doNotFork = false, + defaultBranch = Some(Branch("custom")) + ) + .unsafeRunSync() + assertEquals(repoOut, forkWithCustomDefaultBranch) + assertEquals(branchOut, defaultCustomBranch) + } + test("createForkOrGetRepoWithDefaultBranch without forking") { val (repoOut, branchOut) = - gitHubApiAlg.createForkOrGetRepoWithDefaultBranch(repo, doNotFork = true).unsafeRunSync() + gitHubApiAlg + .createForkOrGetRepoWithDefaultBranch(repo, doNotFork = true, defaultBranch = None) + .unsafeRunSync() assertEquals(repoOut, parent) assertEquals(branchOut, defaultBranch) } + test("createForkOrGetRepoWithDefaultBranch without forking with custom default branch") { + val (repoOut, branchOut) = + gitHubApiAlg + .createForkOrGetRepoWithDefaultBranch( + repo, + doNotFork = true, + defaultBranch = Some(Branch("custom")) + ) + .unsafeRunSync() + assertEquals(repoOut, parentWithCustomDefaultBranch) + assertEquals(branchOut, defaultCustomBranch) + } + test("closePullRequest") { val prOut = gitHubApiAlg.closePullRequest(repo, PullRequestNumber(1347)).unsafeRunSync() assertEquals(prOut.state, PullRequestState.Closed)