Contributing to an Open Source project can seem daunting at first glance. We not only welcome, but encourage, contributions from the community. In an attempt to lower the barrier of entry to the project, I'll walk through the typical Panamax contribution process.

Panamax consists of several moving parts working together, therefore many entry points exist for getting involved, whether you prefer working on the UI or Server side of things. The team has documented best practices for contributing to Panamax on the project's wiki, but I wanted to take some time to walk through a typical code contribution process.

We'll start with a real bug that was submitted by a user.

From mikesplain:

I setup a coreos box in openstack and got Panamax up and running. Things look great! I also have a simple registry server running on a different VM. The easy way I've found to setup a fast registry server and get it working is to tag images as :5000/. I noticed a number of things in Panamax: * I thought I would be able to have Panamax query the registry by just copy and pasting this name in the image search (my assumption may be wrong). * If I ssh to the coreos box and do a docker pull on the images to get local, then try to get that image running in Panamax, Panamax recognizes the name of the image as the fqdn of the server, then tag as :5000/. I would expect it to find the image name as either or :5000. Please let me know if I'm missing something here. If this is a new issue, I'll probably need help debugging and where to determine if issues should be opened under the API or other pieces of Panamax. Thanks!

What caught my eye was the 2nd bullet of mikesplain's comment.

Because he included output in his description, it was clear this was likely a code issue, since :5000/[imagename] isn't a legitimate tag.

Mike clearly outlined the problem and provided the unexpected result making the bug easier to locate. I dive into the code and sure enough, find a line of code that splits on colons in the LocalImage model of the Panamax API project.

repo, tag = tag.split(':')  # see:

Our code assumes only one colon will be present, and we perform a String#split on it. However, we don't account for other colons that may be present, such as a Docker repository with port information. It's this edge case which trips up our String#split method.

After identifying the problem area, it's time to roll up our sleeves and squash this bug! Since this bug is in the API project, we'll need to fork and pull down that codebase. I'll create a fork of the panamax-api project and then clone it to my local system. See below:

For this bug, I created a branch bug/split-on-last-colon, but that's not mandatory. With the code pulled down, we locate the specs for the offending method, add a case to exercise the bug, and finally alter the implementation to fix this case. For this bug, I need to update the LocalImage spec. First, I expect it to fail:

\# spec/models/local_image_spec.rb
describe LocalImage do
\# add another tag to one of our mock localImages that is formatted like a private repo with port information
let(:local_image1) do
id: 'abc123',
info: {
'VirtualSize' => 111,
'RepoTags' => [
\+ 'private:5000/bizzle:1.5' # the new tag, to trip things up
describe '.all_by_repo' do
it 'returns a result for each unique, tagged repo' do
result = described_class.all_by_repo
expect(result).to be_kind_of(Array)
– expect(result.count).to eq 3
\+ expect(result.count).to eq 4
– expect( matcharray %w(foo/bar fizz panamax)
\+ expect( matcharray %w(foo/bar fizz panamax private:5000/bizzle) # note the additional entry at the end, this will cause a failure until we create the fix

and then I update the code to fix the bug.

class LocalImage < ApiModel
def self.all_by_repo
all.eachwithobject({}) do |image, memo|
image.tags.each do |tag|
– repo, tag = tag.split(':') # remove this line…
\+ repo, _, tag = tag.rpartition(':').reject(&:empty?) # in favor of this line
memo[repo] ||= new(id: repo, tags: [])
memo[repo].tags << tag

Commit the test and implementation change as a single commit, while referencing the GitHub issue in the commit body. Here's my commit for the bug.

$ git commit -am "Only split on the last colon.
resolves CenturyLinkLabs/panamax-ui#299"
$ git push

If you have multiple commits, you can squash them together into a single commit. This helps not only with repo sanitization, but makes rollbacks easier should something go awry.

Once everything looks good, submit a pull request between panamax-api and the new fork and/or branch, in my case : CenturyLinkLabs:master … alexwelch:bug/split-on-last-colon. Notice that the issue gets updated with the commit. Once the pull request is reviewed by the team it will either get comments, or be merged into master.

We'll include your changes in our CHANGELOG for the next release, and give you credit.

If you're ready to get involved, check out our Contribution Guide and get started.