From 48a5ec4ad55379e8535e1017b4ec8dbe55edbb28 Mon Sep 17 00:00:00 2001 From: long76 <18124433+long76@users.noreply.github.com> Date: Sun, 7 Dec 2025 13:39:37 +0000 Subject: [PATCH 1/8] implement decorateContext in CloneOptionTrait --- README.adoc | 11 ++++ .../plugins/git/AbstractGitSCMSource.java | 1 + .../plugins/git/GitSCMSourceContext.java | 55 +++++++++++++++++++ .../plugins/git/traits/CloneOptionTrait.java | 8 +++ .../git/traits/CloneOptionTraitTest.java | 42 ++++++++++++++ 5 files changed, 117 insertions(+) create mode 100644 src/test/java/jenkins/plugins/git/traits/CloneOptionTraitTest.java diff --git a/README.adoc b/README.adoc index 9fe260dc41..842025013b 100644 --- a/README.adoc +++ b/README.adoc @@ -136,6 +136,17 @@ checkout scmGit( userRemoteConfigs: [[url: 'https://github.com/jenkinsci/ws-cleanup-plugin']]) ---- +[source,groovy] +---- +resolveScm( + source: gitSource( + credentialsId: 'git-cred', + traits: [cloneOption(cloneOption(depth: 1, shallow: true)), gitBranchDiscovery()] + remote: 'https://github.com/jenkinsci/ws-cleanup-plugin'), + targets: ['main', 'master'] +) +---- + ==== Checkout with a narrow refspec Checkout from the workspace cleanup plugin source repository using https without credentials, the `master` branch, and with a refspec specific to the master branch. diff --git a/src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java b/src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java index 1504297965..2e310a0640 100644 --- a/src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java +++ b/src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java @@ -404,6 +404,7 @@ private , R extends GitSCMSourceRequest> fetch.tags(context.wantTags()); } fetch = fetch.prune(prune); + fetch = fetch.shallow(context.wantShallow()).depth(context.depth()); URIish remoteURI = null; try { diff --git a/src/main/java/jenkins/plugins/git/GitSCMSourceContext.java b/src/main/java/jenkins/plugins/git/GitSCMSourceContext.java index df04fdd288..4fa12dd0a0 100644 --- a/src/main/java/jenkins/plugins/git/GitSCMSourceContext.java +++ b/src/main/java/jenkins/plugins/git/GitSCMSourceContext.java @@ -94,6 +94,14 @@ public class GitSCMSourceContext, R extends */ @NonNull private String remoteName = AbstractGitSCMSource.DEFAULT_REMOTE_NAME; + /** + * Perform shallow clone + */ + private boolean shallow; + /** + * Shallow clone depth + */ + private Integer depth; /** * Constructor. @@ -192,6 +200,25 @@ public final String remoteName() { return remoteName; } + /** + * Returns {@code true} if a limited number of commits will be retrieved when cloning with a GitSCMSource. + * A GitSCMSource is most commonly used when defining a multibranch Pipeline. + * + * @return {@code true} if a limited number of commits will be retrieved + */ + public final boolean wantShallow() { + return shallow; + } + + /** + * Returns shallow clone depth + * + * @return shallow clone depth + */ + public final Integer depth() { + return depth; + } + /** * Adds a requirement for branch details to any {@link GitSCMSourceRequest} for this context. * @@ -358,6 +385,34 @@ public final List asRefSpecs() { return result; } + /** + * Limit the number of commits that will be retrieved when the multibranch Pipeline is cloned. + * When shallow clone is enabled, a single commit will be retrieved instead of retrieving all commits. + * If more commits are needed, set the depth to a larger value. + * + * @param shallow {@code true} to perform shallow clone + * @return {@code this} for method chaining. + */ + @SuppressWarnings("unchecked") + @NonNull + public final C shallow(boolean shallow) { + this.shallow = shallow; + return (C) this; + } + + /** + * Configures shallow clone depth + * + * @param depth upper limit to the number of commits included in the repository clone + * @return {@code this} for method chaining. + */ + @SuppressWarnings("unchecked") + @NonNull + public final C depth(Integer depth) { + this.depth = depth; + return (C) this; + } + /** * {@inheritDoc} */ diff --git a/src/main/java/jenkins/plugins/git/traits/CloneOptionTrait.java b/src/main/java/jenkins/plugins/git/traits/CloneOptionTrait.java index 68a1d3a4ec..fa6c78637c 100644 --- a/src/main/java/jenkins/plugins/git/traits/CloneOptionTrait.java +++ b/src/main/java/jenkins/plugins/git/traits/CloneOptionTrait.java @@ -27,6 +27,8 @@ import hudson.Extension; import hudson.plugins.git.extensions.impl.CloneOption; +import jenkins.plugins.git.GitSCMSourceContext; +import jenkins.scm.api.trait.SCMSourceContext; import jenkins.scm.api.trait.SCMSourceTrait; import org.jenkinsci.Symbol; import org.kohsuke.stapler.DataBoundConstructor; @@ -47,6 +49,12 @@ public CloneOptionTrait(CloneOption extension) { super(extension); } + @Override + protected void decorateContext(SCMSourceContext context) { + CloneOption extension = getExtension(); + ((GitSCMSourceContext) context).shallow(extension.isShallow()).depth(extension.getDepth()); + } + /** * Our {@link hudson.model.Descriptor} */ diff --git a/src/test/java/jenkins/plugins/git/traits/CloneOptionTraitTest.java b/src/test/java/jenkins/plugins/git/traits/CloneOptionTraitTest.java new file mode 100644 index 0000000000..7da43ebd89 --- /dev/null +++ b/src/test/java/jenkins/plugins/git/traits/CloneOptionTraitTest.java @@ -0,0 +1,42 @@ +package jenkins.plugins.git.traits; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +import hudson.plugins.git.extensions.impl.CloneOption; +import jenkins.plugins.git.GitSCMSourceContext; + +class CloneOptionTraitTest { + + @Test + void testShallowDisabledByDefault() { + GitSCMSourceContext context = new GitSCMSourceContext<>(null, null); + assertFalse(context.wantShallow()); + assertNull(context.depth()); + } + + @Test + void testDecorateWithDefaultCloneOption() { + GitSCMSourceContext context = new GitSCMSourceContext<>(null, null); + CloneOption cloneOption = new CloneOption(false, null, null); + CloneOptionTrait cloneOptionTrait = new CloneOptionTrait(cloneOption); + cloneOptionTrait.decorateContext(context); + assertFalse(context.wantShallow()); + assertNull(context.depth()); + } + + @Test + void testDecorateCloneOptionWithShallow() { + GitSCMSourceContext context = new GitSCMSourceContext<>(null, null); + CloneOption cloneOption = new CloneOption(true, null, null); + cloneOption.setDepth(10); + CloneOptionTrait cloneOptionTrait = new CloneOptionTrait(cloneOption); + cloneOptionTrait.decorateContext(context); + assertTrue(context.wantShallow()); + assertEquals(context.depth(), 10); + } +} \ No newline at end of file From 91170f6172372f45245cb06d7df0ec06b3ecfec4 Mon Sep 17 00:00:00 2001 From: long76 <18124433+long76@users.noreply.github.com> Date: Sun, 7 Dec 2025 15:24:17 +0000 Subject: [PATCH 2/8] add usage resolveScm in example --- README.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.adoc b/README.adoc index 842025013b..b63effdd34 100644 --- a/README.adoc +++ b/README.adoc @@ -138,13 +138,14 @@ checkout scmGit( [source,groovy] ---- -resolveScm( +def resolvedSCMBranch = resolveScm( source: gitSource( credentialsId: 'git-cred', traits: [cloneOption(cloneOption(depth: 1, shallow: true)), gitBranchDiscovery()] remote: 'https://github.com/jenkinsci/ws-cleanup-plugin'), targets: ['main', 'master'] ) +checkout resolvedSCMBranch ---- ==== Checkout with a narrow refspec From d609e922eae3e4dc6d1ea8128f33835285100ef9 Mon Sep 17 00:00:00 2001 From: long76 <18124433+long76@users.noreply.github.com> Date: Sun, 7 Dec 2025 15:33:52 +0000 Subject: [PATCH 3/8] checkout directly from resolveScm --- README.adoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.adoc b/README.adoc index b63effdd34..0cf8f4749a 100644 --- a/README.adoc +++ b/README.adoc @@ -138,14 +138,13 @@ checkout scmGit( [source,groovy] ---- -def resolvedSCMBranch = resolveScm( +checkout resolveScm( source: gitSource( credentialsId: 'git-cred', traits: [cloneOption(cloneOption(depth: 1, shallow: true)), gitBranchDiscovery()] remote: 'https://github.com/jenkinsci/ws-cleanup-plugin'), targets: ['main', 'master'] ) -checkout resolvedSCMBranch ---- ==== Checkout with a narrow refspec From cabd3fd02f6595d7596ba17822f3d7bf0a50ae02 Mon Sep 17 00:00:00 2001 From: long76 <18124433+long76@users.noreply.github.com> Date: Sun, 7 Dec 2025 17:38:11 +0000 Subject: [PATCH 4/8] use pattern matching in decorateContext --- .../java/jenkins/plugins/git/traits/CloneOptionTrait.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/jenkins/plugins/git/traits/CloneOptionTrait.java b/src/main/java/jenkins/plugins/git/traits/CloneOptionTrait.java index fa6c78637c..679b98da58 100644 --- a/src/main/java/jenkins/plugins/git/traits/CloneOptionTrait.java +++ b/src/main/java/jenkins/plugins/git/traits/CloneOptionTrait.java @@ -51,8 +51,10 @@ public CloneOptionTrait(CloneOption extension) { @Override protected void decorateContext(SCMSourceContext context) { - CloneOption extension = getExtension(); - ((GitSCMSourceContext) context).shallow(extension.isShallow()).depth(extension.getDepth()); + if (context instanceof GitSCMSourceContext gitContext) { + CloneOption extension = getExtension(); + gitContext.shallow(extension.isShallow()).depth(extension.getDepth()); + } } /** From 2080375a94943e9ffc73f6127531b0b245390f63 Mon Sep 17 00:00:00 2001 From: long76 <18124433+long76@users.noreply.github.com> Date: Mon, 26 Jan 2026 13:53:12 +0000 Subject: [PATCH 5/8] docs: move resolveScm to dedicated paragraph --- README.adoc | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/README.adoc b/README.adoc index 0cf8f4749a..cb8a3c124e 100644 --- a/README.adoc +++ b/README.adoc @@ -136,17 +136,6 @@ checkout scmGit( userRemoteConfigs: [[url: 'https://github.com/jenkinsci/ws-cleanup-plugin']]) ---- -[source,groovy] ----- -checkout resolveScm( - source: gitSource( - credentialsId: 'git-cred', - traits: [cloneOption(cloneOption(depth: 1, shallow: true)), gitBranchDiscovery()] - remote: 'https://github.com/jenkinsci/ws-cleanup-plugin'), - targets: ['main', 'master'] -) ----- - ==== Checkout with a narrow refspec Checkout from the workspace cleanup plugin source repository using https without credentials, the `master` branch, and with a refspec specific to the master branch. @@ -187,6 +176,21 @@ checkout scmGit( userRemoteConfigs: [[url: 'https://github.com/jenkinsci/ws-cleanup-plugin']]) ---- +==== Resolve an SCM from an Git Source and a list of candidate target branch names before checkout + +Find first matching branch from repository and checkout on this. You can pass `cloneOption` with shallow flag for speed-up retrieve target branch. + +[source,groovy] +---- +checkout resolveScm( + source: gitSource( + credentialsId: 'git-cred', + traits: [cloneOption(cloneOption(depth: 1, shallow: true)), gitBranchDiscovery()] + remote: 'https://github.com/jenkinsci/ws-cleanup-plugin'), + targets: ['main', 'master'] +) +---- + [#credential-binding] === Git Credentials Binding From 4e0f1c625dc10e45e2e08619db63e6464c59b103 Mon Sep 17 00:00:00 2001 From: long76 <18124433+long76@users.noreply.github.com> Date: Mon, 26 Jan 2026 14:42:16 +0000 Subject: [PATCH 6/8] docs: expand description --- README.adoc | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/README.adoc b/README.adoc index cb8a3c124e..6c1ac82079 100644 --- a/README.adoc +++ b/README.adoc @@ -178,7 +178,21 @@ checkout scmGit( ==== Resolve an SCM from an Git Source and a list of candidate target branch names before checkout -Find first matching branch from repository and checkout on this. You can pass `cloneOption` with shallow flag for speed-up retrieve target branch. +Find first matching branch from repository and checkout on this. You can pass `cloneOption` trait with shallow flag for speed-up retrieve target branch. + +In Multi-branch pipeline `resolveScm` used for build all or specified(e.g. wildcard rule) branches. You can use `env.BRANCH_NAME` for get current branch this build. + +[source,groovy] +---- +checkout resolveScm( + source: gitSource( + credentialsId: 'git-cred', + traits: [cloneOption(cloneOption(depth: 1, shallow: true)), gitBranchDiscovery()] + remote: 'https://github.com/jenkinsci/ws-cleanup-plugin'), + targets: [env.BRANCH_NAME, 'main', 'master'] +) + +In single pipeline which build one specified branch, `resolveScm` can be used for resolve dependency branch(e.g. the same name `task-1234`). [source,groovy] ---- @@ -187,10 +201,13 @@ checkout resolveScm( credentialsId: 'git-cred', traits: [cloneOption(cloneOption(depth: 1, shallow: true)), gitBranchDiscovery()] remote: 'https://github.com/jenkinsci/ws-cleanup-plugin'), - targets: ['main', 'master'] + targets: ['task-1234', 'main', 'master'] ) ---- +link:https://www.jenkins.io/doc/pipeline/steps/workflow-multibranch/#resolvescm-resolves-an-scm-from-an-scm-source-and-a-list-of-candidate-target-branch-names[Documentation resolveScm] +link:https://www.jenkins.io/doc/book/pipeline/[Documentation pipeline] + [#credential-binding] === Git Credentials Binding From 5c310b3e13e76ebd8fc9ca1d52cb3a4f5a7507c0 Mon Sep 17 00:00:00 2001 From: long76 <18124433+long76@users.noreply.github.com> Date: Mon, 26 Jan 2026 14:43:25 +0000 Subject: [PATCH 7/8] fix docs syntax --- README.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/README.adoc b/README.adoc index 6c1ac82079..a9e6b026cd 100644 --- a/README.adoc +++ b/README.adoc @@ -191,6 +191,7 @@ checkout resolveScm( remote: 'https://github.com/jenkinsci/ws-cleanup-plugin'), targets: [env.BRANCH_NAME, 'main', 'master'] ) +---- In single pipeline which build one specified branch, `resolveScm` can be used for resolve dependency branch(e.g. the same name `task-1234`). From 16707594b02845c230a30351db42c0e2a3a2cc74 Mon Sep 17 00:00:00 2001 From: long76 <18124433+long76@users.noreply.github.com> Date: Mon, 26 Jan 2026 14:49:35 +0000 Subject: [PATCH 8/8] refactor: update docs --- README.adoc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.adoc b/README.adoc index a9e6b026cd..75518d1253 100644 --- a/README.adoc +++ b/README.adoc @@ -178,9 +178,10 @@ checkout scmGit( ==== Resolve an SCM from an Git Source and a list of candidate target branch names before checkout -Find first matching branch from repository and checkout on this. You can pass `cloneOption` trait with shallow flag for speed-up retrieve target branch. +Find first matching branch from repository and checkout on this. link:https://www.jenkins.io/doc/pipeline/steps/workflow-multibranch/#resolvescm-resolves-an-scm-from-an-scm-source-and-a-list-of-candidate-target-branch-names[resolveScm] can be used for resolve dependency branch(e.g. the same name `task-1234`). +You can pass `cloneOption` trait with shallow flag for speed-up retrieve target branch. -In Multi-branch pipeline `resolveScm` used for build all or specified(e.g. wildcard rule) branches. You can use `env.BRANCH_NAME` for get current branch this build. +In link:https://www.jenkins.io/doc/pipeline/steps/workflow-multibranch/[Multi-branch pipeline] `resolveScm` used for build all or specified(e.g. wildcard rule) branches. You can use `env.BRANCH_NAME` for get current branch this build. [source,groovy] ---- @@ -193,7 +194,7 @@ checkout resolveScm( ) ---- -In single pipeline which build one specified branch, `resolveScm` can be used for resolve dependency branch(e.g. the same name `task-1234`). +In single link:https://www.jenkins.io/doc/book/pipeline/[pipeline] which build one specified branch(e.g. from parameters) [source,groovy] ---- @@ -202,13 +203,10 @@ checkout resolveScm( credentialsId: 'git-cred', traits: [cloneOption(cloneOption(depth: 1, shallow: true)), gitBranchDiscovery()] remote: 'https://github.com/jenkinsci/ws-cleanup-plugin'), - targets: ['task-1234', 'main', 'master'] + targets: [params.branchName, 'main', 'master'] ) ---- -link:https://www.jenkins.io/doc/pipeline/steps/workflow-multibranch/#resolvescm-resolves-an-scm-from-an-scm-source-and-a-list-of-candidate-target-branch-names[Documentation resolveScm] -link:https://www.jenkins.io/doc/book/pipeline/[Documentation pipeline] - [#credential-binding] === Git Credentials Binding