From f9a4bb94f6aa3b65293ed71beabbc5c96aefb573 Mon Sep 17 00:00:00 2001 From: Lukas Reschke Date: Wed, 21 Sep 2016 23:55:18 +0200 Subject: [PATCH] Add checker for signed off commits Signed-off-by: Lukas Reschke --- .drone.yml | 8 +++ build/signed-off-checker.php | 120 +++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 build/signed-off-checker.php diff --git a/.drone.yml b/.drone.yml index 4b6dd4e914..51e835cc34 100644 --- a/.drone.yml +++ b/.drone.yml @@ -26,6 +26,13 @@ pipeline: when: matrix: TESTS: app-check-code + signed-off-check: + image: nextcloudci/php7.0:php7.0-2 + commands: + - php ./build/signed-off-checker.php + when: + matrix: + TESTS: signed-off-check syntax-php5.6: image: nextcloudci/php5.6:php5.6-2 commands: @@ -153,6 +160,7 @@ pipeline: matrix: include: + - TESTS: signed-off-check - TESTS: integration - TESTS: jsunit - TESTS: check-autoloader diff --git a/build/signed-off-checker.php b/build/signed-off-checker.php new file mode 100644 index 0000000000..d97f4cf48b --- /dev/null +++ b/build/signed-off-checker.php @@ -0,0 +1,120 @@ + + * + * @author Lukas Reschke + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +/** + * Script to verify that all commits have been signed-off, if a commit doesn't end + * with a signed-off message the script is failing. + */ +$baseDir = __DIR__ . '/../'; + +$pullRequestNumber = getenv('DRONE_PULL_REQUEST'); + +if(!is_string($pullRequestNumber) || $pullRequestNumber === '') { + echo("The environment variable DRONE_PULL_REQUEST has no proper value.\n"); + exit(1); +} + +$ch = curl_init(); +curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); +curl_setopt($ch, CURLOPT_URL, 'https://api.github.com/repos/nextcloud/server/pulls/'.$pullRequestNumber.'/commits'); +curl_setopt($ch, CURLOPT_USERAGENT, 'CI for Nextcloud (https://github.com/nextcloud/server)'); +$response = curl_exec($ch); +curl_close($ch); + +shell_exec( + sprintf( + 'cd %s && git fetch', + escapeshellarg($baseDir), + escapeshellarg($pullRequestNumber) + ) +); + +$decodedResponse = json_decode($response, true); +if(!is_array($decodedResponse) || count($decodedResponse) === 0) { + echo("Could not decode JSON response from GitHub API.\n"); + exit(1); +} + +// Get all commits SHAs +$commits = []; + +foreach($decodedResponse as $commit) { + if(!isset($commit['sha'])) { + echo("No SHA specified in $commit\n"); + exit(1); + } + $commits[] = $commit['sha']; +} + + +if(count($commits) < 1) { + echo("Could not read commits.\n"); + exit(1); +} + +$notSignedCommits = []; +foreach($commits as $commit) { + if($commit === '') { + continue; + } + + $signOffMessage = false; + $commitMessageLines = + explode( + "\n", + shell_exec( + sprintf( + 'cd %s && git rev-list --format=%%B --max-count=1 %s', + $baseDir, + $commit + ) + ) + ); + + foreach($commitMessageLines as $line) { + if(preg_match('/^Signed-off-by: .* <.*@.*>$/', $line)) { + echo "$commit is signed-off with \"$line\"\n"; + $signOffMessage = true; + continue; + } + } + if($signOffMessage === true) { + continue; + } + + $notSignedCommits[] = $commit; +} + +if($notSignedCommits !== []) { + echo("\n"); + echo("Some commits were not signed off!\n"); + echo("Missing signatures on:\n"); + foreach ($notSignedCommits as $commit) { + echo("- " . $commit . "\n"); + } + echo("Build has failed\n"); + exit(1); +} else { + exit(0); +} +