Skip to content

Commit 43b1976

Browse files
author
Jared Murrell
authored
Create README.md
1 parent 7bf6c83 commit 43b1976

File tree

1 file changed

+240
-0
lines changed

1 file changed

+240
-0
lines changed

hooks/jenkins/jira-workflow/README.md

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
## Getting started
2+
This example will take action based on webhooks received from Jira. The actions demonstrated here are:
3+
4+
1. Create a `branch` in GitHub when a `Version` is _created_ in Jira
5+
2. Create a `release` in GitHub when a `Version` is _released_ in Jira
6+
7+
Projects in Jira are mapped to repositories in GitHub based on a `.github/jira-workflow.yml` file and can be altered to suit your needs
8+
9+
### Plugins
10+
In order to configure our Jenkins instance to receive `webhooks` and process them for this example, while storing our [Pipeline as Code](https://jenkins.io/solutions/pipeline), we will need to install a few plugins.
11+
12+
- [Pipeline](https://plugins.jenkins.io/workflow-aggregator): This plugin allows us to store our `Jenkins` _jobs_ as code, and moves away from the common understanding of Jenkins `builds` to an `Agile` and `DevOps` model
13+
- [Pipeline: Declarative](https://plugins.jenkins.io/pipeline-model-definition): Provides the ability to write _declarative pipelines_ and add `Parallel Steps`, `Wait Conditions` and more
14+
- [Pipeline: Basic Steps](https://plugins.jenkins.io/workflow-basic-steps): Provides many of the most commonly used classes and functions used in _Pipelines_
15+
- [Pipeline: Job](https://plugins.jenkins.io/workflow-job): Allows us to define `Triggers` within our _Pipeline_
16+
- [Pipeline: Utility Steps](https://plugins.jenkins.io/pipeline-utility-steps): Provides us with the ability to read config files, zip archives and files on the filesystem
17+
- [Build with Parameters](https://plugins.jenkins.io/build-with-parameters): Allows us to provide parameters to our pipeline
18+
- [Generic Webhook Trigger](https://plugins.jenkins.io/generic-webhook-trigger): This plugin allows any webhook to trigger a build in Jenkins with variables contributed from the JSON/XML. We'll use this plugin instead of a _GitHub specific_ plugin because this one allows us to trigger on _any_ webhook, not just `pull requests` and `commits`
19+
- [HTTP Request](https://plugins.jenkins.io/http_request): This plugin allows us to send HTTP requests (`POST`,`GET`,`PUT`,`DELETE`) with parameters to a URL
20+
- [Jira Pipeline Steps](https://plugins.jenkins.io/jira-steps): Allows using Jira steps within a _Jenkinsfile_
21+
- [Jira](https://plugins.jenkins.io/jira): Enables integration with Jira
22+
- [Credentials Binding](https://plugins.jenkins.io/credentials-binding): Allows credentials to be bound to environment variables for use from miscellaneous build steps.
23+
- [Credentials](https://plugins.jenkins.io/credentials): This plugin allows you to store credentials in Jenkins.
24+
25+
### Getting Jenkins set up
26+
```yaml
27+
# The list of Jira projects that we care about
28+
# will be keys under 'project'
29+
project:
30+
# The name of the project in Jira, not the key.
31+
# if we want the key we can certainly update the
32+
# pipeline to use that instead
33+
- name: GitHub-Demo
34+
# The name of the org in GitHub that will be mapped
35+
# to this project. We cannot use a list here, since
36+
# we will use a list for the repos
37+
org: GitHub-Demo
38+
# A list of repositories that are tied to this project.
39+
# Each repo here will get a branch matching the version
40+
repos:
41+
- sample-core
42+
- sample-api
43+
- sample-ui
44+
```
45+
46+
```groovy
47+
/*
48+
49+
*/
50+
// Define variables that we'll set values to later on
51+
// We only need to define the vars we'll use across stages
52+
def settings
53+
def projectInfo
54+
// This is an array we'll use for dynamic parallization
55+
def repos = [:]
56+
def githubUrl = "https://github.example.com/api/v3"
57+
//def githubUrl = "https://api.github.com/"
58+
59+
/*
60+
node {
61+
// useful debugging info
62+
echo sh(returnStdout: true, script: 'env')
63+
}
64+
*/
65+
66+
pipeline {
67+
// This can run on any agent... we can lock it down to a
68+
// particular node if we have multiple nodes, but we won't here
69+
agent any
70+
triggers {
71+
GenericTrigger(
72+
genericVariables: [
73+
[key: 'event', value: '$.webhookEvent'],
74+
[key: 'version', value: '$.version'],
75+
[key: 'projectId', value: '$.version.projectId'],
76+
[key: 'name', value: '$.version.name'],
77+
[key: 'description', value: '$.version.description']
78+
],
79+
80+
causeString: 'Triggered on $ref',
81+
// This token is arbitrary, but is used to trigger this pipeline.
82+
// Without a token, ALL pipelines that use the Generic Webhook Trigger
83+
// plugin will trigger
84+
token: '6BE4BF6E-A319-40A8-8FE9-D82AE08ABD03',
85+
printContributedVariables: true,
86+
printPostContent: true,
87+
silentResponse: false,
88+
regexpFilterText: '',
89+
regexpFilterExpression: ''
90+
)
91+
}
92+
stages {
93+
// We'll read our settings in this step
94+
stage('Get our settings') {
95+
steps {
96+
script {
97+
try {
98+
settings = readYaml(file: '.github/jira-workflow.yml')
99+
//sh("echo ${settings.project}")
100+
} catch(err) {
101+
echo "Please create .github/jira-workflow.yml"
102+
throw err
103+
//currentBuild.result = 'ABORTED'
104+
//return
105+
//currentBuild.rawBuild.result = Result.ABORTED //This method requires in-process script approval, but is nicer than what's running currently
106+
}
107+
}
108+
}
109+
}
110+
stage('Get project info') {
111+
steps {
112+
script {
113+
// echo projectId
114+
projectInfo = jiraGetProject(idOrKey: projectId, site: 'Jira')
115+
// echo projectInfo.data.name.toString()
116+
}
117+
}
118+
}
119+
stage('Create Release Branches') {
120+
when {
121+
// Let's only run this stage when we have a 'version created' event
122+
expression { event == 'jira:version_created' }
123+
}
124+
steps {
125+
script {
126+
// Specify our credentials to use for the steps
127+
withCredentials([usernamePassword(credentialsId: '<github_credentials_id>',
128+
passwordVariable: 'githubToken',
129+
usernameVariable: 'githubUser')]) {
130+
// Loop through our list of Projects in Jira, which will map to Orgs in GitHub.
131+
// We're assigning it 'p' since 'project' is assigned as part of the YAML structure
132+
settings.project.each { p ->
133+
// Only apply this release to the proper Org
134+
if (p.name.toString() == projectInfo.data.name.toString()) {
135+
// Loop through each repo in the Org
136+
p.repos.each { repo ->
137+
// Create an array that we will use to dynamically parallelize the
138+
// actions with.
139+
repos[repo] = {
140+
node {
141+
// Get the master refs to create the branches from
142+
httpRequest(
143+
contentType: 'APPLICATION_JSON',
144+
consoleLogResponseBody: true,
145+
customHeaders: [[maskValue: true, name: 'Authorization', value: "token ${githubToken}"]],
146+
httpMode: 'GET',
147+
outputFile: "${p.org}_${repo}_master_refs.json",
148+
url: "${githubUrl}/repos/${p.org}/${repo}/git/refs/heads/master")
149+
// Create a variable with the values from the GET response
150+
masterRefs = readJSON(file: "${p.org}_${repo}_master_refs.json")
151+
// Define the payload for the GitHub API call
152+
payload = """{
153+
"ref": "refs/heads/${name}",
154+
"sha": "${masterRefs['object']['sha']}"
155+
}"""
156+
// Create the new branches
157+
httpRequest(
158+
contentType: 'APPLICATION_JSON',
159+
consoleLogResponseBody: true,
160+
customHeaders: [[maskValue: true, name: 'Authorization', value: "token ${githubToken}"]],
161+
httpMode: 'POST',
162+
ignoreSslErrors: false,
163+
requestBody: payload,
164+
responseHandle: 'NONE',
165+
url: "${githubUrl}/repos/${p.org}/${repo}/git/refs")
166+
}
167+
}
168+
}
169+
// Execute the API calls simultaneously for each repo in the Org
170+
parallel repos
171+
}
172+
}
173+
}
174+
}
175+
}
176+
}
177+
stage('Create Release') {
178+
when {
179+
// Let's only run this stage when we have a 'version created' event
180+
expression { event == 'jira:version_released' }
181+
}
182+
steps {
183+
script {
184+
// Specify our credentials to use for the steps
185+
withCredentials([usernamePassword(credentialsId: '<github_credentials_id>',
186+
passwordVariable: 'githubToken',
187+
usernameVariable: 'githubUser')]) {
188+
// Loop through our list of Projects in Jira, which will map to Orgs in GitHub.
189+
// We're assigning it 'p' since 'project' is assigned as part of the YAML structure
190+
settings.project.each { p ->
191+
// Only apply this release to the proper Org
192+
if (p.name.toString() == projectInfo.data.name.toString()) {
193+
// Loop through each repo in the Org
194+
p.repos.each { repo ->
195+
// Create an array that we will use to dynamically parallelize the actions with.
196+
repos[repo] = {
197+
node {
198+
// Get the current releases
199+
httpRequest(
200+
contentType: 'APPLICATION_JSON',
201+
consoleLogResponseBody: true,
202+
customHeaders: [[maskValue: true, name: 'Authorization', value: "token ${githubToken}"]],
203+
httpMode: 'GET',
204+
outputFile: "${p.org}_${repo}_releases.json",
205+
url: "${githubUrl}/repos/${p.org}/${repo}/releases")
206+
// Create a variable with the values from the GET response
207+
releases = readJSON(file: "${p.org}_${repo}_releases.json")
208+
// Define the payload for the GitHub API call
209+
def payload = """{
210+
"tag_name": "${name}",
211+
"target_commitish": "${name}",
212+
"name": "${name}",
213+
"body": "${description}",
214+
"draft": false,
215+
"prerelease": false
216+
}"""
217+
// Create the new release
218+
httpRequest(
219+
contentType: 'APPLICATION_JSON',
220+
consoleLogResponseBody: true,
221+
customHeaders: [[maskValue: true, name: 'Authorization', value: "token ${githubToken}"]],
222+
httpMode: 'POST',
223+
ignoreSslErrors: false,
224+
requestBody: payload,
225+
responseHandle: 'NONE',
226+
url: "${githubUrl}/repos/${p.org}/${repo}/releases")
227+
}
228+
}
229+
}
230+
// Execute the API calls simultaneously for each repo in the Org
231+
parallel repos
232+
}
233+
}
234+
}
235+
}
236+
}
237+
}
238+
}
239+
}
240+
```

0 commit comments

Comments
 (0)