Skip to content

Commit 7e30da3

Browse files
SurpSGSergii Gnatiuk
andauthored
Release 0.0.4 (#2)
* migrate to intellij 2021.1 * diff coverage view flat structure Co-authored-by: Sergii Gnatiuk <sergii.gnatiuk@worldapp.com>
1 parent 7cadde2 commit 7e30da3

11 files changed

Lines changed: 126 additions & 103 deletions

File tree

.github/workflows/build.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,12 @@ jobs:
4343
- name: Fetch Sources
4444
uses: actions/checkout@v2
4545

46-
# Setup Java 1.8 environment for the next steps
46+
# Setup Java 11 environment for the next steps
4747
- name: Setup Java
48-
uses: actions/setup-java@v1
48+
uses: actions/setup-java@v2
4949
with:
50-
java-version: 1.8
50+
distribution: 'adopt'
51+
java-version: 11
5152

5253
# Cache Gradle dependencies
5354
- name: Setup Cache
@@ -88,11 +89,12 @@ jobs:
8889
- name: Fetch Sources
8990
uses: actions/checkout@v2
9091

91-
# Setup Java 1.8 environment for the next steps
92+
# Setup Java 11 environment for the next steps
9293
- name: Setup Java
93-
uses: actions/setup-java@v1
94+
uses: actions/setup-java@v2
9495
with:
95-
java-version: 1.8
96+
distribution: 'adopt'
97+
java-version: 11
9698

9799
# Cache Gradle dependencies
98100
- name: Setup Cache

.github/workflows/release.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@ jobs:
2121
with:
2222
ref: ${{ github.event.release.tag_name }}
2323

24-
# Setup Java 1.8 environment for the next steps
24+
# Setup Java 11 environment for the next steps
2525
- name: Setup Java
26-
uses: actions/setup-java@v1
26+
uses: actions/setup-java@v2
2727
with:
28-
java-version: 1.8
28+
distribution: 'adopt'
29+
java-version: 11
2930

3031
# Publish the plugin to the Marketplace
3132
- name: Publish Plugin
@@ -46,11 +47,12 @@ jobs:
4647
with:
4748
ref: ${{ github.event.release.tag_name }}
4849

49-
# Setup Java 1.8 environment for the next steps
50+
# Setup Java 11 environment for the next steps
5051
- name: Setup Java
51-
uses: actions/setup-java@v1
52+
uses: actions/setup-java@v2
5253
with:
53-
java-version: 1.8
54+
distribution: 'adopt'
55+
java-version: 11
5456

5557
# Update Unreleased section with the current version
5658
- name: Patch Changelog

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,11 @@
33
# diff-coverage-idea-plugin Changelog
44

55
## [Unreleased]
6+
### Fixed
7+
- Intellij 2021.1 compatibility
8+
### Changed
9+
- Code coverage classes list flat structure
10+
11+
## [0.0.3]
612
### Added
713
- Initial scaffold created from [IntelliJ Platform Plugin Template](https://github.com/JetBrains/intellij-platform-plugin-template)

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ Diff coverage IDEA plugin does:
1919
- [x] Create a new [IntelliJ Platform Plugin Template][template] project.
2020
- [x] Verify the [pluginGroup](/gradle.properties), [plugin ID](/src/main/resources/META-INF/plugin.xml) and [sources package](/src/main/kotlin).
2121
- [x] Review the [Legal Agreements](https://plugins.jetbrains.com/docs/marketplace/legal-agreements.html).
22-
- [ ] [Publish a plugin manually](https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/publishing_plugin.html) for the first time.
23-
- [ ] Set the Plugin ID in the above README badges.
24-
- [ ] Set the [Deployment Token](https://plugins.jetbrains.com/docs/marketplace/plugin-upload.html).
25-
- [ ] Click the <kbd>Watch</kbd> button on the top of the [IntelliJ Platform Plugin Template][template] to be notified about releases containing new features and fixes.
22+
- [x] [Publish a plugin manually](https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/publishing_plugin.html) for the first time.
23+
- [x] Set the Plugin ID in the above README badges.
24+
- [x] Set the [Deployment Token](https://plugins.jetbrains.com/docs/marketplace/plugin-upload.html).
25+
- [x] Click the <kbd>Watch</kbd> button on the top of the [IntelliJ Platform Plugin Template][template] to be notified about releases containing new features and fixes.
2626

2727
<!-- Plugin description -->
2828

build.gradle.kts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ plugins {
1818
id("org.jetbrains.changelog") version "0.4.0"
1919
// detekt linter - read more: https://detekt.github.io/detekt/kotlindsl.html
2020
id("io.gitlab.arturbosch.detekt") version "1.10.0"
21-
// ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle
22-
id("org.jlleitschuh.gradle.ktlint") version "10.0.0"
2321
}
2422

2523
// Import variables from gradle.properties file
@@ -103,7 +101,7 @@ tasks {
103101
// Extract the <!-- Plugin description --> section from README.md and provide for the plugin's manifest
104102
pluginDescription(
105103
closure {
106-
File("./README.md").readText().lines().run {
104+
File(project.rootDir, "README.md").readText().lines().run {
107105
val start = "<!-- Plugin description -->"
108106
val end = "<!-- Plugin description end -->"
109107

detekt-config.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,7 @@ complexity:
2424
NestedBlockDepth:
2525
active: true
2626
threshold: 6 # TODO set to 3
27+
28+
formatting:
29+
NoWildcardImports:
30+
active: false

gradle.properties

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33

44
pluginGroup = com.github.surpsg.diffcoverage
55
pluginName = Diff Coverage
6-
pluginVersion = 0.0.3
6+
pluginVersion = 0.0.4
77
pluginSinceBuild = 203
8-
pluginUntilBuild = 203.*
9-
pluginVerifierIdeVersions = 2020.3.2, 2020.3.3
8+
pluginUntilBuild = 211.*
9+
pluginVerifierIdeVersions = 2020.3.2, 2020.3.3, 2021.1
1010

1111
platformType = IC
12-
platformVersion = 2020.3.2
12+
platformVersion = 2021.1
1313
platformDownloadSources = true
Lines changed: 80 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.github.surpsg.diffcoverage.extensions
22

3+
import com.form.diff.ClassFile
34
import com.github.surpsg.diffcoverage.services.diff.ModifiedFilesService
45
import com.intellij.coverage.CoverageSuitesBundle
56
import com.intellij.coverage.JavaCoverageAnnotator
@@ -12,9 +13,7 @@ import com.intellij.ide.util.treeView.AbstractTreeNode
1213
import com.intellij.openapi.application.ReadAction
1314
import com.intellij.openapi.components.service
1415
import com.intellij.openapi.project.Project
15-
import com.intellij.psi.PsiClass
16-
import com.intellij.psi.PsiElement
17-
import com.intellij.psi.PsiPackage
16+
import com.intellij.psi.*
1817
import com.intellij.psi.search.GlobalSearchScope
1918
import java.io.File
2019
import java.nio.file.Paths
@@ -28,100 +27,117 @@ class DiffCoverageViewExtension(
2827
annotator, project, suitesBundle, stateBean
2928
) {
3029

31-
override fun getChildrenNodes(node: AbstractTreeNode<*>?): List<AbstractTreeNode<*>> {
32-
val children: MutableList<AbstractTreeNode<*>> = ArrayList()
30+
private val codeUpdateInfo = myProject.service<ModifiedFilesService>().obtainCodeUpdateInfo()
31+
private val packageCoverageData = PackageCoverageData(myProject)
3332

33+
override fun getChildrenNodes(node: AbstractTreeNode<*>?): List<AbstractTreeNode<*>> {
3434
if (node !is CoverageListNode || node.getValue() is PsiClass) {
35-
return children
35+
return emptyList()
3636
}
37+
38+
var children: Sequence<AbstractTreeNode<*>> = emptySequence()
3739
val nodeValue = node.getValue()
3840
if (nodeValue is PsiPackage) {
39-
val packageCoverageData = PackageCoverageData(myProject)
40-
if (isInCoverageScope(packageCoverageData, nodeValue)) {
41-
directChildrenSequence(nodeValue, PsiPackage::getSubPackages).forEach { subPackage ->
42-
processSubPackage(packageCoverageData, subPackage, children)
43-
}
44-
directChildrenSequence(nodeValue, PsiPackage::getFiles).forEach { file ->
45-
collectFileChildren(file, node, children)
46-
}
47-
} else if (!myStateBean.myFlattenPackages) {
48-
collectSubPackages(packageCoverageData, children, nodeValue)
49-
}
41+
children += collectClasses(nodeValue)
5042
}
5143
if (node is CoverageListRootNode) {
52-
mySuitesBundle.suites.asSequence()
44+
children += mySuitesBundle.suites.asSequence()
5345
.flatMap { mySuitesBundle.suites.asSequence() }
5446
.map { suite -> suite as JavaCoverageSuite }
5547
.flatMap { it.getCurrentSuiteClasses(myProject) }
56-
.forEach {
57-
children += CoverageListNode(myProject, it, mySuitesBundle, myStateBean)
58-
}
48+
.map { CoverageListNode(myProject, it, mySuitesBundle, myStateBean) }
5949
}
6050

61-
return children.onEach {
62-
it.parent = node
63-
}
51+
return children.onEach { it.parent = node }.toList()
6452
}
6553

66-
private fun <T> directChildrenSequence(
67-
nodePackage: PsiPackage,
68-
childrenItemsGetter: (PsiPackage, GlobalSearchScope) -> Array<T>
69-
): Sequence<T> {
70-
return ReadAction.compute<Sequence<T>, RuntimeException> {
71-
if (nodePackage.isValid) {
72-
childrenItemsGetter(nodePackage, getSearchScope()).asSequence()
73-
} else {
74-
emptySequence()
54+
private fun collectClasses(psiPackage: PsiPackage): Sequence<AbstractTreeNode<*>> {
55+
var children = emptySequence<AbstractTreeNode<*>>()
56+
val currentPackages = ArrayDeque<PsiPackage>().apply { this += psiPackage }
57+
while (!currentPackages.isEmpty()) {
58+
val currentPackage = currentPackages.removeFirst()
59+
if (getInReadThread { !currentPackage.isValid }) {
60+
continue
7561
}
76-
}
77-
}
7862

79-
private fun getSearchScope(): GlobalSearchScope {
80-
return mySuitesBundle.getSearchScope(myProject)
81-
}
63+
if (packageCoverageData.isPackageInScope(currentPackage)) {
64+
children += currentPackage.directChildrenSequence(PsiPackage::getFiles).flatMap { file ->
65+
collectChildrenClasses(file)
66+
}
67+
}
8268

83-
private fun collectSubPackages(
84-
packageCoverageData: PackageCoverageData,
85-
children: MutableList<AbstractTreeNode<*>>,
86-
rootPackage: PsiPackage
87-
) {
88-
ReadAction.compute<Array<PsiPackage>, RuntimeException> {
89-
rootPackage.getSubPackages(getSearchScope())
90-
}.forEach {
91-
processSubPackage(packageCoverageData, it, children)
69+
currentPackage.directChildrenSequence(PsiPackage::getSubPackages)
70+
.filter { packageCoverageData.isParentPackageForDiffPackages(it) }
71+
.forEach { currentPackages += it }
9272
}
73+
return children
9374
}
9475

95-
private fun processSubPackage(
96-
packageCoverageData: PackageCoverageData,
97-
aPackage: PsiPackage,
98-
children: MutableList<AbstractTreeNode<*>>
99-
) {
100-
if (isInCoverageScope(packageCoverageData, aPackage)) {
101-
children += CoverageListNode(myProject, aPackage, mySuitesBundle, myStateBean)
102-
} else if (!myStateBean.myFlattenPackages) {
103-
collectSubPackages(packageCoverageData, children, aPackage)
104-
}
105-
if (myStateBean.myFlattenPackages) {
106-
collectSubPackages(packageCoverageData, children, aPackage)
76+
private fun <T> PsiPackage.directChildrenSequence(
77+
childrenItemsGetter: (PsiPackage, GlobalSearchScope) -> Array<T>
78+
): Sequence<T> {
79+
return getValidValue(emptySequence()) {
80+
val searchScope = mySuitesBundle.getSearchScope(myProject)
81+
childrenItemsGetter(this, searchScope).asSequence()
10782
}
10883
}
10984

110-
private fun isInCoverageScope(packageCoverageData: PackageCoverageData, element: PsiElement): Boolean {
111-
return ReadAction.compute<Boolean, RuntimeException> {
112-
element is PsiPackage && packageCoverageData.isPackageInScope(element)
85+
private fun collectChildrenClasses(file: PsiFile): Sequence<AbstractTreeNode<*>> {
86+
return if (file is PsiClassOwner) {
87+
file.getValidValue(PsiClass.EMPTY_ARRAY, PsiClassOwner::getClasses)
88+
.asSequence()
89+
.filter { isFileModified(it) }
90+
.map { CoverageListNode(myProject, it, mySuitesBundle, myStateBean) }
91+
} else {
92+
emptySequence()
11393
}
11494
}
11595

96+
private fun isFileModified(psiClass: PsiClass): Boolean {
97+
val qualifiedClassName = psiClass.getValidValue(null) { qualifiedName } ?: return false
98+
val classFile = ClassFile(psiClass.containingFile.name, qualifiedClassName)
99+
100+
return codeUpdateInfo.isInfoExists(classFile)
101+
}
102+
116103
class PackageCoverageData(project: Project) {
117104
private val diffPackages: Set<String> = project.service<ModifiedFilesService>()
118105
.buildPatchCollection().asSequence()
119106
.map { Paths.get(it.path).parent.toString() }
120107
.map { it.replace(File.separator, ".") }
121108
.toSet()
122109

123-
fun isPackageInScope(psiPackage: PsiPackage): Boolean = diffPackages.any {
124-
it.endsWith(psiPackage.qualifiedName)
110+
fun isPackageInScope(psiPackage: PsiPackage): Boolean {
111+
return psiPackage.isPackageFiltered { packageCandidate, diffPackage ->
112+
diffPackage.endsWith(packageCandidate)
113+
}
114+
}
115+
116+
fun isParentPackageForDiffPackages(psiPackage: PsiPackage): Boolean {
117+
return psiPackage.isPackageFiltered { packageCandidate, diffPackage ->
118+
diffPackage.contains(packageCandidate)
119+
}
120+
}
121+
122+
private fun PsiPackage.isPackageFiltered(
123+
filterCondition: (String, String) -> Boolean
124+
): Boolean {
125+
val qualifiedNamePackage = ReadAction.compute<String, RuntimeException>(::getQualifiedName)
126+
return diffPackages.any { filterCondition(qualifiedNamePackage, it) }
127+
}
128+
}
129+
130+
private fun <T> getInReadThread(func: () -> T): T {
131+
return ReadAction.compute<T, RuntimeException>(func)
132+
}
133+
134+
private fun <T : PsiElement, V> T.getValidValue(defaultValue: V, valueGetter: T.() -> V): V {
135+
return getInReadThread {
136+
if (isValid) {
137+
valueGetter()
138+
} else {
139+
defaultValue
140+
}
125141
}
126142
}
127143
}

src/main/kotlin/com/github/surpsg/diffcoverage/services/notifications/BalloonNotificationService.kt

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,20 @@ package com.github.surpsg.diffcoverage.services.notifications
22

33
import com.github.surpsg.diffcoverage.DiffCoverageBundle
44
import com.github.surpsg.diffcoverage.properties.PLUGIN_NAME
5-
import com.intellij.notification.NotificationDisplayType
6-
import com.intellij.notification.NotificationGroup
7-
import com.intellij.notification.NotificationListener
8-
import com.intellij.notification.NotificationType
9-
import com.intellij.notification.Notifications
5+
import com.intellij.notification.*
106
import com.intellij.openapi.components.Service
117
import com.intellij.openapi.project.Project
128

139
@Service
1410
class BalloonNotificationService(private val project: Project) {
1511

1612
fun notify(
17-
group: NotificationGroup = DIFF_COVERAGE_BALLOON,
1813
notificationType: NotificationType = NotificationType.INFORMATION,
1914
notificationListener: NotificationListener? = null,
2015
message: String
2116
) {
2217
Notifications.Bus.notify(
23-
group.createNotification(
18+
getNotificationGroup().createNotification(
2419
DiffCoverageBundle.message(PLUGIN_NAME),
2520
message,
2621
notificationType,
@@ -30,11 +25,7 @@ class BalloonNotificationService(private val project: Project) {
3025
)
3126
}
3227

33-
companion object {
34-
val DIFF_COVERAGE_BALLOON = NotificationGroup(
35-
"diff.coverage.notification.balloon",
36-
NotificationDisplayType.BALLOON,
37-
true
38-
)
28+
private fun getNotificationGroup(): NotificationGroup {
29+
return NotificationGroupManager.getInstance().getNotificationGroup("diff.coverage.notification")
3930
}
4031
}

src/main/resources/META-INF/plugin.xml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
]]></description>
1515

1616
<change-notes>Initial release of the plugin.</change-notes>
17-
<version>0.0.3</version>
17+
<version>0.0.4</version>
1818

1919
<!-- Product and plugin compatibility requirements -->
2020
<!-- https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html -->
@@ -41,7 +41,9 @@
4141
implementation="com.github.surpsg.diffcoverage.extensions.DiffCoverageEngine"
4242
order="last"/>
4343

44-
<notification.parentGroup id="diff.coverage.notification" title="Diff Coverage notifications"/>
45-
<notification.group parentId="diff.coverage.notification" groupId="diff.coverage.notification.balloon"/>
44+
<notificationGroup id="diff.coverage.notification"
45+
bundle="messages.DiffCoverageBundle"
46+
displayType="TOOL_WINDOW"
47+
key="diff.coverage.notification.group.name"/>
4648
</extensions>
4749
</idea-plugin>

0 commit comments

Comments
 (0)