-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpybump
executable file
·254 lines (198 loc) · 6.42 KB
/
pybump
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#!/usr/bin/env python3
# -*- coding: utf8 -*-
"""
A script to automatically update python modules on PyPI and via git.
See the README.md file for more information.
"""
# Built-in modules #
import os, sys, argparse
# First party modules #
from autopaths import Path
from plumbing.git import GitRepo
from plumbing.check_cmd_found import check_cmd
# Third party modules #
import sh
# Constants #
__version__ = '1.2.1'
# Create a shell parser #
parser = argparse.ArgumentParser(description=sys.modules[__name__].__doc__)
# Ask for the main argument #
help_msg = "The name (or filesystem path) of the module to process."
parser.add_argument("module", help=help_msg, type=str)
# Optional testing mode will switch to testpypi
parser.add_argument("--test", action='store_true')
# Optional infinite number mode
parser.add_argument("--infinite", action='store_true')
# Parse the shell arguments #
args = parser.parse_args()
path_or_name = args.module
test_mode = args.test
infinite_mode = args.infinite
# We can accept module names or filesystem paths #
if '/' in path_or_name:
base_dir = Path(path_or_name)
module_name = base_dir.name
else:
base_dir = Path("~/repos/%s/" % path_or_name)
module_name = path_or_name
# The python code directory #
code_dir = base_dir + module_name + '/'
# The repository #
repo = GitRepo(base_dir)
################################################################################
# At this point we should have following variables:
# repo -> /home/bob/repos/myproject/
# base_dir -> /home/bob/repos/myproject/
# code_dir -> /home/bob/repos/myproject/myproject/
# So let's confirm they exist #
base_dir.must_exist()
code_dir.must_exist()
# Change directory #
os.chdir(base_dir)
# Also we need to make sure that all executables are available #
check_cmd('gsed')
check_cmd('twine')
check_cmd('pdoc')
################################################################################
### Bump the version ###
# Add the module to the python path #
sys.path.insert(0, base_dir)
# The module itself must be importable #
module = __import__(module_name)
# Current version #
v_current = module.__version__
# Compute parts #
maj, mid, fix = map(int, v_current.rstrip('dev').split('.'))
# Functions #
def numbers_to_string(maj, mid, fix):
return '.'.join(map(str, (maj, mid, fix)))
def plus_one_to_version(maj, mid, fix):
maj_next = maj
mid_next = mid
fix_next = fix+1
# Jump to the next mid #
if not infinite_mode:
if fix_next > 9:
fix_next = 0
mid_next = mid+1
return maj_next, mid_next, fix_next
# Next version #
maj_next, mid_next, fix_next = plus_one_to_version(maj, mid, fix)
v_next = numbers_to_string(maj_next, mid_next, fix_next)
# Dev version #
maj_dev, mid_dev, fix_dev = plus_one_to_version(maj_next, mid_next, fix_next)
v_dev = numbers_to_string(maj_dev, mid_dev, fix_dev)
# Messages #
print("---------------------------")
print('-> Versions overview')
print('Current version: %s' % v_current)
print('Next version: %s' % v_next)
print('Dev version: %s' % v_dev)
# Function #
def run_gsed(base, find, repl, path):
find = find.replace('.', '\.')
sh.gsed('-i', base % (find, repl), path)
def replace_everywhere(vcrnt, vnext):
# Replace in __init__.py #
path = code_dir + '__init__.py'
base = "s/^%s/%s/g"
find = "__version__ = '%s'" % vcrnt
repl = "__version__ = '%s'" % vnext
run_gsed(base, find, repl, path)
# Replace in setup.py #
path = base_dir + 'setup.py'
base = "s/%s$/%s/g"
find = vcrnt + "',"
repl = vnext + "',"
run_gsed(base, find, repl, path)
# Replace in README #
path = base_dir + 'README.md'
base = "s/%s$/%s/g"
find = " version %s" % vcrnt
repl = " version %s" % vnext
run_gsed(base, find, repl, path)
# Messages #
print("---------------------------")
print("-> Replacing everywhere")
# Bump the version #
replace_everywhere(v_current, v_next)
# Add the files #
print("---------------------------")
print("-> Adding files to staging area")
repo.add(module_name + '/' + '__init__.py')
repo.add('setup.py')
repo.add('README.md')
################################################################################
### Regenerate the documentation with pdoc3 ###
# Launch command #
print("---------------------------")
print("-> Regenerating the documentation with pdoc3")
print(sh.pdoc('--output-dir', base_dir + 'docs', code_dir))
# Add the files #
print("---------------------------")
print("-> Adding documentation directory to staging area")
repo.add('docs/')
################################################################################
### Commit and push the tagged released version ###
# Messages #
print("---------------------------")
print("-> Committing")
# Commit #
message = 'Version %s' % v_next
print(repo.commit(message))
# Tag #
repo.tag_head(v_next)
print("---------------------------")
print("-> Pushing")
# Push #
print(repo.push(shell=True))
print(repo.push(tags=True, shell=True))
################################################################################
### Submit to PyPI ###
# Message #
print("--------------------------")
print("-> Building distribution")
# Build it #
print(sh.python3('-m', 'build'))
# Message #
print("--------------------------")
print("-> Uploading using twine")
# Upload it #
if test_mode:
# See https://packaging.python.org/guides/using-testpypi/
print(sh.twine('upload', '--repository', 'testpypi', 'dist/*.tar.gz'))
else:
print(sh.twine('upload', 'dist/*.tar.gz'))
# Message #
print("--------------------------")
print("-> Cleaning up")
# Clean up #
manifest_file = base_dir + 'MANIFEST'
dist_directory = base_dir + 'dist/'
build_directory = base_dir + 'build/'
egg_directory = base_dir + module_name + '.egg-info/'
# Remove files #
manifest_file.remove()
dist_directory.remove()
build_directory.remove()
egg_directory.remove()
################################################################################
### Bump the version again to development ###
# Messages #
print("---------------------------")
print("-> Replacing everywhere (dev)")
# Go to development version #
replace_everywhere(v_next, v_dev)
# Add the files #
repo.add(module_name + '/' + '__init__.py')
repo.add('setup.py')
repo.add('README.md')
# Commit #
#print(repo.commit('Back to development version.'))
# Messages #
#print("---------------------------")
#print("-> Pushing (dev)")
# Push #
#print(repo.push(shell=True))
# Done #
print("Success.")