Is there anyone interested in allowing Jenkins to build tags as well other 
than just branches?

In our team, we have a special requirement that every tag pushed to our Git 
repository should trigger a Jenkins build. We've done that via some 
customization to the Jenkins Git Plugin:

I've attached the patch (based on git-1.2.0), and a screen shot of the 
result build configuration section and it's working as expected.

Notes:
1. The patch is made in a way that by default nothing would be changed.
2. By setting the 'Tags to build' field, you can specify shell patterns as 
in `git tag -l <pattern>` to specify the tags to be built.
3. By checking the 'Don't build branches' checkbox, branches can be skipped

I'm curious about whether this could be adopted by the community, and how? 
I'd love to hear your feedback.

Cheers

-- 
You received this message because you are subscribed to the Google Groups 
"Jenkins Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to jenkinsci-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


<<attachment: jenkins.jpg>>

diff --git a/src/main/java/hudson/plugins/git/GitSCM.java b/src/main/java/hudson/plugins/git/GitSCM.java
index 720652c..675a04c 100644
--- a/src/main/java/hudson/plugins/git/GitSCM.java
+++ b/src/main/java/hudson/plugins/git/GitSCM.java
@@ -121,6 +121,8 @@ public class GitSCM extends SCM implements Serializable {
     private boolean skipTag;
     private String includedRegions;
     private String scmName;
+    private String tag;
+    private boolean skipBranches;
 
     public Collection<SubmoduleConfig> getSubmoduleCfg() {
         return submoduleCfg;
@@ -148,6 +150,8 @@ public class GitSCM extends SCM implements Serializable {
                 createRepoList(repositoryUrl),
                 Collections.singletonList(new BranchSpec("")),
                 null,
+                false,
+                null,
                 false, Collections.<SubmoduleConfig>emptyList(), false,
                 false, new DefaultBuildChooser(), null, null, false, null,
                 null,
@@ -159,6 +163,8 @@ public class GitSCM extends SCM implements Serializable {
             String scmName,
             List<UserRemoteConfig> userRemoteConfigs,
             List<BranchSpec> branches,
+            String tag,
+            boolean skipBranches,
             UserMergeOptions userMergeOptions,
             Boolean doGenerateSubmoduleConfigurations,
             Collection<SubmoduleConfig> submoduleCfg,
@@ -194,6 +200,20 @@ public class GitSCM extends SCM implements Serializable {
         }
         this.branches = branches;
 
+        if (tag == null) {
+            tag = "";
+        }
+
+        tag.trim();
+        if (tag.matches("^((refs/tags/)?(?![-])[-_.a-zA-Z0-9*]+)(\\s+((refs/tags/)?(?![-])[-_.a-zA-Z0-9*]+))*$")) {
+            tag = tag.replace("refs/tags/", "");
+            this.tag = tag;
+        } else {
+            this.tag = "";
+        }
+
+        this.skipBranches = skipBranches;
+
         this.localBranch = Util.fixEmptyAndTrim(localBranch);
 
         this.userRemoteConfigs = userRemoteConfigs;
@@ -1064,7 +1084,7 @@ public class GitSCM extends SCM implements Serializable {
             return null;
         }
         if (candidates.size() > 1) {
-            logger.println("Multiple candidate revisions");
+            logger.println("Multiple candidate revisions " + candidates.size());
             AbstractProject<?, ?> project = build.getProject();
             if (!project.isDisabled()) {
                 logger.println("Scheduling another build to catch up with " + project.getFullDisplayName());
@@ -1123,7 +1143,6 @@ public class GitSCM extends SCM implements Serializable {
         environment.put(GIT_COMMIT, revToBuild.getSha1String());
         Branch branch = revToBuild.getBranches().iterator().next();
         environment.put(GIT_BRANCH, branch.getName());
-
         final BuildChooserContext context = new BuildChooserContextImpl(build.getProject(),build);
 
         final String remoteBranchName = getParameterString(mergeOptions.getRemoteBranchName(), build);
@@ -1229,14 +1248,13 @@ public class GitSCM extends SCM implements Serializable {
                         }
                     }
 
-                    checkout(git, revToBuild.getSha1(), paramLocalBranch);
+                    checkout(git, revToBuild.getBranches().iterator().next().getName());
 
                     if (git.hasGitModules() && !disableSubmodules) {
                         // This ensures we don't miss changes to submodule paths and allows
                         // seamless use of bare and non-bare superproject repositories.
                         git.setupSubmoduleUrls(revToBuild, listener);
                         git.submoduleUpdate(recursiveSubmodules);
-
                     }
 
                     // if(compileSubmoduleCompares)
@@ -1265,6 +1283,10 @@ public class GitSCM extends SCM implements Serializable {
         return true;
     }
 
+    protected void checkout(GitClient git, String tag) {
+        git.checkout(tag);
+    }
+
     /**
      * @param branch move/create the branch in this name at the specified commit-ish and check out that branch.
      */
@@ -1312,6 +1334,10 @@ public class GitSCM extends SCM implements Serializable {
                         listener.getLogger().println("Could not record history. Previous build's commit, " + lastRevWas.getSHA1().name()
                                 + ", does not exist in the current repository.");
                     }
+                } else if (git.tagExists(b.getName())) {
+                    String ups_master = git.getRepository().getConfig().getString("branch", "master", "remote") + "/master";
+                    listener.getLogger().println(String.format("Recording changes in %s..%s", ups_master, b.getName()));
+                    putChangelogDiffs(git, b.getName(), ups_master, b.getName(), out);
                 } else {
                     listener.getLogger().println("No change to record in branch " + b.getName());
                 }
@@ -1686,6 +1712,14 @@ public class GitSCM extends SCM implements Serializable {
         return branches;
     }
 
+    public String getTag() {
+        return tag;
+    }
+
+    public boolean getSkipBranches() {
+        return skipBranches;
+    }
+
     @Exported
     public PreBuildMergeOptions getMergeOptions() {
         return mergeOptions;
diff --git a/src/main/java/hudson/plugins/git/util/BuildData.java b/src/main/java/hudson/plugins/git/util/BuildData.java
index 40b0cdd..e0abaa0 100644
--- a/src/main/java/hudson/plugins/git/util/BuildData.java
+++ b/src/main/java/hudson/plugins/git/util/BuildData.java
@@ -119,15 +119,15 @@ public class BuildData implements Action, Serializable, Cloneable {
             }
 
             return false;
-    	}
-    	catch(Exception ex) {
+        }
+        catch(Exception ex) {
             return false;
-    	}
+        }
     }
 
     public void saveBuild(Build build) {
-    	lastBuild = build;
-    	for(Branch branch : build.revision.getBranches()) {
+        lastBuild = build;
+        for(Branch branch : build.revision.getBranches()) {
             buildsByBranchName.put(fixNull(branch.getName()), build);
     	}
     }
diff --git a/src/main/java/hudson/plugins/git/util/DefaultBuildChooser.java b/src/main/java/hudson/plugins/git/util/DefaultBuildChooser.java
index f1dc5f9..ba20427 100644
--- a/src/main/java/hudson/plugins/git/util/DefaultBuildChooser.java
+++ b/src/main/java/hudson/plugins/git/util/DefaultBuildChooser.java
@@ -3,6 +3,7 @@ package hudson.plugins.git.util;
 import hudson.Extension;
 import hudson.model.TaskListener;
 import hudson.plugins.git.*;
+
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.transport.RemoteConfig;
 import org.kohsuke.stapler.DataBoundConstructor;
@@ -161,42 +162,62 @@ public class DefaultBuildChooser extends BuildChooser {
      */
     private List<Revision> getAdvancedCandidateRevisions(boolean isPollCall, TaskListener listener, GitUtils utils, BuildData data) throws GitException, IOException {
         // 1. Get all the (branch) revisions that exist
-        List<Revision> revs = new ArrayList<Revision>(utils.getAllBranchRevisions());
-        verbose(listener, "Starting with all the branches: {0}", revs);
+        List<Revision> revs = new ArrayList<Revision>();
 
-        // 2. Filter out any revisions that don't contain any branches that we
-        // actually care about (spec)
-        for (Iterator<Revision> i = revs.iterator(); i.hasNext();) {
-            Revision r = i.next();
+        if (! gitSCM.getSkipBranches()) {
+            Collection<Revision> brRevs = utils.getAllBranchRevisions();
+            revs.addAll(brRevs);
+            verbose(listener, "Starting with all the branches: {0}", revs);
+
+            // 2. Filter out any revisions that don't contain any branches that we
+            // actually care about (spec)
+            for (Iterator<Revision> i = revs.iterator(); i.hasNext();) {
+                Revision r = i.next();
 
-            // filter out uninteresting branches
-            for (Iterator<Branch> j = r.getBranches().iterator(); j.hasNext();) {
-                Branch b = j.next();
-                boolean keep = false;
-                for (BranchSpec bspec : gitSCM.getBranches()) {
-                    if (bspec.matches(b.getName())) {
-                        keep = true;
-                        break;
+                // filter out uninteresting branches
+                for (Iterator<Branch> j = r.getBranches().iterator(); j.hasNext();) {
+                    Branch b = j.next();
+                    boolean keep = false;
+                    for (BranchSpec bspec : gitSCM.getBranches()) {
+                        if (bspec.matches(b.getName())) {
+                            keep = true;
+                            break;
+                        }
+                    }
+
+                    if (!keep) {
+                        verbose(listener, "Ignoring {0} because it doesn''t match branch specifier", b);
+                        j.remove();
                     }
                 }
 
-                if (!keep) {
-                    verbose(listener, "Ignoring {0} because it doesn''t match branch specifier", b);
-                    j.remove();
+                if (r.getBranches().size() == 0) {
+                    verbose(listener, "Ignoring {0} because we don''t care about any of the branches that point to it", r);
+                    i.remove();
                 }
             }
 
-            if (r.getBranches().size() == 0) {
-                verbose(listener, "Ignoring {0} because we don''t care about any of the branches that point to it", r);
-                i.remove();
-            }
+            verbose(listener, "After branch filtering: {0}", revs);
+
+            // 3. We only want 'tip' revisions
+            revs = utils.filterTipBranches(revs);
+            verbose(listener, "After non-tip filtering: {0}", revs);
         }
 
-        verbose(listener, "After branch filtering: {0}", revs);
+        String pattern = gitSCM.getTag();
+        if (! pattern.isEmpty()) {
+            verbose(listener, "Looking for tags that match: {0}", pattern);
+            // 1. Get all tag revisions that exist
+            Collection<Revision> tagRevs = utils.getTags(pattern);
+            if (tagRevs.size() > 0) {
+                verbose(listener, "Starting with matched tags: {0}", tagRevs);
+
+                // 3. we only want 'tip' reviosions (tagged)
+                tagRevs = utils.filterTipBranches(tagRevs);
 
-        // 3. We only want 'tip' revisions
-        revs = utils.filterTipBranches(revs);
-        verbose(listener, "After non-tip filtering: {0}", revs);
+                revs.addAll(tagRevs);
+            }
+        }
 
         // 4. Finally, remove any revisions that have already been built.
         verbose(listener, "Removing what''s already been built: {0}", data.getBuildsByBranchName());
@@ -207,6 +228,7 @@ public class DefaultBuildChooser extends BuildChooser {
                 i.remove();
             }
         }
+
         verbose(listener, "After filtering out what''s already been built: {0}", revs);
 
         // if we're trying to run a build (not an SCM poll) and nothing new
diff --git a/src/main/java/hudson/plugins/git/util/GitUtils.java b/src/main/java/hudson/plugins/git/util/GitUtils.java
index a9da4b2..c678a90 100644
--- a/src/main/java/hudson/plugins/git/util/GitUtils.java
+++ b/src/main/java/hudson/plugins/git/util/GitUtils.java
@@ -50,6 +50,25 @@ public class GitUtils {
         return revisions.values();
     }
 
+    public Collection<Revision> getTags(String pattern) {
+        Map<String, Revision> map = new HashMap<String, Revision>();
+        Set<String> tags = git.getTagNames(pattern);
+
+        for (String tag : tags) {
+            ObjectId sha = git.revParse(tag);
+            String sha1 = sha.getName();
+            Revision rev = map.get(sha1);
+            if (rev == null) {
+                rev = new Revision(sha);
+                map.put(sha1, rev);
+            }
+
+            rev.getBranches().add(new Branch(tag, sha));
+        }
+
+        return map.values();
+    }
+
     /**
      * Return the revision containing the branch name.
      * @param branchName
diff --git a/src/main/resources/hudson/plugins/git/GitSCM/config.jelly b/src/main/resources/hudson/plugins/git/GitSCM/config.jelly
index c4c4123..ebb8ff4 100644
--- a/src/main/resources/hudson/plugins/git/GitSCM/config.jelly
+++ b/src/main/resources/hudson/plugins/git/GitSCM/config.jelly
@@ -60,12 +60,16 @@
           </f:entry>
 
            </table>
-
         </f:repeatable>
-
   </f:entry>
 
   <f:advanced>
+    <f:entry title="Tags to build" field="tag" help="/plugin/git/tag.html">
+      <f:textbox />
+    </f:entry>
+    <f:entry title="Don't build branches" field="skipBranches" help="/plugin/git/skipBranches.html">
+      <f:checkbox/>
+    </f:entry>
     <f:entry title="${%Included Regions}" field="includedRegions" help="/plugin/git/help-includedRegions.html">
         <f:textarea />
     </f:entry>
diff --git a/src/main/webapp/skipBranches.html b/src/main/webapp/skipBranches.html
new file mode 100755
index 0000000..e2d15c3
--- /dev/null
+++ b/src/main/webapp/skipBranches.html
@@ -0,0 +1,5 @@
+<div>
+  Do not build any branch even if there're changes to them.
+  You might want to specify tags (newly appeared) to build.
+  See the 'Tags to build' field above.
+</div>
diff --git a/src/main/webapp/tag.html b/src/main/webapp/tag.html
new file mode 100755
index 0000000..b141c1f
--- /dev/null
+++ b/src/main/webapp/tag.html
@@ -0,0 +1,6 @@
+<div>
+  Specify the tag(s) to build, this allows you to track and build newly pushed tags,
+  a shell glob expression can be used to match multiple tags,
+  and multiple, space delimited patterns can be as well.
+  If left blank, no tags would be checked.
+</div>
diff --git a/src/test/java/hudson/plugins/git/GitSCMTest.java b/src/test/java/hudson/plugins/git/GitSCMTest.java
index 6fe5180..6096f85 100644
--- a/src/test/java/hudson/plugins/git/GitSCMTest.java
+++ b/src/test/java/hudson/plugins/git/GitSCMTest.java
@@ -693,7 +693,7 @@ public class GitSCMTest extends AbstractGitTestCase {
                 createRemoteRepositories(relativeTargetDir),
                 Collections.singletonList(new BranchSpec(branchString)),
                 null,
-                false, Collections.<SubmoduleConfig>emptyList(), false,
+                false, null, false, Collections.<SubmoduleConfig> emptyList(), false,
                 false, new DefaultBuildChooser(), null, null, authorOrCommitter, relativeTargetDir, null,
                 excludedRegions, excludedUsers, localBranch, false, false, false, fastRemotePoll, null, null, false,
                 includedRegions, false, false));
diff --git a/src/test/java/hudson/plugins/git/GitStatusTest.java b/src/test/java/hudson/plugins/git/GitStatusTest.java
index d70f5bd..b149f63 100644
--- a/src/test/java/hudson/plugins/git/GitStatusTest.java
+++ b/src/test/java/hudson/plugins/git/GitStatusTest.java
@@ -127,7 +127,7 @@ public class GitStatusTest extends HudsonTestCase {
                 Collections.singletonList(new UserRemoteConfig(url, null, null)),
                 Collections.singletonList(new BranchSpec(branchString)),
                 null,
-                false, Collections.<SubmoduleConfig>emptyList(), false,
+                false, null, false, Collections.<SubmoduleConfig> emptyList(), false,
                 false, new DefaultBuildChooser(), null, null, false, null,
                 null,
                 null, null, null, false, false, false, false, null, null, false, null, ignoreNotifyCommit, false));
diff --git a/src/test/java/hudson/plugins/git/MultipleSCMTest.java b/src/test/java/hudson/plugins/git/MultipleSCMTest.java
index 9d620fc..0086ea1 100644
--- a/src/test/java/hudson/plugins/git/MultipleSCMTest.java
+++ b/src/test/java/hudson/plugins/git/MultipleSCMTest.java
@@ -80,6 +80,8 @@ public class MultipleSCMTest extends HudsonTestCase {
 				  branch,
 				  null,
 				  false,
+				  null,
+				  false,
 				  Collections.<SubmoduleConfig>emptyList(),
 				  false,
 				  false,
@@ -107,6 +109,8 @@ public class MultipleSCMTest extends HudsonTestCase {
 				  branch,
 				  null,
 				  false,
+				  null,
+				  false,
 				  Collections.<SubmoduleConfig>emptyList(),
 				  false,
 				  false,

Reply via email to