This document explains how we can use Jenkins to solve some SASS/Git headaches.
One of the problems that we deal with when working with SASS and Git is that the CSS added to the remote repository changes based on who compiled it.
That means every time someone commits to the remote repository before we can push our work up, HEAD will have changed and our push attempt will be rejected.
There are a few options for dealing with that scenario, including git stash
,
git pull --rebase
, etc... but there will always be some extra step required
where we must deal with the compiled CSS before we can commit our work to the
remote repository. As soon as we do, other developers face the same situation
which becomes a massive time-sink after a day or two.
At a higher level, the issue is that developers need to work with SASS locally, in whatever way is most efficient for them, without affecting the compiled output that exists in the remote repository. E.g., Developer A uses tools that require FireSASS to be used during compilation. Developer B doesn't use FireSASS, but does require CR LF line endings for his tools to behave properly. Both developers are compiling CSS that is both unsuitable for a production environment and nightmarish to diff or merge between branches.
Simply "dealing with the problem" is not an efficient way to develop using a CSS preprocessor like SASS where compilation happens with nearly every commit.
One solution would be to standardize the way SASS compiles CSS. This, however, introduces a new kind of time-sink wherein developers must abandon their known workflows and toolsets in favor of working in exactly the same way, which reduces their efficiency further.
To suit the needs of developers working with SASS without impacting their productivity, we can use our already existing CI workflows using Jenkins.
The idea is to add a Jenkins job to watch a specific branch of the repository.
When a commit is pushed to that branch, Jenkins merges that remote branch with
its own local branch, compiles the SASS into CSS, commits the new CSS, merges
with the master
branch, and pushes its local master
branch to the remote.
For explanations in this section, use this example scenario:
There are 2 Developers (A & B) and 3 branches (master, frontend, a-feature) of a repository. Jenkins is watching the
frontend
branch for changes.
-
The project's
.gitignore
file is be set to ignore*.css
andconfig.rb
. -
An initial compilation of CSS is performed and forcefully committed to the
master
branch along with aconfig.rb
suitable for the dev/staging server.git add --force css/*.css
-
After this point, only Jenkins builds will be pushing new CSS to
master
.1 -
Locally, developers can either tell git to ignore local modifications to their
config.rb
and the CSS they compile while developing or alternatively, they can simply ignore git's notices about untracked files by doing nothing.git update-index --assume-unchanged [<file>...]
[1](id: footnote1) If necessary, this could be done manually with a subsequent force push to the branch.
- Developer A commits his final change to
a-feature
. - Developer B has updated the remote
frontend
branch sincea-feature
was branched from it. Developer A now merges the branches locally. - Now that Developer A's local clone of
frontend
is ahead of the remote, he pushes up to the remote repository. - Jenkins sees that
frontend
has been changed and begins its job:- check out local
frontend
- pull remote
frontend
- rebase
frontend
on top ofmaster
to getconfig.rb
- compile SASS into CSS
- checkout local
master
- pull from remote
master
just in case - merge
master
withfrontend
- push local
master
to remotemaster
.
- check out local
- Both Developer A and Developer B dance around the council fires of their people.