It's common practice to perform an extensive testing on a Pull Request before the code is being deployed to production systems.
So far we've seen how pipeline can be built and run around a single Git branch (e.g. main
or dev
). Now we would like to create a new pipeline which will be triggered on every PR that is created in GitHub.
For that we will utilize Jenkins multi-branch pipeline.
- From the main Jenkins dashboard page, choose New Item, and create a Multibranch Pipeline named
pull-request-testing
. - In the GitHub source section, under Discover branches configure this pipeline to discover PRs only!
- This pipeline should be defined by a Jenkinsfile called
PullRequest.Jenkinsfile
. - In
main
branch, create thePullRequest.Jenkinsfile
as follows:
pipeline {
agent any
stages {
stage('Unittest') {
steps {
echo "testing"
}
}
stage('Lint') {
steps {
echo "linting"
}
}
stage('Functional test') {
steps {
echo "testing"
}
}
}
}
- Commit the Jenkinsfile and push it.
From now one, we would like to protect branch main
from being merged by non-tested and reviewed branch.
- From GitHub main repo page, go to Settings, then Branches.
- Add rule for the
main
branch as follows:- Check Require a pull request before merging.
- Check Require status checks to pass before merging and search the
continuous-integration/jenkins/branch
check done by Jenkins. - Save the protection rule.
Your main
branch is now protected and no code can be merged to it unless the PR is reviewed by other team member and passed all automatic tests done by Jenkins.
Let's implement the pull request testing pipeline.
- From branch
main
create a new branch calledsample_feature
which simulates some new feature that a developer is going to develop. Push the branch to remote. - In your app GitHub page, create a Pull Request from
sample_feature
intomain
. - Watch the triggered pipeline in Jenkins.
Unittest is a testing framework in Python that allows developers to write and run small, isolated tests for individual units of code to ensure their correctness and detect any potential bugs or issues.
-
In the
projects/app_development_I/yolo5
directory, you are given directory calledtests
. This is a common name for the directory containing all unittests files. The directory contains a file calledtest_allowed_file.py
which implements unittest for theallowed_file
function inutils.py
file. -
Run the unittest locally (you may need to install the requirements:
pip install -r requirements.txt
), check that all tests are passed:
python3 -m pytest --junitxml results.xml tests
-
Integrate the unittesting in
PullRequest.Jenkinsfile
under the Unittest stage. -
You can add the following
post
step to display the tests results in the readable form:
post {
always {
junit allowEmptyResults: true, testResults: 'results.xml'
}
}
- Make sure Jenkins is blocking the PR to be merged when unittest is failed!
Pylint is a static code analyser for Python. Pylint analyses your code without actually running it. It checks for errors, enforces a coding standard, and can make suggestions about how the code could be refactored.
- Install
pylint
locally if needed. - Generate a default template for
.pylintrc
file which is a configuration file defines how Pylint should behave
pylint --generate-rcfile > .pylintrc
- Lint your code locally by:
python3 -m pylint *.py
How many warnings do you get? If you need to ignore some unuseful warning, add it to disable
list in [MESSAGES CONTROL]
section in your .pylintrc
file.
- Integrate the unittesting in
PullRequest.Jenkinsfile
under the Lint stage. - (Bonus) Add Pylint reports to Jenkins pipeline dashboard:
- Install the Warnings Next Generation Plugin.
- Change your linting stage to be something like (make sure you understand this change):
steps { sh 'python3 -m pylint -f parseable --reports=no *.py > pylint.log' } post { always { sh 'cat pylint.log' recordIssues ( enabledForFailure: true, aggregatingResults: true, tools: [pyLint(name: 'Pylint', pattern: '**/pylint.log')] ) } }
Use parallel
directive to run the test stages in parallel, while failing the whole build when one of the stages is failed.