diff --git a/scripts/eachdist.py b/scripts/eachdist.py index 15b9b8edcbb..c8b7f7c3fc6 100755 --- a/scripts/eachdist.py +++ b/scripts/eachdist.py @@ -1,12 +1,15 @@ #!/usr/bin/env python3 import argparse +import os +import re import shlex import shutil import subprocess import sys from collections import namedtuple from configparser import ConfigParser +from datetime import datetime from inspect import cleandoc from itertools import chain from pathlib import Path, PurePath @@ -236,6 +239,15 @@ def setup_instparser(instparser): "pytestargs", nargs=argparse.REMAINDER, help=extraargs_help("pytest") ) + releaseparser = subparsers.add_parser( + "release", help="Prepares release, used by maintainers and CI", + ) + releaseparser.set_defaults(func=release_args) + releaseparser.add_argument("--version", required=True) + releaseparser.add_argument( + "releaseargs", nargs=argparse.REMAINDER, help=extraargs_help("pytest") + ) + return parser.parse_args(args) @@ -503,6 +515,118 @@ def lint_args(args): ) +def update_changelog(path, version, new_entry): + unreleased_changes = False + try: + with open(path) as changelog: + text = changelog.read() + if "## Version {}".format(version) in text: + raise AttributeError( + "{} already contans version {}".format(path, version) + ) + with open(path) as changelog: + for line in changelog: + if line.startswith("## Unreleased"): + unreleased_changes = False + elif line.startswith("## "): + break + elif len(line.strip()) > 0: + unreleased_changes = True + + except FileNotFoundError: + print("file missing: {}".format(path)) + return + + if unreleased_changes: + print("updating: {}".format(path)) + text = re.sub("## Unreleased", new_entry, text) + with open(path, "w") as changelog: + changelog.write(text) + + +def update_changelogs(targets, version): + print("updating CHANGELOG") + today = datetime.now().strftime("%Y-%m-%d") + new_entry = "## Unreleased\n\n## Version {}\n\nReleased {}".format( + version, today + ) + errors = False + for target in targets: + try: + update_changelog( + "{}/CHANGELOG.md".format(target), version, new_entry + ) + except Exception as err: # pylint: disable=broad-except + print(str(err)) + errors = True + + if errors: + sys.exit(1) + + +def find(name, path): + for root, _, files in os.walk(path): + if name in files: + return os.path.join(root, name) + return None + + +def update_version_files(targets, version): + print("updating version.py files") + update_files( + targets, + version, + "version.py", + "__version__ .*", + '__version__ = "{}"'.format(version), + ) + + +def update_dependencies(targets, version): + print("updating dependencies") + update_files( + targets, + version, + "setup.cfg", + r"(opentelemetry-.*)= (.*)", + r"\1= " + version, + ) + + +def update_files(targets, version, filename, search, replace): + errors = False + for target in targets: + curr_file = find(filename, target) + if curr_file is None: + print("file missing: {}/{}".format(target, filename)) + continue + + with open(curr_file) as _file: + text = _file.read() + + if version in text: + print("{} already contans version {}".format(curr_file, version)) + errors = True + continue + + with open(curr_file, "w") as _file: + _file.write(re.sub(search, replace, text)) + + if errors: + sys.exit(1) + + +def release_args(args): + print("preparing release") + + rootpath = find_projectroot() + targets = list(find_targets_unordered(rootpath)) + version = args.version + update_dependencies(targets, version) + update_version_files(targets, version) + update_changelogs(targets, version) + + def test_args(args): clean_remainder_args(args.pytestargs) execute_args( diff --git a/scripts/prepare_release.sh b/scripts/prepare_release.sh index a74bd17a8ab..e75278eb5e5 100755 --- a/scripts/prepare_release.sh +++ b/scripts/prepare_release.sh @@ -21,57 +21,6 @@ if [[ ! "${VERSION}" =~ ^([0-9])(\.*[0-9]{1,5}[a-b]*){1,3}$ ]]; then exit 1 fi -function update_version_file() { - errors=0 - for f in `find . -name version.py`; do - # check if version is already in version.py - grep -q ${VERSION} $f; - rc=$? - if [ $rc == 0 ]; then - errors=1 - echo "${f} already contains ${VERSION}" - continue - fi - # update version.py - perl -i -pe "s/__version__.*/__version__ = \"${VERSION}\"/g" ${f}; - git add ${f}; - echo "Updating ${f}" - done - if [ ${errors} != 0 ]; then - echo "::set-output name=version_updated::0" - exit 0 - fi -} - -function update_changelog() { - errors=0 - RELEASE_DATE=`date +%F` - for f in `find . -name CHANGELOG.md`; do - # check if version is already in CHANGELOG - grep -q ${VERSION} $f; - rc=$? - if [ $rc == 0 ]; then - errors=1 - echo "${f} already contains ${VERSION}" - continue - fi - # check if changelog contains any new details - changes=`sed -n '/## Unreleased/,/^##/p' ${f} | grep -v '^##' | wc -w | awk '{$1=$1;print}'` - if [ ${changes} != "0" ]; then - # update CHANGELOG.md - perl -i -pe 's/## Unreleased.*/## Unreleased\n\n## '${VERSION}'\n\nReleased '${RELEASE_DATE}'/' ${f}; - git add ${f}; - echo "Updating ${f}" - else - echo "Skipping ${f}, no changes detected" - fi - done - if [ ${errors} != 0 ]; then - echo "::set-output name=version_updated::0" - exit 0 - fi -} - # create the release branch git fetch origin master git checkout master @@ -81,8 +30,15 @@ git push origin release/${VERSION} # create a temporary branch to create a PR for updated version and changelogs git checkout -b release/${VERSION}-auto -update_version_file -update_changelog +./scripts/eachdist.py release --version ${VERSION} +rc=$? +if [ $rc != 0 ]; then + echo "::set-output name=version_updated::0" + exit 0 +fi + +git add **/version.py **/setup.cfg **/CHANGELOG.md + git commit -m "updating changelogs and version to ${VERSION}" echo "Time to create a release, here's a sample title:"