Ruby
Article
By Glenn Goodrich

The Conventions of Contributing to Open Source

By Glenn Goodrich

Open Source Week

It’s Open Source Week at SitePoint! All week we’re publishing articles focused on everything Open Source, Free Software and Community, so keep checking the OSW tag for the latest updates.

open source

This article was peer reviewed by Thom Parkin. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

We all love using open source, right? I have done my fair share of contributing to open source, mainly through small contributions here and there. I’ve tried to open source some libraries in the past, with varying levels of success and failure. I would say I am somewhere in the middle on the Contributor’s Spectrum. There are those that do much more and those that do much less.

If you are interested in becoming an OSS contributor, there is no shortage of articles on how to do that. In fact, I wrote one myself a couple of years ago. I’ll leave the step by step of contributing in the capable hands of said articles.

Today, I want to focus on some of the conventions of open source contributing, looking at it from the perspective of the open source creator. My vehicle for this journey is the Rails Contribution Guides. Rails, as we all know, is a very, very mature framework and an enormous open source undertaking, consisting of many modules and thousands of contributors. With all this activity around creating and maintaining Rails, the documentation and conventions used for contributors have to be comprehensive and well-formed.

In other words, I feel like Rails is a good study when it comes to how open source software can create a contribution guide. Let’s see if I’m right.

The Guide

As I mentioned, we’re going to basically go through the “Contributing to Ruby on Rails” guide, pulling out and discussing the approach Rails takes to contributions. Here are the major bullet points at the start of the guide:

  • How to use GitHub to report issues.
  • How to clone master and run the test suite.
  • How to help resolve existing issues.
  • How to contribute to the Ruby on Rails documentation.
  • How to contribute to the Ruby on Rails code.

This is what the writers of the guide think are the most important, high-level items for contributors. Let’s see how they tackle each one.

Code of Conduct

Before that, though, I’d like to point out that Rails does have an official Code of Conduct (CoC). Whether you agree with the existence of or need for such a document, Rails has one. As such, contributors are expected to abide by the CoC. This brings me to an important consideration when you decide to become an open source contributor.

If you are going to open source your own creation, you should think through the issues raised in the Rails CoC. CoCs are often a polarizing issue, so whether you choose to have one and what it says is important. How will you handle complaints? What can you do if you feel someone is harassing or disrespecting you as a part of your contribution? Be sure you understand expectations: yours and those of the community.

Reporting Bugs/Issues

Rails has chosen Github Issue Tracking for reporting new bugs and issues. This is a great choice, as almost everyone is going to be familiar with Github and the code itself is hosted there. The Rails team differentiates between security-based and non-security-based issues.

Security Issues

Security issues are reported through a different site, which I like to think of as a kind of Batphone for the Core Team. Also, there is a much different protocol for security issues.

Obviously, security is a huge consideration for a framework like Rails. Having a different protocol makes sense, and if you have a library that has major security considerations, you should be sure to have a good way to report them.

All Other Issues

If an issue is not security-related, then Github Issues can be used. The Core Team, being the awesome folks that they are, have created a bunch of templates to help reporters create an executable test case for a given issue. Here is the template an Active Record issue:

begin
  require "bundler/inline"
rescue LoadError => e
  $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
  raise e
end

gemfile(true) do
  source "https://rubygems.org"
  # Activate the gem you are reporting the issue against.
  gem "activerecord", "5.0.0"
  gem "sqlite3"
end

require "active_record"
require "minitest/autorun"
require "logger"

# Ensure backward compatibility with Minitest 4
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)

# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :posts, force: true do |t|
  end

  create_table :comments, force: true do |t|
    t.integer :post_id
  end
end

class Post < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :post
end

class BugTest < Minitest::Test
  def test_association_stuff
    post = Post.create!
    post.comments << Comment.create!

    assert_equal 1, post.comments.count
    assert_equal 1, Comment.count
    assert_equal post.id, Comment.first.post.id
  end
end

This is a great idea and a way to really help someone get an issue reported. It allows others to quickly reproduce the issue which will lead to a much faster resolution.

Feature Requests

Feature requests are not reported as issues for Rails, Instead, it is expected that the requester writes the code for the feature and submit it as a contribution. This makes total sense, so requesting a new feature falls under the new contribution guide.

Helping Resolve Existing Issues

A wonderful way to contribute to any library, including Rails, is to look through open issues and try to nudge them along to a resolution. For example, pick an issue and try to reproduce it. If the contributor has followed convention, there should be an executable test case.

If someone has submitted a fix via a Pull Request (PR), then you can check out the PR and verify the fix.

In both cases, you are helping the Core Team by verifying that things are as reported, allowing them to hurdle the triaging of issues and get to the fixing.

If you are going to offer an open source item, think through the help you can use beyond new code. Can people test out new features and reported bugs? I bet they can, and this is a lower barrier to entry for many people.

--ADVERTISEMENT--

Contribute to Rails Documentation

Rails has an entire section focused on just contributing to the documentation of the framework. Again, this is something to be learned by new open sourcers. How is your library documented? Is it clear and easy to find? Also, how can others improve your docs? Make sure you answer these important questions.

In most cases, you won’t need documentation on the level offered by Rails. It is massive and used by tens of thousands (if not more) people across the globe. But, the point here is to have a good answer for your documentation. I can tell you that I have tried to release a library with a very thin README as docs and it did not go well.

Translating the Documentation

If you expect that your open source library will be used by people who speak different languages, it may be a good idea to have an easy way to translate the docs. Rails does so by asking translators to create a new directory named after the language, copy in the existing docs, and translate them.

Contributing to the Source Code

And we arrived at the meat of what most people think about when contributing to open source: the code. As you’d expect, this section of the guide is by far the longest.

Setting Up a Local Environment

The first thing any contributor will want to do is figure out how to run your code locally. If they can’t do that easily, they can’t contribute easily and you’re turning away helpers.

Rails offers two ways to setup your environment: the “easy” way and the “hard” way. The easy way consists of running the “Rails development box” which is a virtual machine (VM) that is ready to go. If you have VirtualBox and Vagrant, you can fire this up and start writing code. That is easy.

So, then there’s the hard way, which means you basically install everything locally. “Everything” for Rails development consists of:

  • Git
  • SQLite (with dev libraries)
  • Memcached
  • MySQL
  • PostgreSQL
  • Redis

And many of those have setup subtasks. Yikes! That is the hard way.

Regardless, the point here is Rails has documented how to setup a local environment and get coding. All open source offerings should do the same. As a tangent, I wonder why there isn’t a Docker-based Rails development environment/instructions. Hmmm…maybe someone could contribute one…

Write the Code

There are several items to consider when writing code for an open source library like Rails.

Source Control Conventions

The first is how to isolate your code from the main or master branch. In other words, how should the contributor use Git.

Rails keeps it pretty simple and just asks people to create a branch and work in that. Oh, and they offer a cool way to generate a dummy Rails app that will use your local branch.

Coding Conventions

Rails does list a set of code conventions that it expects folks to follow, which is a good idea. There are gems that can help enforce such things, such as Rubucop. In fact, there is a Rubucop configuration file (.rubocop.yml) in the Rails GitHub repository so contributors can be sure their code adheres to the convention.

Testing the Code

Obviously, you are going to want contributors to write and run tests on their code. You should have explicit instructions on how they can do that. It’s probably a good idea to have Rake tasks, or something similar, that will run all your tasks.

As mentioned, Rails is made up of many, many modules. As such, running the tests for the entire Rails code base is not required. Rails documents ways to run tests on a given module to allow contributors to just test what they change. Nice.

Also, Rails uses Travis CI, a continuous integration server, to run all the tests. This is a safety net, which means that not forcing everyone to run all the tests for every contribution is OK. Again, make it easy to run tests or no one will run tests.

Documenting the Change

It is a good idea to keep a running Changelog for your library. Rails asks contributors to place a new entry in the Changelog, documenting what an entry should look like.

Dependency Management

Your library will, no doubt, have dependencies on other Ruby gems. What happens if a contributor needs to change/upgrade one in order to make their code work? You should think this through.

Rails, again, makes it easy because Bundler makes it easy. Just update the Gemfile.lock and run your tests.

Committing Changes

Good commit messages are like a safety vest: Sometimes they are hard to put on, but, if you need them, they’re invaluable. I would strongly recommend you have a standard for your commit messages. Rails does, which I show here:

Short summary (ideally 50 characters or less)

More detailed description, if necessary. It should be wrapped to
72 characters. Try to be as descriptive as you can. Even if you
think that the commit content is obvious, it may not be obvious
to others. Add any description that is already present in the
relevant issues; it should not be necessary to visit a web page
to check the history.

The description section can have multiple paragraphs.

Code examples can be embedded by indenting them with 4 spaces:

    class ArticlesController
      def index
        render json: Article.limit(10)
      end
    end

You can also add bullet points:

- make a bullet point by starting a line with either a dash (-)
  or an asterisk (*)

- wrap lines at 72 characters, and indent any additional lines
  with 2 spaces for readability

Again, it’s not too complicated, but it has it where it counts.

One thing to be aware of is the need to update your feature/bug branch with the latest source from the repository to avoid conflicts with work done while they were contributing. The Rails guide goes through this, which is another good example of documenting your expectations.

Oh, and another thing, it’s a good idea to encourage contributors to squash their commits. You don’t want a PR with 1,023 commits when just one will do.

Forking and Pull Requests

Documenting how you would like to accept code in your source control is paramount. If you’re using Github, there is the well-trodden road of fork the repository and issue PRs. If your open source repository is small, you can issue PRs from branches within the main repo. Regardless of your choice, document what you want.

Discussing and Iterating

The Rails guide goes that extra mile and spells out some of what contributors can expect around discussing a proposed change. Rails is huge, so setting a bit of an informal SLA around when folks will hear back is a good idea.

Also, a few words on how to update a PR is smart. As with the original PR, squashing commits here is probably what you want.

Backwards Compatibility and Backporting

I know I sound a bit like a broken record, but Rails is enormous and people all over the world rely upon it to work and make a living. At any one time, there are various versions of Rails in production on the planet. For those versions that are still supported, you may need to backport fixes.

The Rails guide documents how to create a branch based on an older version of the framework. This makes it easy for contributors to port and test the code against previous versions of Rails. You may not need this level of preparation, but you should think through and communicate how versions of your library will be updated, if at all.

Conclusion

Rails has been around long enough to have created a contribution guide that is worth emulating. I’d say the overarching theme is: Make it easy for people to contribute. If you are thinking of open sourcing a project, you could do worse than to model your contribution strategy on Rails. Be sure to think about:

  • How do contributors set up a local environment?
  • How can people contribute besides writing code?
  • How are my dependencies managed?
  • Is it easy to run the tests?
  • How will I keep my docs up to date?

I hope you found this romp through the Rails contribution guide valuable. I know I did. Now, I am going to go setup my local Rails environment…maybe I’ll use Docker. Happy Open Sourcing!

Recommended
Sponsors
Get the latest in Ruby, once a week, for free.