At Cermati, we use Gulp as our task runner to run most of our build tasks. My first two weeks of working were spent on implementing build-related stuff. Two of which were auto-revert on broken build and auto-tag on sucessful build on production branch. For these two tasks, I used gulp-git plugin, which, as the name implies, handles Git-related tasks using Gulp. At first, my implementation of those two tasks was as follows:

We use Travis CI at Cermati so in our build environment there are several variables like TRAVIS, TRAVIS_BRANCH, etc. and there are also some variables defined in our .travis.yml file like ROBOT_USERNAME, ROBOT_EMAIL, etc. which store our cermati-robot Github account.

I thought this code was perfectly okay and I have set the task dependencies correctly, like ciTag depends on ciGitPrepare which depends on ciSafeGuard. So I expected that only after ciGitPrepare completely finish, ciTag will be run. However, I notice that sometimes the build errored because Git cannot acquire the lock; it seemed that there were two Git processes running simultaneously. This shouldn’t be possible since all git commands were run sequentially, right? Taking a better look at the output, I found that the git commands inside ciGitPrepare sometimes were executed after ciGitPrepare had finished. So, when ciTag was running git push, it errored since another Git process was running git config. How could this happen? Didn’t I already set the dependency correctly?

Reading the Gulp documentation on task dependency once again, I realized that it is not enough to only declare task dependency; we also need to explicitly state that our task dependency is finished by accepting a callback, returning a promise, or returning a stream, as the documentation says.

Modifying the code a little bit, I ended up with this:

Now all the tasks that are depended on are accepting callbacks. Note that I used async library in ciGitPrepare task to avoid ugly nested callbacks (known as callback hell) when writing sequential code. Also note that ciRevert and ciTag does not accept callback nor return anything since there are no tasks dependent on them.

With this code, the problem is now solved. The tasks are run in the correct order and there are no more errors. Hope this helps anyone struggling with similar problem.