Writing build files is a case of creating a text file in /var/linci/config
with a specific name file extension. If you are in the linci shell create build myproj
will create a file
/var/linci/config/myproj.build
based on a template, and open it in vim, or whatever editor you have defined in $EDITOR
.
This is what a linci build file looks like
linci> edit myproj description: Example build environment: init: p4-checkout.sh ssl:vbox:1424 //depot/myproj/... clean: rm -rf * targets:: sync: p4-update.sh test: test/compile-bash.sh deb: sudo deploy/builddeb.sh install: sudo deploy/installdeb.sh publish: sudo -E /var/linci/config/lib/publish.sh myproj-*.x86_64.deb
Lines before targets::
must be executed individually e.g.
linci> build myproj clean
All lines after targets::
are executed in order when you call
linci> build myprojN.B. The above build provides incremental builds.
build myproj init
is called once, build myproj
is triggered by commits.
To guarantee repeatable builds, move clean:
and init:
below targets::
There is no difference between build files created manually, and when created with create build ...
.
Linci contains vim syntax highlighting rules.
The file extension should be .build
for build files and .job
for job files, other extensions are ignored.
Build file names are restricted to letters from a to z, numbers 0 to 9 and the dash character as per sanename. You are discouraged from using uppercase letters; the regexp of file names is as follows. ^[a-zA-Z][a-zA-Z0-9-]*$
.
The file name defines the build name, if changed, build history is disassociated.
Lines starting with a hash #
and blank lines are ignored.
Each target line should be a target name and a colon followed by a command. Target names should be all lowercase letters from a-z (^[a-z]+$
).
Warning: Target name syntax restrictions are not validated at time of writing, but may be in a future version.
Whitespace is significant, it is not permitted before the target name or between the target name and the colon, after the colon any whitespace is sent unadjusted to bash, bash ignores leading whitespace.
test: test/compile-bash.sh
You are strongly encouraged to ensure commands simply define a program and its arguments.
For example...
clean: rm -rf *
Multiple line commands are not supported. Technically pipes and redirects and all single line bash features work in the current version. Linci copies each command to a temporary shell script to run it. There is no modification of the command, when the temporary script is created. Future versions might not use bash, limiting commands to a program and its arguments will ensure compatability.
e.g. the following is not recommended...
publish: do-pub --ip $(hostname -i) | tee extra.log
To running the same build with different parameters use environment variables. e.g.
linci> FOO=bar build myproj
Build files should be text files. Line endings should be \n
, use system encoding, i.e. utf-8.
Every target is executed with the workspace as the current directory, ala Make. This ensures targets executed individually behave the same way, when run with other targets.
When writing build files its important to make the distinction between what you can do, and what you should do. Linci build files allow you to run any commands; this gives you enough rope to hang yourself.
Linci's responsibilities are as follows.
Checking out the code has to be linci's responsibility. Scripts to perform checkout update should be stored in /usr/share/linci/bin/vcs
. bzr,git, p4 and svn are provided, vcs scripts can be as simple as
svn co $1 .
It would have been possible to store the rest of the build configuration alongside the source code, other CI tools go this route (e.g. Jenkinsfile). Linci takes the stance that scripts and configuration related to linci's responsibilities are best stored outside the source. This facilitates different builds for the same source, and enables linci to function without modifications to source code.
Linci specific build scripts should be added to /var/linci/config/lib
, which is on the $PATH.
Scripts that define how to compile and package the code should almost always be in the source tree. A Makefile, maven poms, ant scripts etc. is standard practice. Some CI tools have lanugage specific features and plugins, build instructions end up in the CI tool. Linci considers this an anti-pattern. Many Open Source licenses require build scripts to be delivered with the code.
If a target defines a task that is also executed manually by developers, scripts defining how to perform these tasks should be in the source repository. e.g. scripts that define how to run unit tests. Linci targets should always be a one-liner. Its possible to write in a config file...
pre-test: scripts/prepare.sh do-test: scripts/run-unit-tests.shThis is encapsulates how to run tests in linci. The two steps should be combined in the source code.
Presuming that you never publish code straight from your laptop and you follow a CI flow, it may make sense that scripts to handle publishing should be in linci itself if the process is more than a one-liner. A standard process across projects makes sense to keep in /var/linci/config/lib
. /var/linci/config/lib
should be versioned and backed up along with build files. A reporting script that is only relevant in the CI server, e.g. a script that monitors builds and calculates developer of the month, should be in /var/linci/config/lib
. Avoid linci specific code in the source tree.
Its not so obvious where to store deployment scripts. As a CI only concern: scripts could live in /var/linci/config/lib
. Often deployment process version must match the code being deployed: deployment scripts alongside code can be convenient, Open Source code must be delivered with installation scripts. To support matching versions and to iterate on the deployment scripts a separate source repository is sometimes necessary.
Since CI builds often run without human interaction it is important to inform commiters when there are failures or integrate other systems e.g. raising issues for failures.
Hopefully, after reading this, you understand why we did not implement linci with Make.