Skip to content

Commit 174dde5

Browse files
authored
Merge pull request #39 from codacy/telemetry-fixes
feat: reviewing state change events
2 parents 63ad42d + ff57ec1 commit 174dde5

File tree

5 files changed

+175
-44
lines changed

5 files changed

+175
-44
lines changed

src/main/kotlin/com/codacy/intellij/plugin/services/cli/CodacyCliService.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import com.codacy.intellij.plugin.services.common.Config.Companion.CODACY_TOOLS_
1919
import com.codacy.intellij.plugin.services.common.Config.Companion.CODACY_YAML_NAME
2020
import com.codacy.intellij.plugin.services.common.GitRemoteParser
2121
import com.codacy.intellij.plugin.services.common.IconUtils
22+
import com.codacy.intellij.plugin.services.common.OsType
23+
import com.codacy.intellij.plugin.services.common.SystemDetectionService
2224
import com.codacy.intellij.plugin.services.git.GitProvider
2325
import com.codacy.intellij.plugin.services.paths.PathsBehaviour
2426
import com.codacy.intellij.plugin.services.paths.behaviour.PathsUnix
@@ -172,19 +174,19 @@ class CodacyCliService() {
172174
repository: String,
173175
project: Project,
174176
): CodacyCliService {
175-
val systemOs = System.getProperty("os.name").lowercase()
177+
val systemOs = SystemDetectionService.detectOs()
176178
val cli = project.getService(CodacyCliService::class.java)
177179

178180
val (cliBehaviour, pathsBehaviour) = when {
179-
systemOs == "mac os x" || systemOs.contains("darwin") -> {
181+
systemOs == OsType.MacOS -> {
180182
CliUnix() to PathsUnix()
181183
}
182184

183-
systemOs == "linux" -> {
185+
systemOs == OsType.Linux -> {
184186
CliUnix() to PathsUnix()
185187
}
186188

187-
systemOs.contains("windows") -> {
189+
systemOs == OsType.Windows -> {
188190
val process = ProcessBuilder("wsl", "--list", "--quiet")
189191
.redirectErrorStream(true)
190192
.start()
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package com.codacy.intellij.plugin.services.common
2+
3+
import com.intellij.openapi.application.ApplicationNamesInfo
4+
5+
enum class OsType {
6+
Windows,
7+
MacOS,
8+
Linux,
9+
Unknown;
10+
11+
override fun toString(): String {
12+
return when (this) {
13+
Windows -> "Windows"
14+
MacOS -> "MacOS"
15+
Linux -> "Linux"
16+
Unknown -> "Unknown"
17+
}
18+
}
19+
20+
21+
companion object {
22+
fun fromString(osName: String): OsType {
23+
return when (osName.lowercase()) {
24+
"windows" -> Windows
25+
"macos", "mac os", "mac" -> MacOS
26+
"linux" -> Linux
27+
else -> Unknown // Default to Unknown if OS is not recognized
28+
}
29+
}
30+
}
31+
}
32+
33+
34+
enum class IdeType {
35+
Intellij,
36+
Webstorm,
37+
Pycharm,
38+
Phpstorm,
39+
Rubymine,
40+
Goland,
41+
Rider,
42+
Clion,
43+
Datagrip,
44+
Dataspell,
45+
Unknown;
46+
47+
override fun toString(): String {
48+
return when (this) {
49+
Intellij -> "IntelliJ"
50+
Webstorm -> "WebStorm"
51+
Pycharm -> "PyCharm"
52+
Phpstorm -> "PhpStorm"
53+
Rubymine -> "RubyMine"
54+
Goland -> "GoLand"
55+
Rider -> "Rider"
56+
Clion -> "CLion"
57+
Datagrip -> "DataGrip"
58+
Dataspell -> "DataSpell"
59+
Unknown -> "Unknown"
60+
}
61+
}
62+
63+
companion object {
64+
65+
fun fromString(ideName: String): IdeType {
66+
return when (ideName.lowercase()) {
67+
"intellij" -> Intellij
68+
"webstorm" -> Webstorm
69+
"pycharm" -> Pycharm
70+
"phpstorm" -> Phpstorm
71+
"rubymine" -> Rubymine
72+
"goland" -> Goland
73+
"rider" -> Rider
74+
"clion" -> Clion
75+
"datagrip" -> Datagrip
76+
"dataspell" -> Dataspell
77+
else -> Unknown
78+
}
79+
}
80+
}
81+
}
82+
83+
84+
object SystemDetectionService {
85+
86+
87+
fun detectOs(): OsType {
88+
val systemOs = System.getProperty("os.name").lowercase()
89+
return when {
90+
systemOs.contains("win") || systemOs.contains("windows") -> OsType.Windows
91+
systemOs.contains("mac os x") || systemOs.contains("darwin") -> OsType.MacOS
92+
listOf("nux", "nix", "aix", "linux").any { systemOs.contains(it) } -> OsType.Linux
93+
else -> OsType.Unknown
94+
}
95+
}
96+
97+
fun detectIde(): IdeType = IdeType
98+
.fromString(
99+
ApplicationNamesInfo.getInstance().productName.lowercase()
100+
)
101+
102+
103+
}

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

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package com.codacy.intellij.plugin.services.git
22

33
import com.codacy.intellij.plugin.services.api.Api
4-
import com.codacy.intellij.plugin.services.api.models.*
5-
import com.codacy.intellij.plugin.services.common.*
6-
import com.codacy.intellij.plugin.telemetry.BranchStateChangeEvent
4+
import com.codacy.intellij.plugin.services.api.models.RepositoryData
5+
import com.codacy.intellij.plugin.services.common.Config
6+
import com.codacy.intellij.plugin.services.common.GitRemoteParser
7+
import com.codacy.intellij.plugin.services.common.Logger
8+
import com.codacy.intellij.plugin.services.common.TimeoutManager
9+
import com.codacy.intellij.plugin.telemetry.PullRequestStateChangeEvent
10+
import com.codacy.intellij.plugin.telemetry.RepositoryStateChangeEvent
711
import com.codacy.intellij.plugin.telemetry.Telemetry
812
import com.intellij.openapi.Disposable
913
import com.intellij.openapi.components.Service
@@ -21,7 +25,11 @@ const val MAX_LOAD_ATTEMPTS: Int = 5
2125
class RepositoryManager(private val project: Project) {
2226

2327
enum class RepositoryManagerState {
24-
NoRepository, NoRemote, Initializing, NeedsAuthentication, Loaded
28+
Initializing,
29+
NeedsAuthentication,
30+
NoGitRepository,
31+
Loaded,
32+
NoRepository
2533
}
2634

2735
enum class PullRequestState {
@@ -63,7 +71,7 @@ class RepositoryManager(private val project: Project) {
6371
}
6472

6573
if (currentRepository != gitRepository) {
66-
ProgressManager.getInstance().run(object: Task.Backgroundable(project, "Opening repository", false) {
74+
ProgressManager.getInstance().run(object : Task.Backgroundable(project, "Opening repository", false) {
6775
override fun run(indicator: com.intellij.openapi.progress.ProgressIndicator) {
6876
GlobalScope.launch {
6977
currentRepository = gitRepository
@@ -74,7 +82,7 @@ class RepositoryManager(private val project: Project) {
7482
setNewState(RepositoryManagerState.Initializing)
7583
} else {
7684
if (remoteUrl.isNullOrEmpty()) {
77-
setNewState(RepositoryManagerState.NoRemote)
85+
setNewState(RepositoryManagerState.NoGitRepository)
7886
Logger.error("No remote found")
7987
return@launch
8088
}
@@ -117,13 +125,16 @@ class RepositoryManager(private val project: Project) {
117125
branch = currentHead
118126
pullRequest = null
119127
notifyDidUpdatePullRequest()
120-
prState = PullRequestState.NoPullRequest
128+
setNewPullRequestState(PullRequestState.NoPullRequest)
129+
121130
loadPullRequest()
122131
} else {
123132
val currentHeadCommitSHA = GitProvider.getHeadCommitSHA(project)
124133
val currentHeadAhead: Boolean = GitProvider.isHeadAhead(project)
125-
if (currentHeadCommitSHA != null && pullRequest != null && prState === PullRequestState.Loaded && currentHeadCommitSHA !== pullRequest?.meta?.headCommitSHA && !currentHeadAhead) {
126-
if (refreshTimeout.isTimeoutRunning()) refreshTimeout.clearTimeout()
134+
if (isPrLoadedAndNotCheckedOut(pullRequest, prState, currentHeadCommitSHA, currentHeadAhead)) {
135+
if (refreshTimeout.isTimeoutRunning()) {
136+
refreshTimeout.clearTimeout()
137+
}
127138
refreshTimeout.startTimeout(10000) {
128139
Logger.info("Pushed all local commits, refreshing pull request...")
129140
pullRequestInstance!!.refresh()
@@ -132,6 +143,18 @@ class RepositoryManager(private val project: Project) {
132143
}
133144
}
134145

146+
private fun isPrLoadedAndNotCheckedOut(
147+
pullRequest: PullRequest?,
148+
prState: PullRequestState,
149+
currentHeadCommitSHA: String,
150+
currentHeadAhead: Boolean
151+
): Boolean =
152+
pullRequest != null &&
153+
prState === PullRequestState.Loaded &&
154+
currentHeadCommitSHA != pullRequest.meta?.headCommitSHA &&
155+
!currentHeadAhead
156+
157+
135158
@OptIn(DelicateCoroutinesApi::class)
136159
private suspend fun loadPullRequest() {
137160
if (loadTimeout.isTimeoutRunning()) loadTimeout.clearTimeout()
@@ -141,17 +164,17 @@ class RepositoryManager(private val project: Project) {
141164
branch = currentRepository?.currentBranch?.name
142165
if (branch.isNullOrBlank()) {
143166
Logger.warn("No HEAD information found: ${currentRepository?.currentBranch}")
144-
prState = PullRequestState.NoPullRequest
167+
setNewPullRequestState(PullRequestState.NoPullRequest)
145168
return
146169
}
147170

148171
if (branch == repo.defaultBranch.name) {
149172
Logger.info("Current branch is the default branch: $branch")
150-
prState = PullRequestState.NoPullRequest
173+
setNewPullRequestState(PullRequestState.NoPullRequest)
151174
return
152175
}
153176

154-
ProgressManager.getInstance().run(object: Task.Backgroundable(project, "Loading pull request", false) {
177+
ProgressManager.getInstance().run(object : Task.Backgroundable(project, "Loading pull request", false) {
155178
override fun run(indicator: com.intellij.openapi.progress.ProgressIndicator) {
156179
GlobalScope.launch {
157180
try {
@@ -162,9 +185,7 @@ class RepositoryManager(private val project: Project) {
162185

163186
if (pr == null) {
164187
Logger.info("No PR found in Codacy for: $branch")
165-
prState = PullRequestState.NoPullRequest
166-
// Evaluate branch state after PR discovery fails
167-
evaluateBranchState()
188+
setNewPullRequestState(PullRequestState.NoPullRequest)
168189

169190
if (loadAttempts < MAX_LOAD_ATTEMPTS) {
170191
loadTimeout.startTimeout(LOAD_RETRY_TIME) {
@@ -185,9 +206,7 @@ class RepositoryManager(private val project: Project) {
185206
notifyDidUpdatePullRequest()
186207
}
187208

188-
prState = PullRequestState.Loaded
189-
// Evaluate branch state after PR is loaded
190-
evaluateBranchState()
209+
setNewPullRequestState(PullRequestState.Loaded)
191210
} catch (e: Exception) {
192211
Logger.error("Error loading pull request: ${e.message}")
193212
}
@@ -208,11 +227,21 @@ class RepositoryManager(private val project: Project) {
208227
val stateChange: Boolean = newState !== state
209228
state = newState
210229
if (stateChange) {
230+
Telemetry.track(RepositoryStateChangeEvent(newState.name))
211231
// TODO("execute command setContext")
212232
notifyDidChangeState()
213233
}
214234
}
215235

236+
fun setNewPullRequestState(newState: PullRequestState) {
237+
val stateChange: Boolean = newState !== prState
238+
prState = newState
239+
if (stateChange) {
240+
// Track pull request state change telemetry
241+
Telemetry.track(PullRequestStateChangeEvent(newState.name))
242+
}
243+
}
244+
216245
fun onDidUpdatePullRequest(listener: () -> Unit): Disposable {
217246
onDidUpdatePullRequestListeners.add(listener)
218247
return Disposable { onDidUpdatePullRequestListeners.remove(listener) }
Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.codacy.intellij.plugin.services.paths
22

3+
import com.codacy.intellij.plugin.services.common.OsType
4+
import com.codacy.intellij.plugin.services.common.SystemDetectionService
35
import com.codacy.intellij.plugin.services.paths.behaviour.PathsUnix
46
import com.codacy.intellij.plugin.services.paths.behaviour.PathsWindows
57
import com.intellij.openapi.project.Project
@@ -16,21 +18,16 @@ interface PathsBehaviour {
1618

1719
object Factory {
1820
fun build(): PathsBehaviour {
19-
val systemOs = System.getProperty("os.name").lowercase()
21+
val osType = SystemDetectionService.detectOs()
2022

2123
val pathsInstance = when {
22-
systemOs == "mac os x" || systemOs.contains("darwin") -> PathsUnix()
23-
24-
systemOs == "linux" -> PathsUnix()
25-
26-
systemOs.contains("windows") -> PathsWindows()
27-
28-
else -> {
29-
throw IllegalStateException("Unsupported OS: $systemOs")
30-
}
24+
osType == OsType.MacOS -> PathsUnix()
25+
osType == OsType.Linux -> PathsUnix()
26+
osType == OsType.Windows -> PathsWindows()
27+
else -> throw IllegalStateException("Unsupported OS: $osType")
3128
}
3229

3330
return pathsInstance
3431
}
3532
}
36-
}
33+
}

src/main/kotlin/com/codacy/intellij/plugin/telemetry/Telemetry.kt

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.codacy.intellij.plugin.telemetry
22

33
import com.codacy.intellij.plugin.services.common.Config
4+
import com.codacy.intellij.plugin.services.common.SystemDetectionService
5+
import com.intellij.openapi.application.ApplicationNamesInfo
46
import com.intellij.openapi.components.Service
57
import com.segment.analytics.kotlin.core.Analytics
68

@@ -21,18 +23,15 @@ data object ExtensionUnloadedEvent : TelemetryEvent("extension_unloaded") {
2123
}
2224

2325
data class RepositoryStateChangeEvent(val state: String) : TelemetryEvent("Repository State Change") {
24-
override fun toPayload(): Map<String, Any?> =
25-
mapOf("state" to state)
26+
override fun toPayload(): Map<String, Any?> = mapOf("state" to state)
2627
}
2728

2829
data class BranchStateChangeEvent(val state: String) : TelemetryEvent("Branch State Change") {
29-
override fun toPayload(): Map<String, Any?> =
30-
mapOf("state" to state)
30+
override fun toPayload(): Map<String, Any?> = mapOf("state" to state)
3131
}
3232

3333
data class PullRequestStateChangeEvent(val state: String) : TelemetryEvent("Pull Request State Change") {
34-
override fun toPayload(): Map<String, Any?> =
35-
mapOf("state" to state)
34+
override fun toPayload(): Map<String, Any?> = mapOf("state" to state)
3635
}
3736

3837
data class UnexpectedErrorEvent(val message: String) : TelemetryEvent("Unexpected Error") {
@@ -43,9 +42,10 @@ data class UnexpectedErrorEvent(val message: String) : TelemetryEvent("Unexpecte
4342
@Service
4443
object Telemetry {
4544

46-
private const val IDE: String = "jetbrains"
47-
48-
private val os: String = (System.getProperty("os.name") ?: "unknown").lowercase()
45+
private val ide: String by lazy {
46+
"JetBrains ${SystemDetectionService.detectIde()}"
47+
}
48+
private val os: String by lazy { SystemDetectionService.detectOs().toString() }
4949

5050
private val analytics: Analytics by lazy {
5151
Analytics("ckhmOOSC1drlNKLYmzbK6BAJo8drHqNQ") {
@@ -64,7 +64,7 @@ object Telemetry {
6464
userId = userId.toString(),
6565
traits = mapOf(
6666
"anonymousId" to anonymousId,
67-
"ide" to IDE,
67+
"ide" to ide,
6868
"os" to os
6969
)
7070
)
@@ -80,7 +80,7 @@ object Telemetry {
8080
properties = mapOf(
8181
"anonymousId" to anonymousId,
8282
"userId" to userId,
83-
"ide" to IDE,
83+
"ide" to ide,
8484
"os" to os
8585
) + event.toPayload()
8686
)

0 commit comments

Comments
 (0)