Skip to content

Commit c464b21

Browse files
author
Jared Murrell
authored
Update README.md
1 parent 43b1976 commit c464b21

File tree

1 file changed

+172
-5
lines changed

1 file changed

+172
-5
lines changed

hooks/jenkins/jira-workflow/README.md

Lines changed: 172 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ In order to configure our Jenkins instance to receive `webhooks` and process the
2222
- [Credentials Binding](https://plugins.jenkins.io/credentials-binding): Allows credentials to be bound to environment variables for use from miscellaneous build steps.
2323
- [Credentials](https://plugins.jenkins.io/credentials): This plugin allows you to store credentials in Jenkins.
2424

25-
### Getting Jenkins set up
25+
### Setting up the repo
26+
27+
This example pipeline will read the workflow settings from a YAML file in the `.github` directory of the repository where the pipeline lives, _not_ the repository where the code for your project lives. This particular example is a standalone Jenkins pipeline that will be triggered by multiple projects/orgs.
28+
29+
<details><summary>Sample .github/jira-workflow.yml</summary>
30+
2631
```yaml
2732
# The list of Jira projects that we care about
2833
# will be keys under 'project'
@@ -42,11 +47,173 @@ project:
4247
- sample-api
4348
- sample-ui
4449
```
50+
</details>
51+
52+
### Getting Jenkins set up
53+
Before getting started with the pipeline you'll need to setup a few things.
54+
55+
1. Create a `username`/`password` credential which uses your GitHub token
56+
2. Create a `username`/`password` credential which has access to Jira
57+
3. Create a Jira configuration in `Settings`
58+
59+
60+
This demonstration will make use of the [Declarative Pipeline](https://jenkins.io/doc/book/pipeline/syntax) syntax for Jenkins, and not the less structured _advanced scripting_ syntax. So, in getting started we'll note a few things.
61+
62+
First, because we're dynamically generating parallel steps, we'll need to declare our variables _outside_ the pipeline so we don't hit errors when assigning values to them.
63+
64+
```groovy
65+
def settings
66+
def projectInfo
67+
def githubUrl = "https://api.github.com/"
68+
// This is an array we'll use for dynamic parallization
69+
def repos = [:]
70+
```
71+
72+
Once you've declared them, some with values you won't change and some with no values (we'll set them dynamically), let's enable some debug output so we can test our pipeline and adjust it for the things we need. **This step is optional, but will help you extend this example.**
73+
74+
```groovy
75+
node {
76+
echo sh(returnStdout: true, script: 'env')
77+
}
78+
```
79+
80+
Now we can begin the pipeline itself
81+
82+
```groovy
83+
pipeline {
84+
```
85+
86+
#### Setting up the triggers
87+
The *Generic Webhook Trigger* plugin makes use of a token to differentiate pipelines. You can generate a generic token for this pipeline by running `uuidgen` at the command line on a Unix system, or `[Guid]::NewGuid().ToString()` in PowerShell.
88+
89+
##### Bash
90+
```bash
91+
Shenmue:~ primetheus$ uuidgen
92+
6955F09B-EF96-467F-82EB-A35997A0C141
93+
```
94+
##### Powershell
95+
```powershell
96+
PS /Users/primetheus> [Guid]::NewGuid().ToString()
97+
b92bd80d-375d-4d85-8ba5-0c923e482262
98+
```
99+
100+
Once you have generated your unique ID, add the token to the pipeline as a trigger. We'll capture a few variables about the webhook we'll receive as well, and use them later in the pipeline
101+
102+
```groovy
103+
triggers {
104+
GenericTrigger(
105+
genericVariables: [
106+
[key: 'event', value: '$.webhookEvent'],
107+
[key: 'version', value: '$.version'],
108+
[key: 'projectId', value: '$.version.projectId'],
109+
[key: 'name', value: '$.version.name'],
110+
[key: 'description', value: '$.version.description']
111+
],
112+
113+
causeString: 'Triggered on $ref',
114+
// This token is arbitrary, but is used to trigger this pipeline.
115+
// Without a token, ALL pipelines that use the Generic Webhook Trigger
116+
// plugin will trigger
117+
token: 'b92bd80d-375d-4d85-8ba5-0c923e482262',
118+
printContributedVariables: true,
119+
printPostContent: true,
120+
silentResponse: false,
121+
regexpFilterText: '',
122+
regexpFilterExpression: ''
123+
)
124+
}
125+
```
126+
127+
#### Creating our stages
128+
Once we have the triggers created, let's begin creating our [Stages](https://jenkins.io/doc/book/pipeline/syntax/#stages) for the pipeline.
129+
130+
First, open the `Stages` section
45131

46132
```groovy
47-
/*
133+
stages {
134+
```
135+
136+
Then let's read our YAML file from the repo
48137

49-
*/
138+
```groovy
139+
stage('Get our settings') {
140+
steps {
141+
script {
142+
try {
143+
settings = readYaml(file: '.github/jira-workflow.yml')
144+
} catch(err) {
145+
echo "Please create .github/jira-workflow.yml"
146+
throw err
147+
}
148+
}
149+
}
150+
}
151+
```
152+
153+
Once we've read the settings file (or aborted because one doesn't exist), we'll lookup the project info from Jira. The webhook will send us a Project ID, which won't really help us as humans to map, so we'll look this up once we get the payload.
154+
155+
```groovy
156+
stage('Get project info') {
157+
steps {
158+
script {
159+
projectInfo = jiraGetProject(idOrKey: projectId, site: 'Jira')
160+
}
161+
}
162+
}
163+
```
164+
165+
Now we're going to apply the mapping to our repositories, and if we have multiple repos we'll generate parallel steps for each one.
166+
167+
```groovy
168+
stage('Create Release Branches') {
169+
when {
170+
expression { event == 'jira:version_created' }
171+
}
172+
steps {
173+
script {
174+
withCredentials([usernamePassword(credentialsId: '<github_credentials_id>',
175+
passwordVariable: 'githubToken',
176+
usernameVariable: 'githubUser')]) {
177+
settings.project.each { p ->
178+
if (p.name.toString() == projectInfo.data.name.toString()) {
179+
p.repos.each { repo ->
180+
repos[repo] = {
181+
node {
182+
httpRequest(
183+
contentType: 'APPLICATION_JSON',
184+
consoleLogResponseBody: true,
185+
customHeaders: [[maskValue: true, name: 'Authorization', value: "token ${githubToken}"]],
186+
httpMode: 'GET',
187+
outputFile: "${p.org}_${repo}_master_refs.json",
188+
url: "${githubUrl}/repos/${p.org}/${repo}/git/refs/heads/master")
189+
masterRefs = readJSON(file: "${p.org}_${repo}_master_refs.json")
190+
payload = """{
191+
"ref": "refs/heads/${name}",
192+
"sha": "${masterRefs['object']['sha']}"
193+
}"""
194+
httpRequest(
195+
contentType: 'APPLICATION_JSON',
196+
consoleLogResponseBody: true,
197+
customHeaders: [[maskValue: true, name: 'Authorization', value: "token ${githubToken}"]],
198+
httpMode: 'POST',
199+
ignoreSslErrors: false,
200+
requestBody: payload,
201+
responseHandle: 'NONE',
202+
url: "${githubUrl}/repos/${p.org}/${repo}/git/refs")
203+
}
204+
}
205+
}
206+
parallel repos
207+
}
208+
}
209+
}
210+
}
211+
}
212+
```
213+
214+
<details><summary>Sample Pipeline</summary>
215+
216+
```groovy
50217
// Define variables that we'll set values to later on
51218
// We only need to define the vars we'll use across stages
52219
def settings
@@ -56,12 +223,10 @@ def repos = [:]
56223
def githubUrl = "https://github.example.com/api/v3"
57224
//def githubUrl = "https://api.github.com/"
58225
59-
/*
60226
node {
61227
// useful debugging info
62228
echo sh(returnStdout: true, script: 'env')
63229
}
64-
*/
65230
66231
pipeline {
67232
// This can run on any agent... we can lock it down to a
@@ -238,3 +403,5 @@ pipeline {
238403
}
239404
}
240405
```
406+
407+
</details>

0 commit comments

Comments
 (0)