parse-changelog 1.0.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- parse_changelog/VERSION +1 -0
- parse_changelog/__init__.py +11 -0
- parse_changelog-1.0.10.data/scripts/parse-changelog +292 -0
- parse_changelog-1.0.10.dist-info/LICENSE +21 -0
- parse_changelog-1.0.10.dist-info/METADATA +125 -0
- parse_changelog-1.0.10.dist-info/RECORD +8 -0
- parse_changelog-1.0.10.dist-info/WHEEL +5 -0
- parse_changelog-1.0.10.dist-info/top_level.txt +1 -0
parse_changelog/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.10
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
def get_version():
|
|
4
|
+
dir_path = os.path.dirname(os.path.realpath(__file__))
|
|
5
|
+
try:
|
|
6
|
+
with open(os.path.join(dir_path, "VERSION"), encoding="utf-8") as vf:
|
|
7
|
+
version = vf.read().strip()
|
|
8
|
+
except Exception: #pylint: disable=broad-exception-caught
|
|
9
|
+
version = "0.0.0"
|
|
10
|
+
|
|
11
|
+
return version
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
#!python
|
|
2
|
+
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
|
|
3
|
+
from collections import OrderedDict
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
import sys
|
|
9
|
+
import tempfile
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def add_release(changelog_file, new_release, release_date=None):
|
|
13
|
+
"""
|
|
14
|
+
Add a new release to the changelog, using the current content of the Unreleased section.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
changelog_file: (str) changelog file to parse
|
|
18
|
+
new_release: (str) version of the release to create
|
|
19
|
+
release_date: (datetime) date of the release (default to today)
|
|
20
|
+
"""
|
|
21
|
+
if not release_date:
|
|
22
|
+
release_date = datetime.now().strftime("%Y-%m-%d")
|
|
23
|
+
|
|
24
|
+
new_release_title = f"[{new_release}] - {release_date}"
|
|
25
|
+
|
|
26
|
+
changelog = parse(changelog_file)
|
|
27
|
+
|
|
28
|
+
if new_release in changelog:
|
|
29
|
+
print("Release already exists in changelog")
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
changelog[new_release] = {
|
|
33
|
+
"title": new_release_title,
|
|
34
|
+
"content": changelog["prerelease"]["content"],
|
|
35
|
+
"version": new_release,
|
|
36
|
+
"date": release_date
|
|
37
|
+
}
|
|
38
|
+
# Move the new release into the correct spot - move new release to the beginning, and then put prerelease and intro at the beginning
|
|
39
|
+
changelog.move_to_end(new_release, last=False)
|
|
40
|
+
changelog.move_to_end("prerelease", last=False)
|
|
41
|
+
changelog.move_to_end("introduction", last=False)
|
|
42
|
+
|
|
43
|
+
changelog["prerelease"]["content"] = ""
|
|
44
|
+
|
|
45
|
+
print(json.dumps(changelog, indent=2))
|
|
46
|
+
write_changelog(changelog_file, changelog)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def parse(changelog_file):
|
|
50
|
+
"""
|
|
51
|
+
Parse the changelog into JSON
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
changelog_file: (str) changelog file to parse
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
#
|
|
58
|
+
# Mode 2 - parse the changelog into a list of releases
|
|
59
|
+
#
|
|
60
|
+
try:
|
|
61
|
+
with open(changelog_file, "r", encoding="utf-8") as cf:
|
|
62
|
+
changelog = cf.read()
|
|
63
|
+
except FileNotFoundError:
|
|
64
|
+
print(f"Could not find {changelog_file}")
|
|
65
|
+
sys.exit(1)
|
|
66
|
+
|
|
67
|
+
# This parser is extremely simple and makes many assumptions about the structure of the document.
|
|
68
|
+
# Instead of parsing headings into a generic tree structure, assume the changelog format where there is a single
|
|
69
|
+
# heading1 node, a list of heading2 nodes that refer to releases, and 0 or more heading3 nodes per release that
|
|
70
|
+
# refer to types of changes
|
|
71
|
+
release_list = OrderedDict()
|
|
72
|
+
current_release = None
|
|
73
|
+
current_content = []
|
|
74
|
+
found_heading1 = False
|
|
75
|
+
version = "unknown"
|
|
76
|
+
rel_date = "unknown"
|
|
77
|
+
for line in changelog.split("\n"):
|
|
78
|
+
if line.startswith("#"):
|
|
79
|
+
heading_level = line.count("#")
|
|
80
|
+
title = line.strip("#").strip()
|
|
81
|
+
|
|
82
|
+
# Main heading, there should only be one
|
|
83
|
+
if heading_level == 1:
|
|
84
|
+
assert title.lower() == "changelog", "The top level heading1 must be named Changelog"
|
|
85
|
+
assert not found_heading1, "There can only be one heading1"
|
|
86
|
+
found_heading1 = True
|
|
87
|
+
continue
|
|
88
|
+
|
|
89
|
+
# Heading2, this indicates a release section
|
|
90
|
+
if heading_level == 2:
|
|
91
|
+
# A new release means stop parsing for the previous release
|
|
92
|
+
# Add the previous release to the document
|
|
93
|
+
if current_release:
|
|
94
|
+
if version != "unknown":
|
|
95
|
+
section_key = version
|
|
96
|
+
else:
|
|
97
|
+
section_key = current_release
|
|
98
|
+
release_list[section_key] = {
|
|
99
|
+
"title": current_release,
|
|
100
|
+
"content": "\n".join(current_content).rstrip(),
|
|
101
|
+
"version": version,
|
|
102
|
+
"date": rel_date}
|
|
103
|
+
else:
|
|
104
|
+
release_list["introduction"] = {
|
|
105
|
+
"title": "Changelog",
|
|
106
|
+
"content": "\n".join(current_content).rstrip(),
|
|
107
|
+
"version": "",
|
|
108
|
+
"date": ""
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
current_release = title
|
|
112
|
+
current_content = []
|
|
113
|
+
# Special case for Unreleased section
|
|
114
|
+
if title.lower() == "[unreleased]":
|
|
115
|
+
version = "prerelease"
|
|
116
|
+
rel_date = "unreleased"
|
|
117
|
+
else:
|
|
118
|
+
# Parse version and release date from the section title
|
|
119
|
+
m = re.match(
|
|
120
|
+
r"\[(\d+\.\d+\.\d+)[-\.+0-9a-zA-Z]*\]\s+-\s+(\d{4}-\d{2}-\d{2})", title)
|
|
121
|
+
if m:
|
|
122
|
+
version = m.group(1)
|
|
123
|
+
rel_date = m.group(2)
|
|
124
|
+
else:
|
|
125
|
+
version = "unknown"
|
|
126
|
+
rel_date = "unknown"
|
|
127
|
+
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
# Any other level is content inside a release
|
|
131
|
+
if heading_level >= 3:
|
|
132
|
+
current_content.append(line)
|
|
133
|
+
continue
|
|
134
|
+
|
|
135
|
+
# Anything other than a release line, add to the current content
|
|
136
|
+
current_content.append(line)
|
|
137
|
+
|
|
138
|
+
# Add the last section we found
|
|
139
|
+
if current_release:
|
|
140
|
+
if version != "unknown":
|
|
141
|
+
section_key = version
|
|
142
|
+
else:
|
|
143
|
+
section_key = current_release
|
|
144
|
+
release_list[section_key] = {
|
|
145
|
+
"title": current_release,
|
|
146
|
+
"content": "\n".join(current_content).rstrip(),
|
|
147
|
+
"version": version,
|
|
148
|
+
"date": rel_date}
|
|
149
|
+
|
|
150
|
+
return release_list
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def pretty_print(changelog_file, show_unreleased):
|
|
154
|
+
"""
|
|
155
|
+
Print changelog as JSON
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
changelog_file: (str) changelog file to parse
|
|
159
|
+
show_unreleased: (bool) only show the unreleased section
|
|
160
|
+
"""
|
|
161
|
+
changelog = parse(changelog_file)
|
|
162
|
+
|
|
163
|
+
# Only show the unreleased changes section
|
|
164
|
+
if show_unreleased:
|
|
165
|
+
print(changelog.get("prerelease", {}).get("content", ""))
|
|
166
|
+
return
|
|
167
|
+
|
|
168
|
+
# Show what we parsed, in JSON format
|
|
169
|
+
print(json.dumps(changelog, indent=2))
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def add_change(changelog_file, change_desc, change_type):
|
|
173
|
+
change_type = change_type.title()
|
|
174
|
+
if not change_desc.startswith("*"):
|
|
175
|
+
change_desc = "* " + change_desc
|
|
176
|
+
change_desc.rstrip()
|
|
177
|
+
|
|
178
|
+
changelog = parse(changelog_file)
|
|
179
|
+
prerelease = changelog.get("prerelease", {})
|
|
180
|
+
if not prerelease:
|
|
181
|
+
prerelease = {
|
|
182
|
+
"title": "[Unreleased]",
|
|
183
|
+
"content": "",
|
|
184
|
+
"version": "prerelease",
|
|
185
|
+
"date": "unreleased"
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
# Insert the new change at the appropriate section
|
|
189
|
+
content = prerelease.get("content", "")
|
|
190
|
+
new_content = ""
|
|
191
|
+
found = False
|
|
192
|
+
for line in content.split("\n"):
|
|
193
|
+
if re.search(r"^###\s+" + change_type, line, re.IGNORECASE):
|
|
194
|
+
found = True
|
|
195
|
+
# insert the new change description
|
|
196
|
+
if not new_content.endswith("\n"):
|
|
197
|
+
new_content += "\n"
|
|
198
|
+
new_content += line
|
|
199
|
+
if not new_content.endswith("\n"):
|
|
200
|
+
new_content += "\n"
|
|
201
|
+
new_content += change_desc + "\n"
|
|
202
|
+
else:
|
|
203
|
+
new_content += line
|
|
204
|
+
if not new_content.endswith("\n"):
|
|
205
|
+
new_content += "\n"
|
|
206
|
+
prerelease["content"] = new_content.rstrip()
|
|
207
|
+
if not found:
|
|
208
|
+
prerelease["content"] += f"\n### {change_type}\n{change_desc}"
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
changelog["prerelease"] = prerelease
|
|
212
|
+
|
|
213
|
+
print(json.dumps(changelog, indent=2))
|
|
214
|
+
write_changelog(changelog_file, changelog)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def write_changelog(changelog_file, content):
|
|
218
|
+
"""
|
|
219
|
+
Write out a changelog from the JSON structure
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
changelog_file: (str) changelog file to parse
|
|
223
|
+
content: (OrderedDict) content to write to the changelog
|
|
224
|
+
"""
|
|
225
|
+
target_path = os.path.abspath(changelog_file)
|
|
226
|
+
target_dir = os.path.dirname(target_path) or "."
|
|
227
|
+
new_changelog = None
|
|
228
|
+
try:
|
|
229
|
+
with tempfile.NamedTemporaryFile("w", encoding="utf-8", dir=target_dir, delete=False) as tmp:
|
|
230
|
+
new_changelog = tmp.name
|
|
231
|
+
tmp.write("# Changelog\n")
|
|
232
|
+
intro = content.pop("introduction", {}).get("content", "")
|
|
233
|
+
tmp.write(f"{intro}\n")
|
|
234
|
+
tmp.write("\n")
|
|
235
|
+
|
|
236
|
+
for idx, heading in enumerate(content):
|
|
237
|
+
tmp.write(f"## {content[heading]['title']}\n")
|
|
238
|
+
if content[heading]["content"]:
|
|
239
|
+
tmp.write(content[heading]["content"] + "\n")
|
|
240
|
+
if idx < len(content)-1:
|
|
241
|
+
tmp.write("\n")
|
|
242
|
+
os.replace(new_changelog, target_path)
|
|
243
|
+
finally:
|
|
244
|
+
# Make sure intermediate file is removed
|
|
245
|
+
if new_changelog:
|
|
246
|
+
try:
|
|
247
|
+
os.remove(new_changelog)
|
|
248
|
+
except FileNotFoundError:
|
|
249
|
+
pass
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def get_version():
|
|
253
|
+
try:
|
|
254
|
+
import parse_changelog
|
|
255
|
+
return parse_changelog.get_version()
|
|
256
|
+
except ImportError:
|
|
257
|
+
return "0.0.0"
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
if __name__ == "__main__":
|
|
261
|
+
change_types = ["added", "changed", "deprecated", "removed", "fixed", "security"]
|
|
262
|
+
|
|
263
|
+
parser = ArgumentParser(description="Parse and update changelog files",
|
|
264
|
+
formatter_class=ArgumentDefaultsHelpFormatter)
|
|
265
|
+
# Common args
|
|
266
|
+
parser.add_argument("--changelog", "-c", dest="changelog_file", default="CHANGELOG.md",
|
|
267
|
+
help="the changelog file to parse")
|
|
268
|
+
parser.add_argument("--version", "-v", action="version",
|
|
269
|
+
version=get_version())
|
|
270
|
+
# Args for parsing
|
|
271
|
+
parsing_group = parser.add_argument_group(title="Parsing")
|
|
272
|
+
parsing_group.add_argument("--show-unreleased", "-u", dest="show_unreleased", action="store_true",
|
|
273
|
+
help="When parsing, only show the changes from the Unreleased section")
|
|
274
|
+
# Args for creating a release
|
|
275
|
+
release_group = parser.add_argument_group("Adding a Release")
|
|
276
|
+
release_group.add_argument("--release", "-r", dest="new_release", metavar="X.Y.Z",
|
|
277
|
+
help="Create a new release by moving the Unreleased section to the specified new release section")
|
|
278
|
+
release_group.add_argument("--date", "-d", dest="release_date", metavar="YYYY-MM-DD",
|
|
279
|
+
help="Use this date for the new release, instead of today")
|
|
280
|
+
# Args for adding changes
|
|
281
|
+
change_group = parser.add_argument_group("Adding a change")
|
|
282
|
+
change_group.add_argument("--add-change", "-a", dest="change_desc", metavar="TEXT", help="One-line description of the change")
|
|
283
|
+
change_group.add_argument("--type", "-t", dest="change_type", metavar="TYPE", choices=change_types, help=f"The type of change {change_types}")
|
|
284
|
+
|
|
285
|
+
args = parser.parse_args()
|
|
286
|
+
|
|
287
|
+
if args.new_release:
|
|
288
|
+
add_release(args.changelog_file, args.new_release, args.release_date)
|
|
289
|
+
elif args.change_desc:
|
|
290
|
+
add_change(args.changelog_file, args.change_desc, args.change_type)
|
|
291
|
+
else:
|
|
292
|
+
pretty_print(args.changelog_file, args.show_unreleased)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Carl Seelye
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: parse-changelog
|
|
3
|
+
Version: 1.0.10
|
|
4
|
+
Summary: A very simplistic changelog parser/updater
|
|
5
|
+
Home-page: https://github.com/cseelye/parse-changelog
|
|
6
|
+
Author: Carl Seelye
|
|
7
|
+
Author-email: cseelye@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Dynamic: author
|
|
12
|
+
Dynamic: author-email
|
|
13
|
+
Dynamic: description
|
|
14
|
+
Dynamic: description-content-type
|
|
15
|
+
Dynamic: home-page
|
|
16
|
+
Dynamic: license
|
|
17
|
+
Dynamic: summary
|
|
18
|
+
|
|
19
|
+
# parse-changelog
|
|
20
|
+
This is a simplified changelog updater/parser, made for CI pipeline use. It has these abilities:
|
|
21
|
+
1. Add a new change to the changelog, in the Unreleased section
|
|
22
|
+
1. Add a new release into the changelog, using the list of changes from the Unreleased section
|
|
23
|
+
1. Parse the releases in the changelog into a JSON structure.
|
|
24
|
+
|
|
25
|
+
Changelogs must be in the format documented by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), see the details
|
|
26
|
+
below.
|
|
27
|
+
|
|
28
|
+
Release history: [parse-changelog's CHANGELOG](https://github.com/cseelye/parse-changelog/blob/main/CHANGELOG.md)
|
|
29
|
+
|
|
30
|
+
## Adding a Release
|
|
31
|
+
This mode is invoked by using the `--release` arg and will parse the changelog and insert a new release at the beginning
|
|
32
|
+
of the list of releases, using the changes from the Unreleased section. You can optionally specify a release date, or by
|
|
33
|
+
default use todays date.
|
|
34
|
+
|
|
35
|
+
The changelog must use the format `## [Unreleased]` (case insensitive) for this parser to find it.
|
|
36
|
+
For example, here is the diff generated by adding a new release(`--release 1.0.2`):
|
|
37
|
+
```
|
|
38
|
+
## [Unreleased]
|
|
39
|
+
+
|
|
40
|
+
+## [1.0.2] - 2022-10-20
|
|
41
|
+
* Great new stuff
|
|
42
|
+
|
|
43
|
+
## [1.0.1] - 2022-10-08
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Adding a Change
|
|
47
|
+
This mode is invoked with the `--add-change` and `--type` args. It will parse the changelog to find the Unreleased
|
|
48
|
+
section and any changes already there, find the correct change type heading, and add the new change.
|
|
49
|
+
For example, here is the diff generated by adding a new fix (`--add-change "Fix that annoying bug" --type fixed`):
|
|
50
|
+
```
|
|
51
|
+
## [Unreleased]
|
|
52
|
+
* Great new stuff
|
|
53
|
+
+### Fixed
|
|
54
|
+
+* Fix that annoying bug
|
|
55
|
+
|
|
56
|
+
## [1.0.1] - 2022-10-08
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Changelog Parsing
|
|
60
|
+
This mode will parse the changelog into JSON and print it to the screen. It finds all of
|
|
61
|
+
the heading2 entries (lines starting with `##`) and assumes each of those is a release. For each release, it parses
|
|
62
|
+
the release title into version and date, and collects the content of the release as a single string. Each release
|
|
63
|
+
heading must be of the format `## [release_version] - YYYY-MM-DD`, where `release_version` matches SemVer version string
|
|
64
|
+
spec, and `YYYY-MM-DD` is a valid year-month-day. The one exception to this format is the special release heading for
|
|
65
|
+
unreleased changes, which must match `## [Unreleased]`. The content of the release is parsed as a single string and not
|
|
66
|
+
interpreted in any way.
|
|
67
|
+
|
|
68
|
+
The top heading1 and project description are parsed into a special section named "introduction".
|
|
69
|
+
|
|
70
|
+
For example, given the following changelog:
|
|
71
|
+
```
|
|
72
|
+
# Changelog
|
|
73
|
+
|
|
74
|
+
My Project Name
|
|
75
|
+
|
|
76
|
+
All notable changes to this project will be documented in this file.
|
|
77
|
+
|
|
78
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
79
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
80
|
+
|
|
81
|
+
## [Unreleased]
|
|
82
|
+
* Great new stuff
|
|
83
|
+
|
|
84
|
+
## [1.0.1] - 2022-10-08
|
|
85
|
+
### Fixed
|
|
86
|
+
* Minor bug that we missed
|
|
87
|
+
### Changed
|
|
88
|
+
* New name for an artifact
|
|
89
|
+
|
|
90
|
+
## [1.0.0] - 2022-09-01
|
|
91
|
+
Initial release
|
|
92
|
+
* Some cool feature
|
|
93
|
+
* Other interesting stuff
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
It will be parsed into this JSON:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
{
|
|
100
|
+
"introduction": {
|
|
101
|
+
"title": "Changelog",
|
|
102
|
+
"content": "\nMy Project Name\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).",
|
|
103
|
+
"version": "",
|
|
104
|
+
"date": ""
|
|
105
|
+
},
|
|
106
|
+
"prerelease": {
|
|
107
|
+
"title": "[Unreleased]",
|
|
108
|
+
"content": "* Great new stuff",
|
|
109
|
+
"version": "prerelease",
|
|
110
|
+
"date": "unreleased"
|
|
111
|
+
},
|
|
112
|
+
"[1.0.1] - 2022-10-08": {
|
|
113
|
+
"title": "[1.0.1] - 2022-10-08",
|
|
114
|
+
"content": "### Fixed\n* Minor bug that we missed\n### Changed\n* New name for an artifact",
|
|
115
|
+
"version": "1.0.1",
|
|
116
|
+
"date": "2022-10-08"
|
|
117
|
+
},
|
|
118
|
+
"[1.0.0] - 2022-09-01": {
|
|
119
|
+
"title": "[1.0.0] - 2022-09-01",
|
|
120
|
+
"content": "Initial release\n* Some cool feature\n* Other interesting stuff",
|
|
121
|
+
"version": "1.0.0",
|
|
122
|
+
"date": "2022-09-01"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
parse_changelog/VERSION,sha256=ACUb7h0D9ljCMkkmeFqZbdBA3_Fr-ZOyxSCiDtu6csg,7
|
|
2
|
+
parse_changelog/__init__.py,sha256=C1Qe0BVPxa61b441fKYGAf8Qd7XyHgBYDwR8F-RJxlA,324
|
|
3
|
+
parse_changelog-1.0.10.data/scripts/parse-changelog,sha256=Dt5md5ZmhQ9Cge6v3l--X7rL1NK2wiy8HMDUSXdqdz8,10762
|
|
4
|
+
parse_changelog-1.0.10.dist-info/LICENSE,sha256=Imudq40fjwY04eXGz5ObRd0xy51LT7X_jEphYX-9Y8Q,1068
|
|
5
|
+
parse_changelog-1.0.10.dist-info/METADATA,sha256=BfG0kAk8APC9W4wInj2Bjgq9BhhH5n7Qsh5i7N67Fjg,4383
|
|
6
|
+
parse_changelog-1.0.10.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
|
|
7
|
+
parse_changelog-1.0.10.dist-info/top_level.txt,sha256=scKFCMsZgB5m8oBmtrjV8iybGgm8pXaWF0XqfC6oLuY,16
|
|
8
|
+
parse_changelog-1.0.10.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
parse_changelog
|