For the last few years, I tried to integrate BaseX into a CI/CD workflow
(the one used by gitlab [1]).
My understanding of CI/CD explicitly includes automated tests so I can
be as sure as possible I don’t break anything when doing further
development.
I pondered with using BaseX’ built in unit test framework [2], which I
think is very good in many situations, but I was not really satisfied
when it comes to checking RestXQ endpoints. The way it needs to be
launched [3] is a bit awkward to me as a test for RestXQ and I could not
come up with an easy way to automate this.
When serving HTML based apps that interact with BaseX as a data store
there is also no well-established way to do end-to-end testing, that is
to for example programmatically click a button and capture the result,
but they do exist for Node.js [4].
Unfortunately my projects almost never allow for more than a few tests
due to budget and time constraints. So, I want to make them count. My
experience is that such end-to-end tests are what can test the most code
in JS and RestXQ with the least amount of test code. Admittedly, if you
get an error, you go hunting for the real problem.
Similarly, I use Node.js to do kind of an outside integration test for
RESTful APIs. I have to admit I have a personal aversion against using
many programming languages throughout my day. I try to use two or
maximum three on any given day. But there are also other reasons:
* For one JS and TypeScript are very likely consumers of a RESTful API.
It is hard to escape JS or TypeScript today.
* Other people are probably much better at their preferred programming
languages but I hope almost anyone has a passive knowledge of JS. If
this is true, then tests written in JS are good examples and candidates
for translation into another languages test framework if necessary.
The (now old) gitlab CI/CD workflow uses herokuish [5] and Heroku
buildpacks [6] (but not the actual commercial Heroku service) to achieve
two things:
* Bundle an application written in some programming language in a
container without the author of the program needing to have any
knowledge of containers, Dockerfiles etc. The author just needs to know
the dependency tools of their programming language well
* Having a well-defined way to start up tests and proceed with
deployment if the tests succeed or stopping right there.
The second point is something that the currently used process for
building containers in gitlab, Cloud Native Buildpacks [7], still cannot
do because they are only in the planning phase of a container interface
for launching tests.
As I wanted to bundle everything needed to run and test an application
running in the RestXQ environment provided by BaseX for the GitLab CI/CD
process, I created a Heroku buildpack for BaseX based on the one for
Node.js [8].
As I extended the Node.js buildpack everything is still controlled from
package.json in principle. The “engines” definitions are amended to also
include a version of BaseX and a version of Saxon to use [9]. Due to
inheriting from the Node.js buildpack, JS dependencies for a HTML page
that acts as the user interface for some RestXQ endpoints can be easily
specified, a “build” script can build some sources written to use the
Vue.js, React or angular frameworks. Or maybe only the dependencies of a
more elaborate test suite need to be fetched like mocha, chai etc. [10]
Also, there is a shell script “deployment/initial.sh” [11] is run so XML
data can be fetched and loaded into BaseX at the time the container is
built. For example, I use it to pull data from another git repository
and execute a BaseX bxs script [12] to load the data, generate indices
etc. A “test” script then needs to be defined to run the RESTful API
endpoint tests [13] or the end-to-end test [14] automatically.
Using this approach, it is possible to also launch any external process
for testing so for example BaseX Unit module based tests could be
launched additionally or instead of something truly Node.js based.
We have decided a while ago that we want to have private git
repositories with all their CI/CD at gitlab.com. We provide the compute
resources to run all builds and checks using a Kubernetes cluster we
own. Back then github just didn’t provide any private repositories for
free but we wanted to be present there and so we have all the public
projects at github.com.
The good thing about public repositories on github.com is the Actions
workflows there which run in a VM that provides just about any
conceivable programming languages build environment plus container
building tools and more.
The bad thing is: there is no immediately obvious recipe of how to make
good use of that VM on github.com.
But if there are container building tools we can run pretty much a copy
of the gitlab CI/CD workflow that people over there came up with and
that is documented in their AutoDevOps workflow definitions.
So I cannot really show you the gitlab CI/CD workflow I made the
buildpack for in action, you have to take my word for it or try it
yourself on some gitlab instance. Reenabling the old herokuish workflow
for build (AUTO_DEVOPS_BUILD_IMAGE_CNB_ENABLED=false) and referencing my
BaseX buildpack
(BUILDPACK_URL=https://github.com/simar0at/heroku-buildpack-basex) will
integrate BaseX into the AutoDevOps workflow.
But you can also see it running in some of our public projects on
github.com. There just a pretty stereotypical .github/workflows YAML
file is needed and you can use the github.com Actions just fine [15].
That also has the advantage that one can utilize the infrastructure on
github.com instead of providing some compute resources.
The package might be still a little rough around the edges but I use it
now for a few projects of mine (and my institution).
I hope someone finds this useful. There are probably a lot of things
that need to be fine tuned and I would be happy to work together to get
this package better with time.
[1] https://docs.gitlab.com/ee/topics/autodevops/
[2] https://docs.basex.org/wiki/Unit_Module
[3] https://docs.basex.org/wiki/Unit_Module#Example
[4] for one of the solutions existing for Node.js check out
https://www.cypress.io/ . That is what I used recently.
[5] https://github.com/gliderlabs/herokuish
[6] https://devcenter.heroku.com/articles/buildpacks
[7] https://buildpacks.io/
[8] https://github.com/simar0at/heroku-buildpack-basex
[9]
https://github.com/acdh-oeaw/zuludict-app/blob/master/package.json#L6-L12
[10]
https://github.com/acdh-oeaw/vleserver_basex/blob/main/package.json#L19-L25
[11] https://github.com/acdh-oeaw/zuludict-app/tree/master/deployment
[12]
https://github.com/acdh-oeaw/zuludict-app/blob/master/deployment/deploy-zuludict-data.bxs
[13]
https://github.com/acdh-oeaw/api-problem4restxq/blob/master/package.json#L6-L8
[14] https://github.com/acdh-oeaw/vicav-app/tree/master/cypress/integration
[15]
https://github.com/acdh-oeaw/vleserver_basex/blob/main/.github/workflows/build-vleserver_basex.yml
Best regards
--
Mag. Ing. Omar Siam
Austrian Center for Digital Humanities and Cultural Heritage
Österreichische Akademie der Wissenschaften | Austrian Academy of Sciences
Stellvertretende Behindertenvertrauensperson | Deputy representative for
disabled persons
Wohllebengasse 12-14, 1040 Wien, Österreich | Vienna, Austria
T: +43 1 51581-7295
omar.s...@oeaw.ac.at | www.oeaw.ac.at/acdh