diff --git a/jenkinsapi/job.py b/jenkinsapi/job.py
index 00df4714..fc311d0a 100644
--- a/jenkinsapi/job.py
+++ b/jenkinsapi/job.py
@@ -50,8 +50,14 @@ def __init__(self, url: str, name: str, jenkins_obj: "Jenkins") -> None:
self._scm_prefix = ""
self._scm_map = {
"hudson.scm.SubversionSCM": "svn",
+ "jenkins.scm.impl.subversion.SubversionSCMSource": "svn",
"hudson.plugins.git.GitSCM": "git",
+ "jenkins.plugins.git.GitSCMSource": "git",
"hudson.plugins.mercurial.MercurialSCM": "hg",
+ "org.jenkinsci.plugins.github_branch_source.GitHubSCMSource": "github",
+ "com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource": "bitbucket",
+ "io.jenkins.plugins.gitlabbranchsource.GitLabSCMSource": "gitlab",
+ "org.jenkinsci.plugins.gitea.GiteaSCMSource": "gitea",
"hudson.scm.NullSCM": "NullSCM",
}
self._scmurlmap = {
@@ -528,17 +534,38 @@ def get_config(self):
def load_config(self):
self._config = self.get_config()
+ def _get_scm_from_branch_job_property(self, element_tree):
+ """Check element_tree for BranchJobProperty"""
+ scm_element = None
+ log.debug("Check BranchJobProperty for scm type")
+ multibranch_scm_prefix = "properties/org.jenkinsci.plugins.\
+ workflow.multibranch.BranchJobProperty/branch/"
+ multibranch_path = multibranch_scm_prefix + "scm"
+ scm_element = element_tree.find(multibranch_path)
+ return scm_element
+
+ def _get_scm_from_branch_source(self, element_tree):
+ """Check for scm type from BranchSource"""
+ source_class = None
+ log.debug("Check BranchSource for scm type")
+ branch_source_path = ".//sources//data//jenkins.branch.BranchSource"
+ scm_element = element_tree.find(branch_source_path)
+ if not scm_element:
+ scm_element = element_tree.find(".//sources/..")
+
+ if scm_element:
+ source_class = scm_element.find(".//source")
+
+ return source_class
+
def get_scm_type(self):
element_tree = self._get_config_element_tree()
- scm_element = element_tree.find("scm")
+ scm_element = element_tree.find(".//scm")
+ if not scm_element:
+ scm_element = self._get_scm_from_branch_job_property(element_tree)
if not scm_element:
- multibranch_scm_prefix = "properties/org.jenkinsci.plugins.\
- workflow.multibranch.BranchJobProperty/branch/"
- multibranch_path = multibranch_scm_prefix + "scm"
- scm_element = element_tree.find(multibranch_path)
- if scm_element:
- # multibranch pipeline.
- self._scm_prefix = multibranch_scm_prefix
+ scm_element = self._get_scm_from_branch_source(element_tree)
+
scm_class = scm_element.get("class") if scm_element else None
scm = self._scm_map.get(scm_class)
if not scm:
diff --git a/jenkinsapi_tests/systests/conftest.py b/jenkinsapi_tests/systests/conftest.py
index a7389900..2fad409c 100644
--- a/jenkinsapi_tests/systests/conftest.py
+++ b/jenkinsapi_tests/systests/conftest.py
@@ -15,6 +15,18 @@
# Extra plugins required by the systests
PLUGIN_DEPENDENCIES = [
+ "https://updates.jenkins.io/latest/cloudbees-folder.hpi",
+ "https://updates.jenkins.io/latest/branch-api.hpi",
+ "https://updates.jenkins.io/latest/workflow-job.hpi",
+ "https://updates.jenkins.io/latest/workflow-cps.hpi",
+ "https://updates.jenkins.io/latest/workflow-multibranch.hpi",
+ "https://updates.jenkins.io/latest/okhttp-api.hpi",
+ "https://updates.jenkins.io/latest/github-api.hpi",
+ "https://updates.jenkins.io/latest/json-path-api.hpi",
+ "https://updates.jenkins.io/latest/token-macro.hpi",
+ "https://updates.jenkins.io/latest/github.hpi",
+ "https://updates.jenkins.io/latest/jjwt-api.hpi",
+ "https://updates.jenkins.io/latest/github-branch-source.hpi",
"https://updates.jenkins.io/latest/apache-httpcomponents-client-4-api.hpi",
"https://updates.jenkins.io/latest/mina-sshd-api-common.hpi",
"https://updates.jenkins.io/latest/mina-sshd-api-core.hpi",
diff --git a/jenkinsapi_tests/systests/job_configs.py b/jenkinsapi_tests/systests/job_configs.py
index 35fa782e..d065afea 100644
--- a/jenkinsapi_tests/systests/job_configs.py
+++ b/jenkinsapi_tests/systests/job_configs.py
@@ -339,3 +339,170 @@
""".strip()
+
+PIPELINE_SCM_JOB = """
+
+
+
+
+ 2
+
+
+ https://github.com/salimfadhley/jenkinsapi.git
+
+
+
+
+ main
+
+
+
+
+""".strip()
+
+MULTIBRANCH_GIT_SCM_JOB = """
+
+
+
+
+
+
+
+
+
+
+
+
+
+true
+-1
+-1
+false
+
+
+false
+
+
+
+
+e0a4ce06-e537-4893-9ba4-2dd4f18d7a44
+https://github.com/pycontribs/jenkinsapi
+
+
+
+
+(master.*)
+
+
+
+
+
+
+
+
+
+
+
+
+uv.lock
+
+
+""".strip()
+
+MULTIBRANCH_GIT_BRANCH_JOB_PROPERTY = """
+
+
+
+false
+
+
+
+bc1f7bd0-b8d0-48db-ac98-bcae92939715
+
+a
+
+
+2
+
+
+https://github.com/pycontribs/jenkinsapi.git
+
+
+
+
+*/master
+
+
+false
+
+
+
+
+
+
+
+
+
+uv.lock
+
+
+false
+
+""".strip()
+
+MULTIBRANCH_GITHUB_SCM_JOB = """
+
+
+
+
+
+
+
+
+
+
+
+
+
+true
+-1
+-1
+false
+
+
+false
+
+
+
+
+e82f0840-83c9-44b3-a903-3825f776da38
+https://api.github.com
+pycontribs
+jenkinsapi
+https://github.com/pycontribs/jenkinsapi
+
+
+1
+
+
+2
+
+
+2
+
+
+
+
+
+
+
+
+
+
+
+
+
+uv.lock
+
+
+"""
diff --git a/jenkinsapi_tests/systests/test_scm.py b/jenkinsapi_tests/systests/test_scm.py
index 3558b787..d1a6841b 100644
--- a/jenkinsapi_tests/systests/test_scm.py
+++ b/jenkinsapi_tests/systests/test_scm.py
@@ -1,32 +1,73 @@
# '''
# System tests for `jenkinsapi.jenkins` module.
# '''
-# To run unittests on python 2.6 please use unittest2 library
-# try:
-# import unittest2 as unittest
-# except ImportError:
-# import unittest
-# from jenkinsapi_tests.systests.base import BaseSystemTest
-# from jenkinsapi_tests.test_utils.random_strings import random_string
-# from jenkinsapi_tests.systests.job_configs import SCM_GIT_JOB
-
-# # Maybe have a base class for all SCM test activites?
-# class TestSCMGit(BaseSystemTest):
-# # Maybe it makes sense to move plugin dependencies outside the code.
-# # Have a config to dependencies mapping from the launcher can use
-# # to install plugins.
-# def test_get_revision(self):
-# job_name = 'git_%s' % random_string()
-# job = self.jenkins.create_job(job_name, SCM_GIT_JOB)
-# ii = job.invoke()
-# ii.block(until='completed')
-# self.assertFalse(ii.is_running())
-# b = ii.get_build()
-# try:
-# self.assertIsInstance(b.get_revision(), basestring)
-# except NameError:
-# # Python3
-# self.assertIsInstance(b.get_revision(), str)
-
-# if __name__ == '__main__':
-# unittest.main()
+from testfixtures import compare
+from time import sleep
+
+from jenkinsapi_tests.test_utils.random_strings import random_string
+from jenkinsapi_tests.systests.job_configs import (
+ SCM_GIT_JOB,
+ MULTIBRANCH_GIT_BRANCH_JOB_PROPERTY,
+ MULTIBRANCH_GIT_SCM_JOB,
+ MULTIBRANCH_GITHUB_SCM_JOB,
+)
+
+
+def wait_for_job_setup(jenkins, job_name):
+ for _ in range(5):
+ for _url, name in list(jenkins.get_jobs_info()):
+ if job_name in name:
+ return True
+ else:
+ sleep(10)
+
+
+def test_get_scm_type(jenkins):
+ job_name = "git_%s" % random_string()
+ job = jenkins.create_job(job_name, SCM_GIT_JOB)
+ queueItem = job.invoke()
+ queueItem.block_until_complete()
+
+ wait_for_job_setup(jenkins, job_name)
+ compare(job.get_scm_type(), "git")
+ jenkins.delete_job(job_name)
+
+
+def test_get_scm_type_pipeline_scm_multibranch_BranchJobProperty(
+ jenkins,
+):
+ job_name = "git_%s" % random_string()
+ job = jenkins.create_job(job_name, MULTIBRANCH_GIT_BRANCH_JOB_PROPERTY)
+ queueItem = job.invoke()
+ queueItem.block_until_complete()
+ wait_for_job_setup(jenkins, job_name)
+ compare(job.get_scm_type(), "git")
+
+
+## Disabling for now, running into permissions errors
+def test_get_scm_type_pipeline_scm_multibranch_BranchSource(
+ jenkins,
+):
+ job_name = "git_%s" % random_string()
+ job = jenkins.create_multibranch_pipeline_job(
+ job_name, MULTIBRANCH_GIT_SCM_JOB
+ )
+ queueItem = job.invoke()
+ queueItem.block_until_complete()
+ wait_for_job_setup(jenkins, job_name)
+ job.invoke(block=True, delay=20)
+ compare(job[0].get_scm_type(), "git")
+
+
+def test_get_scm_type_pipeline_github_multibranch_BranchSource(
+ jenkins,
+):
+ job_name = "git_%s" % random_string()
+ job = jenkins.create_multibranch_pipeline_job(
+ job_name, MULTIBRANCH_GITHUB_SCM_JOB
+ )
+ queueItem = job.invoke()
+ queueItem.block_until_complete()
+ wait_for_job_setup(jenkins, job_name)
+ job.invoke(block=True, delay=20)
+ compare(job.get_scm_type(), "github")
diff --git a/pyproject.toml b/pyproject.toml
index ac6ae681..003284c3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -80,6 +80,7 @@ dev = [
"mock>=5.1.0",
"requests-kerberos>=0.15.0",
"ruff>=0.9.6",
+ "testfixtures>=8.3.0",
]
docs = [
"docutils>=0.20.1",
diff --git a/uv.lock b/uv.lock
index e3f5e304..6f13ed8d 100644
--- a/uv.lock
+++ b/uv.lock
@@ -584,6 +584,8 @@ dev = [
{ name = "pytest-mock" },
{ name = "requests-kerberos" },
{ name = "ruff" },
+ { name = "testfixtures", version = "8.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "testfixtures", version = "10.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
{ name = "tox", version = "4.30.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "tox", version = "4.32.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
@@ -613,6 +615,7 @@ dev = [
{ name = "pytest-mock", specifier = ">=3.14.0" },
{ name = "requests-kerberos", specifier = ">=0.15.0" },
{ name = "ruff", specifier = ">=0.9.6" },
+ { name = "testfixtures", specifier = ">=8.3.0" },
{ name = "tox", specifier = ">=2.3.1" },
]
docs = [
@@ -1310,6 +1313,32 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/6e/9a/8c11707040d13c53a2bc1dab54cb8c172e1bb00e34e9f92f64a6a41302e6/sspilib-0.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:d45eff48922c23eb63d39a7f0a51167c5284ec348e0663f1377c983bcb9eb94d", size = 495125, upload-time = "2025-09-01T00:26:19.86Z" },
]
+[[package]]
+name = "testfixtures"
+version = "8.3.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version == '3.10.*'",
+ "python_full_version < '3.10'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/3b/25/d7e9d05f87e2ab84657a0dfb1f24fc295d542ac2eb221531d976ea4aa1ff/testfixtures-8.3.0.tar.gz", hash = "sha256:d4c0b84af2f267610f908009b50d6f983a4e58ade22c67bab6787b5a402d59c0", size = 137420, upload-time = "2024-06-07T18:12:27.484Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1a/4e/699671ba484b94bda0959b281ff59b24f728263befd13e060fa038ce3bc8/testfixtures-8.3.0-py3-none-any.whl", hash = "sha256:3d1e0e0005c4d6ac2a2ab27916704c6471047f0d2f78f2e54adf20abdacc7b10", size = 105085, upload-time = "2024-06-07T18:12:23.298Z" },
+]
+
+[[package]]
+name = "testfixtures"
+version = "10.0.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.12'",
+ "python_full_version == '3.11.*'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4d/53/d7439458a89dc5be4780b23af09432a8347c798ea52ba0b53fd158f86653/testfixtures-10.0.0.tar.gz", hash = "sha256:2b9829bf7f42f0ca8600250762e6725575da59af18d9a7f82aae2c97b14f0f66", size = 147464, upload-time = "2025-10-29T08:42:20.733Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/15/30/70da9c7cd9931f2299ab2a353cf082427ba5dbea5f34db57e6a9ef89c8a5/testfixtures-10.0.0-py3-none-any.whl", hash = "sha256:c54ed5c4cd93ad271a6add94a575a5843964ea3aaf590f4c3cb4df16a261b15f", size = 111285, upload-time = "2025-10-29T08:42:19.647Z" },
+]
+
[[package]]
name = "tomli"
version = "2.2.1"