autopub 0.2.2__py3-none-any.whl → 0.4.0__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/base copy.py ADDED
@@ -0,0 +1,159 @@
1
+ import os
2
+ import re
3
+ import subprocess
4
+
5
+ from pathlib import Path
6
+ from tomlkit import parse
7
+
8
+
9
+ def dict_get(_dict, keys, default=None):
10
+ """Query nested dictionary with list of keys, returning None if not found."""
11
+ for key in keys:
12
+ if isinstance(_dict, dict):
13
+ _dict = _dict.get(key, default)
14
+ else:
15
+ return default
16
+ return _dict
17
+
18
+
19
+ # Determine CI/CD environment
20
+
21
+ if os.environ.get("CIRCLECI"):
22
+ CI_SYSTEM = "circleci"
23
+ CIRCLE_PROJECT_USERNAME = os.environ.get("CIRCLE_PROJECT_USERNAME")
24
+ CIRCLE_PROJECT_REPONAME = os.environ.get("CIRCLE_PROJECT_REPONAME")
25
+ REPO_SLUG = f"{CIRCLE_PROJECT_USERNAME}/{CIRCLE_PROJECT_REPONAME}"
26
+ elif os.environ.get("GITHUB_WORKFLOW"):
27
+ CI_SYSTEM = "github"
28
+ REPO_SLUG = os.environ.get("GITHUB_REPOSITORY")
29
+ elif os.environ.get("TRAVIS"):
30
+ CI_SYSTEM = "travis"
31
+ REPO_SLUG = os.environ.get("TRAVIS_REPO_SLUG")
32
+ else:
33
+ CI_SYSTEM = os.environ.get("CI_SYSTEM", None)
34
+ REPO_SLUG = os.environ.get("REPO_SLUG", None)
35
+
36
+ # Project root and file name configuration
37
+
38
+ PROJECT_ROOT = os.environ.get("PROJECT_ROOT")
39
+ PYPROJECT_FILE_NAME = os.environ.get("PYPROJECT_FILE_NAME", "pyproject.toml")
40
+
41
+ if PROJECT_ROOT:
42
+ ROOT = Path(PROJECT_ROOT)
43
+ else:
44
+ ROOT = Path(
45
+ subprocess.check_output(["git", "rev-parse", "--show-toplevel"])
46
+ .decode("ascii")
47
+ .strip()
48
+ )
49
+
50
+ PYPROJECT_FILE = ROOT / PYPROJECT_FILE_NAME
51
+
52
+ # Retrieve configuration from pyproject file
53
+
54
+ if os.path.exists(PYPROJECT_FILE):
55
+ config = parse(open(PYPROJECT_FILE).read())
56
+ else:
57
+ raise SystemExit(f"Could not find pyproject file at: {PYPROJECT_FILE}")
58
+
59
+ PROJECT_NAME = dict_get(config, ["tool", "autopub", "project-name"])
60
+ if not PROJECT_NAME:
61
+ PROJECT_NAME = dict_get(config, ["tool", "poetry", "name"])
62
+ if not PROJECT_NAME:
63
+ raise SystemExit(
64
+ "Could not determine project name. Under the pyproject file's "
65
+ '[tool.autopub] header, add:\nproject-name = "YourProjectName"'
66
+ )
67
+
68
+ RELEASE_FILE_NAME = dict_get(
69
+ config, ["tool", "autopub", "release-file"], default="RELEASE.md"
70
+ )
71
+ RELEASE_FILE = ROOT / RELEASE_FILE_NAME
72
+
73
+ CHANGELOG_FILE_NAME = dict_get(
74
+ config, ["tool", "autopub", "changelog-file"], default="CHANGELOG.md"
75
+ )
76
+ CHANGELOG_FILE = ROOT / CHANGELOG_FILE_NAME
77
+
78
+ CHANGELOG_HEADER = dict_get(
79
+ config, ["tool", "autopub", "changelog-header"], default="========="
80
+ )
81
+
82
+ VERSION_HEADER = dict_get(config, ["tool", "autopub", "version-header"], default="-")
83
+ VERSION_STRINGS = dict_get(config, ["tool", "autopub", "version-strings"], default=[])
84
+
85
+ TAG_PREFIX = dict_get(config, ["tool", "autopub", "tag-prefix"], default="")
86
+
87
+ PYPI_URL = dict_get(config, ["tool", "autopub", "pypi-url"])
88
+
89
+ BUILD_SYSTEM = dict_get(config, ["tool", "autopub", "build-system"])
90
+ if not BUILD_SYSTEM:
91
+ build_requires = dict_get(config, ["build-system", "requires"])
92
+ if "poetry" in build_requires:
93
+ BUILD_SYSTEM = "poetry"
94
+ elif "setuptools" in build_requires:
95
+ BUILD_SYSTEM = "setuptools"
96
+
97
+ # Git configuration
98
+
99
+ GIT_USERNAME = dict_get(config, ["tool", "autopub", "git-username"])
100
+ GIT_EMAIL = dict_get(config, ["tool", "autopub", "git-email"])
101
+
102
+ # GitHub
103
+
104
+ GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN", None)
105
+ APPEND_GITHUB_CONTRIBUTOR = dict_get(
106
+ config, ["tool", "autopub", "append-github-contributor"], False
107
+ )
108
+
109
+
110
+ def run_process(popenargs, encoding="utf-8"):
111
+ return subprocess.check_output(popenargs).decode(encoding).strip()
112
+
113
+
114
+ def git(popenargs):
115
+ # Do not decode ASCII for commit messages so emoji are preserved
116
+ return subprocess.check_output(["git", *popenargs])
117
+
118
+
119
+ def check_exit_code(popenargs):
120
+ return subprocess.call(popenargs, shell=True)
121
+
122
+
123
+ def get_project_version():
124
+ VERSION_REGEX = re.compile(r"^version\s*=\s*\"(?P<version>\d+\.\d+\.\d+)\"$")
125
+
126
+ with open(PYPROJECT_FILE) as f:
127
+ for line in f:
128
+ match = VERSION_REGEX.match(line)
129
+
130
+ if match:
131
+ return match.group("version")
132
+
133
+ return None
134
+
135
+
136
+ def get_release_info():
137
+ RELEASE_TYPE_REGEX = re.compile(r"^[Rr]elease [Tt]ype: (major|minor|patch)$")
138
+
139
+ with open(RELEASE_FILE, "r") as f:
140
+ line = f.readline()
141
+ match = RELEASE_TYPE_REGEX.match(line)
142
+
143
+ if not match:
144
+ raise SystemExit(
145
+ "The RELEASE file should start with 'Release type' and "
146
+ "specify one of the following values: major, minor, or patch."
147
+ )
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
+ raise SystemExit("git-username and git-email must be defined in the pyproject file")
158
+ git(["config", "user.name", GIT_USERNAME])
159
+ git(["config", "user.email", GIT_EMAIL])
autopub/base.py CHANGED
@@ -1,8 +1,9 @@
1
1
  import os
2
2
  import re
3
3
  import subprocess
4
-
4
+ import sys
5
5
  from pathlib import Path
6
+
6
7
  from tomlkit import parse
7
8
 
8
9
 
@@ -23,7 +24,7 @@ if os.environ.get("CIRCLECI"):
23
24
  CIRCLE_PROJECT_USERNAME = os.environ.get("CIRCLE_PROJECT_USERNAME")
24
25
  CIRCLE_PROJECT_REPONAME = os.environ.get("CIRCLE_PROJECT_REPONAME")
25
26
  REPO_SLUG = f"{CIRCLE_PROJECT_USERNAME}/{CIRCLE_PROJECT_REPONAME}"
26
- elif os.environ.get("GITHUB_WORKFLOW"):
27
+ elif os.environ.get("GITHUB_ACTIONS") == "true":
27
28
  CI_SYSTEM = "github"
28
29
  REPO_SLUG = os.environ.get("GITHUB_REPOSITORY")
29
30
  elif os.environ.get("TRAVIS"):
@@ -54,16 +55,20 @@ PYPROJECT_FILE = ROOT / PYPROJECT_FILE_NAME
54
55
  if os.path.exists(PYPROJECT_FILE):
55
56
  config = parse(open(PYPROJECT_FILE).read())
56
57
  else:
57
- raise SystemExit(f"Could not find pyproject file at: {PYPROJECT_FILE}")
58
+ print(f"Could not find pyproject file at: {PYPROJECT_FILE}")
59
+ sys.exit(1)
58
60
 
59
61
  PROJECT_NAME = dict_get(config, ["tool", "autopub", "project-name"])
60
62
  if not PROJECT_NAME:
61
63
  PROJECT_NAME = dict_get(config, ["tool", "poetry", "name"])
62
64
  if not PROJECT_NAME:
63
- raise SystemExit(
65
+ PROJECT_NAME = dict_get(config, ["project", "name"])
66
+ if not PROJECT_NAME:
67
+ print(
64
68
  "Could not determine project name. Under the pyproject file's "
65
69
  '[tool.autopub] header, add:\nproject-name = "YourProjectName"'
66
70
  )
71
+ sys.exit(1)
67
72
 
68
73
  RELEASE_FILE_NAME = dict_get(
69
74
  config, ["tool", "autopub", "release-file"], default="RELEASE.md"
@@ -86,14 +91,6 @@ TAG_PREFIX = dict_get(config, ["tool", "autopub", "tag-prefix"], default="")
86
91
 
87
92
  PYPI_URL = dict_get(config, ["tool", "autopub", "pypi-url"])
88
93
 
89
- BUILD_SYSTEM = dict_get(config, ["tool", "autopub", "build-system"])
90
- if not BUILD_SYSTEM:
91
- build_requires = dict_get(config, ["build-system", "requires"])
92
- if "poetry" in build_requires:
93
- BUILD_SYSTEM = "poetry"
94
- elif "setuptools" in build_requires:
95
- BUILD_SYSTEM = "setuptools"
96
-
97
94
  # Git configuration
98
95
 
99
96
  GIT_USERNAME = dict_get(config, ["tool", "autopub", "git-username"])
@@ -107,8 +104,14 @@ APPEND_GITHUB_CONTRIBUTOR = dict_get(
107
104
  )
108
105
 
109
106
 
110
- def run_process(popenargs, encoding="utf-8"):
111
- return subprocess.check_output(popenargs).decode(encoding).strip()
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)
112
115
 
113
116
 
114
117
  def git(popenargs):
@@ -121,16 +124,12 @@ def check_exit_code(popenargs):
121
124
 
122
125
 
123
126
  def get_project_version():
124
- VERSION_REGEX = re.compile(r"^version\s*=\s*\"(?P<version>\d+\.\d+\.\d+)\"$")
125
-
126
- with open(PYPROJECT_FILE) as f:
127
- for line in f:
128
- match = VERSION_REGEX.match(line)
129
-
130
- if match:
131
- return match.group("version")
132
-
133
- return None
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
134
133
 
135
134
 
136
135
  def get_release_info():
@@ -141,10 +140,11 @@ def get_release_info():
141
140
  match = RELEASE_TYPE_REGEX.match(line)
142
141
 
143
142
  if not match:
144
- raise SystemExit(
143
+ print(
145
144
  "The RELEASE file should start with 'Release type' and "
146
145
  "specify one of the following values: major, minor, or patch."
147
146
  )
147
+ sys.exit(1)
148
148
 
149
149
  type_ = match.group(1)
150
150
  changelog = "".join([l for l in f.readlines()]).strip()
@@ -154,6 +154,7 @@ def get_release_info():
154
154
 
155
155
  def configure_git():
156
156
  if not GIT_USERNAME or not GIT_EMAIL:
157
- raise SystemExit("git-username and git-email must be defined in the pyproject file")
157
+ print("git-username and git-email must be defined in the pyproject file")
158
+ sys.exit(1)
158
159
  git(["config", "user.name", GIT_USERNAME])
159
160
  git(["config", "user.email", GIT_EMAIL])
autopub/build_release.py CHANGED
@@ -3,13 +3,12 @@ import sys
3
3
 
4
4
  sys.path.append(os.path.dirname(__file__)) # noqa
5
5
 
6
- from base import BUILD_SYSTEM, run_process
7
-
8
- if BUILD_SYSTEM == "poetry":
9
- build_cmd = ["poetry", "build"]
10
- else:
11
- build_cmd = ["python", "setup.py", "sdist", "bdist_wheel"]
6
+ from base import git, run_process
12
7
 
13
8
 
14
9
  def build_release():
15
- run_process(build_cmd)
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)
autopub/check_release.py CHANGED
@@ -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:
@@ -1,22 +1,17 @@
1
+ import glob
1
2
  import os
2
3
  import sys
3
4
 
4
5
  sys.path.append(os.path.dirname(__file__)) # noqa
5
6
 
6
- from base import BUILD_SYSTEM, PYPI_URL, run_process
7
-
8
- poetry_pub = ["poetry", "publish", "-u", "$PYPI_USERNAME", "-p", "$PYPI_PASSWORD"]
9
-
10
- if PYPI_URL:
11
- twine_pub = ["twine", "upload", "--repository-url", PYPI_URL, "dist/*"]
12
- else:
13
- twine_pub = ["twine", "upload", "dist/*"]
14
-
15
- if BUILD_SYSTEM == "poetry":
16
- pub_cmd = poetry_pub
17
- else:
18
- pub_cmd = twine_pub
7
+ from base import PYPI_URL, run_process
19
8
 
20
9
 
21
10
  def publish_release():
22
- run_process(pub_cmd)
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