📜 ⬆️ ⬇️

CI: continuous integration in 5 minutes


Having read the article to the very end, you will guess why the beaver in the box was chosen as the CCDV.

All health, comrades Habrozhiteli. Most recently, I faced the need to raise and configure the Continuous Integration service (hereinafter referred to as CI) on one very small project, which is very indirectly related to my work. Time was not running out, so I decided to try something new (previously I used only Travis and Jenkins). The main selection criterion was: “simplicity and speed of system deployment on an integration server”.

Under the cut is a small story and the resulting tool for CI, written in two evenings on Bash.

Idea


Maybe I was looking badly, maybe I wanted to sacrifice bicycles to the god, but I didn’t see any CI service that could just be thrown onto the server, put a couple of webhooks into Github configuration and forget about DevOps. Therefore, I decided not to spend time searching any more (and I spent about 1-2 hours), but to write something simple on Bash.
')
The idea was as follows: to write the simplest CI-trigger on Bash, which will run along the chain (pipe) of the functions configured from another (configuration) script.

The advantages of this solution are obvious:


I think about the downsides of this decision, you yourself guessed it. I will give only a few:


Implementation


The CI-trigger itself is elementary:

CI-trigger
config=`pwd`/ci.config #    log=`pwd`/ci.log #  - #   # ... #   - function ci_bootstrap { return 0 } function ci_update { return 0 } function ci_analyse { return 0 } function ci_build { return 0 } function ci_unit_test { return 0 } function ci_deploy { return 0 } function ci_test { return 0 } function ci_archive { return 0 } function ci_report { return 0 } function ci_error { return 0 } #      . $config &&\ ( \ ci_bootstrap &&\ ci_update &&\ ci_analyse &&\ ci_build &&\ ci_unit_test &&\ ci_deploy &&\ ci_test &&\ ci_archive &&\ ci_report || ci_error ) 1>>$log 2>&1 


I did not give the full script code, omitting the logic for parsing command line arguments, since this is trivial and irrelevant to the task (at the end of the article there will be a link to the project repository where you can see the source code without abbreviations).

As you can see, it all comes down to declaring 9 integration functions called pipelining to perform integration when the CI-trigger starts. Both output pipelines are combined in a single log file , which acts as a report on the results of the integration.

Before executing the integration pipeline, a configuration script is invoked on behalf of CI-tirgger ( . $config Config), allowing it to redefine any functions. This is the whole “magic” of the solution. Due to the fact that the configuration script is written in Bash, we can use any logic to perform the integration, simply by grouping it into functions.

Configuration example
 #     cd my-project #     function ci_bootstrap { mysql -uadmin -pmy_pass -e "DROP DATABASE db; CREATE DATABASE db" } #     function ci_update { if test -d .git; then return git pull else return git clone https://github.com/vendor/project ./ fi } #  function ci_build { return npm install && npm run build } #    function ci_unit_test { return npm run unit_test } #   function ci_deploy { return mysql -uadmin -pmy_pass db < migration/schema.sql &&\ mysql -uadmin -pmy_pass db < migration/data.sql } #     function ci_report { return mail -s "CI report" my@mail.com < $log } #    function ci_error { echo "== Error ==" return mail -s "CI report" my@mail.com < $log } 


Now we just have to adjust the logic of the CI-trigger call in accordance with our requirements.

Periodic call


To do this, just configure Cron, for example:

crontab
 0 0 * * * /home/user/ci/trigger 


Call at change


This solution requires the implementation of the mechanism responsible for listening to the port of the integration server with a CI-trigger call when accessing it. I suggest using netcat and the following simple bash script for this:

Listening port
 while true; do { echo -ne "HTTP/1.0 200 OK\r\n\r\n"; } | nc -v -l -p 8000 && /home/user/ci/trigger done 


Now you need to configure the version control system used by us to execute an HTTP request to this port with each push commits, for example using Curl:

.git / hooks / post-commit
 curl -X POST http://ci-server.com:8000 


Links and all that


Naturally, this solution is far from ideal, you will have to “work with your hands” a lot in order to use it in a large project, but for a quick launch of the CI service it is quite suitable (I think so!).

Source: https://habr.com/ru/post/341818/


All Articles