diff --git a/modules/core/src/main/scala/org/scalasteward/core/forge/bitbucket/RepositoryResponse.scala b/modules/core/src/main/scala/org/scalasteward/core/forge/bitbucket/RepositoryResponse.scala index d6af58a783..36aad7798a 100644 --- a/modules/core/src/main/scala/org/scalasteward/core/forge/bitbucket/RepositoryResponse.scala +++ b/modules/core/src/main/scala/org/scalasteward/core/forge/bitbucket/RepositoryResponse.scala @@ -23,6 +23,7 @@ import org.scalasteward.core.data.Repo import org.scalasteward.core.forge.data.UserOut import org.scalasteward.core.git.Branch import org.scalasteward.core.util.uri._ + import scala.annotation.tailrec final private[bitbucket] case class RepositoryResponse( @@ -44,29 +45,31 @@ private[bitbucket] object RepositoryResponse { } } - implicit val decoder: Decoder[RepositoryResponse] = Decoder.instance { c => - for { - name <- c.downField("name").as[String] - owner <- - c.downField("owner") - .downField("username") - .as[String] - .orElse(c.downField("owner").downField("nickname").as[String]) - cloneUrl <- - c.downField("links") - .downField("clone") - .downAt { p => - p.asObject - .flatMap(o => o("name")) - .flatMap(_.asString) - .contains("https") - } - .downField("href") - .as[Uri] - defaultBranch <- c.downField("mainbranch").downField("name").as[Branch] - maybeParent <- c.downField("parent").downField("full_name").as[Option[Repo]] - } yield RepositoryResponse(name, defaultBranch, UserOut(owner), cloneUrl, maybeParent) - } + implicit val decoder: Decoder[RepositoryResponse] = Decoder + .instance { c => + for { + name <- c.downField("name").as[String] + owner <- + c.downField("owner") + .downField("username") + .as[String] + .orElse(c.downField("owner").downField("nickname").as[String]) + cloneUrl <- + c.downField("links") + .downField("clone") + .downAt { p => + p.asObject + .flatMap(o => o("name")) + .flatMap(_.asString) + .contains("https") + } + .downField("href") + .as[Uri] + defaultBranch <- c.downField("mainbranch").downField("name").as[Branch] + maybeParent <- c.downField("parent").downField("full_name").as[Option[Repo]] + } yield RepositoryResponse(name, defaultBranch, UserOut(owner), cloneUrl, maybeParent) + } + .prepare(_.withFocus(_.dropNullValues)) /** Monkey patches the [[io.circe.ACursor]] class to get the `downAt` function back, which was * removed in version 0.12.0-M4. diff --git a/modules/core/src/test/scala/org/scalasteward/core/forge/bitbucket/BitbucketApiAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/forge/bitbucket/BitbucketApiAlgTest.scala index a98f104496..be66fa5d47 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/forge/bitbucket/BitbucketApiAlgTest.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/forge/bitbucket/BitbucketApiAlgTest.scala @@ -50,6 +50,28 @@ class BitbucketApiAlgTest extends CatsEffectSuite with Http4sDsl[MockEff] { } }""" ) + case GET -> Root / "repositories" / "null-parenthood" / "base.g8" => + Ok( + json"""{ + "name": "base.g8", + "mainbranch": { + "type": "branch", + "name": "master" + }, + "owner": { + "nickname": "fthomas" + }, + "links": { + "clone": [ + { + "href": "https://scala-steward@bitbucket.org/fthomas/base.g8.git", + "name": "https" + } + ] + }, + "parent": null + }""" + ) case GET -> Root / "repositories" / "scala-steward" / "base.g8" => Ok( json"""{ @@ -248,6 +270,13 @@ class BitbucketApiAlgTest extends CatsEffectSuite with Http4sDsl[MockEff] { assertIO(repoOut, parent) } + test("createForkOrGetRepo without forking - handle null parent") { + val repoOut = bitbucketApiAlg + .createForkOrGetRepo(Repo("null-parenthood", "base.g8"), doNotFork = true) + .runA(state) + assertIO(repoOut, parent) + } + test("createForkOrGetRepoWithBranch") { bitbucketApiAlg .createForkOrGetRepoWithBranch(repo, doNotFork = false)