python-kacl 0.7.4__tar.gz → 0.7.6__tar.gz
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.
- {python_kacl-0.7.4/python_kacl.egg-info → python_kacl-0.7.6}/PKG-INFO +1 -1
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/__init__.py +1 -1
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/document.py +23 -14
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/kacl_cli.py +7 -2
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/version.py +34 -4
- {python_kacl-0.7.4 → python_kacl-0.7.6}/pyproject.toml +1 -1
- {python_kacl-0.7.4 → python_kacl-0.7.6/python_kacl.egg-info}/PKG-INFO +1 -1
- {python_kacl-0.7.4 → python_kacl-0.7.6}/tests/test_cli_workflow.py +41 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/tests/test_kacl.py +23 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/LICENSE +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/MANIFEST.in +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/README.md +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/__main__.py +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/changes.py +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/config/kacl-default.yml +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/config.py +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/element.py +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/exception.py +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/jira_client.py +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/link_provider.py +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/parser.py +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/serializer.py +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/utils.py +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/kacl/validation.py +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/python_kacl.egg-info/SOURCES.txt +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/python_kacl.egg-info/dependency_links.txt +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/python_kacl.egg-info/entry_points.txt +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/python_kacl.egg-info/not-zip-safe +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/python_kacl.egg-info/requires.txt +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/python_kacl.egg-info/top_level.txt +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/requirements.txt +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/setup.cfg +0 -0
- {python_kacl-0.7.4 → python_kacl-0.7.6}/tests/test_cli.py +0 -0
|
@@ -74,20 +74,29 @@ class KACLDocument:
|
|
|
74
74
|
if not os.path.isdir(local_stash_dir):
|
|
75
75
|
return
|
|
76
76
|
|
|
77
|
-
# read all md files in the stash directory
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
77
|
+
# read all md files in the stash directory (including legacy
|
|
78
|
+
# sub-directories created by branch names containing a slash)
|
|
79
|
+
for md_file in self.stash_files():
|
|
80
|
+
with open(md_file, "r") as fh:
|
|
81
|
+
data = fh.read()
|
|
82
|
+
try:
|
|
83
|
+
doc = KACLDocument.parse(data, None)
|
|
84
|
+
# stash documents must be validated against the same
|
|
85
|
+
# config as the changelog they belong to
|
|
86
|
+
doc.config = self.config
|
|
87
|
+
self.stash.append(doc)
|
|
88
|
+
except Exception:
|
|
89
|
+
continue
|
|
90
|
+
|
|
91
|
+
def stash_files(self):
|
|
92
|
+
"""Returns the paths of all stash files, including nested ones."""
|
|
93
|
+
stash_dir = self._ensure_stash_directory()
|
|
94
|
+
files = []
|
|
95
|
+
for root, _, names in os.walk(stash_dir):
|
|
96
|
+
for name in sorted(names):
|
|
97
|
+
if name.endswith(".md"):
|
|
98
|
+
files.append(os.path.join(root, name))
|
|
99
|
+
return sorted(files)
|
|
91
100
|
|
|
92
101
|
def _ensure_stash_directory(self):
|
|
93
102
|
# the stash needs always to be relative to the current file_path
|
|
@@ -545,11 +545,16 @@ def release(
|
|
|
545
545
|
|
|
546
546
|
# delete all file in the stash directory
|
|
547
547
|
stash_files = []
|
|
548
|
-
for
|
|
549
|
-
stash_file = os.path.join(kacl_changelog.stash_directory, f)
|
|
548
|
+
for stash_file in kacl_changelog.stash_files():
|
|
550
549
|
os.remove(stash_file)
|
|
551
550
|
stash_files.append(stash_file)
|
|
552
551
|
|
|
552
|
+
# remove sub-directories left empty (legacy branch names with slashes)
|
|
553
|
+
stash_dir = kacl_changelog.stash_directory
|
|
554
|
+
for root, _, _ in os.walk(stash_dir, topdown=False):
|
|
555
|
+
if root != stash_dir and not os.listdir(root):
|
|
556
|
+
os.rmdir(root)
|
|
557
|
+
|
|
553
558
|
if commit or tag or kacl_config.git_create_commit or kacl_config.git_create_tag:
|
|
554
559
|
vcs_context = {
|
|
555
560
|
"latest_version": latest_version,
|
|
@@ -105,6 +105,24 @@ class KACLVersion(KACLElement):
|
|
|
105
105
|
self.__sections[sec.title()] = sec
|
|
106
106
|
return self.__sections
|
|
107
107
|
|
|
108
|
+
def duplicate_sections(self):
|
|
109
|
+
"""Returns every section element whose title was already used earlier in this version."""
|
|
110
|
+
if not self.body().strip():
|
|
111
|
+
return []
|
|
112
|
+
|
|
113
|
+
seen = set()
|
|
114
|
+
duplicates = []
|
|
115
|
+
for section in KACLParser.parse_header(
|
|
116
|
+
text=self.body(),
|
|
117
|
+
start_depth=3,
|
|
118
|
+
end_depth=3,
|
|
119
|
+
line_offset=self.line_number(),
|
|
120
|
+
):
|
|
121
|
+
if section.title() in seen:
|
|
122
|
+
duplicates.append(section)
|
|
123
|
+
seen.add(section.title())
|
|
124
|
+
return duplicates
|
|
125
|
+
|
|
108
126
|
def changes(self, section):
|
|
109
127
|
sections = self.sections()
|
|
110
128
|
if sections and section in sections:
|
|
@@ -200,11 +218,23 @@ class KACLVersion(KACLElement):
|
|
|
200
218
|
try:
|
|
201
219
|
sections = self.sections()
|
|
202
220
|
except ValueError as e:
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
221
|
+
duplicates = self.duplicate_sections()
|
|
222
|
+
if not duplicates:
|
|
223
|
+
errors.append(
|
|
224
|
+
KACLValidationError(
|
|
225
|
+
error_message=str(e), line_number=self.line_number()
|
|
226
|
+
)
|
|
227
|
+
)
|
|
228
|
+
for duplicate in duplicates:
|
|
229
|
+
errors.append(
|
|
230
|
+
KACLValidationError(
|
|
231
|
+
line=duplicate.raw(),
|
|
232
|
+
line_number=duplicate.line_number(),
|
|
233
|
+
error_message=f"Version '{self.version()}' has multiple sections with title '{duplicate.title()}'",
|
|
234
|
+
start_character_pos=0,
|
|
235
|
+
end_character_pos=len(duplicate.raw()),
|
|
236
|
+
)
|
|
206
237
|
)
|
|
207
|
-
)
|
|
208
238
|
return errors
|
|
209
239
|
|
|
210
240
|
for title, element in sections.items():
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-kacl"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.6"
|
|
8
8
|
description = "Python module and CLI tool for validating and modifying Changelogs in \"keep-a-changelog\" format\""
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -182,3 +182,44 @@ def test_integration_workflow_config(tmp_path, snapshot):
|
|
|
182
182
|
|
|
183
183
|
assert result.exit_code == 0, result.output
|
|
184
184
|
snapshot_directory(snapshot=snapshot, directory_path=project_root_path)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def test_release_with_nested_stash_directory(tmp_path):
|
|
188
|
+
runner = CliRunner()
|
|
189
|
+
resources_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/")
|
|
190
|
+
changelog_file = os.path.join(resources_dir, "CHANGELOG_with_changes.md")
|
|
191
|
+
config = os.path.join(resources_dir, "stash-config.yml")
|
|
192
|
+
|
|
193
|
+
with runner.isolated_filesystem(temp_dir=tmp_path) as project_root_path:
|
|
194
|
+
shutil.copyfile(changelog_file, os.path.join(project_root_path, "CHANGELOG.md"))
|
|
195
|
+
|
|
196
|
+
# stash file for a branch like "refactor/foo" written by older versions
|
|
197
|
+
result = runner.invoke(
|
|
198
|
+
cli,
|
|
199
|
+
[
|
|
200
|
+
"-c",
|
|
201
|
+
config,
|
|
202
|
+
"-f",
|
|
203
|
+
"CHANGELOG.md",
|
|
204
|
+
"add",
|
|
205
|
+
"--stash",
|
|
206
|
+
"-m",
|
|
207
|
+
"Changed",
|
|
208
|
+
"x",
|
|
209
|
+
],
|
|
210
|
+
catch_exceptions=False,
|
|
211
|
+
)
|
|
212
|
+
assert result.exit_code == 0, result.output
|
|
213
|
+
stash_dir = os.path.join(project_root_path, ".kacl_stash")
|
|
214
|
+
flat = os.path.join(stash_dir, os.listdir(stash_dir)[0])
|
|
215
|
+
nested_dir = os.path.join(stash_dir, "refactor")
|
|
216
|
+
os.makedirs(nested_dir)
|
|
217
|
+
shutil.move(flat, os.path.join(nested_dir, "foo.md"))
|
|
218
|
+
|
|
219
|
+
result = runner.invoke(
|
|
220
|
+
cli,
|
|
221
|
+
["-c", config, "-f", "CHANGELOG.md", "release", "99.0.0", "-m"],
|
|
222
|
+
catch_exceptions=False,
|
|
223
|
+
)
|
|
224
|
+
assert result.exit_code == 0, result.output
|
|
225
|
+
assert os.listdir(stash_dir) == []
|
|
@@ -657,3 +657,26 @@ def test_release_no_unreleased_multiple_versions(tmp_path):
|
|
|
657
657
|
second_version_after = versions_after[1]
|
|
658
658
|
# The link might be updated during auto-link, but shouldn't be broken
|
|
659
659
|
assert second_version_after.link() is not None
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
def test_validate_reports_every_duplicated_section():
|
|
663
|
+
changelog = kacl.parse(
|
|
664
|
+
"# Changelog\n\n"
|
|
665
|
+
"All notable changes to this project will be documented in this file.\n\n"
|
|
666
|
+
"The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), "
|
|
667
|
+
"and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n"
|
|
668
|
+
"## [Unreleased]\n\n"
|
|
669
|
+
"### Added\n\n- a\n\n"
|
|
670
|
+
"### Changed\n\n- b\n\n"
|
|
671
|
+
"### Added\n\n- a again\n\n"
|
|
672
|
+
"### Changed\n\n- b again\n\n"
|
|
673
|
+
)
|
|
674
|
+
errors = [
|
|
675
|
+
e
|
|
676
|
+
for e in changelog.validate().errors()
|
|
677
|
+
if "multiple sections" in e.error_message()
|
|
678
|
+
]
|
|
679
|
+
assert [(e.line_number(), e.line()) for e in errors] == [
|
|
680
|
+
(17, "### Added"),
|
|
681
|
+
(21, "### Changed"),
|
|
682
|
+
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|