diff --git a/contrib/source-control-tools/automated-commits.sh b/contrib/source-control-tools/automated-commits.sh --- a/contrib/source-control-tools/automated-commits.sh +++ b/contrib/source-control-tools/automated-commits.sh @@ -234,17 +234,6 @@ git commit -m "${BOT_PREFIX} Update manpages" ;; - update-seeds) - TEAMCITY_DIR="${TOPLEVEL}"/contrib/teamcity - "${TEAMCITY_DIR}"/build-configurations.py --config "${TEAMCITY_DIR}"/automated-commits.yml "${COMMIT_TYPE}" - - git add "${TOPLEVEL}"/contrib/seeds/nodes_main.txt - git add "${TOPLEVEL}"/contrib/seeds/nodes_test.txt - git add "${TOPLEVEL}"/src/chainparamsseeds.h - - git commit -m "${BOT_PREFIX} Update seeds" - ;; - update-timings) "${DEVTOOLS_DIR}"/build_cmake.sh pushd "${BUILD_DIR}" @@ -278,9 +267,18 @@ ;; *) - echo "Error: Invalid commit name '${COMMIT_TYPE}'" - exit 10 + TEAMCITY_DIR="${TOPLEVEL}"/contrib/teamcity + "${TEAMCITY_DIR}"/build-configurations.py --config "${TEAMCITY_DIR}"/automated-commits.yml "${COMMIT_TYPE}" + + # If there is no change, we're done. + if [ -z "$(git status --porcelain)" ]; then + echo "There is nothing to commit because no changes were made." + exit 0 + fi + + "${TOPLEVEL}"/contrib/source-control-tools/prepare-commit.py "${COMMIT_TYPE}" ;; + esac # Smoke tests to give some confidence that master won't be put into a bad state diff --git a/contrib/source-control-tools/prepare-commit.py b/contrib/source-control-tools/prepare-commit.py new file mode 100755 --- /dev/null +++ b/contrib/source-control-tools/prepare-commit.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2020 The Bitcoin developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import argparse +import os +import subprocess +import sys +import yaml + + +def prepare_commit(toplevel, config_path, build_name): + with open(config_path, 'r', encoding='utf-8') as config_file: + # Load configuration file + builds = yaml.safe_load(config_file).get('builds') + if not builds: + return ( + 1, "Error: Configuration file missing expected 'builds' at the top level") + + config = builds.get(build_name) + if not config: + return (2, "Error: Configuration file does not have a build named '{}'".format( + build_name)) + + # Stage specified files + commit_files = config.get('commit_files', []) + subprocess.run(['git', 'add'] + [os.path.join(toplevel, f) + for f in commit_files], check=True) + + # Get the commit message associated with this build + commit_message = config.get('commit_message') + if not commit_message: + return ( + 10, "Error: Expected commit_message in '{}' config".format(build_name)) + + # Commit the staged files + subprocess.run( + ['git', 'commit', '-m', '[Automated] {}'.format(commit_message)], check=True) + + return (0, "Finished preparing commit") + + +def main(): + toplevel = subprocess.check_output( + ['git', 'rev-parse', '--show-toplevel']).rstrip().decode('utf-8') + default_config_path = os.path.join( + toplevel, 'contrib/teamcity/automated-commits.yml') + + parser = argparse.ArgumentParser( + description="Prepare a git commit based on some config") + parser.add_argument( + "build_name", + help="The name of the build to fetch the commit information from" + ) + parser.add_argument( + "--config", + "-c", + default=default_config_path, + help="Path to the configuration file (default: {})".format( + default_config_path) + ) + + args = parser.parse_args() + return_code, message = prepare_commit( + toplevel, args.config, args.build_name) + print(message) + sys.exit(return_code) + + +if __name__ == '__main__': + main() diff --git a/contrib/teamcity/automated-commits.yml b/contrib/teamcity/automated-commits.yml --- a/contrib/teamcity/automated-commits.yml +++ b/contrib/teamcity/automated-commits.yml @@ -1,6 +1,11 @@ --- builds: update-seeds: + commit_files: + - contrib/seeds/nodes_main.txt + - contrib/seeds/nodes_test.txt + - src/chainparamsseeds.h + commit_message: "Update seeds" targets: - - bitcoind - bitcoin-cli