Jenkins Pipelines - GitHub integration service
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
app
configs
src/com
tests
.gitignore
.gitmodules
Dockerfile
LICENSE
Pipfile
Pipfile.lock
README.md
config.yml
docker-compose.yml
pom.xml
triggear.png

README.md

Triggear

Triggear

Triggear is a service that integrates GitHub with Jenkins pipelines. It provides ways of registering Jenkins pipelines for specific events in GitHub and reporting job statuses and details back to GitHub. If you ever thought about running Jenkins jobs without entering Jenkins and remembering about all the jobs that you need to run - Triggear is the guy you were looking for.

It should not be confused with GitHub plugins/service integration with Jenkins as Triggear can do much more for you.

The example usage flow is following:

  1. Jenkins pipeline sends registration request to Triggear, specifying what type of events in some repository should trigger it
  2. Triggear saves registration in Mongo DB
  3. At this point if event specified in registration request occurs in repository, Triggear will automatically trigger job that registered
  4. After build is done, Triggear reports its status to GitHub - usually to commit/PR that triggered the job

Important note

Triggear now have submodule of triggear_pipeline located in src/com/futuresimple. So be sure to clone with submodules:

git clone --recursive git@github.com:futuresimple/triggear.git

For overview of Triggear features please read 6. Workflows section

Table of Contents

  1. Building Triggear
  2. Running tests
  3. Running Triggear as a service
  4. Setup in Jenkins
  5. Setup in GitHub
  6. Workflows
    1. Running jobs on pushes
    2. Running jobs when PR is labeled
    3. Running jobs on PR sync
    4. Running jobs on PR opened
    5. Re-running failed jobs
    6. Setting custom commit statuses
    7. Commenting PRs
    8. Running jobs with tags
    9. Running jobs with PR comments

Feel free to propose any new sections of docs by creating an issue. ###1. Building Triggear To build triggear:

  • manually

You need to have Python 3.6.3 installed with pip. Then you download dependencies with:

pip install -r requirements.txt
  • with docker
docker build --tag triggear .

Note: docker build runs all the unittests by default

  • with docker-compose
docker-compose build

Note: docker-compose build runs all the unittests by default ###2. Running tests

  • manually
PYTHONPATH=[PATH_TO_TRIGGEAR] py.test .
  • with docker

Included in build phase

  • with docker-compose

Included in build phase ###3. Running Triggear as a service To run Triggear you need to have running Jenkins instance and GitHub repository (or many repositories). Then you need to prepare creds.yml file like in example providing:

  • Jenkins URL
  • Jenkins user ID (will be used to trigger builds)
  • Jenkins API token for this user
  • GitHub token for your GitHub bot (needs write access to repositories)
  • Triggear token that will be used to authorize pipeline/github calls

There are couple of ways of running Triggear providing creds.yml

  • manually In this case you need to have running mongo DB on localhost
CREDS_PATH=[PATH_TO_CREDS_YML] CONFIG_PATH=config.yml python3 app/main.py
  • with docker

In this case creds.yml needs to be in <triggear-path>/configs and mongo DB needs to be running on localhost

docker run doc python app/main.py
  • with docker-compose

In this case creds.yml needs to be in <triggear-path>/configs

docker-compose up

This is of course easiest and preferred version of running Triggear not taking into consideration deploy to Kubernetes option. ###4. Setup in Jenkins

Provided that you have running Triggear instance, we need to setup it as a shared library in Jenkins, to let pipelines use registration and status methods. To do it:

  1. Add TRIGGEAR_URL and global Jenkins variable. Its value should be something like `https://TRIGGEAR_URL/"

  2. Add Triggear repository as Shared Library in Jenkins. By doing so pipelines will get access to vars directory and will be able to use register and status update functions

  3. Add secret text with name triggear_token and value of triggear_token field from your creds.yml

Alternatively you can simply add triggear_pipeline as submodule in your shared library src/com to make it available for you pipelines.

Note: Workflows section of docs assumes that you called Triggear shared library as simply as Triggear ###5. Setup in GitHub

Note: this setup needs to be done in all repositories that are supposed to trigger Jenkins jobs

  1. Add GitHub bot (the one that has API token used in creds.yml) to repository collaborators with write permissions

  2. Add webhook to repository:

    • Set Payload URL to https://TRIGGEAR_URL/github
    • Set Content type to application/json
    • Set secret to value of your triggear_token
    • Select individual hook elements: Issue comment, Pull request, Push, Create
  3. Save - at this point test payload should be sent to Triggear and response 200 should be returned to GitHub (can be seen in the bottom of webhook configuration where logs are)

At this point events from GitHub will be sent to Triggear. ###6. Workflows

This section will describe possible user scenarios that Triggear can execute.

Note: for all trigger types Triggear uses value of rerun_time_limit set in ./config.yml. It is meant to throttle builds, not to run some job 30 times in 1 minute just because someone furiously pushes TYPO fixes to your repo. This limit can be modified manually.

i. Running jobs on pushes

Case #1 You want your pipeline to be run on every push to repository X

To solve that you want your pipeline to use Triggear var triggearRegister:

// Assuming you called this shared library "Triggear" in Jenkins
// Ommit this line if you add Triggear as shared library implicitly
@Library(['Triggear']) _

import com.futuresimple.triggear.Request
import com.futuresimple.triggear.TriggearClient
import com.futuresimple.triggear.GitHubRepository
import org.jenkinsci.plugins.workflow.libs.Library

TriggearClient triggear = new TriggearClient(this, new GitHubRepository('triggear'))
triggear.register(Request
        .forPushes()
        .build())

Now you need to run your job once to call register properly. From then on every time someone pushes something to X this job will be triggered.

Case #2 You want your pipeline to be run on every push to repository X and get branch and commit SHA of this push (e.g. you want to run unittests job for every push)

To solve that you want your pipeline to use Triggear method registerForPushes:

// Assuming you called this shared library "Triggear" in Jenkins
// Ommit this line if you add Triggear as shared library implicitly
@Library(['Triggear']) _

import com.futuresimple.triggear.Request
import com.futuresimple.triggear.TriggearClient

TriggearClient triggear = new TriggearClient(this, new GitHubRepository('triggear'))
triggear.register(Request
        .forPushes()
        .addBranchAsParameter()
        .addShaAsParameter()
        .build())

Now you need to run your job once to call register properly. From then on every time someone pushes something to X this job will be triggered with branch and sha parameters. __Remember that your pipeline needs to accept branch and sha parameters, otherwise execution will fail.

In both cases once your job is done, commit status in GitHub will be set based on it's results: Commit status set by Triggear

You can see, that job name is set as status context. When you click on Details link you will be redirected to your job build URL.

Case #3 You want your pipeline to be run on every push to repository X only if something changed in directory 'X/Y' or file 'Z'

To do it, you will need to pass changeRestrictions parameter to registerForPushes method:

// Assuming you called this shared library "Triggear" in Jenkins
// Ommit this line if you add Triggear as shared library implicitly
@Library(['Triggear']) _

import com.futuresimple.triggear.Request
import com.futuresimple.triggear.TriggearClient

TriggearClient triggear = new TriggearClient(this, new GitHubRepository('X'))
triggear.register(Request.forPushes()
        .addChangeRestriction('X/Y')
        .addChangeRestriction('Z')
        .addBranchAsParameter()
        .addShaAsParameter()
        .build())

Please note, that it works in a way, that Triggear checks if any files paths changed/added/removed in current push starts with strings mentioned in changeRestrictions parameter. If so - job will be triggered. If not - nothing happens, message is logged in Triggear.

ii. Running jobs when PR is labeled

Case #1 You want your job to be run, when label Y is set on PR in repository X

To solve that you want your pipeline to use Triggear var triggearRegister:

// Assuming you called this shared library "Triggear" in Jenkins
// Ommit this line if you add Triggear as shared library implicitly
@Library(['Triggear']) _

import com.futuresimple.triggear.Request
import com.futuresimple.triggear.TriggearClient

triggering_label = 'Y'

TriggearClient triggear = new TriggearClient(this, new GitHubRepository('X'))
Request registrationRequest = Request.forLabels()
        .addLabel(triggering_label)
        .build()
triggear.register(registrationRequest)

Now run you pipeline once to make register call. From then on you can set label Y on your PR in X repository it will trigger your pipeline.

Case #2 You want your job to be run, when label Y is set on PR in repository X and get branch and current SHA of this PR (e.g. you want to deploy this branch to some environment)

To solve that you want your pipeline to use Triggear var triggearRegister:

// Assuming you called this shared library "Triggear" in Jenkins
// Ommit this line if you add Triggear as shared library implicitly
@Library(['Triggear']) _

import com.futuresimple.triggear.Request
import com.futuresimple.triggear.TriggearClient

triggering_label = 'Y'

TriggearClient triggear = new TriggearClient(this, new GitHubRepository('X'))
Request registrationRequest = Request.forLabels()
        .addLabel(triggering_label)
        .addBranchAsParameter()
        .addShaAsParameter()
        .build()
triggear.register(registrationRequest)

Now run you pipeline once to make register call. From then on you can set label Y on your PR in X repository it will trigger your pipeline setting branch and sha as parameters. Remember that your job needs to accept such parameters.

In both cases once the job is done it will create or update PR status with your job results:

PR status by Triggear

As you can see job name is again used as context. Details link will redirect users from GitHub to your pipeline build.

iii. Running jobs on PR labeled

Case #1 You want to run job registered for label Y on every push to the PR labeled with Y (e.g. redeploy code on every PR sync)

At first you need to register your job for label Y in repo X:

// Assuming you called this shared library "Triggear" in Jenkins
// Ommit this line if you add Triggear as shared library implicitly
@Library(['Triggear']) _

import com.futuresimple.triggear.Request
import com.futuresimple.triggear.TriggearClient

triggering_label = 'Y'

TriggearClient triggear = new TriggearClient(this, new GitHubRepository('X'))
Request registrationRequest = Request.forLabels()
        .addLabel(triggering_label)
        .build()
triggear.register(registrationRequest)

Then, you'll need a special label in your GitHub repo. It's name should be triggear-label-sync.

Set label Y and triggear-label-sync on one of your PRs.

Triggear run on sync

From then on every push to this PRs branch will trigger your job. Removing triggear-label-sync label will stop this behaviour.

iv. Running jobs on PR opened

Case #1 You want to run job on every PR opened in repo X. Also you would like for it to be rerun if anything is pushed to that PR (so called synchronize events):

At first you need to register your job for PR opened events in repo X:

// Assuming you called this shared library "Triggear" in Jenkins
// Ommit this line if you add Triggear as shared library implicitly
@Library(['Triggear']) _

import com.futuresimple.triggear.Request
import com.futuresimple.triggear.TriggearClient

TriggearClient triggear = new TriggearClient(this, new FSTechRepo('PipelinesExamples'))
triggear.register(Request.forPrOpened()
        .build())

Then, you'll need a special label in your GitHub repo. It's name should be triggear-pr-sync. If that label is present triggear will set in on PR automatically. It will cause all synchronize events to re-run the job.

v. Re-running failed jobs

Case #1 You labeled PR with label Y which triggered some jobs and reported status back to PR. Commit status is set to fail, as your job failed and you know that it is not related to code. You want to rerun it without having to push something to PR.

To do this simply open GitHub PR and write comment:

triggear-label-sync

By doing so following behaviour will start:

  • Triggear will look on your PR and check it's labels
  • Triggear will run the job that failed giving it branch and sha parameters according to what you specified in PR/comment, where sha is latest commit in this PR
  • Once the job is done Triggear will update commit status according to job results

Voila - no pushes/labels caused full rerun of jobs registered with context of specified SHA.

Triggear resync

vi. Setting custom commit statuses

Case #1 Some event (push/labeled) triggered your job and it produced an artifact in Jenkins available at some URL. You want to make this URL visible as one of commits statuses, not to dig through Jenkins UI. Common use case for us at Base is that we want link to unittest report to be visible directly in GitHub without digging through Jenkins build UI

So let's assume that unittests report is stored at $BUILD_URL/report. Your job is registered for pushes and gets SHA from Triggear and you want this report to be visible in GitHub for every commit.

To do so - in your Pipeline, once it's done call triggearStatus var:

import com.futuresimple.triggear.CommitStatus

// this is the case when your job handles sha as param
triggear.addCommitStatus(sha,
    currentBuild.result == "SUCCESS" ? CommitState.SUCCESS : CommitState.FAILURE,
    "Custom status console logs link",
    "Console logs",
    "${BUILD_URL}console"
)

By doing so, every commit will have new custom status once the job is done:

Triggear custom SHA status

Of course this status will only be visible after job is done so there won't be any pending state visible in GH for it at any time.

vii. Commenting PRs

Case #1 You want your job to create a comment on PR/commit with some details that are too long to be presented as commit statuses

So the common case for us at Base is that we won't to present some information about build that are simply too long for statuses in GH (remember: it has content length limit). It can be info about binary size, build time or anything non-status-like.

To do so, use triggearComment var at some point in your pipeline:

// this is the case when your job handles sha as param
triggear.addComment(sha, 'Important build details as commit comment')

By doing so you will see the following results:

Triggear custom commit

Of course one pipeline can create multiple comments.

viii. Running jobs with tags

Case #1 You want your job to run at the time when someone pushes a new tag to repository. At Base we use that to create app's with given tag for reference

To do so you need to register your job for tagged events in repo X:

// Assuming you called this shared library "Triggear" in Jenkins
@Library(['Triggear']) _

import com.futuresimple.triggear.Request
import com.futuresimple.triggear.TriggearClient

TriggearClient triggear = new TriggearClient(this, new FSTechRepo('PipelinesExamples'))
triggear.register(Request.forTags()
        .addTagAsParameter()
        .addBranchAsParameter()
        .addShaAsParameter()
        .build())

By running your job once, you'll enable functionality of running your job every time new tag is pushed to origin. Your job will receive tag name and branch/sha of tagged commit as parameters, so make sure that it accepts them and can handle such params.

ix. Running jobs with PR comments

Case #1 You want to run specific job by writing comment on you PR, not having to enter Jenkins

This is rather uncommon case but maybe you remember your job name and it's parameters, but you don't want to enter Jenkins UI and you want to run it with PR comment?

So in PR type following comment:

Triggear run jobDir/jobName param1=value1 param2=value2

If your job has no params simply remove params specification from that line. Once the job is executed you will get a PR comment with it's status and URL to it.

Triggear run by comment