Tests, logging, restructuring
This commit is contained in:
parent
536ac398c4
commit
fdcef5d209
16 changed files with 118 additions and 26 deletions
|
@ -27,7 +27,7 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
jib {
|
jib {
|
||||||
to.image = "antifa-info-bot"
|
to.image = "github-release-bot"
|
||||||
container.creationTime.set(DateTimeFormatter.ISO_DATE_TIME.format(Instant.now().atZone(ZoneId.of("UTC"))))
|
container.creationTime.set(DateTimeFormatter.ISO_DATE_TIME.format(Instant.now().atZone(ZoneId.of("UTC"))))
|
||||||
|
|
||||||
val buildDir = layout.buildDirectory.get()
|
val buildDir = layout.buildDirectory.get()
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package de.rpr.githubreleases
|
package de.rpr.githubreleases
|
||||||
|
|
||||||
|
import de.rpr.githubreleases.feed.FeedService
|
||||||
|
import de.rpr.githubreleases.publishing.MastodonClientFactory
|
||||||
|
import de.rpr.githubreleases.publishing.Publishers
|
||||||
|
import de.rpr.githubreleases.repository.ReleaseRepository
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
@ -27,7 +31,7 @@ class App(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun execute() {
|
private fun execute() {
|
||||||
|
log("Processing feed...")
|
||||||
config.githubRepos.forEach { githubRepo ->
|
config.githubRepos.forEach { githubRepo ->
|
||||||
val existingReleases = releaseRepo.getExistingReleases(githubRepo)
|
val existingReleases = releaseRepo.getExistingReleases(githubRepo)
|
||||||
val feedService = FeedService(githubRepo, httpClient)
|
val feedService = FeedService(githubRepo, httpClient)
|
||||||
|
@ -35,6 +39,7 @@ class App(
|
||||||
val publisher = publishers.forName(githubRepo.name)
|
val publisher = publishers.forName(githubRepo.name)
|
||||||
val publishedReleases = publisher.sendReleases(newReleases)
|
val publishedReleases = publisher.sendReleases(newReleases)
|
||||||
releaseRepo.save(publishedReleases)
|
releaseRepo.save(publishedReleases)
|
||||||
|
log("Finished feed processing...")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package de.rpr.githubreleases;
|
package de.rpr.githubreleases;
|
||||||
|
|
||||||
import de.rpr.githubreleases.LogLevel.ERROR
|
import de.rpr.githubreleases.LogLevel.ERROR
|
||||||
|
import de.rpr.githubreleases.model.GithubRepo
|
||||||
|
|
||||||
class Config {
|
class Config {
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ class Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
githubRepos = githubReposString.split(",").map {
|
githubRepos = githubReposString.split(",").map {
|
||||||
GithubRepo(repoName(it), it)
|
GithubRepo(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
mastodonCredentials = githubRepos.associate {
|
mastodonCredentials = githubRepos.associate {
|
||||||
|
@ -73,9 +74,5 @@ class Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun repoName(url: String): String {
|
|
||||||
val usernameEnd = url.indexOf("/", startIndex = 20)
|
|
||||||
return url.substring(usernameEnd + 1).trimEnd { ch -> ch == '/' }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
package de.rpr.githubreleases
|
|
||||||
|
|
||||||
data class GithubRepo(
|
|
||||||
val name: String,
|
|
||||||
val url: String
|
|
||||||
)
|
|
|
@ -1,4 +1,4 @@
|
||||||
package de.rpr.githubreleases
|
package de.rpr.githubreleases.feed
|
||||||
|
|
||||||
import com.ouattararomuald.syndication.atom.AtomFeed
|
import com.ouattararomuald.syndication.atom.AtomFeed
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
package de.rpr.githubreleases
|
package de.rpr.githubreleases.feed
|
||||||
|
|
||||||
import com.ouattararomuald.syndication.Syndication
|
import com.ouattararomuald.syndication.Syndication
|
||||||
|
import de.rpr.githubreleases.*
|
||||||
|
import de.rpr.githubreleases.model.GithubRepo
|
||||||
|
import de.rpr.githubreleases.model.Release
|
||||||
|
import de.rpr.githubreleases.model.Releases
|
||||||
|
import de.rpr.githubreleases.model.asCollection
|
||||||
import de.rpr.terminenbg.LocalDateTimeAdapter
|
import de.rpr.terminenbg.LocalDateTimeAdapter
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.time.ZoneId
|
||||||
|
|
||||||
class FeedService(
|
class FeedService(
|
||||||
private val githubRepo: GithubRepo,
|
private val githubRepo: GithubRepo,
|
||||||
|
@ -15,18 +22,19 @@ class FeedService(
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getNewReleases(existingReleases: Releases): Releases {
|
fun getNewReleases(existingReleases: Releases): Releases {
|
||||||
log("Consuming releases feed for ${githubRepo.url}")
|
log("Consuming releases feed for ${githubRepo.repoPath}")
|
||||||
|
|
||||||
val feedReader = syndication.create(FeedReader::class.java)
|
val feedReader = syndication.create(FeedReader::class.java)
|
||||||
return feedReader.readAtom()
|
return feedReader.readAtom()
|
||||||
.items
|
.items
|
||||||
?.map {
|
?.map {
|
||||||
val created = LocalDateTime.parse(it.lastUpdatedTime, LocalDateTimeAdapter.formatter)
|
|
||||||
|
val created = OffsetDateTime.parse(it.lastUpdatedTime)
|
||||||
val link = it.links!!.first().href!!
|
val link = it.links!!.first().href!!
|
||||||
Release(
|
Release(
|
||||||
id = it.title,
|
id = it.title,
|
||||||
link = link,
|
link = link,
|
||||||
created = created,
|
created = created.atZoneSameInstant(ZoneId.of("UTC")).toLocalDateTime(),
|
||||||
githubRepo = githubRepo
|
githubRepo = githubRepo
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package de.rpr.githubreleases.model
|
||||||
|
|
||||||
|
data class GithubRepo(private val repositoryPath: String) {
|
||||||
|
|
||||||
|
private val urlPrefix = "https://github.com/"
|
||||||
|
|
||||||
|
val name: String
|
||||||
|
get() {
|
||||||
|
val usernameEnd = repoPath.indexOf("/")
|
||||||
|
return repoPath.substring(usernameEnd + 1).trimEnd { ch -> ch == '/' }
|
||||||
|
}
|
||||||
|
val repoPath: String = repoPath(repositoryPath)
|
||||||
|
|
||||||
|
val url = urlPrefix + repoPath
|
||||||
|
|
||||||
|
private fun repoPath(repositoryPath: String) = if (repositoryPath.startsWith(urlPrefix)) {
|
||||||
|
repositoryPath.substring(19)
|
||||||
|
} else {
|
||||||
|
repositoryPath
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package de.rpr.githubreleases
|
package de.rpr.githubreleases.model
|
||||||
|
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package de.rpr.githubreleases
|
package de.rpr.githubreleases.publishing
|
||||||
|
|
||||||
import social.bigbone.MastodonClient
|
import social.bigbone.MastodonClient
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package de.rpr.githubreleases
|
package de.rpr.githubreleases.publishing
|
||||||
|
|
||||||
|
import de.rpr.githubreleases.Config
|
||||||
|
import de.rpr.githubreleases.LogLevel
|
||||||
|
import de.rpr.githubreleases.model.Releases
|
||||||
|
import de.rpr.githubreleases.log
|
||||||
import social.bigbone.MastodonClient
|
import social.bigbone.MastodonClient
|
||||||
import social.bigbone.api.entity.data.Visibility
|
import social.bigbone.api.entity.data.Visibility
|
||||||
import social.bigbone.api.exception.BigBoneRequestException
|
import social.bigbone.api.exception.BigBoneRequestException
|
||||||
|
@ -11,6 +15,7 @@ class Publisher(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun sendReleases(releases: Releases): Releases {
|
fun sendReleases(releases: Releases): Releases {
|
||||||
|
log("${releases.size} new releases to publish")
|
||||||
val result = releases
|
val result = releases
|
||||||
.onEach { release -> log("Publishing release: ${release.title}") }
|
.onEach { release -> log("Publishing release: ${release.title}") }
|
||||||
.mapNotNull { release ->
|
.mapNotNull { release ->
|
|
@ -1,7 +1,12 @@
|
||||||
package de.rpr.githubreleases
|
package de.rpr.githubreleases.repository
|
||||||
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
|
import de.rpr.githubreleases.*
|
||||||
|
import de.rpr.githubreleases.model.GithubRepo
|
||||||
|
import de.rpr.githubreleases.model.Release
|
||||||
|
import de.rpr.githubreleases.model.Releases
|
||||||
|
import de.rpr.githubreleases.model.asCollection
|
||||||
import de.rpr.terminenbg.LocalDateAdapter
|
import de.rpr.terminenbg.LocalDateAdapter
|
||||||
import de.rpr.terminenbg.LocalDateTimeAdapter
|
import de.rpr.terminenbg.LocalDateTimeAdapter
|
||||||
import java.io.File
|
import java.io.File
|
|
@ -3,6 +3,7 @@ package de.rpr.githubreleases
|
||||||
import assertk.assertThat
|
import assertk.assertThat
|
||||||
import assertk.assertions.containsExactly
|
import assertk.assertions.containsExactly
|
||||||
import assertk.assertions.containsOnly
|
import assertk.assertions.containsOnly
|
||||||
|
import de.rpr.githubreleases.model.GithubRepo
|
||||||
import io.kotest.core.spec.style.DescribeSpec
|
import io.kotest.core.spec.style.DescribeSpec
|
||||||
import io.kotest.extensions.system.withEnvironment
|
import io.kotest.extensions.system.withEnvironment
|
||||||
import org.junit.jupiter.api.assertThrows
|
import org.junit.jupiter.api.assertThrows
|
||||||
|
@ -22,7 +23,7 @@ class ConfigTest : DescribeSpec({
|
||||||
it("should populate instances from config") {
|
it("should populate instances from config") {
|
||||||
val config = Config()
|
val config = Config()
|
||||||
assertThat(config.githubRepos).containsExactly(
|
assertThat(config.githubRepos).containsExactly(
|
||||||
GithubRepo("navidrome", "https://github.com/navidrome/navidrome/")
|
GithubRepo("https://github.com/navidrome/navidrome/")
|
||||||
)
|
)
|
||||||
assertThat(config.mastodonCredentials).containsOnly(
|
assertThat(config.mastodonCredentials).containsOnly(
|
||||||
"navidrome" to Config.PublishingCredentials(
|
"navidrome" to Config.PublishingCredentials(
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package de.rpr.githubreleases
|
package de.rpr.githubreleases
|
||||||
|
|
||||||
|
import de.rpr.githubreleases.model.GithubRepo
|
||||||
|
import de.rpr.githubreleases.model.Release
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
val testGithubRepo = GithubRepo("example", "https://github.com/example/example")
|
val testGithubRepo = GithubRepo("https://github.com/example/example")
|
||||||
|
|
||||||
val testRelease = Release(
|
val testRelease = Release(
|
||||||
id = "id",
|
id = "id",
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package de.rpr.githubreleases.feed
|
||||||
|
|
||||||
|
import assertk.assertThat
|
||||||
|
import assertk.assertions.doesNotContain
|
||||||
|
import de.rpr.githubreleases.model.GithubRepo
|
||||||
|
import de.rpr.githubreleases.model.asCollection
|
||||||
|
import de.rpr.githubreleases.testRelease
|
||||||
|
import io.kotest.core.spec.style.DescribeSpec
|
||||||
|
import io.mockk.clearAllMocks
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import okhttp3.Call
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Response
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
|
||||||
|
class FeedServiceTest : DescribeSpec({
|
||||||
|
|
||||||
|
val feedData = this::class.java.classLoader.getResource("releases.atom")?.readText()!!
|
||||||
|
|
||||||
|
val httpClient = mockk<OkHttpClient>()
|
||||||
|
val mockCall = mockk<Call>()
|
||||||
|
val mockResponse = mockk<Response>()
|
||||||
|
val mockResponseBody = mockk<ResponseBody>()
|
||||||
|
|
||||||
|
beforeTest {
|
||||||
|
clearAllMocks()
|
||||||
|
every { mockResponse.isSuccessful } returns true
|
||||||
|
every { mockResponse.body } returns mockResponseBody
|
||||||
|
every { mockResponseBody.string() } returns feedData
|
||||||
|
every { mockCall.execute() } returns mockResponse
|
||||||
|
every { httpClient.newCall(any()) } returns mockCall
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("FeedService") {
|
||||||
|
|
||||||
|
it("should only return new releases") {
|
||||||
|
val feedService = FeedService(GithubRepo("navidrome/navidrome"), httpClient)
|
||||||
|
val result = feedService.getNewReleases(testRelease.copy(id = "v0.50.2").asCollection())
|
||||||
|
assertThat(result.map { it.id }).doesNotContain("v0.50.2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
|
@ -1,9 +1,13 @@
|
||||||
package de.rpr.githubreleases
|
package de.rpr.githubreleases.publishing
|
||||||
|
|
||||||
import assertk.assertThat
|
import assertk.assertThat
|
||||||
import assertk.assertions.isEqualTo
|
import assertk.assertions.isEqualTo
|
||||||
import assertk.assertions.isTrue
|
import assertk.assertions.isTrue
|
||||||
import assertk.assertions.prop
|
import assertk.assertions.prop
|
||||||
|
import de.rpr.githubreleases.Config
|
||||||
|
import de.rpr.githubreleases.model.Releases
|
||||||
|
import de.rpr.githubreleases.model.asCollection
|
||||||
|
import de.rpr.githubreleases.testRelease
|
||||||
import io.kotest.core.spec.style.DescribeSpec
|
import io.kotest.core.spec.style.DescribeSpec
|
||||||
import io.kotest.extensions.system.withEnvironment
|
import io.kotest.extensions.system.withEnvironment
|
||||||
import io.mockk.*
|
import io.mockk.*
|
|
@ -1,8 +1,14 @@
|
||||||
package de.rpr.githubreleases
|
package de.rpr.githubreleases.repository
|
||||||
|
|
||||||
import assertk.assertThat
|
import assertk.assertThat
|
||||||
import assertk.assertions.contains
|
import assertk.assertions.contains
|
||||||
import assertk.assertions.isTrue
|
import assertk.assertions.isTrue
|
||||||
|
import de.rpr.githubreleases.model.Release
|
||||||
|
import de.rpr.githubreleases.model.Releases
|
||||||
|
import de.rpr.githubreleases.testGithubRepo
|
||||||
|
import de.rpr.githubreleases.testRelease
|
||||||
|
import de.rpr.githubreleases.toFile
|
||||||
|
import de.rpr.githubreleases.toPath
|
||||||
import io.kotest.core.spec.style.DescribeSpec
|
import io.kotest.core.spec.style.DescribeSpec
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
Loading…
Reference in a new issue