Skip to content

Commit

Permalink
allow to use kdiff as cli application
Browse files Browse the repository at this point in the history
  • Loading branch information
mikethebeer committed Oct 11, 2023
1 parent 2629f3c commit 4a0a017
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 106 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/cli_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ jobs:
with:
java-version: '17'
distribution: 'temurin'
cache: 'gradle'
- name: Setup and execute Gradle 'test' task
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
with:
gradle-version: 8.3
Expand All @@ -28,4 +27,8 @@ jobs:
- name: Release
uses: softprops/action-gh-release@v1
with:
tag_name: dev
files: cli/build/distributions/*.zip

permissions:
contents: write
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Changes for gradle-kdiff plugin

## 2023-10-10 / 0.1.0

- Initial release
11 changes: 11 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugins {
id("com.lovelysystems.gradle") version ("1.12.0")
}

lovely {
gitProject()
}

subprojects {
version = rootProject.version
}
28 changes: 28 additions & 0 deletions cli/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
plugins {
application
kotlin("jvm") version "1.9.0"
id("com.github.johnrengelman.shadow") version "8.1.1"
}

application {
applicationName = "kdiff"
}

tasks.shadowDistZip {
archiveBaseName.set("kdiff")
archiveVersion.set(project.version.toString())
archiveClassifier.set("")
}

repositories {
mavenCentral()
}

dependencies {
implementation("com.github.ajalt.clikt:clikt:4.2.1")
implementation("io.github.java-diff-utils:java-diff-utils:4.12")
}

application {
mainClass = "at.mibe.kdiff.ApplicationKt"
}
3 changes: 3 additions & 0 deletions cli/src/main/kotlin/at/mibe/kdiff/Application.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package at.mibe.kdiff

fun main(args: Array<String>) = KDiffCommand().main(args)
102 changes: 102 additions & 0 deletions cli/src/main/kotlin/at/mibe/kdiff/KDiffCommand.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package at.mibe.kdiff

import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.arguments.help
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.help
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.types.file
import com.github.ajalt.clikt.parameters.types.path
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import java.util.concurrent.TimeUnit
import kotlin.io.path.Path
import kotlin.io.path.div
import kotlin.io.path.pathString

class KDiffCommand : CliktCommand(name = "kdiff") {

private val kpath: Path by argument("path").path(mustExist = true).help("The path to the Kustomization file")
private val remoteBranch: String by option("-b", "--branch").help("Remote branch to diff against").default("master")
private val remoteDirOverride: String by option("-r", "--remote-dir").help("Root directory of the remote branch to diff against")
.default("")
private val kustomize: File by option("--kustomize").file(mustExist = true).help("Path to the kustomize executable")
.default(File("kustomize"))

override fun run() {
// clone the git repo
val remoteRepoDir = cloneGitRepo(gitOriginUrl(), Path("/tmp/kdiff"))
checkoutBranch(remoteRepoDir, remoteBranch)

val remoteRepoExecDir = if (remoteDirOverride.isNotEmpty()) {
remoteRepoDir / remoteDirOverride
} else {
remoteRepoDir
}

// run kustomize on the cloned remote branch
// suppress error output because we don't care about the exit code
val branch1Output = execCmd(kustomize.path, "build", (remoteRepoExecDir / kpath).pathString) { "" }

// run kustomize on the local branch
// suppress error output because we don't care about the exit code
val branch2Output = execCmd(kustomize.path, "build", kpath.pathString) { "" }

val diffs = findTextDifferences(branch1Output, branch2Output)
if (diffs.deltas.isNotEmpty()) {
val inlineDiff = generateInlineDiff(branch1Output, diffs)
println(inlineDiff)
} else {
println("No differences found.")
}
}

private fun cloneGitRepo(originUrl: String, dest: Path): Path {
// Store target directory into a variable to avoid project reference in the configuration cache
val repoPath = dest / Path(originUrl)
Files.createDirectories(repoPath)

execCmd("git", "clone", originUrl, ".", dir = repoPath.toFile()) { "Git clone failed" }
return repoPath
}

private fun checkoutBranch(repoPath: Path, branch: String) {
execCmd("git", "checkout", branch, dir = repoPath.toFile())
execCmd("git", "pull", "origin", branch, dir = repoPath.toFile())
}

private fun gitOriginUrl(): String = execCmd("git", "remote", "get-url", "origin")

private fun execCmd(
vararg args: String,
dir: File? = null,
onError: ((String) -> String)? = null
): String {
val cmd = args.toList()
val stdoutFile = kotlin.io.path.createTempFile().toFile()
val stderrFile = kotlin.io.path.createTempFile().toFile()

try {
val proc = ProcessBuilder(cmd)
.directory(dir)
.redirectOutput(stdoutFile)
.redirectError(stderrFile)
.start()
proc.waitFor(10, TimeUnit.SECONDS)
val stdout = stdoutFile.readText().trim()
val stderr = stderrFile.readText().trim()
return if (proc.exitValue() == 0) {
stdout
} else {
onError?.invoke(stderr) ?: throw RuntimeException(
"command failed: ${cmd.joinToString(" ")}\n$stderr"
)
}
} finally {
stderrFile.delete()
stdoutFile.delete()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package at.mibe.gradle.kdiff
package at.mibe.kdiff

import com.github.difflib.DiffUtils
import com.github.difflib.patch.Patch
Expand Down Expand Up @@ -31,7 +31,8 @@ fun generateInlineDiff(text1: String, patch: Patch<String>): String {

// Process the inserted lines (green color)
for (i in delta.target.position until delta.target.position + delta.target.size()) {
val insertedLine = "\u001B[32m+${delta.target.lines[i - delta.target.position]}\u001B[0m" // Green for insertions
val insertedLine =
"\u001B[32m+${delta.target.lines[i - delta.target.position]}\u001B[0m" // Green for insertions
highlightedLines.add(insertedLine)
}

Expand Down
3 changes: 1 addition & 2 deletions plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
`java-gradle-plugin`

// Apply the Kotlin JVM plugin to add support for Kotlin.
id("org.jetbrains.kotlin.jvm") version "1.9.0"
kotlin("jvm") version "1.9.0"
id("de.undercouch.download") version "5.5.0"
}

Expand All @@ -15,7 +15,6 @@ repositories {

dependencies {
implementation("de.undercouch:gradle-download-task:5.5.0")
implementation("io.github.java-diff-utils:java-diff-utils:4.12")

// Use the Kotlin JUnit 5 integration.
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
Expand Down
57 changes: 51 additions & 6 deletions plugin/src/main/kotlin/at/mibe/gradle/kdiff/GradleKDiffPlugin.kt
Original file line number Diff line number Diff line change
@@ -1,35 +1,80 @@
package at.mibe.gradle.kdiff

import de.undercouch.gradle.tasks.download.Download
import org.gradle.api.Project
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.file.RelativePath
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.Exec

@Suppress("unused")
class GradleKDiffPlugin : Plugin<Project> {

companion object {
const val KDIFF_GROUP = "kdiff"
}

override fun apply(project: Project) {
val kDiffLocation = project.layout.buildDirectory.dir("kdiff").get()

// Apply the third-party plugin
project.apply { action ->
action.plugin("de.undercouch.download")
}

project.tasks.register("kDiffVersion") {
it.group = KDIFF_GROUP
it.description = "Prints the kDiff version"

it.doLast {
println("GradleKDiffPlugin version: ${project.version}")
}
}

project.tasks.register("downloadKustomize", Download::class.java) {
val downloadKustomize = project.tasks.register("downloadKustomize", Download::class.java) {
it.group = KDIFF_GROUP
it.description = "Download kustomize CLI"

it.src("https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh")
it.dest(project.layout.buildDirectory)
it.dest(kDiffLocation.dir("bin"))
it.overwrite(false)
}

project.tasks.register("installKustomize", Exec::class.java) {
it.dependsOn("downloadKustomize")
it.workingDir(project.layout.buildDirectory)
it.group = KDIFF_GROUP
it.description = "Install kustomize CLI"

it.onlyIf { !kDiffLocation.asFile.resolve("bin/kustomize").exists() }
it.dependsOn(downloadKustomize)

it.workingDir(kDiffLocation.dir("bin"))
// only install kustomize if it is not already installed
it.commandLine("bash", "install_kustomize.sh")
}

project.tasks.register("kDiff", KDiffTask::class.java)
val downloadKDiff = project.tasks.register("downloadKDiff", Download::class.java) {
it.group = KDIFF_GROUP
it.description = "Download kDiff CLI"

it.src("https://github.com/mikethebeer/gradle-kdiff/releases/download/${project.version}/kdiff-${project.version}.zip")
it.dest(project.layout.buildDirectory.file("kdiff.zip"))
it.overwrite(false)
}

project.tasks.register("installKDiff", Copy::class.java) {
it.group = KDIFF_GROUP
it.description = "Install kDiff CLI"

it.dependsOn(downloadKDiff)

it.from(project.zipTree(downloadKDiff.get().dest)) { f ->
f.include("kdiff-*/**")
f.eachFile { cd ->
cd.relativePath = RelativePath(true, *cd.relativePath.segments.drop(1).toTypedArray())
}
f.includeEmptyDirs = false
}
it.into(kDiffLocation)
}
}
}
93 changes: 0 additions & 93 deletions plugin/src/main/kotlin/at/mibe/gradle/kdiff/KDiffTask.kt

This file was deleted.

2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
rootProject.name = "gradle-kdiff"
include("plugin")
include("plugin", "cli")

0 comments on commit 4a0a017

Please sign in to comment.