autopub 1.0.0a14__tar.gz → 1.0.0a16__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: autopub
3
- Version: 1.0.0a14
3
+ Version: 1.0.0a16
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
@@ -18,7 +18,10 @@ from autopub.exceptions import (
18
18
  ReleaseTypeInvalid,
19
19
  ReleaseTypeMissing,
20
20
  )
21
- from autopub.plugins import AutopubPackageManagerPlugin, AutopubPlugin
21
+ from autopub.plugins import (
22
+ AutopubPackageManagerPlugin,
23
+ AutopubPlugin,
24
+ )
22
25
  from autopub.types import ReleaseInfo
23
26
 
24
27
 
@@ -41,26 +44,22 @@ class Autopub:
41
44
  return hashlib.sha256(self.release_notes.encode("utf-8")).hexdigest()
42
45
 
43
46
  @property
44
- def release_data_file(self) -> Path:
45
- return Path(".autopub") / "release_data.json"
47
+ def release_info_file(self) -> Path:
48
+ return Path(".autopub") / "release_info.json"
46
49
 
47
50
  @property
48
- def release_data(self) -> ReleaseInfo:
49
- if not self.release_data_file.exists():
51
+ def release_info(self) -> ReleaseInfo:
52
+ if not self.release_info_file.exists():
50
53
  raise ArtifactNotFound()
51
54
 
52
- release_data = json.loads(self.release_data_file.read_text())
55
+ release_info = json.loads(self.release_info_file.read_text())
53
56
 
54
- if release_data["hash"] != self.release_file_hash:
57
+ if release_info["hash"] != self.release_file_hash:
55
58
  raise ArtifactHashMismatch()
56
59
 
57
- return ReleaseInfo(
58
- release_type=release_data["release_type"],
59
- release_notes=release_data["release_notes"],
60
- additional_info=release_data["plugin_data"],
61
- )
60
+ return ReleaseInfo.from_dict(release_info)
62
61
 
63
- def check(self) -> ReleaseInfo:
62
+ def check(self) -> None:
64
63
  release_file = Path(self.RELEASE_FILE_PATH)
65
64
 
66
65
  if not release_file.exists():
@@ -76,9 +75,10 @@ class Autopub:
76
75
  for plugin in self.plugins:
77
76
  plugin.on_release_notes_valid(release_info)
78
77
 
79
- self._write_artifact(release_info)
78
+ for plugin in self.plugins:
79
+ plugin.post_check(release_info)
80
80
 
81
- return release_info
81
+ self._write_artifact(release_info)
82
82
 
83
83
  def build(self) -> None:
84
84
  if not any(
@@ -91,21 +91,21 @@ class Autopub:
91
91
  plugin.build()
92
92
 
93
93
  def prepare(self) -> None:
94
- for plugin in self.plugins:
95
- plugin.prepare(self.release_data)
94
+ release_info = self.release_info
96
95
 
97
- self._write_artifact(self.release_data)
96
+ for plugin in self.plugins:
97
+ plugin.prepare(release_info)
98
98
 
99
99
  for plugin in self.plugins:
100
- plugin.post_prepare(self.release_data)
100
+ plugin.post_prepare(release_info)
101
101
 
102
- self._write_artifact(self.release_data)
102
+ self._write_artifact(release_info)
103
103
 
104
104
  def _delete_release_file(self) -> None:
105
105
  self.release_file.unlink(missing_ok=True)
106
106
 
107
107
  def publish(self, repository: str | None = None) -> None:
108
- release_info = self.release_data
108
+ release_info = self.release_info
109
109
 
110
110
  for plugin in self.plugins:
111
111
  # TODO: maybe pass release info to publish method?
@@ -119,18 +119,12 @@ class Autopub:
119
119
 
120
120
  def _write_artifact(self, release_info: ReleaseInfo) -> None:
121
121
  data = {
122
+ **release_info.dict(),
122
123
  "hash": self.release_file_hash,
123
- "release_type": release_info.release_type,
124
- "release_notes": release_info.release_notes,
125
- "plugin_data": {
126
- key: value
127
- for plugin in self.plugins
128
- for key, value in plugin.data.items()
129
- },
130
124
  }
131
125
 
132
- self.release_data_file.parent.mkdir(exist_ok=True)
133
- self.release_data_file.write_text(json.dumps(data))
126
+ self.release_info_file.parent.mkdir(exist_ok=True)
127
+ self.release_info_file.write_text(json.dumps(data))
134
128
 
135
129
  def _deprecated_load(self, release_notes: str) -> ReleaseInfo:
136
130
  # supports loading of old release notes format, which is
@@ -178,6 +172,8 @@ class Autopub:
178
172
  release_type=release_type,
179
173
  release_notes=post.content,
180
174
  additional_info=data,
175
+ version=None,
176
+ previous_version=None,
181
177
  )
182
178
 
183
179
  def _validate_release_notes(self, release_notes: str) -> ReleaseInfo:
@@ -29,12 +29,14 @@ def check():
29
29
  autopub = Autopub(plugins=find_plugins(state["plugins"]))
30
30
 
31
31
  try:
32
- release_info = autopub.check()
32
+ autopub.check()
33
33
  except AutopubException as e:
34
34
  rich.print(Panel.fit(f"[red]{e.message}"))
35
35
 
36
36
  raise typer.Exit(1) from e
37
37
  else:
38
+ release_info = autopub.release_info
39
+
38
40
  rich.print(
39
41
  Padding(
40
42
  Group(
@@ -17,25 +17,43 @@ class AutopubPlugin:
17
17
  except subprocess.CalledProcessError as e:
18
18
  raise CommandFailed(command=command, returncode=e.returncode) from e
19
19
 
20
+ def post_check(self, release_info: ReleaseInfo) -> None: # pragma: no cover
21
+ ...
22
+
20
23
  def prepare(self, release_info: ReleaseInfo) -> None: # pragma: no cover
21
24
  ...
22
25
 
23
26
  def post_prepare(self, release_info: ReleaseInfo) -> None: # pragma: no cover
24
27
  ...
25
28
 
26
- def validate_release_notes(self, release_info: ReleaseInfo): # pragma: no cover
29
+ def validate_release_notes(
30
+ self, release_info: ReleaseInfo
31
+ ) -> None: # pragma: no cover
27
32
  ...
28
33
 
29
- def on_release_notes_valid(self, release_info: ReleaseInfo): # pragma: no cover
34
+ def on_release_notes_valid(
35
+ self, release_info: ReleaseInfo
36
+ ) -> None: # pragma: no cover
30
37
  ...
31
38
 
32
- def on_release_notes_invalid(self, exception: AutopubException): # pragma: no cover
39
+ def on_release_notes_invalid(
40
+ self, exception: AutopubException
41
+ ) -> None: # pragma: no cover
33
42
  ...
34
43
 
35
44
  def post_publish(self, release_info: ReleaseInfo) -> None: # pragma: no cover
36
45
  ...
37
46
 
38
47
 
48
+ @runtime_checkable
49
+ class AutopubBumpVersionPlugin(Protocol):
50
+ new_version: str
51
+ current_version: str
52
+
53
+ def post_check(self, release_info: ReleaseInfo) -> None: # pragma: no cover
54
+ ...
55
+
56
+
39
57
  @runtime_checkable
40
58
  class AutopubPackageManagerPlugin(Protocol):
41
59
  def build(self) -> None: # pragma: no cover
@@ -5,11 +5,14 @@ import pathlib
5
5
  import tomlkit
6
6
  from dunamai import Version
7
7
 
8
- from autopub.plugins import AutopubPlugin
8
+ from autopub.plugins import AutopubBumpVersionPlugin, AutopubPlugin
9
9
  from autopub.types import ReleaseInfo
10
10
 
11
11
 
12
- class BumpVersionPlugin(AutopubPlugin):
12
+ class BumpVersionPlugin(AutopubBumpVersionPlugin, AutopubPlugin):
13
+ current_version: str
14
+ new_version: str
15
+
13
16
  @property
14
17
  def pyproject_config(self) -> tomlkit.TOMLDocument:
15
18
  content = pathlib.Path("pyproject.toml").read_text()
@@ -28,17 +31,16 @@ class BumpVersionPlugin(AutopubPlugin):
28
31
  except KeyError:
29
32
  config["project"]["version"] = new_version # type: ignore
30
33
 
31
- def prepare(self, release_info: ReleaseInfo) -> None:
34
+ def post_check(self, release_info: ReleaseInfo) -> None:
32
35
  config = self.pyproject_config
33
36
 
34
- version = Version(self._get_version(config))
35
-
36
37
  bump_type = {"major": 0, "minor": 1, "patch": 2}[release_info.release_type]
37
- new_version = version.bump(bump_type).serialize()
38
38
 
39
- self.data["old_version"] = version.serialize()
40
- self.data["new_version"] = new_version
39
+ version = Version(self._get_version(config))
40
+
41
+ self.previous_version = str(version)
42
+ self.new_version = version.bump(bump_type).serialize()
41
43
 
42
- self._update_version(config, new_version)
44
+ self._update_version(config, self.new_version)
43
45
 
44
46
  pathlib.Path("pyproject.toml").write_text(tomlkit.dumps(config)) # type: ignore
@@ -6,16 +6,18 @@ from autopub.types import ReleaseInfo
6
6
 
7
7
  class GitPlugin(AutopubPlugin):
8
8
  def post_publish(self, release_info: ReleaseInfo) -> None:
9
- tag = release_info.additional_info["new_version"]
9
+ assert release_info.version is not None
10
+
11
+ tag_name = release_info.version
10
12
 
11
13
  self.run_command(["git", "config", "--global", "user.email", "autopub@autopub"])
12
14
  self.run_command(["git", "config", "--global", "user.name", "autopub"])
13
15
 
14
- self.run_command(["git", "tag", tag])
16
+ self.run_command(["git", "tag", tag_name])
15
17
 
16
18
  # TODO: config?
17
19
  self.run_command(["git", "rm", "RELEASE.md"])
18
20
  self.run_command(["git", "add", "--all", "--", ":!main/.autopub"])
19
21
  self.run_command(["git", "commit", "-m", "🤖 autopub publish"])
20
22
  self.run_command(["git", "push"])
21
- self.run_command(["git", "push", "origin", tag])
23
+ self.run_command(["git", "push", "origin", tag_name])
@@ -17,8 +17,6 @@ class UpdateChangelogPlugin(AutopubPlugin):
17
17
  return Path("CHANGELOG.md")
18
18
 
19
19
  def post_prepare(self, release_info: ReleaseInfo) -> None:
20
- assert release_info.additional_info["new_version"]
21
-
22
20
  if not self.changelog_file.exists():
23
21
  self.changelog_file.write_text(f"CHANGELOG\n{CHANGELOG_HEADER}\n\n")
24
22
 
@@ -37,7 +35,9 @@ class UpdateChangelogPlugin(AutopubPlugin):
37
35
  header = lines[: index + 1]
38
36
  break
39
37
 
40
- new_version = release_info.additional_info["new_version"]
38
+ new_version = release_info.version
39
+
40
+ assert new_version is not None
41
41
 
42
42
  with self.changelog_file.open("w") as f:
43
43
  f.write("\n".join(header))
@@ -48,5 +48,9 @@ class UpdateChangelogPlugin(AutopubPlugin):
48
48
  f.write(f"\n{new_version_header}\n")
49
49
  f.write(f"{VERSION_HEADER * len(new_version_header)}\n\n")
50
50
  f.write(release_info.release_notes)
51
+
52
+ for line in release_info.additional_release_notes:
53
+ f.write(f"\n\n{line}")
54
+
51
55
  f.write("\n")
52
56
  f.write("\n".join(old_changelog_data))
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ import dataclasses
4
+ from typing import Any
5
+
6
+ from typing_extensions import Self
7
+
8
+
9
+ @dataclasses.dataclass(kw_only=True)
10
+ class ReleaseInfo:
11
+ """Release information."""
12
+
13
+ release_type: str
14
+ release_notes: str
15
+ additional_info: dict[str, Any] = dataclasses.field(default_factory=dict)
16
+ additional_release_notes: list[str] = dataclasses.field(default_factory=list)
17
+ version: str | None = None
18
+ previous_version: str | None = None
19
+
20
+ def dict(self) -> dict[str, Any]:
21
+ """Return a dictionary representation of the release info."""
22
+ return dataclasses.asdict(self)
23
+
24
+ @classmethod
25
+ def from_dict(cls, data: dict[str, Any]) -> Self:
26
+ return cls(
27
+ release_type=data["release_type"],
28
+ release_notes=data["release_notes"],
29
+ additional_info=data["additional_info"],
30
+ additional_release_notes=data["additional_release_notes"],
31
+ version=data["version"],
32
+ previous_version=data["previous_version"],
33
+ )
@@ -3,7 +3,7 @@ requires-python = ">=3.8"
3
3
 
4
4
  [tool.poetry]
5
5
  name = "autopub"
6
- version = "1.0.0-alpha.14"
6
+ version = "1.0.0-alpha.16"
7
7
  description = "Automatic package release upon pull request merge"
8
8
  authors = ["Justin Mayer <entroP@gmail.com>", "Patrick Arminio <patrick.arminio@gmail.com>"]
9
9
  license = "AGPL-3.0"
@@ -66,6 +66,7 @@ autopub = "autopub.cli:app"
66
66
 
67
67
  [tool.poetry.group.dev.dependencies]
68
68
  pytest-cov = "^4.1.0"
69
+ pytest-mock = "^3.12.0"
69
70
 
70
71
  [tool.autopub]
71
72
  project-name = "AutoPub"
@@ -1,11 +0,0 @@
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
File without changes
File without changes
File without changes