autopub 0.2.2__py3-none-any.whl → 1.0.0a1__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.
- autopub/__init__.py +182 -0
- autopub/cli/__init__.py +121 -0
- autopub/cli/plugins.py +37 -0
- autopub/exceptions.py +47 -0
- autopub/plugins/__init__.py +40 -0
- autopub/plugins/bump_version.py +41 -0
- autopub/plugins/pdm.py +18 -0
- autopub/plugins/poetry.py +16 -0
- autopub/plugins/update_changelog.py +50 -0
- autopub/types.py +11 -0
- {autopub-0.2.2.dist-info → autopub-1.0.0a1.dist-info}/METADATA +15 -9
- autopub-1.0.0a1.dist-info/RECORD +15 -0
- {autopub-0.2.2.dist-info → autopub-1.0.0a1.dist-info}/WHEEL +1 -1
- autopub-1.0.0a1.dist-info/entry_points.txt +3 -0
- autopub/autopub.py +0 -83
- autopub/base.py +0 -159
- autopub/build_release.py +0 -15
- autopub/check_release.py +0 -15
- autopub/commit_release.py +0 -33
- autopub/create_github_release.py +0 -66
- autopub/deploy_release.py +0 -18
- autopub/github_contributor.py +0 -83
- autopub/prepare_release copy.py +0 -119
- autopub/prepare_release.py +0 -93
- autopub/publish_release.py +0 -22
- autopub-0.2.2.dist-info/RECORD +0 -17
- autopub-0.2.2.dist-info/entry_points.txt +0 -3
- {autopub-0.2.2.dist-info → autopub-1.0.0a1.dist-info}/LICENSE +0 -0
autopub/__init__.py
CHANGED
@@ -0,0 +1,182 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import hashlib
|
4
|
+
import json
|
5
|
+
from collections.abc import Iterable
|
6
|
+
from pathlib import Path
|
7
|
+
|
8
|
+
import frontmatter
|
9
|
+
|
10
|
+
from autopub.exceptions import (
|
11
|
+
ArtifactHashMismatch,
|
12
|
+
ArtifactNotFound,
|
13
|
+
AutopubException,
|
14
|
+
NoPackageManagerPluginFound,
|
15
|
+
ReleaseFileEmpty,
|
16
|
+
ReleaseFileNotFound,
|
17
|
+
ReleaseNotesEmpty,
|
18
|
+
ReleaseTypeInvalid,
|
19
|
+
ReleaseTypeMissing,
|
20
|
+
)
|
21
|
+
from autopub.plugins import AutopubPackageManagerPlugin, AutopubPlugin
|
22
|
+
from autopub.types import ReleaseInfo
|
23
|
+
|
24
|
+
|
25
|
+
class Autopub:
|
26
|
+
RELEASE_FILE_PATH = "RELEASE.md"
|
27
|
+
|
28
|
+
def __init__(self, plugins: Iterable[type[AutopubPlugin]] = ()) -> None:
|
29
|
+
self.plugins = [plugin_class() for plugin_class in plugins]
|
30
|
+
|
31
|
+
@property
|
32
|
+
def release_file(self) -> Path:
|
33
|
+
return Path.cwd() / self.RELEASE_FILE_PATH
|
34
|
+
|
35
|
+
@property
|
36
|
+
def release_notes(self) -> str:
|
37
|
+
return self.release_file.read_text()
|
38
|
+
|
39
|
+
@property
|
40
|
+
def release_file_hash(self) -> str:
|
41
|
+
return hashlib.sha256(self.release_notes.encode("utf-8")).hexdigest()
|
42
|
+
|
43
|
+
@property
|
44
|
+
def release_data_file(self) -> Path:
|
45
|
+
return Path(".autopub") / "release_data.json"
|
46
|
+
|
47
|
+
# TODO: typed dict
|
48
|
+
@property
|
49
|
+
def release_data(self) -> ReleaseInfo:
|
50
|
+
if not self.release_data_file.exists():
|
51
|
+
raise ArtifactNotFound()
|
52
|
+
|
53
|
+
release_data = json.loads(self.release_data_file.read_text())
|
54
|
+
|
55
|
+
if release_data["hash"] != self.release_file_hash:
|
56
|
+
raise ArtifactHashMismatch()
|
57
|
+
|
58
|
+
return ReleaseInfo(
|
59
|
+
release_type=release_data["release_type"],
|
60
|
+
release_notes=release_data["release_notes"],
|
61
|
+
additional_info=release_data["plugin_data"],
|
62
|
+
)
|
63
|
+
|
64
|
+
def check(self) -> ReleaseInfo:
|
65
|
+
release_file = Path(self.RELEASE_FILE_PATH)
|
66
|
+
|
67
|
+
if not release_file.exists():
|
68
|
+
raise ReleaseFileNotFound()
|
69
|
+
|
70
|
+
try:
|
71
|
+
release_info = self._validate_release_notes(self.release_notes)
|
72
|
+
except AutopubException as e:
|
73
|
+
for plugin in self.plugins:
|
74
|
+
plugin.on_release_notes_invalid(e)
|
75
|
+
raise
|
76
|
+
|
77
|
+
for plugin in self.plugins:
|
78
|
+
plugin.on_release_notes_valid(release_info)
|
79
|
+
|
80
|
+
self._write_artifact(release_info)
|
81
|
+
|
82
|
+
return release_info
|
83
|
+
|
84
|
+
def build(self) -> None:
|
85
|
+
if not any(
|
86
|
+
isinstance(plugin, AutopubPackageManagerPlugin) for plugin in self.plugins
|
87
|
+
):
|
88
|
+
raise NoPackageManagerPluginFound()
|
89
|
+
|
90
|
+
for plugin in self.plugins:
|
91
|
+
if isinstance(plugin, AutopubPackageManagerPlugin):
|
92
|
+
plugin.build()
|
93
|
+
|
94
|
+
def prepare(self) -> None:
|
95
|
+
for plugin in self.plugins:
|
96
|
+
plugin.prepare(self.release_data)
|
97
|
+
|
98
|
+
def publish(self, repository: str | None = None) -> None:
|
99
|
+
# TODO: shall we put this in a function, to make it
|
100
|
+
# clear that we are triggering the logic to check the release file?
|
101
|
+
self.release_data
|
102
|
+
|
103
|
+
for plugin in self.plugins:
|
104
|
+
if isinstance(plugin, AutopubPackageManagerPlugin):
|
105
|
+
plugin.publish(repository=repository)
|
106
|
+
|
107
|
+
def _write_artifact(self, release_info: ReleaseInfo) -> None:
|
108
|
+
data = {
|
109
|
+
"hash": self.release_file_hash,
|
110
|
+
"release_type": release_info.release_type,
|
111
|
+
"release_notes": release_info.release_notes,
|
112
|
+
"plugin_data": {
|
113
|
+
key: value
|
114
|
+
for plugin in self.plugins
|
115
|
+
for key, value in plugin.data.items()
|
116
|
+
},
|
117
|
+
}
|
118
|
+
|
119
|
+
self.release_data_file.parent.mkdir(exist_ok=True)
|
120
|
+
self.release_data_file.write_text(json.dumps(data))
|
121
|
+
|
122
|
+
def _deprecated_load(self, release_notes: str) -> ReleaseInfo:
|
123
|
+
# supports loading of old release notes format, which is
|
124
|
+
# deprecated and will be removed in a future release
|
125
|
+
# and looks like this:
|
126
|
+
# Release type: patch
|
127
|
+
# release notes here.
|
128
|
+
|
129
|
+
try:
|
130
|
+
release_info, release_notes = release_notes.split("\n", 1)
|
131
|
+
except ValueError as e:
|
132
|
+
raise ReleaseTypeMissing() from e
|
133
|
+
|
134
|
+
release_info = release_info.lower()
|
135
|
+
|
136
|
+
if not release_info.startswith("release type:"):
|
137
|
+
raise ReleaseTypeMissing()
|
138
|
+
|
139
|
+
release_type = release_info.split(":", 1)[1].strip().lower()
|
140
|
+
|
141
|
+
return ReleaseInfo(
|
142
|
+
release_type=release_type, release_notes=release_notes.strip()
|
143
|
+
)
|
144
|
+
|
145
|
+
def _load_from_frontmatter(self, release_notes: str) -> ReleaseInfo:
|
146
|
+
# supports loading of new release notes format, which looks like this:
|
147
|
+
# ---
|
148
|
+
# release type: patch
|
149
|
+
# ---
|
150
|
+
# release notes here.
|
151
|
+
|
152
|
+
post = frontmatter.loads(release_notes)
|
153
|
+
|
154
|
+
data: dict[str, str] = post.to_dict()
|
155
|
+
|
156
|
+
release_type = data.pop("release type").lower()
|
157
|
+
|
158
|
+
if release_type not in ("major", "minor", "patch"):
|
159
|
+
raise ReleaseTypeInvalid(release_type)
|
160
|
+
|
161
|
+
if post.content.strip() == "":
|
162
|
+
raise ReleaseNotesEmpty()
|
163
|
+
|
164
|
+
return ReleaseInfo(
|
165
|
+
release_type=release_type,
|
166
|
+
release_notes=post.content,
|
167
|
+
additional_info=data,
|
168
|
+
)
|
169
|
+
|
170
|
+
def _validate_release_notes(self, release_notes: str) -> ReleaseInfo:
|
171
|
+
if not release_notes:
|
172
|
+
raise ReleaseFileEmpty()
|
173
|
+
|
174
|
+
try:
|
175
|
+
release_info = self._load_from_frontmatter(release_notes)
|
176
|
+
except KeyError:
|
177
|
+
release_info = self._deprecated_load(release_notes)
|
178
|
+
|
179
|
+
for plugin in self.plugins:
|
180
|
+
plugin.validate_release_notes(release_info)
|
181
|
+
|
182
|
+
return release_info
|
autopub/cli/__init__.py
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
from typing import Optional, TypedDict
|
2
|
+
|
3
|
+
import rich
|
4
|
+
import typer
|
5
|
+
from rich.console import Group
|
6
|
+
from rich.markdown import Markdown
|
7
|
+
from rich.padding import Padding
|
8
|
+
from rich.panel import Panel
|
9
|
+
from typing_extensions import Annotated
|
10
|
+
|
11
|
+
from autopub import Autopub
|
12
|
+
from autopub.cli.plugins import find_plugins
|
13
|
+
from autopub.exceptions import AutopubException
|
14
|
+
|
15
|
+
app = typer.Typer()
|
16
|
+
|
17
|
+
|
18
|
+
class State(TypedDict):
|
19
|
+
plugins: list[str]
|
20
|
+
|
21
|
+
|
22
|
+
state: State = {"plugins": []}
|
23
|
+
|
24
|
+
|
25
|
+
@app.command()
|
26
|
+
def check():
|
27
|
+
"""This commands checks if the current PR has a valid release file."""
|
28
|
+
|
29
|
+
autopub = Autopub(plugins=find_plugins(state["plugins"]))
|
30
|
+
|
31
|
+
try:
|
32
|
+
release_info = autopub.check()
|
33
|
+
except AutopubException as e:
|
34
|
+
rich.print(Panel.fit(f"[red]{e.message}"))
|
35
|
+
|
36
|
+
raise typer.Exit(1) from e
|
37
|
+
else:
|
38
|
+
rich.print(
|
39
|
+
Padding(
|
40
|
+
Group(
|
41
|
+
(
|
42
|
+
"[bold on bright_magenta] Release type: [/] "
|
43
|
+
f"[yellow italic underline]{release_info.release_type}[/]\n"
|
44
|
+
),
|
45
|
+
"[bold on bright_magenta] Release notes: [/]\n",
|
46
|
+
Markdown(release_info.release_notes),
|
47
|
+
"\n---\n\n[green bold]Release file is valid![/] 🚀",
|
48
|
+
),
|
49
|
+
(1, 1),
|
50
|
+
)
|
51
|
+
)
|
52
|
+
|
53
|
+
|
54
|
+
@app.command()
|
55
|
+
def build():
|
56
|
+
autopub = Autopub(plugins=find_plugins(state["plugins"]))
|
57
|
+
|
58
|
+
try:
|
59
|
+
autopub.build()
|
60
|
+
except AutopubException as e:
|
61
|
+
rich.print(Panel.fit(f"[red]{e.message}"))
|
62
|
+
|
63
|
+
raise typer.Exit(1) from e
|
64
|
+
else:
|
65
|
+
rich.print(Panel.fit("[green]Build succeeded"))
|
66
|
+
|
67
|
+
|
68
|
+
@app.command()
|
69
|
+
def prepare():
|
70
|
+
autopub = Autopub(plugins=find_plugins(state["plugins"]))
|
71
|
+
|
72
|
+
try:
|
73
|
+
autopub.prepare()
|
74
|
+
except AutopubException as e:
|
75
|
+
rich.print(Panel.fit(f"[red]{e.message}"))
|
76
|
+
|
77
|
+
raise typer.Exit(1) from e
|
78
|
+
else:
|
79
|
+
rich.print(Panel.fit("[green]Preparation succeeded"))
|
80
|
+
|
81
|
+
|
82
|
+
@app.command()
|
83
|
+
def publish(
|
84
|
+
repository: Annotated[
|
85
|
+
Optional[str],
|
86
|
+
typer.Option("--repository", "-r", help="Repository to publish to"),
|
87
|
+
] = None,
|
88
|
+
):
|
89
|
+
autopub = Autopub(plugins=find_plugins(state["plugins"]))
|
90
|
+
|
91
|
+
try:
|
92
|
+
autopub.publish(repository=repository)
|
93
|
+
except AutopubException as e:
|
94
|
+
rich.print(Panel.fit(f"[red]{e.message}"))
|
95
|
+
|
96
|
+
raise typer.Exit(1) from e
|
97
|
+
else:
|
98
|
+
rich.print(Panel.fit("[green]Publishing succeeded"))
|
99
|
+
|
100
|
+
|
101
|
+
@app.callback(invoke_without_command=True)
|
102
|
+
def main(
|
103
|
+
plugins: list[str] = typer.Option(
|
104
|
+
[],
|
105
|
+
"--plugin",
|
106
|
+
"-p",
|
107
|
+
help="List of plugins to use",
|
108
|
+
),
|
109
|
+
should_show_version: Annotated[
|
110
|
+
Optional[bool], typer.Option("--version", is_eager=True)
|
111
|
+
] = None,
|
112
|
+
):
|
113
|
+
state["plugins"] = plugins
|
114
|
+
state["plugins"].extend(["bump_version"])
|
115
|
+
|
116
|
+
if should_show_version:
|
117
|
+
from importlib.metadata import version
|
118
|
+
|
119
|
+
print(version("autopub"))
|
120
|
+
|
121
|
+
raise typer.Exit()
|
autopub/cli/plugins.py
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
from importlib import import_module
|
2
|
+
|
3
|
+
from autopub.plugins import AutopubPlugin
|
4
|
+
|
5
|
+
|
6
|
+
def _find_plugin(module: object) -> type[AutopubPlugin] | None:
|
7
|
+
for obj in module.__dict__.values():
|
8
|
+
if (
|
9
|
+
isinstance(obj, type)
|
10
|
+
and issubclass(obj, AutopubPlugin)
|
11
|
+
and obj is not AutopubPlugin
|
12
|
+
):
|
13
|
+
return obj
|
14
|
+
|
15
|
+
return None
|
16
|
+
|
17
|
+
|
18
|
+
def find_plugins(names: list[str]) -> list[type[AutopubPlugin]]:
|
19
|
+
plugins: list[type] = []
|
20
|
+
|
21
|
+
for plugin_name in names:
|
22
|
+
try:
|
23
|
+
# TODO: find plugins outside the autopub namespace
|
24
|
+
plugin_module = import_module(f"autopub.plugins.{plugin_name}")
|
25
|
+
|
26
|
+
plugin_class = _find_plugin(plugin_module)
|
27
|
+
|
28
|
+
if plugin_class is None:
|
29
|
+
print(f"Could not find plugin {plugin_name}")
|
30
|
+
# TODO: raise
|
31
|
+
continue
|
32
|
+
|
33
|
+
plugins.append(plugin_class)
|
34
|
+
except ImportError as e:
|
35
|
+
print(f"Error importing plugin {plugin_name}: {e}")
|
36
|
+
|
37
|
+
return plugins
|
autopub/exceptions.py
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
class AutopubException(Exception):
|
2
|
+
message: str
|
3
|
+
|
4
|
+
def __init__(self) -> None:
|
5
|
+
super().__init__(self.message)
|
6
|
+
|
7
|
+
|
8
|
+
class ReleaseFileNotFound(AutopubException):
|
9
|
+
message = "Release file not found"
|
10
|
+
|
11
|
+
|
12
|
+
class ReleaseFileEmpty(AutopubException):
|
13
|
+
message = "Release file is empty"
|
14
|
+
|
15
|
+
|
16
|
+
class ReleaseNotesEmpty(AutopubException):
|
17
|
+
message = "Release notes are empty"
|
18
|
+
|
19
|
+
|
20
|
+
class ReleaseTypeMissing(AutopubException):
|
21
|
+
message: str = "Release note is missing release type"
|
22
|
+
|
23
|
+
|
24
|
+
class ReleaseTypeInvalid(AutopubException):
|
25
|
+
def __init__(self, release_type: str):
|
26
|
+
self.message = f"Release type {release_type} is invalid"
|
27
|
+
super().__init__()
|
28
|
+
|
29
|
+
|
30
|
+
class NoPackageManagerPluginFound(AutopubException):
|
31
|
+
message = "No package manager plugin found"
|
32
|
+
|
33
|
+
|
34
|
+
class ArtifactNotFound(AutopubException):
|
35
|
+
message = "Artifact not found, did you run `autopub check`?"
|
36
|
+
|
37
|
+
|
38
|
+
class ArtifactHashMismatch(AutopubException):
|
39
|
+
message = "Artifact hash mismatch, did you run `autopub check`?"
|
40
|
+
|
41
|
+
|
42
|
+
class CommandFailed(AutopubException):
|
43
|
+
def __init__(self, command: list[str], returncode: int) -> None:
|
44
|
+
self.message = (
|
45
|
+
f"Command {' '.join(command)} failed with return code {returncode}"
|
46
|
+
)
|
47
|
+
super().__init__()
|
@@ -0,0 +1,40 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import subprocess
|
4
|
+
from typing import Any, Protocol, runtime_checkable
|
5
|
+
|
6
|
+
from autopub.exceptions import AutopubException, CommandFailed
|
7
|
+
from autopub.types import ReleaseInfo
|
8
|
+
|
9
|
+
|
10
|
+
class AutopubPlugin:
|
11
|
+
data: dict[str, object] = {}
|
12
|
+
|
13
|
+
def run_command(self, command: list[str]) -> None:
|
14
|
+
try:
|
15
|
+
subprocess.run(command, check=True)
|
16
|
+
except subprocess.CalledProcessError as e:
|
17
|
+
raise CommandFailed(command=command, returncode=e.returncode) from e
|
18
|
+
|
19
|
+
def prepare(self, release_info: ReleaseInfo) -> None: # pragma: no cover
|
20
|
+
...
|
21
|
+
|
22
|
+
def validate_release_notes(self, release_info: ReleaseInfo): # pragma: no cover
|
23
|
+
...
|
24
|
+
|
25
|
+
def on_release_notes_valid(self, release_info: ReleaseInfo): # pragma: no cover
|
26
|
+
...
|
27
|
+
|
28
|
+
def on_release_notes_invalid(self, exception: AutopubException): # pragma: no cover
|
29
|
+
...
|
30
|
+
|
31
|
+
|
32
|
+
@runtime_checkable
|
33
|
+
class AutopubPackageManagerPlugin(Protocol):
|
34
|
+
def build(self) -> None: # pragma: no cover
|
35
|
+
...
|
36
|
+
|
37
|
+
def publish(
|
38
|
+
self, repository: str | None = None, **kwargs: Any
|
39
|
+
) -> None: # pragma: no cover
|
40
|
+
...
|
@@ -0,0 +1,41 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import pathlib
|
4
|
+
|
5
|
+
import tomlkit
|
6
|
+
from dunamai import Version
|
7
|
+
|
8
|
+
from autopub.plugins import AutopubPlugin
|
9
|
+
from autopub.types import ReleaseInfo
|
10
|
+
|
11
|
+
|
12
|
+
class BumpVersionPlugin(AutopubPlugin):
|
13
|
+
@property
|
14
|
+
def pyproject_config(self) -> tomlkit.TOMLDocument:
|
15
|
+
content = pathlib.Path("pyproject.toml").read_text()
|
16
|
+
|
17
|
+
return tomlkit.parse(content)
|
18
|
+
|
19
|
+
def _get_version(self, config: tomlkit.TOMLDocument) -> str:
|
20
|
+
try:
|
21
|
+
return config["tool"]["poetry"]["version"] # type: ignore
|
22
|
+
except KeyError:
|
23
|
+
return config["project"]["version"] # type: ignore
|
24
|
+
|
25
|
+
def _update_version(self, config: tomlkit.TOMLDocument, new_version: str) -> None:
|
26
|
+
try:
|
27
|
+
config["tool"]["poetry"]["version"] = new_version # type: ignore
|
28
|
+
except KeyError:
|
29
|
+
config["project"]["version"] = new_version # type: ignore
|
30
|
+
|
31
|
+
def prepare(self, release_info: ReleaseInfo) -> None:
|
32
|
+
config = self.pyproject_config
|
33
|
+
|
34
|
+
version = Version(self._get_version(config))
|
35
|
+
|
36
|
+
bump_type = {"major": 0, "minor": 1, "patch": 2}[release_info.release_type]
|
37
|
+
new_version = version.bump(bump_type).serialize()
|
38
|
+
|
39
|
+
self._update_version(config, new_version)
|
40
|
+
|
41
|
+
pathlib.Path("pyproject.toml").write_text(tomlkit.dumps(config)) # type: ignore
|
autopub/plugins/pdm.py
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import Any
|
4
|
+
|
5
|
+
from autopub.plugins import AutopubPackageManagerPlugin, AutopubPlugin
|
6
|
+
|
7
|
+
|
8
|
+
class PDMPlugin(AutopubPlugin, AutopubPackageManagerPlugin):
|
9
|
+
def build(self) -> None:
|
10
|
+
self.run_command(["pdm", "build"])
|
11
|
+
|
12
|
+
def publish(self, repository: str | None = None, **kwargs: Any) -> None:
|
13
|
+
additional_args: list[str] = []
|
14
|
+
|
15
|
+
if repository:
|
16
|
+
additional_args += ["--repository", repository]
|
17
|
+
|
18
|
+
self.run_command(["pdm", "publish", *additional_args])
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from autopub.plugins import AutopubPackageManagerPlugin, AutopubPlugin
|
4
|
+
|
5
|
+
|
6
|
+
class PoetryPlugin(AutopubPlugin, AutopubPackageManagerPlugin):
|
7
|
+
def build(self) -> None:
|
8
|
+
self.run_command(["poetry", "build"])
|
9
|
+
|
10
|
+
def publish(self, repository: str | None = None, **kwargs: str) -> None:
|
11
|
+
additional_args: list[str] = []
|
12
|
+
|
13
|
+
if repository:
|
14
|
+
additional_args += ["--repository", repository]
|
15
|
+
|
16
|
+
self.run_command(["poetry", "publish", *additional_args])
|
@@ -0,0 +1,50 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from datetime import date
|
4
|
+
from pathlib import Path
|
5
|
+
|
6
|
+
from autopub.plugins import AutopubPlugin
|
7
|
+
from autopub.types import ReleaseInfo
|
8
|
+
|
9
|
+
# TODO: from config
|
10
|
+
CHANGELOG_HEADER = "========="
|
11
|
+
VERSION_HEADER = "-"
|
12
|
+
|
13
|
+
|
14
|
+
class UpdateChangelogPlugin(AutopubPlugin):
|
15
|
+
@property
|
16
|
+
def changelog_file(self) -> Path:
|
17
|
+
return Path("CHANGELOG.md")
|
18
|
+
|
19
|
+
def post_prepare(self, release_info: ReleaseInfo) -> None:
|
20
|
+
assert release_info.version is not None
|
21
|
+
|
22
|
+
if not self.changelog_file.exists():
|
23
|
+
self.changelog_file.write_text(f"CHANGELOG\n{CHANGELOG_HEADER}\n\n")
|
24
|
+
|
25
|
+
current_date = date.today().strftime("%Y-%m-%d")
|
26
|
+
|
27
|
+
old_changelog_data = ""
|
28
|
+
header = ""
|
29
|
+
|
30
|
+
lines = self.changelog_file.read_text().splitlines()
|
31
|
+
|
32
|
+
for index, line in enumerate(lines):
|
33
|
+
if CHANGELOG_HEADER != line.strip():
|
34
|
+
continue
|
35
|
+
|
36
|
+
old_changelog_data = lines[index + 1 :]
|
37
|
+
header = lines[: index + 1]
|
38
|
+
break
|
39
|
+
|
40
|
+
with self.changelog_file.open("w") as f:
|
41
|
+
f.write("\n".join(header))
|
42
|
+
f.write("\n")
|
43
|
+
|
44
|
+
new_version_header = f"{release_info.version} - {current_date}"
|
45
|
+
|
46
|
+
f.write(f"\n{new_version_header}\n")
|
47
|
+
f.write(f"{VERSION_HEADER * len(new_version_header)}\n\n")
|
48
|
+
f.write(release_info.release_notes)
|
49
|
+
f.write("\n")
|
50
|
+
f.write("\n".join(old_changelog_data))
|
autopub/types.py
ADDED
@@ -1,31 +1,37 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: autopub
|
3
|
-
Version: 0.
|
3
|
+
Version: 1.0.0a1
|
4
4
|
Summary: Automatic package release upon pull request merge
|
5
5
|
Home-page: https://github.com/autopub/autopub
|
6
6
|
License: AGPL-3.0
|
7
7
|
Keywords: automatic,packaging,publish,release,version
|
8
8
|
Author: Justin Mayer
|
9
9
|
Author-email: entroP@gmail.com
|
10
|
-
Requires-Python: >=3.
|
10
|
+
Requires-Python: >=3.8,<4.0
|
11
11
|
Classifier: Development Status :: 4 - Beta
|
12
12
|
Classifier: Environment :: Console
|
13
13
|
Classifier: Intended Audience :: Developers
|
14
14
|
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
|
15
15
|
Classifier: Operating System :: OS Independent
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
17
|
-
Classifier: Programming Language :: Python :: 3.6
|
18
|
-
Classifier: Programming Language :: Python :: 3.7
|
19
17
|
Classifier: Programming Language :: Python :: 3.8
|
20
18
|
Classifier: Programming Language :: Python :: 3.9
|
21
19
|
Classifier: Programming Language :: Python :: 3.10
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
22
21
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
23
22
|
Classifier: Topic :: System :: Software Distribution
|
24
23
|
Classifier: Topic :: System :: Systems Administration
|
25
24
|
Provides-Extra: github
|
26
|
-
Requires-Dist:
|
27
|
-
Requires-Dist:
|
25
|
+
Requires-Dist: build (>=0.10.0,<0.11.0)
|
26
|
+
Requires-Dist: dunamai (>=1.17.0,<2.0.0)
|
27
|
+
Requires-Dist: githubrelease (>=1.5.9,<2.0.0) ; extra == "github"
|
28
|
+
Requires-Dist: httpx (==0.16.1) ; extra == "github"
|
29
|
+
Requires-Dist: python-frontmatter (>=1.0.0,<2.0.0)
|
30
|
+
Requires-Dist: rich (>=12.5.1,<13.0.0)
|
31
|
+
Requires-Dist: time-machine (>=2.13.0,<3.0.0)
|
28
32
|
Requires-Dist: tomlkit (>=0.5,<2.0)
|
33
|
+
Requires-Dist: twine (>=4.0.2,<5.0.0)
|
34
|
+
Requires-Dist: typer (>=0.9.0,<0.10.0)
|
29
35
|
Project-URL: Issue Tracker, https://github.com/autopub/autopub/issues
|
30
36
|
Project-URL: Repository, https://github.com/autopub/autopub
|
31
37
|
Description-Content-Type: text/markdown
|
@@ -38,7 +44,7 @@ AutoPub enables project maintainers to release new package versions to PyPI by m
|
|
38
44
|
|
39
45
|
## Environment
|
40
46
|
|
41
|
-
AutoPub is intended for use with continuous integration (CI) systems such as [GitHub Actions][], [CircleCI][], or [Travis CI][]. Projects used with AutoPub
|
47
|
+
AutoPub is intended for use with continuous integration (CI) systems such as [GitHub Actions][], [CircleCI][], or [Travis CI][]. Projects used with AutoPub are built via [build][] and published via [Twine][]. Contributions that add support for other CI and build systems are welcome.
|
42
48
|
|
43
49
|
## Configuration
|
44
50
|
|
@@ -82,6 +88,6 @@ For systems such as Travis CI in which only one deployment step is permitted, th
|
|
82
88
|
[GitHub Actions]: https://github.com/features/actions
|
83
89
|
[CircleCI]: https://circleci.com
|
84
90
|
[Travis CI]: https://travis-ci.org
|
85
|
-
[
|
86
|
-
[
|
91
|
+
[build]: https://pypa-build.readthedocs.io
|
92
|
+
[Twine]: https://twine.readthedocs.io/
|
87
93
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
autopub/__init__.py,sha256=zcNp8aJE_jo-D5xvDuWNZ-ZK6c67NqbTaKtwfGJWtZs,5576
|
2
|
+
autopub/cli/__init__.py,sha256=XG1QVlKPv7svwFOcuosBzXr9AIy9xKDTuOPfI14dtBs,2980
|
3
|
+
autopub/cli/plugins.py,sha256=x80BsIpY81o6rv3MJTH2oTAZkqnAYp3MkjUtpPfxGfI,1021
|
4
|
+
autopub/exceptions.py,sha256=JYn8sIYWCedhtO3XfftZ0M5M_rAPxiGQ4MGbWUaTYwE,1243
|
5
|
+
autopub/plugins/__init__.py,sha256=HtnCcxvZqTUC79vs5aVpNHenRCNuTPpz1gAu2OYkCzg,1153
|
6
|
+
autopub/plugins/bump_version.py,sha256=p-_q80pJDCUy-fKhp-9_9HWTWC2pKe2lFJnimuHHH7w,1338
|
7
|
+
autopub/plugins/pdm.py,sha256=Pczye06fKg8_HMJDkEfMXQyvao9rZ7sqzTHFd6lLEpU,532
|
8
|
+
autopub/plugins/poetry.py,sha256=d2LvW9RI7ZB3reBOXbcp1mqWmzQ06Uyg_T-MxTvlSBg,517
|
9
|
+
autopub/plugins/update_changelog.py,sha256=MmDBGFs6v8zPn3NCfUumpF8YODhg5x2AdjyTzgq5bYQ,1456
|
10
|
+
autopub/types.py,sha256=FcRH4l27nrkQFUQrbAKxNzPPJfzg_0DExZYsCu9Jdzk,249
|
11
|
+
autopub-1.0.0a1.dist-info/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
12
|
+
autopub-1.0.0a1.dist-info/METADATA,sha256=hJImNEz5eaUoQoG1Ziu44EuCP5Wwjo-s9NBUiFWLiMk,3757
|
13
|
+
autopub-1.0.0a1.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
|
14
|
+
autopub-1.0.0a1.dist-info/entry_points.txt,sha256=oeTav5NgCxif6mcZ_HeVGgGv5LzS4DwdI01nr4bO1IM,43
|
15
|
+
autopub-1.0.0a1.dist-info/RECORD,,
|