-
Notifications
You must be signed in to change notification settings - Fork 48
/
release.py
149 lines (117 loc) · 5.13 KB
/
release.py
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
"""
===============================================================================
Create a release of "python-ebay". Upload files and metadata to PyPi.
===============================================================================
This script can be used to automate the release of new versions of the
"python-ebay" library, but it should also serve as documentation for the
somewhat complex release process.
The PyPi site for "python-ebay" is at:
https://pypi.python.org/pypi/python-ebay
Usage
======
The script has several options.
At the beginning of the release process you might want to run::
python release.py -s
This stores your PyPi user name and password in "~/.pypirc". This step is not
necessary to make releases, but is convenient if you need several attempts to
get the release right. If user name and password are not stored in in
"~/.pypirc" Python's upload machinery will ask for them.
To upload metadata and files to PyPi run::
python release.py -u
To clean up after a release, run::
python release.py -c
This option deletes the "~/.pypirc" file.
"""
import argparse
import getpass
import os
import os.path as path
import textwrap
import shutil
import subprocess
def relative(*path_fragments):
'Create a file path that is relative to the location of this file.'
return path.abspath(path.join(path.dirname(__file__), *path_fragments))
#Parse the command line arguments of the release script
parser = argparse.ArgumentParser(description=
'Upload a new version of "python-ebay" to PyPi.')
parser.add_argument('-s, --start', dest='start', action='store_true',
help='Start the release process. '
'Temporarily store password and user name for PyPi '
'in "~/.pypirc".')
parser.add_argument('-u, --upload', dest='upload', action='store_true',
help='Upload files and metadata to PyPi.')
parser.add_argument('-c, --cleanup', dest='cleanup', action='store_true',
help='Cleanup after the release. '
'Especially remove "~/.pypirc".')
args = parser.parse_args()
#Do some necessary computations and checks
homedir = path.expanduser("~")
pypirc_path = path.join(homedir, ".pypirc")
if path.exists(pypirc_path):
print ('"~/.pypirc" file exists. '
'Delete it with "release -c" when you are done.\n')
#Default action: display help message. ----------------------------------------
if not (args.start or args.upload or args.cleanup):
print "No action selected. You must select at least one action/option.\n"
parser.print_help()
exit(0)
#Start the release process ----------------------------------------------------
if args.start:
#Create a ".pypirc" file
print 'Store PyPi username and password temporarily in "~/.pypirc" file.'
username = raw_input("PyPi username:")
password = getpass.getpass('PyPi password:')
pypirc_text = textwrap.dedent(
"""
[distutils]
index-servers =
pypi
[pypi]
repository: http://www.python.org/pypi
username: {u}
password: {p}
""".format(u=username, p=password))
with open(pypirc_path, "w") as pypirc_file:
pypirc_file.write(pypirc_text)
#Remind of necessary actions, that are easily forgotten.
print '\n=============================================='
print "* Don't forget to increase the version."
print '* Please run the tests before uploading a release!'
print '============================================\n'
#TODO: In the future, if tests really work, run the test suite.
#Do the release ---------------------------------------------------------------
if args.upload:
#Backup "config.ini" because we need a working one for testing.
config_ini_path = relative("ebay/config.ini")
config_example_path = relative("ebay/config.ini.example")
if path.exists(config_ini_path):
#Test if "config.ini" is worth to be backed up
config_ini_text = open(config_ini_path).read()
config_example_text = open(config_example_path).read()
if config_ini_text != config_example_text:
#Backup the "config.ini" file
for i in range(1000):
config_bak_path = config_ini_path + ".{}.bak".format(i)
if not path.exists(config_bak_path):
break
shutil.copy(config_ini_path, config_bak_path)
#Delete "config.ini" because it may contain secrets.
#(However `python setup.py` will create a dummy "config.ini".)
try:
os.remove(config_ini_path)
except OSError:
pass
#Build source distribution, upload metadata, upload distribution(s)
subprocess.call(["python", "setup.py",
"sdist",
"register", "-r", "pypi",
"upload", "-r", "pypi",])
#Clean up from the release process. -------------------------------------------
if args.cleanup:
#Remove the ".pypirc" file.
if path.exists(pypirc_path):
print 'Removing "~/.pypirc".'
os.remove(pypirc_path)
else:
print 'Nothing to do.'