python-kacl 0.6.5__py3-none-any.whl → 0.6.7__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.
kacl/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # Version of the python-kacl package
2
- __version__ = "0.6.5"
2
+ __version__ = "0.6.7"
3
3
 
4
4
  from kacl.document import KACLDocument
5
5
  from kacl.serializer import KACLMarkdownSerializer
@@ -14,14 +14,14 @@ def load(file):
14
14
  with open(file, "r") as f:
15
15
  document = f.read()
16
16
  try:
17
- doc = KACLDocument.parse(document)
17
+ doc = KACLDocument.parse(document, file)
18
18
  finally:
19
19
  f.close()
20
20
  return doc
21
21
 
22
22
 
23
- def parse(text):
24
- return KACLDocument.parse(text)
23
+ def parse(text, file=None):
24
+ return KACLDocument.parse(text, file)
25
25
 
26
26
 
27
27
  def dump(document):
kacl/changes.py CHANGED
@@ -11,6 +11,8 @@ class KACLChanges(KACLElement):
11
11
  line_number=element.line_number(),
12
12
  )
13
13
  self.__items = []
14
+ # initializes
15
+ self.items()
14
16
 
15
17
  def items(self):
16
18
  if not len(self.__items) and len(self.body().strip()):
@@ -13,6 +13,8 @@ kacl:
13
13
  default_content:
14
14
  - All notable changes to this project will be documented in this file.
15
15
  - The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
16
+ release:
17
+ add_unreleased: True
16
18
  git:
17
19
  commit: False
18
20
  commit_message: "[skip ci] Releasing Changelog version {new_version}"
@@ -45,4 +47,6 @@ kacl:
45
47
  ## 🧭 Reference
46
48
 
47
49
  Code: [Source Code Management System]({link})
48
-
50
+ stash:
51
+ directory: .kacl_stash
52
+ always: False
kacl/config.py CHANGED
@@ -20,6 +20,9 @@ class KACLConfig:
20
20
  self.allowed_header_titles = self.__config.get("allowed_header_titles")
21
21
  self.allowed_version_sections = self.__config.get("allowed_version_sections")
22
22
  self.default_content = self.__config.get("default_content")
23
+ self.add_unreleased = self.__config.get("release", {}).get(
24
+ "add_unreleased", True
25
+ )
23
26
  self.git_tag_name = self.__config.get("git", {}).get("tag_name")
24
27
  self.git_tag_description = self.__config.get("git", {}).get("tag_description")
25
28
  self.changelog_file_path = self.__config.get("file")
@@ -72,6 +75,9 @@ class KACLConfig:
72
75
  if not self.issue_tracker_jira_password:
73
76
  self.issue_tracker_jira_password = os.getenv("JIRA_PASSWORD", None)
74
77
 
78
+ self.stash_dir = self.__config.get("stash", {}).get("dir", ".kacl_stash")
79
+ self.stash_always = self.__config.get("stash", {}).get("always", False)
80
+
75
81
  @staticmethod
76
82
  def merge(a, b, path=None):
77
83
  """merge two dictionaries
kacl/document.py CHANGED
@@ -4,6 +4,7 @@ import os
4
4
  import git
5
5
  import semver
6
6
 
7
+ import kacl
7
8
  from kacl.config import KACLConfig
8
9
  from kacl.element import KACLElement
9
10
  from kacl.exception import KACLException
@@ -28,6 +29,7 @@ class KACLDocument:
28
29
  versions=None,
29
30
  link_references=None,
30
31
  meta_data=None,
32
+ file_path=None,
31
33
  config=KACLConfig(),
32
34
  ):
33
35
  self.__data = data
@@ -38,6 +40,80 @@ class KACLDocument:
38
40
  self.__link_references = dict()
39
41
  self.__meta_data = meta_data
40
42
  self.config = config
43
+ self.stash = []
44
+ self.file_path = file_path
45
+
46
+ @property
47
+ def stash_directory(self):
48
+ return self._ensure_stash_directory()
49
+
50
+ def load_stash(self):
51
+ self._refresh_stash()
52
+ # get all unreleased changes from stash
53
+ for stashed_changelog in self.stash:
54
+ unreleased_stash_version = stashed_changelog.get("Unreleased")
55
+ for title, change in unreleased_stash_version.sections().items():
56
+ for change_item in change.items():
57
+ self.add(section=title, data=change_item)
58
+
59
+ def _refresh_stash(self):
60
+ if not self.file_path:
61
+ return
62
+
63
+ self.stash = []
64
+ if self.file_path is None:
65
+ local_stash_dir = os.path.join(
66
+ os.path.abspath(os.getcwd()), self.config.stash_dir
67
+ )
68
+ else:
69
+ # the stash needs always to be relative to the current file_path
70
+ local_stash_dir = os.path.join(
71
+ os.path.abspath(os.path.dirname(self.file_path)), self.config.stash_dir
72
+ )
73
+
74
+ if not os.path.isdir(local_stash_dir):
75
+ return
76
+
77
+ # read all md files in the stash directory
78
+ for f in os.listdir(local_stash_dir):
79
+ if f.endswith(".md"):
80
+ md_file = os.path.join(local_stash_dir, f)
81
+ with open(md_file, "r") as fh:
82
+ data = fh.read()
83
+ try:
84
+ doc = KACLDocument.parse(data, None)
85
+ self.stash.append(doc)
86
+ except Exception:
87
+ continue
88
+
89
+ def _ensure_stash_directory(self):
90
+ # the stash needs always to be relative to the current file_path
91
+ local_stash_dir = os.path.join(
92
+ os.path.abspath(os.path.dirname(self.file_path)), self.config.stash_dir
93
+ )
94
+
95
+ if not os.path.isdir(local_stash_dir):
96
+ os.makedirs(local_stash_dir, exist_ok=True)
97
+
98
+ return local_stash_dir
99
+
100
+ def _get_stash_file(self):
101
+ # the stash file should be named after the current git branch
102
+ local_stash_dir = self._ensure_stash_directory()
103
+ try:
104
+ repo = git.Repo(
105
+ os.path.abspath(os.path.dirname(self.file_path)),
106
+ search_parent_directories=True,
107
+ )
108
+ branch_name = repo.active_branch.name
109
+ # sanitize branch name for filename
110
+ branch_name = branch_name.replace("/", "__").replace("\\", "_")
111
+ stash_file_name = f"{branch_name}.md"
112
+ except Exception:
113
+ # fallback to with date
114
+ stash_file_name = f"{datetime.datetime.now().strftime('%Y%m%d')}.md"
115
+
116
+ return os.path.join(local_stash_dir, stash_file_name)
41
117
 
42
118
  def validate(self):
43
119
  """Validates the current changelog and returns KACLValidation object containing all information
@@ -46,6 +122,14 @@ class KACLDocument:
46
122
  [KACLValidation] -- object holding all error information
47
123
  """
48
124
  validation = KACLValidation()
125
+
126
+ # first load the stash
127
+ self._refresh_stash()
128
+ for stashed_changelog in self.stash:
129
+ val = stashed_changelog.validate()
130
+ for e in val.errors():
131
+ validation.add(e)
132
+
49
133
  # 1. assert only one header and starts on first line
50
134
  if len(self.__headers) == 0:
51
135
  validation.add_error(
@@ -213,18 +297,38 @@ class KACLDocument:
213
297
 
214
298
  return False
215
299
 
216
- def add(self, section, data):
300
+ def add(self, section, data, stash=False):
217
301
  """adds a new change to a given section in the 'unreleased' version
218
302
 
219
303
  Arguments:
220
304
  section {[str]} -- section to add data to
221
305
  data {[str]} -- change information
306
+ stash {[bool]} -- if true the change will be stashed instead of added to the changelog (default: {False})
222
307
  """
223
- unreleased_version = self.get("Unreleased")
224
- if unreleased_version is None:
225
- unreleased_version = KACLVersion(version="Unreleased")
226
- self.__versions.insert(0, unreleased_version)
227
- unreleased_version.add(section.capitalize(), data)
308
+
309
+ if stash:
310
+ # check if the stash directory already contains the required changelog file, if not initialize it
311
+ stash_file = self._get_stash_file()
312
+
313
+ if not os.path.exists(stash_file):
314
+ kacl_changelog = kacl.new()
315
+ kacl_changelog_content = kacl.dump(kacl_changelog)
316
+ with open(stash_file, "w") as f:
317
+ f.write(kacl_changelog_content)
318
+ f.close()
319
+
320
+ kacl_changelog = kacl.load(stash_file)
321
+ kacl_changelog.add(section.capitalize(), data)
322
+ kacl_changelog_content = kacl.dump(kacl_changelog)
323
+ with open(stash_file, "w") as f:
324
+ f.write(kacl_changelog_content)
325
+ f.close()
326
+ else:
327
+ unreleased_version = self.get("Unreleased")
328
+ if unreleased_version is None:
329
+ unreleased_version = KACLVersion(version="Unreleased")
330
+ self.__versions.insert(0, unreleased_version)
331
+ unreleased_version.add(section.capitalize(), data)
228
332
 
229
333
  def release(
230
334
  self,
@@ -326,13 +430,9 @@ class KACLDocument:
326
430
  # remove current unrelease version from list
327
431
  self.__versions.pop(0)
328
432
 
329
- self.__versions.insert(
330
- 0, KACLVersion(version="Unreleased", link=unreleased_version.link())
331
- )
332
-
333
433
  # convert unreleased version to version
334
434
  self.__versions.insert(
335
- 1,
435
+ 0,
336
436
  KACLVersion(
337
437
  version=version,
338
438
  link=KACLElement(title=version, body=link),
@@ -341,6 +441,11 @@ class KACLDocument:
341
441
  ),
342
442
  )
343
443
 
444
+ if self.config.add_unreleased:
445
+ self.__versions.insert(
446
+ 0, KACLVersion(version="Unreleased", link=unreleased_version.link())
447
+ )
448
+
344
449
  if auto_link:
345
450
  link_provider = self.__get_link_provider()
346
451
  for i in range(2):
@@ -584,7 +689,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
584
689
  )
585
690
 
586
691
  @staticmethod
587
- def parse(data):
692
+ def parse(data, file=None):
588
693
  """Parses a given text object and returns the KACLDocument
589
694
 
590
695
  Arguments:
@@ -624,6 +729,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
624
729
  versions=versions,
625
730
  link_references=link_references,
626
731
  meta_data=meta_data,
732
+ file_path=file,
627
733
  )
628
734
 
629
735
  def __get_link_provider(
kacl/kacl_cli.py CHANGED
@@ -69,6 +69,7 @@ def load_changelog(ctx):
69
69
  # read the changelog
70
70
  kacl_changelog = kacl.load(kacl_config.changelog_file_path)
71
71
  kacl_changelog.config = kacl_config
72
+ kacl_changelog.load_stash()
72
73
 
73
74
  # share the objects
74
75
  return kacl_changelog
@@ -128,17 +129,32 @@ def cli(ctx, version=None, config=None, file=None):
128
129
  is_flag=True,
129
130
  help="This option will add the changes directly into changelog file.",
130
131
  )
131
- def add(ctx, section, message, modify):
132
+ @click.option(
133
+ "-s",
134
+ "--stash",
135
+ is_flag=True,
136
+ help="This option will stash changes instead of applying them.",
137
+ )
138
+ def add(ctx, section, message, modify, stash):
132
139
  """Adds a given message to a specified unreleased section. Use '--modify' to directly modify the changelog file."""
133
140
  kacl_changelog = load_changelog(ctx)
134
141
 
142
+ if not modify:
143
+ stash = False
144
+ else:
145
+ # check if we need to stash
146
+ stash = stash or kacl_changelog.config.stash_always
147
+
135
148
  # add changes to changelog
136
- kacl_changelog.add(section=section, data=message)
149
+ kacl_changelog.add(section=section, data=message, stash=stash)
150
+
137
151
  kacl_changelog_content = kacl.dump(kacl_changelog)
152
+ # if stashing is enabled, do not modify the changelog file
138
153
  if modify:
139
- with open(kacl_changelog.config.changelog_file_path, "w") as f:
140
- f.write(kacl_changelog_content)
141
- f.close()
154
+ if not stash:
155
+ with open(kacl_changelog.config.changelog_file_path, "w") as f:
156
+ f.write(kacl_changelog_content)
157
+ f.close()
142
158
  else:
143
159
  click.echo(kacl_changelog_content)
144
160
 
@@ -472,6 +488,13 @@ def release(
472
488
  if no_commit:
473
489
  return
474
490
 
491
+ # delete all file in the stash directory
492
+ stash_files = []
493
+ for f in os.listdir(kacl_changelog.stash_directory):
494
+ stash_file = os.path.join(kacl_changelog.stash_directory, f)
495
+ os.remove(stash_file)
496
+ stash_files.append(stash_file)
497
+
475
498
  if commit or tag or kacl_config.git_create_commit or kacl_config.git_create_tag:
476
499
  vcs_context = {
477
500
  "latest_version": latest_version,
@@ -516,6 +539,11 @@ def release(
516
539
  repo.git.add(kacl_config.changelog_file_path)
517
540
  for f in kacl_config.git_commit_additional_files:
518
541
  repo.git.add(f)
542
+ for f in stash_files:
543
+ try:
544
+ repo.git.add(f)
545
+ except git.GitCommandError:
546
+ pass
519
547
  repo.git.commit("-m", commit_message.format(**vcs_context))
520
548
 
521
549
  if tag or kacl_config.git_create_tag:
@@ -618,6 +646,52 @@ def new(output_file):
618
646
  click.echo(kacl_changelog_content)
619
647
 
620
648
 
649
+ @cli.command()
650
+ @click.option(
651
+ "-f",
652
+ "--force",
653
+ required=False,
654
+ is_flag=True,
655
+ help="Will overwrite existing files.",
656
+ )
657
+ def init(force):
658
+ """Initializes a project with all necessary kacl setting."""
659
+ kacl_changelog = kacl.new()
660
+ kacl_changelog_content = kacl.dump(kacl_changelog)
661
+
662
+ if os.path.exists("CHANGELOG.md") and not force:
663
+ click.echo(
664
+ click.style("Error: ", fg="red")
665
+ + "CHANGELOG.md already exists. Use '--force' to overwrite."
666
+ )
667
+ sys.exit(1)
668
+
669
+ if os.path.exists(".kacl.yml") and not force:
670
+ click.echo(
671
+ click.style("Error: ", fg="red")
672
+ + ".kacl.yml already exists. Use '--force' to overwrite."
673
+ )
674
+ sys.exit(1)
675
+
676
+ with open("CHANGELOG.md", "w") as f:
677
+ f.write(kacl_changelog_content)
678
+ f.close()
679
+
680
+ default_config_file = os.path.join(
681
+ os.path.dirname(os.path.abspath(__file__)), "config", "kacl-default.yml"
682
+ )
683
+
684
+ # copy the default config file
685
+ if os.path.exists(default_config_file):
686
+ with open(default_config_file, "r") as df:
687
+ default_config_content = df.read()
688
+ df.close()
689
+
690
+ with open(".kacl.yml", "w") as cf:
691
+ cf.write(default_config_content)
692
+ cf.close()
693
+
694
+
621
695
  @cli.command("add-comments")
622
696
  @click.pass_context
623
697
  @click.option(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-kacl
3
- Version: 0.6.5
3
+ Version: 0.6.7
4
4
  Summary: Python module and CLI tool for validating and modifying Changelogs in "keep-a-changelog" format"
5
5
  Home-page: https://gitlab.com/schmieder.matthias/python-kacl.git
6
6
  Author: Matthias Schmieder
@@ -47,12 +47,23 @@ A tool for verifying and modifying changelog in the [**K**eep-**A-C**hange-**L**
47
47
  - [Docker](#docker)
48
48
  - [pre-commit](#pre-commit)
49
49
  - [CLI](#cli)
50
+ - [Initialize a new project](#initialize-a-new-project)
50
51
  - [Create a Changelog](#create-a-changelog)
51
52
  - [Verify a Changelog](#verify-a-changelog)
52
53
  - [Print the current release version](#print-the-current-release-version)
53
54
  - [Print a single release changelog](#print-a-single-release-changelog)
54
55
  - [Add an entry to an unreleased section](#add-an-entry-to-an-unreleased-section)
55
56
  - [Prepare a Changelog for a Release](#prepare-a-changelog-for-a-release)
57
+ - [Changelog Fragments](#changelog-fragments)
58
+ - [Configuration](#configuration)
59
+ - [How It Works](#how-it-works)
60
+ - [Usage Patterns](#usage-patterns)
61
+ - [Automatic Fragment Creation](#automatic-fragment-creation)
62
+ - [Manual Fragment Control](#manual-fragment-control)
63
+ - [Fragment Structure](#fragment-structure)
64
+ - [Release Integration](#release-integration)
65
+ - [Workflow Integration](#workflow-integration)
66
+ - [Benefits](#benefits)
56
67
  - [Link Generation](#link-generation)
57
68
  - [Squashing releases](#squashing-releases)
58
69
  - [Example](#example)
@@ -63,6 +74,9 @@ A tool for verifying and modifying changelog in the [**K**eep-**A-C**hange-**L**
63
74
  - [Extensions](#extensions)
64
75
  - [Post-release/Hotfix](#post-releasehotfix)
65
76
  - [Config file](#config-file)
77
+ - [Default Config](#default-config)
78
+ - [Configuration Parameters](#configuration-parameters)
79
+ - [Template Variables](#template-variables)
66
80
  - [Development](#development)
67
81
 
68
82
  ## Installation
@@ -143,10 +157,97 @@ Commands:
143
157
  verify Verifies if the changelog is in "keep-a-changelog" format.
144
158
  ```
145
159
 
160
+ ## Initialize a new project
146
161
 
147
- ## Create a Changelog
162
+ ```bash
163
+ Usage: kacl-cli init [OPTIONS]
164
+
165
+ Initializes a project with all necessary kacl setting.
166
+
167
+ Options:
168
+ -f, --force Will overwrite existing files.
169
+ --help Show this message and exit.
170
+ ```
171
+
172
+ The `init` command provides a quick way to set up a new project with all necessary KACL files and configuration. This command creates two essential files:
173
+
174
+ 1. **CHANGELOG.md** - A new changelog file with the standard Keep a Changelog format
175
+ 2. **.kacl.yml** - A complete configuration file with all available options and sensible defaults
148
176
 
177
+ **Usage**
178
+
179
+ ```bash
180
+ kacl-cli init
181
+ ```
182
+
183
+ This will create both files in the current directory. If either file already exists, the command will fail unless you use the `--force` option:
184
+
185
+ ```bash
186
+ kacl-cli init --force
149
187
  ```
188
+
189
+ **Created Files**
190
+
191
+ The `init` command creates a standard CHANGELOG.md file and copies the complete default configuration. The `.kacl.yml` file includes all available configuration options:
192
+
193
+ ```yaml
194
+ kacl:
195
+ file: CHANGELOG.md
196
+ allowed_header_titles:
197
+ - Changelog
198
+ - Change Log
199
+ allowed_version_sections:
200
+ - Added
201
+ - Changed
202
+ - Deprecated
203
+ - Removed
204
+ - Fixed
205
+ - Security
206
+ default_content:
207
+ - All notable changes to this project will be documented in this file.
208
+ - The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
209
+ git:
210
+ commit: False
211
+ commit_message: "[skip ci] Releasing Changelog version {new_version}"
212
+ commit_additional_files: []
213
+ tag: False
214
+ tag_name: "v{new_version}"
215
+ tag_description: "Version v{new_version} released"
216
+ links:
217
+ auto_generate: False
218
+ compare_versions_template: '{host}/compare/{previous_version}...{version}'
219
+ unreleased_changes_template: '{host}/compare/{latest_version}...master'
220
+ initial_version_template: '{host}/tree/{version}'
221
+ extension:
222
+ post_release_version_prefix: null
223
+ issue_tracker:
224
+ jira:
225
+ host: null
226
+ username: null
227
+ password: null
228
+ issue_patterns: ["[A-Z]+-[0-9]+"]
229
+ comment_template: |
230
+ # 🚀 New version [v{new_version}]({link})
231
+
232
+ A new release has been created referencing this issue. Please check it out.
233
+
234
+ ## 🚧 Changes in this version
235
+
236
+ {changes}
237
+
238
+ ## 🧭 Reference
239
+
240
+ Code: [Source Code Management System]({link})
241
+ stash:
242
+ directory: .kacl_stash
243
+ always: False
244
+ ```
245
+
246
+ You can customize any of these settings according to your project's needs. The configuration provides sensible defaults that work for most projects while offering extensive customization options for advanced use cases.
247
+
248
+ ## Create a Changelog
249
+
250
+ ```bash
150
251
  Usage: kacl-cli new [OPTIONS]
151
252
 
152
253
  Creates a new changelog.
@@ -254,8 +355,9 @@ kacl-cli get 0.2.2
254
355
  ```
255
356
  Usage: kacl-cli add [OPTIONS] SECTION MESSAGE
256
357
 
257
- Adds a given message to a specified unreleased section. Use '--modify' to
258
- directly modify the changelog file.
358
+ Adds a given message to a specified unreleased section. A new unreleased
359
+ section is added if it doesn't exist. Use '--modify' to directly modify
360
+ the changelog file.
259
361
 
260
362
  Options:
261
363
  -m, --modify This option will add the changes directly into changelog file
@@ -277,7 +379,9 @@ Usage: kacl-cli release [OPTIONS] VERSION
277
379
 
278
380
  Creates a release for the latest 'unreleased' changes. Use '--modify' to
279
381
  directly modify the changelog file. You can automatically use the latest
280
- version by using the version keywords 'major', 'minor', 'patch', 'post'
382
+ version by using the version keywords 'major', 'minor', 'patch', 'post'.
383
+ Creates a new empty unreleased section if not disabled in the configuration
384
+ file.
281
385
 
282
386
  Example:
283
387
 
@@ -429,6 +533,102 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
429
533
  [Unreleased]: https://gitlab.com/schmieder.matthias/python-kacl/compare/v1.0.0...HEAD
430
534
  ```
431
535
 
536
+ ## Changelog Fragments
537
+
538
+ **kacl-cli** supports "changelog fragments" starting from version 6.6.0, which provides a powerful solution for managing unreleased changes in collaborative development environments. This feature helps avoid merge conflicts and simplifies changelog management when multiple developers are working on different branches simultaneously.
539
+
540
+ ### Configuration
541
+
542
+ Enable changelog fragments through the `.kacl.yml` configuration file:
543
+
544
+ ```yaml
545
+ kacl:
546
+ stash:
547
+ dir: .kacl_stash
548
+ always: True
549
+ ```
550
+
551
+ **Configuration Options:**
552
+
553
+ - `dir`: Directory where changelog fragments are stored (default: `.kacl_stash`)
554
+ - `always`: When `True`, all `kacl add` commands automatically create fragments instead of modifying the main changelog
555
+
556
+ ### How It Works
557
+
558
+ The stash functionality stores "Unreleased" changes in separate fragment files within the configured stash directory. These fragment files are **git-branch aware**:
559
+
560
+ - **Inside a git repository**: Fragment files are named `{git_branch}.md`
561
+ - **Outside a git repository**: Fragment files use a timestamp-based name
562
+
563
+ This branch-aware naming ensures maximum segregation of changes, preventing merge conflicts and rebase issues that commonly occur when multiple merge requests modify the same changelog file simultaneously.
564
+
565
+ ### Usage Patterns
566
+
567
+ #### Automatic Fragment Creation
568
+
569
+ With `always: True` in your configuration, all changelog additions are automatically directed to fragments:
570
+
571
+ ```bash
572
+ kacl add -m Changed "my new changelog entry"
573
+ ```
574
+
575
+ This command creates or updates a fragment file (e.g., `feature-branch.md`) instead of modifying the main `CHANGELOG.md`.
576
+
577
+ #### Manual Fragment Control
578
+
579
+ With `always: False`, you have explicit control over where changes are added:
580
+
581
+ ```bash
582
+ # Add directly to CHANGELOG.md
583
+ kacl add -m Changed "directly to the CHANGELOG.md"
584
+
585
+ # Add to a fragment file
586
+ kacl add -m --stash Changed "into the fragment"
587
+ ```
588
+
589
+ ### Fragment Structure
590
+
591
+ Each fragment file contains a standard changelog structure:
592
+
593
+ ```markdown
594
+ # Changelog
595
+ All notable changes to this project will be documented in this file.
596
+
597
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
598
+
599
+ ## Unreleased
600
+ ### Changed
601
+ - my new changelog entry
602
+ ```
603
+
604
+ ### Release Integration
605
+
606
+ When executing `kacl release`, the system automatically:
607
+
608
+ 1. **Collects all fragments** from the stash directory
609
+ 2. **Merges fragment content** into the main changelog under the new release version
610
+ 3. **Deletes processed fragments** from the stash directory
611
+ 4. **Stages deletions in git** so fragments are removed when the release is committed
612
+
613
+ This seamless integration ensures that all distributed changes across branches are consolidated into a single release entry.
614
+
615
+ ### Workflow Integration
616
+
617
+ Changelog fragments are fully integrated into all kacl workflows:
618
+
619
+ - **`kacl verify`**: Validates both the main changelog and all fragments
620
+ - **`kacl get`**: Considers fragment content when retrieving version information
621
+ - **Git operations**: Fragment cleanup is automatically handled during release commits
622
+
623
+ ### Benefits
624
+
625
+ - **Eliminates merge conflicts** on changelog files
626
+ - **Enables parallel development** without coordination overhead
627
+ - **Maintains changelog quality** through individual fragment validation
628
+ - **Simplifies release process** with automatic fragment consolidation
629
+ - **Preserves git history** of changelog contributions per branch
630
+
631
+
432
632
  ## Link Generation
433
633
 
434
634
  `kacl-cli` let's you easily generate links to your versions. You can automatically generate all links following the desired patterns using `kacl-cli link generate`.
@@ -581,12 +781,12 @@ Options:
581
781
 
582
782
  The `comment_template` parameter allows various templating options. The following template variables are available:
583
783
 
584
- | Variable | Description |
585
- | -------------- | ---------------------------------------------------------------------------------------------------- |
586
- | `new_version` | The version that was just released |
587
- | `changes` | The markdown content within the change section of your CHANGELOG |
784
+ | Variable | Description |
785
+ | -------------- | ----------------------------------------------------------------------------------------------------- |
786
+ | `new_version` | The version that was just released |
787
+ | `changes` | The markdown content within the change section of your CHANGELOG |
588
788
  | `link` | The link to the version within your source code management system according to the link configuration |
589
- | `env.MYENVVAR` | Any environment variable |
789
+ | `env.MYENVVAR` | Any environment variable |
590
790
 
591
791
  This flexibility allows you to adapt the comment patterns to your needs and dynamically create them. For example, adding CI/CD information can be easily achieved as follows:
592
792
 
@@ -651,11 +851,11 @@ required _default content_.
651
851
  By specifying a `.kacl.yml` with any of those options, the _default config_ will be merged with those local changes. Most options are also available on the CLI which take precedence over the ones
652
852
  within the config files.
653
853
 
654
- **Default Config**
854
+ ### Default Config
655
855
 
656
856
  ```yaml
657
857
  kacl:
658
- changelog_file: CHANGELOG.md
858
+ file: CHANGELOG.md
659
859
  allowed_header_titles:
660
860
  - Changelog
661
861
  - Change Log
@@ -669,20 +869,20 @@ kacl:
669
869
  default_content:
670
870
  - All notable changes to this project will be documented in this file.
671
871
  - The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
872
+ release:
873
+ add_unreleased: True
672
874
  git:
673
- commit: True
875
+ commit: False
674
876
  commit_message: "[skip ci] Releasing Changelog version {new_version}"
675
877
  commit_additional_files: []
676
878
  tag: False
677
879
  tag_name: "v{new_version}"
678
880
  tag_description: "Version v{new_version} released"
679
881
  links:
680
- # The host url is optional and will be automatically determined using your git repository
681
- # host_url: https://github.com/mschmieder/kacl-cli
682
- compare_versions_template: '{host}/compare/{previous_version}...{version}'
683
- unreleased_changes_template: '{host}/compare/{latest_version}...master'
684
- initial_version_template: '{host}/tree/{version}'
685
- auto_generate: True
882
+ auto_generate: False
883
+ compare_versions_template: '{host}/compare/{previous_version}...{version}'
884
+ unreleased_changes_template: '{host}/compare/{latest_version}...master'
885
+ initial_version_template: '{host}/tree/{version}'
686
886
  extension:
687
887
  post_release_version_prefix: null
688
888
  issue_tracker:
@@ -703,7 +903,59 @@ kacl:
703
903
  ## 🧭 Reference
704
904
 
705
905
  Code: [Source Code Management System]({link})
706
- ```
906
+ stash:
907
+ directory: .kacl_stash
908
+ always: False
909
+ ```
910
+
911
+ ### Configuration Parameters
912
+
913
+ | Parameter | Type | Default | Description |
914
+ | --------------------------------------- | ------- | -------------------------------------------------------------------- | -------------------------------------------------------- |
915
+ | **Basic Settings** | | | |
916
+ | `file` | string | `CHANGELOG.md` | Path to the changelog file |
917
+ | `allowed_header_titles` | array | `["Changelog", "Change Log"]` | Valid changelog header titles |
918
+ | `allowed_version_sections` | array | `["Added", "Changed", "Deprecated", "Removed", "Fixed", "Security"]` | Valid section names within version entries |
919
+ | `default_content` | array | See default config | Default content lines for new changelog files |
920
+ | **Git Integration** | | | |
921
+ | `git.commit` | boolean | `false` | Automatically commit changelog changes during release |
922
+ | `git.commit_message` | string | `"[skip ci] Releasing Changelog version {new_version}"` | Template for commit messages |
923
+ | `git.commit_additional_files` | array | `[]` | Additional files to include in release commits |
924
+ | `git.tag` | boolean | `false` | Automatically create git tags during release |
925
+ | `git.tag_name` | string | `"v{new_version}"` | Template for git tag names |
926
+ | `git.tag_description` | string | `"Version v{new_version} released"` | Template for git tag descriptions |
927
+ | **Release Settings** | | | |
928
+ | `release.add_unreleased` | boolean | `true` | Automatically add new "Unreleased" section after release |
929
+ | **Link Generation** | | | |
930
+ | `links.auto_generate` | boolean | `false` | Automatically generate version links during release |
931
+ | `links.compare_versions_template` | string | `"{host}/compare/{previous_version}...{version}"` | Template for version comparison links |
932
+ | `links.unreleased_changes_template` | string | `"{host}/compare/{latest_version}...master"` | Template for unreleased changes links |
933
+ | `links.initial_version_template` | string | `"{host}/tree/{version}"` | Template for initial version links |
934
+ | **Extensions** | | | |
935
+ | `extension.post_release_version_prefix` | string | `null` | Prefix for post-release/hotfix versions (non-SemVer) |
936
+ | **Issue Tracker Integration** | | | |
937
+ | `issue_tracker.jira.host` | string | `null` | JIRA instance hostname (also reads `JIRA_HOST` env var) |
938
+ | `issue_tracker.jira.username` | string | `null` | JIRA username (also reads `JIRA_USERNAME` env var) |
939
+ | `issue_tracker.jira.password` | string | `null` | JIRA password (also reads `JIRA_PASSWORD` env var) |
940
+ | `issue_tracker.jira.issue_patterns` | array | `["[A-Z]+-[0-9]+"]` | Regex patterns to identify issue references in changelog |
941
+ | `issue_tracker.jira.comment_template` | string | See default config | Template for comments posted to JIRA issues |
942
+ | **Changelog Fragments** | | | |
943
+ | `stash.directory` | string | `.kacl_stash` | Directory for storing changelog fragments |
944
+ | `stash.always` | boolean | `false` | Always use fragments instead of modifying main changelog |
945
+
946
+ ### Template Variables
947
+
948
+ The following variables are available for templating in commit messages, tag names, descriptions, and JIRA comments:
949
+
950
+ | Variable | Description | Example |
951
+ | -------------------- | --------------------------------- | ------------------------------ |
952
+ | `{new_version}` | The version being released | `1.2.3` |
953
+ | `{latest_version}` | The previous version | `1.2.2` |
954
+ | `{previous_version}` | Same as latest_version | `1.2.2` |
955
+ | `{host}` | Git repository host URL | `https://github.com/user/repo` |
956
+ | `{changes}` | Changelog content for the version | Markdown content |
957
+ | `{link}` | Link to the version in SCM | Generated link URL |
958
+ | `{env.VAR_NAME}` | Environment variable | Value of `VAR_NAME` |
707
959
 
708
960
  ## Development
709
961
 
@@ -716,7 +968,7 @@ cd python-kacl
716
968
 
717
969
  # create a virtual env
718
970
  python3 -m venv .venv
719
- source ./venv/bin/activate
971
+ source ./.venv/bin/activate
720
972
 
721
973
  # install in development mode
722
974
  pip install -e .
@@ -1,22 +1,22 @@
1
- kacl/__init__.py,sha256=WUM42QzTkxNY6Yd-x-FEqcO2NFfzXkqDhRoAyqME1EE,644
1
+ kacl/__init__.py,sha256=LVMIQ2xATXmaQ0FdcE9sRrOy2X7w-s6DKQHtZgSLNpA,667
2
2
  kacl/__main__.py,sha256=cpulIGoFUJNN5ZW9oUoNN1PnBvrOyJ24xwtpf_yRwgQ,91
3
- kacl/changes.py,sha256=A0POz-xFMpFuq7nISnx_K75xOZOMmBuHq6EZ8NOQDsU,661
4
- kacl/config.py,sha256=Glw-1hRqS3AHpZ-2QRGzHRQ-TSLc1xtneb2MEATWFEQ,3966
5
- kacl/document.py,sha256=dzeYCIgLA1WzK04jeeCW_AYSOCampc9x2cAHdbnEMpY,24737
3
+ kacl/changes.py,sha256=Speu1KLMNQVn0U2BMaO8ta4IEaQLTQtpW0IhN0JjGdY,704
4
+ kacl/config.py,sha256=c2QiP-BriJJwzrw36oigJWKe6t4o6yhmN_nPSL6bcRk,4242
5
+ kacl/document.py,sha256=oNnxlXWEh4yfqK4dK8xhzjWrUPHbUizEj_PQhP73poQ,28763
6
6
  kacl/element.py,sha256=OG02QI8ND5fJpBMceT6dbIHr4uX9gLxK_fPCsOvMDHI,416
7
7
  kacl/exception.py,sha256=MfOVpUvhcQtm10rSY__74-oLo445PG8mLFGJPPIfXH0,41
8
8
  kacl/jira_client.py,sha256=KPE94bZDkJFKw3okFsCgf2DjoyMlUUTMZKtQGKreVQY,989
9
- kacl/kacl_cli.py,sha256=KeCT4DydkHjckt5sbTtTwp2BQf0RllXpBUwLj-G5-U0,19987
9
+ kacl/kacl_cli.py,sha256=RshCxLhh5YJa6tzl8f5dnLOYF3Kbl-EDD4m21hIJDPw,22176
10
10
  kacl/link_provider.py,sha256=tgvMYhJe2ErH1m_qXMlQEacq9Cg_KGp_-sF03sVFP6E,1866
11
11
  kacl/parser.py,sha256=EUtRjgaW0beWVqiYaRJ9Rcf6jbuGoTgWzVBdOdUHnv8,2587
12
12
  kacl/serializer.py,sha256=PdR2FFCh9rbBhkxXwUYD0fSjQqTG_Mb6mYws3lNAWQ8,3090
13
13
  kacl/utils.py,sha256=bHiDDmjoYB868Bm732vNjpfML-6xcNQQqS7NQn_Sfm0,2824
14
14
  kacl/validation.py,sha256=b9r_5CyY6Cmi9BePh47IgZ3j64zdVsoB_fFvucieNbw,2125
15
15
  kacl/version.py,sha256=IDYCWIIXzxdYyMptUAidMgf0SXJqoETFVJ8NVyKgA9A,9526
16
- kacl/config/kacl-default.yml,sha256=BdrQytOsx32_vXXBtR3VRp1-nzWrczNVc-gHuCGYuIA,1424
17
- python_kacl-0.6.5.dist-info/licenses/LICENSE,sha256=TRSJOIt7LZuMeZXFleJVL_LHczSxqi70HEiTLT-kI8Q,1075
18
- python_kacl-0.6.5.dist-info/METADATA,sha256=kVBx144zCKsmVBAnZS-RQ1omJ2QiPfIME6DtJRz8loE,24325
19
- python_kacl-0.6.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
20
- python_kacl-0.6.5.dist-info/entry_points.txt,sha256=rXqqJKfm6Y7fYfioq_7ay2VWOOM9C-hts1IsoGTtojM,76
21
- python_kacl-0.6.5.dist-info/top_level.txt,sha256=BcmQgo67JyGnVZ3Jc0Ag8hKMGVOqXc8ex01zW4Njw5M,5
22
- python_kacl-0.6.5.dist-info/RECORD,,
16
+ kacl/config/kacl-default.yml,sha256=cXHl_w04SW0HA7OyJMMuaC6DTeXlhI2Sfsx7lygTPf4,1513
17
+ python_kacl-0.6.7.dist-info/licenses/LICENSE,sha256=TRSJOIt7LZuMeZXFleJVL_LHczSxqi70HEiTLT-kI8Q,1075
18
+ python_kacl-0.6.7.dist-info/METADATA,sha256=WXFDjyEQ1jS_sJyzfcHgx3wfq9OijduqLo1KYSkYpXY,38157
19
+ python_kacl-0.6.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
20
+ python_kacl-0.6.7.dist-info/entry_points.txt,sha256=rXqqJKfm6Y7fYfioq_7ay2VWOOM9C-hts1IsoGTtojM,76
21
+ python_kacl-0.6.7.dist-info/top_level.txt,sha256=BcmQgo67JyGnVZ3Jc0Ag8hKMGVOqXc8ex01zW4Njw5M,5
22
+ python_kacl-0.6.7.dist-info/RECORD,,