Coverage for pump.py: 55%
42 statements
« prev ^ index » next coverage.py v7.1.0, created at 2023-02-19 17:08 +0800
« prev ^ index » next coverage.py v7.1.0, created at 2023-02-19 17:08 +0800
1"""Version Pump Automation
3- update pyproject.toml
4- run pytest and doctest
5- generate coverage report and github badges
6- update changelog
7- create new github commit, tag and release
8- publish new version to PyPi
10Examples:
11 - dry run
12 ./pump.py patch
14 - update pyproject.toml and local git tag
15 ./pump.py patch --tag
17 - update everything and publish new version
18 ./pump.py patch --tag --publish
19"""
21import toml
22from click import argument, Choice, option, command, secho
23from subprocess import getstatusoutput
24from functools import reduce
26CHOICES = ["major", "minor", "patch"]
29# === uti ===
30def abort(msg: str = "") -> None:
31 secho(msg or "Aborted.", fg="red")
32 exit(1)
35def run(cmd: str) -> None:
36 """run shell command"""
37 secho(cmd)
38 if getstatusoutput(cmd)[0]:
39 abort()
42# === main ===
45@command()
46@argument("section", type=Choice(CHOICES))
47@option("--tag/--no-tag", help="tag local commit with new version", default=False)
48@option(
49 "--publish/--no-publish",
50 help="publish to pypi and update github release",
51 default=False,
52)
53def main(section, tag, publish):
54 """Version Pump Automation CLI"""
56 # parse toml
57 data = toml.load("pyproject.toml")
58 old_version = data["tool"]["poetry"]["version"]
59 new_version = upgrade_version(section, old_version)
60 data["tool"]["poetry"]["version"] = new_version
62 print(old_version, "->", new_version)
64 if tag:
65 with open("pyproject.toml", "w") as f:
66 toml.dump(data, f)
67 print(f"pyproject.toml pumped to {new_version}")
69 run(f"git tag {new_version}")
71 # publish to pypi, update github release, commit changelog
72 if publish:
73 cmds = [
74 "git push --tag -f",
75 # run test w/ coverage
76 "coverage run -m pytest --doctest-modules",
77 "coverage report",
78 # create html report for docs
79 "coverage html -d docs/assets/coverage",
80 "if [ -f docs/assets/coverage/.gitignore ]; then rm docs/assets/coverage/.gitignore; fi",
81 # not use `coverage.xml` to avoid ignore
82 "coverage xml -o docs/assets/coverage-report.xml",
83 # create coverage badge
84 "genbadge coverage -i docs/assets/coverage-report.xml -o docs/assets/coverage-badge.svg",
85 # update changelog
86 "auto-changelog",
87 '[ -x "$(command -v prettier)" ] && prettier -w CHANGELOG.md',
88 # commit docs and changelog Δ
89 'git add . && git cm -am "chore: update changelog, version pump" && git push',
90 # clear previous built assets
91 "rm -rf dist/*",
92 # build and publish to pypi
93 "poetry publish --build",
94 # update github release to the current tag
95 "gh release create $(git describe --tags --abbrev=0) --generate-notes ./dist/*",
96 ]
98 for cmd in cmds:
99 run(cmd)
102def upgrade_version(section: str, old_version: str) -> str:
103 """upgrade new version from old version
105 Tests:
106 >>> upgrade_version('major', '0.1.1')
107 '1.0.0'
109 >>> upgrade_version('minor', '0.1.1')
110 '0.2.0'
112 >>> upgrade_version('patch', '0.1.1')
113 '0.1.2'
114 """
115 ver_dict = {k: int(v) for k, v in zip(CHOICES, old_version.split("."))}
117 # pump version
118 ver_dict[section] += 1
120 # reset sub-version num
121 match section:
122 case "minor":
123 ver_dict["patch"] = 0
124 case "major":
125 ver_dict["patch"] = 0
126 ver_dict["minor"] = 0
128 new_version = reduce("{}.{}".format, ver_dict.values())
129 return new_version