salt/tools/changelog.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

285 lines
7.5 KiB
Python
Raw Normal View History

2023-01-23 18:15:05 -07:00
"""
These commands are used manage Salt's changelog.
"""
# pylint: disable=resource-leakage,broad-except
from __future__ import annotations
import datetime
import logging
import os
import pathlib
import subprocess
import sys
2023-01-23 18:15:05 -07:00
import textwrap
from ptscripts import Context, command_group
log = logging.getLogger(__name__)
REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent
# Define the command group
cl = command_group(
name="changelog",
help="Changelog tools",
description=__doc__,
venv_config={
"requirements_files": [
REPO_ROOT
/ "requirements"
/ "static"
/ "ci"
/ "py{}.{}".format(*sys.version_info)
/ "changelog.txt"
],
},
)
2023-01-23 18:15:05 -07:00
def _get_changelog_contents(ctx: Context, version: str):
2023-01-23 18:15:05 -07:00
"""
Return the full changelog generated by towncrier.
"""
return ctx.run(
"towncrier",
"build",
"--draft",
f"--version={version}",
capture=True,
2023-01-26 11:11:30 +00:00
).stdout.decode()
2023-01-23 18:15:05 -07:00
def _get_pkg_changelog_contents(ctx: Context, version: str):
2023-01-23 18:15:05 -07:00
"""
Return a version of the changelog entries suitable for packaged changelogs.
"""
changes = _get_changelog_contents(ctx, version)
2023-01-23 18:15:05 -07:00
changes = "\n".join(changes.split("\n")[2:])
2023-01-27 03:47:31 +00:00
changes = changes.replace(
textwrap.dedent(
"""
2023-01-23 18:15:05 -07:00
Removed
-------
2023-01-27 03:47:31 +00:00
"""
),
"",
)
changes = changes.replace(
textwrap.dedent(
"""
2023-01-23 18:15:05 -07:00
Deprecated
----------
2023-01-27 03:47:31 +00:00
"""
),
"",
)
changes = changes.replace(
textwrap.dedent(
"""
2023-01-23 18:15:05 -07:00
Changed
-------
2023-01-27 03:47:31 +00:00
"""
),
"",
)
changes = changes.replace(
textwrap.dedent(
"""
2023-01-23 18:15:05 -07:00
Fixed
-----
2023-01-27 03:47:31 +00:00
"""
),
"",
)
changes = changes.replace(
textwrap.dedent(
"""
2023-01-23 18:15:05 -07:00
Added
-----
2023-01-27 03:47:31 +00:00
"""
),
"",
)
2023-01-23 18:15:05 -07:00
return changes
def _get_salt_version():
2023-01-26 11:11:30 +00:00
return (
subprocess.run(
["python3", "salt/version.py"], stdout=subprocess.PIPE, check=True
)
.stdout.decode()
.strip()
2023-01-27 03:47:31 +00:00
)
2023-01-23 18:15:05 -07:00
@cl.command(
name="update-rpm",
arguments={
"salt_version": {
"help": (
"The salt package version. If not passed "
"it will be discovered by running 'python3 salt/version.py'."
),
"nargs": "?",
2023-01-27 03:47:31 +00:00
"default": None,
2023-01-23 18:15:05 -07:00
},
"draft": {
2023-01-24 13:53:46 -07:00
"help": "Do not make any changes, instead output what would be changed.",
2023-01-23 18:15:05 -07:00
},
},
)
2023-01-24 13:53:46 -07:00
def update_rpm(ctx: Context, salt_version: str, draft: bool = False):
2023-01-27 03:47:31 +00:00
if salt_version is None:
salt_version = _get_salt_version()
changes = _get_pkg_changelog_contents(ctx, salt_version)
2023-01-26 11:11:30 +00:00
ctx.info("Salt version is %s", salt_version)
orig = ctx.run(
"sed",
f"s/Version: .*/Version: {salt_version}/g",
"pkg/rpm/salt.spec",
capture=True,
2023-01-27 03:47:31 +00:00
check=True,
2023-01-26 11:11:30 +00:00
).stdout.decode()
2023-01-23 18:15:05 -07:00
dt = datetime.datetime.utcnow()
date = dt.strftime("%a %b %d %Y")
header = f"* {date} Salt Project Packaging <saltproject-packaging@vmware.com> - {salt_version}\n"
2023-01-27 03:47:31 +00:00
parts = orig.split("%changelog")
2023-01-23 18:15:05 -07:00
tmpspec = "pkg/rpm/salt.spec.1"
with open(tmpspec, "w") as wfp:
wfp.write(parts[0])
wfp.write("%changelog\n")
wfp.write(header)
wfp.write(changes)
wfp.write(parts[1])
try:
2023-01-27 03:47:31 +00:00
with open(tmpspec) as rfp:
2023-01-23 18:15:05 -07:00
if draft:
ctx.info(rfp.read())
else:
with open("pkg/rpm/salt.spec", "w") as wfp:
wfp.write(rfp.read())
finally:
os.remove(tmpspec)
@cl.command(
name="update-deb",
arguments={
"salt_version": {
"help": (
"The salt package version. If not passed "
"it will be discovered by running 'python3 salt/version.py'."
),
"nargs": "?",
2023-01-27 03:47:31 +00:00
"default": None,
2023-01-23 18:15:05 -07:00
},
"draft": {
2023-01-24 13:53:46 -07:00
"help": "Do not make any changes, instead output what would be changed.",
2023-01-23 18:15:05 -07:00
},
},
)
2023-01-24 13:53:46 -07:00
def update_deb(ctx: Context, salt_version: str, draft: bool = False):
2023-01-27 03:47:31 +00:00
if salt_version is None:
salt_version = _get_salt_version()
changes = _get_pkg_changelog_contents(ctx, salt_version)
2023-01-27 03:47:31 +00:00
formated = "\n".join([f" {_.replace('-', '*', 1)}" for _ in changes.split("\n")])
2023-01-23 18:15:05 -07:00
dt = datetime.datetime.utcnow()
date = dt.strftime("%a, %d %b %Y %H:%M:%S +0000")
tmpchanges = "pkg/rpm/salt.spec.1"
with open(tmpchanges, "w") as wfp:
wfp.write(f"salt ({salt_version}) stable; urgency=medium\n\n")
wfp.write(formated)
2023-01-27 03:47:31 +00:00
wfp.write(
f"\n -- Salt Project Packaging <saltproject-packaging@vmware.com> {date}\n\n"
)
with open("pkg/debian/changelog") as rfp:
2023-01-23 18:15:05 -07:00
wfp.write(rfp.read())
try:
2023-01-27 03:47:31 +00:00
with open(tmpchanges) as rfp:
2023-01-23 18:15:05 -07:00
if draft:
ctx.info(rfp.read())
else:
2023-01-26 11:11:30 +00:00
with open("pkg/debian/changelog", "w") as wfp:
2023-01-23 18:15:05 -07:00
wfp.write(rfp.read())
finally:
os.remove(tmpchanges)
2023-01-27 03:47:31 +00:00
2023-01-23 18:15:05 -07:00
@cl.command(
name="update-release-notes",
arguments={
"salt_version": {
"help": (
"The salt version used to generate the release notes. If not passed "
"it will be discovered by running 'python3 salt/version.py'."
),
"nargs": "?",
2023-01-27 03:47:31 +00:00
"default": None,
2023-01-23 18:15:05 -07:00
},
"draft": {
2023-01-24 13:53:46 -07:00
"help": "Do not make any changes, instead output what would be changed.",
2023-01-23 18:15:05 -07:00
},
},
)
2023-01-24 13:53:46 -07:00
def update_release_notes(ctx: Context, salt_version: str, draft: bool = False):
2023-01-27 03:47:31 +00:00
if salt_version is None:
salt_version = _get_salt_version()
2023-01-27 03:47:31 +00:00
if "+" in salt_version:
2023-01-23 18:15:05 -07:00
major_version = salt_version.split("+", 1)[0]
else:
2023-01-26 11:11:30 +00:00
major_version = salt_version
changes = _get_changelog_contents(ctx, salt_version)
2023-01-23 18:15:05 -07:00
changes = "\n".join(changes.split("\n")[2:])
tmpnotes = f"doc/topics/releases/{salt_version}.rst.tmp"
2023-01-23 18:15:05 -07:00
try:
2023-01-27 03:47:31 +00:00
with open(f"doc/topics/releases/{major_version}.rst") as rfp:
2023-01-23 18:15:05 -07:00
existing = rfp.read()
except FileNotFoundError:
existing = ""
with open(tmpnotes, "w") as wfp:
wfp.write(existing)
wfp.write(changes)
try:
2023-01-27 03:47:31 +00:00
with open(tmpnotes) as rfp:
2023-01-23 18:15:05 -07:00
if draft:
ctx.info(rfp.read())
else:
2023-01-26 11:11:30 +00:00
with open(f"doc/topics/releases/{salt_version}.rst", "w") as wfp:
2023-01-23 18:15:05 -07:00
wfp.write(rfp.read())
finally:
2023-01-27 03:47:31 +00:00
os.remove(tmpnotes)
2023-01-23 18:15:05 -07:00
@cl.command(
2023-01-26 11:11:30 +00:00
name="update-changelog-md",
2023-01-23 18:15:05 -07:00
arguments={
"salt_version": {
"help": (
"The salt version to use in the changelog. If not passed "
"it will be discovered by running 'python3 salt/version.py'."
),
"nargs": "?",
2023-01-27 03:47:31 +00:00
"default": None,
2023-01-23 18:15:05 -07:00
},
"draft": {
2023-01-24 13:53:46 -07:00
"help": "Do not make any changes, instead output what would be changed.",
2023-01-23 18:15:05 -07:00
},
},
)
2023-01-24 13:53:46 -07:00
def generate_changelog_md(ctx: Context, salt_version: str, draft: bool = False):
2023-01-27 03:47:31 +00:00
if salt_version is None:
salt_version = _get_salt_version()
cmd = ["towncrier", "build", f"--version={salt_version}"]
2023-01-23 18:15:05 -07:00
if draft:
cmd += ["--draft"]
2023-01-26 11:11:30 +00:00
else:
cmd += ["--yes"]
ctx.run(*cmd, check=True)
ctx.run("git", "restore", "--staged", "CHANGELOG.md", "changelog/", check=True)