# -*- coding: utf-8 -*- """Handles creating a release PR""" import base64 import json import os import tempfile import textwrap from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from pathlib import Path from typing import Tuple import httplib2 from apiclient import discovery from git import Remote, Repo from oauth2client import client, file, tools from packaging.version import Version ROOT_SRC_DIR = Path(__file__).parents[1] def main() -> None: repo = Repo(str(ROOT_SRC_DIR)) update_upstream(repo) prev_version, release_version = get_last_release_versions(repo) send_mail_message( subject=f"tox release {release_version}", content=get_message_body(release_version, prev_version), ) print("All done! ✨ 🍰 ✨") def get_message_body(release_version: Version, prev_version: Version) -> str: is_major_release = release_version.release[0:2] != prev_version.release[0:2] if is_major_release: return textwrap.dedent( f""" The tox team is proud to announce the {release_version} feature release at https://pypi.org/project/tox/! tox aims to automate and standardize testing in Python. It is part of a larger vision of easing the packaging, testing and release process of Python software. Details about the changes can be found at https://tox.readthedocs.io/en/{release_version}/changelog.html For complete documentation, please visit: https://tox.readthedocs.io/en/{release_version}/ As usual, you can upgrade from PyPI via: pip install --upgrade tox or - if you also want to get pre release versions: pip install -upgrade --pre tox We thank all present and past contributors to tox. Have a look at https://github.com/tox-dev/tox/blob/master/CONTRIBUTORS to see who contributed. Happy toxing, the tox-dev team """, # noqa ) else: return textwrap.dedent( f""" The tox team is proud to announce the {release_version} bug fix release at https://pypi.org/project/tox/! tox aims to automate and standardize testing in Python. It is part of a larger vision of easing the packaging, testing and release process of Python software. For details about the fix(es),please check the CHANGELOG: https://tox.readthedocs.io/en/{release_version}/changelog.html We thank all present and past contributors to tox. Have a look at https://github.com/tox-dev/tox/blob/master/CONTRIBUTORS to see who contributed. Happy toxing, the tox-dev team """, # noqa ) def get_upstream(repo: Repo) -> Remote: for remote in repo.remotes: for url in remote.urls: if url.endswith("tox-dev/tox.git"): return remote raise RuntimeError("could not find tox-dev/tox.git remote") def get_last_release_versions(repo: Repo) -> Tuple[Version, Version]: print("get latest release version") commit_to_tag = {tag.commit.hexsha: tag for tag in repo.tags} _, release_tag = sorted( [(tag.commit.committed_datetime, tag) for tag in repo.tags], reverse=True, )[0] for commit in release_tag.commit.iter_parents(): if commit.hexsha in commit_to_tag: prev_release_tag = commit_to_tag[commit.hexsha] prev_version = Version(prev_release_tag.name) if not any( ( prev_version.is_devrelease, prev_version.is_prerelease, prev_version.is_postrelease, ), ): break else: raise RuntimeError("no previous release") release_version = Version(release_tag.name) print(f"\trelease {release_version} with previous {prev_version}") return prev_version, release_version def update_upstream(repo: Repo) -> None: print("fetch latest remote") upstream = get_upstream(repo) upstream.fetch() def send_mail_message(subject, content): this_dir = Path(__file__).parent store = file.Storage("credentials.json") credentials = store.get() if not credentials or credentials.invalid: client_secret_json = json.loads((this_dir / "client_secret.json").read_text()) client_secret_json["installed"]["client_secret"] = os.environ["TOX_DEV_GOOGLE_SECRET"] with tempfile.NamedTemporaryFile(mode="w+t") as temp_filename: json.dump(client_secret_json, temp_filename) temp_filename.flush() flow = client.flow_from_clientsecrets( filename=temp_filename.name, scope="https://www.googleapis.com/auth/gmail.send", ) credentials = tools.run_flow(flow, store) service = discovery.build("gmail", "v1", http=credentials.authorize(httplib2.Http())) message = MIMEMultipart("alternative") message["Subject"] = subject message["From"] = "toxdevorg@gmail.com" recipients = ["testing-in-python@lists.idyll.org", "tox-dev@python.org"] message["To"] = ", ".join(recipients) message.attach(MIMEText(content, "plain")) raw_message_no_attachment = base64.urlsafe_b64encode(message.as_bytes()) raw_message_no_attachment = raw_message_no_attachment.decode() body = {"raw": raw_message_no_attachment} message_sent = service.users().messages().send(userId="me", body=body).execute() message_id = message_sent["id"] print(f"\tMessage sent with id: {message_id}") if __name__ == "__main__": main()