autopub 0.2.2__tar.gz → 0.4.0__tar.gz

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.
@@ -1,31 +1,32 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: autopub
3
- Version: 0.2.2
3
+ Version: 0.4.0
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.10.0,<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
- Classifier: Programming Language :: Python :: 3.8
20
- Classifier: Programming Language :: Python :: 3.9
21
17
  Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
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: httpx (==0.16.1) ; extra == "github"
28
28
  Requires-Dist: tomlkit (>=0.5,<2.0)
29
+ Requires-Dist: twine (>=4.0.2,<5.0.0)
29
30
  Project-URL: Issue Tracker, https://github.com/autopub/autopub/issues
30
31
  Project-URL: Repository, https://github.com/autopub/autopub
31
32
  Description-Content-Type: text/markdown
@@ -38,7 +39,7 @@ AutoPub enables project maintainers to release new package versions to PyPI by m
38
39
 
39
40
  ## Environment
40
41
 
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.
42
+ 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
43
 
43
44
  ## Configuration
44
45
 
@@ -82,6 +83,5 @@ For systems such as Travis CI in which only one deployment step is permitted, th
82
83
  [GitHub Actions]: https://github.com/features/actions
83
84
  [CircleCI]: https://circleci.com
84
85
  [Travis CI]: https://travis-ci.org
85
- [Poetry]: https://poetry.eustace.io
86
- [setuptools]: https://setuptools.readthedocs.io/
87
-
86
+ [build]: https://pypa-build.readthedocs.io
87
+ [Twine]: https://twine.readthedocs.io/
@@ -6,7 +6,7 @@ AutoPub enables project maintainers to release new package versions to PyPI by m
6
6
 
7
7
  ## Environment
8
8
 
9
- 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.
9
+ 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.
10
10
 
11
11
  ## Configuration
12
12
 
@@ -50,5 +50,5 @@ For systems such as Travis CI in which only one deployment step is permitted, th
50
50
  [GitHub Actions]: https://github.com/features/actions
51
51
  [CircleCI]: https://circleci.com
52
52
  [Travis CI]: https://travis-ci.org
53
- [Poetry]: https://poetry.eustace.io
54
- [setuptools]: https://setuptools.readthedocs.io/
53
+ [build]: https://pypa-build.readthedocs.io
54
+ [Twine]: https://twine.readthedocs.io/
@@ -0,0 +1,160 @@
1
+ import os
2
+ import re
3
+ import subprocess
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ from tomlkit import parse
8
+
9
+
10
+ def dict_get(_dict, keys, default=None):
11
+ """Query nested dictionary with list of keys, returning None if not found."""
12
+ for key in keys:
13
+ if isinstance(_dict, dict):
14
+ _dict = _dict.get(key, default)
15
+ else:
16
+ return default
17
+ return _dict
18
+
19
+
20
+ # Determine CI/CD environment
21
+
22
+ if os.environ.get("CIRCLECI"):
23
+ CI_SYSTEM = "circleci"
24
+ CIRCLE_PROJECT_USERNAME = os.environ.get("CIRCLE_PROJECT_USERNAME")
25
+ CIRCLE_PROJECT_REPONAME = os.environ.get("CIRCLE_PROJECT_REPONAME")
26
+ REPO_SLUG = f"{CIRCLE_PROJECT_USERNAME}/{CIRCLE_PROJECT_REPONAME}"
27
+ elif os.environ.get("GITHUB_ACTIONS") == "true":
28
+ CI_SYSTEM = "github"
29
+ REPO_SLUG = os.environ.get("GITHUB_REPOSITORY")
30
+ elif os.environ.get("TRAVIS"):
31
+ CI_SYSTEM = "travis"
32
+ REPO_SLUG = os.environ.get("TRAVIS_REPO_SLUG")
33
+ else:
34
+ CI_SYSTEM = os.environ.get("CI_SYSTEM", None)
35
+ REPO_SLUG = os.environ.get("REPO_SLUG", None)
36
+
37
+ # Project root and file name configuration
38
+
39
+ PROJECT_ROOT = os.environ.get("PROJECT_ROOT")
40
+ PYPROJECT_FILE_NAME = os.environ.get("PYPROJECT_FILE_NAME", "pyproject.toml")
41
+
42
+ if PROJECT_ROOT:
43
+ ROOT = Path(PROJECT_ROOT)
44
+ else:
45
+ ROOT = Path(
46
+ subprocess.check_output(["git", "rev-parse", "--show-toplevel"])
47
+ .decode("ascii")
48
+ .strip()
49
+ )
50
+
51
+ PYPROJECT_FILE = ROOT / PYPROJECT_FILE_NAME
52
+
53
+ # Retrieve configuration from pyproject file
54
+
55
+ if os.path.exists(PYPROJECT_FILE):
56
+ config = parse(open(PYPROJECT_FILE).read())
57
+ else:
58
+ print(f"Could not find pyproject file at: {PYPROJECT_FILE}")
59
+ sys.exit(1)
60
+
61
+ PROJECT_NAME = dict_get(config, ["tool", "autopub", "project-name"])
62
+ if not PROJECT_NAME:
63
+ PROJECT_NAME = dict_get(config, ["tool", "poetry", "name"])
64
+ if not PROJECT_NAME:
65
+ PROJECT_NAME = dict_get(config, ["project", "name"])
66
+ if not PROJECT_NAME:
67
+ print(
68
+ "Could not determine project name. Under the pyproject file's "
69
+ '[tool.autopub] header, add:\nproject-name = "YourProjectName"'
70
+ )
71
+ sys.exit(1)
72
+
73
+ RELEASE_FILE_NAME = dict_get(
74
+ config, ["tool", "autopub", "release-file"], default="RELEASE.md"
75
+ )
76
+ RELEASE_FILE = ROOT / RELEASE_FILE_NAME
77
+
78
+ CHANGELOG_FILE_NAME = dict_get(
79
+ config, ["tool", "autopub", "changelog-file"], default="CHANGELOG.md"
80
+ )
81
+ CHANGELOG_FILE = ROOT / CHANGELOG_FILE_NAME
82
+
83
+ CHANGELOG_HEADER = dict_get(
84
+ config, ["tool", "autopub", "changelog-header"], default="========="
85
+ )
86
+
87
+ VERSION_HEADER = dict_get(config, ["tool", "autopub", "version-header"], default="-")
88
+ VERSION_STRINGS = dict_get(config, ["tool", "autopub", "version-strings"], default=[])
89
+
90
+ TAG_PREFIX = dict_get(config, ["tool", "autopub", "tag-prefix"], default="")
91
+
92
+ PYPI_URL = dict_get(config, ["tool", "autopub", "pypi-url"])
93
+
94
+ # Git configuration
95
+
96
+ GIT_USERNAME = dict_get(config, ["tool", "autopub", "git-username"])
97
+ GIT_EMAIL = dict_get(config, ["tool", "autopub", "git-email"])
98
+
99
+ # GitHub
100
+
101
+ GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN", None)
102
+ APPEND_GITHUB_CONTRIBUTOR = dict_get(
103
+ config, ["tool", "autopub", "append-github-contributor"], False
104
+ )
105
+
106
+
107
+ def run_process(popenargs, encoding="utf-8", env=None):
108
+ if env is not None:
109
+ env = {**os.environ, **env}
110
+ try:
111
+ return subprocess.check_output(popenargs, encoding=encoding, env=env).strip()
112
+ except subprocess.CalledProcessError as e:
113
+ print(e.output, file=sys.stderr)
114
+ sys.exit(1)
115
+
116
+
117
+ def git(popenargs):
118
+ # Do not decode ASCII for commit messages so emoji are preserved
119
+ return subprocess.check_output(["git", *popenargs])
120
+
121
+
122
+ def check_exit_code(popenargs):
123
+ return subprocess.call(popenargs, shell=True)
124
+
125
+
126
+ def get_project_version():
127
+ # Backwards compat: Try poetry first and then fall "back" to standards
128
+ version = dict_get(config, ["tool", "poetry", "version"])
129
+ if version is None:
130
+ return dict_get(config, ["project", "version"])
131
+ else:
132
+ return version
133
+
134
+
135
+ def get_release_info():
136
+ RELEASE_TYPE_REGEX = re.compile(r"^[Rr]elease [Tt]ype: (major|minor|patch)$")
137
+
138
+ with open(RELEASE_FILE, "r") as f:
139
+ line = f.readline()
140
+ match = RELEASE_TYPE_REGEX.match(line)
141
+
142
+ if not match:
143
+ print(
144
+ "The RELEASE file should start with 'Release type' and "
145
+ "specify one of the following values: major, minor, or patch."
146
+ )
147
+ sys.exit(1)
148
+
149
+ type_ = match.group(1)
150
+ changelog = "".join([l for l in f.readlines()]).strip()
151
+
152
+ return type_, changelog
153
+
154
+
155
+ def configure_git():
156
+ if not GIT_USERNAME or not GIT_EMAIL:
157
+ print("git-username and git-email must be defined in the pyproject file")
158
+ sys.exit(1)
159
+ git(["config", "user.name", GIT_USERNAME])
160
+ git(["config", "user.email", GIT_EMAIL])
@@ -0,0 +1,14 @@
1
+ import os
2
+ import sys
3
+
4
+ sys.path.append(os.path.dirname(__file__)) # noqa
5
+
6
+ from base import git, run_process
7
+
8
+
9
+ def build_release():
10
+ env = None
11
+ if "SOURCE_DATE_EPOCH" not in os.environ:
12
+ ctime = git(["log", "-1", "--pretty=%ct"]).decode().strip()
13
+ env = {"SOURCE_DATE_EPOCH": ctime}
14
+ run_process([sys.executable, "-m", "build"], env=env)
@@ -7,9 +7,13 @@ from base import CI_SYSTEM, RELEASE_FILE, run_process
7
7
 
8
8
 
9
9
  def check_release():
10
- if not os.path.exists(RELEASE_FILE):
10
+ needs_release = os.path.exists(RELEASE_FILE)
11
+ if not needs_release:
11
12
  print("Not releasing a new version because there is no RELEASE file.")
12
13
  if CI_SYSTEM == "circleci":
13
14
  run_process(["circleci", "step", "halt"])
14
- elif CI_SYSTEM == "github" or CI_SYSTEM == "travis":
15
+ elif CI_SYSTEM == "travis":
15
16
  sys.exit(1)
17
+ if CI_SYSTEM == "github":
18
+ with open(os.path.expandvars("$GITHUB_OUTPUT"), "a") as f:
19
+ f.write("autopub_release={}\n".format("true" if needs_release else "false"))
@@ -5,20 +5,20 @@ import time
5
5
  sys.path.append(os.path.dirname(__file__)) # noqa
6
6
 
7
7
  from base import (
8
- run_process,
9
- check_exit_code,
10
- get_project_version,
11
- configure_git,
12
8
  PROJECT_NAME,
13
9
  REPO_SLUG,
14
10
  TAG_PREFIX,
11
+ check_exit_code,
12
+ configure_git,
13
+ get_project_version,
15
14
  get_release_info,
15
+ run_process,
16
16
  )
17
17
 
18
18
 
19
19
  def create_github_release():
20
20
  try:
21
- from github_release import gh_release_create, gh_asset_upload
21
+ from .vendor.github_release import gh_asset_upload, gh_release_create
22
22
  except ModuleNotFoundError:
23
23
  print("Cannot create GitHub release due to missing dependency: github_release")
24
24
  sys.exit(1)
@@ -6,17 +6,20 @@ sys.path.append(os.path.dirname(__file__)) # noqa
6
6
 
7
7
  from datetime import datetime
8
8
 
9
+ import tomlkit
9
10
  from base import (
10
- configure_git,
11
- get_release_info,
12
- run_process,
13
11
  CHANGELOG_FILE,
14
12
  CHANGELOG_HEADER,
13
+ PYPROJECT_FILE,
15
14
  ROOT,
16
15
  VERSION_HEADER,
17
16
  VERSION_STRINGS,
17
+ configure_git,
18
+ dict_get,
19
+ get_project_version,
20
+ get_release_info,
18
21
  )
19
-
22
+ from dunamai import Version
20
23
  from github_contributor import append_github_contributor
21
24
 
22
25
 
@@ -38,20 +41,22 @@ def update_version_strings(file_path, new_version):
38
41
  def prepare_release():
39
42
  configure_git()
40
43
 
41
- POETRY_DUMP_VERSION_OUTPUT = re.compile(
42
- r"Bumping version from \d+\.\d+\.\d+ to (?P<version>\d+\.\d+\.\d+)"
43
- )
44
-
45
44
  type_, release_changelog = get_release_info()
46
45
 
47
- output = run_process(["poetry", "version", type_])
48
- version_match = POETRY_DUMP_VERSION_OUTPUT.match(output)
46
+ version = Version(get_project_version())
47
+ new_version = version.bump({"major": 0, "minor": 1, "patch": 2}[type_]).serialize()
48
+
49
+ with open(PYPROJECT_FILE, "r") as f:
50
+ config = tomlkit.load(f)
49
51
 
50
- if not version_match:
51
- print("Unable to bump the project version using Poetry")
52
- sys.exit(1)
52
+ poetry = dict_get(config, ["tool", "poetry", "version"])
53
+ if poetry:
54
+ config["tool"]["poetry"]["version"] = new_version
55
+ else:
56
+ config["project"]["version"] = new_version
53
57
 
54
- new_version = version_match.group("version")
58
+ with open(PYPROJECT_FILE, "w") as f:
59
+ config = tomlkit.dump(config, f)
55
60
 
56
61
  if VERSION_STRINGS:
57
62
  for version_file in VERSION_STRINGS:
@@ -0,0 +1,17 @@
1
+ import glob
2
+ import os
3
+ import sys
4
+
5
+ sys.path.append(os.path.dirname(__file__)) # noqa
6
+
7
+ from base import PYPI_URL, run_process
8
+
9
+
10
+ def publish_release():
11
+ env = None
12
+ if PYPI_URL:
13
+ env = {"TWINE_REPOSITORY_URL": PYPI_URL}
14
+ dists = glob.glob("dist/*")
15
+ run_process(
16
+ [sys.executable, "-m", "twine", "upload", "--non-interactive", *dists], env=env
17
+ )
File without changes