Checking CLAs via Travis — or — Make the Robots Enforce Legal F/OSS Requirements
If you're running an Open Source project using a Copyleft license like the GNU General Public License, its weaker cousin the LGPL, or even a variation on the Apache License, you should probably be getting Contributor License Agreements from everyone submitting code for inclusion.
Why?
Without a CLA, or some other legal contract, you technically have no right to redistribute anyone elses changes. There's a big debate online about whether CLAs are too heavy-handed, whether they provide any real protection, and if they drive away would-be contributors.
I want to side-step the socio-legal issues for now, and just focus on using a the Travis CI tool for enforcing CLAs whenever a Github Pull Request is submitted.
The concept is pretty straightforward: maintain a list of identities (read: email addresses) of people who have signed and submitted CLAs. Keep that file in-repo, and teach the CI build script to check the new commits it's testing against that list.
Simple!
Here's the format of the CONTRIBUTORS file:
# comments start with an octothorpe
# and run until the end of the line
# ^^ blank lines are ignored.
# the normal case - one person, one email
Felicia Adkins <felicia@example.com>
# two emails can be supplied if necessary
Mike Nash <m@example.com> <mike.nash@example.com>
When someone signs a new CLA, add their name to the list!
With Travis, we can use the TRAVIS_COMMIT_RANGE environment variable,
which lists the range of commits (SHA1 IDs) that were included in the git
push or Github Pull Request.  The idea is this:
- Loop over the commit range
- For each commit, check the Author Email against the CONTRIBUTORSfile
- If the author isn't listed in CONTRIBUTORS, fail (but defer...)
Here's a Bash function you can add to your CI script:
check_cla() {
  local passchar="\xe2\x9c\x94" # U+2714 - ballot check
  local failchar="\xe2\x9c\x98" # U+2718 - ballot x
  local rc=0
  local IFS=$'\n'
  echo "Checking CONTRIBUTOR status..."
  for x in $(git log --pretty=format:'%aE %h - %s (%aN <%aE>)' \
                 ${TRAVIS_COMMIT_RANGE}); do
    email=${x%% *}
    desc=${x#* }
    if grep -q '^[^#].*<'${email}'>' CONTRIBUTORS; then
      echo -e "\033[32m${passchar}\033[0m $desc"
    else
      echo -e "\033[31m${failchar}\033[0m $desc"
      echo -e "  \033[31m<${email}> not listed in CONTRIBUTORS file!\033[0m"
      rc=1
    fi
  done
  echo
  return $rc
}
When you call it, it will print out something like this:

If it finds any commit authors who aren't listed (again, by email address)
in the CONTRIBUTORS file, it will print a message to that effect and
ultimately return non-zero.  With set -e enabled, this will fail your
build.  Otherwise, you can just check $? or wrap the call in an if
block.
Happy Hacking!
