This builds a container image containing the DCO checking script. It is then published at: registry.gitlab.com/libvirt/libvirt-jenkins-ci/check-dco:master from where it can be used in all other project repositories. This avoids having to copy the check-dco.py script into every repo when we want to make changes to it. Signed-off-by: Daniel P. Berrangé <berrange@xxxxxxxxxx> --- .gitlab-ci.yml | 39 +++++++++++++++++ check-dco/Dockerfile | 6 +++ check-dco/check-dco.py | 99 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 .gitlab-ci.yml create mode 100644 check-dco/Dockerfile create mode 100755 check-dco/check-dco.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..83b0d64 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,39 @@ + +stages: + - containers + - postbuild + +.build_container_template: &build_container_definition + image: docker:stable + stage: containers + services: + - docker:dind + before_script: + - docker info + - docker login registry.gitlab.com -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} + script: + - docker build --tag ${CI_REGISTRY_IMAGE}/${NAME}:${CI_COMMIT_REF_SLUG} -f ${NAME}/Dockerfile ${NAME} + - docker push ${CI_REGISTRY_IMAGE}/${NAME}:${CI_COMMIT_REF_SLUG} + after_script: + - docker logout + +build-dco: + <<: *build_container_definition + variables: + NAME: check-dco + +# Check that all commits are signed-off for the DCO. Skip +# on master branch and -maint branches, since we only need +# to test developer's personal branches. +check-dco: + # In most projects we'd put this in a "prebuild", but this + # repo is a special case as we need to actually build the + # container first! + stage: postbuild + image: ${CI_REGISTRY_IMAGE}/check-dco:${CI_COMMIT_REF_SLUG} + script: + - /check-dco.py + only: + - branches + except: + - master diff --git a/check-dco/Dockerfile b/check-dco/Dockerfile new file mode 100644 index 0000000..86cada7 --- /dev/null +++ b/check-dco/Dockerfile @@ -0,0 +1,6 @@ +FROM centos:8 + +RUN dnf -y install python3 git && \ + dnf -y clean all + +COPY check-dco.py check-dco.py diff --git a/check-dco/check-dco.py b/check-dco/check-dco.py new file mode 100755 index 0000000..f8204ca --- /dev/null +++ b/check-dco/check-dco.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# +# ci-job.py: validate all commits are signed off +# +# Copyright (C) 2020 Red Hat, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see +# <http://www.gnu.org/licenses/>. + +import os +import os.path +import sys +import subprocess + +cwd = os.getcwd() +reponame = os.path.basename(cwd) +repourl = "https://gitlab.com/libvirt/%s.git" % reponame + +subprocess.check_call(["git", "remote", "add", "dcocheck", repourl]) +subprocess.check_call(["git", "fetch", "dcocheck", "master"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) + +ancestor = subprocess.check_output(["git", "merge-base", "dcocheck/master", "HEAD"], + universal_newlines=True) + +ancestor = ancestor.strip() + +subprocess.check_call(["git", "remote", "rm", "dcocheck"]) + +errors = False + +print("\nChecking for 'Signed-off-by: NAME <EMAIL>' on all commits since %s...\n" % ancestor) + +log = subprocess.check_output(["git", "log", "--format=%H %s", ancestor + "..."], + universal_newlines=True) + +if log == "": + commits = [] +else: + commits = [[c[0:40], c[41:]] for c in log.strip().split("\n")] + +for sha, subject in commits: + + msg = subprocess.check_output(["git", "show", "-s", sha], + universal_newlines=True) + lines = msg.strip().split("\n") + + print("🔍 %s %s" % (sha, subject)) + sob = False + for line in lines: + if "Signed-off-by:" in line: + sob = True + if "localhost" in line: + print(" ❌ FAIL: bad email in %s" % line) + errors = True + + if not sob: + print(" ❌ FAIL missing Signed-off-by tag") + errors = True + +if errors: + print(""" + +❌ ERROR: One or more commits are missing a valid Signed-off-By tag. + + +This project requires all contributors to assert that their contributions +are provided in compliance with the terms of the Developer's Certificate +of Origin 1.1 (DCO): + + https://developercertificate.org/ + +To indicate acceptance of the DCO every commit must have a tag + + Signed-off-by: REAL NAME <EMAIL> + +This can be achieved by passing the "-s" flag to the "git commit" command. + +To bulk update all commits on current branch "git rebase" can be used: + + git rebase -i master -x 'git commit --amend --no-edit -s' + +""") + + sys.exit(1) + +sys.exit(0) -- 2.24.1