Skip to content

Commit 63ad42d

Browse files
authored
Merge pull request #40 from codacy/add-branch-state-telemetry
feat: branch state telemetry
2 parents 15c076a + bbe42d3 commit 63ad42d

File tree

3 files changed

+102
-3
lines changed

3 files changed

+102
-3
lines changed

src/main/kotlin/com/codacy/intellij/plugin/services/api/Api.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ class Api {
120120
return makeRequest(endpointUrl, GetRepositoryResponse::class.java)
121121
}
122122

123+
suspend fun listRepositoryBranches(provider: String, remoteOrganizationName: String, repositoryName: String, enabledOnly: Boolean = true): ListRepositoryBranchesResponse {
124+
val enabledParam = if (enabledOnly) "?enabled=true" else ""
125+
val endpointUrl = "repositories/$provider/$remoteOrganizationName/$repositoryName/branches$enabledParam"
126+
return makeRequest(endpointUrl, ListRepositoryBranchesResponse::class.java)
127+
}
128+
123129
suspend fun getUserProfile(): UserProfile? {
124130
val endpointUrl = "user"
125131
return try {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.codacy.intellij.plugin.services.api.models
2+
3+
data class ListRepositoryBranchesResponse(
4+
val data: List<Branch>
5+
)
6+

src/main/kotlin/com/codacy/intellij/plugin/services/git/RepositoryManager.kt

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ class RepositoryManager(private val project: Project) {
2828
NoPullRequest, Loaded
2929
}
3030

31+
enum class BranchState {
32+
OnPullRequestBranch, OnAnalysedBranch, OnAnalysedBranchOutdated, OnUnknownBranch
33+
}
34+
3135
var currentRepository: GitRepository? = null
3236
var repository: RepositoryData? = null
3337
var state: RepositoryManagerState = RepositoryManagerState.Initializing
@@ -41,6 +45,11 @@ class RepositoryManager(private val project: Project) {
4145
private val config = Config()
4246
private var pullRequestInstance: PullRequest? = null
4347

48+
// Branch state management
49+
private var enabledBranches: List<Branch> = emptyList()
50+
private var branchState: BranchState = BranchState.OnUnknownBranch
51+
private var lastBranchState: BranchState? = null
52+
4453
private var onDidUpdatePullRequestListeners = mutableListOf<() -> Unit>()
4554
private var onDidLoadRepositoryListeners = mutableListOf<() -> Unit>()
4655
private var onDidChangeStateListeners = mutableListOf<() -> Unit>()
@@ -74,6 +83,17 @@ class RepositoryManager(private val project: Project) {
7483
val (data) = api.getRepository(repo.provider, repo.organization, repo.repository)
7584

7685
repository = data
86+
87+
// Fetch enabled branches
88+
try {
89+
val branchesResponse = api.listRepositoryBranches(repo.provider, repo.organization, repo.repository, true)
90+
enabledBranches = branchesResponse.data
91+
Logger.info("Fetched ${enabledBranches.size} enabled branches")
92+
} catch (e: Exception) {
93+
Logger.error("Failed to fetch enabled branches: ${e.message}")
94+
enabledBranches = emptyList()
95+
}
96+
7797
setNewState(RepositoryManagerState.Loaded)
7898
notifyDidLoadRepository()
7999
loadPullRequest()
@@ -100,9 +120,9 @@ class RepositoryManager(private val project: Project) {
100120
prState = PullRequestState.NoPullRequest
101121
loadPullRequest()
102122
} else {
103-
val currentHeadCommitSHA: String = GitProvider.getHeadCommitSHA(project)!!
123+
val currentHeadCommitSHA = GitProvider.getHeadCommitSHA(project)
104124
val currentHeadAhead: Boolean = GitProvider.isHeadAhead(project)
105-
if (pullRequest != null && prState === PullRequestState.Loaded && currentHeadCommitSHA !== pullRequest?.meta?.headCommitSHA && !currentHeadAhead) {
125+
if (currentHeadCommitSHA != null && pullRequest != null && prState === PullRequestState.Loaded && currentHeadCommitSHA !== pullRequest?.meta?.headCommitSHA && !currentHeadAhead) {
106126
if (refreshTimeout.isTimeoutRunning()) refreshTimeout.clearTimeout()
107127
refreshTimeout.startTimeout(10000) {
108128
Logger.info("Pushed all local commits, refreshing pull request...")
@@ -143,6 +163,8 @@ class RepositoryManager(private val project: Project) {
143163
if (pr == null) {
144164
Logger.info("No PR found in Codacy for: $branch")
145165
prState = PullRequestState.NoPullRequest
166+
// Evaluate branch state after PR discovery fails
167+
evaluateBranchState()
146168

147169
if (loadAttempts < MAX_LOAD_ATTEMPTS) {
148170
loadTimeout.startTimeout(LOAD_RETRY_TIME) {
@@ -164,6 +186,8 @@ class RepositoryManager(private val project: Project) {
164186
}
165187

166188
prState = PullRequestState.Loaded
189+
// Evaluate branch state after PR is loaded
190+
evaluateBranchState()
167191
} catch (e: Exception) {
168192
Logger.error("Error loading pull request: ${e.message}")
169193
}
@@ -173,8 +197,10 @@ class RepositoryManager(private val project: Project) {
173197
}
174198

175199
fun clear() {
176-
177200
currentRepository = null
201+
enabledBranches = emptyList()
202+
branchState = BranchState.OnUnknownBranch
203+
lastBranchState = null
178204
setNewState(RepositoryManagerState.NoRepository)
179205
}
180206

@@ -223,4 +249,65 @@ class RepositoryManager(private val project: Project) {
223249
}
224250
}
225251

252+
@OptIn(DelicateCoroutinesApi::class)
253+
private suspend fun evaluateBranchState() {
254+
if (state != RepositoryManagerState.Loaded || repository == null) return
255+
256+
val currentBranch = currentRepository?.currentBranch?.name
257+
val repo = repository!!
258+
259+
// If no HEAD name, set to OnUnknownBranch
260+
if (currentBranch.isNullOrBlank()) {
261+
Logger.warn("No HEAD information found: ${currentRepository?.currentBranch}")
262+
setBranchState(BranchState.OnUnknownBranch)
263+
return
264+
}
265+
266+
// If PR is loaded, set to OnPullRequestBranch
267+
if (prState == PullRequestState.Loaded) {
268+
setBranchState(BranchState.OnPullRequestBranch)
269+
return
270+
}
271+
272+
// Check if current branch is in enabled branches
273+
val isEnabledBranch = enabledBranches.any { it.name == currentBranch }
274+
275+
if (isEnabledBranch) {
276+
Logger.info("Current branch is an analyzed branch: $currentBranch")
277+
278+
// Get the last analyzed commit for this branch
279+
try {
280+
val analysisResponse = api.getRepositoryWithAnalysis(repo.provider, repo.owner, repo.name)
281+
val lastAnalysedCommit = analysisResponse.data.lastAnalysedCommit
282+
val localHeadCommit = GitProvider.getHeadCommitSHA(project)
283+
284+
if (localHeadCommit != null && lastAnalysedCommit.sha != localHeadCommit) {
285+
Logger.info("Local branch '$currentBranch' is outdated: Local Head ${localHeadCommit.substring(0, 7)} !== Last analysed Head ${lastAnalysedCommit.sha.substring(0, 7)}")
286+
setBranchState(BranchState.OnAnalysedBranchOutdated)
287+
} else {
288+
setBranchState(BranchState.OnAnalysedBranch)
289+
}
290+
} catch (e: Exception) {
291+
Logger.error("Failed to get repository analysis: ${e.message}")
292+
setBranchState(BranchState.OnUnknownBranch)
293+
}
294+
} else {
295+
// Not an enabled branch and no PR loaded
296+
setBranchState(BranchState.OnUnknownBranch)
297+
}
298+
}
299+
300+
private fun setBranchState(newState: BranchState) {
301+
if (branchState != newState) {
302+
val previousState = branchState
303+
branchState = newState
304+
lastBranchState = previousState
305+
306+
// Emit telemetry
307+
Telemetry.track(BranchStateChangeEvent(newState.name))
308+
309+
Logger.info("Branch state changed from $previousState to $newState")
310+
}
311+
}
312+
226313
}

0 commit comments

Comments
 (0)