Skip to content

Commit

Permalink
Merge pull request #133 from amosproj/Feature/103-Error-message-if-co…
Browse files Browse the repository at this point in the history
…mpanion-Gradle-plugin-for-MutationMate-is-missing

Feature/103 error message if companion gradle plugin for mutation mate is missing
  • Loading branch information
nikomall34 authored Dec 13, 2023
2 parents d0349b1 + 99d2b66 commit 32f79ed
Show file tree
Hide file tree
Showing 21 changed files with 643 additions and 40 deletions.
28 changes: 14 additions & 14 deletions .github/linters/.groovylintrc.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{
"extends": "recommended",
"rules": {
"BlankLineBeforePackage": {
"enabled": false
},
"JUnitPublicNonTestMethod": {
"enabled": false
},
"MethodName": {
"enabled": false
},
"CatchException": {
"enabled": false
}
"extends": "recommended",
"rules": {
"BlankLineBeforePackage": {
"enabled": false
},
"JUnitPublicNonTestMethod": {
"enabled": false
},
"MethodName": {
"enabled": false
},
"CatchException": {
"enabled": false
}
}
}
1 change: 0 additions & 1 deletion .github/linters/.yaml-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,3 @@ rules:
new-lines:
type: unix
trailing-spaces: disable

11 changes: 5 additions & 6 deletions .github/workflows/override-build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,14 @@ jobs:
with:
distribution: temurin
java-version: 11

- name: Setup Gradle
uses: gradle/gradle-build-action@v2

- name: Build with Gradle
run: ./gradlew build --no-daemon
working-directory: 'pitmutationmate-override-plugin'

- name: Run Tests
run: ./gradlew test --no-daemon
working-directory: 'pitmutationmate-override-plugin'
working-directory: "pitmutationmate-override-plugin"

- name: Run Tests
run: ./gradlew test --no-daemon
working-directory: "pitmutationmate-override-plugin"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ bin/

# MacOS
.DS_Store

# Groovy SDK
lib
1 change: 0 additions & 1 deletion pitmutationmate-override-plugin/.gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,3 @@

# These are Windows script files and should use crlf
*.bat text eol=crlf

6 changes: 3 additions & 3 deletions pitmutationmate-override-plugin/gradlew.bat
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
REM SPDX-FileCopyrightText: the original authors
REM
REM SPDX-License-Identifier: Apache-2.0
@rem SPDX-FileCopyrightText: the original authors
@rem
@rem SPDX-License-Identifier: Apache-2.0

@rem
@rem Copyright 2015 the original author or authors.
Expand Down
5 changes: 1 addition & 4 deletions pitmutationmate/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ dependencies {
implementation("org.jfree:jfreechart:1.0.19")
// https://mvnrepository.com/artifact/jfree/jcommon
implementation("org.jfree:jcommon:1.0.24")
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.0")

// https://mvnrepository.com/artifact/org.mockito/mockito-core
testImplementation("org.mockito:mockito-core:5.8.0")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1")
Expand All @@ -38,9 +36,8 @@ repositories {
// Configure Gradle IntelliJ Plugin
// Read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
intellij {
version.set("2022.2.5")
version.set("2023.1")
type.set("IC") // Target IDE Platform

plugins.set(listOf("org.jetbrains.kotlin", "com.intellij.java"))
}

Expand Down
6 changes: 3 additions & 3 deletions pitmutationmate/gradlew.bat
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
REM SPDX-FileCopyrightText: the original authors
REM
REM SPDX-License-Identifier: Apache-2.0
@rem SPDX-FileCopyrightText: the original authors
@rem
@rem SPDX-License-Identifier: Apache-2.0

@rem Copyright 2015 the original author or authors.
@rem
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2023

package com.amos.pitmutationmate.pitmutationmate.plugincheck

import org.codehaus.groovy.ast.CodeVisitorSupport
import org.codehaus.groovy.ast.expr.MethodCallExpression

class PluginCheckerGroovy : CodeVisitorSupport() {

var pitestPluginAvailable = false
var companionPluginAvailable = false

override fun visitMethodCallExpression(call: MethodCallExpression?) {
val method = call?.methodAsString
if (method.equals("plugins") || method.equals("apply") || method.equals("version")) {
super.visitMethodCallExpression(call)
} else if (method.equals("id")) {
if (call != null) {
val pluginName = call.arguments.text
if (pluginName.contains("pitest")) {
pitestPluginAvailable = true
}
if (pluginName.contains("io.github.amosproj.pitmutationmate.override")) {
companionPluginAvailable = true
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2023

package com.amos.pitmutationmate.pitmutationmate.plugincheck

import org.jetbrains.kotlin.idea.structuralsearch.visitor.KotlinRecursiveElementVisitor
import org.jetbrains.kotlin.psi.KtCallExpression

class PluginCheckerKotlin : KotlinRecursiveElementVisitor() {

var pitestPluginAvailable = false
var companionPluginAvailable = false

override fun visitCallExpression(expression: KtCallExpression) {
val method = expression.calleeExpression?.text
if (method.equals("plugins")) {
expression.acceptChildren(this)
}
if (method.equals("id")) {
if (expression.valueArgumentList != null) {
for (arg in expression.valueArgumentList!!.arguments) {
val pluginName = arg.text
if (pluginName.contains("pitest")) {
pitestPluginAvailable = true
}
if (pluginName.contains("io.github.amosproj.pitmutationmate.override")) {
companionPluginAvailable = true
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2023

package com.amos.pitmutationmate.pitmutationmate.plugincheck

import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.ProjectActivity
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.psi.PsiManager
import org.apache.commons.io.IOUtils
import org.codehaus.groovy.ast.builder.AstBuilder
import java.io.File
import java.io.FileInputStream

class StartupPluginChecker : ProjectActivity {

override suspend fun execute(project: Project) {
ApplicationManager.getApplication().invokeLater {
checkGroovyBuildFile(project)
checkKotlinBuildFile(project)
}
}

private fun checkKotlinBuildFile(project: Project) {
val buildFileName = "build.gradle.kts"
val kotlinBuildFile = File(project.basePath + "/$buildFileName")
if (kotlinBuildFile.exists()) {
val virtualFile = LocalFileSystem.getInstance().findFileByIoFile(kotlinBuildFile)
if (virtualFile != null) {
val psiFile = PsiManager.getInstance(project).findFile(virtualFile)
val pluginCheckerKotlin = PluginCheckerKotlin()
psiFile?.node?.psi?.accept(pluginCheckerKotlin)
val pitestPluginText = "id(\"info.solidsoft.pitest\") version \"x.y.z\""
val companionPluginText = "id(\"io.github.amosproj.pitmutationmate.override\") version \"x.y.z\""
throwErrorMessage(
pluginCheckerKotlin.pitestPluginAvailable,
pluginCheckerKotlin.companionPluginAvailable,
buildFileName,
project,
pitestPluginText,
companionPluginText
)
}
}
}

private fun checkGroovyBuildFile(project: Project) {
val buildFileName = "build.gradle"
val groovyBuildFile = File(project.basePath + "/$buildFileName")
if (groovyBuildFile.exists()) {
val builder = AstBuilder()
val nodes = builder.buildFromString(
IOUtils.toString(
FileInputStream(groovyBuildFile),
"UTF-8"
)
)
val pluginCheckerGroovy = PluginCheckerGroovy()
for (node in nodes) {
node.visit(pluginCheckerGroovy)
}
val pitestPluginText = "id 'info.solidsoft.pitest' version 'x.y.z'"
val companionPluginText = "id 'io.github.amosproj.pitmutationmate.override' version 'x.y.z'"
throwErrorMessage(
pluginCheckerGroovy.pitestPluginAvailable,
pluginCheckerGroovy.companionPluginAvailable,
buildFileName,
project,
pitestPluginText,
companionPluginText
)
}
}

private fun throwErrorMessage(
pitestPluginAvailable: Boolean,
companionPluginAvailable: Boolean,
buildFileName: String,
project: Project,
pitestPluginText: String,
companionPluginText: String
) {
var errorMessage = ""
if (!pitestPluginAvailable) {
errorMessage += String.format(
ERROR_MESSAGE_PITEST_PLUGIN_MISSING,
buildFileName,
pitestPluginText
)
}
if (!companionPluginAvailable) {
errorMessage += String.format(
ERROR_MESSAGE_COMPANION_PLUGIN_MISSING,
buildFileName,
companionPluginText
)
}
if (errorMessage.isNotEmpty()) {
Messages.showErrorDialog(project, errorMessage, ERROR_MESSAGE_TITLE)
}
}

companion object {
private const val ERROR_MESSAGE_TITLE = "Plugins for PITMutationPlugin are missing"
private const val ERROR_MESSAGE_PITEST_PLUGIN_MISSING = "The pitest gradle Plugin is missing.\n" +
"Please add a Gradle Pitest Plugin to the %s file like the following:\n" +
"%s\nAnd see the pitest docs for missing configurations of pitest\n\n"
private const val ERROR_MESSAGE_COMPANION_PLUGIN_MISSING = "The Companion Plugin is missing.\n" +
"Please add the following line to your %s file:\n%s\n\n"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.MessageType
import com.intellij.openapi.wm.ToolWindowManager
import org.jetbrains.kotlin.idea.gradleTooling.get
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.util.*

/**
* A simple UDP server that listens on a given port and prints the received messages.
Expand Down Expand Up @@ -66,7 +66,7 @@ class UdpMessagingServer(private val project: Project) {
if (overrideClassFQN != null && message.contains(overrideClassFQN)) {
// class was successfully overridden. Notify the user
ToolWindowManager.getInstance(project).notifyByBalloon(
"Pitest Result",
"Pitest",
MessageType.INFO,
"<p>Successfully applied pitest target class</p><p>$overrideClassFQN.</p>"
)
Expand Down
9 changes: 3 additions & 6 deletions pitmutationmate/src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,12 @@
<!-- Extension points defined by the plugin.
Read more: https://plugins.jetbrains.com/docs/intellij/plugin-extension-points.html -->
<extensions defaultExtensionNs="com.intellij">

<toolWindow id="Pitest" secondary="false" icon="AllIcons.Toolwindows.WebToolWindow" anchor="right"
<toolWindow id="Pitest" secondary="false" icon="AllIcons.Toolwindows.WebToolWindow" anchor="right"
factoryClass="com.amos.pitmutationmate.pitmutationmate.MutationTestToolWindowFactory"/>

<runLineMarkerContributor implementationClass="com.amos.pitmutationmate.pitmutationmate.actions.GutterMarker"
language=""/>

<configurationType
implementation="com.amos.pitmutationmate.pitmutationmate.configuration.RunConfigurationType"/>
<configurationType implementation="com.amos.pitmutationmate.pitmutationmate.configuration.RunConfigurationType"/>
<backgroundPostStartupActivity implementation="com.amos.pitmutationmate.pitmutationmate.plugincheck.StartupPluginChecker"/>
</extensions>
<actions>
<action id="com.amos.pitmutationmate.pitmutationmate.actions.ToolMenuAction"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2023

package com.amos.pitmutationmate.pitmutationmate

import com.amos.pitmutationmate.pitmutationmate.plugincheck.PluginCheckerGroovy
import org.apache.commons.io.IOUtils
import org.codehaus.groovy.ast.builder.AstBuilder
import org.junit.jupiter.api.Test
import java.io.File
import java.io.FileInputStream

class PluginCeckerTest {

private fun runPluginCheckerForTestFile(testFile: String): PluginCheckerGroovy {
val builder = AstBuilder()
val testFile = File("src/test/resources/test_build_scripts/$testFile")
val nodes = builder.buildFromString(
IOUtils.toString(
FileInputStream(testFile),
"UTF-8"
)
)
val pluginCheck = PluginCheckerGroovy()
for (node in nodes) {
node.visit(pluginCheck)
}
return pluginCheck
}

@Test
fun checkTestBuildFile1_groovy() {
val pluginCheck = runPluginCheckerForTestFile("testbuild1.gradle")
assert(pluginCheck.pitestPluginAvailable)
assert(pluginCheck.companionPluginAvailable)
}

@Test
fun checkTestBuildFile2_groovy() {
val pluginCheck = runPluginCheckerForTestFile("testbuild2.gradle")
assert(!pluginCheck.pitestPluginAvailable)
assert(pluginCheck.companionPluginAvailable)
}

@Test
fun checkTestBuildFile3_groovy() {
val pluginCheck = runPluginCheckerForTestFile("testbuild3.gradle")
assert(pluginCheck.pitestPluginAvailable)
assert(!pluginCheck.companionPluginAvailable)
}

@Test
fun checkTestBuildFile4_groovy() {
val pluginCheck = runPluginCheckerForTestFile("testbuild4.gradle")
assert(!pluginCheck.pitestPluginAvailable)
assert(!pluginCheck.companionPluginAvailable)
}
}
Loading

0 comments on commit 32f79ed

Please sign in to comment.