For those of you that have not yet peaked under the hood of this blog, it’s running Jekyll. In short, I was no longer interested in maintaining a three tier infrastructure to simply host a blog. After comparing the field of static Content Management Systems (CMS), I chose it over Hugo only because I have a bit more experience with Ruby versus Go, and based on a cursory review felt that the breath of plugins was deeper based on its maturity. With that said, customizing it had a learning curve to understand the nuances of theming and the use of plugins through RubyGems.

A little more than a week ago, I decided that I would migrate the site to Jekyll 4. In the process, I discovered that one of the plugins was not defined to support any version above 3. This sent me down a journey of contributing back to the community, instead of forcing the version on my own instance.

The gem that is the subject of this post is jekyll_github_sample. Its purpose is to extract code from a GitHub reference and add it to a post during Jekyll build time. The intent is to reference the code as commited instead of having to manually copy and paste it into the post. I found it early on when building this blog, and love its ease of use. To say that I was disappointed when I discovered that it wouldn’t load when using Jekyll 4 is an understatement which is why I had to solve the issue. I wasn’t going to migrate to 4 without this plugin.

Typically, when I discover a bug, I follow a standard set of steps to find, fix, and contribute it back to the repository where the code originated. Over the years, I can say with confidence that I’m more efficient about it only because of practice. The steps are the following:

  1. Find the upstream repository where the code exists and fork it into a local repository (If it doesn’t exist, decompile the binary you do have)
  2. Set up a development and test environment (even if you have minimal experience in the language that it was written in)
  3. Reproduce the issue with the existing code base
  4. Debug and identify where changes in the code are required
  5. Write a test, or confirm that a test exists for the required functionality
  6. Create a working branch for the change in the repository
  7. Change the code, and test. Rinse and repeat until it works as expected ensuring you didn’t break anything else. You will break something else.
  8. Commit the change(s) to a working branch in your local repository
  9. Create a pull request to merge your fix into the upstream repository
  10. Use the code you wrote until your changes are merged into the official release

It sounds like a lot of work, and it is, but in the grand scheme of things, it’s the reason how the open source community can deliver quality products to the consumer at no financial cost. The value is in the virtual sweat equity that is invested by the developers, and the users.

For this use case steps 1-4 were quite easy as the plugin is already hosted in GitHub, and forking through the UI is a piece of cake. Once forked, I created my working branch. Everyone has their own convention for branch names. Years ago, I started using the following patterns:

bug/
Self-explanatory
feat/
A branch focussed on a specific feature typically related to a minor version release
wip/
A branch that’s a work in progress for a duration of time typically related to a major version release

For this specific issue, I created the branch bug/jekyll-4 with the intent of keeping the related commits to resolve the bug in one place. You may have noticed I glossed over step five, and went straight to step six. My excuses are weak - can I claim lack of enough coffee and/or chocolate?

Now on to step seven - the best part!

The issue of not being able to load the plugin in version four was due to one single line in the gem’s gemspec. The original version had the following definition for the Jekyll dependency:

s.add_dependency 'jekyll',        '~> 3.0'

My modification was the following:

s.add_dependency 'jekyll',        '>= 3.0', '< 5.0'

For those of you that are looking through the branch, you’ll note that there were a few other changes, namely the depencies in gemfile.lock, and a slight bump to the plugin’s version number. Other than that, the above change was the only piece required for the plugin to work in Jekyll 4.

Over the years, testing my version of compiled binaries was always a challenge. Maybe it’s just me, but I always felt like I was struggling with dependency hell, or linking failures that I could never get right. My experience gradually improved because I started using Java more, and interpreted languages, but it was still painful.

This is the first time I didn’t have to struggle.

I present to you… Bundler. At the surface, this is a fantastic solution to solving dependency madness, and easing iterative development of libraries. I don’t have enough experience to comment further, but for my use case, I was incredibly pleased.

I used Bundler to package up, and manage depencies for Jekyll, but I didn’t realize its real might until now. In the Gemfile for my Jekyll 3 deployment, I had the following line to include the github_sample plugin:

gem "jekyll_github_sample"

This indicates to Bundler that I want to inclue that specific gem from the rubygems.org repository at build time. For my test, I needed to change this to point to my local branch.

I give you the magic of Bundler.

gem 'jekyll_github_sample', :path => '/path/to/branch'

When Bundler is executed, it handles all of the depencies of the gems requested, and as long as they’re met, builds your package without issue.

After confirming that my changes didn’t break anything for both Jekyll 3, and 4, I commited the changes to my repository, and created a pull request from my branch to the upstream repository. Until the plugin owner merges my changes, I can use the following nifty feature in my gemfile:

gem 'jekyll_github_sample', :git => 'git@github.com:kriation/jekyll-github-sample.git', :branch => 'bug/jekyll-4'

That’s right folks! Bundler can pull gems from any Git repository as long as it’s accessible. In addition, you can specify :tag, :branch, or :ref modifiers to pull specific versions of the requested package. For my case, I specified the branch, as I don’t intend on changing the configuration until the merge is completed.

I learned quite a bit in this process, specifically about Ruby, and how it manages library depencies. I’m now considering writing my own plugin to help in how I write these posts. With the knowledge I learned here, I definitely think I’ll be able to.

In my opinion, the benefits of contributing back to open source software that you use are the following:

  1. The user community of that software now can benefit from your own change. In this case, users of the plugin can now upgrade to Jekyll 4 instead of resorting to providing code examples the old way again.

  2. You learn. I know we all have a metric ton of priorities and responsibilities but in the grand scheme, increasing your knowlege about a specific topic enables you to become better.