PipelineLib/Tutorial/TestingHelloNode using parallel execution
Welcome to Testing Hello Node (using parallel execution), an even more advanced PipelineLib tutorial than the previous Testing Hello Node (using multiple stages) tutorial.
Prerequisites
- An understanding of the PipelineLib multi-stage concepts introduced in Testing Hello Node (using multiple stages) as well as the prerequisites mentioned there.
- A very basic understanding of directed acyclic graphs and how they can be expressed as adjacency lists.
Learning objectives
At the end of this tutorial, you will understand:
- How to configure a pipeline's execution graph to run certain stages in parallel and rejoin on subsequent stages.
- How to reference output from previous stages and how stage exports are scoped.
Tutorial
The basic steps to this tutorial will be to:
- Start with the project modifications made in the previous tutorial.
- Define an additional pipeline stage that executes the project's system tests.
- Configure the
testpipeline to execute its stages in parallel. - Submit your change to Gerrit.
- Observe how Jenkins executes the project's multi-stage
testpipeline according to the execution graph. - Clean up.
Starting point
You should start with the changes you made in to the helloworldoid repo in the previous tutorial.
dev@laptop:~$ cd blubber-doc/example/helloworldoid
Define a stage for running system tests
Remember that systemtest script we saw in the project's package.json? No? Fine.
dev@laptop:helloworldoid$ grep -A 4 scripts package.json
"scripts": {
"lint": "eslint --ignore-path .gitignore .",
"systemtest": "mocha ./test/system.js",
"test": "mocha ./test/unit.js"
},
Yes, that one. OK. Let's add a stage that runs it using the generic script image variant from before.
dev@laptop:helloworldoid$ vim .pipeline/config.yaml # or ed; j/k
pipelines:
test:
blubberfile: blubber.yaml
stages:
- name: build
build: script
- name: test
run:
image: '${build.imageID}'
arguments: [test]
- name: lint
run:
image: '${build.imageID}'
arguments: [lint]
- name: systemtest
run:
image: '${build.imageID}'
arguments: [systemtest]
Line by line, we are:
- Defining a new stage in our pipeline called
systemtest. - Specifying that this stage should run the image built in the
buildstage (script) and pass it the argumentsystemtest.
Simple enough and very similar to what we did last time. However, now we have four distinct stages, and running them all serially seems like a waste of time. Let's see if we can at least run the test and lint stages in parallel before proceeding to systemtest.
Define a custom execution graph
By default, a pipeline's stages are executed serially in the same order in which they were defined. In this case, the default execution graph is currently representing something like this:
build
⇘
test
⇘
lint
⇘
systemtest
But let's change that. Let's instead execute test and lint in parallel after our image is built, and perform the more expensive systemtest stage only after all the other stages finish. In other words, let's make the execution graph look like this:
build ⇙ ⇘ test lint ⇘ ⇙ systemtest
To accomplish that, we need to define a custom execution entry under the test pipeline.
dev@laptop:helloworldoid$ vim .pipeline/config.yaml
pipelines:
test:
blubberfile: blubber.yaml
stages:
- name: build
build: script
- name: test
run:
image: '${build.imageID}'
arguments: [test]
- name: lint
run:
image: '${build.imageID}'
arguments: [lint]
- name: systemtest
run:
image: '${build.imageID}'
arguments: [systemtest]
execution:
- [build, test, systemtest]
- [build, lint, systemtest]
Line by line, we are:
- Providing a custom
executiongraph for ourtestpipeline. - Declaring a branch of execution that says stage
testshould be executed after stagebuildand before stagesystemtest. - Declaring a branch of execution that says stage
lintshould also be executed after stagebuildand before stagesystemtest.
Submit our change and watch our pipeline execute
Now that we have a .pipeline/config.yaml that will tell our CI system to execute our stages in a cool directed-graph order, let's push our changes to Gerrit and watch Jenkins execute it.
dev@laptop:helloworldoid$ git add .pipeline/{blubber,config}.yaml
dev@laptop:helloworldoid$ git commit -m 'tutorial2: Configure CI to execute using a DAG'
dev@laptop:helloworldoid$ git push origin HEAD:refs/for/master
Head over to the helloworldoid-pipeline-test job to see its progress!
Clean up
Help us to keep Gerrit tidy by abandoning your change, and reset your local branch to origin/master.