python-kacl 0.5.0__tar.gz → 0.6.0__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.5.0/python_kacl.egg-info → python_kacl-0.6.0}/PKG-INFO +134 -3
- {python_kacl-0.5.0 → python_kacl-0.6.0}/README.md +130 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/__init__.py +1 -1
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/config/kacl-default.yml +20 -1
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/config.py +28 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/document.py +83 -4
- python_kacl-0.6.0/kacl/jira_client.py +36 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/kacl_cli.py +97 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/link_provider.py +5 -0
- python_kacl-0.6.0/kacl/utils.py +71 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0/python_kacl.egg-info}/PKG-INFO +134 -3
- {python_kacl-0.5.0 → python_kacl-0.6.0}/python_kacl.egg-info/SOURCES.txt +2 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/python_kacl.egg-info/requires.txt +1 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/setup.py +3 -3
- {python_kacl-0.5.0 → python_kacl-0.6.0}/tests/test_cli.py +163 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/tests/test_kacl.py +38 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/LICENSE +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/MANIFEST.in +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/__main__.py +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/changes.py +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/element.py +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/exception.py +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/parser.py +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/serializer.py +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/validation.py +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/kacl/version.py +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/python_kacl.egg-info/dependency_links.txt +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/python_kacl.egg-info/entry_points.txt +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/python_kacl.egg-info/not-zip-safe +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/python_kacl.egg-info/top_level.txt +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/setup.cfg +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/tests/__init__.py +0 -0
- {python_kacl-0.5.0 → python_kacl-0.6.0}/tests/snapshot_directory.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-kacl
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
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
|
|
@@ -8,16 +8,17 @@ Author-email: schmieder.matthias@gmail.com
|
|
|
8
8
|
License: MIT
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Topic :: Software Development :: Version Control
|
|
14
|
-
Requires-Python: >=3.
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: click
|
|
18
18
|
Requires-Dist: semver
|
|
19
19
|
Requires-Dist: gitpython
|
|
20
20
|
Requires-Dist: pyyaml
|
|
21
|
+
Requires-Dist: jira
|
|
21
22
|
|
|
22
23
|
# python-kacl
|
|
23
24
|
|
|
@@ -44,6 +45,10 @@ A tool for verifying and modifying changelog in the [**K**eep-**A-C**hange-**L**
|
|
|
44
45
|
- [Link Generation](#link-generation)
|
|
45
46
|
- [Squashing releases](#squashing-releases)
|
|
46
47
|
- [Example](#example)
|
|
48
|
+
- [Issue Management Integration](#issue-management-integration)
|
|
49
|
+
- [Adding Comments to Issues](#adding-comments-to-issues)
|
|
50
|
+
- [Command Options](#command-options)
|
|
51
|
+
- [Templating the Comment](#templating-the-comment)
|
|
47
52
|
- [Extensions](#extensions)
|
|
48
53
|
- [Post-release/Hotfix](#post-releasehotfix)
|
|
49
54
|
- [Config file](#config-file)
|
|
@@ -483,6 +488,114 @@ kacl-cli -f CHANGELOG.md squash \
|
|
|
483
488
|
|
|
484
489
|
This example will squash all versions between `0.0.1` and `1.0.0` and move them under `1.0.0`
|
|
485
490
|
|
|
491
|
+
## Issue Management Integration
|
|
492
|
+
|
|
493
|
+
With `python-kacl >= 0.6.0`, you can integrate changelog and release management directly into your Issue Management System. Currently, the supported system is JIRA.
|
|
494
|
+
|
|
495
|
+
It is common practice to reference fixed or addressed issues in the changelog, as shown below:
|
|
496
|
+
|
|
497
|
+
```markdown
|
|
498
|
+
## Unreleased
|
|
499
|
+
### Added
|
|
500
|
+
- JIRA-1754 Just unreleased stuff
|
|
501
|
+
|
|
502
|
+
## 1.0.0 - 2017-06-20
|
|
503
|
+
### Added
|
|
504
|
+
- JIRA-9: added UI functionality
|
|
505
|
+
|
|
506
|
+
### Fixed
|
|
507
|
+
- issue JIRA-13 closed by applying the solution
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Adding Comments to Issues
|
|
511
|
+
|
|
512
|
+
The `add-comments` command allows you to detect issue IDs using a custom pattern and create comments in the Issue Tracking system about a new release.
|
|
513
|
+
|
|
514
|
+
You can pass all necessary arguments via CLI or set up your `.kacl.yaml` configuration file. The following options are available:
|
|
515
|
+
|
|
516
|
+
```yaml
|
|
517
|
+
issue_tracker:
|
|
518
|
+
jira:
|
|
519
|
+
host: jira.atlassian.com # The host name of your JIRA instance
|
|
520
|
+
username: null # The username to login. Uses JIRA_USERNAME environment variable if available
|
|
521
|
+
password: null # The password to login. Uses JIRA_PASSWORD environment variable if available
|
|
522
|
+
issue_patterns: # List of regex patterns to identify the issues
|
|
523
|
+
- "[A-Z]+-[0-9]+"
|
|
524
|
+
- "JIRA-[0-9]+"
|
|
525
|
+
comment_template: | # A text template used to comment on the issue
|
|
526
|
+
# 🚀 New version [v{new_version}]({link})
|
|
527
|
+
|
|
528
|
+
A new release has been created referencing this issue. Please check it out.
|
|
529
|
+
|
|
530
|
+
## 🚧 Changes in this version
|
|
531
|
+
|
|
532
|
+
{changes}
|
|
533
|
+
|
|
534
|
+
## 🧭 Reference
|
|
535
|
+
|
|
536
|
+
Code: [Source Code Management System]({link})
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
Run the following command to create the comments:
|
|
540
|
+
|
|
541
|
+
```bash
|
|
542
|
+
kacl-cli add-comments 1.0.0
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
### Command Options
|
|
546
|
+
|
|
547
|
+
See all available command options:
|
|
548
|
+
|
|
549
|
+
```bash
|
|
550
|
+
Usage: kacl-cli add-comments [OPTIONS] VERSION
|
|
551
|
+
|
|
552
|
+
Adds comments to issues identified within the CHANGELOG. Currently
|
|
553
|
+
supported system: JIRA
|
|
554
|
+
|
|
555
|
+
Options:
|
|
556
|
+
--jira-username TEXT JIRA username. Will also look for the
|
|
557
|
+
JIRA_USERNAME environment variable.
|
|
558
|
+
--jira-password TEXT JIRA password. Will also look for the
|
|
559
|
+
JIRA_PASSWORD environment variable.
|
|
560
|
+
--jira-host TEXT JIRA host. Will also look for the JIRA_HOST
|
|
561
|
+
environment variable.
|
|
562
|
+
--jira-issue-pattern TEXT Issue pattern to search the changelog for. Can
|
|
563
|
+
be specified multiple times.
|
|
564
|
+
--jira-comment-template TEXT JIRA comment template.
|
|
565
|
+
--fail Fail if comments could not be added.
|
|
566
|
+
--help Show this message and exit.
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
### Templating the Comment
|
|
570
|
+
|
|
571
|
+
The `comment_template` parameter allows various templating options. The following template variables are available:
|
|
572
|
+
|
|
573
|
+
| Variable | Description |
|
|
574
|
+
| -------------- | ---------------------------------------------------------------------------------------------------- |
|
|
575
|
+
| `new_version` | The version that was just released |
|
|
576
|
+
| `changes` | The markdown content within the change section of your CHANGELOG |
|
|
577
|
+
| `link` | The link to the version within your source code management system according to the link configuration |
|
|
578
|
+
| `env.MYENVVAR` | Any environment variable |
|
|
579
|
+
|
|
580
|
+
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:
|
|
581
|
+
|
|
582
|
+
```yaml
|
|
583
|
+
comment_template: | # A text template used to comment on the issue
|
|
584
|
+
# 🚀 New version [v{new_version}]({link})
|
|
585
|
+
|
|
586
|
+
A new release has been created referencing this issue. Please check it out.
|
|
587
|
+
|
|
588
|
+
## 🚧 Changes in this version
|
|
589
|
+
|
|
590
|
+
{changes}
|
|
591
|
+
|
|
592
|
+
## 🧭 Reference
|
|
593
|
+
|
|
594
|
+
Code: [Source Code Management System]({link})
|
|
595
|
+
Pipeline: [Pipeline ({env.CI_PIPELINE_IID})]({env.CI_PIPELINE_URL})
|
|
596
|
+
GitLab Project: [({env.CI_PROJECT_TITLE})]({env.CI_PROJECT_URL})
|
|
597
|
+
```
|
|
598
|
+
|
|
486
599
|
## Extensions
|
|
487
600
|
|
|
488
601
|
### Post-release/Hotfix
|
|
@@ -561,6 +674,24 @@ kacl:
|
|
|
561
674
|
auto_generate: True
|
|
562
675
|
extension:
|
|
563
676
|
post_release_version_prefix: null
|
|
677
|
+
issue_tracker:
|
|
678
|
+
jira:
|
|
679
|
+
host: null
|
|
680
|
+
username: null
|
|
681
|
+
password: null
|
|
682
|
+
issue_patterns: ["[A-Z]+-[0-9]+"]
|
|
683
|
+
comment_template: |
|
|
684
|
+
# 🚀 New version [v{new_version}]({link})
|
|
685
|
+
|
|
686
|
+
A new release has been created referencing this issue. Please check it out.
|
|
687
|
+
|
|
688
|
+
## 🚧 Changes in this version
|
|
689
|
+
|
|
690
|
+
{changes}
|
|
691
|
+
|
|
692
|
+
## 🧭 Reference
|
|
693
|
+
|
|
694
|
+
Code: [Source Code Management System]({link})
|
|
564
695
|
```
|
|
565
696
|
|
|
566
697
|
## Development
|
|
@@ -23,6 +23,10 @@ A tool for verifying and modifying changelog in the [**K**eep-**A-C**hange-**L**
|
|
|
23
23
|
- [Link Generation](#link-generation)
|
|
24
24
|
- [Squashing releases](#squashing-releases)
|
|
25
25
|
- [Example](#example)
|
|
26
|
+
- [Issue Management Integration](#issue-management-integration)
|
|
27
|
+
- [Adding Comments to Issues](#adding-comments-to-issues)
|
|
28
|
+
- [Command Options](#command-options)
|
|
29
|
+
- [Templating the Comment](#templating-the-comment)
|
|
26
30
|
- [Extensions](#extensions)
|
|
27
31
|
- [Post-release/Hotfix](#post-releasehotfix)
|
|
28
32
|
- [Config file](#config-file)
|
|
@@ -462,6 +466,114 @@ kacl-cli -f CHANGELOG.md squash \
|
|
|
462
466
|
|
|
463
467
|
This example will squash all versions between `0.0.1` and `1.0.0` and move them under `1.0.0`
|
|
464
468
|
|
|
469
|
+
## Issue Management Integration
|
|
470
|
+
|
|
471
|
+
With `python-kacl >= 0.6.0`, you can integrate changelog and release management directly into your Issue Management System. Currently, the supported system is JIRA.
|
|
472
|
+
|
|
473
|
+
It is common practice to reference fixed or addressed issues in the changelog, as shown below:
|
|
474
|
+
|
|
475
|
+
```markdown
|
|
476
|
+
## Unreleased
|
|
477
|
+
### Added
|
|
478
|
+
- JIRA-1754 Just unreleased stuff
|
|
479
|
+
|
|
480
|
+
## 1.0.0 - 2017-06-20
|
|
481
|
+
### Added
|
|
482
|
+
- JIRA-9: added UI functionality
|
|
483
|
+
|
|
484
|
+
### Fixed
|
|
485
|
+
- issue JIRA-13 closed by applying the solution
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### Adding Comments to Issues
|
|
489
|
+
|
|
490
|
+
The `add-comments` command allows you to detect issue IDs using a custom pattern and create comments in the Issue Tracking system about a new release.
|
|
491
|
+
|
|
492
|
+
You can pass all necessary arguments via CLI or set up your `.kacl.yaml` configuration file. The following options are available:
|
|
493
|
+
|
|
494
|
+
```yaml
|
|
495
|
+
issue_tracker:
|
|
496
|
+
jira:
|
|
497
|
+
host: jira.atlassian.com # The host name of your JIRA instance
|
|
498
|
+
username: null # The username to login. Uses JIRA_USERNAME environment variable if available
|
|
499
|
+
password: null # The password to login. Uses JIRA_PASSWORD environment variable if available
|
|
500
|
+
issue_patterns: # List of regex patterns to identify the issues
|
|
501
|
+
- "[A-Z]+-[0-9]+"
|
|
502
|
+
- "JIRA-[0-9]+"
|
|
503
|
+
comment_template: | # A text template used to comment on the issue
|
|
504
|
+
# 🚀 New version [v{new_version}]({link})
|
|
505
|
+
|
|
506
|
+
A new release has been created referencing this issue. Please check it out.
|
|
507
|
+
|
|
508
|
+
## 🚧 Changes in this version
|
|
509
|
+
|
|
510
|
+
{changes}
|
|
511
|
+
|
|
512
|
+
## 🧭 Reference
|
|
513
|
+
|
|
514
|
+
Code: [Source Code Management System]({link})
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
Run the following command to create the comments:
|
|
518
|
+
|
|
519
|
+
```bash
|
|
520
|
+
kacl-cli add-comments 1.0.0
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Command Options
|
|
524
|
+
|
|
525
|
+
See all available command options:
|
|
526
|
+
|
|
527
|
+
```bash
|
|
528
|
+
Usage: kacl-cli add-comments [OPTIONS] VERSION
|
|
529
|
+
|
|
530
|
+
Adds comments to issues identified within the CHANGELOG. Currently
|
|
531
|
+
supported system: JIRA
|
|
532
|
+
|
|
533
|
+
Options:
|
|
534
|
+
--jira-username TEXT JIRA username. Will also look for the
|
|
535
|
+
JIRA_USERNAME environment variable.
|
|
536
|
+
--jira-password TEXT JIRA password. Will also look for the
|
|
537
|
+
JIRA_PASSWORD environment variable.
|
|
538
|
+
--jira-host TEXT JIRA host. Will also look for the JIRA_HOST
|
|
539
|
+
environment variable.
|
|
540
|
+
--jira-issue-pattern TEXT Issue pattern to search the changelog for. Can
|
|
541
|
+
be specified multiple times.
|
|
542
|
+
--jira-comment-template TEXT JIRA comment template.
|
|
543
|
+
--fail Fail if comments could not be added.
|
|
544
|
+
--help Show this message and exit.
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### Templating the Comment
|
|
548
|
+
|
|
549
|
+
The `comment_template` parameter allows various templating options. The following template variables are available:
|
|
550
|
+
|
|
551
|
+
| Variable | Description |
|
|
552
|
+
| -------------- | ---------------------------------------------------------------------------------------------------- |
|
|
553
|
+
| `new_version` | The version that was just released |
|
|
554
|
+
| `changes` | The markdown content within the change section of your CHANGELOG |
|
|
555
|
+
| `link` | The link to the version within your source code management system according to the link configuration |
|
|
556
|
+
| `env.MYENVVAR` | Any environment variable |
|
|
557
|
+
|
|
558
|
+
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:
|
|
559
|
+
|
|
560
|
+
```yaml
|
|
561
|
+
comment_template: | # A text template used to comment on the issue
|
|
562
|
+
# 🚀 New version [v{new_version}]({link})
|
|
563
|
+
|
|
564
|
+
A new release has been created referencing this issue. Please check it out.
|
|
565
|
+
|
|
566
|
+
## 🚧 Changes in this version
|
|
567
|
+
|
|
568
|
+
{changes}
|
|
569
|
+
|
|
570
|
+
## 🧭 Reference
|
|
571
|
+
|
|
572
|
+
Code: [Source Code Management System]({link})
|
|
573
|
+
Pipeline: [Pipeline ({env.CI_PIPELINE_IID})]({env.CI_PIPELINE_URL})
|
|
574
|
+
GitLab Project: [({env.CI_PROJECT_TITLE})]({env.CI_PROJECT_URL})
|
|
575
|
+
```
|
|
576
|
+
|
|
465
577
|
## Extensions
|
|
466
578
|
|
|
467
579
|
### Post-release/Hotfix
|
|
@@ -540,6 +652,24 @@ kacl:
|
|
|
540
652
|
auto_generate: True
|
|
541
653
|
extension:
|
|
542
654
|
post_release_version_prefix: null
|
|
655
|
+
issue_tracker:
|
|
656
|
+
jira:
|
|
657
|
+
host: null
|
|
658
|
+
username: null
|
|
659
|
+
password: null
|
|
660
|
+
issue_patterns: ["[A-Z]+-[0-9]+"]
|
|
661
|
+
comment_template: |
|
|
662
|
+
# 🚀 New version [v{new_version}]({link})
|
|
663
|
+
|
|
664
|
+
A new release has been created referencing this issue. Please check it out.
|
|
665
|
+
|
|
666
|
+
## 🚧 Changes in this version
|
|
667
|
+
|
|
668
|
+
{changes}
|
|
669
|
+
|
|
670
|
+
## 🧭 Reference
|
|
671
|
+
|
|
672
|
+
Code: [Source Code Management System]({link})
|
|
543
673
|
```
|
|
544
674
|
|
|
545
675
|
## Development
|
|
@@ -26,4 +26,23 @@ kacl:
|
|
|
26
26
|
unreleased_changes_template: '{host}/compare/{latest_version}...master'
|
|
27
27
|
initial_version_template: '{host}/tree/{version}'
|
|
28
28
|
extension:
|
|
29
|
-
post_release_version_prefix: null
|
|
29
|
+
post_release_version_prefix: null
|
|
30
|
+
issue_tracker:
|
|
31
|
+
jira:
|
|
32
|
+
host: null
|
|
33
|
+
username: null
|
|
34
|
+
password: null
|
|
35
|
+
issue_patterns: ["[A-Z]+-[0-9]+"]
|
|
36
|
+
comment_template: |
|
|
37
|
+
# 🚀 New version [v{new_version}]({link})
|
|
38
|
+
|
|
39
|
+
A new release has been created referencing this issue. Please check it out.
|
|
40
|
+
|
|
41
|
+
## 🚧 Changes in this version
|
|
42
|
+
|
|
43
|
+
{changes}
|
|
44
|
+
|
|
45
|
+
## 🧭 Reference
|
|
46
|
+
|
|
47
|
+
Code: [Source Code Management System]({link})
|
|
48
|
+
|
|
@@ -44,6 +44,34 @@ class KACLConfig:
|
|
|
44
44
|
"post_release_version_prefix"
|
|
45
45
|
)
|
|
46
46
|
|
|
47
|
+
# issue tracker config
|
|
48
|
+
self.issue_tracker_jira_host = (
|
|
49
|
+
self.__config.get("issue_tracker", {}).get("jira", {}).get("host")
|
|
50
|
+
)
|
|
51
|
+
self.issue_tracker_jira_username = (
|
|
52
|
+
self.__config.get("issue_tracker", {}).get("jira", {}).get("username")
|
|
53
|
+
)
|
|
54
|
+
self.issue_tracker_jira_password = (
|
|
55
|
+
self.__config.get("issue_tracker", {}).get("jira", {}).get("password")
|
|
56
|
+
)
|
|
57
|
+
self.issue_tracker_jira_issue_patterns = (
|
|
58
|
+
self.__config.get("issue_tracker", {})
|
|
59
|
+
.get("jira", {})
|
|
60
|
+
.get("issue_patterns", [])
|
|
61
|
+
)
|
|
62
|
+
self.issue_tracker_jira_comment_template = (
|
|
63
|
+
self.__config.get("issue_tracker", {})
|
|
64
|
+
.get("jira", {})
|
|
65
|
+
.get("comment_template")
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if not self.issue_tracker_jira_host:
|
|
69
|
+
self.issue_tracker_jira_host = os.getenv("JIRA_HOST", None)
|
|
70
|
+
if not self.issue_tracker_jira_username:
|
|
71
|
+
self.issue_tracker_jira_username = os.getenv("JIRA_USERNAME", None)
|
|
72
|
+
if not self.issue_tracker_jira_password:
|
|
73
|
+
self.issue_tracker_jira_password = os.getenv("JIRA_PASSWORD", None)
|
|
74
|
+
|
|
47
75
|
@staticmethod
|
|
48
76
|
def merge(a, b, path=None):
|
|
49
77
|
"""merge two dictionaries
|
|
@@ -7,8 +7,12 @@ import semver
|
|
|
7
7
|
from kacl.config import KACLConfig
|
|
8
8
|
from kacl.element import KACLElement
|
|
9
9
|
from kacl.exception import KACLException
|
|
10
|
+
from kacl.jira_client import KACLJiraClient
|
|
10
11
|
from kacl.link_provider import LinkProvider
|
|
11
12
|
from kacl.parser import KACLParser
|
|
13
|
+
from kacl.utils import convert_markdown_to_jira
|
|
14
|
+
from kacl.utils import extract_issue_ids
|
|
15
|
+
from kacl.utils import replace_env_variables
|
|
12
16
|
from kacl.validation import KACLValidation
|
|
13
17
|
from kacl.version import KACLVersion
|
|
14
18
|
|
|
@@ -293,10 +297,17 @@ class KACLDocument:
|
|
|
293
297
|
):
|
|
294
298
|
comp_result = future_version.compare(last_version)
|
|
295
299
|
# 2.3 if 'last version' was NOT a 'post version' ensure 'post version' has same 'base version'
|
|
296
|
-
elif future_version_base != last_version_base:
|
|
297
|
-
comp_result = -1 # indicate error
|
|
298
300
|
else:
|
|
299
|
-
comp_result =
|
|
301
|
+
comp_result = future_version_base.compare(last_version_base)
|
|
302
|
+
# 2.4 if 'last version' has same 'base version' as 'future version' this is ok, because we
|
|
303
|
+
# define post version as 'higher' than base version
|
|
304
|
+
if comp_result == 0:
|
|
305
|
+
comp_result = 1
|
|
306
|
+
elif (
|
|
307
|
+
last_version.prerelease
|
|
308
|
+
and post_release_version_prefix in last_version.prerelease
|
|
309
|
+
):
|
|
310
|
+
comp_result = future_version_base.compare(last_version_base)
|
|
300
311
|
else:
|
|
301
312
|
comp_result = future_version.compare(last_version)
|
|
302
313
|
else:
|
|
@@ -354,7 +365,7 @@ class KACLDocument:
|
|
|
354
365
|
link_provider.initial_version(**fargs)
|
|
355
366
|
)
|
|
356
367
|
|
|
357
|
-
def get(self, version):
|
|
368
|
+
def get(self, version) -> KACLVersion:
|
|
358
369
|
"""Returns the selected version
|
|
359
370
|
|
|
360
371
|
Arguments:
|
|
@@ -455,6 +466,74 @@ class KACLDocument:
|
|
|
455
466
|
else:
|
|
456
467
|
versions[0].set_link(link_provider.initial_version(**fargs))
|
|
457
468
|
|
|
469
|
+
def get_associated_issues(self, version=None):
|
|
470
|
+
"""returns all issues for the given version"""
|
|
471
|
+
kacl_version = None
|
|
472
|
+
if not version:
|
|
473
|
+
# if no version is given, we will use the current version
|
|
474
|
+
kacl_version = self.get(self.current_version())
|
|
475
|
+
else:
|
|
476
|
+
kacl_version = self.get(version)
|
|
477
|
+
|
|
478
|
+
patterns = {"jira": self.config.issue_tracker_jira_issue_patterns}
|
|
479
|
+
|
|
480
|
+
# get all issue ids
|
|
481
|
+
return extract_issue_ids(kacl_version, patterns)
|
|
482
|
+
|
|
483
|
+
def render_comments(self, version=None) -> dict[str:str]:
|
|
484
|
+
if version is None:
|
|
485
|
+
version = self.current_version()
|
|
486
|
+
|
|
487
|
+
changes = self.get(version)
|
|
488
|
+
link_provider = self.__get_link_provider()
|
|
489
|
+
|
|
490
|
+
format_string = {
|
|
491
|
+
"new_version": version,
|
|
492
|
+
"changes": changes.body(),
|
|
493
|
+
"link": link_provider.version_link(version),
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
comments = {}
|
|
497
|
+
|
|
498
|
+
if self.config.issue_tracker_jira_comment_template:
|
|
499
|
+
jira_comment = replace_env_variables(
|
|
500
|
+
self.config.issue_tracker_jira_comment_template
|
|
501
|
+
)
|
|
502
|
+
jira_comment = jira_comment.format(**format_string)
|
|
503
|
+
jira_comment = convert_markdown_to_jira(jira_comment)
|
|
504
|
+
comments["jira"] = jira_comment
|
|
505
|
+
|
|
506
|
+
return comments
|
|
507
|
+
|
|
508
|
+
def add_comments(self, version=None) -> dict[str : dict[str:bool]]:
|
|
509
|
+
# This function will parse all versions for known issue ids and search the defined
|
|
510
|
+
# issue tracking system for the issue. If the issue is found, a comment will be added to the
|
|
511
|
+
# issue with the changelog/release information
|
|
512
|
+
|
|
513
|
+
issue_ids = self.get_associated_issues(version)
|
|
514
|
+
|
|
515
|
+
jira_client = None
|
|
516
|
+
if "jira" in issue_ids and len(issue_ids["jira"]) > 0:
|
|
517
|
+
client = KACLJiraClient(self.config)
|
|
518
|
+
if client.is_authenticated():
|
|
519
|
+
jira_client = client
|
|
520
|
+
|
|
521
|
+
rendered_comments = self.render_comments(version)
|
|
522
|
+
|
|
523
|
+
report = {"jira": {}}
|
|
524
|
+
|
|
525
|
+
if jira_client:
|
|
526
|
+
# comment on jira tickets
|
|
527
|
+
for jira_issue in issue_ids["jira"]:
|
|
528
|
+
try:
|
|
529
|
+
jira_client.add_comment(jira_issue, rendered_comments["jira"])
|
|
530
|
+
report["jira"][jira_issue] = True
|
|
531
|
+
except Exception:
|
|
532
|
+
report["jira"][jira_issue] = False
|
|
533
|
+
continue
|
|
534
|
+
|
|
535
|
+
return report
|
|
536
|
+
|
|
458
537
|
def header(self):
|
|
459
538
|
"""Gives access to the top level heading element
|
|
460
539
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from jira import JIRA
|
|
2
|
+
|
|
3
|
+
from kacl.config import KACLConfig
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class KACLJiraClient:
|
|
7
|
+
def __init__(self, config: KACLConfig):
|
|
8
|
+
self.config = config
|
|
9
|
+
self.client = JIRA(
|
|
10
|
+
server=config.issue_tracker_jira_host,
|
|
11
|
+
basic_auth=(
|
|
12
|
+
config.issue_tracker_jira_username,
|
|
13
|
+
config.issue_tracker_jira_password,
|
|
14
|
+
),
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
def is_authenticated(self):
|
|
18
|
+
try:
|
|
19
|
+
# Attempt to fetch the current user as a way to check if authentication was successful
|
|
20
|
+
self.client.current_user()
|
|
21
|
+
except Exception:
|
|
22
|
+
return False
|
|
23
|
+
return True
|
|
24
|
+
|
|
25
|
+
def add_comment(self, issue_key, comment):
|
|
26
|
+
"""
|
|
27
|
+
Adds a comment to a JIRA issue.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
issue_key (str): The key of the issue to add the comment to.
|
|
31
|
+
comment (str): The text of the comment to add.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
None
|
|
35
|
+
"""
|
|
36
|
+
self.client.add_comment(issue_key, comment)
|
|
@@ -611,6 +611,103 @@ def new(output_file):
|
|
|
611
611
|
click.echo(kacl_changelog_content)
|
|
612
612
|
|
|
613
613
|
|
|
614
|
+
@cli.command("add-comments")
|
|
615
|
+
@click.pass_context
|
|
616
|
+
@click.option(
|
|
617
|
+
"--jira-username",
|
|
618
|
+
required=False,
|
|
619
|
+
type=str,
|
|
620
|
+
default=os.getenv(
|
|
621
|
+
"JIRA_USERNAME",
|
|
622
|
+
None,
|
|
623
|
+
),
|
|
624
|
+
help="JIRA username. Will also look for JIRA_USERNAME environment variable.",
|
|
625
|
+
)
|
|
626
|
+
@click.option(
|
|
627
|
+
"--jira-password",
|
|
628
|
+
required=False,
|
|
629
|
+
type=str,
|
|
630
|
+
default=os.getenv(
|
|
631
|
+
"JIRA_PASSWORD",
|
|
632
|
+
None,
|
|
633
|
+
),
|
|
634
|
+
help="JIRA password. Will also look for JIRA_PASSWORD environment variable.",
|
|
635
|
+
)
|
|
636
|
+
@click.option(
|
|
637
|
+
"--jira-host",
|
|
638
|
+
required=False,
|
|
639
|
+
type=str,
|
|
640
|
+
default=os.getenv(
|
|
641
|
+
"JIRA_HOST",
|
|
642
|
+
None,
|
|
643
|
+
),
|
|
644
|
+
help="JIRA host. Will also look for JIRA_HOST environment variable.",
|
|
645
|
+
)
|
|
646
|
+
@click.option(
|
|
647
|
+
"--jira-issue-pattern",
|
|
648
|
+
required=False,
|
|
649
|
+
multiple=True,
|
|
650
|
+
help="Issue pattern to search the changlog for. Can be specified multiple times.",
|
|
651
|
+
)
|
|
652
|
+
@click.option(
|
|
653
|
+
"--jira-comment-template",
|
|
654
|
+
required=False,
|
|
655
|
+
default=None,
|
|
656
|
+
type=str,
|
|
657
|
+
help="JIRA comment template.",
|
|
658
|
+
)
|
|
659
|
+
@click.option(
|
|
660
|
+
"--fail",
|
|
661
|
+
is_flag=True,
|
|
662
|
+
help="Will fail if comments could not be added.",
|
|
663
|
+
)
|
|
664
|
+
@click.argument("version", type=str)
|
|
665
|
+
def add_comments(
|
|
666
|
+
ctx,
|
|
667
|
+
version,
|
|
668
|
+
jira_username,
|
|
669
|
+
jira_password,
|
|
670
|
+
jira_host,
|
|
671
|
+
jira_issue_pattern,
|
|
672
|
+
jira_comment_template,
|
|
673
|
+
fail,
|
|
674
|
+
):
|
|
675
|
+
"""Will add comments to issues identified within the CHANGELOG. Currently supported systems are: [JIRA]"""
|
|
676
|
+
kacl_changelog = load_changelog(ctx)
|
|
677
|
+
kacl_config = kacl_changelog.config
|
|
678
|
+
|
|
679
|
+
if jira_host:
|
|
680
|
+
kacl_config.issue_tracker_jira_host = jira_host
|
|
681
|
+
if jira_username:
|
|
682
|
+
kacl_config.issue_tracker_jira_username = jira_username
|
|
683
|
+
if jira_password:
|
|
684
|
+
kacl_config.issue_tracker_jira_password = jira_password
|
|
685
|
+
if jira_issue_pattern:
|
|
686
|
+
kacl_config.issue_tracker_jira_issue_patterns = list(jira_issue_pattern)
|
|
687
|
+
if jira_comment_template:
|
|
688
|
+
kacl_config.issue_tracker_jira_comment_template = jira_comment_template
|
|
689
|
+
|
|
690
|
+
raise_on_invalid(kacl_changelog)
|
|
691
|
+
|
|
692
|
+
issues = kacl_changelog.get_associated_issues(version)
|
|
693
|
+
for issue_type in issues.keys():
|
|
694
|
+
click.secho(f"Found {len(issues[issue_type])} '{issue_type}' issues", fg="blue")
|
|
695
|
+
for issue in issues[issue_type]:
|
|
696
|
+
click.secho(f"{issue_type}: {issue}")
|
|
697
|
+
|
|
698
|
+
report = kacl_changelog.add_comments(version)
|
|
699
|
+
|
|
700
|
+
failed = False
|
|
701
|
+
for issue_type in report.keys():
|
|
702
|
+
for issue, success in report[issue_type].items():
|
|
703
|
+
if not success:
|
|
704
|
+
failed = True
|
|
705
|
+
click.secho(f"Failed to add comment to {issue_type}: {issue}", fg="red")
|
|
706
|
+
|
|
707
|
+
if fail and failed:
|
|
708
|
+
sys.exit(1)
|
|
709
|
+
|
|
710
|
+
|
|
614
711
|
def start():
|
|
615
712
|
try:
|
|
616
713
|
cli(obj={})
|
|
@@ -49,3 +49,8 @@ class LinkProvider:
|
|
|
49
49
|
previous_version=previous_version,
|
|
50
50
|
latest_version=latest_version,
|
|
51
51
|
)
|
|
52
|
+
|
|
53
|
+
def version_link(self, version=None, previous_version=None, latest_version=None):
|
|
54
|
+
return self.initial_version(
|
|
55
|
+
version=version, previous_version=version, latest_version=version
|
|
56
|
+
)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
from kacl.version import KACLVersion
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def extract_issue_ids(
|
|
8
|
+
version: KACLVersion,
|
|
9
|
+
search_patterns: dict[str : list[str]] = {"jira": [r"[A-Z]+-[0-9]+"]},
|
|
10
|
+
) -> dict[str : list[str]]:
|
|
11
|
+
"""
|
|
12
|
+
Extract JIRA IDs from a version object.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
version (KACLVersion): The version object to extract JIRA IDs from.
|
|
16
|
+
search_patterns (list[str], optional): A list of search patterns to use. Defaults to ["[A-Z]+-[0-9]+"].
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
list[str]: A list of JIRA IDs.
|
|
20
|
+
"""
|
|
21
|
+
issue_ids = {}
|
|
22
|
+
for key in search_patterns.keys():
|
|
23
|
+
ids = []
|
|
24
|
+
for pattern in search_patterns[key]:
|
|
25
|
+
ids.extend(re.findall(pattern, (version.body())))
|
|
26
|
+
issue_ids[key] = ids
|
|
27
|
+
return issue_ids
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def replace_env_variables(text):
|
|
31
|
+
"""
|
|
32
|
+
Parses a given text and replaces occurrences of {env.VAR} with the value of the environment
|
|
33
|
+
variable VAR if it exists, or with an empty string if it does not.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
text (str): The text to parse and replace environment variables in.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
str: The text with environment variables replaced.
|
|
40
|
+
"""
|
|
41
|
+
# Regular expression to find {env.VAR} patterns
|
|
42
|
+
pattern = re.compile(r"\{env\.([A-Za-z_][A-Za-z0-9_]*)\}")
|
|
43
|
+
|
|
44
|
+
# Function to replace each match
|
|
45
|
+
def replace_match(match):
|
|
46
|
+
# Extract the environment variable name from the match
|
|
47
|
+
env_var = match.group(1)
|
|
48
|
+
# Return the environment variable's value if it exists, else return an empty string
|
|
49
|
+
return os.getenv(env_var, "")
|
|
50
|
+
|
|
51
|
+
# Replace all occurrences of the pattern in the text
|
|
52
|
+
return pattern.sub(replace_match, text)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def convert_markdown_to_jira(markdown_text):
|
|
56
|
+
# Convert markdown headings to JIRA headings
|
|
57
|
+
def replace_heading(match):
|
|
58
|
+
heading_level = len(match.group(1))
|
|
59
|
+
return f"h{heading_level}. {match.group(2)}"
|
|
60
|
+
|
|
61
|
+
# Convert markdown links to JIRA links
|
|
62
|
+
def replace_link(match):
|
|
63
|
+
link_text = match.group(1)
|
|
64
|
+
url = match.group(2)
|
|
65
|
+
return f"[{link_text}|{url}]"
|
|
66
|
+
|
|
67
|
+
converted_text = re.sub(
|
|
68
|
+
r"^(#{1,6})\s+(.*)", replace_heading, markdown_text, flags=re.MULTILINE
|
|
69
|
+
)
|
|
70
|
+
converted_text = re.sub(r"\[(.*?)\]\((.*?)\)", replace_link, converted_text)
|
|
71
|
+
return converted_text
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-kacl
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
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
|
|
@@ -8,16 +8,17 @@ Author-email: schmieder.matthias@gmail.com
|
|
|
8
8
|
License: MIT
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Topic :: Software Development :: Version Control
|
|
14
|
-
Requires-Python: >=3.
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: click
|
|
18
18
|
Requires-Dist: semver
|
|
19
19
|
Requires-Dist: gitpython
|
|
20
20
|
Requires-Dist: pyyaml
|
|
21
|
+
Requires-Dist: jira
|
|
21
22
|
|
|
22
23
|
# python-kacl
|
|
23
24
|
|
|
@@ -44,6 +45,10 @@ A tool for verifying and modifying changelog in the [**K**eep-**A-C**hange-**L**
|
|
|
44
45
|
- [Link Generation](#link-generation)
|
|
45
46
|
- [Squashing releases](#squashing-releases)
|
|
46
47
|
- [Example](#example)
|
|
48
|
+
- [Issue Management Integration](#issue-management-integration)
|
|
49
|
+
- [Adding Comments to Issues](#adding-comments-to-issues)
|
|
50
|
+
- [Command Options](#command-options)
|
|
51
|
+
- [Templating the Comment](#templating-the-comment)
|
|
47
52
|
- [Extensions](#extensions)
|
|
48
53
|
- [Post-release/Hotfix](#post-releasehotfix)
|
|
49
54
|
- [Config file](#config-file)
|
|
@@ -483,6 +488,114 @@ kacl-cli -f CHANGELOG.md squash \
|
|
|
483
488
|
|
|
484
489
|
This example will squash all versions between `0.0.1` and `1.0.0` and move them under `1.0.0`
|
|
485
490
|
|
|
491
|
+
## Issue Management Integration
|
|
492
|
+
|
|
493
|
+
With `python-kacl >= 0.6.0`, you can integrate changelog and release management directly into your Issue Management System. Currently, the supported system is JIRA.
|
|
494
|
+
|
|
495
|
+
It is common practice to reference fixed or addressed issues in the changelog, as shown below:
|
|
496
|
+
|
|
497
|
+
```markdown
|
|
498
|
+
## Unreleased
|
|
499
|
+
### Added
|
|
500
|
+
- JIRA-1754 Just unreleased stuff
|
|
501
|
+
|
|
502
|
+
## 1.0.0 - 2017-06-20
|
|
503
|
+
### Added
|
|
504
|
+
- JIRA-9: added UI functionality
|
|
505
|
+
|
|
506
|
+
### Fixed
|
|
507
|
+
- issue JIRA-13 closed by applying the solution
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Adding Comments to Issues
|
|
511
|
+
|
|
512
|
+
The `add-comments` command allows you to detect issue IDs using a custom pattern and create comments in the Issue Tracking system about a new release.
|
|
513
|
+
|
|
514
|
+
You can pass all necessary arguments via CLI or set up your `.kacl.yaml` configuration file. The following options are available:
|
|
515
|
+
|
|
516
|
+
```yaml
|
|
517
|
+
issue_tracker:
|
|
518
|
+
jira:
|
|
519
|
+
host: jira.atlassian.com # The host name of your JIRA instance
|
|
520
|
+
username: null # The username to login. Uses JIRA_USERNAME environment variable if available
|
|
521
|
+
password: null # The password to login. Uses JIRA_PASSWORD environment variable if available
|
|
522
|
+
issue_patterns: # List of regex patterns to identify the issues
|
|
523
|
+
- "[A-Z]+-[0-9]+"
|
|
524
|
+
- "JIRA-[0-9]+"
|
|
525
|
+
comment_template: | # A text template used to comment on the issue
|
|
526
|
+
# 🚀 New version [v{new_version}]({link})
|
|
527
|
+
|
|
528
|
+
A new release has been created referencing this issue. Please check it out.
|
|
529
|
+
|
|
530
|
+
## 🚧 Changes in this version
|
|
531
|
+
|
|
532
|
+
{changes}
|
|
533
|
+
|
|
534
|
+
## 🧭 Reference
|
|
535
|
+
|
|
536
|
+
Code: [Source Code Management System]({link})
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
Run the following command to create the comments:
|
|
540
|
+
|
|
541
|
+
```bash
|
|
542
|
+
kacl-cli add-comments 1.0.0
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
### Command Options
|
|
546
|
+
|
|
547
|
+
See all available command options:
|
|
548
|
+
|
|
549
|
+
```bash
|
|
550
|
+
Usage: kacl-cli add-comments [OPTIONS] VERSION
|
|
551
|
+
|
|
552
|
+
Adds comments to issues identified within the CHANGELOG. Currently
|
|
553
|
+
supported system: JIRA
|
|
554
|
+
|
|
555
|
+
Options:
|
|
556
|
+
--jira-username TEXT JIRA username. Will also look for the
|
|
557
|
+
JIRA_USERNAME environment variable.
|
|
558
|
+
--jira-password TEXT JIRA password. Will also look for the
|
|
559
|
+
JIRA_PASSWORD environment variable.
|
|
560
|
+
--jira-host TEXT JIRA host. Will also look for the JIRA_HOST
|
|
561
|
+
environment variable.
|
|
562
|
+
--jira-issue-pattern TEXT Issue pattern to search the changelog for. Can
|
|
563
|
+
be specified multiple times.
|
|
564
|
+
--jira-comment-template TEXT JIRA comment template.
|
|
565
|
+
--fail Fail if comments could not be added.
|
|
566
|
+
--help Show this message and exit.
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
### Templating the Comment
|
|
570
|
+
|
|
571
|
+
The `comment_template` parameter allows various templating options. The following template variables are available:
|
|
572
|
+
|
|
573
|
+
| Variable | Description |
|
|
574
|
+
| -------------- | ---------------------------------------------------------------------------------------------------- |
|
|
575
|
+
| `new_version` | The version that was just released |
|
|
576
|
+
| `changes` | The markdown content within the change section of your CHANGELOG |
|
|
577
|
+
| `link` | The link to the version within your source code management system according to the link configuration |
|
|
578
|
+
| `env.MYENVVAR` | Any environment variable |
|
|
579
|
+
|
|
580
|
+
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:
|
|
581
|
+
|
|
582
|
+
```yaml
|
|
583
|
+
comment_template: | # A text template used to comment on the issue
|
|
584
|
+
# 🚀 New version [v{new_version}]({link})
|
|
585
|
+
|
|
586
|
+
A new release has been created referencing this issue. Please check it out.
|
|
587
|
+
|
|
588
|
+
## 🚧 Changes in this version
|
|
589
|
+
|
|
590
|
+
{changes}
|
|
591
|
+
|
|
592
|
+
## 🧭 Reference
|
|
593
|
+
|
|
594
|
+
Code: [Source Code Management System]({link})
|
|
595
|
+
Pipeline: [Pipeline ({env.CI_PIPELINE_IID})]({env.CI_PIPELINE_URL})
|
|
596
|
+
GitLab Project: [({env.CI_PROJECT_TITLE})]({env.CI_PROJECT_URL})
|
|
597
|
+
```
|
|
598
|
+
|
|
486
599
|
## Extensions
|
|
487
600
|
|
|
488
601
|
### Post-release/Hotfix
|
|
@@ -561,6 +674,24 @@ kacl:
|
|
|
561
674
|
auto_generate: True
|
|
562
675
|
extension:
|
|
563
676
|
post_release_version_prefix: null
|
|
677
|
+
issue_tracker:
|
|
678
|
+
jira:
|
|
679
|
+
host: null
|
|
680
|
+
username: null
|
|
681
|
+
password: null
|
|
682
|
+
issue_patterns: ["[A-Z]+-[0-9]+"]
|
|
683
|
+
comment_template: |
|
|
684
|
+
# 🚀 New version [v{new_version}]({link})
|
|
685
|
+
|
|
686
|
+
A new release has been created referencing this issue. Please check it out.
|
|
687
|
+
|
|
688
|
+
## 🚧 Changes in this version
|
|
689
|
+
|
|
690
|
+
{changes}
|
|
691
|
+
|
|
692
|
+
## 🧭 Reference
|
|
693
|
+
|
|
694
|
+
Code: [Source Code Management System]({link})
|
|
564
695
|
```
|
|
565
696
|
|
|
566
697
|
## Development
|
|
@@ -9,10 +9,12 @@ kacl/config.py
|
|
|
9
9
|
kacl/document.py
|
|
10
10
|
kacl/element.py
|
|
11
11
|
kacl/exception.py
|
|
12
|
+
kacl/jira_client.py
|
|
12
13
|
kacl/kacl_cli.py
|
|
13
14
|
kacl/link_provider.py
|
|
14
15
|
kacl/parser.py
|
|
15
16
|
kacl/serializer.py
|
|
17
|
+
kacl/utils.py
|
|
16
18
|
kacl/validation.py
|
|
17
19
|
kacl/version.py
|
|
18
20
|
kacl/config/kacl-default.yml
|
|
@@ -11,7 +11,7 @@ this_directory = path.abspath(path.dirname(__file__))
|
|
|
11
11
|
with open(path.join(this_directory, "README.md"), encoding="utf-8") as f:
|
|
12
12
|
long_description = f.read()
|
|
13
13
|
|
|
14
|
-
version = "0.
|
|
14
|
+
version = "0.6.0"
|
|
15
15
|
|
|
16
16
|
version = f"{version}{os.environ.get('PIP_VERSION_POSTFIX', '')}"
|
|
17
17
|
|
|
@@ -37,13 +37,13 @@ setup(
|
|
|
37
37
|
license="MIT",
|
|
38
38
|
packages=find_packages(),
|
|
39
39
|
include_package_data=True,
|
|
40
|
-
python_requires=">=3.
|
|
40
|
+
python_requires=">=3.9",
|
|
41
41
|
install_requires=requirements,
|
|
42
42
|
zip_safe=False,
|
|
43
43
|
classifiers=[
|
|
44
44
|
"License :: OSI Approved :: MIT License",
|
|
45
45
|
"Programming Language :: Python :: 3",
|
|
46
|
-
"Programming Language :: Python :: 3.
|
|
46
|
+
"Programming Language :: Python :: 3.9",
|
|
47
47
|
"Intended Audience :: Developers",
|
|
48
48
|
"Topic :: Software Development :: Version Control",
|
|
49
49
|
],
|
|
@@ -2,6 +2,7 @@ import json
|
|
|
2
2
|
import os
|
|
3
3
|
import shutil
|
|
4
4
|
|
|
5
|
+
import pytest
|
|
5
6
|
from click.testing import CliRunner
|
|
6
7
|
from freezegun import freeze_time
|
|
7
8
|
|
|
@@ -95,6 +96,128 @@ def test_release_patch(tmp_path, snapshot):
|
|
|
95
96
|
snapshot_directory(snapshot=snapshot, directory_path=project_root_path)
|
|
96
97
|
|
|
97
98
|
|
|
99
|
+
@freeze_time("2023-01-01")
|
|
100
|
+
def test_release_post_bump(tmp_path, snapshot):
|
|
101
|
+
runner = CliRunner()
|
|
102
|
+
resources_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/")
|
|
103
|
+
changelog_file = os.path.join(resources_dir, "CHANGELOG_with_changes.md")
|
|
104
|
+
|
|
105
|
+
with runner.isolated_filesystem(temp_dir=tmp_path) as project_root_path:
|
|
106
|
+
shutil.copyfile(changelog_file, os.path.join(project_root_path, "CHANGELOG.md"))
|
|
107
|
+
result = runner.invoke(
|
|
108
|
+
cli,
|
|
109
|
+
[
|
|
110
|
+
"-c",
|
|
111
|
+
os.path.join(resources_dir, "extension-config.yml"),
|
|
112
|
+
"-f",
|
|
113
|
+
"CHANGELOG.md",
|
|
114
|
+
"release",
|
|
115
|
+
"post",
|
|
116
|
+
"-m",
|
|
117
|
+
],
|
|
118
|
+
catch_exceptions=False,
|
|
119
|
+
)
|
|
120
|
+
assert result.exit_code == 0, result.output
|
|
121
|
+
snapshot_directory(snapshot=snapshot, directory_path=project_root_path)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@freeze_time("2023-01-01")
|
|
125
|
+
def test_release_post_manual(tmp_path, snapshot):
|
|
126
|
+
runner = CliRunner()
|
|
127
|
+
resources_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/")
|
|
128
|
+
changelog_file = os.path.join(resources_dir, "CHANGELOG_with_changes.md")
|
|
129
|
+
|
|
130
|
+
with runner.isolated_filesystem(temp_dir=tmp_path) as project_root_path:
|
|
131
|
+
shutil.copyfile(changelog_file, os.path.join(project_root_path, "CHANGELOG.md"))
|
|
132
|
+
result = runner.invoke(
|
|
133
|
+
cli,
|
|
134
|
+
[
|
|
135
|
+
"-c",
|
|
136
|
+
os.path.join(resources_dir, "extension-config.yml"),
|
|
137
|
+
"-f",
|
|
138
|
+
"CHANGELOG.md",
|
|
139
|
+
"release",
|
|
140
|
+
"2.0.0-hotfix.0",
|
|
141
|
+
"-m",
|
|
142
|
+
],
|
|
143
|
+
catch_exceptions=False,
|
|
144
|
+
)
|
|
145
|
+
assert result.exit_code == 0, result.output
|
|
146
|
+
snapshot_directory(snapshot=snapshot, directory_path=project_root_path)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@freeze_time("2023-01-01")
|
|
150
|
+
def test_release_post_manual_fail(tmp_path, snapshot):
|
|
151
|
+
runner = CliRunner()
|
|
152
|
+
resources_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/")
|
|
153
|
+
changelog_file = os.path.join(resources_dir, "CHANGELOG_with_changes.md")
|
|
154
|
+
|
|
155
|
+
with runner.isolated_filesystem(temp_dir=tmp_path) as project_root_path:
|
|
156
|
+
shutil.copyfile(changelog_file, os.path.join(project_root_path, "CHANGELOG.md"))
|
|
157
|
+
result = runner.invoke(
|
|
158
|
+
cli,
|
|
159
|
+
[
|
|
160
|
+
"-c",
|
|
161
|
+
os.path.join(resources_dir, "extension-config.yml"),
|
|
162
|
+
"-f",
|
|
163
|
+
"CHANGELOG.md",
|
|
164
|
+
"release",
|
|
165
|
+
"0.5.0-hotfix.0",
|
|
166
|
+
"-m",
|
|
167
|
+
],
|
|
168
|
+
catch_exceptions=True,
|
|
169
|
+
)
|
|
170
|
+
assert result.exit_code == 1, result.output
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@freeze_time("2023-01-01")
|
|
174
|
+
def test_release_version_manual_fail_same_base_after_post(tmp_path, snapshot):
|
|
175
|
+
runner = CliRunner()
|
|
176
|
+
resources_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/")
|
|
177
|
+
changelog_file = os.path.join(resources_dir, "CHANGELOG_post_with_changes.md")
|
|
178
|
+
|
|
179
|
+
with runner.isolated_filesystem(temp_dir=tmp_path) as project_root_path:
|
|
180
|
+
shutil.copyfile(changelog_file, os.path.join(project_root_path, "CHANGELOG.md"))
|
|
181
|
+
result = runner.invoke(
|
|
182
|
+
cli,
|
|
183
|
+
[
|
|
184
|
+
"-c",
|
|
185
|
+
os.path.join(resources_dir, "extension-config.yml"),
|
|
186
|
+
"-f",
|
|
187
|
+
"CHANGELOG.md",
|
|
188
|
+
"release",
|
|
189
|
+
"1.0.0",
|
|
190
|
+
"-m",
|
|
191
|
+
],
|
|
192
|
+
catch_exceptions=True,
|
|
193
|
+
)
|
|
194
|
+
assert result.exit_code == 1, result.output
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@freeze_time("2023-01-01")
|
|
198
|
+
def test_release_post_manual_same_base(tmp_path, snapshot):
|
|
199
|
+
runner = CliRunner()
|
|
200
|
+
resources_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/")
|
|
201
|
+
changelog_file = os.path.join(resources_dir, "CHANGELOG_with_changes.md")
|
|
202
|
+
|
|
203
|
+
with runner.isolated_filesystem(temp_dir=tmp_path) as project_root_path:
|
|
204
|
+
shutil.copyfile(changelog_file, os.path.join(project_root_path, "CHANGELOG.md"))
|
|
205
|
+
result = runner.invoke(
|
|
206
|
+
cli,
|
|
207
|
+
[
|
|
208
|
+
"-c",
|
|
209
|
+
os.path.join(resources_dir, "extension-config.yml"),
|
|
210
|
+
"-f",
|
|
211
|
+
"CHANGELOG.md",
|
|
212
|
+
"release",
|
|
213
|
+
"1.0.0-post.0",
|
|
214
|
+
"-m",
|
|
215
|
+
],
|
|
216
|
+
catch_exceptions=False,
|
|
217
|
+
)
|
|
218
|
+
assert result.exit_code == 0, result.output
|
|
219
|
+
|
|
220
|
+
|
|
98
221
|
@freeze_time("2023-01-01")
|
|
99
222
|
def test_release_minor(tmp_path, snapshot):
|
|
100
223
|
runner = CliRunner()
|
|
@@ -253,3 +376,43 @@ def test_squash_current(tmp_path, snapshot):
|
|
|
253
376
|
)
|
|
254
377
|
assert result.exit_code == 0, result.output
|
|
255
378
|
snapshot_directory(snapshot=snapshot, directory_path=project_root_path)
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
@pytest.mark.skip(reason="No issue tracker openly available, test locally.")
|
|
382
|
+
def test_add_comments(tmp_path):
|
|
383
|
+
runner = CliRunner()
|
|
384
|
+
root_dir = os.path.join(
|
|
385
|
+
os.path.dirname(os.path.realpath(__file__)),
|
|
386
|
+
"..",
|
|
387
|
+
)
|
|
388
|
+
resources_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/")
|
|
389
|
+
changelog_file = os.path.join(resources_dir, "CHANGELOG_issue_management.md")
|
|
390
|
+
|
|
391
|
+
with runner.isolated_filesystem(temp_dir=tmp_path) as project_root_path:
|
|
392
|
+
shutil.copyfile(changelog_file, os.path.join(project_root_path, "CHANGELOG.md"))
|
|
393
|
+
shutil.copytree(
|
|
394
|
+
os.path.join(root_dir, ".git"), os.path.join(project_root_path, ".git")
|
|
395
|
+
)
|
|
396
|
+
result = runner.invoke(
|
|
397
|
+
cli,
|
|
398
|
+
[
|
|
399
|
+
"-f",
|
|
400
|
+
"CHANGELOG.md",
|
|
401
|
+
"add-comments",
|
|
402
|
+
"1.0.0",
|
|
403
|
+
"--jira-username",
|
|
404
|
+
os.getenv("JIRA_USERNAME"),
|
|
405
|
+
"--jira-password",
|
|
406
|
+
os.getenv("JIRA_PASSWORD"),
|
|
407
|
+
"--jira-host",
|
|
408
|
+
os.getenv("JIRA_HOST"),
|
|
409
|
+
"--jira-issue-pattern",
|
|
410
|
+
"JIRA-[0-9]+",
|
|
411
|
+
"--jira-issue-pattern",
|
|
412
|
+
"MYJIRA-[0-9]+",
|
|
413
|
+
"--jira-issue-pattern",
|
|
414
|
+
"[A-Z]+-[0-9]+",
|
|
415
|
+
],
|
|
416
|
+
catch_exceptions=False,
|
|
417
|
+
)
|
|
418
|
+
assert result.exit_code == 0, result.output
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from unittest import TestCase
|
|
3
3
|
|
|
4
|
+
import pytest
|
|
4
5
|
import yaml
|
|
5
6
|
|
|
6
7
|
import kacl
|
|
@@ -406,3 +407,40 @@ def test_squash(tmp_path, snapshot):
|
|
|
406
407
|
f.write(kacl.dump(changelog))
|
|
407
408
|
|
|
408
409
|
snapshot_directory(snapshot=snapshot, directory_path=tmp_path)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
@pytest.mark.skip(reason="No issue tracker openly available, test locally.")
|
|
413
|
+
def test_issue_tracker_comment(tmp_path):
|
|
414
|
+
changelog_file = os.path.join(
|
|
415
|
+
os.path.dirname(os.path.realpath(__file__)),
|
|
416
|
+
"data/CHANGELOG_issue_management.md",
|
|
417
|
+
)
|
|
418
|
+
changelog = kacl.load(changelog_file)
|
|
419
|
+
assert changelog.is_valid()
|
|
420
|
+
|
|
421
|
+
changelog.add_comments(version=changelog.current_version())
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def test_render_comments(tmp_path):
|
|
425
|
+
changelog_file = os.path.join(
|
|
426
|
+
os.path.dirname(os.path.realpath(__file__)),
|
|
427
|
+
"data/CHANGELOG_issue_management.md",
|
|
428
|
+
)
|
|
429
|
+
changelog = kacl.load(changelog_file)
|
|
430
|
+
assert changelog.is_valid()
|
|
431
|
+
|
|
432
|
+
rendered_comments = changelog.render_comments(version=changelog.current_version())
|
|
433
|
+
|
|
434
|
+
assert "jira" in rendered_comments
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def test_get_issues(tmp_path):
|
|
438
|
+
changelog_file = os.path.join(
|
|
439
|
+
os.path.dirname(os.path.realpath(__file__)),
|
|
440
|
+
"data/CHANGELOG_issue_management.md",
|
|
441
|
+
)
|
|
442
|
+
changelog = kacl.load(changelog_file)
|
|
443
|
+
assert changelog.is_valid()
|
|
444
|
+
|
|
445
|
+
issues = changelog.get_associated_issues(version=changelog.current_version())
|
|
446
|
+
assert len(issues["jira"]) == 5
|
|
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
|