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 TRAVISCOMMITRANGE
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
CONTRIBUTORS
file - 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!