Sat, 22 Jul 2023 13:04:12 +0200
remove vcs connectors in favor of externally fed logs
relates to #276
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/kotlin/de/uapcore/lightpit/types/CommitRef.kt Sat Jul 22 13:04:12 2023 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2023 Mike Becker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package de.uapcore.lightpit.types + +data class CommitRef(val hash: String, val issueId: Int, val message: String) + +/** + * Takes a [commitLog] in format `::lpitref::{node}:{desc}` and parses commit references. + * Supported references are (in this example, 47 is the issue ID): + * - fixes #47 + * - fix #47 + * - closes #47 + * - close #47 + * - relates to #47 + */ +fun parseCommitRefs(commitLog: String): List<CommitRef> = buildList { + val marker = "::lpitref:" + var currentHash = "" + var currentDesc = "" + for (line in commitLog.split("\n")) { + // see if current line contains a new log entry + if (line.startsWith(marker)) { + val head = line.substring(marker.length).split(':', limit = 2) + currentHash = head[0] + currentDesc = head[1] + } + + // skip possible preamble output + if (currentHash.isEmpty()) continue + + // scan the lines for commit references + Regex("""(?:relates to|fix(?:es)?|close(?:es)?) #(\d+)""") + .findAll(line) + .map { it.groupValues[1] } + .map { it.toIntOrNull() } + .filterNotNull() + .forEach { commitId -> add(CommitRef(currentHash, commitId, currentDesc)) } + } +} +
--- a/src/main/kotlin/de/uapcore/lightpit/vcs/CommitRef.kt Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -package de.uapcore.lightpit.vcs - -data class CommitRef(val hash: String, val issueId: Int, val message: String)
--- a/src/main/kotlin/de/uapcore/lightpit/vcs/HgConnector.kt Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright 2023 Mike Becker. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -package de.uapcore.lightpit.vcs - -import java.nio.file.Files -import kotlin.io.path.ExperimentalPathApi -import kotlin.io.path.deleteRecursively - -/** - * A connector for Mercurial repositories. - * - * @param path the path to the Mercurial binary - */ -class HgConnector(path: String) : VcsConnector(path) { - - /** - * Checks, if the specified binary is available and executable. - */ - fun checkAvailability(): Boolean { - return when (val versionInfo = invokeCommand("--version")) { - is VcsConnectorResult.Success -> versionInfo.content.contains("Mercurial") - else -> false - } - } - - /** - * Reads the commit log and parses every reference to an issue. - * - * The [pathOrUrl] must be a valid path or URL recognized by the VCS binary. - * Currently, no authentication is supported and the repository must therefore be publicly readable. - */ - @OptIn(ExperimentalPathApi::class) - fun readCommitLog(pathOrUrl: String): VcsConnectorResult<List<CommitRef>> { - val tmpDir = try { - Files.createTempDirectory("lightpit-vcs-") - } catch (e: Throwable) { - return VcsConnectorResult.Error("Creating temporary directory for VCS connection failed: " + e.message) - } - val init = invokeCommand("init", workingDir = tmpDir) - if (init is VcsConnectorResult.Error) { - return init - } - - val commitLogContent = when (val result = invokeCommand( - "incoming", pathOrUrl, "-n", "--template", "::lpitref::{node}:{desc}\\n", - workingDir = tmpDir, - timeout = 60 - )) { - is VcsConnectorResult.Error -> return result - is VcsConnectorResult.Success -> result.content - } - - val commitRefs = parseCommitRefs(commitLogContent) - - tmpDir.deleteRecursively() - return VcsConnectorResult.Success(commitRefs) - } -} \ No newline at end of file
--- a/src/main/kotlin/de/uapcore/lightpit/vcs/VcsConnector.kt Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -package de.uapcore.lightpit.vcs - -import java.nio.file.Path -import java.util.concurrent.TimeUnit - -abstract class VcsConnector(protected val path: String) { - /** - * Invokes the VCS binary with the given [args] and returns the output on stdout. - */ - protected fun invokeCommand( - vararg args: String, - workingDir: Path = Path.of("."), - timeout: Long = 30L - ): VcsConnectorResult<String> { - return try { - val command = mutableListOf(path) - command.addAll(args) - val process = ProcessBuilder(command).directory(workingDir.toFile()).start() - val stdout = String(process.inputStream.readAllBytes(), Charsets.UTF_8) - if (process.waitFor(timeout, TimeUnit.SECONDS)) { - if (process.exitValue() == 0) { - VcsConnectorResult.Success(stdout) - } else { - VcsConnectorResult.Error("VCS process did not return successfully.") - } - } else { - VcsConnectorResult.Error("VCS process did not return in time.") - } - } catch (e: Throwable) { - VcsConnectorResult.Error("Error during process invocation: "+e.message) - } - } - - /** - * Takes a [commitLog] in format `::lpitref::{node}:{desc}` and parses commit references. - * Supported references are (in this example, 47 is the issue ID): - * - fixes #47 - * - fix #47 - * - closes #47 - * - close #47 - * - relates to #47 - */ - protected fun parseCommitRefs(commitLog: String): List<CommitRef> = buildList { - val marker = "::lpitref::" - var currentHash = "" - var currentDesc = "" - for (line in commitLog.split("\n")) { - // see if current line contains a new log entry - if (line.startsWith(marker)) { - val head = line.substring(marker.length).split(':', limit = 2) - currentHash = head[0] - currentDesc = head[1] - } - - // skip possible preamble output - if (currentHash.isEmpty()) continue - - // scan the lines for commit references - Regex("""(?:relates to|fix(?:es)?|close(?:es)?) #(\d+)""") - .findAll(line) - .map { it.groupValues[1] } - .map { it.toIntOrNull() } - .filterNotNull() - .forEach { commitId -> add(CommitRef(currentHash, commitId, currentDesc)) } - } - } -} \ No newline at end of file
--- a/src/main/kotlin/de/uapcore/lightpit/vcs/VcsConnectorResult.kt Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -package de.uapcore.lightpit.vcs - -sealed class VcsConnectorResult<out T> { - data class Success<T>(val content: T) : VcsConnectorResult<T>() - data class Error(val message: String) : VcsConnectorResult<Nothing>() -} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/kotlin/de/uapcore/lightpit/types/CommitRefTest.kt Sat Jul 22 13:04:12 2023 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2023 Mike Becker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package de.uapcore.lightpit.types + +import kotlin.test.Test +import kotlin.test.assertContentEquals + +class CommitRefTest { + + @Test + fun readCommitLog() { + assertContentEquals( + listOf( + CommitRef("cf9f5982ddeb28c7f695dc547fe73abf5460016f", 50, "here we fix #50"), + CommitRef("cf9f5982ddeb28c7f695dc547fe73abf5460016f", 30, "here we fix #50"), + CommitRef( + "ed7134e5f4ce278c4f62798fb9f96129be2b132b", + 1337, + "commit with a #non-ref, relates to #wrong ref but still fixes #1337" + ), + CommitRef("74d770da3c80c0c3fc1fb7e44fb710d665127dfe", 47, "a change with commitref in body"), + CommitRef("9a14e5628bdf2d578f3385d78022ddcaf23d1abb", 47, "add test file - relates to #47") + ), + parseCommitRefs( + """::lpitref:cf9f5982ddeb28c7f695dc547fe73abf5460016f:here we fix #50 + +and close #30 +::lpitref:ed7134e5f4ce278c4f62798fb9f96129be2b132b:commit with a #non-ref, relates to #wrong ref but still fixes #1337 +::lpitref:74d770da3c80c0c3fc1fb7e44fb710d665127dfe:a change with commitref in body + +some more details +fixes #47 +::lpitref:d533c717dfecb8e4b993ca6c8760f1493bc834b6:no commitref +::lpitref:9a14e5628bdf2d578f3385d78022ddcaf23d1abb:add test file - relates to #47 +""" + ) + ) + } +} \ No newline at end of file
--- a/src/test/kotlin/de/uapcore/lightpit/vcs/HgConnectorTest.kt Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * Copyright 2023 Mike Becker. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -package de.uapcore.lightpit.vcs - -import kotlin.io.path.Path -import kotlin.io.path.absolutePathString -import kotlin.io.path.exists -import kotlin.io.path.moveTo -import kotlin.test.* - -class HgConnectorTest { - - private val testee = HgConnector("/usr/bin/hg") - private val testRepoPath = Path("src/test/resources/test-repo") - - @BeforeTest - fun prepareTestRepo() { - assertTrue(testRepoPath.exists(), "Test must be run from the project root.") - val hg = testRepoPath.resolve("hg") - val dothg = testRepoPath.resolve(".hg") - assertTrue(hg.exists(), "hg dir not found, maybe a previous execution did not terminated cleanly.") - assertFalse(dothg.exists(), ".hg dir found, maybe a previous execution did not terminated cleanly.") - hg.moveTo(dothg) - } - - @AfterTest - fun cleanup() { - val hg = testRepoPath.resolve("hg") - val dothg = testRepoPath.resolve(".hg") - dothg.moveTo(hg) - } - - @Test - fun checkAvailability() { - assertTrue(testee.checkAvailability()) - } - - @Test - fun checkAvailabilityFalse() { - assertFalse(HgConnector("/bin/false").checkAvailability()) - } - - @Test - fun readCommitLog() { - val result = testee.readCommitLog(testRepoPath.absolutePathString()) - assertTrue(result is VcsConnectorResult.Success) - - assertContentEquals( - listOf( - CommitRef("cf9f5982ddeb28c7f695dc547fe73abf5460016f", 50, "here we fix #50"), - CommitRef("cf9f5982ddeb28c7f695dc547fe73abf5460016f", 30, "here we fix #50"), - CommitRef( - "ed7134e5f4ce278c4f62798fb9f96129be2b132b", - 1337, - "commit with a #non-ref, relates to #wrong ref but still fixes #1337" - ), - CommitRef("74d770da3c80c0c3fc1fb7e44fb710d665127dfe", 47, "a change with commitref in body"), - CommitRef("9a14e5628bdf2d578f3385d78022ddcaf23d1abb", 47, "add test file - relates to #47") - ), - result.content - ) - } -} \ No newline at end of file
--- a/src/test/resources/test-repo/hg/cache/branch2-served Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -cf9f5982ddeb28c7f695dc547fe73abf5460016f 4 -cf9f5982ddeb28c7f695dc547fe73abf5460016f o default
--- a/src/test/resources/test-repo/hg/cache/rbc-names-v1 Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -default \ No newline at end of file
--- a/src/test/resources/test-repo/hg/cache/tags2-visible Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -4 cf9f5982ddeb28c7f695dc547fe73abf5460016f
--- a/src/test/resources/test-repo/hg/last-message.txt Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -here we fix #50 - -and close #30 -
--- a/src/test/resources/test-repo/hg/requires Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -share-safe
--- a/src/test/resources/test-repo/hg/store/fncache Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -data/testfile.i -data/another-file.i
--- a/src/test/resources/test-repo/hg/store/phaseroots Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -1 9a14e5628bdf2d578f3385d78022ddcaf23d1abb
--- a/src/test/resources/test-repo/hg/store/requires Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -dotencode -fncache -generaldelta -revlog-compression-zstd -revlogv1 -sparserevlog -store
--- a/src/test/resources/test-repo/hg/store/undo.backup.fncache Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -data/testfile.i
--- a/src/test/resources/test-repo/hg/store/undo.phaseroots Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -1 9a14e5628bdf2d578f3385d78022ddcaf23d1abb
--- a/src/test/resources/test-repo/hg/undo.branch Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -default \ No newline at end of file
--- a/src/test/resources/test-repo/hg/undo.desc Sat Jul 22 11:32:27 2023 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -4 -commit