46

It would be nice for our Jenkins CI server to automatically detect, deploy and build tags as they are created in our Github repository.

Is this possible?

Ricardo Gladwell
  • 3,770
  • 4
  • 38
  • 59
  • 2
    The practice usually followed is to create a tag after a successful build and deploy. Any reason why you want to build tags rather than master? – leenasn Oct 18 '11 at 16:50
  • 1
    I'm using Tycho which doesn't have support for mvn:release yet, but doing it your way works as well. – Ricardo Gladwell Oct 19 '11 at 13:09

5 Answers5

36

With the following configuration, you can make a job build all tags:

  1. Make the job fetch tags as if they were branches: Click on the Advanced button below the repository URL and enter the Refspec +refs/tags/*:refs/remotes/origin/tags/*
  2. Have it build all tag "branches" with the Branch Specifier */tags/*
  3. Enable SCM polling, so that the job detects new tags.

This approach has one drawback: The job will build all tags and not just newly added tags. So after you have created the job, it will be triggered once for every existing tag. So you probably want to have the job do nothing at first, then wait until all existing tags have been processed, and only then configure the build steps you want to be done for every new tag.

Since tags don't change in git, the job will then only be triggered once for every new tag.

oberlies
  • 11,503
  • 4
  • 63
  • 110
  • Have you actually gotten this working? I'm attempting to enable, but no success. Tag is not on master branch. In Jenkins Git plugin, define Name as origin and refspec as '+refs/tags/*:refs/remotes/origin/tags/*'. Define branches to build as '*/tags/*', but keep getting told "No candidate revisions ERROR: Couldn't find any revision to build. Verify the repository and branch configuration for this job. Finished: FAILURE". Any thoughts? Do I need to identify branches in some manner too? – Mikezx6r Oct 30 '13 at 13:33
  • Apologies, I certainly started that last comment out poorly. I truly do appreciate your assistance here. It appears either I didn't type it correctly, or stackoverflow stripped out the '*', but I'll re-confirm, and re-try. Thank you again for this way of 'fooling' git into treating tags as a branch. – Mikezx6r Nov 01 '13 at 11:57
  • Unfortunately, as mentioned [here](https://issues.jenkins-ci.org/browse/JENKINS-14917?focusedCommentId=199178&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-199178), this way of triggering builds on new tags seems to be currently broken. – sschuberth Jul 18 '14 at 10:07
  • My problem is that the build is randomly triggered every so often without any changes to the repository. Something's off :/ – meza Jan 28 '15 at 14:20
  • Seems this is still not working. It build for me, on every poll. – Jolta Apr 07 '15 at 13:13
  • I just double-checked, and the solution works flawlessly for us. We are using Jenkins 1.565.1, Git Plugin 2.2.4, and Git Client Plugin 1.15.0. And we are using tags only for releases, i.e. there is at most one tag per commit and we don't move tags around. – oberlies Apr 16 '15 at 09:06
  • ```This approach has one drawback``` another one - you can't build tag which will point to a previous hash than head. For e.g. you have the following history: ```550313e(commit1) -> 22ce31f(commit2) -> e31e663(commit3, head)``` Then you add a new tag: tag1 -> e31e663. The job will be triggered, BUT after this job you won't be able to trigger jobs for commits ```550313e/22ce31f``` – ALex_hha Sep 07 '16 at 09:46
18

To overcome the drawback of @oberlies' answer that all tags will be built I'm using a special trigger build instead. The trigger build uses the same git repository and branch as the main build and the following (post) build steps.

Build -> Execute shell:

# Get the most recent release tag.
PATTERN="release-tag-[0-9][0-9]-[0-9][0-9][0-9][0-9]"
TAG=$(git log --tags=$PATTERN --no-walk --pretty="format:%d" | grep -m 1 -o $PATTERN)

# Due to a Jenkins limitation (https://issues.jenkins-ci.org/browse/JENKINS-8952)
# when passing environment variables we have to write the tag to a file and
# inject it later again.
mv release.properties release-old.properties || true
echo "TAG = $TAG" > release.properties

# Fail the build if the most recent release tag did not change.
! diff release.properties release-old.properties

Build -> Inject environment variables:

Properties File Path: release.properties

Post-build Actions -> : Trigger parameterized build on other projects

Projects to build: <your main project>
Trigger when build is: Stable
Parameters: TAG=$TAG

Finally, in your main build, tick "This build is parameterized" with the following string parameter

Name: TAG
Default Value: <your release branch>

And in the "Source Code management" section use "$TAG" in the "Branches to build" field.

sschuberth
  • 28,386
  • 6
  • 101
  • 146
3

You can install a post-receive hook, which checks if a tag was commited, and creates a build in jenkins.

The hook can look something like this [*]:

#!/usr/bin/env python

import sys
from subprocess import Popen, PIPE, check_call

def call_git(command, args):
    return Popen(['git', command] + args, stdout=PIPE).communicate()[0]
JENKINS = 'http://localhost:8002/jenkins'
TOKEN = 'asdf8saffwedssdf'
jobname = 'project-tag'

def handle_ref(old, new, ref):
     print 'handle_ref(%s, %s, %s)' % (old, new, ref)
     if not ref.startswith('refs/tags/'):
          return
     url = '%s/job/%s/buildWithParameters?token=%s&branch=%s' % (
        JENKINS, jobname, TOKEN, new)
     print "queueing jenkins job " + jobname + " for " + new
     check_call(["wget", "-O/dev/null", "--quiet", url])
if __name__ == '__main__':
    for line in sys.stdin:
        handle_ref(*line.split())

[*] note: this is just a quick conversion from a slightly different script, so it's quite probable that there are some small bugs here. This is mostly to show the idea.

On the jenkins side, you need to configure a parametrized job. The only parameter is 'branch'.

  1. Check 'this build is parametrized' and add the parameter
  2. In 'source code management -> branches to build' put '$branch'

This gives a fairly secure and robust way to build. To test, run a build through the web interface, it'll ask for the value of the parameter.

zbyszek
  • 5,105
  • 1
  • 27
  • 22
1

In the world of modern (?) multi-branch pipelines, building tags works as follows.

  1. Add the "behaviour" to discover tags:
    enter image description here
  2. Use plugin Basic Branch Build Strategies to add a "build strategy" for tags: enter image description here Don't forget to add a build strategy for branches as well; the plugin disables the defaults completely!
Raphael
  • 9,779
  • 5
  • 63
  • 94
  • 1
    I have this exact configuration. But Jenkins only creates a new project for tags in the tag section and does not build those. Any idea on what could be missing? FWIW, I also have `fetch tags` checked in advanced clone behavior in Project Behavior tab. – Roseau Feb 15 '21 at 08:19
  • @RheaS It's been a while and I don't have a Jenkins installation handy right now. I think your best shot it to post a new question; good luck! – Raphael Feb 15 '21 at 21:22
  • @RheaS were you able to figure anything out for that issue? i am experiencing the same thing – William Reed Apr 14 '21 at 13:16
  • 1
    @WilliamReed I later found that this was the case with only few repositories in the org and not all. Could not find the root cause for why was it not working for some repositories. My config was exactly same as described in this answer. – Roseau May 17 '21 at 11:00
-3

You can use the option "Git Publisher" which comes as part of the Git Plugin to create a tag after a successful build/deploy.

leenasn
  • 1,466
  • 10
  • 16