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/autopub.py DELETED
@@ -1,83 +0,0 @@
1
- import argparse
2
- import os
3
- import sys
4
-
5
- sys.path.append(os.path.dirname(__file__)) # noqa
6
-
7
- from build_release import build_release
8
- from check_release import check_release
9
- from commit_release import git_commit_and_push
10
- from create_github_release import create_github_release
11
- from deploy_release import deploy_release
12
- from prepare_release import prepare_release
13
- from publish_release import publish_release
14
-
15
-
16
- def check(arguments):
17
- check_release()
18
-
19
-
20
- def prepare(arguments):
21
- prepare_release()
22
-
23
-
24
- def build(arguments):
25
- build_release()
26
-
27
-
28
- def commit(arguments):
29
- git_commit_and_push()
30
-
31
-
32
- def githubrelease(arguments):
33
- create_github_release()
34
-
35
-
36
- def publish(arguments):
37
- publish_release()
38
-
39
-
40
- def deploy(arguments):
41
- deploy_release()
42
-
43
-
44
- def parse_arguments():
45
- try:
46
- version = __import__("pkg_resources").get_distribution("autopub").version
47
- except Exception:
48
- version = "unknown"
49
-
50
- parser = argparse.ArgumentParser()
51
- parser.add_argument("--version", action="version", version=version)
52
-
53
- subparsers = parser.add_subparsers()
54
-
55
- check_parser = subparsers.add_parser("check")
56
- check_parser.set_defaults(func=check)
57
-
58
- prepare_parser = subparsers.add_parser("prepare")
59
- prepare_parser.set_defaults(func=prepare)
60
-
61
- build_parser = subparsers.add_parser("build")
62
- build_parser.set_defaults(func=build)
63
-
64
- commit_parser = subparsers.add_parser("commit")
65
- commit_parser.set_defaults(func=commit)
66
-
67
- githubrelease_parser = subparsers.add_parser("githubrelease")
68
- githubrelease_parser.set_defaults(func=githubrelease)
69
-
70
- publish_parser = subparsers.add_parser("publish")
71
- publish_parser.set_defaults(func=publish)
72
-
73
- deploy_parser = subparsers.add_parser("deploy")
74
- deploy_parser.set_defaults(func=deploy)
75
-
76
- arguments = parser.parse_args()
77
-
78
- return arguments
79
-
80
-
81
- def main():
82
- arguments = parse_arguments()
83
- arguments.func(arguments)
autopub/base.py DELETED
@@ -1,159 +0,0 @@
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/build_release.py DELETED
@@ -1,15 +0,0 @@
1
- import os
2
- import sys
3
-
4
- sys.path.append(os.path.dirname(__file__)) # noqa
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"]
12
-
13
-
14
- def build_release():
15
- run_process(build_cmd)
autopub/check_release.py DELETED
@@ -1,15 +0,0 @@
1
- import os
2
- import sys
3
-
4
- sys.path.append(os.path.dirname(__file__)) # noqa
5
-
6
- from base import CI_SYSTEM, RELEASE_FILE, run_process
7
-
8
-
9
- def check_release():
10
- if not os.path.exists(RELEASE_FILE):
11
- print("Not releasing a new version because there is no RELEASE file.")
12
- if CI_SYSTEM == "circleci":
13
- run_process(["circleci", "step", "halt"])
14
- elif CI_SYSTEM == "github" or CI_SYSTEM == "travis":
15
- sys.exit(1)
autopub/commit_release.py DELETED
@@ -1,33 +0,0 @@
1
- import os
2
- import sys
3
-
4
- sys.path.append(os.path.dirname(__file__)) # noqa
5
-
6
- from base import (
7
- get_project_version,
8
- git,
9
- configure_git,
10
- PROJECT_NAME,
11
- PYPROJECT_FILE_NAME,
12
- CHANGELOG_FILE_NAME,
13
- RELEASE_FILE_NAME,
14
- VERSION_STRINGS,
15
- )
16
-
17
-
18
- def git_commit_and_push():
19
- configure_git()
20
-
21
- version = get_project_version()
22
-
23
- git(["add", PYPROJECT_FILE_NAME])
24
- git(["add", CHANGELOG_FILE_NAME])
25
-
26
- if VERSION_STRINGS:
27
- for version_file in VERSION_STRINGS:
28
- git(["add", version_file])
29
-
30
- git(["rm", "--cached", RELEASE_FILE_NAME])
31
-
32
- git(["commit", "-m", f"Release {PROJECT_NAME} {version}"])
33
- git(["push", "origin", "HEAD"])
@@ -1,66 +0,0 @@
1
- import os
2
- import sys
3
- import time
4
-
5
- sys.path.append(os.path.dirname(__file__)) # noqa
6
-
7
- from base import (
8
- run_process,
9
- check_exit_code,
10
- get_project_version,
11
- configure_git,
12
- PROJECT_NAME,
13
- REPO_SLUG,
14
- TAG_PREFIX,
15
- get_release_info,
16
- )
17
-
18
-
19
- def create_github_release():
20
- try:
21
- from github_release import gh_release_create, gh_asset_upload
22
- except ModuleNotFoundError:
23
- print("Cannot create GitHub release due to missing dependency: github_release")
24
- sys.exit(1)
25
-
26
- configure_git()
27
- version = get_project_version()
28
- tag = f"{TAG_PREFIX}{version}"
29
-
30
- if not version:
31
- print("Unable to determine the current version")
32
- sys.exit(1)
33
-
34
- tag_exists = (
35
- check_exit_code([f'git show-ref --tags --quiet --verify -- "refs/tags/{tag}"'])
36
- == 0
37
- )
38
-
39
- if not tag_exists:
40
- run_process(["git", "tag", tag])
41
- run_process(["git", "push", "--tags"])
42
-
43
- _, changelog = get_release_info()
44
-
45
- gh_release_create(
46
- REPO_SLUG,
47
- tag,
48
- publish=True,
49
- name=f"{PROJECT_NAME} {version}",
50
- body=changelog,
51
- )
52
-
53
- # give some time to the API to get updated
54
- # not sure if this is the proper way to fix the issue
55
- # ideally the githubrelease package shouldn't need
56
- # to do another API call to get the release since it
57
- # should be returned by the create API.
58
- # anyway, this fix might be good enough for the time being
59
-
60
- time.sleep(2)
61
-
62
- gh_asset_upload(
63
- REPO_SLUG,
64
- tag,
65
- pattern="dist/*",
66
- )
autopub/deploy_release.py DELETED
@@ -1,18 +0,0 @@
1
- import os
2
- import sys
3
-
4
- sys.path.append(os.path.dirname(__file__)) # noqa
5
-
6
- from build_release import build_release
7
- from create_github_release import create_github_release
8
- from commit_release import git_commit_and_push
9
- from prepare_release import prepare_release
10
- from publish_release import publish_release
11
-
12
-
13
- def deploy_release():
14
- prepare_release()
15
- build_release()
16
- git_commit_and_push()
17
- create_github_release()
18
- publish_release()
@@ -1,83 +0,0 @@
1
- import os
2
- import subprocess
3
- import sys
4
-
5
- sys.path.append(os.path.dirname(__file__)) # noqa
6
-
7
- from base import GITHUB_TOKEN, REPO_SLUG, APPEND_GITHUB_CONTRIBUTOR
8
-
9
-
10
- def append_github_contributor(file):
11
- if not APPEND_GITHUB_CONTRIBUTOR:
12
- return
13
-
14
- try:
15
- import httpx
16
- except ModuleNotFoundError:
17
- print("Cannot append the GitHub contributor due to missing dependency: httpx")
18
- sys.exit(1)
19
-
20
- org, repo = REPO_SLUG.split("/")
21
- current_commit = (
22
- subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("ascii").strip()
23
- )
24
-
25
- response = httpx.post(
26
- "https://api.github.com/graphql",
27
- json={
28
- "query": """query Contributor(
29
- $owner: String!
30
- $name: String!
31
- $commit: GitObjectID!
32
- ) {
33
- repository(owner: $owner, name: $name) {
34
- object(oid: $commit) {
35
- __typename
36
- ... on Commit {
37
- associatedPullRequests(first: 1) {
38
- nodes {
39
- number
40
- author {
41
- __typename
42
- login
43
- ... on User {
44
- name
45
- }
46
- }
47
- }
48
- }
49
- }
50
- }
51
- }
52
- }""",
53
- "variables": {"owner": org, "name": repo, "commit": current_commit},
54
- },
55
- headers={
56
- "Content-Type": "application/json",
57
- "Authorization": f"Bearer {GITHUB_TOKEN}",
58
- },
59
- )
60
-
61
- payload = response.json()
62
- commit = payload["data"]["repository"]["object"]
63
-
64
- if not commit:
65
- return
66
-
67
- prs = commit["associatedPullRequests"]["nodes"]
68
-
69
- if not prs:
70
- return
71
-
72
- pr = prs[0]
73
-
74
- pr_number = pr["number"]
75
- pr_author_username = pr["author"]["login"]
76
- pr_author_fullname = pr["author"].get("name", "")
77
-
78
- file.write("\n")
79
- file.write("\n")
80
- file.write(
81
- f"Contributed by [{pr_author_fullname or pr_author_username}](https://github.com/{pr_author_username}) via [PR #{pr_number}](https://github.com/{REPO_SLUG}/pull/{pr_number}/)"
82
- )
83
- file.write("\n")
@@ -1,119 +0,0 @@
1
- import os
2
- import re
3
- import sys
4
-
5
- sys.path.append(os.path.dirname(__file__)) # noqa
6
-
7
- from datetime import datetime
8
-
9
- from base import (
10
- configure_git,
11
- get_release_info,
12
- run_process,
13
- CHANGELOG_FILE,
14
- CHANGELOG_HEADER,
15
- ROOT,
16
- VERSION_HEADER,
17
- VERSION_STRINGS,
18
- )
19
-
20
-
21
- def find_existing_changelog_files():
22
- changelogs = []
23
- changelog_paths = [ROOT, ROOT / "docs"]
24
- changelog_names = ["CHANGELOG", "CHANGES", "HISTORY"]
25
- changelog_extensions = ["", ".md", ".markdown", ".mdown", ".mkd", ".rst", ".txt"]
26
- for path in changelog_paths:
27
- for name in changelog_names:
28
- for ext in changelog_extensions:
29
- changelog = path / f"{name}{ext}"
30
- if changelog.is_file():
31
- changelogs.append(changelog)
32
- if len(changelogs) > 0:
33
- print(f"Specified changelog file not found: {CHANGELOG_FILE}")
34
- print("Maybe set 'changelog-file' setting to discovered existing file:\n")
35
- for changelog in changelogs:
36
- print(f"{changelog}\n")
37
- sys.exit(1)
38
-
39
-
40
- def validate_release():
41
- if not CHANGELOG_FILE.is_file():
42
- find_existing_changelog_files()
43
-
44
- if not os.environ.get("PYPI_PASSWORD"):
45
- print("PYPI_PASSWORD environment variable is not set.")
46
- sys.exit(1)
47
-
48
-
49
- def update_version_strings(file_path, new_version):
50
- version_regex = re.compile(r"(^_*?version_*?\s*=\s*['\"])(\d+\.\d+\.\d+)", re.M)
51
- with open(file_path, "r+") as f:
52
- content = f.read()
53
- f.seek(0)
54
- f.write(
55
- re.sub(
56
- version_regex,
57
- lambda match: "{}{}".format(match.group(1), new_version),
58
- content,
59
- )
60
- )
61
- f.truncate()
62
-
63
-
64
- def prepare_release():
65
- configure_git()
66
- validate_release()
67
-
68
- POETRY_DUMP_VERSION_OUTPUT = re.compile(
69
- r"Bumping version from \d+\.\d+\.\d+ to (?P<version>\d+\.\d+\.\d+)"
70
- )
71
-
72
- release_type, release_changelog = get_release_info()
73
-
74
- output = run_process(["poetry", "version", release_type])
75
- version_match = POETRY_DUMP_VERSION_OUTPUT.match(output)
76
-
77
- if not version_match:
78
- print("Unable to bump the project version using Poetry")
79
- sys.exit(1)
80
-
81
- new_version = version_match.group("version")
82
-
83
- if VERSION_STRINGS:
84
- for version_file in VERSION_STRINGS:
85
- file_path = ROOT / version_file
86
- update_version_strings(file_path, new_version)
87
-
88
- current_date = datetime.utcnow().strftime("%Y-%m-%d")
89
-
90
- old_changelog_data = ""
91
- header = ""
92
-
93
- if not CHANGELOG_FILE.is_file():
94
- with open(CHANGELOG_FILE, "a+") as f:
95
- f.write(f"CHANGELOG\n{CHANGELOG_HEADER}\n\n")
96
-
97
- with open(CHANGELOG_FILE, "r") as f:
98
- lines = f.readlines()
99
-
100
- for index, line in enumerate(lines):
101
- if CHANGELOG_HEADER != line.strip():
102
- continue
103
-
104
- old_changelog_data = lines[index + 1 :]
105
- header = lines[: index + 1]
106
- break
107
-
108
- with open(CHANGELOG_FILE, "w") as f:
109
- f.write("".join(header))
110
-
111
- new_version_header = f"{new_version} - {current_date}"
112
-
113
- f.write(f"\n{new_version_header}\n")
114
- f.write(f"{VERSION_HEADER * len(new_version_header)}\n\n")
115
-
116
- f.write(release_changelog)
117
- f.write("\n")
118
-
119
- f.write("".join(old_changelog_data))
@@ -1,93 +0,0 @@
1
- import os
2
- import re
3
- import sys
4
-
5
- sys.path.append(os.path.dirname(__file__)) # noqa
6
-
7
- from datetime import datetime
8
-
9
- from base import (
10
- configure_git,
11
- get_release_info,
12
- run_process,
13
- CHANGELOG_FILE,
14
- CHANGELOG_HEADER,
15
- ROOT,
16
- VERSION_HEADER,
17
- VERSION_STRINGS,
18
- )
19
-
20
- from github_contributor import append_github_contributor
21
-
22
-
23
- def update_version_strings(file_path, new_version):
24
- version_regex = re.compile(r"(^_*?version_*?\s*=\s*['\"])(\d+\.\d+\.\d+)", re.M)
25
- with open(file_path, "r+") as f:
26
- content = f.read()
27
- f.seek(0)
28
- f.write(
29
- re.sub(
30
- version_regex,
31
- lambda match: "{}{}".format(match.group(1), new_version),
32
- content,
33
- )
34
- )
35
- f.truncate()
36
-
37
-
38
- def prepare_release():
39
- configure_git()
40
-
41
- POETRY_DUMP_VERSION_OUTPUT = re.compile(
42
- r"Bumping version from \d+\.\d+\.\d+ to (?P<version>\d+\.\d+\.\d+)"
43
- )
44
-
45
- type_, release_changelog = get_release_info()
46
-
47
- output = run_process(["poetry", "version", type_])
48
- version_match = POETRY_DUMP_VERSION_OUTPUT.match(output)
49
-
50
- if not version_match:
51
- print("Unable to bump the project version using Poetry")
52
- sys.exit(1)
53
-
54
- new_version = version_match.group("version")
55
-
56
- if VERSION_STRINGS:
57
- for version_file in VERSION_STRINGS:
58
- file_path = ROOT / version_file
59
- update_version_strings(file_path, new_version)
60
-
61
- current_date = datetime.utcnow().strftime("%Y-%m-%d")
62
-
63
- old_changelog_data = ""
64
- header = ""
65
-
66
- if not CHANGELOG_FILE.is_file():
67
- with open(CHANGELOG_FILE, "a+") as f:
68
- f.write(f"CHANGELOG\n{CHANGELOG_HEADER}\n\n")
69
-
70
- with open(CHANGELOG_FILE, "r") as f:
71
- lines = f.readlines()
72
-
73
- for index, line in enumerate(lines):
74
- if CHANGELOG_HEADER != line.strip():
75
- continue
76
-
77
- old_changelog_data = lines[index + 1 :]
78
- header = lines[: index + 1]
79
- break
80
-
81
- with open(CHANGELOG_FILE, "w") as f:
82
- f.write("".join(header))
83
-
84
- new_version_header = f"{new_version} - {current_date}"
85
-
86
- f.write(f"\n{new_version_header}\n")
87
- f.write(f"{VERSION_HEADER * len(new_version_header)}\n\n")
88
-
89
- f.write(release_changelog)
90
- append_github_contributor(f)
91
- f.write("\n")
92
-
93
- f.write("".join(old_changelog_data))