|
1 | 1 | #!/usr/bin/env python3 |
2 | 2 |
|
3 | 3 | import argparse |
| 4 | +import os |
| 5 | +import re |
4 | 6 | import shlex |
5 | 7 | import shutil |
6 | 8 | import subprocess |
7 | 9 | import sys |
8 | 10 | from collections import namedtuple |
9 | 11 | from configparser import ConfigParser |
| 12 | +from datetime import datetime |
10 | 13 | from inspect import cleandoc |
11 | 14 | from itertools import chain |
12 | 15 | from pathlib import Path, PurePath |
@@ -236,6 +239,15 @@ def setup_instparser(instparser): |
236 | 239 | "pytestargs", nargs=argparse.REMAINDER, help=extraargs_help("pytest") |
237 | 240 | ) |
238 | 241 |
|
| 242 | + releaseparser = subparsers.add_parser( |
| 243 | + "release", help="Prepares release, used by maintainers and CI", |
| 244 | + ) |
| 245 | + releaseparser.set_defaults(func=release_args) |
| 246 | + releaseparser.add_argument("--version", required=True) |
| 247 | + releaseparser.add_argument( |
| 248 | + "releaseargs", nargs=argparse.REMAINDER, help=extraargs_help("pytest") |
| 249 | + ) |
| 250 | + |
239 | 251 | return parser.parse_args(args) |
240 | 252 |
|
241 | 253 |
|
@@ -503,6 +515,118 @@ def lint_args(args): |
503 | 515 | ) |
504 | 516 |
|
505 | 517 |
|
| 518 | +def update_changelog(path, version, new_entry): |
| 519 | + unreleased_changes = False |
| 520 | + try: |
| 521 | + with open(path) as changelog: |
| 522 | + text = changelog.read() |
| 523 | + if "## Version {}".format(version) in text: |
| 524 | + raise AttributeError( |
| 525 | + "{} already contans version {}".format(path, version) |
| 526 | + ) |
| 527 | + with open(path) as changelog: |
| 528 | + for line in changelog: |
| 529 | + if line.startswith("## Unreleased"): |
| 530 | + unreleased_changes = False |
| 531 | + elif line.startswith("## "): |
| 532 | + break |
| 533 | + elif len(line.strip()) > 0: |
| 534 | + unreleased_changes = True |
| 535 | + |
| 536 | + except FileNotFoundError: |
| 537 | + print("file missing: {}".format(path)) |
| 538 | + return |
| 539 | + |
| 540 | + if unreleased_changes: |
| 541 | + print("updating: {}".format(path)) |
| 542 | + text = re.sub("## Unreleased", new_entry, text) |
| 543 | + with open(path, "w") as changelog: |
| 544 | + changelog.write(text) |
| 545 | + |
| 546 | + |
| 547 | +def update_changelogs(targets, version): |
| 548 | + print("updating CHANGELOG") |
| 549 | + today = datetime.now().strftime("%Y-%m-%d") |
| 550 | + new_entry = "## Unreleased\n\n## Version {}\n\nReleased {}".format( |
| 551 | + version, today |
| 552 | + ) |
| 553 | + errors = False |
| 554 | + for target in targets: |
| 555 | + try: |
| 556 | + update_changelog( |
| 557 | + "{}/CHANGELOG.md".format(target), version, new_entry |
| 558 | + ) |
| 559 | + except Exception as err: # pylint: disable=broad-except |
| 560 | + print(str(err)) |
| 561 | + errors = True |
| 562 | + |
| 563 | + if errors: |
| 564 | + sys.exit(1) |
| 565 | + |
| 566 | + |
| 567 | +def find(name, path): |
| 568 | + for root, _, files in os.walk(path): |
| 569 | + if name in files: |
| 570 | + return os.path.join(root, name) |
| 571 | + return None |
| 572 | + |
| 573 | + |
| 574 | +def update_version_files(targets, version): |
| 575 | + print("updating version.py files") |
| 576 | + update_files( |
| 577 | + targets, |
| 578 | + version, |
| 579 | + "version.py", |
| 580 | + "__version__ .*", |
| 581 | + '__version__ = "{}"'.format(version), |
| 582 | + ) |
| 583 | + |
| 584 | + |
| 585 | +def update_dependencies(targets, version): |
| 586 | + print("updating dependencies") |
| 587 | + update_files( |
| 588 | + targets, |
| 589 | + version, |
| 590 | + "setup.cfg", |
| 591 | + r"(opentelemetry-.*)= (.*)", |
| 592 | + r"\1= " + version, |
| 593 | + ) |
| 594 | + |
| 595 | + |
| 596 | +def update_files(targets, version, filename, search, replace): |
| 597 | + errors = False |
| 598 | + for target in targets: |
| 599 | + curr_file = find(filename, target) |
| 600 | + if curr_file is None: |
| 601 | + print("file missing: {}/{}".format(target, filename)) |
| 602 | + continue |
| 603 | + |
| 604 | + with open(curr_file) as _file: |
| 605 | + text = _file.read() |
| 606 | + |
| 607 | + if version in text: |
| 608 | + print("{} already contans version {}".format(curr_file, version)) |
| 609 | + errors = True |
| 610 | + continue |
| 611 | + |
| 612 | + with open(curr_file, "w") as _file: |
| 613 | + _file.write(re.sub(search, replace, text)) |
| 614 | + |
| 615 | + if errors: |
| 616 | + sys.exit(1) |
| 617 | + |
| 618 | + |
| 619 | +def release_args(args): |
| 620 | + print("preparing release") |
| 621 | + |
| 622 | + rootpath = find_projectroot() |
| 623 | + targets = list(find_targets_unordered(rootpath)) |
| 624 | + version = args.version |
| 625 | + update_dependencies(targets, version) |
| 626 | + update_version_files(targets, version) |
| 627 | + update_changelogs(targets, version) |
| 628 | + |
| 629 | + |
506 | 630 | def test_args(args): |
507 | 631 | clean_remainder_args(args.pytestargs) |
508 | 632 | execute_args( |
|
0 commit comments