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 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
+