Skip to content

Commit

Permalink
feat: 🎸 allow specific service name per file with git (#183)
Browse files Browse the repository at this point in the history
allow specific service name per file with git
  • Loading branch information
MaethorNaur committed Sep 13, 2020
1 parent 8b2410e commit 37c2fa1
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 26 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ src_managed/
project/boot/
project/plugins/project/
project/metals.sbt
project/project/metals.sbt
project/project/project/metals.sbt
.history
.cache
.lib/
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,8 @@ name: "Test"
specifications:
- "foo-service.yaml"
- "/openapi/bar-service.yaml"
- name: "Name used for this file"
path: "foobar.yaml"
```

```yaml
Expand All @@ -323,6 +325,10 @@ specifications:
# Example: "https://github.com/MyOrg/MyRepo" -> "MyOrg/MyOrg"
name = "service name"
# List of OpenApi spec files or directories
# This list can be a mixed of string (path)
# or an object:
# name: Name of this service
# path: Path of files
specifications = []
```

Expand Down
43 changes: 26 additions & 17 deletions providers/git/src/main/scala/restui/providers/git/git/Git.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ import io.circe.yaml.parser
import restui.Concurrency
import restui.models.{Metadata, Service}
import restui.providers.git._
import restui.providers.git.git.data.{Repository, RestUI}
import restui.providers.git.git.data._
import restui.providers.git.process.{Process, ProcessArgs}
import restui.providers.git.settings.{Location, RepositorySettings}

object Git extends LazyLogging {
private val GitCmd = "git"
private val DefaultBranch = "master"
private type RepositoryWithSha = (Repository, Option[String])
private type Files = (Repository, List[Path])
private type Files = (Repository, List[(Option[String], Path)])
private type FilesWithSha = (Files, Option[String])

private val outboundFlow: Flow[FilesWithSha, Service] =
Expand All @@ -45,7 +45,7 @@ object Git extends LazyLogging {
.asScala
.to(LazyList)
.filter(Files.isRegularFile(_))
.map(_.normalize)
.map(path => None -> path.normalize)
.toList
repository -> localFiles
}
Expand Down Expand Up @@ -81,7 +81,7 @@ object Git extends LazyLogging {
cacheDuration,
AkkaSource(repositories.collect {
case RepositorySettings(Location.Uri(uri), branch, specificationPaths) =>
Repository(uri, branch.getOrElse(DefaultBranch), specificationPaths)
Repository(uri, branch.getOrElse(DefaultBranch), specificationPaths.map(UnnamedSpecification(_)))
})
)

Expand Down Expand Up @@ -127,7 +127,7 @@ object Git extends LazyLogging {
execute("diff" :: "--name-only" :: sha1 :: "HEAD" :: Nil, repository.directory).flatMapConcat {
case Right(files) =>
val repoPath = repository.directory.get.toPath
AkkaSource.single(repository -> files.map(file => repoPath.resolve(Paths.get(file)).normalize))
AkkaSource.single(repository -> files.map(file => None -> repoPath.resolve(Paths.get(file)).normalize))
case Left(exception) =>
logger.warn(s"Error during changed: $exception")
AkkaSource.empty[Files]
Expand All @@ -151,12 +151,19 @@ object Git extends LazyLogging {
None
}

private def filterSpecificationsFiles(repo: Repository, files: List[Path]): List[Path] = {
val repoPath = repo.directory.get.toPath
val specificationPaths = repo.specificationPaths.map(repoPath.resolve(_).normalize)
files.filter { file =>
specificationPaths.exists { specificationPath =>
file.startsWith(specificationPath)
private def filterSpecificationsFiles(repo: Repository, files: List[(Option[String], Path)]): List[(Option[String], Path)] = {
val repoPath = repo.directory.get.toPath
val specificationPaths = repo.specificationPaths.map {
case UnnamedSpecification(path) => None -> repoPath.resolve(path).normalize
case NamedSpecification(name, path) => Some(name) -> repoPath.resolve(path).normalize
}
files.collect {
Function.unlift {
case (_, file) =>
specificationPaths.find {
case (_, specificationPath) =>
file.startsWith(specificationPath)
}.map { case (name, _) => name -> file }
}
}
}
Expand All @@ -167,10 +174,10 @@ object Git extends LazyLogging {
AkkaSource(files)
.flatMapMerge(Concurrency.AvailableCore, loadFile(_).async)
.map {
case (path, file) =>
case (maybeName, path, content) =>
val uri = akka.http.scaladsl.model.Uri(repo.uri)
val nameFromUri = uri.path.toString.substring(1)
val serviceName = repo.serviceName.getOrElse(nameFromUri)
val serviceName = maybeName.getOrElse(repo.serviceName.getOrElse(nameFromUri))
val filePath = repo.directory.get.toPath.relativize(path).toString
val id = s"$nameFromUri:$filePath"
val provider = uri.authority.host.address.split('.').head
Expand All @@ -179,18 +186,20 @@ object Git extends LazyLogging {
Metadata.Provider -> provider,
Metadata.File -> filePath
)
Service(id, serviceName, file, metadata)
Service(id, serviceName, content, metadata)
}
.async

}

private def loadFile(path: Path): Source[(Path, String)] =
private def loadFile(file: (Option[String], Path)): Source[(Option[String], Path, String)] = {
val (name, path) = file
Try(new String(Files.readAllBytes(path), StandardCharsets.UTF_8)) match {
case Success(content) =>
AkkaSource.single(path -> content)
AkkaSource.single((name, path, content))
case Failure(exception) =>
logger.warn(s"Error while reading $path", exception)
AkkaSource.empty[(Path, String)]
AkkaSource.empty[(Option[String], Path, String)]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,43 @@ package restui.providers.git.git

import java.io.File

import cats.syntax.functor._
import io.circe.generic.auto._
import io.circe.{Decoder, HCursor}

package object data {
final case class Repository(uri: String,
branch: String,
specificationPaths: List[String],
specificationPaths: List[Specification],
directory: Option[File] = None,
serviceName: Option[String] = None)
final case class RestUI(name: Option[String], specifications: List[String])
trait Specification
final case class UnnamedSpecification(path: String) extends Specification
final case class NamedSpecification(name: String, path: String) extends Specification
final case class RestUI(name: Option[String], specifications: List[Specification])

object RestUI {
implicit val decoder: Decoder[RestUI] = (cursor: HCursor) =>
for {
name <- cursor.get[Option[String]]("name")
specifications <- cursor.get[List[Specification]]("specifications")
} yield RestUI(name, specifications)
}

object Specification {
implicit val decoder: Decoder[Specification] =
List[Decoder[Specification]](Decoder[UnnamedSpecification].widen, Decoder[NamedSpecification].widen).reduceLeft(_ or _)
}

object UnnamedSpecification {
implicit val decoder: Decoder[UnnamedSpecification] = (cursor: HCursor) => cursor.as[String].map(UnnamedSpecification(_))
}

object NamedSpecification {
implicit val decoder: Decoder[NamedSpecification] = (cursor: HCursor) =>
for {
name <- cursor.get[String]("name")
path <- cursor.get[String]("path")
} yield NamedSpecification(name, path)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import akka.stream.scaladsl.{Broadcast, Flow => AkkaFlow, GraphDSL, Merge, Sourc
import com.typesafe.scalalogging.LazyLogging
import restui.Concurrency
import restui.providers.git.Source
import restui.providers.git.git.data.Repository
import restui.providers.git.git.data.{Repository, UnnamedSpecification}
import restui.providers.git.github.data.Node

object Github extends LazyLogging {
Expand All @@ -29,7 +29,7 @@ object Github extends LazyLogging {
logger.debug(s"Matching repository: $name")
val uri = Uri(url)
val uriWithToken = uri.withAuthority(uri.authority.copy(userinfo = githubClient.settings.apiToken))
Repository(uriWithToken.toString, branch, repository.specificationPaths)
Repository(uriWithToken.toString, branch, repository.specificationPaths.map(UnnamedSpecification(_)))
}

}.collect { case Some(repository) => repository }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import akka.testkit.TestProbe
import base.TestBase
import org.scalatest.Inside
import restui.models.{Service}
import restui.providers.git.git.data.Repository
import restui.providers.git.git.data._
class GitSpec extends TestBase with Inside {

private val duration = 50.millis
Expand All @@ -36,7 +36,7 @@ class GitSpec extends TestBase with Inside {
"there is a failure with a git command" in {
val fixture = new StubRepository {}
val tempDir = Files.createTempDirectory("restui-git-test-clone").toFile
val repo = Repository(fixture.repo.toAbsolutePath.toString, "i-do-not-exists", List("test"), Some(tempDir))
val repo = Repository(fixture.repo.toAbsolutePath.toString, "i-do-not-exists", List(UnnamedSpecification("test")), Some(tempDir))

val probe = TestProbe()
Git.fromSource(duration, Source.single(repo)).to(Sink.actorRef(probe.ref, "completed", _ => ())).run()
Expand All @@ -50,7 +50,7 @@ class GitSpec extends TestBase with Inside {
"there is no matching files" in {
val fixture = new StubRepository {}
val tempDir = Files.createTempDirectory("restui-git-test-clone").toFile
val repo = Repository(fixture.repo.toAbsolutePath.toString, "master", List("test"), Some(tempDir))
val repo = Repository(fixture.repo.toAbsolutePath.toString, "master", List(UnnamedSpecification("test")), Some(tempDir))

val probe = TestProbe()
Git.fromSource(duration, Source.single(repo)).to(Sink.actorRef(probe.ref, "completed", _ => ())).run()
Expand All @@ -63,7 +63,7 @@ class GitSpec extends TestBase with Inside {
val fixture = new StubRepository {}
fixture.commit("test", "test")
val tempDir = Files.createTempDirectory("restui-git-test-clone").toFile
val repo = Repository(fixture.repo.toAbsolutePath.toString, "master", List("test"), Some(tempDir))
val repo = Repository(fixture.repo.toAbsolutePath.toString, "master", List(UnnamedSpecification("test")), Some(tempDir))

val probe = TestProbe()
Git.fromSource(duration, Source.single(repo)).to(Sink.actorRef(probe.ref, "completed", _ => ())).run()
Expand All @@ -77,7 +77,7 @@ class GitSpec extends TestBase with Inside {
val fixture = new StubRepository {}
fixture.commit("test", "test")
val tempDir = Files.createTempDirectory("restui-git-test-clone").toFile
val repo = Repository(fixture.repo.toAbsolutePath.toString, "master", List("test"), Some(tempDir))
val repo = Repository(fixture.repo.toAbsolutePath.toString, "master", List(UnnamedSpecification("test")), Some(tempDir))

val probe = TestProbe()
Git.fromSource(duration, Source.single(repo)).to(Sink.actorRef(probe.ref, "completed", _ => ())).run()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package restui.providers.git.git.data

import cats.syntax.either._
import io.circe.yaml.parser
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class RestUISpec extends AnyFlatSpec with Matchers {
it should "decode a restui config file" in {
val input = """name: "test"
|specifications:
| - "file.yaml"
| - name: "another service"
| path: "other.yaml"
""".stripMargin
val restui = parser
.parse(input)
.flatMap(_.as[RestUI])
.valueOr(throw _)
restui shouldBe RestUI(Some("test"), UnnamedSpecification("file.yaml") :: NamedSpecification("another service", "other.yaml") :: Nil)
}
}

0 comments on commit 37c2fa1

Please sign in to comment.