intent, such as SUBMIT, which changes the ledger,
or EVALUATE, which only reads it. A Context must
always be passed in addition to any function param-
eters. createProduct() is a simple function that takes
the Context, and name, category, content to prepare
a Product with generated UUID for productID. Addi-
tionally, it checks if it does not already exist. Follow-
ing that, it serializes the Product class with Genson
and, thanks to Context, obtains the ChaincodeStub to
inserts a new state into it.
4.3 CI/CD Pipelines
The next step is to set up CI/CD pipelines using Git-
Lab CI/CD services for previously created fully func-
tional blockchain for one of the main puroposes of our
system, so the user opinion storage. GitLab CI/CD is
a built-in feature of GitLab that allows the automated
testing, building, and deployment of code changes.
The pipelines is created from parent and children
pipelines, this means they contain five .gitlab-ci.yml
files, one for each chaincode and one core pipeline.
These files define all stages and jobs, and enforce au-
tomation and performance rules.
All child pipelines dedicated to integrating chain-
codes look in the same way as shown in figure 5. Each
child pipeline contains two stages and two jobs. The
first stage is the build stage with a dedicated job. It
simply compiles the code with Gradle and for opti-
mization purposes, the results get cached. This job
must succeed in order for the next job to start. The
next stage and job is more complex and offers three
benefits: code listing, unit testing and scenario test-
ing. Everything is managed by a Gradle tool, JU-
nit, Checkstyle, and Cucumber plugins. Before the
script starts, it sets up the Gradle user home direc-
tory and applies it to the current CLI. This step is
required for all Gradle-related jobs inside a GitLab
CI. When it is done, the core script begin with gradle
check command, which implies three functions. First
one lints the codebase of chaincode according to the
given checkstyle file. Next one proceeds with veri-
fying the unit tests, and last one triggers all scenario
tests with Cucumber runner. It is worth noting that if
Gradle check command fails on any step it will not
proceed further. Therefore, it might be a good idea
to split the Gradle tasks into three separate jobs. This
will also decrease the duration time of a pipeline be-
cause these jobs could run simultaneously. However,
this GitLab pipeline setup uses a single runner and
running linting process automatically runs any other
test cases, therefore the results would not be better for
this exact setup. When children pipelines were exe-
cuted for every chaincode that was changed and if all
succeed, the parent pipeline continues with the next
stages.
The main pipeline .gitlab-ci.yml file is in project
root folder, next to fablo-config.json. The main
pipeline (Fig. 5) must include triggers for child
pipelines, build and configure a network for tests, and
deliver containers to storage. As a result, the work-
flow has three stages in the following order: trig-
gers, test and deliver. The first stage includes a job
for each chaincode – it has defined conditions known
as rules or only that, when met, the main pipeline
will include and execute the specified child pipeline.
The only defined rule for this job is changes. As a
result, it only occurs when GitLab detects a differ-
ence between this and the previous commit, in order
to save time and resources. After all child pipelines
have passed and the triggers stage has finished, it is
time for the next step in the workflow, which is the
test stage. It involves creating the actual network, in-
stalling the previously tested chaincodes and testing
it against a real network. The job requires an im-
age with docker and docker-compose already config-
ured. Nonetheless, the environment requires the defi-
nition of a few variables that will be selected automat-
ically by Docker and utilized during execution. This
includes DOCKER HOST, DOCKER DRIVER, and
DOCKER TLS CERTDIR. DOCKER HOST is an
environment variable that is used to specify the URL
of Docker daemon. It ensures that Docker client will
automatically connect correctly to running Docker
daemon. DOCKER DRIVER configuration option is
used to specify the storage driver that should be used
by Docker. The overlay2 storage driver is a mod-
ern and recommended storage driver that provides
better performance and stability in comparison to its
predecessors. DOCKER TLS CERTDIR is an envi-
ronment variable that is used to specify the directory
where the Transport Layer Security (TLS) certificates
for Docker daemon are located. When it is set to an
empty string, it also requires turning the TLS com-
munication off. It can be achieved by invoking the
command –tls = false on creation.
Before the script can execute, it must download
some basic dependencies, because the image comes
as small as possible. Alpine Linux has its own pack-
age manager, apk, for installing and managing soft-
ware packages. The main script pulls the Fablo tool
and starts the network using fablo-config.json. The
chaincodes are already defined in the file and is in-
stalled after the network is up and running. Next,
the job pulls another tool, which is the Api-test bash
script and runs all test cases against Fablo REST API.
To implement CD, the project first established a
strong testing infrastructure and Continuous Integra-
ICSOFT 2023 - 18th International Conference on Software Technologies
586