Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 13 additions & 12 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLGenerateClientTask

plugins {
id("org.springframework.boot") version "3.5.7"
id("org.springframework.boot") version "4.0.5"
id("io.spring.dependency-management") version "1.1.7"
id("com.expediagroup.graphql") version "8.8.1"
id("io.gitlab.arturbosch.detekt") version "1.23.8"
kotlin("jvm") version "2.0.21"
kotlin("plugin.spring") version "2.0.21"
id("com.expediagroup.graphql") version "10.0.0-alpha.2"
id("dev.detekt") version "2.0.0-alpha.2"
kotlin("jvm") version "2.3.0"
kotlin("plugin.spring") version "2.3.0"
jacoco
}

Expand All @@ -23,7 +23,7 @@ repositories {
mavenCentral()
}

extra["springCloudVersion"] = "2025.0.0"
extra["springCloudVersion"] = "2025.1.1"

dependencyManagement {
imports {
Expand All @@ -33,16 +33,16 @@ dependencyManagement {

dependencies {
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.springframework.boot:spring-boot-starter-aop")
implementation("org.springframework.boot:spring-boot-starter-aspectj")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-cache")
implementation("com.github.ben-manes.caffeine:caffeine:2.9.3")
implementation("org.springframework.cloud:spring-cloud-starter-openfeign:4.3.0")
implementation("org.springframework.cloud:spring-cloud-starter-openfeign:5.0.1")
implementation("org.springframework.boot:spring-boot-starter-websocket")
implementation("io.github.resilience4j:resilience4j-spring-boot3")
implementation("io.github.resilience4j:resilience4j-spring-boot4:2.4.0")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("com.fasterxml.jackson.core:jackson-annotations:2.20")
implementation("com.expediagroup:graphql-kotlin-spring-client:8.8.1")
implementation("tools.jackson.module:jackson-module-kotlin")
implementation("com.expediagroup:graphql-kotlin-spring-client:10.0.0-alpha.2")
developmentOnly("io.netty:netty-resolver-dns-native-macos:4.2.7.Final") {
artifact {
classifier = "osx-aarch_64"
Expand All @@ -54,6 +54,7 @@ dependencies {
implementation("io.jsonwebtoken:jjwt-jackson:0.13.0")

testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.boot:spring-boot-webmvc-test")
testImplementation("com.ninja-squad:springmockk:4.0.2"){
exclude(module = "mockito-core")
}
Expand Down Expand Up @@ -83,7 +84,7 @@ detekt {
parallel = true
buildUponDefaultConfig = true
dependencies {
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.8")
detektPlugins("dev.detekt:detekt-rules-ktlint-wrapper:2.0.0-alpha.2")
}
}

Expand Down
6 changes: 5 additions & 1 deletion config/detekt/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ style:
active: true
ReturnCount:
active: false
UnusedPrivateMember:
UnusedPrivateClass:
active: true
UnusedPrivateFunction:
active: true
UnusedPrivateProperty:
active: true
ThrowsCount:
active: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,10 @@ import org.springframework.scheduling.annotation.EnableScheduling
@EnableConfigurationProperties(
value = [
net.leanix.githubagent.config.GitHubEnterpriseProperties::class,
net.leanix.githubagent.config.LeanIXProperties::class
]
net.leanix.githubagent.config.LeanIXProperties::class,
],
)
class GitHubAgentApplication(
private val syncLogService: SyncLogService,
private val cachingService: CachingService
) {
class GitHubAgentApplication(private val syncLogService: SyncLogService, private val cachingService: CachingService) {

private val logger = LoggerFactory.getLogger(GitHubAgentApplication::class.java)

Expand All @@ -43,7 +40,7 @@ class GitHubAgentApplication(
syncLogService.sendSyncLog(
message = message,
logLevel = LogLevel.INFO,
synchronizationProgress = synchronizationProgress
synchronizationProgress = synchronizationProgress,
)
logger.info(message)
}
Expand Down
18 changes: 9 additions & 9 deletions src/main/kotlin/net/leanix/githubagent/client/GitHubClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,52 +21,52 @@ import org.springframework.web.bind.annotation.RequestParam
@FeignClient(
name = "githubClient",
url = "\${github-enterprise.baseUrl}",
configuration = [FeignClientConfig::class]
configuration = [FeignClientConfig::class],
)
interface GitHubClient {

@GetMapping("/api/v3/app")
fun getApp(
@RequestHeader("Authorization") jwt: String,
@RequestHeader("Accept") accept: String = "application/vnd.github.v3+json"
@RequestHeader("Accept") accept: String = "application/vnd.github.v3+json",
): GitHubAppResponse

@Retry(name = "secondary_rate_limit")
@GetMapping("/api/v3/app/installations")
fun getInstallations(
@RequestHeader("Authorization") jwt: String,
@RequestParam("per_page", defaultValue = "30") perPage: Int,
@RequestParam("page", defaultValue = "1") page: Int
@RequestParam("page", defaultValue = "1") page: Int,
): List<Installation>

@Retry(name = "secondary_rate_limit")
@GetMapping("/api/v3/app/installations/{installationId}")
fun getInstallation(
@PathVariable("installationId") installationId: Long,
@RequestHeader("Authorization") jwt: String
@RequestHeader("Authorization") jwt: String,
): Installation

@Retry(name = "secondary_rate_limit")
@PostMapping("/api/v3/app/installations/{installationId}/access_tokens")
fun createInstallationToken(
@PathVariable("installationId") installationId: Long,
@RequestHeader("Authorization") jwt: String,
@RequestBody emptyBody: String = ""
@RequestBody emptyBody: String = "",
): InstallationTokenResponse

@Retry(name = "secondary_rate_limit")
@GetMapping("/api/v3/organizations")
fun getOrganizations(
@RequestHeader("Authorization") jwt: String,
@RequestParam("per_page", defaultValue = "30") perPage: Int,
@RequestParam("since", defaultValue = "1") since: Int
@RequestParam("since", defaultValue = "1") since: Int,
): List<Organization>

@Retry(name = "secondary_rate_limit")
@GetMapping("/api/v3/orgs/{org}/repos")
fun getRepositories(
@PathVariable("org") org: String,
@RequestHeader("Authorization") token: String
@RequestHeader("Authorization") token: String,
): List<Repository>

@Retry(name = "secondary_rate_limit")
Expand All @@ -82,7 +82,7 @@ interface GitHubClient {
@PathVariable("owner") owner: String,
@PathVariable("repo") repo: String,
@PathVariable("runId") runId: Long,
@RequestHeader("Authorization") token: String
@RequestHeader("Authorization") token: String,
): ArtifactsListResponse

@Retry(name = "secondary_rate_limit")
Expand All @@ -91,6 +91,6 @@ interface GitHubClient {
@PathVariable("owner") owner: String,
@PathVariable("repo") repo: String,
@PathVariable("artifactId") artifactId: Long,
@RequestHeader("Authorization") token: String
@RequestHeader("Authorization") token: String,
): Response
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,5 @@ import org.springframework.web.bind.annotation.RequestHeader
fun interface LeanIXAuthClient {

@PostMapping(value = ["/oauth2/token"], consumes = [APPLICATION_FORM_URLENCODED_VALUE])
fun getToken(
@RequestHeader(name = AUTHORIZATION) authorization: String,
@RequestBody body: String,
): JwtDto
fun getToken(@RequestHeader(name = AUTHORIZATION) authorization: String, @RequestBody body: String): JwtDto
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.springframework.stereotype.Component
@Component
class AgentSetupValidation(
private val gitHubEnterpriseProperties: GitHubEnterpriseProperties,
private val leanIXProperties: LeanIXProperties
private val leanIXProperties: LeanIXProperties,
) {

@EventListener
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,5 @@ import org.springframework.context.annotation.Configuration
class FeignClientConfig {

@Bean
fun rateLimitResponseInterceptor(): ResponseInterceptor {
return RateLimitResponseInterceptor()
}
fun rateLimitResponseInterceptor(): ResponseInterceptor = RateLimitResponseInterceptor()
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ data class GitHubEnterpriseProperties(
val baseUrl: String,
val gitHubAppId: String,
val pemFile: String,
val webhookSecret: String
val webhookSecret: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@ package net.leanix.githubagent.config
import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties(prefix = "leanix")
data class LeanIXProperties(
val wsBaseUrl: String,
val auth: Auth
) {
data class Auth(
val accessTokenUri: String,
val technicalUserToken: String
)
data class LeanIXProperties(val wsBaseUrl: String, val auth: Auth) {
data class Auth(val accessTokenUri: String, val technicalUserToken: String)
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,17 @@ class Resilience4jConfig {
Locale.getDefault(),
"%d minutes, %d seconds",
event.waitInterval.toMinutes(),
event.waitInterval.minus(event.waitInterval.toMinutes(), ChronoUnit.MINUTES).seconds
event.waitInterval.minus(event.waitInterval.toMinutes(), ChronoUnit.MINUTES).seconds,
)
logger.info(
"Retrying call due to ${event.name}, attempt: ${event.numberOfRetryAttempts}, " +
"wait time: $readableWaitTime"
"wait time: $readableWaitTime",
)
}
.onError { event ->
logger.error(
"Call failed due to ${event.name}, after attempts: ${event.numberOfRetryAttempts}, " +
"last exception: ${event.lastThrowable.message}"
"last exception: ${event.lastThrowable.message}",
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package net.leanix.githubagent.config

import com.fasterxml.jackson.databind.ObjectMapper
import io.github.resilience4j.retry.annotation.Retry
import net.leanix.githubagent.handler.BrokerStompSessionHandler
import net.leanix.githubagent.services.LeanIXAuthService
import net.leanix.githubagent.shared.GitHubAgentProperties.GITHUB_AGENT_VERSION
import net.leanix.githubagent.shared.GitHubAgentProperties.githubAgentVersion
import org.slf4j.LoggerFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
Expand All @@ -21,10 +20,9 @@ import org.springframework.web.socket.sockjs.client.WebSocketTransport
@Configuration
class WebSocketClientConfig(
private val brokerStompSessionHandler: BrokerStompSessionHandler,
private val objectMapper: ObjectMapper,
private val leanIXAuthService: LeanIXAuthService,
private val leanIXProperties: LeanIXProperties,
private val gitHubEnterpriseProperties: GitHubEnterpriseProperties
private val gitHubEnterpriseProperties: GitHubEnterpriseProperties,
) {
private val logger = LoggerFactory.getLogger(WebSocketClientConfig::class.java)

Expand All @@ -40,7 +38,7 @@ class WebSocketClientConfig(
throw it
}
stompHeaders["GitHub-Enterprise-URL"] = gitHubEnterpriseProperties.baseUrl
stompHeaders["GitHub-Agent-Version"] = GITHUB_AGENT_VERSION
stompHeaders["GitHub-Agent-Version"] = githubAgentVersion
return stompClient().connectAsync(
leanIXProperties.wsBaseUrl,
headers,
Expand All @@ -52,7 +50,6 @@ class WebSocketClientConfig(
@Bean
fun stompClient(): WebSocketStompClient {
val jsonConverter = MappingJackson2MessageConverter()
jsonConverter.objectMapper = objectMapper

val simpleWebSocketClient = StandardWebSocketClient()
val transports = listOf(WebSocketTransport(simpleWebSocketClient))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class GitHubWebhookController(private val gitHubWebhookService: GitHubWebhookSer
@RequestHeader("X-Github-Event") eventType: String,
@RequestHeader("X-GitHub-Enterprise-Host") host: String,
@RequestHeader("X-Hub-Signature-256", required = false) signature256: String?,
@RequestBody payload: String
@RequestBody payload: String,
) {
gitHubWebhookService.handleWebhookEvent(eventType, host, signature256, payload)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler

@ControllerAdvice
class GlobalExceptionHandler(
private val syncLogService: SyncLogService
) {
class GlobalExceptionHandler(private val syncLogService: SyncLogService) {

val exceptionLogger: Logger = LoggerFactory.getLogger(GlobalExceptionHandler::class.java)

Expand Down
6 changes: 1 addition & 5 deletions src/main/kotlin/net/leanix/githubagent/dto/ArtifactDTO.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
package net.leanix.githubagent.dto

data class ArtifactDTO(
val repositoryFullName: String,
val artifactFileName: String,
val artifactFileContent: String,
)
data class ArtifactDTO(val repositoryFullName: String, val artifactFileName: String, val artifactFileContent: String)
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
data class ArtifactsListResponse(
@JsonProperty("total_count")
val totalCount: Int,
val artifacts: List<Artifact>
val artifacts: List<Artifact>,
)

@JsonIgnoreProperties(ignoreUnknown = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,4 @@ package net.leanix.githubagent.dto
import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties(ignoreUnknown = true)
class GenericWebhookEvent(
val action: String? = null
)
class GenericWebhookEvent(val action: String? = null)
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ import com.fasterxml.jackson.annotation.JsonProperty
data class GitHubAppResponse(
@JsonProperty("slug") val slug: String,
@JsonProperty("permissions") val permissions: Map<String, String>,
@JsonProperty("events") val events: List<String>
@JsonProperty("events") val events: List<String>,
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,28 @@ data class InstallationTokenResponse(
@JsonProperty("token") val token: String,
@JsonProperty("expires_at") val expiresAt: String,
@JsonProperty("permissions") val permissions: Map<String, String>,
@JsonProperty("repository_selection") val repositorySelection: String
@JsonProperty("repository_selection") val repositorySelection: String,
)

@JsonIgnoreProperties(ignoreUnknown = true)
data class Installation(
@JsonProperty("id") val id: Long,
@JsonProperty("account") val account: Account,
@JsonProperty("permissions") val permissions: Map<String, String>,
@JsonProperty("events") val events: List<String>
@JsonProperty("events") val events: List<String>,
)

@JsonIgnoreProperties(ignoreUnknown = true)
data class Account(
@JsonProperty("login") val login: String
)
data class Account(@JsonProperty("login") val login: String)

@JsonIgnoreProperties(ignoreUnknown = true)
data class Organization(
@JsonProperty("login") val login: String,
@JsonProperty("id") val id: Int,
)
data class Organization(@JsonProperty("login") val login: String, @JsonProperty("id") val id: Int)

@JsonIgnoreProperties(ignoreUnknown = true)
data class Repository(
@JsonProperty("id") val id: String,
@JsonProperty("name") val name: String,
@JsonProperty("full_name") val fullName: Boolean,
@JsonProperty("owner") val owner: Organization,
@JsonProperty("topics") val topics: List<String>
@JsonProperty("topics") val topics: List<String>,
)
Loading
Loading