Coverage for pump.py: 55%

42 statements  

« prev     ^ index     » next       coverage.py v7.1.0, created at 2023-02-19 17:08 +0800

1"""Version Pump Automation 

2 

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 

9 

10Examples: 

11 - dry run 

12 ./pump.py patch 

13 

14 - update pyproject.toml and local git tag 

15 ./pump.py patch --tag 

16 

17 - update everything and publish new version 

18 ./pump.py patch --tag --publish 

19""" 

20 

21import toml 

22from click import argument, Choice, option, command, secho 

23from subprocess import getstatusoutput 

24from functools import reduce 

25 

26CHOICES = ["major", "minor", "patch"] 

27 

28 

29# === uti === 

30def abort(msg: str = "") -> None: 

31 secho(msg or "Aborted.", fg="red") 

32 exit(1) 

33 

34 

35def run(cmd: str) -> None: 

36 """run shell command""" 

37 secho(cmd) 

38 if getstatusoutput(cmd)[0]: 

39 abort() 

40 

41 

42# === main === 

43 

44 

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""" 

55 

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 

61 

62 print(old_version, "->", new_version) 

63 

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}") 

68 

69 run(f"git tag {new_version}") 

70 

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 ] 

97 

98 for cmd in cmds: 

99 run(cmd) 

100 

101 

102def upgrade_version(section: str, old_version: str) -> str: 

103 """upgrade new version from old version 

104 

105 Tests: 

106 >>> upgrade_version('major', '0.1.1') 

107 '1.0.0' 

108 

109 >>> upgrade_version('minor', '0.1.1') 

110 '0.2.0' 

111 

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("."))} 

116 

117 # pump version 

118 ver_dict[section] += 1 

119 

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 

127 

128 new_version = reduce("{}.{}".format, ver_dict.values()) 

129 return new_version