Skip to content

Commit 7aed232

Browse files
Merge pull request #98 from leanix/feature/CID-3745/Handle-Repository-Archived-Unarchived-Events
CID-3745: Handle Repository Archived & Unarchived Events
2 parents 0673ddb + 3388717 commit 7aed232

File tree

7 files changed

+214
-61
lines changed

7 files changed

+214
-61
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package net.leanix.githubagent.dto
2+
3+
data class RepositoryRequestDTO(
4+
val installation: RepositoryRequestInstallationDTO,
5+
val repositoryName: String,
6+
val repositoryFullName: String,
7+
)
8+
9+
data class RepositoryRequestInstallationDTO(
10+
val id: Long,
11+
val account: Account
12+
)

src/main/kotlin/net/leanix/githubagent/handler/BrokerStompSessionHandler.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import java.util.concurrent.CountDownLatch
1313

1414
@Component
1515
class BrokerStompSessionHandler(
16-
private val artifactDownloadHandler: ArtifactDownloadHandler
16+
private val artifactDownloadHandler: ArtifactDownloadHandler,
17+
private val repositoryGetHandler: RepositoryGetHandler,
1718
) : StompSessionHandlerAdapter() {
1819
@Lazy
1920
@Autowired
@@ -30,6 +31,7 @@ class BrokerStompSessionHandler(
3031
isConnected = true
3132
latch.countDown()
3233
session.subscribe("/user/queue/message/artifact", artifactDownloadHandler)
34+
session.subscribe("/user/queue/message/repository", repositoryGetHandler)
3335
}
3436

3537
override fun handleException(
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package net.leanix.githubagent.handler
2+
3+
import net.leanix.githubagent.dto.Installation
4+
import net.leanix.githubagent.dto.RepositoryRequestDTO
5+
import net.leanix.githubagent.services.GitHubAuthenticationService
6+
import net.leanix.githubagent.services.GitHubRepositoryService
7+
import org.slf4j.LoggerFactory
8+
import org.springframework.beans.factory.annotation.Autowired
9+
import org.springframework.context.annotation.Lazy
10+
import org.springframework.messaging.simp.stomp.StompFrameHandler
11+
import org.springframework.messaging.simp.stomp.StompHeaders
12+
import org.springframework.stereotype.Component
13+
import java.lang.reflect.Type
14+
15+
@Component
16+
class RepositoryGetHandler(
17+
@Lazy @Autowired
18+
private val gitHubAuthenticationService: GitHubAuthenticationService,
19+
@Lazy @Autowired
20+
private val repositoryGetService: GitHubRepositoryService
21+
) : StompFrameHandler {
22+
23+
private val logger = LoggerFactory.getLogger(RepositoryGetHandler::class.java)
24+
25+
override fun getPayloadType(headers: StompHeaders): Type {
26+
return RepositoryRequestDTO::class.java
27+
}
28+
29+
override fun handleFrame(headers: StompHeaders, payload: Any?) {
30+
payload?.let {
31+
val dto = payload as RepositoryRequestDTO
32+
logger.info("Received repository get message from server for repo: ${dto.repositoryName}")
33+
runCatching {
34+
val installationToken = gitHubAuthenticationService.getInstallationToken(dto.installation.id.toInt())
35+
repositoryGetService.fetchAndSendRepositoryAndManifest(
36+
Installation(
37+
id = dto.installation.id,
38+
account = dto.installation.account,
39+
mapOf(),
40+
emptyList(),
41+
),
42+
dto.repositoryName,
43+
dto.repositoryFullName,
44+
installationToken
45+
)
46+
}
47+
}
48+
}
49+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package net.leanix.githubagent.services
2+
3+
import net.leanix.githubagent.dto.Installation
4+
import net.leanix.githubagent.dto.ManifestFileAction
5+
import net.leanix.githubagent.dto.ManifestFileUpdateDto
6+
import net.leanix.githubagent.dto.RateLimitType
7+
import net.leanix.githubagent.dto.RepositoryDto
8+
import net.leanix.githubagent.handler.RateLimitHandler
9+
import net.leanix.githubagent.shared.fileNameMatchRegex
10+
import net.leanix.githubagent.shared.generateFullPath
11+
import org.slf4j.LoggerFactory
12+
import org.springframework.beans.factory.annotation.Autowired
13+
import org.springframework.context.annotation.Lazy
14+
import org.springframework.stereotype.Service
15+
16+
@Service
17+
class GitHubRepositoryService(
18+
@Lazy @Autowired
19+
private val webSocketService: WebSocketService,
20+
private val gitHubGraphQLService: GitHubGraphQLService,
21+
@Lazy @Autowired
22+
private val gitHubScanningService: GitHubScanningService,
23+
@Lazy @Autowired
24+
private val rateLimitHandler: RateLimitHandler,
25+
) {
26+
private val logger = LoggerFactory.getLogger(GitHubRepositoryService::class.java)
27+
28+
fun fetchAndSendRepositoryAndManifest(
29+
installation: Installation,
30+
repositoryName: String,
31+
repositoryFullName: String,
32+
installationToken: String
33+
) {
34+
kotlin.runCatching {
35+
logger.info("Fetching repository details for: $repositoryFullName")
36+
val repository = rateLimitHandler.executeWithRateLimitHandler(RateLimitType.GRAPHQL) {
37+
gitHubGraphQLService.getRepository(
38+
installation.account.login,
39+
repositoryName,
40+
installationToken
41+
)
42+
}
43+
if (repository == null) {
44+
logger.error("Failed to fetch repository details for: $repositoryFullName")
45+
return
46+
}
47+
if (repository.archived) {
48+
logger.info("Repository ${repository.fullName} is archived, skipping.")
49+
return
50+
}
51+
logger.info("Sending repository details for: ${repository.fullName}")
52+
webSocketService.sendMessage("/events/repository", repository)
53+
fetchAndSendManifestFiles(installation, repository)
54+
}.onFailure {
55+
logger.error("Failed to process repository event: $repositoryFullName", it)
56+
}
57+
}
58+
59+
private fun fetchAndSendManifestFiles(installation: Installation, repositoryAdded: RepositoryDto) {
60+
logger.info("Fetching manifest files for repository: ${repositoryAdded.fullName}")
61+
val manifestFiles = gitHubScanningService.fetchManifestFiles(installation, repositoryAdded.name).getOrThrow()
62+
val manifestContents = gitHubScanningService.fetchManifestContents(
63+
installation,
64+
manifestFiles,
65+
repositoryAdded.name,
66+
repositoryAdded.defaultBranch
67+
).getOrThrow()
68+
69+
if (manifestContents.isEmpty()) {
70+
logger.info("No manifest files found for repository: ${repositoryAdded.fullName}")
71+
return
72+
}
73+
manifestContents.forEach {
74+
logger.info("Sending manifest file content for: ${it.path} in repository: ${repositoryAdded.fullName}")
75+
webSocketService.sendMessage(
76+
"/events/manifestFile",
77+
ManifestFileUpdateDto(
78+
repositoryAdded.fullName,
79+
ManifestFileAction.ADDED,
80+
it.content,
81+
generateFullPath(repositoryAdded.defaultBranch, fileNameMatchRegex.replace(it.path, ""))
82+
)
83+
)
84+
}
85+
}
86+
}

src/main/kotlin/net/leanix/githubagent/services/WebhookEventService.kt

Lines changed: 5 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,14 @@ package net.leanix.githubagent.services
33
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
44
import com.fasterxml.jackson.module.kotlin.readValue
55
import net.leanix.githubagent.client.GitHubClient
6-
import net.leanix.githubagent.dto.Installation
76
import net.leanix.githubagent.dto.InstallationEventPayload
87
import net.leanix.githubagent.dto.InstallationRepositoriesEventPayload
9-
import net.leanix.githubagent.dto.InstallationRepositoriesRepository
108
import net.leanix.githubagent.dto.ManifestFileAction
119
import net.leanix.githubagent.dto.ManifestFileUpdateDto
1210
import net.leanix.githubagent.dto.PushEventCommit
1311
import net.leanix.githubagent.dto.PushEventPayload
14-
import net.leanix.githubagent.dto.RateLimitType
15-
import net.leanix.githubagent.dto.RepositoryDto
1612
import net.leanix.githubagent.dto.toInstallation
1713
import net.leanix.githubagent.exceptions.JwtTokenNotFound
18-
import net.leanix.githubagent.handler.RateLimitHandler
1914
import net.leanix.githubagent.shared.INSTALLATION_LABEL
2015
import net.leanix.githubagent.shared.INSTALLATION_REPOSITORIES
2116
import net.leanix.githubagent.shared.MANIFEST_FILE_NAME
@@ -37,7 +32,7 @@ class WebhookEventService(
3732
@Value("\${webhookEventService.waitingTime}") private val waitingTime: Long,
3833
private val gitHubClient: GitHubClient,
3934
private val gitHubEnterpriseService: GitHubEnterpriseService,
40-
private val rateLimitHandler: RateLimitHandler,
35+
private val gitHubRepositoryService: GitHubRepositoryService,
4136
) {
4237

4338
private val logger = LoggerFactory.getLogger(WebhookEventService::class.java)
@@ -50,7 +45,7 @@ class WebhookEventService(
5045
INSTALLATION_REPOSITORIES -> handleInstallationRepositories(payload)
5146
else -> {
5247
logger.info("Sending event of type: $eventType")
53-
webSocketService.sendMessage("/events/$eventType", payload)
48+
webSocketService.sendMessage("/events/other/$eventType", payload)
5449
}
5550
}
5651
}
@@ -222,61 +217,12 @@ class WebhookEventService(
222217
installationRepositoriesEventPayload.repositoriesAdded
223218
.forEach { repositoryAdded ->
224219
logger.info("Processing repository: ${repositoryAdded.fullName}")
225-
processRepository(installation.toInstallation(), repositoryAdded, installationToken)
226-
}
227-
}
228-
229-
private fun processRepository(
230-
installation: Installation,
231-
repositoryAdded: InstallationRepositoriesRepository,
232-
installationToken: String
233-
) {
234-
kotlin.runCatching {
235-
logger.info("Fetching repository details for: ${repositoryAdded.fullName}")
236-
val repository = rateLimitHandler.executeWithRateLimitHandler(RateLimitType.GRAPHQL) {
237-
gitHubGraphQLService.getRepository(
238-
installation.account.login,
220+
gitHubRepositoryService.fetchAndSendRepositoryAndManifest(
221+
installation.toInstallation(),
239222
repositoryAdded.name,
223+
repositoryAdded.fullName,
240224
installationToken
241225
)
242226
}
243-
if (repository == null) {
244-
logger.error("Failed to fetch repository details for: ${repositoryAdded.fullName}")
245-
return
246-
}
247-
if (repository.archived) {
248-
logger.info("Repository ${repository.fullName} is archived, skipping.")
249-
return
250-
}
251-
logger.info("Sending repository details for: ${repository.fullName}")
252-
webSocketService.sendMessage("/events/repository", repository)
253-
fetchAndSendManifestFiles(installation, repository)
254-
}.onFailure {
255-
logger.error("Failed to process repository event: ${repositoryAdded.fullName}", it)
256-
}
257-
}
258-
259-
private fun fetchAndSendManifestFiles(installation: Installation, repositoryAdded: RepositoryDto) {
260-
logger.info("Fetching manifest files for repository: ${repositoryAdded.fullName}")
261-
val manifestFiles = gitHubScanningService.fetchManifestFiles(installation, repositoryAdded.name).getOrThrow()
262-
val manifestContents = gitHubScanningService.fetchManifestContents(
263-
installation,
264-
manifestFiles,
265-
repositoryAdded.name,
266-
repositoryAdded.defaultBranch
267-
).getOrThrow()
268-
269-
manifestContents.forEach {
270-
logger.info("Sending manifest file content for: ${it.path} in repository: ${repositoryAdded.fullName}")
271-
webSocketService.sendMessage(
272-
"/events/manifestFile",
273-
ManifestFileUpdateDto(
274-
repositoryAdded.fullName,
275-
ManifestFileAction.ADDED,
276-
it.content,
277-
generateFullPath(repositoryAdded.defaultBranch, fileNameMatchRegex.replace(it.path, ""))
278-
)
279-
)
280-
}
281227
}
282228
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package net.leanix.githubagent.handler
2+
3+
import io.mockk.MockKAnnotations
4+
import io.mockk.every
5+
import io.mockk.mockk
6+
import io.mockk.verify
7+
import net.leanix.githubagent.dto.Account
8+
import net.leanix.githubagent.dto.Installation
9+
import net.leanix.githubagent.dto.RepositoryRequestDTO
10+
import net.leanix.githubagent.dto.RepositoryRequestInstallationDTO
11+
import net.leanix.githubagent.services.GitHubAuthenticationService
12+
import net.leanix.githubagent.services.GitHubRepositoryService
13+
import org.junit.jupiter.api.BeforeEach
14+
import org.junit.jupiter.api.Test
15+
import org.springframework.messaging.simp.stomp.StompHeaders
16+
17+
class RepositoryGetHandlerTest {
18+
19+
private val gitHubAuthenticationService = mockk<GitHubAuthenticationService>()
20+
21+
private val gitHubRepositoryService = mockk<GitHubRepositoryService>()
22+
23+
private val repositoryGetHandler = RepositoryGetHandler(
24+
gitHubAuthenticationService,
25+
gitHubRepositoryService
26+
)
27+
28+
@BeforeEach
29+
fun setup() {
30+
MockKAnnotations.init(repositoryGetHandler)
31+
}
32+
33+
@Test
34+
fun `it should receive message from server and send repository data and manifest files`() {
35+
// given
36+
every { gitHubAuthenticationService.getInstallationToken(any()) } returns "token"
37+
38+
// when
39+
repositoryGetHandler.handleFrame(
40+
StompHeaders(),
41+
RepositoryRequestDTO(
42+
installation = RepositoryRequestInstallationDTO(1, Account("account")),
43+
repositoryName = "repoName",
44+
repositoryFullName = "repoFullName"
45+
)
46+
)
47+
48+
// then
49+
verify {
50+
gitHubRepositoryService.fetchAndSendRepositoryAndManifest(
51+
installation = Installation(1, Account("account"), mapOf(), listOf()),
52+
repositoryName = "repoName",
53+
repositoryFullName = "repoFullName",
54+
installationToken = "token"
55+
)
56+
}
57+
}
58+
}

src/test/kotlin/net/leanix/githubagent/services/WebhookEventServiceTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ class WebhookEventServiceTest {
226226

227227
webhookEventService.consumeWebhookEvent("OTHER", payload)
228228

229-
verify(exactly = 1) { webSocketService.sendMessage("/events/OTHER", payload) }
229+
verify(exactly = 1) { webSocketService.sendMessage("/events/other/OTHER", payload) }
230230
}
231231

232232
@Test

0 commit comments

Comments
 (0)