134ed46a2SDaniel P. Berrangé#!/usr/bin/env python3 234ed46a2SDaniel P. Berrangé# 334ed46a2SDaniel P. Berrangé# check-dco.py: validate all commits are signed off 434ed46a2SDaniel P. Berrangé# 534ed46a2SDaniel P. Berrangé# Copyright (C) 2020 Red Hat, Inc. 634ed46a2SDaniel P. Berrangé# 734ed46a2SDaniel P. Berrangé# SPDX-License-Identifier: GPL-2.0-or-later 834ed46a2SDaniel P. Berrangé 934ed46a2SDaniel P. Berrangéimport os 1034ed46a2SDaniel P. Berrangéimport os.path 1134ed46a2SDaniel P. Berrangéimport sys 1234ed46a2SDaniel P. Berrangéimport subprocess 1334ed46a2SDaniel P. Berrangé 1434ed46a2SDaniel P. Berrangénamespace = "qemu-project" 1534ed46a2SDaniel P. Berrangéif len(sys.argv) >= 2: 1634ed46a2SDaniel P. Berrangé namespace = sys.argv[1] 1734ed46a2SDaniel P. Berrangé 1834ed46a2SDaniel P. Berrangécwd = os.getcwd() 1934ed46a2SDaniel P. Berrangéreponame = os.path.basename(cwd) 2034ed46a2SDaniel P. Berrangérepourl = "https://gitlab.com/%s/%s.git" % (namespace, reponame) 2134ed46a2SDaniel P. Berrangé 2297f116f9SAlex Bennéeprint(f"adding upstream git repo @ {repourl}") 2334ed46a2SDaniel P. Berrangésubprocess.check_call(["git", "remote", "add", "check-dco", repourl]) 2497f116f9SAlex Bennéesubprocess.check_call(["git", "fetch", "check-dco", "master"]) 2534ed46a2SDaniel P. Berrangé 2634ed46a2SDaniel P. Berrangéancestor = subprocess.check_output(["git", "merge-base", 2734ed46a2SDaniel P. Berrangé "check-dco/master", "HEAD"], 2834ed46a2SDaniel P. Berrangé universal_newlines=True) 2934ed46a2SDaniel P. Berrangé 3034ed46a2SDaniel P. Berrangéancestor = ancestor.strip() 3134ed46a2SDaniel P. Berrangé 3234ed46a2SDaniel P. Berrangésubprocess.check_call(["git", "remote", "rm", "check-dco"]) 3334ed46a2SDaniel P. Berrangé 3434ed46a2SDaniel P. Berrangéerrors = False 3534ed46a2SDaniel P. Berrangé 3634ed46a2SDaniel P. Berrangéprint("\nChecking for 'Signed-off-by: NAME <EMAIL>' " + 3734ed46a2SDaniel P. Berrangé "on all commits since %s...\n" % ancestor) 3834ed46a2SDaniel P. Berrangé 3934ed46a2SDaniel P. Berrangélog = subprocess.check_output(["git", "log", "--format=%H %s", 4034ed46a2SDaniel P. Berrangé ancestor + "..."], 4134ed46a2SDaniel P. Berrangé universal_newlines=True) 4234ed46a2SDaniel P. Berrangé 4334ed46a2SDaniel P. Berrangéif log == "": 4434ed46a2SDaniel P. Berrangé commits = [] 4534ed46a2SDaniel P. Berrangéelse: 4634ed46a2SDaniel P. Berrangé commits = [[c[0:40], c[41:]] for c in log.strip().split("\n")] 4734ed46a2SDaniel P. Berrangé 4834ed46a2SDaniel P. Berrangéfor sha, subject in commits: 4934ed46a2SDaniel P. Berrangé 5034ed46a2SDaniel P. Berrangé msg = subprocess.check_output(["git", "show", "-s", sha], 5134ed46a2SDaniel P. Berrangé universal_newlines=True) 5234ed46a2SDaniel P. Berrangé lines = msg.strip().split("\n") 5334ed46a2SDaniel P. Berrangé 5434ed46a2SDaniel P. Berrangé print(" %s %s" % (sha, subject)) 5534ed46a2SDaniel P. Berrangé sob = False 5634ed46a2SDaniel P. Berrangé for line in lines: 5734ed46a2SDaniel P. Berrangé if "Signed-off-by:" in line: 5834ed46a2SDaniel P. Berrangé sob = True 5934ed46a2SDaniel P. Berrangé if "localhost" in line: 6034ed46a2SDaniel P. Berrangé print(" ❌ FAIL: bad email in %s" % line) 6134ed46a2SDaniel P. Berrangé errors = True 6234ed46a2SDaniel P. Berrangé 6334ed46a2SDaniel P. Berrangé if not sob: 6434ed46a2SDaniel P. Berrangé print(" ❌ FAIL missing Signed-off-by tag") 6534ed46a2SDaniel P. Berrangé errors = True 6634ed46a2SDaniel P. Berrangé 6734ed46a2SDaniel P. Berrangéif errors: 6834ed46a2SDaniel P. Berrangé print(""" 6934ed46a2SDaniel P. Berrangé 7034ed46a2SDaniel P. Berrangé❌ ERROR: One or more commits are missing a valid Signed-off-By tag. 7134ed46a2SDaniel P. Berrangé 7234ed46a2SDaniel P. Berrangé 7334ed46a2SDaniel P. BerrangéThis project requires all contributors to assert that their contributions 7434ed46a2SDaniel P. Berrangéare provided in compliance with the terms of the Developer's Certificate 7534ed46a2SDaniel P. Berrangéof Origin 1.1 (DCO): 7634ed46a2SDaniel P. Berrangé 7734ed46a2SDaniel P. Berrangé https://developercertificate.org/ 7834ed46a2SDaniel P. Berrangé 7934ed46a2SDaniel P. BerrangéTo indicate acceptance of the DCO every commit must have a tag 8034ed46a2SDaniel P. Berrangé 81*270c81b7SDaniel P. Berrangé Signed-off-by: YOUR NAME <EMAIL> 82*270c81b7SDaniel P. Berrangé 83*270c81b7SDaniel P. Berrangéwhere "YOUR NAME" is your commonly known identity in the context 84*270c81b7SDaniel P. Berrangéof the community. 8534ed46a2SDaniel P. Berrangé 8634ed46a2SDaniel P. BerrangéThis can be achieved by passing the "-s" flag to the "git commit" command. 8734ed46a2SDaniel P. Berrangé 8834ed46a2SDaniel P. BerrangéTo bulk update all commits on current branch "git rebase" can be used: 8934ed46a2SDaniel P. Berrangé 9034ed46a2SDaniel P. Berrangé git rebase -i master -x 'git commit --amend --no-edit -s' 9134ed46a2SDaniel P. Berrangé 9234ed46a2SDaniel P. Berrangé""") 9334ed46a2SDaniel P. Berrangé 9434ed46a2SDaniel P. Berrangé sys.exit(1) 9534ed46a2SDaniel P. Berrangé 9634ed46a2SDaniel P. Berrangésys.exit(0) 97