Browse Source

add Changelog V3 format

master
Niklas Rosenstein 10 months ago
parent
commit
9cfafab52c
No known key found for this signature in database GPG Key ID: 6D269B33D25F6C6
2 changed files with 77 additions and 24 deletions
  1. + 5
    - 5
      src/shore/__main__.py
  2. + 72
    - 19
      src/shore/util/changelog.py

+ 5
- 5
src/shore/__main__.py

@ -34,7 +34,7 @@ from shore.core.plugins import (
from shore.mapper import mapper
from shore.model import Monorepo, ObjectCache, Package, VersionSelector
from shore.plugins.core import get_monorepo_interdependency_version_refs
from shore.util.changelog import ChangelogEntryV2, ChangelogTypeV2, ChangelogManager, render_changelogs
from shore.util.changelog import ChangelogV3, ChangelogManager, render_changelogs
from shore.util.classifiers import get_classifiers
from shore.util.license import get_license_metadata, wrap_license_text
from shore.util.resources import walk_package_resources
@ -807,12 +807,12 @@ def changelog(**args):
args['for'] = 'general'
try:
type_ = ChangelogTypeV2[args['add']]
type_ = ChangelogV3.Type[args['add']]
except KeyError:
logger.error('invalid changelog type: %r', args['add'])
sys.exit(1)
entry = ChangelogEntryV2(
entry = ChangelogV3.Entry(
type_,
args['for'],
args['message'] or '',
@ -821,8 +821,8 @@ def changelog(**args):
# Allow the user to edit the entry if no description is provided or the
# -e,--edit option was set.
if not entry.description or args['edit']:
serialized = yaml.safe_dump(mapper.serialize(entry, ChangelogEntryV2), sort_keys=False)
entry = mapper.deserialize(yaml.safe_load(_edit_text(serialized)), ChangelogEntryV2)
serialized = yaml.safe_dump(mapper.serialize(entry, ChangelogV3.Entry), sort_keys=False)
entry = mapper.deserialize(yaml.safe_load(_edit_text(serialized)), ChangelogV3.Entry)
# Validate the entry contents (need a description and at least one type and component).
if not entry.description or not entry.component:

+ 72
- 19
src/shore/util/changelog.py

@ -19,11 +19,12 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
from nr.databind.core import Field, FieldName, ObjectMapper, Struct
from nr.databind.core import Collection, Field, FieldName, ObjectMapper, Struct
from nr.stream import Stream
from shore.util.version import Version
from termcolor import colored
from typing import Iterable, List, Optional, TextIO
import datetime
import enum
import os
import re
@ -32,25 +33,36 @@ import textwrap
import yaml
class ChangelogEntryV1(Struct):
## changelog v1
class ChangelogV1Entry(Struct):
types = Field([str])
issues = Field([(str, int)], default=list)
components = Field([str])
description = Field(str)
def as_v2(self) -> 'ChangelogEntryV2':
def to_v3(self) -> 'ChangelogV3Entry':
try:
type_ = ChangelogTypeV2[self.types[0].strip().lower()]
type_ = ChangelogV3Type[self.types[0].strip().lower()]
except KeyError:
type_ = ChangelogTypeV2.change
return ChangelogEntryV2(
type_ = ChangelogV3Type.change
return ChangelogV3Entry(
type_,
self.components[0],
self.description,
list(map(str, self.issues)))
class ChangelogTypeV2(enum.Enum):
class ChangelogV1(Collection, list):
item_type = ChangelogV1Entry
def to_v3(self) -> 'ChangelogV3':
return ChangelogV3(None, [x.to_v3() for x in self])
## changelog v2
class ChangelogV2Type(enum.Enum):
fix = 0
improvement = 1
change = 3
@ -60,45 +72,83 @@ class ChangelogTypeV2(enum.Enum):
tests = 7
class ChangelogEntryV2(Struct):
type_ = Field(ChangelogTypeV2, FieldName('type'))
class ChangelogV2Entry(Struct):
type_ = Field(ChangelogV2Type, FieldName('type'))
component = Field(str)
description = Field(str)
fixes = Field([str])
def as_v2(self) -> 'ChangelogEntryV2':
return self
class ChangelogV2(Collection, list):
item_type = ChangelogV2Entry
def to_v3(self) -> 'ChangelogV3':
return ChangelogV3(None, list(self))
## changelog v3
ChangelogV3Type = ChangelogV2Type
ChangelogV3Entry = ChangelogV2Entry
class ChangelogV3(Struct):
release_date = Field(datetime.date, default=None)
changes = Field([ChangelogV3Entry])
Type = ChangelogV3Type
Entry = ChangelogV3Entry
## public API
class Changelog:
"""
Represents a changelog on disk.
"""
#: A mapping for the changelog renderers that are available. The default
#: renderer implementations are "terminal" and "markdown".
RENDERERS = {}
def __init__(self, filename: str, version: Optional[Version], mapper: ObjectMapper) -> None:
self.filename = filename
self.version = version
self.mapper = mapper
self.entries = []
self.data = ChangelogV3(changes=[])
def exists(self) -> bool:
" Returns #True if the changelog file exists. "
return os.path.isfile(self.filename)
def load(self) -> None:
" Loads the data from the file of this changelog. "
with open(self.filename) as fp:
data = yaml.safe_load(fp)
datatype = [(ChangelogEntryV2, ChangelogEntryV1)]
self.entries = self.mapper.deserialize(data, datatype, filename=self.filename)
self.entries = [x.as_v2() for x in self.entries]
raw_data = yaml.safe_load(fp)
datatype = (ChangelogV1, ChangelogV2, ChangelogV3)
data = self.mapper.deserialize(raw_data, datatype, filename=self.filename)
if isinstance(data, (ChangelogV1, ChangelogV2)):
data = data.to_v3()
self.data = data
def save(self, create_directory: bool = False) -> None:
" Saves the changelog. It will always save the changelog in the newest supported format. "
if create_directory:
os.makedirs(os.path.dirname(self.filename), exist_ok=True)
data = self.mapper.serialize(self.entries, [ChangelogEntryV2])
data = self.mapper.serialize(self.data, ChangelogV3)
with open(self.filename, 'w') as fp:
yaml.safe_dump(data, fp, sort_keys=False)
def add_entry(self, entry: ChangelogEntryV2) -> None:
self.entries.append(entry)
def set_release_date(self, date: datetime.date) -> None:
self.data.release_date = date
def add_entry(self, entry: ChangelogV2Entry) -> None:
self.data.entries.append(entry)
class ChangelogManager:
@ -152,6 +202,9 @@ class ChangelogManager:
yield self.version(version)
## changelog renderers
def _group_entries_by_component(entries):
key = lambda x: x.component
return list(Stream.sortby(entries, key).groupby(key, collect=list))

Loading…
Cancel
Save