python-kacl 0.7.0__tar.gz → 0.7.2__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.0/python_kacl.egg-info → python_kacl-0.7.2}/PKG-INFO +124 -2
- {python_kacl-0.7.0 → python_kacl-0.7.2}/README.md +123 -1
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/__init__.py +1 -1
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/document.py +54 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/kacl_cli.py +48 -2
- {python_kacl-0.7.0 → python_kacl-0.7.2}/pyproject.toml +1 -1
- {python_kacl-0.7.0 → python_kacl-0.7.2/python_kacl.egg-info}/PKG-INFO +124 -2
- {python_kacl-0.7.0 → python_kacl-0.7.2}/tests/test_cli.py +151 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/LICENSE +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/MANIFEST.in +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/__main__.py +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/changes.py +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/config/kacl-default.yml +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/config.py +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/element.py +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/exception.py +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/jira_client.py +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/link_provider.py +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/parser.py +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/serializer.py +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/utils.py +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/validation.py +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/kacl/version.py +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/python_kacl.egg-info/SOURCES.txt +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/python_kacl.egg-info/dependency_links.txt +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/python_kacl.egg-info/entry_points.txt +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/python_kacl.egg-info/not-zip-safe +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/python_kacl.egg-info/requires.txt +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/python_kacl.egg-info/top_level.txt +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/requirements.txt +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/setup.cfg +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/tests/test_cli_workflow.py +0 -0
- {python_kacl-0.7.0 → python_kacl-0.7.2}/tests/test_kacl.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-kacl
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: Python module and CLI tool for validating and modifying Changelogs in "keep-a-changelog" format"
|
|
5
5
|
Author-email: Matthias Schmieder <schmieder.matthias@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -42,6 +42,8 @@ A tool for verifying and modifying changelog in the [**K**eep-**A-C**hange-**L**
|
|
|
42
42
|
- [Print the current release version](#print-the-current-release-version)
|
|
43
43
|
- [Print a single release changelog](#print-a-single-release-changelog)
|
|
44
44
|
- [Add an entry to an unreleased section](#add-an-entry-to-an-unreleased-section)
|
|
45
|
+
- [Stashing Unreleased Changes](#stashing-unreleased-changes)
|
|
46
|
+
- [Pre-commit Hook Integration](#pre-commit-hook-integration)
|
|
45
47
|
- [Prepare a Changelog for a Release](#prepare-a-changelog-for-a-release)
|
|
46
48
|
- [Changelog Fragments](#changelog-fragments)
|
|
47
49
|
- [Configuration](#configuration)
|
|
@@ -121,13 +123,26 @@ docker -v $(pwd):$(pwd) -w $(pwd) mschmieder/kacl-cli:latest verify
|
|
|
121
123
|
|
|
122
124
|
The package can also be used as a pre-commit hook. Just add the following to your `.pre-commit-config.yaml`
|
|
123
125
|
|
|
126
|
+
**Verify Changelog Format**
|
|
127
|
+
|
|
124
128
|
```yaml
|
|
125
129
|
- repo: https://gitlab.com/schmieder.matthias/python-kacl
|
|
126
|
-
rev: 'v0.
|
|
130
|
+
rev: 'v0.7.0' # Use the latest version
|
|
127
131
|
hooks:
|
|
128
132
|
- id: kacl-verify
|
|
129
133
|
```
|
|
130
134
|
|
|
135
|
+
**Auto-Stash Unreleased Changes (Prevent Merge Conflicts)**
|
|
136
|
+
|
|
137
|
+
```yaml
|
|
138
|
+
- repo: https://gitlab.com/schmieder.matthias/python-kacl
|
|
139
|
+
rev: 'v0.7.0' # Use the latest version
|
|
140
|
+
hooks:
|
|
141
|
+
- id: kacl-stash
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The `kacl-stash` hook automatically moves unreleased changes to stash files before each commit, preventing merge conflicts in `CHANGELOG.md`. See [Stashing Unreleased Changes](#stashing-unreleased-changes) for more details.
|
|
145
|
+
|
|
131
146
|
## CLI
|
|
132
147
|
|
|
133
148
|
```
|
|
@@ -143,6 +158,7 @@ Commands:
|
|
|
143
158
|
get Returns a given version from the Changelog
|
|
144
159
|
new Creates a new changelog.
|
|
145
160
|
release Creates a release for the latest 'unreleased' changes.
|
|
161
|
+
stash Moves all unreleased changes from the changelog to the stash.
|
|
146
162
|
verify Verifies if the changelog is in "keep-a-changelog" format.
|
|
147
163
|
```
|
|
148
164
|
|
|
@@ -361,6 +377,112 @@ kacl-cli add added 'We just added some new cool stuff' --modify
|
|
|
361
377
|
kacl-cli add changed 'And changed things a bit' --modify
|
|
362
378
|
```
|
|
363
379
|
|
|
380
|
+
## Stashing Unreleased Changes
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
Usage: kacl-cli stash [OPTIONS]
|
|
384
|
+
|
|
385
|
+
Moves all unreleased changes from the changelog to the stash.
|
|
386
|
+
|
|
387
|
+
Options:
|
|
388
|
+
-m, --modify This option will modify the changelog file directly.
|
|
389
|
+
--help Show this message and exit.
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
The `stash` command provides a powerful solution for managing unreleased changes and **preventing merge conflicts** in collaborative development environments. It moves all unreleased changes from `CHANGELOG.md` to a stash file, leaving an empty "Unreleased" section in the main changelog.
|
|
393
|
+
|
|
394
|
+
**Primary Use Case: Avoiding Merge Conflicts**
|
|
395
|
+
|
|
396
|
+
When multiple team members work on different branches simultaneously and manually edit `CHANGELOG.md`, merge conflicts are inevitable. The `stash` command solves this problem by:
|
|
397
|
+
|
|
398
|
+
1. **Moving changes out of the main changelog** into separate stash files
|
|
399
|
+
2. **Preventing conflicts** during merges since the main changelog remains minimal
|
|
400
|
+
3. **Preserving all changes** in stash files that are later consolidated during release
|
|
401
|
+
|
|
402
|
+
**Usage**
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
# Preview what would be stashed (dry-run)
|
|
406
|
+
kacl-cli stash
|
|
407
|
+
|
|
408
|
+
# Actually stash the changes and update CHANGELOG.md
|
|
409
|
+
kacl-cli stash --modify
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
**How It Works**
|
|
413
|
+
|
|
414
|
+
When you run `kacl-cli stash --modify`:
|
|
415
|
+
|
|
416
|
+
1. All changes from the "Unreleased" section are extracted
|
|
417
|
+
2. Changes are moved to a stash file in `.kacl_stash/` directory (default location)
|
|
418
|
+
3. Stash files are named based on:
|
|
419
|
+
- Git branch name (when inside a git repository): `feature-branch.md`
|
|
420
|
+
- Current date (when outside git): `20230101.md`
|
|
421
|
+
4. The "Unreleased" section in `CHANGELOG.md` is cleared
|
|
422
|
+
5. During `kacl-cli release`, all stashed changes are automatically merged into the release
|
|
423
|
+
|
|
424
|
+
**Example Workflow**
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
# Developer edits CHANGELOG.md directly
|
|
428
|
+
echo "- Added new feature" >> CHANGELOG.md
|
|
429
|
+
|
|
430
|
+
# Before committing, stash the changes to avoid conflicts
|
|
431
|
+
kacl-cli stash --modify
|
|
432
|
+
|
|
433
|
+
# CHANGELOG.md now has an empty Unreleased section
|
|
434
|
+
# Changes are in .kacl_stash/your-branch.md
|
|
435
|
+
|
|
436
|
+
# When ready to release, all stashed changes are included
|
|
437
|
+
kacl-cli release patch --modify
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Pre-commit Hook Integration
|
|
441
|
+
|
|
442
|
+
For maximum convenience, you can automate the stashing process using a pre-commit hook. This allows developers to continue editing `CHANGELOG.md` manually while automatically moving changes to the stash before each commit.
|
|
443
|
+
|
|
444
|
+
**Setup**
|
|
445
|
+
|
|
446
|
+
Add the `kacl-stash` hook to your `.pre-commit-config.yaml`:
|
|
447
|
+
|
|
448
|
+
```yaml
|
|
449
|
+
repos:
|
|
450
|
+
- repo: https://gitlab.com/schmieder.matthias/python-kacl
|
|
451
|
+
rev: 'v0.7.0' # Use the latest version
|
|
452
|
+
hooks:
|
|
453
|
+
- id: kacl-stash
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
**How It Works**
|
|
457
|
+
|
|
458
|
+
1. Developer manually edits `CHANGELOG.md` (traditional workflow)
|
|
459
|
+
2. Pre-commit hook automatically runs `kacl-cli stash -m` before each commit
|
|
460
|
+
3. Changes are moved to stash files
|
|
461
|
+
4. Only the cleaned `CHANGELOG.md` is committed
|
|
462
|
+
5. Multiple branches can work independently without conflicts
|
|
463
|
+
6. During release, all stashed changes are consolidated
|
|
464
|
+
|
|
465
|
+
**Benefits**
|
|
466
|
+
|
|
467
|
+
- ✅ **No workflow changes**: Developers continue editing `CHANGELOG.md` normally
|
|
468
|
+
- ✅ **Zero merge conflicts**: Main changelog stays minimal and conflict-free
|
|
469
|
+
- ✅ **Automatic management**: Pre-commit hook handles everything
|
|
470
|
+
- ✅ **Branch isolation**: Each branch has its own stash file
|
|
471
|
+
- ✅ **Seamless integration**: Changes automatically included in releases
|
|
472
|
+
|
|
473
|
+
**Configuration**
|
|
474
|
+
|
|
475
|
+
You can customize the stash directory in `.kacl.yml`:
|
|
476
|
+
|
|
477
|
+
```yaml
|
|
478
|
+
kacl:
|
|
479
|
+
stash:
|
|
480
|
+
dir: .kacl_stash # Custom stash directory
|
|
481
|
+
always: False # Set to True to always use stash for 'kacl add'
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
**Note**: The `stash` command is complementary to [Changelog Fragments](#changelog-fragments). While fragments support the `kacl add` workflow, the `stash` command is specifically designed for teams that prefer manually editing `CHANGELOG.md` but want to avoid merge conflicts.
|
|
485
|
+
|
|
364
486
|
## Prepare a Changelog for a Release
|
|
365
487
|
|
|
366
488
|
```
|
|
@@ -20,6 +20,8 @@ A tool for verifying and modifying changelog in the [**K**eep-**A-C**hange-**L**
|
|
|
20
20
|
- [Print the current release version](#print-the-current-release-version)
|
|
21
21
|
- [Print a single release changelog](#print-a-single-release-changelog)
|
|
22
22
|
- [Add an entry to an unreleased section](#add-an-entry-to-an-unreleased-section)
|
|
23
|
+
- [Stashing Unreleased Changes](#stashing-unreleased-changes)
|
|
24
|
+
- [Pre-commit Hook Integration](#pre-commit-hook-integration)
|
|
23
25
|
- [Prepare a Changelog for a Release](#prepare-a-changelog-for-a-release)
|
|
24
26
|
- [Changelog Fragments](#changelog-fragments)
|
|
25
27
|
- [Configuration](#configuration)
|
|
@@ -99,13 +101,26 @@ docker -v $(pwd):$(pwd) -w $(pwd) mschmieder/kacl-cli:latest verify
|
|
|
99
101
|
|
|
100
102
|
The package can also be used as a pre-commit hook. Just add the following to your `.pre-commit-config.yaml`
|
|
101
103
|
|
|
104
|
+
**Verify Changelog Format**
|
|
105
|
+
|
|
102
106
|
```yaml
|
|
103
107
|
- repo: https://gitlab.com/schmieder.matthias/python-kacl
|
|
104
|
-
rev: 'v0.
|
|
108
|
+
rev: 'v0.7.0' # Use the latest version
|
|
105
109
|
hooks:
|
|
106
110
|
- id: kacl-verify
|
|
107
111
|
```
|
|
108
112
|
|
|
113
|
+
**Auto-Stash Unreleased Changes (Prevent Merge Conflicts)**
|
|
114
|
+
|
|
115
|
+
```yaml
|
|
116
|
+
- repo: https://gitlab.com/schmieder.matthias/python-kacl
|
|
117
|
+
rev: 'v0.7.0' # Use the latest version
|
|
118
|
+
hooks:
|
|
119
|
+
- id: kacl-stash
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The `kacl-stash` hook automatically moves unreleased changes to stash files before each commit, preventing merge conflicts in `CHANGELOG.md`. See [Stashing Unreleased Changes](#stashing-unreleased-changes) for more details.
|
|
123
|
+
|
|
109
124
|
## CLI
|
|
110
125
|
|
|
111
126
|
```
|
|
@@ -121,6 +136,7 @@ Commands:
|
|
|
121
136
|
get Returns a given version from the Changelog
|
|
122
137
|
new Creates a new changelog.
|
|
123
138
|
release Creates a release for the latest 'unreleased' changes.
|
|
139
|
+
stash Moves all unreleased changes from the changelog to the stash.
|
|
124
140
|
verify Verifies if the changelog is in "keep-a-changelog" format.
|
|
125
141
|
```
|
|
126
142
|
|
|
@@ -339,6 +355,112 @@ kacl-cli add added 'We just added some new cool stuff' --modify
|
|
|
339
355
|
kacl-cli add changed 'And changed things a bit' --modify
|
|
340
356
|
```
|
|
341
357
|
|
|
358
|
+
## Stashing Unreleased Changes
|
|
359
|
+
|
|
360
|
+
```
|
|
361
|
+
Usage: kacl-cli stash [OPTIONS]
|
|
362
|
+
|
|
363
|
+
Moves all unreleased changes from the changelog to the stash.
|
|
364
|
+
|
|
365
|
+
Options:
|
|
366
|
+
-m, --modify This option will modify the changelog file directly.
|
|
367
|
+
--help Show this message and exit.
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
The `stash` command provides a powerful solution for managing unreleased changes and **preventing merge conflicts** in collaborative development environments. It moves all unreleased changes from `CHANGELOG.md` to a stash file, leaving an empty "Unreleased" section in the main changelog.
|
|
371
|
+
|
|
372
|
+
**Primary Use Case: Avoiding Merge Conflicts**
|
|
373
|
+
|
|
374
|
+
When multiple team members work on different branches simultaneously and manually edit `CHANGELOG.md`, merge conflicts are inevitable. The `stash` command solves this problem by:
|
|
375
|
+
|
|
376
|
+
1. **Moving changes out of the main changelog** into separate stash files
|
|
377
|
+
2. **Preventing conflicts** during merges since the main changelog remains minimal
|
|
378
|
+
3. **Preserving all changes** in stash files that are later consolidated during release
|
|
379
|
+
|
|
380
|
+
**Usage**
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
# Preview what would be stashed (dry-run)
|
|
384
|
+
kacl-cli stash
|
|
385
|
+
|
|
386
|
+
# Actually stash the changes and update CHANGELOG.md
|
|
387
|
+
kacl-cli stash --modify
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**How It Works**
|
|
391
|
+
|
|
392
|
+
When you run `kacl-cli stash --modify`:
|
|
393
|
+
|
|
394
|
+
1. All changes from the "Unreleased" section are extracted
|
|
395
|
+
2. Changes are moved to a stash file in `.kacl_stash/` directory (default location)
|
|
396
|
+
3. Stash files are named based on:
|
|
397
|
+
- Git branch name (when inside a git repository): `feature-branch.md`
|
|
398
|
+
- Current date (when outside git): `20230101.md`
|
|
399
|
+
4. The "Unreleased" section in `CHANGELOG.md` is cleared
|
|
400
|
+
5. During `kacl-cli release`, all stashed changes are automatically merged into the release
|
|
401
|
+
|
|
402
|
+
**Example Workflow**
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
# Developer edits CHANGELOG.md directly
|
|
406
|
+
echo "- Added new feature" >> CHANGELOG.md
|
|
407
|
+
|
|
408
|
+
# Before committing, stash the changes to avoid conflicts
|
|
409
|
+
kacl-cli stash --modify
|
|
410
|
+
|
|
411
|
+
# CHANGELOG.md now has an empty Unreleased section
|
|
412
|
+
# Changes are in .kacl_stash/your-branch.md
|
|
413
|
+
|
|
414
|
+
# When ready to release, all stashed changes are included
|
|
415
|
+
kacl-cli release patch --modify
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### Pre-commit Hook Integration
|
|
419
|
+
|
|
420
|
+
For maximum convenience, you can automate the stashing process using a pre-commit hook. This allows developers to continue editing `CHANGELOG.md` manually while automatically moving changes to the stash before each commit.
|
|
421
|
+
|
|
422
|
+
**Setup**
|
|
423
|
+
|
|
424
|
+
Add the `kacl-stash` hook to your `.pre-commit-config.yaml`:
|
|
425
|
+
|
|
426
|
+
```yaml
|
|
427
|
+
repos:
|
|
428
|
+
- repo: https://gitlab.com/schmieder.matthias/python-kacl
|
|
429
|
+
rev: 'v0.7.0' # Use the latest version
|
|
430
|
+
hooks:
|
|
431
|
+
- id: kacl-stash
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
**How It Works**
|
|
435
|
+
|
|
436
|
+
1. Developer manually edits `CHANGELOG.md` (traditional workflow)
|
|
437
|
+
2. Pre-commit hook automatically runs `kacl-cli stash -m` before each commit
|
|
438
|
+
3. Changes are moved to stash files
|
|
439
|
+
4. Only the cleaned `CHANGELOG.md` is committed
|
|
440
|
+
5. Multiple branches can work independently without conflicts
|
|
441
|
+
6. During release, all stashed changes are consolidated
|
|
442
|
+
|
|
443
|
+
**Benefits**
|
|
444
|
+
|
|
445
|
+
- ✅ **No workflow changes**: Developers continue editing `CHANGELOG.md` normally
|
|
446
|
+
- ✅ **Zero merge conflicts**: Main changelog stays minimal and conflict-free
|
|
447
|
+
- ✅ **Automatic management**: Pre-commit hook handles everything
|
|
448
|
+
- ✅ **Branch isolation**: Each branch has its own stash file
|
|
449
|
+
- ✅ **Seamless integration**: Changes automatically included in releases
|
|
450
|
+
|
|
451
|
+
**Configuration**
|
|
452
|
+
|
|
453
|
+
You can customize the stash directory in `.kacl.yml`:
|
|
454
|
+
|
|
455
|
+
```yaml
|
|
456
|
+
kacl:
|
|
457
|
+
stash:
|
|
458
|
+
dir: .kacl_stash # Custom stash directory
|
|
459
|
+
always: False # Set to True to always use stash for 'kacl add'
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
**Note**: The `stash` command is complementary to [Changelog Fragments](#changelog-fragments). While fragments support the `kacl add` workflow, the `stash` command is specifically designed for teams that prefer manually editing `CHANGELOG.md` but want to avoid merge conflicts.
|
|
463
|
+
|
|
342
464
|
## Prepare a Changelog for a Release
|
|
343
465
|
|
|
344
466
|
```
|
|
@@ -330,6 +330,60 @@ class KACLDocument:
|
|
|
330
330
|
self.__versions.insert(0, unreleased_version)
|
|
331
331
|
unreleased_version.add(section.capitalize(), data)
|
|
332
332
|
|
|
333
|
+
def stash_unreleased(self):
|
|
334
|
+
"""Moves all unreleased changes to the stash file.
|
|
335
|
+
|
|
336
|
+
This method takes all changes from the Unreleased section and writes them to
|
|
337
|
+
the stash file, then clears the Unreleased section from the changelog.
|
|
338
|
+
"""
|
|
339
|
+
# Check if there are any unreleased changes
|
|
340
|
+
if not self.has_changes():
|
|
341
|
+
return False
|
|
342
|
+
|
|
343
|
+
# Get the unreleased version
|
|
344
|
+
unreleased_version = self.get("Unreleased")
|
|
345
|
+
if not unreleased_version:
|
|
346
|
+
return False
|
|
347
|
+
|
|
348
|
+
# Get or create the stash file
|
|
349
|
+
stash_file = self._get_stash_file()
|
|
350
|
+
|
|
351
|
+
if os.path.exists(stash_file):
|
|
352
|
+
# Load the stash file
|
|
353
|
+
kacl_changelog = kacl.load(stash_file)
|
|
354
|
+
else:
|
|
355
|
+
# Create a new stash file with an empty changelog
|
|
356
|
+
kacl_changelog = kacl.new()
|
|
357
|
+
|
|
358
|
+
# Add all unreleased changes to the stash
|
|
359
|
+
sections = unreleased_version.sections()
|
|
360
|
+
if sections:
|
|
361
|
+
for section_title, section_changes in sections.items():
|
|
362
|
+
for change_item in section_changes.items():
|
|
363
|
+
kacl_changelog.add(section=section_title, data=change_item)
|
|
364
|
+
|
|
365
|
+
# Write the updated stash file
|
|
366
|
+
kacl_changelog_content = kacl.dump(kacl_changelog)
|
|
367
|
+
with open(stash_file, "w") as f:
|
|
368
|
+
f.write(kacl_changelog_content)
|
|
369
|
+
f.close()
|
|
370
|
+
|
|
371
|
+
# Clear the unreleased section by replacing it with an empty one
|
|
372
|
+
# Find and remove the current unreleased version but keep the link reference if it exists
|
|
373
|
+
link = None
|
|
374
|
+
|
|
375
|
+
for i, version in enumerate(self.__versions):
|
|
376
|
+
if version.version() == "Unreleased":
|
|
377
|
+
link = version.link()
|
|
378
|
+
self.__versions.pop(i)
|
|
379
|
+
break
|
|
380
|
+
|
|
381
|
+
# Add a new empty unreleased version
|
|
382
|
+
new_unreleased = KACLVersion(version="Unreleased", link=link)
|
|
383
|
+
self.__versions.insert(0, new_unreleased)
|
|
384
|
+
|
|
385
|
+
return True
|
|
386
|
+
|
|
333
387
|
def release(
|
|
334
388
|
self,
|
|
335
389
|
version=None,
|
|
@@ -44,7 +44,7 @@ def raise_on_invalid(kacl_changelog):
|
|
|
44
44
|
sys.exit(1)
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
def load_changelog(ctx):
|
|
47
|
+
def load_changelog(ctx, load_stash_files=True):
|
|
48
48
|
config_file_path = ctx.obj["config"]
|
|
49
49
|
input_file = ctx.obj["file"]
|
|
50
50
|
|
|
@@ -69,7 +69,8 @@ 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
|
-
|
|
72
|
+
if load_stash_files:
|
|
73
|
+
kacl_changelog.load_stash()
|
|
73
74
|
|
|
74
75
|
# share the objects
|
|
75
76
|
return kacl_changelog
|
|
@@ -159,6 +160,51 @@ def add(ctx, section, message, modify, stash):
|
|
|
159
160
|
click.echo(kacl_changelog_content)
|
|
160
161
|
|
|
161
162
|
|
|
163
|
+
@cli.command()
|
|
164
|
+
@click.pass_context
|
|
165
|
+
@click.option(
|
|
166
|
+
"-m",
|
|
167
|
+
"--modify",
|
|
168
|
+
is_flag=True,
|
|
169
|
+
help="This option will modify the changelog file directly.",
|
|
170
|
+
)
|
|
171
|
+
def stash(ctx, modify):
|
|
172
|
+
"""Moves all unreleased changes from the changelog to the stash."""
|
|
173
|
+
# Load changelog WITHOUT loading stash files to avoid circular stashing
|
|
174
|
+
kacl_changelog = load_changelog(ctx, load_stash_files=False)
|
|
175
|
+
|
|
176
|
+
# Check if there are changes to stash
|
|
177
|
+
if not kacl_changelog.has_changes():
|
|
178
|
+
click.echo(
|
|
179
|
+
click.style("Info: ", fg="yellow") + "No unreleased changes to stash."
|
|
180
|
+
)
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
# Stash the unreleased changes
|
|
184
|
+
kacl_changelog.stash_unreleased()
|
|
185
|
+
|
|
186
|
+
stash_file = kacl_changelog._get_stash_file()
|
|
187
|
+
click.echo(
|
|
188
|
+
click.style("Success: ", fg="green")
|
|
189
|
+
+ f"Unreleased changes have been moved to {stash_file}"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# Update the changelog file if modify flag is set
|
|
193
|
+
if modify:
|
|
194
|
+
kacl_changelog_content = kacl.dump(kacl_changelog)
|
|
195
|
+
with open(kacl_changelog.config.changelog_file_path, "w") as f:
|
|
196
|
+
f.write(kacl_changelog_content)
|
|
197
|
+
f.close()
|
|
198
|
+
click.echo(
|
|
199
|
+
click.style("Success: ", fg="green")
|
|
200
|
+
+ f"Changelog file {kacl_changelog.config.changelog_file_path} has been updated."
|
|
201
|
+
)
|
|
202
|
+
else:
|
|
203
|
+
# Just print the modified changelog
|
|
204
|
+
kacl_changelog_content = kacl.dump(kacl_changelog)
|
|
205
|
+
click.echo(kacl_changelog_content)
|
|
206
|
+
|
|
207
|
+
|
|
162
208
|
@cli.command()
|
|
163
209
|
@click.pass_context
|
|
164
210
|
def current(ctx):
|
|
@@ -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.2"
|
|
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"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-kacl
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: Python module and CLI tool for validating and modifying Changelogs in "keep-a-changelog" format"
|
|
5
5
|
Author-email: Matthias Schmieder <schmieder.matthias@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -42,6 +42,8 @@ A tool for verifying and modifying changelog in the [**K**eep-**A-C**hange-**L**
|
|
|
42
42
|
- [Print the current release version](#print-the-current-release-version)
|
|
43
43
|
- [Print a single release changelog](#print-a-single-release-changelog)
|
|
44
44
|
- [Add an entry to an unreleased section](#add-an-entry-to-an-unreleased-section)
|
|
45
|
+
- [Stashing Unreleased Changes](#stashing-unreleased-changes)
|
|
46
|
+
- [Pre-commit Hook Integration](#pre-commit-hook-integration)
|
|
45
47
|
- [Prepare a Changelog for a Release](#prepare-a-changelog-for-a-release)
|
|
46
48
|
- [Changelog Fragments](#changelog-fragments)
|
|
47
49
|
- [Configuration](#configuration)
|
|
@@ -121,13 +123,26 @@ docker -v $(pwd):$(pwd) -w $(pwd) mschmieder/kacl-cli:latest verify
|
|
|
121
123
|
|
|
122
124
|
The package can also be used as a pre-commit hook. Just add the following to your `.pre-commit-config.yaml`
|
|
123
125
|
|
|
126
|
+
**Verify Changelog Format**
|
|
127
|
+
|
|
124
128
|
```yaml
|
|
125
129
|
- repo: https://gitlab.com/schmieder.matthias/python-kacl
|
|
126
|
-
rev: 'v0.
|
|
130
|
+
rev: 'v0.7.0' # Use the latest version
|
|
127
131
|
hooks:
|
|
128
132
|
- id: kacl-verify
|
|
129
133
|
```
|
|
130
134
|
|
|
135
|
+
**Auto-Stash Unreleased Changes (Prevent Merge Conflicts)**
|
|
136
|
+
|
|
137
|
+
```yaml
|
|
138
|
+
- repo: https://gitlab.com/schmieder.matthias/python-kacl
|
|
139
|
+
rev: 'v0.7.0' # Use the latest version
|
|
140
|
+
hooks:
|
|
141
|
+
- id: kacl-stash
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The `kacl-stash` hook automatically moves unreleased changes to stash files before each commit, preventing merge conflicts in `CHANGELOG.md`. See [Stashing Unreleased Changes](#stashing-unreleased-changes) for more details.
|
|
145
|
+
|
|
131
146
|
## CLI
|
|
132
147
|
|
|
133
148
|
```
|
|
@@ -143,6 +158,7 @@ Commands:
|
|
|
143
158
|
get Returns a given version from the Changelog
|
|
144
159
|
new Creates a new changelog.
|
|
145
160
|
release Creates a release for the latest 'unreleased' changes.
|
|
161
|
+
stash Moves all unreleased changes from the changelog to the stash.
|
|
146
162
|
verify Verifies if the changelog is in "keep-a-changelog" format.
|
|
147
163
|
```
|
|
148
164
|
|
|
@@ -361,6 +377,112 @@ kacl-cli add added 'We just added some new cool stuff' --modify
|
|
|
361
377
|
kacl-cli add changed 'And changed things a bit' --modify
|
|
362
378
|
```
|
|
363
379
|
|
|
380
|
+
## Stashing Unreleased Changes
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
Usage: kacl-cli stash [OPTIONS]
|
|
384
|
+
|
|
385
|
+
Moves all unreleased changes from the changelog to the stash.
|
|
386
|
+
|
|
387
|
+
Options:
|
|
388
|
+
-m, --modify This option will modify the changelog file directly.
|
|
389
|
+
--help Show this message and exit.
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
The `stash` command provides a powerful solution for managing unreleased changes and **preventing merge conflicts** in collaborative development environments. It moves all unreleased changes from `CHANGELOG.md` to a stash file, leaving an empty "Unreleased" section in the main changelog.
|
|
393
|
+
|
|
394
|
+
**Primary Use Case: Avoiding Merge Conflicts**
|
|
395
|
+
|
|
396
|
+
When multiple team members work on different branches simultaneously and manually edit `CHANGELOG.md`, merge conflicts are inevitable. The `stash` command solves this problem by:
|
|
397
|
+
|
|
398
|
+
1. **Moving changes out of the main changelog** into separate stash files
|
|
399
|
+
2. **Preventing conflicts** during merges since the main changelog remains minimal
|
|
400
|
+
3. **Preserving all changes** in stash files that are later consolidated during release
|
|
401
|
+
|
|
402
|
+
**Usage**
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
# Preview what would be stashed (dry-run)
|
|
406
|
+
kacl-cli stash
|
|
407
|
+
|
|
408
|
+
# Actually stash the changes and update CHANGELOG.md
|
|
409
|
+
kacl-cli stash --modify
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
**How It Works**
|
|
413
|
+
|
|
414
|
+
When you run `kacl-cli stash --modify`:
|
|
415
|
+
|
|
416
|
+
1. All changes from the "Unreleased" section are extracted
|
|
417
|
+
2. Changes are moved to a stash file in `.kacl_stash/` directory (default location)
|
|
418
|
+
3. Stash files are named based on:
|
|
419
|
+
- Git branch name (when inside a git repository): `feature-branch.md`
|
|
420
|
+
- Current date (when outside git): `20230101.md`
|
|
421
|
+
4. The "Unreleased" section in `CHANGELOG.md` is cleared
|
|
422
|
+
5. During `kacl-cli release`, all stashed changes are automatically merged into the release
|
|
423
|
+
|
|
424
|
+
**Example Workflow**
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
# Developer edits CHANGELOG.md directly
|
|
428
|
+
echo "- Added new feature" >> CHANGELOG.md
|
|
429
|
+
|
|
430
|
+
# Before committing, stash the changes to avoid conflicts
|
|
431
|
+
kacl-cli stash --modify
|
|
432
|
+
|
|
433
|
+
# CHANGELOG.md now has an empty Unreleased section
|
|
434
|
+
# Changes are in .kacl_stash/your-branch.md
|
|
435
|
+
|
|
436
|
+
# When ready to release, all stashed changes are included
|
|
437
|
+
kacl-cli release patch --modify
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Pre-commit Hook Integration
|
|
441
|
+
|
|
442
|
+
For maximum convenience, you can automate the stashing process using a pre-commit hook. This allows developers to continue editing `CHANGELOG.md` manually while automatically moving changes to the stash before each commit.
|
|
443
|
+
|
|
444
|
+
**Setup**
|
|
445
|
+
|
|
446
|
+
Add the `kacl-stash` hook to your `.pre-commit-config.yaml`:
|
|
447
|
+
|
|
448
|
+
```yaml
|
|
449
|
+
repos:
|
|
450
|
+
- repo: https://gitlab.com/schmieder.matthias/python-kacl
|
|
451
|
+
rev: 'v0.7.0' # Use the latest version
|
|
452
|
+
hooks:
|
|
453
|
+
- id: kacl-stash
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
**How It Works**
|
|
457
|
+
|
|
458
|
+
1. Developer manually edits `CHANGELOG.md` (traditional workflow)
|
|
459
|
+
2. Pre-commit hook automatically runs `kacl-cli stash -m` before each commit
|
|
460
|
+
3. Changes are moved to stash files
|
|
461
|
+
4. Only the cleaned `CHANGELOG.md` is committed
|
|
462
|
+
5. Multiple branches can work independently without conflicts
|
|
463
|
+
6. During release, all stashed changes are consolidated
|
|
464
|
+
|
|
465
|
+
**Benefits**
|
|
466
|
+
|
|
467
|
+
- ✅ **No workflow changes**: Developers continue editing `CHANGELOG.md` normally
|
|
468
|
+
- ✅ **Zero merge conflicts**: Main changelog stays minimal and conflict-free
|
|
469
|
+
- ✅ **Automatic management**: Pre-commit hook handles everything
|
|
470
|
+
- ✅ **Branch isolation**: Each branch has its own stash file
|
|
471
|
+
- ✅ **Seamless integration**: Changes automatically included in releases
|
|
472
|
+
|
|
473
|
+
**Configuration**
|
|
474
|
+
|
|
475
|
+
You can customize the stash directory in `.kacl.yml`:
|
|
476
|
+
|
|
477
|
+
```yaml
|
|
478
|
+
kacl:
|
|
479
|
+
stash:
|
|
480
|
+
dir: .kacl_stash # Custom stash directory
|
|
481
|
+
always: False # Set to True to always use stash for 'kacl add'
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
**Note**: The `stash` command is complementary to [Changelog Fragments](#changelog-fragments). While fragments support the `kacl add` workflow, the `stash` command is specifically designed for teams that prefer manually editing `CHANGELOG.md` but want to avoid merge conflicts.
|
|
485
|
+
|
|
364
486
|
## Prepare a Changelog for a Release
|
|
365
487
|
|
|
366
488
|
```
|
|
@@ -589,3 +589,154 @@ def test_get_suppress_available_link(tmp_path, snapshot):
|
|
|
589
589
|
with open(os.path.join(project_root_path, "output.md"), "w") as file:
|
|
590
590
|
file.write(result.output)
|
|
591
591
|
snapshot_directory(snapshot=snapshot, directory_path=project_root_path)
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
@freeze_time("2023-01-01")
|
|
595
|
+
def test_stash_no_pre_existing(tmp_path, snapshot):
|
|
596
|
+
"""Test stashing when there is no pre-existing stash file."""
|
|
597
|
+
runner = CliRunner()
|
|
598
|
+
resources_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/")
|
|
599
|
+
changelog_file = os.path.join(resources_dir, "CHANGELOG_with_changes.md")
|
|
600
|
+
|
|
601
|
+
with runner.isolated_filesystem(temp_dir=tmp_path) as project_root_path:
|
|
602
|
+
shutil.copyfile(changelog_file, os.path.join(project_root_path, "CHANGELOG.md"))
|
|
603
|
+
result = runner.invoke(
|
|
604
|
+
cli,
|
|
605
|
+
[
|
|
606
|
+
"-f",
|
|
607
|
+
"CHANGELOG.md",
|
|
608
|
+
"stash",
|
|
609
|
+
"-m",
|
|
610
|
+
],
|
|
611
|
+
catch_exceptions=False,
|
|
612
|
+
)
|
|
613
|
+
assert result.exit_code == 0, result.output
|
|
614
|
+
assert "Success: Unreleased changes have been moved to" in result.output
|
|
615
|
+
assert "Success: Changelog file CHANGELOG.md has been updated" in result.output
|
|
616
|
+
|
|
617
|
+
# Verify stash directory and file were created
|
|
618
|
+
stash_dir = os.path.join(project_root_path, ".kacl_stash")
|
|
619
|
+
assert os.path.exists(stash_dir)
|
|
620
|
+
assert len(os.listdir(stash_dir)) == 1
|
|
621
|
+
|
|
622
|
+
snapshot_directory(snapshot=snapshot, directory_path=project_root_path)
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
@freeze_time("2023-01-01")
|
|
626
|
+
def test_stash_with_pre_existing(tmp_path, snapshot):
|
|
627
|
+
"""Test stashing when there is a pre-existing stash file with changes."""
|
|
628
|
+
runner = CliRunner()
|
|
629
|
+
resources_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/")
|
|
630
|
+
changelog_file = os.path.join(resources_dir, "CHANGELOG_with_changes.md")
|
|
631
|
+
stash_dir_source = os.path.join(resources_dir, "stash")
|
|
632
|
+
|
|
633
|
+
with runner.isolated_filesystem(temp_dir=tmp_path) as project_root_path:
|
|
634
|
+
shutil.copyfile(changelog_file, os.path.join(project_root_path, "CHANGELOG.md"))
|
|
635
|
+
# Copy pre-existing stash directory
|
|
636
|
+
shutil.copytree(
|
|
637
|
+
stash_dir_source, os.path.join(project_root_path, ".kacl_stash")
|
|
638
|
+
)
|
|
639
|
+
|
|
640
|
+
result = runner.invoke(
|
|
641
|
+
cli,
|
|
642
|
+
[
|
|
643
|
+
"-f",
|
|
644
|
+
"CHANGELOG.md",
|
|
645
|
+
"stash",
|
|
646
|
+
"-m",
|
|
647
|
+
],
|
|
648
|
+
catch_exceptions=False,
|
|
649
|
+
)
|
|
650
|
+
assert result.exit_code == 0, result.output
|
|
651
|
+
assert "Success: Unreleased changes have been moved to" in result.output
|
|
652
|
+
assert "Success: Changelog file CHANGELOG.md has been updated" in result.output
|
|
653
|
+
|
|
654
|
+
snapshot_directory(snapshot=snapshot, directory_path=project_root_path)
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
@freeze_time("2023-01-01")
|
|
658
|
+
def test_stash_with_link(tmp_path, snapshot):
|
|
659
|
+
"""Test stashing when there is a pre-existing stash file with changes."""
|
|
660
|
+
runner = CliRunner()
|
|
661
|
+
resources_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/")
|
|
662
|
+
changelog_file = os.path.join(resources_dir, "CHANGELOG_with_changes_and_link.md")
|
|
663
|
+
stash_dir_source = os.path.join(resources_dir, "stash")
|
|
664
|
+
|
|
665
|
+
with runner.isolated_filesystem(temp_dir=tmp_path) as project_root_path:
|
|
666
|
+
shutil.copyfile(changelog_file, os.path.join(project_root_path, "CHANGELOG.md"))
|
|
667
|
+
# Copy pre-existing stash directory
|
|
668
|
+
shutil.copytree(
|
|
669
|
+
stash_dir_source, os.path.join(project_root_path, ".kacl_stash")
|
|
670
|
+
)
|
|
671
|
+
|
|
672
|
+
result = runner.invoke(
|
|
673
|
+
cli,
|
|
674
|
+
[
|
|
675
|
+
"-c",
|
|
676
|
+
os.path.join(resources_dir, "extension-config.yml"),
|
|
677
|
+
"-f",
|
|
678
|
+
"CHANGELOG.md",
|
|
679
|
+
"stash",
|
|
680
|
+
"-m",
|
|
681
|
+
],
|
|
682
|
+
catch_exceptions=False,
|
|
683
|
+
)
|
|
684
|
+
assert result.exit_code == 0, result.output
|
|
685
|
+
assert "Success: Unreleased changes have been moved to" in result.output
|
|
686
|
+
assert "Success: Changelog file CHANGELOG.md has been updated" in result.output
|
|
687
|
+
|
|
688
|
+
snapshot_directory(snapshot=snapshot, directory_path=project_root_path)
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
@freeze_time("2023-01-01")
|
|
692
|
+
def test_stash_no_changes(tmp_path, snapshot):
|
|
693
|
+
"""Test stashing when there are no unreleased changes."""
|
|
694
|
+
runner = CliRunner()
|
|
695
|
+
resources_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/")
|
|
696
|
+
changelog_file = os.path.join(resources_dir, "CHANGELOG_without_changes.md")
|
|
697
|
+
|
|
698
|
+
with runner.isolated_filesystem(temp_dir=tmp_path) as project_root_path:
|
|
699
|
+
shutil.copyfile(changelog_file, os.path.join(project_root_path, "CHANGELOG.md"))
|
|
700
|
+
result = runner.invoke(
|
|
701
|
+
cli,
|
|
702
|
+
[
|
|
703
|
+
"-f",
|
|
704
|
+
"CHANGELOG.md",
|
|
705
|
+
"stash",
|
|
706
|
+
"-m",
|
|
707
|
+
],
|
|
708
|
+
catch_exceptions=False,
|
|
709
|
+
)
|
|
710
|
+
assert result.exit_code == 0, result.output
|
|
711
|
+
assert "Info: No unreleased changes to stash" in result.output
|
|
712
|
+
|
|
713
|
+
# Verify no stash directory was created
|
|
714
|
+
stash_dir = os.path.join(project_root_path, ".kacl_stash")
|
|
715
|
+
assert not os.path.exists(stash_dir)
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
@freeze_time("2023-01-01")
|
|
719
|
+
def test_stash_without_modify(tmp_path, snapshot):
|
|
720
|
+
"""Test stash command without --modify flag (dry run)."""
|
|
721
|
+
runner = CliRunner()
|
|
722
|
+
resources_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/")
|
|
723
|
+
changelog_file = os.path.join(resources_dir, "CHANGELOG_with_changes.md")
|
|
724
|
+
|
|
725
|
+
with runner.isolated_filesystem(temp_dir=tmp_path) as project_root_path:
|
|
726
|
+
shutil.copyfile(changelog_file, os.path.join(project_root_path, "CHANGELOG.md"))
|
|
727
|
+
result = runner.invoke(
|
|
728
|
+
cli,
|
|
729
|
+
[
|
|
730
|
+
"-f",
|
|
731
|
+
"CHANGELOG.md",
|
|
732
|
+
"stash",
|
|
733
|
+
],
|
|
734
|
+
catch_exceptions=False,
|
|
735
|
+
)
|
|
736
|
+
assert result.exit_code == 0, result.output
|
|
737
|
+
assert "Success: Unreleased changes have been moved to" in result.output
|
|
738
|
+
# Should output the modified changelog content
|
|
739
|
+
assert "## Unreleased" in result.output
|
|
740
|
+
assert "## 1.0.0" in result.output
|
|
741
|
+
|
|
742
|
+
snapshot_directory(snapshot=snapshot, directory_path=project_root_path)
|
|
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
|
|
File without changes
|