Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor erroring system #117

Merged
merged 19 commits into from
Apr 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import com.alejandrohdezma.sbt.github.http.Authentication
* This will only happen during the release stage in Travis CI, since its only
* needed during this phase.
*/
@SuppressWarnings(Array("scalafix:DisableSyntax.=="))
@SuppressWarnings(Array("scalafix:DisableSyntax.==", "scalafix:Disable.get"))
object SbtGithubPlugin extends AutoPlugin {

object autoImport {
Expand Down Expand Up @@ -128,7 +128,7 @@ object SbtGithubPlugin extends AutoPlugin {
implicit val entryPoint: GithubEntryPoint = GithubEntryPoint(githubApiEntryPoint.value)
implicit val auth: Authentication = githubToken.value

Some(Repository.get(info.value._1, info.value._2).fold(sys.error, identity))
Some(Repository.get(info.value._1, info.value._2).get)
}
else Def.setting(None)
}.value,
Expand All @@ -142,21 +142,20 @@ object SbtGithubPlugin extends AutoPlugin {
.filter(_ => populateOrganizationWithOwner.value)
.map(_.owner.map(_.asOrganization))
}
.map(_.fold(sys.error, identity))
.map(_.get)
},
contributors := {
implicit val log: Logger = sLog.value
implicit val auth: Authentication = githubToken.value
repository.value.fold(Contributors(Nil)) {
_.contributors(excludedContributors.value).fold(sys.error, identity)
_.contributors(excludedContributors.value).get
}
},
collaborators := {
implicit val log: Logger = sLog.value
implicit val auth: Authentication = githubToken.value
repository.value.fold(Collaborators(Nil)) {
_.collaborators(contributors.value.list.map(_.login))
.fold(sys.error, identity)
_.collaborators(contributors.value.list.map(_.login)).get
.include(
extraCollaborators.value.map(_(auth)(GithubEntryPoint(githubApiEntryPoint.value))(log))
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.alejandrohdezma.sbt.github.error

import scala.util.control.NoStackTrace

case object NotFound extends Throwable("Unable to found") with NoStackTrace
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package com.alejandrohdezma.sbt.github.github

import sbt.util.Logger

import com.alejandrohdezma.sbt.github.github.urls.GithubEntryPoint
import com.alejandrohdezma.sbt.github.github.urls.{GithubEntryPoint, UserEntryPoint}
import com.alejandrohdezma.sbt.github.http.{client, Authentication}
import com.alejandrohdezma.sbt.github.json.Decoder
import com.alejandrohdezma.sbt.github.syntax.json._
Expand All @@ -35,16 +35,22 @@ final case class Collaborator private[github] (

object Collaborator {

/** Obtains a collaborator information from its Github login ID */
/**
* Obtains a collaborator information from its Github login ID
*/
@SuppressWarnings(Array("scalafix:Disable.get"))
def github(id: String): Authentication => GithubEntryPoint => Logger => Collaborator = {
implicit auth => implicit entrypoint => implicit log =>
val userUrl = implicitly[urls.User].get(id)
val userUrl = implicitly[UserEntryPoint].get(id)

log.info(s"Retrieving `$id` information from Github API")

client.get[User](userUrl).map { user =>
new Collaborator(user.login, user.url, userUrl, user.name, user.email, user.avatar)
} fold (_ => sys.error(s"Unable to get info for user $id"), identity)
client
.get[User](userUrl)
.map(user =>
new Collaborator(user.login, user.url, userUrl, user.name, user.email, user.avatar)
)
.get
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@ package com.alejandrohdezma.sbt.github.github

import java.time.ZonedDateTime

import scala.util.Try

import sbt.URL
import sbt.util.Logger

import com.alejandrohdezma.sbt.github.error.NotFound
import com.alejandrohdezma.sbt.github.github.error.GithubError
import com.alejandrohdezma.sbt.github.github.urls.RepositoryEntryPoint
import com.alejandrohdezma.sbt.github.http.{client, Authentication}
import com.alejandrohdezma.sbt.github.json.Decoder
import com.alejandrohdezma.sbt.github.json.Json.Fail.NotFound
import com.alejandrohdezma.sbt.github.syntax.either._
import com.alejandrohdezma.sbt.github.syntax.json._
import com.alejandrohdezma.sbt.github.syntax.list._
import com.alejandrohdezma.sbt.github.syntax.scalatry._

/** Represents a repository in Github */
final case class Repository(
Expand All @@ -53,15 +57,15 @@ final case class Repository(
*/
def contributors(
excluded: List[String]
)(implicit auth: Authentication, logger: Logger): Either[String, Contributors] = {
)(implicit auth: Authentication, logger: Logger): Try[Contributors] = {
logger.info(s"Retrieving `$name` contributors from Github API")

client
.get[List[Contributor]](contributorsUrl)
.map(_.sortBy(-_.contributions))
.map(_.filterNot(contributor => excluded.exists(contributor.login.matches)))
.map(Contributors)
.leftMap(_ => "Unable to get repository contributors")
.failAs(GithubError("Unable to get repository contributors"))
}

/**
Expand All @@ -71,7 +75,7 @@ final case class Repository(
def collaborators(allowed: List[String])(
implicit auth: Authentication,
logger: Logger
): Either[String, Collaborators] = {
): Try[Collaborators] = {
logger.info(s"Retrieving `$name` collaborators from Github API")

client
Expand All @@ -86,7 +90,7 @@ final case class Repository(
})
.map(_.sortBy(collaborator => collaborator.name -> collaborator.login))
.map(Collaborators)
.leftMap(_ => "Unable to get repository collaborators")
.failAs(GithubError("Unable to get repository collaborators"))
}

/**
Expand All @@ -95,21 +99,21 @@ final case class Repository(
def organization(
implicit auth: Authentication,
logger: Logger
): Option[Either[String, Organization]] = {
): Option[Try[Organization]] = {
logger.info(s"Retrieving `$name` organization from Github API")

organizationUrl
.map(client.get[Organization])
.map(_.leftMap(_ => "Unable to get repository organization"))
.map(_.failAs(GithubError("Unable to get repository organization")))
}

/**
* Returns the repository's owner information.
*/
def owner(implicit auth: Authentication, logger: Logger): Either[String, User] = {
def owner(implicit auth: Authentication, logger: Logger): Try[User] = {
logger.info(s"Retrieving `$name` owner from Github API")

client.get[User](ownerUrl).leftMap(_ => "Unable to get repository owner")
client.get[User](ownerUrl).failAs(GithubError("Unable to get repository owner"))
}

}
Expand All @@ -120,21 +124,29 @@ object Repository {
def get(owner: String, name: String)(
implicit auth: Authentication,
logger: Logger,
url: urls.Repository
): Either[String, Repository] = {
url: RepositoryEntryPoint
): Try[Repository] = {
logger.info(s"Retrieving `$owner/$name` information from Github API")

client.get[Repository](url.get(owner, name)).leftMap {
case "description" / NotFound =>
s"Repository doesn't have a description! Go to https://github.com/$owner/$name and add it"
case "license" / NotFound =>
s"Repository doesn't have a license! Go to https://github.com/$owner/$name and add it"
case "license" / ("spdx_id" / NotFound) =>
s"Repository's license id couldn't be inferred! Go to https://github.com/$owner/$name and check it"
case "license" / ("url" / NotFound) =>
s"Repository's license url couldn't be inferred! Go to https://github.com/$owner/$name and check it"
case _ => "Unable to get repository information"
}
val descriptionNotFound =
s"Repository doesn't have a description! Go to https://github.com/$owner/$name and add it"
val licenseNotFound =
s"Repository doesn't have a license! Go to https://github.com/$owner/$name and add it"
val licenseNotInferred =
s"Repository's license id couldn't be inferred! Go to https://github.com/$owner/$name and check it"
val urlNotInferred =
s"Repository's license url couldn't be inferred! Go to https://github.com/$owner/$name and check it"

client
.get[Repository](url.get(owner, name))
.failMap {
case "description" / NotFound => GithubError(descriptionNotFound)
case "license" / NotFound => GithubError(licenseNotFound)
case "license" / ("spdx_id" / NotFound) => GithubError(licenseNotInferred)
case "license" / ("url" / NotFound) => GithubError(urlNotInferred)
case _ => GithubError("Unable to get repository information")
}

}

implicit val RepositoryDecoder: Decoder[Repository] = json =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.alejandrohdezma.sbt.github.github.error

import scala.util.control.NoStackTrace

final case class GithubError(msg: String) extends Throwable(msg) with NoStackTrace
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,33 @@ package com.alejandrohdezma.sbt.github.github.urls

import sbt.util.Logger

import com.alejandrohdezma.sbt.github.github.error.GithubError
import com.alejandrohdezma.sbt.github.http._
import com.alejandrohdezma.sbt.github.json.Decoder
import com.alejandrohdezma.sbt.github.syntax.json._
import com.alejandrohdezma.sbt.github.syntax.scalatry._

final case class Repository(base: String) {
final case class RepositoryEntryPoint(base: String) {

def get(owner: String, repo: String): String =
base.replace("{owner}", owner).replace("{repo}", repo)

}

object Repository {
object RepositoryEntryPoint {

@SuppressWarnings(Array("scalafix:Disable.get"))
implicit def repository(
implicit auth: Authentication,
logger: Logger,
entryPoint: GithubEntryPoint
): Repository =
): RepositoryEntryPoint =
client
.get[Repository](entryPoint.value)
.getOrElse(sys.error("Unable to connect to Github"))
.get[RepositoryEntryPoint](entryPoint.value)
.failAs(GithubError("Unable to connect to Github"))
.get

implicit val RepositoryUrlDecoder: Decoder[Repository] = json =>
json.get[String]("repository_url").map(Repository(_))
implicit val RepositoryUrlDecoder: Decoder[RepositoryEntryPoint] = json =>
json.get[String]("repository_url").map(RepositoryEntryPoint(_))

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,32 @@ package com.alejandrohdezma.sbt.github.github.urls

import sbt.util.Logger

import com.alejandrohdezma.sbt.github.github.error.GithubError
import com.alejandrohdezma.sbt.github.http.{client, Authentication}
import com.alejandrohdezma.sbt.github.json.Decoder
import com.alejandrohdezma.sbt.github.syntax.json._
import com.alejandrohdezma.sbt.github.syntax.scalatry._

final case class User(base: String) {
final case class UserEntryPoint(base: String) {

def get(login: String): String = base.replace("{user}", login)

}

object User {
object UserEntryPoint {

@SuppressWarnings(Array("scalafix:Disable.get"))
implicit def user(
implicit auth: Authentication,
logger: Logger,
entryPoint: GithubEntryPoint
): User =
): UserEntryPoint =
client
.get[User](entryPoint.value)
.getOrElse(sys.error("Unable to connect to Github"))
.get[UserEntryPoint](entryPoint.value)
.failAs(GithubError("Unable to connect to Github"))
.get

implicit val UserUrlDecoder: Decoder[User] = json => json.get[String]("user_url").map(User(_))
implicit val UserUrlDecoder: Decoder[UserEntryPoint] = json =>
json.get[String]("user_url").map(UserEntryPoint(_))

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,13 @@ import java.util.concurrent.ConcurrentHashMap

import scala.io.Source
import scala.util.Try
import scala.util.control.NonFatal

import sbt.util.Logger

import com.alejandrohdezma.sbt.github.json.Json.Fail.URLNotFound
import com.alejandrohdezma.sbt.github.json.Json.{Fail, Result}
import com.alejandrohdezma.sbt.github.http.error.URLNotFound
import com.alejandrohdezma.sbt.github.json.{Decoder, Json}
import com.alejandrohdezma.sbt.github.syntax.either._
import com.alejandrohdezma.sbt.github.syntax.json._
import com.alejandrohdezma.sbt.github.syntax.scalatry._

object client {

Expand All @@ -39,7 +37,7 @@ object client {
* returns its contents as `String`.
*/
@SuppressWarnings(Array("all"))
def get[A: Decoder](uri: String)(implicit auth: Authentication, logger: Logger): Result[A] =
def get[A: Decoder](uri: String)(implicit auth: Authentication, logger: Logger): Try[A] =
Try {
logger.verbose(s"Getting content from URL: $uri")

Expand All @@ -62,15 +60,9 @@ object client {
Source.fromInputStream(inputStream, "UTF-8").mkString
}
)
}.toEither.leftMap {
}.failMap {
case _: FileNotFoundException => URLNotFound(uri)
case NonFatal(t) => Fail.Unknown(t)
}.flatMap(Json.parse).as[A].onLeft {
case f @ Fail.Unknown(cause) =>
logger.error(f.readableMessage)
logger.trace(cause)
case fail => logger.error(fail.readableMessage)
}
}.flatMap(Json.parse).as[A]

private val cache: ConcurrentHashMap[String, String] = new ConcurrentHashMap[String, String]()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.alejandrohdezma.sbt.github.http.error

import scala.util.control.NoStackTrace

final case class URLNotFound(url: String)
extends Throwable(s"$url was not found (maybe there's no connection to the internet)")
with NoStackTrace
Loading