Skip to content
This repository was archived by the owner on Mar 29, 2022. It is now read-only.

Commit 00a6bc7

Browse files
authored
Merge pull request #27 from SD2E/devel
Devel
2 parents f20107b + b52b7f7 commit 00a6bc7

File tree

4 files changed

+433
-11
lines changed

4 files changed

+433
-11
lines changed

docs/03.apps_ci_jenkins.md

Lines changed: 190 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,211 @@ title: Continuous Integration with Jenkins
44
tagline:
55
---
66

7-
The SD2E project uses [Jenkins](http://jenkins.sd2e.org/) for continuous
8-
integration (CI). It is now standard practice to set up CI for all Agave apps.
9-
This will ensure your deployed app is always up to date with the master branch
10-
of your git repo, and it will alert you if jobs are not working.
7+
Jenkins is an automation server for running continuous integration tests. The
8+
SD2E project uses [Jenkins](http://jenkins.sd2e.org/) for continuous integration
9+
(CI) to ensure any changes that have been made to apps do not break their core
10+
functionality. It is now standard practice to set up CI for all Agave apps. This
11+
will ensure your deployed app is always up to date with the master branch of
12+
your git repo, and it will alert you if jobs are not working. This guide will
13+
help you integrate CI testing into any app you would like to deploy, but is not
14+
meant to be a replacement for the
15+
[Jenkins documentation](https://jenkins.io/doc/).
1116

1217

1318

1419
<br>
15-
#### Header 1
20+
#### The Jenkins file
21+
22+
The Jenkins file defines the stages and environment variables of your Jenkins
23+
job. The Jenkins file is written in [Groovy](http://groovy-lang.org/), and
24+
should be located at the top-level directory for your app. For the previous
25+
FastQC app example, the Jenkins file would be in the `~/fastqc-app/` directory.
26+
Here is an example of a Jenkins file for the FastQC app:
1627

1728
```
18-
% code block
29+
#!groovy
30+
31+
pipeline {
32+
agent any
33+
environment {
34+
AGAVE_JOB_TIMEOUT = 900
35+
AGAVE_JOB_GET_DIR = "job_output"
36+
AGAVE_DATA_URI = "agave://data-sd2e-community/sample/sailfish/test/read1.fastq"
37+
CONTAINER_REPO = "fastqc"
38+
CONTAINER_TAG = "test"
39+
AGAVE_CACHE_DIR = "${HOME}/credentials_cache/${JOB_BASE_NAME}"
40+
AGAVE_JSON_PARSER = "jq"
41+
AGAVE_TENANTID = "sd2e"
42+
AGAVE_APISERVER = "https://api.sd2e.org"
43+
AGAVE_USERNAME = "sd2etest"
44+
AGAVE_PASSWORD = credentials('sd2etest-tacc-password')
45+
REGISTRY_USERNAME = "sd2etest"
46+
REGISTRY_PASSWORD = credentials('sd2etest-dockerhub-password')
47+
REGISTRY_ORG = credentials('sd2etest-dockerhub-org')
48+
PATH = "${HOME}/bin:${HOME}/sd2e-cloud-cli/bin:${env.PATH}"
49+
}
50+
stages {
51+
52+
stage('Create Oauth client') {
53+
steps {
54+
sh "make-session-client ${JOB_BASE_NAME} ${JOB_BASE_NAME}-${BUILD_ID}"
55+
}
56+
}
57+
stage('Build container') {
58+
steps {
59+
sh "apps-build-container -O ${REGISTRY_USERNAME} --image ${CONTAINER_REPO} --tag ${CONTAINER_TAG}"
60+
}
61+
}
62+
stage('Deploy to TACC.cloud') {
63+
steps {
64+
sh "apps-deploy -T -O ${REGISTRY_USERNAME} --image ${CONTAINER_REPO} --tag ${CONTAINER_TAG}"
65+
sh "cat deploy-*"
66+
}
67+
}
68+
stage('Run a test job') {
69+
steps {
70+
sh "run-test-job deploy-${AGAVE_USERNAME}-job.json ${AGAVE_JOB_TIMEOUT}"
71+
sh "get-test-job-outputs deploy-${AGAVE_USERNAME}-job.json.jobid ${AGAVE_JOB_GET_DIR}"
72+
}
73+
}
74+
stage('Validate results') {
75+
steps {
76+
sh "python -m pytest tests/validate-job --job-directory ${AGAVE_JOB_GET_DIR}"
77+
}
78+
}
79+
}
80+
post {
81+
always {
82+
sh "delete-session-client ${JOB_BASE_NAME} ${JOB_BASE_NAME}-${BUILD_ID}"
83+
}
84+
success {
85+
deleteDir()
86+
}
87+
}
88+
}
89+
1990
```
2091

92+
Copy and paste the above text into a file called `Jenkinsfile` in the top level
93+
of your `~/fastqc-app/` directory.
94+
95+
The file is divided into three sections: `environment`, `stages`, and `post`.
96+
The `environment` section defines environment variables needed by the Jenkins
97+
server to run the test job. Most of the variables in this section are specific
98+
to the Jenkins server and should be left alone. The `CONTAINER_REPO` and
99+
`CONTAINER_TAG` variables should, collectively, point to a "test" repository
100+
location so that the versioned app is not overwritten. It is good practice to
101+
use the app name (e.g. "`fastqc`") as the `CONTAINER_REPO`, and "`test`" as the
102+
`CONTAINER_TAG`.
103+
104+
You may also need to change `AGAVE_DATA_URI` if your data is located on some
105+
other system or in a different path. Also note that if your test data is located
106+
in your private storage system, `data-tacc-work-username`, you will need to grant
107+
`READ` access to the `sd2etest` user with the following command:
108+
109+
```
110+
systems-roles-addupdate -u sd2etest -r USER data-tacc-work-username
111+
```
112+
113+
The `stages` section of the Jenkins file will also remain largely unchanged. You
114+
will typically need the following sections:
115+
1. `Create Oauth client`
116+
2. `Build container`
117+
3. `Deploy to TACC.cloud`
118+
4. `Run a test job`, and
119+
5. `Validate results`
120+
121+
The first four steps depend on scripts that exist on the Jenkins server, and
122+
should work the same for most apps. The final step must be written by the app
123+
developer, and will be different from app to app. More details on this step are
124+
included in the next section below.
125+
126+
Finally, the `post` section uses one more script on the Jenkins server to clean
127+
up the session and exit the Jenkins test. This section should not change.
21128

22129
<br>
23-
#### Header 2
130+
#### Validating results with pytests
131+
132+
To validate your results, you will need to define pytests that will be run to
133+
verify your app is functional. For the FastQC app, navigate to the tests
134+
directory `~/fastqc-app/tests`, and create a new sub-directory called
135+
`validate-job`:
136+
```
137+
cd ~/fastqc-app/tests
138+
mkdir validate-job
139+
cd validate-job
140+
```
24141

25-
[Example link](https://url/)
142+
Create two pytests in that directory, `conftest.py` and `test_files.py`. You can
143+
copy and paste these two examples directly:
26144

145+
`conftest.py`:
146+
```
147+
import pytest
148+
149+
def pytest_addoption(parser):
150+
parser.addoption("--job-directory", action="store", default="job_output",
151+
help="Directory containing output to evaluate")
152+
153+
@pytest.fixture
154+
def job_directory(request):
155+
return request.config.getoption("--job-directory")
156+
```
157+
158+
`test_files.py`:
159+
```
160+
'''Test for specific files existence in a directory'''
161+
import pytest
162+
import os
163+
164+
'''Parameterize the test with a list of required files'''
165+
@pytest.mark.parametrize("file_list", [
166+
(['reads1_fastqc.html', 'reads1_fastqc.zip'])
167+
])
168+
def test_files(job_directory,file_list):
169+
'''checks job_directory for existence of all contents of file_list'''
170+
# Existence
171+
listdir = os.listdir(job_directory)
172+
assert(len(list(set(listdir) & set(file_list))) == len(file_list)), \
173+
"Missing files"
174+
# Files are readable and not zero length
175+
for f in file_list:
176+
try:
177+
fstat = os.stat(os.path.join(job_directory, f))
178+
assert (fstat.st_size > 0), "Zero length file: {}".format(f)
179+
except Exception:
180+
raise IOError("Couldn't stat {}".format(f))
181+
```
182+
183+
The `conftest.py` adds a `--job-directory` option to pytest, this points to the
184+
location of the output files that are created by running your app. The pytest
185+
`test_files.py` checks if files exist and are greater than 0 bytes.
186+
187+
If you are creating pytests for a different app, you can simply change the output
188+
file names in line 7 of `test_files.py`, to the file names that are output by your app:
189+
190+
```
191+
'''Parameterize the test with a list of required files'''
192+
@pytest.mark.parametrize("file_list", [
193+
(['reads1_fastqc.html', 'reads1_fastqc.zip'])
194+
])
195+
```
196+
In this example, Jenkins is testing for the existence of `reads1_fastqc.html`
197+
and `reads1_fastqc.zip`, which indicate that the FastQC app ran successfully.
27198

28199
<br>
29-
#### Header 3
200+
#### Setting up the Jenkins server
201+
202+
Now that you have created a groovy file and defined pytests, you will need to
203+
add your repo to the Jenkins server and define when it should run tests. We
204+
typically have the server run a test every time a changed is pushed to the
205+
master branch, or anytime a merge request to the master branch is made. It may
206+
also be a good idea to schedule weekly or monthly builds to ensure your app
207+
continues working even when no changes have been made to the source repo.
208+
209+
To set up Jenkins tests for your app, follow the instructions in this video tutorial:
30210

211+
<iframe width="560" height="315" src="https://www.youtube.com/embed/XfhgGZ0CAPw" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
31212

32213

33214
---

docs/03.create_app_04.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ First, create a template job json file:
9595
```
9696
% jobs-template username-fastqc-0.11.7 > job.json
9797
```
98+
If it is not already present, add `"fastq": "agave://data-sd2e-community/sample/sailfish/test/read1.fastq"` to the "inputs" field of the job.json to run a test job.
9899

99100
Here are the expected contents of `job.json`:
100101
```

0 commit comments

Comments
 (0)