autopub 0.2.2__py3-none-any.whl → 1.0.0a1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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
@@ -0,0 +1,11 @@
1
+ import dataclasses
2
+
3
+
4
+ @dataclasses.dataclass
5
+ class ReleaseInfo:
6
+ """Release information."""
7
+
8
+ release_type: str
9
+ release_notes: str
10
+ additional_info: dict[str, str] = dataclasses.field(default_factory=dict)
11
+ version: str | None = None
@@ -1,31 +1,37 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: autopub
3
- Version: 0.2.2
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.6,<4.0
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: githubrelease (>=1.5.8,<2.0.0); extra == "github"
27
- Requires-Dist: httpx (==0.16.1); extra == "github"
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 can be published via [Poetry][] or [setuptools][]. Contributions that add support for other CI and build systems are welcome.
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
- [Poetry]: https://poetry.eustace.io
86
- [setuptools]: https://setuptools.readthedocs.io/
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,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.1.0b2
2
+ Generator: poetry-core 1.7.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ autopub=autopub.cli:app
3
+