You may think that CI (Continuous Integration) consists only of technical tasks like unit testing, code compilation or static code analysis. However, :) If you are familiar with Jenkins which among others . sometimes you may want to put a little bit of fun to boring build logs you may have heard of Chuck Norris plugin adds funny facts/jokes about Chuck Norris to the builds Before I will show you how to add such functionality to , let me explain, what Bitrise.io is. Bitrise.io What is Bitrise.io? At Droids On Roids, we switched our CI/CD platform from to Bitrise a few years ago. The main reason of that relocation was a better adaptation to mobile (native Android and iOS projects) and faster bug fixes (e.g. in Jenkins Android emulator plugin has been waiting about 1.5 years for review). However, one small additional feature was missing on Bitrise… there were no for Chuck Norris jokes. Bitrise is a Continuous Integration and Delivery (CI/CD) Platform as a Service (PaaS) with the main focus on mobile app development. Jenkins this my PR integrations Implementing Chuck Norris jokes integration The process of adding a joke to a build log is pretty simple. Of course, we can’t forget about proper error handling. We just need to obtain a joke text and print it to the log. Let’s start with installing and invoking . You can find more info about step creation in my previous blogpost: . Bitrise CLI bitrise :step create How to Create Bitrise Step in Go – Flutter Example Bitrise At a glance, this integration looks trivial so it may be a good candidate for a shell script. However, since we need some basic logic like validations or error handling and Bitrise provides libraries which can help us, we will use golang toolkit. officially supports two toolkits for writing integrations (so-called steps): bash (shell scripts) and go . ➡ The source of the jokes Jenkins plugin uses . It is the simplest source to implement. However, it also has a major drawback. Adding a new joke would require releasing a new version of the Bitrise step each time. Each of those versions would need to be approved and users would need to in their (unless they selected “always latest” version). Usually, it is a good idea to separate data from the logic. hardcoded joke texts update step version workflows This one contains many different jokes, it is open source and supports plain text responses so it fits perfectly our needs. However, there are also . We can get jokes from external, free-of-charge API. For example chucknorris.io . other alternatives ➡ The configuration Although task performed by this step may look straightforward — we just need to download jokes and display them, it may be also useful to introduce a little bit of flexibility by allowing some parameters to be configurable. First of them is API host URL, one may want to use a different one than public chucknorris.io e.g. self-hosted instance due to privacy reasons. All the backend components of chucknorris.io are so it shouldn’t be a problem. open source Secondly, we may want to . One may prefer some particular one. There is a query parameter in API for that. customize jokes category They appear as form fields in workflow editor GUI and are injected as environment variables to the build. Newly generated step contains sample input. We can base on it when adding actual inputs. After customization, inputs section should look like this: Configuration parameters are specified using step inputs . Note several things: Input names ( and ) are written using lower snakecase. category api_base_url is marked as required, this fact will be reflected in the workflow editor. api_base_url has a default value set to so users don't need to specify it explicitly. api_base_url https://api.chucknorris.io OK, we have inputs defined. Now we can try to read their values. Fortunately, Bitrise provides library which does all the work for us. We only need to define data structure for config: steputils Note different naming convention in Go than in YAML. Name mapping, as well as additional properties (whether the value is required or not), are specified using . Now we can simply read inputs from the environment: struct tags If there is an error (e.g. required input is not present) we print a message to a build log and exit with failure code, next instructions won’t be executed. ➡ Getting the jokes The process of downloading jokes can be split into several stages. First, we need to create an HTTP request based on configuration parameters (API host URL and category): Note that we request plain text response so there is no need to process it in the next steps to obtain actual joke text. All the errors are propagated to the caller, we will deal with them in the top-level function. Next, we perform the request: The only customization here is a timeout set to 20 seconds. It is important since by default timeout is infinite so step may hang the build. Finally, we can read text from the response: We need to explicitly check the HTTP status code. Without that, in case of errors, we could joke texts like . Note that the error message starts with lowercase. It’s an error to capitalize them since they will be later appended to a prefix. 500 Internal server error After connecting all these steps together we should get code like this: Apart from invoking aforementioned functions we also have deferred response body closing. It will be closed after enclosing functions finishes. Note that if closing fails we cannot return this error to the caller. We log it instead of just ignoring. Swallowing errors is considered a bad practice and static code analysis tools like will complain about that. errcheck ➡ Presenting the output When we have a joke text the only thing we need to do is printing it to the build log, which just contains everything printed to the standard output and standard error during build. Additionally, we can export joke text as a step so it may be potentially used by next steps e.g. by posting inside a slack message. Finally, our main (top-level) function looks like this: output Note that we used from to print a colored message. In case of success we don't need to explicitly exit with code since it's the default value. Moreover exporting needs to be done using which adds it to the envstore accessible by next steps. If we just the environment variable for the current process it will be lost after step finishes. Keep in mind that output should be declared in in order to be visible in workflow editor. By convention output names are written using upper snakecase: log go-utils 0 envman set step.yml Step properties By default, when step on Bitrise fails then the whole build is considered failed, and next steps are not executed. Those behaviors do not match our use case. We want to get the joke always (even if some of the previous steps has failed) and . E.g. user rather won’t be happy that has failed only due to the error during downloading Chuck Norris joke and PR cannot be merged. we don’t want those failures during getting jokes to affect the overall build result pull request status check The first one tells that step should be started even build is marked as failed (some of the previous steps has failed). The user will be able to override that setting in the workflow editor. Skippable step means that its failures won't affect overall build status – it can be still successful. If one really needs a joke, it is possible to override that setting in configuration file. To achieve desired behaviors we need to adjust step configuration by setting **is_always_run** and **is_skippable** to true. bitrise.yml NEED A SUCCESSFUL TEAM? We’re 100% office based team with 7-years’ experience in mobile & web app development Estimate project CI of the CI One of the elements in Bitrise steplib submission says that step should have test workflow inside its repo. By default, it consists of running the step. However, Bitrise provides few utilities useful in Continuous Integration of steps written in Go: , and . All those steps need to know which is the Go package under test. The easiest way to provide that is to use step. The complete workflow looks like this: checklist golint errcheck Go test Go list Note that we added there. It’s an official Golang static analysis tool. go vet Publication Bitrise devcenter contains about sharing own steps. However, there is also workflow which combines all those instructions. Step sharing process requires environment variable. It can be provided using file as follows: tutorial share-this-step MY_STEPLIB_REPO_FORK_GIT_URL .bitrise.secrets.yml By default, this file is ignored and not checked into version control. We’ve also added one little improvement. Instead of hardcoding step version in variable we retrieve the current git tag: . In this case there is no need to assign the same version in 2 different places - in git tag and in . There is only one source of truth. BITRISE_STEP_VERSION --tag $(git describe --tags --exact-match) bitrise.yml Wrap up As you can see, Continuous Integration consists not only of technical tasks, you may also do funny things :) In case of Bitrise CI platform we can easily develop and share our own extensions in form of steps. The full source code is available on . GitHub
Share Your Thoughts