pezin 0.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pezin/__init__.py +27 -0
- pezin/cli/__init__.py +13 -0
- pezin/cli/commands.py +427 -0
- pezin/cli/hooks.py +318 -0
- pezin/cli/main.py +673 -0
- pezin/cli/utils.py +12 -0
- pezin/core/__init__.py +15 -0
- pezin/core/changelog.py +300 -0
- pezin/core/commit.py +172 -0
- pezin/core/handlers.py +367 -0
- pezin/core/version.py +594 -0
- pezin/hooks/__init__.py +5 -0
- pezin/hooks/post_commit.py +363 -0
- pezin/hooks/pre_commit.py +576 -0
- pezin/hooks/prepare_commit_msg.py +243 -0
- pezin/logging.py +71 -0
- pezin-0.0.2.dist-info/METADATA +225 -0
- pezin-0.0.2.dist-info/RECORD +21 -0
- pezin-0.0.2.dist-info/WHEEL +5 -0
- pezin-0.0.2.dist-info/entry_points.txt +2 -0
- pezin-0.0.2.dist-info/top_level.txt +1 -0
pezin/__init__.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Automated version bumping and changelog management.
|
|
2
|
+
|
|
3
|
+
Example:
|
|
4
|
+
```bash
|
|
5
|
+
# Install pre-commit hook
|
|
6
|
+
pre-commit install --hook-type commit-msg
|
|
7
|
+
|
|
8
|
+
# Run manually
|
|
9
|
+
pezin bump minor
|
|
10
|
+
```
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from .core.changelog import ChangelogConfig, ChangelogManager
|
|
14
|
+
from .core.commit import BumpType, CommitType, ConventionalCommit
|
|
15
|
+
from .core.version import Version, VersionBumpType
|
|
16
|
+
|
|
17
|
+
__version__ = "0.1.0"
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"Version",
|
|
21
|
+
"VersionBumpType",
|
|
22
|
+
"ConventionalCommit",
|
|
23
|
+
"CommitType",
|
|
24
|
+
"BumpType",
|
|
25
|
+
"ChangelogConfig",
|
|
26
|
+
"ChangelogManager",
|
|
27
|
+
]
|
pezin/cli/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""CLI package for pezin."""
|
|
2
|
+
|
|
3
|
+
from .commands import bump_version, get_commits_since_last_tag, update_changelog
|
|
4
|
+
from .main import app
|
|
5
|
+
from .utils import find_project_root
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"app",
|
|
9
|
+
"bump_version",
|
|
10
|
+
"update_changelog",
|
|
11
|
+
"get_commits_since_last_tag",
|
|
12
|
+
"find_project_root",
|
|
13
|
+
]
|
pezin/cli/commands.py
ADDED
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
"""Command implementations for pezin CLI."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
6
|
+
|
|
7
|
+
import tomli
|
|
8
|
+
import tomli_w
|
|
9
|
+
|
|
10
|
+
from ..core.changelog import ChangelogConfig, ChangelogManager
|
|
11
|
+
from ..core.commit import ConventionalCommit
|
|
12
|
+
from ..core.version import Version, VersionBumpType, VersionFileConfig, VersionManager
|
|
13
|
+
from ..logging import get_logger
|
|
14
|
+
|
|
15
|
+
logger = get_logger()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def resolve_path(path: Path, base_dir: Optional[Path] = None) -> Path:
|
|
19
|
+
"""Resolve a path relative to a base directory."""
|
|
20
|
+
if path.is_absolute():
|
|
21
|
+
return path
|
|
22
|
+
if base_dir is None:
|
|
23
|
+
base_dir = Path.cwd()
|
|
24
|
+
elif base_dir.is_file():
|
|
25
|
+
base_dir = base_dir.parent
|
|
26
|
+
resolved = (base_dir / path).resolve()
|
|
27
|
+
logger.debug(f"Resolved path {path} relative to {base_dir} -> {resolved}")
|
|
28
|
+
return resolved
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def read_toml_file(file_path: Path) -> Dict[str, Any]:
|
|
32
|
+
"""Read and parse a TOML file."""
|
|
33
|
+
try:
|
|
34
|
+
if not file_path.is_file():
|
|
35
|
+
logger.debug(f"TOML file not found: {file_path}")
|
|
36
|
+
return {}
|
|
37
|
+
content = file_path.read_text()
|
|
38
|
+
logger.debug(f"Reading TOML from {file_path}:\n{content}")
|
|
39
|
+
return tomli.loads(content)
|
|
40
|
+
except Exception as e:
|
|
41
|
+
logger.debug(f"Failed to read TOML file {file_path}: {e}")
|
|
42
|
+
return {}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def read_config(config_file: Path) -> Dict[str, Any]:
|
|
46
|
+
"""Read configuration from a TOML file."""
|
|
47
|
+
if config_file.suffix != ".toml":
|
|
48
|
+
return {}
|
|
49
|
+
|
|
50
|
+
config = read_toml_file(config_file)
|
|
51
|
+
base_dir = config_file.parent
|
|
52
|
+
|
|
53
|
+
# Initialize pezin section if needed - check both locations
|
|
54
|
+
pezin_config = {}
|
|
55
|
+
if "pezin" in config:
|
|
56
|
+
pezin_config = config["pezin"]
|
|
57
|
+
elif "tool" in config and "pezin" in config["tool"]:
|
|
58
|
+
pezin_config = config["tool"]["pezin"]
|
|
59
|
+
|
|
60
|
+
# Ensure pezin section exists in the expected location
|
|
61
|
+
config["pezin"] = pezin_config
|
|
62
|
+
|
|
63
|
+
# Make paths absolute
|
|
64
|
+
if config["pezin"]:
|
|
65
|
+
# Handle legacy single version_file configuration
|
|
66
|
+
if "version_file" in config["pezin"]:
|
|
67
|
+
version_path = Path(config["pezin"]["version_file"])
|
|
68
|
+
if not version_path.is_absolute():
|
|
69
|
+
abs_path = resolve_path(version_path, base_dir)
|
|
70
|
+
logger.debug(
|
|
71
|
+
f"Making version_file path absolute: {version_path} -> {abs_path}"
|
|
72
|
+
)
|
|
73
|
+
config["pezin"]["version_file"] = str(abs_path)
|
|
74
|
+
|
|
75
|
+
# Handle new multi-file version_files configuration
|
|
76
|
+
if "version_files" in config["pezin"]:
|
|
77
|
+
version_files = config["pezin"]["version_files"]
|
|
78
|
+
for i, file_config in enumerate(version_files):
|
|
79
|
+
if isinstance(file_config, dict) and "path" in file_config:
|
|
80
|
+
file_path = Path(file_config["path"])
|
|
81
|
+
if not file_path.is_absolute():
|
|
82
|
+
abs_path = resolve_path(file_path, base_dir)
|
|
83
|
+
logger.debug(
|
|
84
|
+
f"Making version_files[{i}] path absolute: {file_path} -> {abs_path}"
|
|
85
|
+
)
|
|
86
|
+
config["pezin"]["version_files"][i]["path"] = str(abs_path)
|
|
87
|
+
|
|
88
|
+
if "changelog_file" in config["pezin"]:
|
|
89
|
+
changelog_path = Path(config["pezin"]["changelog_file"])
|
|
90
|
+
if not changelog_path.is_absolute():
|
|
91
|
+
abs_path = resolve_path(changelog_path, base_dir)
|
|
92
|
+
logger.debug(
|
|
93
|
+
f"Making changelog_file path absolute: {changelog_path} -> {abs_path}"
|
|
94
|
+
)
|
|
95
|
+
config["pezin"]["changelog_file"] = str(abs_path)
|
|
96
|
+
|
|
97
|
+
return config
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def read_version_from_toml(file_path: Path) -> Optional[str]:
|
|
101
|
+
"""Read version from TOML file sections."""
|
|
102
|
+
logger.debug(f"Reading version from TOML file: {file_path}")
|
|
103
|
+
data = read_toml_file(file_path)
|
|
104
|
+
|
|
105
|
+
# Try project section first
|
|
106
|
+
if "project" in data and "version" in data["project"]:
|
|
107
|
+
return get_version_data(data, "project", "Found version in [project] section: ")
|
|
108
|
+
# Try pezin section next
|
|
109
|
+
if "pezin" in data and "version" in data["pezin"]:
|
|
110
|
+
return get_version_data(data, "pezin", "Found version in [pezin] section: ")
|
|
111
|
+
# Try tool.pezin section (PEP 518)
|
|
112
|
+
if (
|
|
113
|
+
"tool" in data
|
|
114
|
+
and "pezin" in data["tool"]
|
|
115
|
+
and "version" in data["tool"]["pezin"]
|
|
116
|
+
):
|
|
117
|
+
version = data["tool"]["pezin"]["version"]
|
|
118
|
+
logger.debug(f"Found version in [tool.pezin] section: {version}")
|
|
119
|
+
return version
|
|
120
|
+
|
|
121
|
+
logger.debug("No version found in TOML file")
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def get_version_data(data, project_type, debug_message):
|
|
126
|
+
version = data[project_type]["version"]
|
|
127
|
+
logger.debug(f"{debug_message}{version}")
|
|
128
|
+
return version
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def write_toml_version(file_path: Path, new_version: str) -> None:
|
|
132
|
+
"""Write version to a TOML file."""
|
|
133
|
+
try:
|
|
134
|
+
data = read_toml_file(file_path)
|
|
135
|
+
|
|
136
|
+
# Update in existing location if found
|
|
137
|
+
if "project" in data and "version" in data["project"]:
|
|
138
|
+
data["project"]["version"] = new_version
|
|
139
|
+
elif "pezin" in data and "version" in data["pezin"]:
|
|
140
|
+
data["pezin"]["version"] = new_version
|
|
141
|
+
elif (
|
|
142
|
+
"tool" in data
|
|
143
|
+
and "pezin" in data["tool"]
|
|
144
|
+
and "version" in data["tool"]["pezin"]
|
|
145
|
+
):
|
|
146
|
+
data["tool"]["pezin"]["version"] = new_version
|
|
147
|
+
else:
|
|
148
|
+
# Default to project section
|
|
149
|
+
if "project" not in data:
|
|
150
|
+
data["project"] = {}
|
|
151
|
+
data["project"]["version"] = new_version
|
|
152
|
+
|
|
153
|
+
file_path.write_text(tomli_w.dumps(data))
|
|
154
|
+
except Exception as e:
|
|
155
|
+
raise ValueError(f"Failed to write TOML file: {e}") from e
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def read_raw_version(file_path: Path) -> Optional[str]:
|
|
159
|
+
"""Read version from a raw version file."""
|
|
160
|
+
if not file_path.is_file():
|
|
161
|
+
return None
|
|
162
|
+
content = file_path.read_text().strip()
|
|
163
|
+
if len(content.splitlines()) == 1:
|
|
164
|
+
Version.parse(content) # Validate version string
|
|
165
|
+
return content
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def get_version_info(
|
|
169
|
+
config_file: Path, config: Optional[Dict[str, Any]] = None
|
|
170
|
+
) -> Tuple[str, Path]:
|
|
171
|
+
"""Get version information from config or file (legacy function)."""
|
|
172
|
+
if config is None:
|
|
173
|
+
config = read_config(config_file)
|
|
174
|
+
|
|
175
|
+
config_file = config_file.resolve()
|
|
176
|
+
logger.debug(f"Getting version info from {config_file} with config: {config}")
|
|
177
|
+
|
|
178
|
+
# First try reading version from config file if it's TOML
|
|
179
|
+
if config_file.suffix == ".toml":
|
|
180
|
+
if version := read_version_from_toml(config_file):
|
|
181
|
+
return version, config_file
|
|
182
|
+
|
|
183
|
+
# Check for external version file
|
|
184
|
+
if "pezin" in config and "version_file" in config["pezin"]:
|
|
185
|
+
version_file = Path(config["pezin"]["version_file"])
|
|
186
|
+
version_file = resolve_path(version_file, config_file.parent)
|
|
187
|
+
else:
|
|
188
|
+
version_file = config_file
|
|
189
|
+
|
|
190
|
+
logger.debug(f"Checking version file: {version_file}")
|
|
191
|
+
|
|
192
|
+
# Try reading from version file
|
|
193
|
+
if version_file.suffix == ".toml":
|
|
194
|
+
if version := read_version_from_toml(version_file):
|
|
195
|
+
return version, version_file
|
|
196
|
+
|
|
197
|
+
if version := read_raw_version(version_file):
|
|
198
|
+
return version, version_file
|
|
199
|
+
|
|
200
|
+
if not version_file.exists():
|
|
201
|
+
raise FileNotFoundError(f"Version file not found: {version_file}")
|
|
202
|
+
|
|
203
|
+
raise ValueError(f"Version not found in {version_file}")
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def get_version_manager(
|
|
207
|
+
config_file: Path, config: Optional[dict] = None
|
|
208
|
+
) -> VersionManager:
|
|
209
|
+
"""Get VersionManager instance from configuration."""
|
|
210
|
+
if config is None:
|
|
211
|
+
config = read_config(config_file)
|
|
212
|
+
|
|
213
|
+
# Check if we have new multi-file configuration
|
|
214
|
+
if config and "pezin" in config and "version_files" in config["pezin"]:
|
|
215
|
+
return VersionManager.from_config(config["pezin"])
|
|
216
|
+
|
|
217
|
+
# Create manager from legacy configuration
|
|
218
|
+
if config and "pezin" in config and "version_file" in config["pezin"]:
|
|
219
|
+
version_file = config["pezin"]["version_file"]
|
|
220
|
+
else:
|
|
221
|
+
version_file = str(config_file)
|
|
222
|
+
|
|
223
|
+
return VersionManager([VersionFileConfig(path=version_file)])
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def get_current_version(
|
|
227
|
+
config_file: Path, config: Optional[dict] = None
|
|
228
|
+
) -> Optional[str]:
|
|
229
|
+
"""Get current version using the new VersionManager system."""
|
|
230
|
+
try:
|
|
231
|
+
version_manager = get_version_manager(config_file, config)
|
|
232
|
+
version = version_manager.get_primary_version()
|
|
233
|
+
return str(version) if version else None
|
|
234
|
+
except Exception as e:
|
|
235
|
+
logger.error(f"Failed to get current version: {e}")
|
|
236
|
+
return None
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def write_version_to_file(
|
|
240
|
+
file_path: Path, new_version: str, config: Optional[dict] = None
|
|
241
|
+
) -> None:
|
|
242
|
+
"""Write version to a file."""
|
|
243
|
+
file_path = file_path.resolve()
|
|
244
|
+
logger.debug(f"Writing version {new_version} to {file_path}")
|
|
245
|
+
|
|
246
|
+
# Create parent directories if needed
|
|
247
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
248
|
+
|
|
249
|
+
# Write version based on file type
|
|
250
|
+
if file_path.suffix == ".toml":
|
|
251
|
+
write_toml_version(file_path, new_version)
|
|
252
|
+
else:
|
|
253
|
+
file_path.write_text(new_version)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def get_changelog_file(config: Dict[str, Any], default_file: Path) -> Path:
|
|
257
|
+
"""Get changelog file path from config or default."""
|
|
258
|
+
if "pezin" in config and "changelog_file" in config["pezin"]:
|
|
259
|
+
return Path(config["pezin"]["changelog_file"])
|
|
260
|
+
return default_file
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def get_git_repo_url() -> Optional[str]:
|
|
264
|
+
"""Get repository URL from git config."""
|
|
265
|
+
import subprocess
|
|
266
|
+
|
|
267
|
+
try:
|
|
268
|
+
result = subprocess.run(
|
|
269
|
+
["git", "config", "--get", "remote.origin.url"],
|
|
270
|
+
capture_output=True,
|
|
271
|
+
text=True,
|
|
272
|
+
check=True,
|
|
273
|
+
)
|
|
274
|
+
url = result.stdout.strip()
|
|
275
|
+
|
|
276
|
+
# Convert SSH to HTTPS URL if needed
|
|
277
|
+
if url.startswith("git@"):
|
|
278
|
+
url = url.replace(":", "/").replace("git@", "https://")
|
|
279
|
+
|
|
280
|
+
if url.endswith(".git"):
|
|
281
|
+
url = url[:-4]
|
|
282
|
+
|
|
283
|
+
return url
|
|
284
|
+
|
|
285
|
+
except subprocess.CalledProcessError:
|
|
286
|
+
return None
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def get_commits_since_last_tag() -> List[ConventionalCommit]:
|
|
290
|
+
"""Get commits since the last version tag."""
|
|
291
|
+
import subprocess
|
|
292
|
+
|
|
293
|
+
commits = []
|
|
294
|
+
try:
|
|
295
|
+
get_commits_from_logs(subprocess, commits)
|
|
296
|
+
except subprocess.CalledProcessError:
|
|
297
|
+
logger.debug("Not in a git repository or no commits found")
|
|
298
|
+
|
|
299
|
+
return commits
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def get_commits_from_logs(subprocess, commits):
|
|
303
|
+
# Check if in a git repo first
|
|
304
|
+
subprocess.run(["git", "rev-parse", "--git-dir"], capture_output=True, check=True)
|
|
305
|
+
|
|
306
|
+
# Try to get last tag
|
|
307
|
+
result = subprocess.run(
|
|
308
|
+
["git", "describe", "--tags", "--abbrev=0"],
|
|
309
|
+
capture_output=True,
|
|
310
|
+
text=True,
|
|
311
|
+
check=False,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
# Build git log command
|
|
315
|
+
log_cmd = ["git", "log", "--pretty=format:%B%n<<>>%n"]
|
|
316
|
+
if result.returncode == 0:
|
|
317
|
+
log_cmd.extend([f"{result.stdout.strip()}..HEAD"])
|
|
318
|
+
|
|
319
|
+
# Get and parse commits
|
|
320
|
+
log_output = subprocess.run(log_cmd, capture_output=True, text=True, check=True)
|
|
321
|
+
|
|
322
|
+
for message in log_output.stdout.split("<<>>\n"):
|
|
323
|
+
if message.strip():
|
|
324
|
+
try:
|
|
325
|
+
commits.append(ConventionalCommit.parse(message.strip()))
|
|
326
|
+
except ValueError:
|
|
327
|
+
continue
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def bump_version(
|
|
331
|
+
bump_type: VersionBumpType,
|
|
332
|
+
config_file: Path,
|
|
333
|
+
config: Optional[dict] = None,
|
|
334
|
+
dry_run: bool = False,
|
|
335
|
+
prerelease: Optional[str] = None,
|
|
336
|
+
) -> Optional[str]:
|
|
337
|
+
"""Bump version in config file and all configured version files."""
|
|
338
|
+
try:
|
|
339
|
+
# Read config if not provided
|
|
340
|
+
if config is None and config_file.suffix == ".toml":
|
|
341
|
+
config = read_config(config_file)
|
|
342
|
+
|
|
343
|
+
logger.debug(f"Bumping version with config: {config}")
|
|
344
|
+
|
|
345
|
+
if config and "pezin" in config and "version_files" in config["pezin"]:
|
|
346
|
+
return prepare_new_version(config, bump_type, prerelease, dry_run)
|
|
347
|
+
# Fallback to legacy single file logic
|
|
348
|
+
current, version_file = get_version_info(config_file, config)
|
|
349
|
+
version = Version.parse(current)
|
|
350
|
+
new_version = str(version.bump(bump_type, prerelease))
|
|
351
|
+
|
|
352
|
+
if not dry_run:
|
|
353
|
+
write_version_to_file(version_file, new_version)
|
|
354
|
+
logger.info(f"Version bumped: {current} -> {new_version}")
|
|
355
|
+
else:
|
|
356
|
+
logger.info(f"Dry run - Would bump: {current} -> {new_version}")
|
|
357
|
+
|
|
358
|
+
return new_version
|
|
359
|
+
|
|
360
|
+
except Exception as e:
|
|
361
|
+
logger.error(f"Failed to bump version: {e}")
|
|
362
|
+
return None
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def prepare_new_version(config, bump_type, prerelease, dry_run):
|
|
366
|
+
# Use new VersionManager system
|
|
367
|
+
version_manager = VersionManager.from_config(config["pezin"])
|
|
368
|
+
|
|
369
|
+
# Get current version from primary file
|
|
370
|
+
current_version = version_manager.get_primary_version()
|
|
371
|
+
if not current_version:
|
|
372
|
+
raise ValueError("No version found in configured files")
|
|
373
|
+
|
|
374
|
+
# Check version consistency across all files
|
|
375
|
+
if not version_manager.validate_version_consistency():
|
|
376
|
+
logger.warning("Version inconsistency detected across files")
|
|
377
|
+
|
|
378
|
+
# Calculate new version
|
|
379
|
+
new_version = current_version.bump(bump_type, prerelease)
|
|
380
|
+
|
|
381
|
+
if not dry_run:
|
|
382
|
+
updated_files = version_manager.write_versions(new_version)
|
|
383
|
+
logger.info(f"Version bumped: {current_version} -> {new_version}")
|
|
384
|
+
logger.info(f"Updated files: {', '.join(updated_files)}")
|
|
385
|
+
else:
|
|
386
|
+
versions = version_manager.read_versions()
|
|
387
|
+
logger.info(f"Dry run - Would bump: {current_version} -> {new_version}")
|
|
388
|
+
logger.info(f"Files to update: {', '.join(versions.keys())}")
|
|
389
|
+
|
|
390
|
+
return str(new_version)
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def update_changelog(
|
|
394
|
+
version: str,
|
|
395
|
+
commits: List[ConventionalCommit],
|
|
396
|
+
changelog_file: Path = Path("CHANGELOG.md"),
|
|
397
|
+
dry_run: bool = False,
|
|
398
|
+
config: Optional[dict] = None,
|
|
399
|
+
) -> bool:
|
|
400
|
+
"""Update changelog with new version."""
|
|
401
|
+
try:
|
|
402
|
+
# Get actual changelog file path
|
|
403
|
+
actual_file = get_changelog_file(config or {}, changelog_file)
|
|
404
|
+
actual_file = resolve_path(actual_file)
|
|
405
|
+
|
|
406
|
+
logger.debug(f"Using changelog file: {actual_file}")
|
|
407
|
+
|
|
408
|
+
# Create changelog file if it doesn't exist
|
|
409
|
+
if not dry_run:
|
|
410
|
+
actual_file.parent.mkdir(parents=True, exist_ok=True)
|
|
411
|
+
if not actual_file.exists():
|
|
412
|
+
actual_file.write_text("# Changelog\n\n## [Unreleased]\n")
|
|
413
|
+
|
|
414
|
+
manager_config = ChangelogConfig(repo_url=get_git_repo_url())
|
|
415
|
+
manager = ChangelogManager(manager_config)
|
|
416
|
+
|
|
417
|
+
if not dry_run:
|
|
418
|
+
manager.update_changelog(actual_file, version, commits, datetime.now())
|
|
419
|
+
logger.info(f"Updated changelog for version {version}")
|
|
420
|
+
else:
|
|
421
|
+
logger.info(f"Dry run - Would update changelog for version {version}")
|
|
422
|
+
|
|
423
|
+
return True
|
|
424
|
+
|
|
425
|
+
except Exception as e:
|
|
426
|
+
logger.error(f"Failed to update changelog: {e}")
|
|
427
|
+
return False
|