spreen-pr 0.1.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.
- spreen_pr-0.1.0/LICENSE.txt +21 -0
- spreen_pr-0.1.0/PKG-INFO +112 -0
- spreen_pr-0.1.0/README.md +91 -0
- spreen_pr-0.1.0/pyproject.toml +47 -0
- spreen_pr-0.1.0/setup.cfg +4 -0
- spreen_pr-0.1.0/src/spreen_pr/__init__.py +13 -0
- spreen_pr-0.1.0/src/spreen_pr/application.py +49 -0
- spreen_pr-0.1.0/src/spreen_pr/cli.py +56 -0
- spreen_pr-0.1.0/src/spreen_pr/py.typed +0 -0
- spreen_pr-0.1.0/src/spreen_pr.egg-info/PKG-INFO +112 -0
- spreen_pr-0.1.0/src/spreen_pr.egg-info/SOURCES.txt +14 -0
- spreen_pr-0.1.0/src/spreen_pr.egg-info/dependency_links.txt +1 -0
- spreen_pr-0.1.0/src/spreen_pr.egg-info/entry_points.txt +2 -0
- spreen_pr-0.1.0/src/spreen_pr.egg-info/top_level.txt +1 -0
- spreen_pr-0.1.0/test/test_application.py +64 -0
- spreen_pr-0.1.0/test/test_cli.py +46 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 - present @hayat01sh1da
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
spreen_pr-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spreen-pr
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Print a pull request title with labels derived from the topic branch name.
|
|
5
|
+
Author: hayat01sh1da
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/hayat01sh1da/spreen-pr
|
|
8
|
+
Project-URL: Source, https://github.com/hayat01sh1da/spreen-pr
|
|
9
|
+
Project-URL: Changelog, https://github.com/hayat01sh1da/spreen-pr/blob/master/CHANGELOG.md
|
|
10
|
+
Keywords: github,pull-request,title,label,branch
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE.txt
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
## 1. Environment
|
|
23
|
+
|
|
24
|
+
- Python 3.14.6
|
|
25
|
+
- pip 26.1.2
|
|
26
|
+
|
|
27
|
+
## 2. Installation
|
|
28
|
+
|
|
29
|
+
```command
|
|
30
|
+
$ pipx install spreen-pr
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
(`pip install spreen-pr` works too if you prefer managing the environment yourself.)
|
|
34
|
+
|
|
35
|
+
For development, install the dependencies via requirements.txt:
|
|
36
|
+
|
|
37
|
+
```command
|
|
38
|
+
$ pip install -r requirements.txt
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 3. Execution
|
|
42
|
+
|
|
43
|
+
```command
|
|
44
|
+
$ pr-title hayat01sh1da/issue-89/service/improve-onboarding-flow
|
|
45
|
+
[service] Improve Onboarding Flow
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
With no argument, the current git branch is used:
|
|
49
|
+
|
|
50
|
+
```command
|
|
51
|
+
$ git switch hayat01sh1da/issue-90/hotfix/service/fix_login_crash
|
|
52
|
+
$ pr-title
|
|
53
|
+
[Hotfix][service] Fix Login Crash
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`--format json` exposes the labels separately for scripting and CI:
|
|
57
|
+
|
|
58
|
+
```command
|
|
59
|
+
$ pr-title hayat01sh1da/issue-90/hotfix/service/fix_login_crash --format json
|
|
60
|
+
{"title": "[Hotfix][service] Fix Login Crash", "labels": ["Hotfix", "service"]}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
As a library:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from spreen_pr import Application
|
|
67
|
+
|
|
68
|
+
Application.run(branch_name='hayat01sh1da/issue-89/service/improve-onboarding-flow')
|
|
69
|
+
# => '[service] Improve Onboarding Flow'
|
|
70
|
+
|
|
71
|
+
application = Application(branch_name='hayat01sh1da/issue-90/hotfix/service/fix_login_crash')
|
|
72
|
+
application.title # => '[Hotfix][service] Fix Login Crash'
|
|
73
|
+
application.labels # => ['Hotfix', 'service']
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 4. Unit Test
|
|
77
|
+
|
|
78
|
+
```command
|
|
79
|
+
$ pytest
|
|
80
|
+
============================= test session starts ==============================
|
|
81
|
+
platform linux -- Python 3.14.6, pytest-9.1.1, pluggy-1.6.0
|
|
82
|
+
rootdir: spreen-pr/pypi
|
|
83
|
+
configfile: pyproject.toml
|
|
84
|
+
collected 15 items
|
|
85
|
+
|
|
86
|
+
test/test_application.py ......... [ 60%]
|
|
87
|
+
test/test_cli.py ...... [100%]
|
|
88
|
+
|
|
89
|
+
============================== 15 passed in 0.12s ===============================
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 5. Static Code Analysis
|
|
93
|
+
|
|
94
|
+
```command
|
|
95
|
+
$ flake8 .
|
|
96
|
+
$ autoflake8 --in-place --remove-duplicate-keys --remove-unused-variables --recursive .
|
|
97
|
+
$ autopep8 --in-place --aggressive --aggressive --recursive .
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## 6. Type Checks
|
|
101
|
+
|
|
102
|
+
```command
|
|
103
|
+
$ mypy .
|
|
104
|
+
Success: no issues found in 6 source files
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## 7. Build
|
|
108
|
+
|
|
109
|
+
```command
|
|
110
|
+
$ python -m build
|
|
111
|
+
$ pipx install ./dist/spreen_pr-0.1.0-py3-none-any.whl
|
|
112
|
+
```
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
## 1. Environment
|
|
2
|
+
|
|
3
|
+
- Python 3.14.6
|
|
4
|
+
- pip 26.1.2
|
|
5
|
+
|
|
6
|
+
## 2. Installation
|
|
7
|
+
|
|
8
|
+
```command
|
|
9
|
+
$ pipx install spreen-pr
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
(`pip install spreen-pr` works too if you prefer managing the environment yourself.)
|
|
13
|
+
|
|
14
|
+
For development, install the dependencies via requirements.txt:
|
|
15
|
+
|
|
16
|
+
```command
|
|
17
|
+
$ pip install -r requirements.txt
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 3. Execution
|
|
21
|
+
|
|
22
|
+
```command
|
|
23
|
+
$ pr-title hayat01sh1da/issue-89/service/improve-onboarding-flow
|
|
24
|
+
[service] Improve Onboarding Flow
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
With no argument, the current git branch is used:
|
|
28
|
+
|
|
29
|
+
```command
|
|
30
|
+
$ git switch hayat01sh1da/issue-90/hotfix/service/fix_login_crash
|
|
31
|
+
$ pr-title
|
|
32
|
+
[Hotfix][service] Fix Login Crash
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`--format json` exposes the labels separately for scripting and CI:
|
|
36
|
+
|
|
37
|
+
```command
|
|
38
|
+
$ pr-title hayat01sh1da/issue-90/hotfix/service/fix_login_crash --format json
|
|
39
|
+
{"title": "[Hotfix][service] Fix Login Crash", "labels": ["Hotfix", "service"]}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
As a library:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from spreen_pr import Application
|
|
46
|
+
|
|
47
|
+
Application.run(branch_name='hayat01sh1da/issue-89/service/improve-onboarding-flow')
|
|
48
|
+
# => '[service] Improve Onboarding Flow'
|
|
49
|
+
|
|
50
|
+
application = Application(branch_name='hayat01sh1da/issue-90/hotfix/service/fix_login_crash')
|
|
51
|
+
application.title # => '[Hotfix][service] Fix Login Crash'
|
|
52
|
+
application.labels # => ['Hotfix', 'service']
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 4. Unit Test
|
|
56
|
+
|
|
57
|
+
```command
|
|
58
|
+
$ pytest
|
|
59
|
+
============================= test session starts ==============================
|
|
60
|
+
platform linux -- Python 3.14.6, pytest-9.1.1, pluggy-1.6.0
|
|
61
|
+
rootdir: spreen-pr/pypi
|
|
62
|
+
configfile: pyproject.toml
|
|
63
|
+
collected 15 items
|
|
64
|
+
|
|
65
|
+
test/test_application.py ......... [ 60%]
|
|
66
|
+
test/test_cli.py ...... [100%]
|
|
67
|
+
|
|
68
|
+
============================== 15 passed in 0.12s ===============================
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 5. Static Code Analysis
|
|
72
|
+
|
|
73
|
+
```command
|
|
74
|
+
$ flake8 .
|
|
75
|
+
$ autoflake8 --in-place --remove-duplicate-keys --remove-unused-variables --recursive .
|
|
76
|
+
$ autopep8 --in-place --aggressive --aggressive --recursive .
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 6. Type Checks
|
|
80
|
+
|
|
81
|
+
```command
|
|
82
|
+
$ mypy .
|
|
83
|
+
Success: no issues found in 6 source files
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 7. Build
|
|
87
|
+
|
|
88
|
+
```command
|
|
89
|
+
$ python -m build
|
|
90
|
+
$ pipx install ./dist/spreen_pr-0.1.0-py3-none-any.whl
|
|
91
|
+
```
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "spreen-pr"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Print a pull request title with labels derived from the topic branch name."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE.txt"]
|
|
12
|
+
authors = [{ name = "hayat01sh1da" }]
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
keywords = ["github", "pull-request", "title", "label", "branch"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Topic :: Software Development :: Version Control :: Git",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://github.com/hayat01sh1da/spreen-pr"
|
|
26
|
+
Source = "https://github.com/hayat01sh1da/spreen-pr"
|
|
27
|
+
Changelog = "https://github.com/hayat01sh1da/spreen-pr/blob/master/CHANGELOG.md"
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
pr-title = "spreen_pr.cli:main"
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.packages.find]
|
|
33
|
+
where = ["src"]
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.package-data]
|
|
36
|
+
spreen_pr = ["py.typed"]
|
|
37
|
+
|
|
38
|
+
[tool.pytest.ini_options]
|
|
39
|
+
pythonpath = ["src"]
|
|
40
|
+
testpaths = ["test"]
|
|
41
|
+
|
|
42
|
+
[tool.mypy]
|
|
43
|
+
python_version = "3.14"
|
|
44
|
+
warn_return_any = true
|
|
45
|
+
warn_unused_configs = true
|
|
46
|
+
disallow_untyped_defs = true
|
|
47
|
+
mypy_path = "src"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Spreens a pull request — the falcon's stoop, then the preen: derives a
|
|
2
|
+
PR title and labels from a topic branch name shaped
|
|
3
|
+
``{user}/{issue}/{category}/{summary}`` (with a hotfix special case) and
|
|
4
|
+
prints them as plain text or JSON."""
|
|
5
|
+
|
|
6
|
+
from .application import Application
|
|
7
|
+
|
|
8
|
+
__version__ = '0.1.0'
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
'Application',
|
|
12
|
+
'__version__',
|
|
13
|
+
]
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Application:
|
|
5
|
+
"""Derives a pull request title and labels from a topic branch name
|
|
6
|
+
shaped ``{user}/{issue}/{category}/{summary}``, with the hotfix special
|
|
7
|
+
case ``{user}/{issue}/hotfix/{category}/{summary}``."""
|
|
8
|
+
|
|
9
|
+
EXPECTED_SHAPE = '{user}/{issue}/{category}/{summary}'
|
|
10
|
+
|
|
11
|
+
@classmethod
|
|
12
|
+
def run(cls, branch_name: str) -> str:
|
|
13
|
+
return cls(branch_name=branch_name).title
|
|
14
|
+
|
|
15
|
+
def __init__(self, branch_name: str) -> None:
|
|
16
|
+
self._branch_name = branch_name
|
|
17
|
+
self._segments = branch_name.split('/')
|
|
18
|
+
self._validate()
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def title(self) -> str:
|
|
22
|
+
labels = ''.join(f'[{label}]' for label in self.labels)
|
|
23
|
+
return f'{labels} {self.topic}'
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def labels(self) -> list[str]:
|
|
27
|
+
if self._is_hotfix():
|
|
28
|
+
return [self._segments[-3].capitalize(), self._segments[-2]]
|
|
29
|
+
return [self._segments[-2]]
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def topic(self) -> str:
|
|
33
|
+
words = re.split(r'[-_]', self._segments[-1])
|
|
34
|
+
return ' '.join(word.capitalize() for word in words)
|
|
35
|
+
|
|
36
|
+
def to_dict(self) -> dict[str, object]:
|
|
37
|
+
return {'title': self.title, 'labels': self.labels}
|
|
38
|
+
|
|
39
|
+
# private
|
|
40
|
+
|
|
41
|
+
def _is_hotfix(self) -> bool:
|
|
42
|
+
return self._segments[-3] == 'hotfix'
|
|
43
|
+
|
|
44
|
+
def _validate(self) -> None:
|
|
45
|
+
if len(self._segments) >= 3 and all(self._segments):
|
|
46
|
+
return
|
|
47
|
+
raise ValueError(
|
|
48
|
+
f'Branch name `{self._branch_name}` does not match the expected '
|
|
49
|
+
f'`{self.EXPECTED_SHAPE}` shape')
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Command line interface behind the `pr-title` executable:
|
|
2
|
+
`pr-title [BRANCH_NAME] [--format text|json]`."""
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import json
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from . import __version__
|
|
10
|
+
from .application import Application
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
14
|
+
parser = argparse.ArgumentParser(
|
|
15
|
+
prog='pr-title',
|
|
16
|
+
description='Print a pull request title with labels derived from '
|
|
17
|
+
'a topic branch name.')
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
'branch_name', nargs='?', metavar='BRANCH_NAME',
|
|
20
|
+
help='Topic branch name (default: the current git branch)')
|
|
21
|
+
parser.add_argument(
|
|
22
|
+
'--format', choices=('text', 'json'), default='text',
|
|
23
|
+
help='Output format (default: text)')
|
|
24
|
+
parser.add_argument('--version', action='version', version=__version__)
|
|
25
|
+
return parser
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _current_git_branch() -> str:
|
|
29
|
+
try:
|
|
30
|
+
return subprocess.run(
|
|
31
|
+
['git', 'branch', '--show-current'],
|
|
32
|
+
capture_output=True, text=True, check=False).stdout.strip()
|
|
33
|
+
except OSError:
|
|
34
|
+
return ''
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def main(argv: list[str] | None = None) -> int:
|
|
38
|
+
args = _build_parser().parse_args(argv)
|
|
39
|
+
try:
|
|
40
|
+
branch_name = args.branch_name or _current_git_branch()
|
|
41
|
+
if not branch_name:
|
|
42
|
+
raise ValueError('No branch name given and the current git '
|
|
43
|
+
'branch could not be detected')
|
|
44
|
+
application = Application(branch_name=branch_name)
|
|
45
|
+
except ValueError as error:
|
|
46
|
+
print(error, file=sys.stderr)
|
|
47
|
+
return 1
|
|
48
|
+
if args.format == 'json':
|
|
49
|
+
print(json.dumps(application.to_dict()))
|
|
50
|
+
else:
|
|
51
|
+
print(application.title)
|
|
52
|
+
return 0
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
if __name__ == '__main__':
|
|
56
|
+
sys.exit(main())
|
|
File without changes
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spreen-pr
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Print a pull request title with labels derived from the topic branch name.
|
|
5
|
+
Author: hayat01sh1da
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/hayat01sh1da/spreen-pr
|
|
8
|
+
Project-URL: Source, https://github.com/hayat01sh1da/spreen-pr
|
|
9
|
+
Project-URL: Changelog, https://github.com/hayat01sh1da/spreen-pr/blob/master/CHANGELOG.md
|
|
10
|
+
Keywords: github,pull-request,title,label,branch
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE.txt
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
## 1. Environment
|
|
23
|
+
|
|
24
|
+
- Python 3.14.6
|
|
25
|
+
- pip 26.1.2
|
|
26
|
+
|
|
27
|
+
## 2. Installation
|
|
28
|
+
|
|
29
|
+
```command
|
|
30
|
+
$ pipx install spreen-pr
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
(`pip install spreen-pr` works too if you prefer managing the environment yourself.)
|
|
34
|
+
|
|
35
|
+
For development, install the dependencies via requirements.txt:
|
|
36
|
+
|
|
37
|
+
```command
|
|
38
|
+
$ pip install -r requirements.txt
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 3. Execution
|
|
42
|
+
|
|
43
|
+
```command
|
|
44
|
+
$ pr-title hayat01sh1da/issue-89/service/improve-onboarding-flow
|
|
45
|
+
[service] Improve Onboarding Flow
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
With no argument, the current git branch is used:
|
|
49
|
+
|
|
50
|
+
```command
|
|
51
|
+
$ git switch hayat01sh1da/issue-90/hotfix/service/fix_login_crash
|
|
52
|
+
$ pr-title
|
|
53
|
+
[Hotfix][service] Fix Login Crash
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`--format json` exposes the labels separately for scripting and CI:
|
|
57
|
+
|
|
58
|
+
```command
|
|
59
|
+
$ pr-title hayat01sh1da/issue-90/hotfix/service/fix_login_crash --format json
|
|
60
|
+
{"title": "[Hotfix][service] Fix Login Crash", "labels": ["Hotfix", "service"]}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
As a library:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from spreen_pr import Application
|
|
67
|
+
|
|
68
|
+
Application.run(branch_name='hayat01sh1da/issue-89/service/improve-onboarding-flow')
|
|
69
|
+
# => '[service] Improve Onboarding Flow'
|
|
70
|
+
|
|
71
|
+
application = Application(branch_name='hayat01sh1da/issue-90/hotfix/service/fix_login_crash')
|
|
72
|
+
application.title # => '[Hotfix][service] Fix Login Crash'
|
|
73
|
+
application.labels # => ['Hotfix', 'service']
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 4. Unit Test
|
|
77
|
+
|
|
78
|
+
```command
|
|
79
|
+
$ pytest
|
|
80
|
+
============================= test session starts ==============================
|
|
81
|
+
platform linux -- Python 3.14.6, pytest-9.1.1, pluggy-1.6.0
|
|
82
|
+
rootdir: spreen-pr/pypi
|
|
83
|
+
configfile: pyproject.toml
|
|
84
|
+
collected 15 items
|
|
85
|
+
|
|
86
|
+
test/test_application.py ......... [ 60%]
|
|
87
|
+
test/test_cli.py ...... [100%]
|
|
88
|
+
|
|
89
|
+
============================== 15 passed in 0.12s ===============================
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 5. Static Code Analysis
|
|
93
|
+
|
|
94
|
+
```command
|
|
95
|
+
$ flake8 .
|
|
96
|
+
$ autoflake8 --in-place --remove-duplicate-keys --remove-unused-variables --recursive .
|
|
97
|
+
$ autopep8 --in-place --aggressive --aggressive --recursive .
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## 6. Type Checks
|
|
101
|
+
|
|
102
|
+
```command
|
|
103
|
+
$ mypy .
|
|
104
|
+
Success: no issues found in 6 source files
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## 7. Build
|
|
108
|
+
|
|
109
|
+
```command
|
|
110
|
+
$ python -m build
|
|
111
|
+
$ pipx install ./dist/spreen_pr-0.1.0-py3-none-any.whl
|
|
112
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE.txt
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/spreen_pr/__init__.py
|
|
5
|
+
src/spreen_pr/application.py
|
|
6
|
+
src/spreen_pr/cli.py
|
|
7
|
+
src/spreen_pr/py.typed
|
|
8
|
+
src/spreen_pr.egg-info/PKG-INFO
|
|
9
|
+
src/spreen_pr.egg-info/SOURCES.txt
|
|
10
|
+
src/spreen_pr.egg-info/dependency_links.txt
|
|
11
|
+
src/spreen_pr.egg-info/entry_points.txt
|
|
12
|
+
src/spreen_pr.egg-info/top_level.txt
|
|
13
|
+
test/test_application.py
|
|
14
|
+
test/test_cli.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
spreen_pr
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from spreen_pr import Application
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@pytest.mark.parametrize(
|
|
7
|
+
('branch_name', 'expected'),
|
|
8
|
+
[
|
|
9
|
+
(
|
|
10
|
+
'hayat01sh1da/issue-xxxxx/service/this_is_a_test_branch',
|
|
11
|
+
'[service] This Is A Test Branch',
|
|
12
|
+
),
|
|
13
|
+
(
|
|
14
|
+
'hayat01sh1da/issue-xxxxx/hotfix/service/this_is_a_test_branch',
|
|
15
|
+
'[Hotfix][service] This Is A Test Branch',
|
|
16
|
+
),
|
|
17
|
+
(
|
|
18
|
+
'hayat01sh1da/issue-xxxxx/service/this-is-a-test-branch',
|
|
19
|
+
'[service] This Is A Test Branch',
|
|
20
|
+
),
|
|
21
|
+
],
|
|
22
|
+
)
|
|
23
|
+
def test_run(branch_name: str, expected: str) -> None:
|
|
24
|
+
assert Application.run(branch_name=branch_name) == expected
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.mark.parametrize(
|
|
28
|
+
('branch_name', 'expected'),
|
|
29
|
+
[
|
|
30
|
+
(
|
|
31
|
+
'hayat01sh1da/issue-xxxxx/service/this_is_a_test_branch',
|
|
32
|
+
['service'],
|
|
33
|
+
),
|
|
34
|
+
(
|
|
35
|
+
'hayat01sh1da/issue-xxxxx/hotfix/service/this_is_a_test_branch',
|
|
36
|
+
['Hotfix', 'service'],
|
|
37
|
+
),
|
|
38
|
+
],
|
|
39
|
+
)
|
|
40
|
+
def test_labels(branch_name: str, expected: list[str]) -> None:
|
|
41
|
+
assert Application(branch_name=branch_name).labels == expected
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_to_dict() -> None:
|
|
45
|
+
branch_name = 'hayat01sh1da/issue-xxxxx/hotfix/service/this_is_a_test_branch'
|
|
46
|
+
|
|
47
|
+
assert Application(branch_name=branch_name).to_dict() == {
|
|
48
|
+
'title': '[Hotfix][service] This Is A Test Branch',
|
|
49
|
+
'labels': ['Hotfix', 'service'],
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@pytest.mark.parametrize(
|
|
54
|
+
'branch_name',
|
|
55
|
+
[
|
|
56
|
+
'main',
|
|
57
|
+
'fix/typo',
|
|
58
|
+
'hayat01sh1da//service/this_is_a_test_branch',
|
|
59
|
+
'',
|
|
60
|
+
],
|
|
61
|
+
)
|
|
62
|
+
def test_run_raises_on_an_unexpected_branch_name(branch_name: str) -> None:
|
|
63
|
+
with pytest.raises(ValueError, match='does not match the expected'):
|
|
64
|
+
Application.run(branch_name=branch_name)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from spreen_pr import __version__
|
|
6
|
+
from spreen_pr.cli import main
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_text_format(capsys: pytest.CaptureFixture[str]) -> None:
|
|
10
|
+
status = main(['hayat01sh1da/issue-xxxxx/service/this_is_a_test_branch'])
|
|
11
|
+
|
|
12
|
+
assert status == 0
|
|
13
|
+
assert capsys.readouterr().out == '[service] This Is A Test Branch\n'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_json_format(capsys: pytest.CaptureFixture[str]) -> None:
|
|
17
|
+
status = main([
|
|
18
|
+
'hayat01sh1da/issue-xxxxx/hotfix/service/this_is_a_test_branch',
|
|
19
|
+
'--format', 'json',
|
|
20
|
+
])
|
|
21
|
+
|
|
22
|
+
assert status == 0
|
|
23
|
+
assert json.loads(capsys.readouterr().out) == {
|
|
24
|
+
'title': '[Hotfix][service] This Is A Test Branch',
|
|
25
|
+
'labels': ['Hotfix', 'service'],
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_invalid_branch_name(capsys: pytest.CaptureFixture[str]) -> None:
|
|
30
|
+
status = main(['main'])
|
|
31
|
+
|
|
32
|
+
assert status == 1
|
|
33
|
+
assert 'does not match the expected' in capsys.readouterr().err
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_invalid_format() -> None:
|
|
37
|
+
with pytest.raises(SystemExit):
|
|
38
|
+
main(['hayat01sh1da/issue-xxxxx/service/topic', '--format', 'yaml'])
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_version(capsys: pytest.CaptureFixture[str]) -> None:
|
|
42
|
+
with pytest.raises(SystemExit) as excinfo:
|
|
43
|
+
main(['--version'])
|
|
44
|
+
|
|
45
|
+
assert excinfo.value.code == 0
|
|
46
|
+
assert capsys.readouterr().out == f'{__version__}\n'
|