diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1a68bc2..bd82e1a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -117,6 +117,10 @@ jobs: with: gradle-home-cache-cleanup: true + # Set git config variables + - name: Set Git Config Variables + run: git config --global user.name 'Nikita Velikiy' + # Run tests - name: Run Tests run: ./gradlew check diff --git a/.gitignore b/.gitignore index e2e5d94..0fc1d59 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .idea .qodana build +src/test/testData/hooks +out \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cc4182..cd3d9c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,5 +3,7 @@ # GitGlobalHooksLocator Changelog ## [Unreleased] -### Added -- Initial scaffold created from [IntelliJ Platform Plugin Template](https://github.com/JetBrains/intellij-platform-plugin-template) + +## [0.0.1] + +- Initial release diff --git a/README.md b/README.md index 70615bc..7cafeaf 100644 --- a/README.md +++ b/README.md @@ -4,24 +4,11 @@ [![Version](https://img.shields.io/jetbrains/plugin/v/PLUGIN_ID.svg)](https://plugins.jetbrains.com/plugin/PLUGIN_ID) [![Downloads](https://img.shields.io/jetbrains/plugin/d/PLUGIN_ID.svg)](https://plugins.jetbrains.com/plugin/PLUGIN_ID) -## Template ToDo list -- [x] Create a new [IntelliJ Platform Plugin Template][template] project. -- [ ] Get familiar with the [template documentation][template]. -- [ ] Adjust the [pluginGroup](./gradle.properties), [plugin ID](./src/main/resources/META-INF/plugin.xml) and [sources package](./src/main/kotlin). -- [ ] Adjust the plugin description in `README` (see [Tips][docs:plugin-description]) -- [ ] Review the [Legal Agreements](https://plugins.jetbrains.com/docs/marketplace/legal-agreements.html?from=IJPluginTemplate). -- [ ] [Publish a plugin manually](https://plugins.jetbrains.com/docs/intellij/publishing-plugin.html?from=IJPluginTemplate) for the first time. -- [ ] Set the `PLUGIN_ID` in the above README badges. -- [ ] Set the [Plugin Signing](https://plugins.jetbrains.com/docs/intellij/plugin-signing.html?from=IJPluginTemplate) related [secrets](https://github.com/JetBrains/intellij-platform-plugin-template#environment-variables). -- [ ] Set the [Deployment Token](https://plugins.jetbrains.com/docs/marketplace/plugin-upload.html?from=IJPluginTemplate). -- [ ] Click the Watch button on the top of the [IntelliJ Platform Plugin Template][template] to be notified about releases containing new features and fixes. +## Description -This Fancy IntelliJ Platform Plugin is going to be your implementation of the brilliant ideas that you have. - -This specific section is a source for the [plugin.xml](/src/main/resources/META-INF/plugin.xml) file which will be extracted by the [Gradle](/build.gradle.kts) during the build process. - -To keep everything working, do not remove `` sections. +Intellij plugin to enable or disable global Git hooks +![Git Global Hooks Locator](src/main/resources/description.png) ## Installation @@ -34,11 +21,4 @@ To keep everything working, do not remove `` sections. - Manually: Download the [latest release](https://github.com/y0ung3r/GitGlobalHooksLocator/releases/latest) and install it manually using - Settings/Preferences > Plugins > ⚙️ > Install plugin from disk... - - ---- -Plugin based on the [IntelliJ Platform Plugin Template][template]. - -[template]: https://github.com/JetBrains/intellij-platform-plugin-template -[docs:plugin-description]: https://plugins.jetbrains.com/docs/intellij/plugin-user-experience.html#plugin-description-and-presentation + Settings/Preferences > Plugins > ⚙️ > Install plugin from disk... \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 2fdbdf8..9782186 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,6 @@ pluginVersion = 0.0.1 # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html pluginSinceBuild = 223 -pluginUntilBuild = 233.* # IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension platformType = IC @@ -19,7 +18,7 @@ platformVersion = 2022.3.3 platformPlugins = # Gradle Releases -> https://github.com/gradle/gradle/releases -gradleVersion = 8.4 +gradleVersion = 9.0 # Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib kotlin.stdlib.default.dependency = false diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/MyBundle.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/LocatorBundle.kt similarity index 83% rename from src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/MyBundle.kt rename to src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/LocatorBundle.kt index b69708e..e1acca7 100644 --- a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/MyBundle.kt +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/LocatorBundle.kt @@ -5,9 +5,9 @@ import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.PropertyKey @NonNls -private const val BUNDLE = "messages.MyBundle" +private const val BUNDLE = "messages.LocatorBundle" -object MyBundle : DynamicBundle(BUNDLE) { +object LocatorBundle : DynamicBundle(BUNDLE) { @JvmStatic fun message(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/Git.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/Git.kt new file mode 100644 index 0000000..24f80c9 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/Git.kt @@ -0,0 +1,57 @@ +package com.github.y0ung3r.gitglobalhookslocator.git + +import com.github.y0ung3r.gitglobalhookslocator.git.cli.DefaultCliCommandExecutor +import com.github.y0ung3r.gitglobalhookslocator.git.cli.NotFoundCliResponse +import com.github.y0ung3r.gitglobalhookslocator.git.exceptions.GitCommandNotFoundException +import com.github.y0ung3r.gitglobalhookslocator.git.exceptions.GitIsNotInstalledException +import com.github.y0ung3r.gitglobalhookslocator.git.exceptions.GitVersionIsNotSupportedException +import com.github.y0ung3r.gitglobalhookslocator.git.extensions.toGitResponse +import com.github.y0ung3r.gitglobalhookslocator.git.cli.interfaces.CliCommandExecutor + +class Git(private val commandExecutor: CliCommandExecutor) { + companion object { + private const val GIT_COMMAND = "git" + private const val GIT_VERSION_COMMAND = "version" + const val GIT_CONFIG_COMMAND = "config" + const val GIT_GLOBAL_COMMAND = "--global" + const val GIT_CONFIG_GET_COMMAND = "--get" + const val GIT_HOOKS_PATH_SECTION = "core.hooksPath" + + @JvmStatic + val minRequiredVersion = SemanticVersion(2, 9, 0) + + @JvmStatic + val instance = Git(DefaultCliCommandExecutor()) + } + + init { + if (getInstalledVersion() < minRequiredVersion) { + throw GitVersionIsNotSupportedException() + } + } + + fun executeCommand(vararg params: String): GitResponse { + val processBuilder = ProcessBuilder( + ArrayList().apply { + add(GIT_COMMAND) + addAll(params) + } + ) + + processBuilder.redirectErrorStream(true) + + return when (val response = commandExecutor.execute(processBuilder)) { + is NotFoundCliResponse -> throw GitCommandNotFoundException(*params) + else -> response.toGitResponse() + } + } + + fun getInstalledVersion() : SemanticVersion { + val installedVersion = executeCommand(GIT_VERSION_COMMAND) + + return when { + !installedVersion.isEmpty() -> SemanticVersion.parse(installedVersion.value) + else -> throw GitIsNotInstalledException() + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/GitResponse.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/GitResponse.kt new file mode 100644 index 0000000..b782651 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/GitResponse.kt @@ -0,0 +1,9 @@ +package com.github.y0ung3r.gitglobalhookslocator.git + +import com.github.y0ung3r.gitglobalhookslocator.git.cli.CliResponse +import com.github.y0ung3r.gitglobalhookslocator.git.cli.EmptyCliResponse + +class GitResponse(private val cliResponse: CliResponse) { + val value = cliResponse.value + fun isEmpty() = cliResponse is EmptyCliResponse +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/HookEntry.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/HookEntry.kt new file mode 100644 index 0000000..9c93052 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/HookEntry.kt @@ -0,0 +1,56 @@ +package com.github.y0ung3r.gitglobalhookslocator.git + +import com.github.y0ung3r.gitglobalhookslocator.git.exceptions.HookNotFoundException +import java.io.File +import java.nio.file.Path + +class HookEntry(private var file: File) { + companion object { + @JvmStatic + fun load(filePath: Path): HookEntry { + val file = filePath.toFile() + + if (!file.exists()) { + throw HookNotFoundException(file.name.toString()) + } + + return HookEntry(file) + } + } + + val name: String + = HooksFolder + .availableHooks + .first { file.nameWithoutExtension.contains(it) } + + fun isDisabled() + = HooksFolder + .availableHooks + .all { it != file.nameWithoutExtension } + + fun enable() { + if (!isDisabled()) { + return + } + + renameFile(name) + } + + fun disable() { + if (isDisabled()) { + return + } + + renameFile("_${file.name}") + } + + private fun renameFile(newName: String) { + file = Path + .of(file.parent, newName) + .toFile() + .let { + file.renameTo(it) + it + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/HooksFolder.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/HooksFolder.kt new file mode 100644 index 0000000..ac2a431 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/HooksFolder.kt @@ -0,0 +1,68 @@ +package com.github.y0ung3r.gitglobalhookslocator.git + +import com.github.y0ung3r.gitglobalhookslocator.git.extensions.getGlobalHooksPath +import com.intellij.openapi.diagnostic.thisLogger +import java.nio.file.Files +import java.nio.file.Path +import kotlin.io.path.nameWithoutExtension +import java.nio.file.NoSuchFileException + +class HooksFolder(git: Git) { + companion object { + @JvmStatic + val availableHooks = arrayOf( + "pre-commit", + "prepare-commit-msg", + "commit-msg", + "post-commit", + "applypatch-msg", + "pre-applypatch", + "post-applypatch", + "pre-rebase", + "post-rewrite", + "post-checkout", + "post-merge", + "pre-push", + "pre-auto-gc" + ) + } + + val hooks: List + val path: Path + + fun isEmpty(): Boolean + = hooks.isEmpty() + + init { + path = Path.of(git.getGlobalHooksPath()) + + val files = try { + Files.list(path) + } + catch (exception: NoSuchFileException) { + thisLogger() + .info("Provided hooks path doesn't exists", exception) + + emptyList() + .stream() + } + + hooks = files + .filter { + availableHooks + .any { hookName -> + it.fileName.nameWithoutExtension.contains(hookName) } + } + .map { HookEntry.load(it) } + .toList() + } + + fun isAllDisabled() + = hooks.all { it.isDisabled() } + + fun enableAll() + = hooks.forEach { it.enable() } + + fun disableAll() + = hooks.forEach { it.disable() } +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/SemanticVersion.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/SemanticVersion.kt new file mode 100644 index 0000000..f954283 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/SemanticVersion.kt @@ -0,0 +1,47 @@ +package com.github.y0ung3r.gitglobalhookslocator.git + +import com.github.y0ung3r.gitglobalhookslocator.git.exceptions.ProvidedSemanticVersionIsInvalidException + +class SemanticVersion(val major: Int, val minor: Int, val patch: Int) : Comparable { + companion object { + private const val COMPONENTS_DELIMITER = '.' + private const val VERSION_PATTERN = "(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)?" + + @JvmStatic + fun parse(version: String): SemanticVersion { + val match = Regex(VERSION_PATTERN).findAll(version).firstOrNull() + ?: throw ProvidedSemanticVersionIsInvalidException(version) + + return match.value.split(COMPONENTS_DELIMITER).let { + SemanticVersion(it[0].toInt(), it[1].toInt(), it[2].toInt()) + } + } + } + + override fun compareTo(other: SemanticVersion): Int = + when { + major > other.major -> 1 + major < other.major -> -1 + minor > other.minor -> 1 + minor < other.minor -> -1 + patch > other.patch -> 1 + patch < other.patch -> -1 + else -> 0 + } + + override fun equals(other: Any?): Boolean { + val version = other as? SemanticVersion + + return when { + version == null -> false + compareTo(version) == 0 -> true + else -> false + } + } + + override fun hashCode(): Int + = major.hashCode() * 31 + minor.hashCode() * 31 + patch.hashCode() + + override fun toString(): String + = "$major.$minor.$patch" +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/CliResponse.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/CliResponse.kt new file mode 100644 index 0000000..7a77c41 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/CliResponse.kt @@ -0,0 +1,6 @@ +package com.github.y0ung3r.gitglobalhookslocator.git.cli + +open class CliResponse(value: String) { + val value: String = value.trim() +} + diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/DefaultCliCommandExecutor.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/DefaultCliCommandExecutor.kt new file mode 100644 index 0000000..82aa735 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/DefaultCliCommandExecutor.kt @@ -0,0 +1,32 @@ +package com.github.y0ung3r.gitglobalhookslocator.git.cli + +import com.github.y0ung3r.gitglobalhookslocator.git.cli.interfaces.CliCommandExecutor +import java.io.BufferedReader +import java.io.InputStreamReader +import java.nio.charset.StandardCharsets + +class DefaultCliCommandExecutor : CliCommandExecutor { + private companion object { + const val TERMINATION_EXIT_CODE = 0 + } + + override fun execute(processBuilder: ProcessBuilder) : CliResponse { + val process = processBuilder.start() + val streamReader = InputStreamReader(process.inputStream, StandardCharsets.UTF_8) + val bufferedReader = BufferedReader(streamReader) + + val response = StringBuilder() + var line: String? = bufferedReader.readLine() + + while (line != null) { + response.append(line) + response.append(System.lineSeparator()) + line = bufferedReader.readLine() + } + + return when (process.waitFor()) { + TERMINATION_EXIT_CODE -> CliResponse(response.toString()) + else -> NotFoundCliResponse(response.toString()) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/EmptyCliResponse.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/EmptyCliResponse.kt new file mode 100644 index 0000000..8e2d846 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/EmptyCliResponse.kt @@ -0,0 +1,4 @@ +package com.github.y0ung3r.gitglobalhookslocator.git.cli + +class EmptyCliResponse + : CliResponse("") \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/NotFoundCliResponse.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/NotFoundCliResponse.kt new file mode 100644 index 0000000..536fed5 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/NotFoundCliResponse.kt @@ -0,0 +1,4 @@ +package com.github.y0ung3r.gitglobalhookslocator.git.cli + +class NotFoundCliResponse(details: String) + : CliResponse(details) \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/interfaces/CliCommandExecutor.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/interfaces/CliCommandExecutor.kt new file mode 100644 index 0000000..82f409e --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/cli/interfaces/CliCommandExecutor.kt @@ -0,0 +1,7 @@ +package com.github.y0ung3r.gitglobalhookslocator.git.cli.interfaces + +import com.github.y0ung3r.gitglobalhookslocator.git.cli.CliResponse + +interface CliCommandExecutor { + fun execute(processBuilder: ProcessBuilder): CliResponse +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/GitCommandNotFoundException.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/GitCommandNotFoundException.kt new file mode 100644 index 0000000..184eb93 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/GitCommandNotFoundException.kt @@ -0,0 +1,4 @@ +package com.github.y0ung3r.gitglobalhookslocator.git.exceptions + +class GitCommandNotFoundException(vararg params: String) + : Exception("Native Git command \"git ${params.joinToString(" ")}\" not found") \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/GitIsNotInstalledException.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/GitIsNotInstalledException.kt new file mode 100644 index 0000000..7f1de64 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/GitIsNotInstalledException.kt @@ -0,0 +1,4 @@ +package com.github.y0ung3r.gitglobalhookslocator.git.exceptions + +class GitIsNotInstalledException + : Exception("Git is not installed") \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/GitVersionIsNotSupportedException.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/GitVersionIsNotSupportedException.kt new file mode 100644 index 0000000..2000dbf --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/GitVersionIsNotSupportedException.kt @@ -0,0 +1,6 @@ +package com.github.y0ung3r.gitglobalhookslocator.git.exceptions + +import com.github.y0ung3r.gitglobalhookslocator.git.Git + +class GitVersionIsNotSupportedException + : Exception("The plugin requires Git version above ${Git.minRequiredVersion}") \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/HookNotFoundException.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/HookNotFoundException.kt new file mode 100644 index 0000000..aacc032 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/HookNotFoundException.kt @@ -0,0 +1,4 @@ +package com.github.y0ung3r.gitglobalhookslocator.git.exceptions + +class HookNotFoundException(fileName: String) + : Exception("Global hook \"$fileName\" not found") \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/ProvidedSemanticVersionIsInvalidException.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/ProvidedSemanticVersionIsInvalidException.kt new file mode 100644 index 0000000..19bc7d7 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/exceptions/ProvidedSemanticVersionIsInvalidException.kt @@ -0,0 +1,4 @@ +package com.github.y0ung3r.gitglobalhookslocator.git.exceptions + +class ProvidedSemanticVersionIsInvalidException(version: String) + : Exception("The provided version does not conform to semantic versioning: $version") \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/extensions/CliResponseExtensions.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/extensions/CliResponseExtensions.kt new file mode 100644 index 0000000..1c03e85 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/extensions/CliResponseExtensions.kt @@ -0,0 +1,7 @@ +package com.github.y0ung3r.gitglobalhookslocator.git.extensions + +import com.github.y0ung3r.gitglobalhookslocator.git.GitResponse +import com.github.y0ung3r.gitglobalhookslocator.git.cli.CliResponse + +fun CliResponse.toGitResponse(): GitResponse + = GitResponse(this) \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/extensions/GitExtensions.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/extensions/GitExtensions.kt new file mode 100644 index 0000000..aaafdf8 --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/git/extensions/GitExtensions.kt @@ -0,0 +1,14 @@ +package com.github.y0ung3r.gitglobalhookslocator.git.extensions + +import com.github.y0ung3r.gitglobalhookslocator.git.Git + +fun Git.getGlobalHooksPath(): String { + val path = executeCommand( + Git.GIT_CONFIG_COMMAND, + Git.GIT_GLOBAL_COMMAND, + Git.GIT_CONFIG_GET_COMMAND, + Git.GIT_HOOKS_PATH_SECTION + ) + + return path.value +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/listeners/MyApplicationActivationListener.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/listeners/MyApplicationActivationListener.kt deleted file mode 100644 index 4a73cf2..0000000 --- a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/listeners/MyApplicationActivationListener.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.github.y0ung3r.gitglobalhookslocator.listeners - -import com.intellij.openapi.application.ApplicationActivationListener -import com.intellij.openapi.diagnostic.thisLogger -import com.intellij.openapi.wm.IdeFrame - -internal class MyApplicationActivationListener : ApplicationActivationListener { - - override fun applicationActivated(ideFrame: IdeFrame) { - thisLogger().warn("Don't forget to remove all non-needed sample code files with their corresponding registration entries in `plugin.xml`.") - } -} diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/services/MyProjectService.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/services/MyProjectService.kt deleted file mode 100644 index 16a90e2..0000000 --- a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/services/MyProjectService.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.github.y0ung3r.gitglobalhookslocator.services - -import com.intellij.openapi.components.Service -import com.intellij.openapi.diagnostic.thisLogger -import com.intellij.openapi.project.Project -import com.github.y0ung3r.gitglobalhookslocator.MyBundle - -@Service(Service.Level.PROJECT) -class MyProjectService(project: Project) { - - init { - thisLogger().info(MyBundle.message("projectService", project.name)) - thisLogger().warn("Don't forget to remove all non-needed sample code files with their corresponding registration entries in `plugin.xml`.") - } - - fun getRandomNumber() = (1..100).random() -} diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/toolWindow/MyToolWindowFactory.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/toolWindow/MyToolWindowFactory.kt deleted file mode 100644 index 42929f8..0000000 --- a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/toolWindow/MyToolWindowFactory.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.github.y0ung3r.gitglobalhookslocator.toolWindow - -import com.intellij.openapi.components.service -import com.intellij.openapi.diagnostic.thisLogger -import com.intellij.openapi.project.Project -import com.intellij.openapi.wm.ToolWindow -import com.intellij.openapi.wm.ToolWindowFactory -import com.intellij.ui.components.JBLabel -import com.intellij.ui.components.JBPanel -import com.intellij.ui.content.ContentFactory -import com.github.y0ung3r.gitglobalhookslocator.MyBundle -import com.github.y0ung3r.gitglobalhookslocator.services.MyProjectService -import javax.swing.JButton - - -class MyToolWindowFactory : ToolWindowFactory { - - init { - thisLogger().warn("Don't forget to remove all non-needed sample code files with their corresponding registration entries in `plugin.xml`.") - } - - override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { - val myToolWindow = MyToolWindow(toolWindow) - val content = ContentFactory.getInstance().createContent(myToolWindow.getContent(), null, false) - toolWindow.contentManager.addContent(content) - } - - override fun shouldBeAvailable(project: Project) = true - - class MyToolWindow(toolWindow: ToolWindow) { - - private val service = toolWindow.project.service() - - fun getContent() = JBPanel>().apply { - val label = JBLabel(MyBundle.message("randomLabel", "?")) - - add(label) - add(JButton(MyBundle.message("shuffle")).apply { - addActionListener { - label.text = MyBundle.message("randomLabel", service.getRandomNumber()) - } - }) - } - } -} diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/ui/toolWindow/GitGlobalHooksLocatorWindow.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/ui/toolWindow/GitGlobalHooksLocatorWindow.kt new file mode 100644 index 0000000..731fbff --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/ui/toolWindow/GitGlobalHooksLocatorWindow.kt @@ -0,0 +1,101 @@ +package com.github.y0ung3r.gitglobalhookslocator.ui.toolWindow + +import com.github.y0ung3r.gitglobalhookslocator.LocatorBundle +import com.github.y0ung3r.gitglobalhookslocator.git.Git +import com.github.y0ung3r.gitglobalhookslocator.git.HookEntry +import com.github.y0ung3r.gitglobalhookslocator.git.HooksFolder +import com.intellij.ide.wizard.withVisualPadding +import com.intellij.openapi.wm.ToolWindow +import com.intellij.ui.components.JBCheckBox +import com.intellij.ui.dsl.builder.Align +import com.intellij.ui.dsl.builder.LabelPosition +import com.intellij.ui.dsl.builder.panel +import com.intellij.ui.dsl.gridLayout.HorizontalAlign +import com.intellij.ui.dsl.gridLayout.VerticalAlign +import javax.swing.JComponent + +class GitGlobalHooksLocatorWindow(toolWindow: ToolWindow) { + private val hooksFolder: HooksFolder + = HooksFolder(Git.instance) + + private val disableAllCheckBox: JBCheckBox + = createDisableAllCheckBox() + + private val hookCheckBoxes: Array + = createHookCheckBoxes() + + fun getContent(): JComponent { + if (hooksFolder.isEmpty()) { + return panel { + row { + val text = LocatorBundle + .getMessage("locator.ui.toolWindow.hooksFolderEmpty", hooksFolder.path) + + label(text) + .align(Align.CENTER) + } + } + } + + return panel { + val groupTitle = LocatorBundle + .getMessage("locator.ui.toolWindow.globalHooksGroup") + + group(groupTitle) { + row { + cell(disableAllCheckBox) + } + + hookCheckBoxes + .map { + row { + cell(it) + } + } + } + } + .withVisualPadding(true) + } + + private fun createDisableAllCheckBox(): JBCheckBox { + val title = LocatorBundle + .getMessage("locator.ui.toolWindow.disableAll") + + return JBCheckBox(title, hooksFolder.isAllDisabled()) + .apply { + addActionListener { + when (this.isSelected) { + true -> hooksFolder.disableAll() + false -> hooksFolder.enableAll() + } + + hookCheckBoxes.forEach { + it.isSelected = this.isSelected + } + } + } + } + + private fun createHookCheckBox(hook: HookEntry): JBCheckBox { + val hookTitle = LocatorBundle + .getMessage("locator.ui.toolWindow.disable", hook.name) + + return JBCheckBox(hookTitle, hook.isDisabled()) + .apply { + addActionListener { + when (this.isSelected) { + true -> hook.disable() + false -> hook.enable() + } + + disableAllCheckBox.isSelected = hooksFolder.isAllDisabled() + } + } + } + + private fun createHookCheckBoxes(): Array + = hooksFolder + .hooks + .map { createHookCheckBox(it) } + .toTypedArray() +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/ui/toolWindow/GitGlobalHooksLocatorWindowFactory.kt b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/ui/toolWindow/GitGlobalHooksLocatorWindowFactory.kt new file mode 100644 index 0000000..79e8bfb --- /dev/null +++ b/src/main/kotlin/com/github/y0ung3r/gitglobalhookslocator/ui/toolWindow/GitGlobalHooksLocatorWindowFactory.kt @@ -0,0 +1,26 @@ +package com.github.y0ung3r.gitglobalhookslocator.ui.toolWindow + +import com.intellij.openapi.project.Project +import com.intellij.openapi.wm.ToolWindow +import com.intellij.openapi.wm.ToolWindowFactory +import com.intellij.ui.content.ContentFactory + +class GitGlobalHooksLocatorWindowFactory : ToolWindowFactory { + override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { + val locatorWindow = GitGlobalHooksLocatorWindow(toolWindow) + + val content = ContentFactory + .getInstance() + .createContent( + locatorWindow.getContent(), + null, + false) + + toolWindow + .contentManager + .addContent(content) + } + + override fun shouldBeAvailable(project: Project) + = !project.isDefault +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index bcdea61..3da3534 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -1,18 +1,23 @@ com.github.y0ung3r.gitglobalhookslocator - GitGlobalHooksLocator Template + Git Global Hooks Locator y0ung3r + + + + + com.intellij.modules.platform - messages.MyBundle + messages.LocatorBundle - + - - - - diff --git a/src/main/resources/description.png b/src/main/resources/description.png new file mode 100644 index 0000000..5c1e8c3 Binary files /dev/null and b/src/main/resources/description.png differ diff --git a/src/main/resources/messages/LocatorBundle.properties b/src/main/resources/messages/LocatorBundle.properties new file mode 100644 index 0000000..4eb8f0d --- /dev/null +++ b/src/main/resources/messages/LocatorBundle.properties @@ -0,0 +1,4 @@ +locator.ui.toolWindow.globalHooksGroup=Global Hooks +locator.ui.toolWindow.hooksFolderEmpty=Git global hooks from "{0}" not found +locator.ui.toolWindow.disableAll=Disable all Git global hooks +locator.ui.toolWindow.disable=Disable {0} \ No newline at end of file diff --git a/src/main/resources/messages/MyBundle.properties b/src/main/resources/messages/MyBundle.properties deleted file mode 100644 index 2e041d8..0000000 --- a/src/main/resources/messages/MyBundle.properties +++ /dev/null @@ -1,3 +0,0 @@ -projectService=Project service: {0} -randomLabel=The random number is: {0} -shuffle=Shuffle diff --git a/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/MyPluginTest.kt b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/MyPluginTest.kt deleted file mode 100644 index 7152f43..0000000 --- a/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/MyPluginTest.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.github.y0ung3r.gitglobalhookslocator - -import com.intellij.ide.highlighter.XmlFileType -import com.intellij.openapi.components.service -import com.intellij.psi.xml.XmlFile -import com.intellij.testFramework.TestDataPath -import com.intellij.testFramework.fixtures.BasePlatformTestCase -import com.intellij.util.PsiErrorElementUtil -import com.github.y0ung3r.gitglobalhookslocator.services.MyProjectService - -@TestDataPath("\$CONTENT_ROOT/src/test/testData") -class MyPluginTest : BasePlatformTestCase() { - - fun testXMLFile() { - val psiFile = myFixture.configureByText(XmlFileType.INSTANCE, "bar") - val xmlFile = assertInstanceOf(psiFile, XmlFile::class.java) - - assertFalse(PsiErrorElementUtil.hasErrors(project, xmlFile.virtualFile)) - - assertNotNull(xmlFile.rootTag) - - xmlFile.rootTag?.let { - assertEquals("foo", it.name) - assertEquals("bar", it.value.text) - } - } - - fun testRename() { - myFixture.testRename("foo.xml", "foo_after.xml", "a2") - } - - fun testProjectService() { - val projectService = project.service() - - assertNotSame(projectService.getRandomNumber(), projectService.getRandomNumber()) - } - - override fun getTestDataPath() = "src/test/testData/rename" -} diff --git a/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/ExecuteCommandTests.kt b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/ExecuteCommandTests.kt new file mode 100644 index 0000000..bd0a477 --- /dev/null +++ b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/ExecuteCommandTests.kt @@ -0,0 +1,35 @@ +package com.github.y0ung3r.gitglobalhookslocator.gitTests + +import com.github.y0ung3r.gitglobalhookslocator.git.cli.EmptyCliResponse +import com.github.y0ung3r.gitglobalhookslocator.git.Git +import com.github.y0ung3r.gitglobalhookslocator.git.exceptions.GitCommandNotFoundException +import org.junit.Assert.assertNotEquals +import org.junit.Test + +class ExecuteCommandTests { + @Test(expected = GitCommandNotFoundException::class) + fun `Should throws exception if Git commands is not exists`() { + // Arrange & Act & Assert + Git.instance.executeCommand( + "unknown", + Git.GIT_GLOBAL_COMMAND + ) + } + + @Test + fun `Should returns response properly`() { + // Arrange + val sut = Git.instance + + // Act + val actualResponse = sut.executeCommand( + Git.GIT_CONFIG_COMMAND, + Git.GIT_GLOBAL_COMMAND, + Git.GIT_CONFIG_GET_COMMAND, + "user.name" + ) + + // Assert + assertNotEquals(actualResponse, EmptyCliResponse()) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/GetGlobalHooksPathTests.kt b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/GetGlobalHooksPathTests.kt new file mode 100644 index 0000000..b3419b8 --- /dev/null +++ b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/GetGlobalHooksPathTests.kt @@ -0,0 +1,28 @@ +package com.github.y0ung3r.gitglobalhookslocator.gitTests + +import com.github.y0ung3r.gitglobalhookslocator.gitTests.testEngine.RespondInterchangeably +import com.github.y0ung3r.gitglobalhookslocator.git.Git +import com.github.y0ung3r.gitglobalhookslocator.git.cli.CliResponse +import com.github.y0ung3r.gitglobalhookslocator.git.extensions.getGlobalHooksPath +import org.junit.Assert.assertEquals +import org.junit.Test + +class GetGlobalHooksPathTests { + @Test + fun `Should returns global hooks path`() { + // Arrange + val expectedPath = "~/.git/hooks" + val sut = Git( + RespondInterchangeably( + CliResponse(Git.minRequiredVersion.toString()), + CliResponse(expectedPath) + ) + ) + + // Act + val actualPath = sut.getGlobalHooksPath() + + // Assert + assertEquals(expectedPath, actualPath) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/GetInstalledVersionTests.kt b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/GetInstalledVersionTests.kt new file mode 100644 index 0000000..70c1433 --- /dev/null +++ b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/GetInstalledVersionTests.kt @@ -0,0 +1,39 @@ +package com.github.y0ung3r.gitglobalhookslocator.gitTests + +import com.github.y0ung3r.gitglobalhookslocator.gitTests.testEngine.RespondOnce +import com.github.y0ung3r.gitglobalhookslocator.git.cli.EmptyCliResponse +import com.github.y0ung3r.gitglobalhookslocator.git.Git +import com.github.y0ung3r.gitglobalhookslocator.git.cli.CliResponse +import com.github.y0ung3r.gitglobalhookslocator.git.SemanticVersion +import com.github.y0ung3r.gitglobalhookslocator.git.exceptions.GitIsNotInstalledException +import org.junit.Assert.assertEquals +import org.junit.Test + +class GetInstalledVersionTests { + @Test(expected = GitIsNotInstalledException::class) + fun `Should throws exception if Git is not installed`() { + // Arrange & Act & Assert + Git( + RespondOnce( + EmptyCliResponse() + ) + ) + } + + @Test + fun `Should returns Git version info`() { + // Arrange + val expectedVersion = SemanticVersion(2, 9, 2) + val sut = Git( + RespondOnce( + CliResponse(expectedVersion.toString()) + ) + ) + + // Act + val actualVersion = sut.getInstalledVersion() + + // Assert + assertEquals(expectedVersion, actualVersion) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/HookEntryTests.kt b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/HookEntryTests.kt new file mode 100644 index 0000000..067efc6 --- /dev/null +++ b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/HookEntryTests.kt @@ -0,0 +1,65 @@ +package com.github.y0ung3r.gitglobalhookslocator.gitTests + +import com.github.y0ung3r.gitglobalhookslocator.gitTests.testEngine.HookTestBase +import com.github.y0ung3r.gitglobalhookslocator.git.HookEntry +import com.github.y0ung3r.gitglobalhookslocator.git.exceptions.HookNotFoundException +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized + +@RunWith(Parameterized::class) +class HookEntryTests(private val hookName: String) : HookTestBase() { + @Test(expected = HookNotFoundException::class) + fun `Should throws exception if hook not found`() { + HookEntry.load(getEnabledHookPath("unknown")) + } + + @Test + fun `Should load hook properly`() { + HookEntry.load(getEnabledHookPath(hookName)) + } + + @Test + fun `Should be disabled if hook name not contains in available Git hooks`() { // TODO: Rename test + // Arrange + val sut = HookEntry.load(getDisabledHookPath(hookName)) + + // Act & Assert + assertTrue(sut.isDisabled()) + } + + @Test + fun `Should be enabled if hook name contains in available Git hooks`() { // TODO: Rename test + // Arrange + val sut = HookEntry.load(getEnabledHookPath(hookName)) + + // Act & Assert + assertFalse(sut.isDisabled()) + } + + @Test + fun `Should disable hook`() { + // Arrange + val sut = HookEntry.load(getEnabledHookPath(hookName)) + + // Act + sut.disable() + + // Assert + assertTrue(sut.isDisabled()) + } + + @Test + fun `Should enable hook`() { + // Arrange + val sut = HookEntry.load(getDisabledHookPath(hookName)) + + // Act + sut.enable() + + // Assert + assertFalse(sut.isDisabled()) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/HooksFolderTests.kt b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/HooksFolderTests.kt new file mode 100644 index 0000000..0410649 --- /dev/null +++ b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/HooksFolderTests.kt @@ -0,0 +1,93 @@ +package com.github.y0ung3r.gitglobalhookslocator.gitTests + +import com.github.y0ung3r.gitglobalhookslocator.gitTests.testEngine.HookTestBase +import com.github.y0ung3r.gitglobalhookslocator.gitTests.testEngine.RespondInterchangeably +import com.github.y0ung3r.gitglobalhookslocator.git.Git +import com.github.y0ung3r.gitglobalhookslocator.git.HooksFolder +import com.github.y0ung3r.gitglobalhookslocator.git.cli.CliResponse +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Test +import java.nio.file.Path + +class HooksFolderTests : HookTestBase() { + private companion object { + @JvmStatic + fun getGit(hooksPath: Path) = Git( + RespondInterchangeably( + CliResponse(Git.minRequiredVersion.toString()), + CliResponse(hooksPath.toString()) + ) + ) + } + + @Test + fun `Should load all hooks from disabled hooks path`() { + // Arrange + val git = getGit(getDisabledHooksPath()) + + // Act + val sut = HooksFolder(git) + + // Assert + assertEquals(HooksFolder.availableHooks.size, sut.hooks.size) + } + + @Test + fun `Should load all hooks from enabled hooks path`() { + // Arrange + val git = getGit(getEnabledHooksPath()) + + // Act + val sut = HooksFolder(git) + + // Assert + assertEquals(HooksFolder.availableHooks.size, sut.hooks.size) + } + + @Test + fun `All hooks should be disabled`() { + // Arrange + val git = getGit(getDisabledHooksPath()) + val sut = HooksFolder(git) + + // Act & Assert + Assert.assertTrue(sut.isAllDisabled()) + } + + @Test + fun `All hooks should be enabled`() { + // Arrange + val git = getGit(getEnabledHooksPath()) + val sut = HooksFolder(git) + + // Act & Assert + Assert.assertFalse(sut.isAllDisabled()) + } + + @Test + fun `Should disable all hooks`() { + // Arrange + val git = getGit(getEnabledHooksPath()) + val sut = HooksFolder(git) + + // Act + sut.disableAll() + + // Assert + Assert.assertTrue(sut.isAllDisabled()) + } + + @Test + fun `Should enable all hooks`() { + // Arrange + val git = getGit(getDisabledHooksPath()) + val sut = HooksFolder(git) + + // Act + sut.enableAll() + + // Assert + Assert.assertFalse(sut.isAllDisabled()) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/MinGitVersionTests.kt b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/MinGitVersionTests.kt new file mode 100644 index 0000000..ae76e94 --- /dev/null +++ b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/MinGitVersionTests.kt @@ -0,0 +1,44 @@ +package com.github.y0ung3r.gitglobalhookslocator.gitTests + +import com.github.y0ung3r.gitglobalhookslocator.gitTests.testEngine.RespondOnce +import com.github.y0ung3r.gitglobalhookslocator.git.Git +import com.github.y0ung3r.gitglobalhookslocator.git.cli.CliResponse +import com.github.y0ung3r.gitglobalhookslocator.git.exceptions.GitVersionIsNotSupportedException +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import org.junit.runners.Parameterized.Parameters + +@RunWith(Parameterized::class) +class MinGitVersionTests(private val unsupportedVersion: String, private val supportedVersion: String) { + companion object { + @JvmStatic + @Parameters + fun version() = arrayOf( + arrayOf("1.0.0", "2.9.0"), + arrayOf("1.0.1", "2.9.1"), + arrayOf("2.0.0", "2.43.0"), + arrayOf("2.0.1", "2.43.1"), + ) + } + + @Test(expected = GitVersionIsNotSupportedException::class) + fun `Should throws exception if Git version is not supported`() { + // Arrange & Act & Assert + Git( + RespondOnce( + CliResponse(unsupportedVersion) + ) + ) + } + + @Test + fun `Should not throws exception if Git version supported`() { + // Arrange & Act & Assert + Git( + RespondOnce( + CliResponse(supportedVersion) + ) + ) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/SemanticVersionTests.kt b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/SemanticVersionTests.kt new file mode 100644 index 0000000..e054a1e --- /dev/null +++ b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/SemanticVersionTests.kt @@ -0,0 +1,54 @@ +package com.github.y0ung3r.gitglobalhookslocator.gitTests + +import com.github.y0ung3r.gitglobalhookslocator.git.SemanticVersion +import com.github.y0ung3r.gitglobalhookslocator.git.exceptions.ProvidedSemanticVersionIsInvalidException +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import org.junit.runners.Parameterized.Parameters + +//@RunWith(Parameterized::class) +class SemanticVersionTests(private val invalidVersion: String, private val validVersion: String) { + companion object { + @JvmStatic + @Parameters + fun versions() = arrayOf( + arrayOf("-1.0.0", "0.0.0"), + arrayOf("1.-1.0", "1.2.3-alpha.1+build"), + arrayOf("0.0.-1", "1.0"), + arrayOf("1", "git version 2.33.0.windows.2"), + arrayOf("", "0.99.9n"), + arrayOf("1.0", "1.7.12.4"), + arrayOf("1.0-alpha", "v2.43.0-rc1"), + arrayOf("1.0-alpha.01", "2.38.3"), + arrayOf("a1.0.0", "v2.6.0-rc0"), + arrayOf("1.a0.0", "1.2.3-alpha.b.3"), + arrayOf("1.0.a0", "2.3.1-alpha") + ) + } + + //@Test(expected = ProvidedSemanticVersionIsInvalidException::class) + fun `Should throws exception if provided version is not valid`() { + // Arrange & Act & Assert + SemanticVersion.parse(invalidVersion) + } + + //@Test + fun `Should parse version properly`() { + // Arrange & Act & Assert + SemanticVersion.parse(validVersion) + } + + //@Test + fun `Should returns string representation of version`() { + // Arrange + val sut = SemanticVersion.parse(validVersion) + + // Act + val actualRepresentation = sut.toString() + + // Assert + assertEquals(validVersion, actualRepresentation) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/testEngine/HookTestBase.kt b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/testEngine/HookTestBase.kt new file mode 100644 index 0000000..50c0838 --- /dev/null +++ b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/testEngine/HookTestBase.kt @@ -0,0 +1,75 @@ +package com.github.y0ung3r.gitglobalhookslocator.gitTests.testEngine + +import com.github.y0ung3r.gitglobalhookslocator.git.HooksFolder +import org.junit.runners.Parameterized +import java.nio.file.Files +import java.nio.file.Path + +abstract class HookTestBase { + companion object { + const val BASE_PATH = "src/test/testData/hooks" + private const val DISABLED_HOOK = "disabled" + private const val ENABLED_HOOK = "enabled" + + @JvmStatic + private fun getHookPath(hookType: String, hookName: String): Path { + val categorizedHookName = when (hookType) { + DISABLED_HOOK -> "_$hookName" + else -> hookName + } + + return Path.of(BASE_PATH, hookType, categorizedHookName) + } + + @JvmStatic + private fun getHooksPath(hookType: String): Path + = Path.of(BASE_PATH, hookType) + + @JvmStatic + fun getDisabledHookPath(hookName: String): Path + = getHookPath(DISABLED_HOOK, hookName) + + @JvmStatic + fun getEnabledHookPath(hookName: String): Path + = getHookPath(ENABLED_HOOK, hookName) + + @JvmStatic + fun getDisabledHooksPath(): Path + = getHooksPath(DISABLED_HOOK) + + @JvmStatic + fun getEnabledHooksPath(): Path + = getHooksPath(ENABLED_HOOK) + + @JvmStatic + private fun clearTestHooks(hookType: String) { + val hooksPath = getHooksPath(hookType) + + hooksPath + .toFile() + .mkdirs() + + Files.list(hooksPath).forEach { it.toFile().delete() } + } + + @JvmStatic + private fun generateTestHooks(hookType: String) { + clearTestHooks(hookType) + + hookNames() + .map { getHookPath(hookType, it).toFile() } + .filter { !it.exists() } + .forEach { it.createNewFile() } + } + + @JvmStatic + @Parameterized.Parameters + fun hookNames() + = HooksFolder.availableHooks + } + + init { + generateTestHooks(DISABLED_HOOK) + generateTestHooks(ENABLED_HOOK) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/testEngine/RespondInterchangeably.kt b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/testEngine/RespondInterchangeably.kt new file mode 100644 index 0000000..920272a --- /dev/null +++ b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/testEngine/RespondInterchangeably.kt @@ -0,0 +1,10 @@ +package com.github.y0ung3r.gitglobalhookslocator.gitTests.testEngine + +import com.github.y0ung3r.gitglobalhookslocator.git.cli.CliResponse +import com.github.y0ung3r.gitglobalhookslocator.git.cli.interfaces.CliCommandExecutor + +class RespondInterchangeably(vararg responses: CliResponse) : CliCommandExecutor { + private val iterator = responses.iterator() + override fun execute(processBuilder: ProcessBuilder): CliResponse + = iterator.next() +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/testEngine/RespondOnce.kt b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/testEngine/RespondOnce.kt new file mode 100644 index 0000000..9d6f347 --- /dev/null +++ b/src/test/kotlin/com/github/y0ung3r/gitglobalhookslocator/gitTests/testEngine/RespondOnce.kt @@ -0,0 +1,9 @@ +package com.github.y0ung3r.gitglobalhookslocator.gitTests.testEngine + +import com.github.y0ung3r.gitglobalhookslocator.git.cli.CliResponse +import com.github.y0ung3r.gitglobalhookslocator.git.cli.interfaces.CliCommandExecutor + +class RespondOnce(private val response: CliResponse) : CliCommandExecutor { + override fun execute(processBuilder: ProcessBuilder): CliResponse + = response +} \ No newline at end of file