diff --git a/core/src/main/java/cz/xtf/core/git/GitResolver.java b/core/src/main/java/cz/xtf/core/git/GitResolver.java
new file mode 100644
index 00000000..a2c6018a
--- /dev/null
+++ b/core/src/main/java/cz/xtf/core/git/GitResolver.java
@@ -0,0 +1,7 @@
+package cz.xtf.core.git;
+
+interface GitResolver {
+ String resolveRepoUrl();
+
+ String resolveRepoRef();
+}
diff --git a/core/src/main/java/cz/xtf/core/git/GitResolverFactory.java b/core/src/main/java/cz/xtf/core/git/GitResolverFactory.java
new file mode 100644
index 00000000..4ffedf72
--- /dev/null
+++ b/core/src/main/java/cz/xtf/core/git/GitResolverFactory.java
@@ -0,0 +1,16 @@
+package cz.xtf.core.git;
+
+import cz.xtf.core.config.XTFConfig;
+
+class GitResolverFactory {
+ static final String GIT_URL = "xtf.git.repository.url";
+ static final String GIT_BRANCH = "xtf.git.repository.ref";
+
+ public static GitResolver createResolver() {
+ if (XTFConfig.get(GIT_URL) == null || XTFConfig.get(GIT_BRANCH) == null) {
+ return new JGitResolver();
+ } else {
+ return new SystemPropertyGitResolver();
+ }
+ }
+}
diff --git a/core/src/main/java/cz/xtf/core/git/GitUtils.java b/core/src/main/java/cz/xtf/core/git/GitUtils.java
new file mode 100644
index 00000000..65e45673
--- /dev/null
+++ b/core/src/main/java/cz/xtf/core/git/GitUtils.java
@@ -0,0 +1,14 @@
+package cz.xtf.core.git;
+
+public class GitUtils {
+ private static final GitResolver gitResolver = GitResolverFactory.createResolver();
+
+ // Static method to get repo URL and ref
+ public static String getRepoUrl() {
+ return gitResolver.resolveRepoUrl();
+ }
+
+ public static String getRepoRef() {
+ return gitResolver.resolveRepoRef();
+ }
+}
diff --git a/core/src/main/java/cz/xtf/core/git/JGitResolver.java b/core/src/main/java/cz/xtf/core/git/JGitResolver.java
new file mode 100644
index 00000000..fd02a380
--- /dev/null
+++ b/core/src/main/java/cz/xtf/core/git/JGitResolver.java
@@ -0,0 +1,140 @@
+package cz.xtf.core.git;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
+import org.eclipse.jgit.transport.RemoteConfig;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Try to resolve repository remote URL and branch from .git directory
+ *
+ * This method tries to match HEAD commit to remote references.
+ * If there is a match, the remote URL and branch are set.
+ * For attached HEAD this method could be simplified with jgit methods, but
+ * "universal" approach was chosen, as for example Jenkins git plugin creates a detached state.
+ * In case of multiple matches, upstream or origin (in this order) is preferred.
+ *
+ */
+@Slf4j
+class JGitResolver implements GitResolver {
+ private static final String URL_TEMPLATE = "https://%s/%s/%s";
+ private static String reference;
+ private static String url;
+
+ /**
+ * Try to set repository ref and URL from HEAD commit
+ */
+ public JGitResolver() {
+ try {
+ resolveRepoFromHEAD();
+ } catch (IOException | URISyntaxException e) {
+ log.error("Failed to resolve repository from HEAD", e);
+ throw new RuntimeException("Failed to resolve repository from HEAD with error: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Try to set repository ref and URL from HEAD commit
+ */
+ private static void resolveRepoFromHEAD() throws IOException, URISyntaxException {
+ //look for a git repository recursively till system root folder
+ Repository repository = new FileRepositoryBuilder().findGitDir().build();
+
+ if (repository == null) {
+ log.error("Failed to find a git repository");
+ return;
+ }
+
+ //get current commit hash
+ ObjectId commitId = repository.resolve("HEAD");
+
+ //get all remote references
+ List[ refs = repository.getRefDatabase().getRefs().stream()
+ .filter(reference -> reference.getName().startsWith("refs/remotes/")).collect(Collectors.toList());
+
+ List matches = new ArrayList<>();
+ // Walk through all the refs to see if any point to this commit
+ for (Ref ref : refs) {
+ if (ref.getObjectId().equals(commitId)) {
+ matches.add(ref.getName());
+ }
+ }
+
+ if (matches.isEmpty()) {
+ log.error("No remote references found for the current commit");
+ return;
+ }
+
+ //In case there are multiple matches, we prefer upstream or origin (in this order)
+ List preferredMatches = matches.stream()
+ .filter(reference -> reference.contains("upstream") || reference.contains("origin"))
+ .sorted(Comparator.reverseOrder()) // 1) upstream 2) origin
+ .collect(Collectors.toList());
+
+ if (matches.size() > 1 && !preferredMatches.isEmpty()) {
+ matches = preferredMatches;
+ }
+
+ //branch is string behind the last /
+ reference = matches.stream().findFirst().map(ref -> ref.substring(ref.lastIndexOf('/') + 1)).orElse(null);
+
+ log.info("xtf.git.repository.ref got automatically resolved as {}", reference);
+
+ String remote = repository.getRemoteName(matches.get(0));
+ url = getRemoteUrl(repository, remote);
+
+ if (url != null) {
+ log.info("xtf.git.repository.url got automatically resolved as {}", url);
+ }
+
+ }
+
+ /**
+ * given a remote reference, get it's remote URL
+ *
+ * @param repository git repository
+ * @param remoteReference reference in format "refs/remotes/remote/branch"
+ * @return URL in HTTPS format
+ */
+ private static String getRemoteUrl(Repository repository, String remoteReference) throws URISyntaxException {
+ RemoteConfig remoteConfig = new RemoteConfig(repository.getConfig(), remoteReference);
+ if (remoteConfig.getURIs() == null || remoteConfig.getURIs().isEmpty()) {
+ log.info("Missing URI in git remote ref '{}'", remoteReference);
+ return null;
+ }
+ // we expect a single URI
+ String[] pathTokens = remoteConfig.getURIs().get(0).getPath().split("/");
+ if (pathTokens.length != 2) {
+ log.info("Unexpected path '{}' in URI '{}' of git remote ref '{}'", remoteConfig.getURIs().get(0).getPath(),
+ remoteConfig.getURIs().get(0), remoteReference);
+ return null;
+ }
+ // the URI must be in HTTPS format
+ return getRepositoryUrl(remoteConfig.getURIs().get(0).getHost(), pathTokens[0], pathTokens[1]);
+ }
+
+ /**
+ * We require HTTPS format, for unauthorized access to the repository, let's convert it
+ */
+ private static String getRepositoryUrl(String host, String remote, String repository) {
+ return String.format(URL_TEMPLATE, host, remote, repository);
+ }
+
+ public String resolveRepoUrl() {
+ return url;
+ }
+
+ public String resolveRepoRef() {
+ return reference;
+ }
+}
diff --git a/core/src/main/java/cz/xtf/core/git/SystemPropertyGitResolver.java b/core/src/main/java/cz/xtf/core/git/SystemPropertyGitResolver.java
new file mode 100644
index 00000000..d75134a3
--- /dev/null
+++ b/core/src/main/java/cz/xtf/core/git/SystemPropertyGitResolver.java
@@ -0,0 +1,16 @@
+package cz.xtf.core.git;
+
+import cz.xtf.core.config.XTFConfig;
+
+class SystemPropertyGitResolver implements GitResolver {
+ static final String GIT_URL = "xtf.git.repository.url";
+ static final String GIT_BRANCH = "xtf.git.repository.ref";
+
+ public String resolveRepoUrl() {
+ return XTFConfig.get(GIT_URL);
+ }
+
+ public String resolveRepoRef() {
+ return XTFConfig.get(GIT_BRANCH);
+ }
+}
diff --git a/pom.xml b/pom.xml
index 1562765a..aa91d41e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -80,6 +80,7 @@
1.18.22
2.8.9
32.0.1-jre
+ 5.13.3.202401111512-r
3.2.1
@@ -226,6 +227,12 @@
openshift-server-mock
${version.openshift-client}
+
+
+ org.eclipse.jgit
+ org.eclipse.jgit
+ ${version.org.eclipse.jgit}
+
]