diff --git a/packaging/release.py b/packaging/release.py index 41ddf91b595..c58b415ffe4 100755 --- a/packaging/release.py +++ b/packaging/release.py @@ -60,6 +60,11 @@ def run(*args: t.Any, env: dict[str, t.Any] | None, cwd: pathlib.Path | str, cap ... +@t.overload +def run(*args: t.Any, env: dict[str, t.Any] | None, cwd: pathlib.Path | str, capture_output: bool) -> CompletedProcess | None: + ... + + @t.overload def run(*args: t.Any, env: dict[str, t.Any] | None, cwd: pathlib.Path | str) -> None: ... @@ -349,14 +354,6 @@ class ReleaseArtifact: digest_algorithm: str -@dataclasses.dataclass(frozen=True) -class ReleaseAnnouncement: - """Contents of a release announcement.""" - - subject: str - body: str - - # endregion # region Utilities @@ -477,7 +474,7 @@ def git(*args: t.Any) -> None: ... -def git(*args: t.Any, capture_output: t.Literal[True] | t.Literal[False] = False) -> CompletedProcess | None: +def git(*args: t.Any, capture_output: bool = False) -> CompletedProcess | None: """Run the specified git command.""" return run("git", *args, env=None, cwd=CHECKOUT_DIR, capture_output=capture_output) @@ -943,7 +940,7 @@ def describe_release_artifact(version: Version, item: dict[str, t.Any], validate """Return release artifact details extracted from the given PyPI data.""" package_type = item["packagetype"] - # The artifact URL is documented as stable, so is safe to put in release notes and announcements. + # The artifact URL is documented as stable, so is safe to put in release notes. # See: https://github.com/pypi/warehouse/blame/c95be4a1055f4b36a8852715eb80318c81fc00ca/docs/api-reference/integration-guide.rst#L86-L90 url = item["url"] @@ -1021,58 +1018,10 @@ def create_github_release_notes(upstream: Remote, repository: str, version: Vers return release_notes -def create_release_announcement(upstream: Remote, repository: str, version: Version, validate: bool) -> ReleaseAnnouncement: - """Create and return a release announcement message.""" - env = create_template_environment() - subject_template = env.from_string(RELEASE_ANNOUNCEMENT_SUBJECT_TEMPLATE) - body_template = env.from_string(RELEASE_ANNOUNCEMENT_BODY_TEMPLATE) - - today = datetime.datetime.now(tz=datetime.timezone.utc).date() - - variables = dict( - version=version, - info=dict( - name="ansible-core", - short=f"{version.major}.{version.minor}", - releases=get_release_artifact_details(repository, version, validate), - ), - next_rc=get_next_release_date(datetime.date(2021, 8, 9), 28, today), - next_ga=get_next_release_date(datetime.date(2021, 8, 16), 28, today), - rc=version.pre and version.pre[0] == "rc", - beta=version.pre and version.pre[0] == "b", - alpha=version.pre and version.pre[0] == "a", - major=version.micro == 0, - upstream=upstream, - ) - - if version.pre and version.pre[0] in ("a", "b"): - display.warning("The release announcement template does not populate the date for the next release.") - - subject = subject_template.render(**variables).strip() - body = body_template.render(**variables).strip() - - message = ReleaseAnnouncement( - subject=subject, - body=body, - ) - - return message - - # endregion # region Templates -FINAL_RELEASE_ANNOUNCEMENT_RECIPIENTS = [ - "ansible-announce@googlegroups.com", - "ansible-project@googlegroups.com", - "ansible-devel@googlegroups.com", -] - -PRE_RELEASE_ANNOUNCEMENT_RECIPIENTS = [ - "ansible-devel@googlegroups.com", -] - GITHUB_RELEASE_NOTES_TEMPLATE = """ # Changelog @@ -1086,91 +1035,17 @@ See the [full changelog]({{ changelog }}) for the changes included in this relea {%- endfor %} """ -# These release templates were adapted from sivel's release announcement script. -# See: https://gist.github.com/sivel/937bc2862a9677d8db875f3b10744d8c - -RELEASE_ANNOUNCEMENT_SUBJECT_TEMPLATE = """ -New release{% if rc %} candidate{% elif beta %} beta{% elif alpha %} alpha{% endif %}: {{ info.name }} {{ version }} -""" - -# NOTE: Gmail will automatically wrap the plain text version when sending. -# There's no need to perform wrapping ahead of time for normal sentences. -# However, lines with special formatting should be kept short to avoid unwanted wrapping. -RELEASE_ANNOUNCEMENT_BODY_TEMPLATE = """ -Hi all- we're happy to announce the{{ " " }} -{%- if rc -%} -following release candidate -{%- elif beta -%} -beta release of -{%- elif alpha -%} -alpha release of -{%- else -%} -general release of -{%- endif -%}: - -{{ info.name }} {{ version }} - - -How to get it -------------- - -$ python3 -m pip install --user {{ info.name }}=={{ version }} - -The release artifacts can be found here: -{% for release in info.releases %} -# {{ release.package_label }}: {{ release.size }} bytes -# {{ release.digest_algorithm }}: {{ release.digest }} -{{ release.url }} -{%- endfor %} - - -What's new ----------- - -{% if major %} -This release is a major release. -{%- else -%} -This release is a maintenance release containing numerous bugfixes. -{% endif %} -The full changelog can be found here: - -https://github.com/{{ upstream.user }}/{{ upstream.repo }}/blob/v{{ version }}/changelogs/CHANGELOG-v{{ info.short }}.rst - - -Schedule for future releases ----------------------------- -{% if rc %} -The release candidate will become a general availability release on {{ next_ga.strftime('%-d %B %Y') }}. -{% elif beta %} -Subject to the need for additional beta releases, the first release candidate is scheduled for X. -{% elif alpha %} -Subject to the need for additional alpha releases, the first release beta is scheduled for X. -{% else %} -The next release candidate is planned to be released on {{ next_rc.strftime('%-d %B %Y') }}. The next general availability release will be one week after. -{% endif %} - -Porting help ------------- - -If you discover any errors or if any of your working playbooks break when you upgrade, please use the following link to report the regression: - -https://github.com/{{ upstream.user }}/{{ upstream.repo }}/issues/new/choose - -In your issue, be sure to mention the version that works and the one that doesn't. - -Thanks! -""" # endregion # region Commands + command = CommandFramework( repository=dict(metavar="REPO", choices=tuple(PYPI_ENDPOINTS), default="pypi", help="PyPI repository to use: %(choices)s [%(default)s]"), version=dict(exclusive="version", help="version to set"), pre=dict(exclusive="version", help="increment version to the specified pre-release (aN, bN, rcN)"), final=dict(exclusive="version", action="store_true", help="increment version to the next final release"), commit=dict(help="commit to tag"), - mailto=dict(name="--mailto", action="store_true", help="write announcement to mailto link instead of console"), validate=dict(name="--no-validate", action="store_false", help="disable validation of PyPI artifacts against local ones"), prompt=dict(name="--no-prompt", action="store_false", help="disable interactive prompt before publishing with twine"), setuptools=dict(name='--no-setuptools', action="store_false", help="disable updating setuptools upper bound"), @@ -1195,9 +1070,8 @@ Releases must be performed using an up-to-date checkout of a fork of the Ansible 4. Run the `complete` command [2], then: a. Submit the GitHub release opened in the browser. b. Submit the PR opened in the browser. - c. Send the release announcement opened in your browser. - d. Wait for CI to pass. - e. Merge the PR. + c. Wait for CI to pass. + d. Merge the PR. [1] Use the `--final`, `--pre` or `--version` option for control over the version. [2] During the `publish` step, `twine` may prompt for credentials. @@ -1326,7 +1200,7 @@ def create_release_pr(allow_stale: bool = False) -> None: # noinspection PyUnusedLocal @command -def complete(repository: str, mailto: bool = True, allow_dirty: bool = False) -> None: +def complete(repository: str, allow_dirty: bool = False) -> None: """Complete a release after the prepared changes have been merged.""" command.run( check_state, @@ -1336,7 +1210,6 @@ def complete(repository: str, mailto: bool = True, allow_dirty: bool = False) -> tag_release, post_version, create_post_pr, - release_announcement, ) @@ -1527,35 +1400,6 @@ def create_post_pr(allow_stale: bool = False) -> None: create_pull_request(pr) -@command -def release_announcement(repository: str, version: str | None = None, mailto: bool = True, validate: bool = True) -> None: - """Generate a release announcement for the current or specified version.""" - parsed_version = get_ansible_version(version, mode=VersionMode.STRIP_POST) - upstream = get_remotes().upstream - message = create_release_announcement(upstream, repository, parsed_version, validate) - recipient_list = PRE_RELEASE_ANNOUNCEMENT_RECIPIENTS if parsed_version.is_prerelease else FINAL_RELEASE_ANNOUNCEMENT_RECIPIENTS - recipients = ", ".join(recipient_list) - - if mailto: - to = urllib.parse.quote(recipients) - - params = dict( - subject=message.subject, - body=message.body, - ) - - query_string = urllib.parse.urlencode(params) - url = f"mailto:{to}?{query_string}" - - display.show("Opening email client through default web browser ...") - webbrowser.open(url) - else: - print(f"TO: {recipients}") - print(f"SUBJECT: {message.subject}") - print() - print(message.body) - - # endregion