Coverage for gpaw/utilities/newrelease.py: 8%

167 statements  

« prev     ^ index     » next       coverage.py v7.7.1, created at 2025-07-20 00:19 +0000

1"""Generate new release of ASE. 

2 

3This script does not attempt to import ASE - then it would depend on 

4which ASE is installed and how - but assumes that it is run from the 

5ASE root directory.""" 

6 

7import subprocess 

8import re 

9import argparse 

10from time import strftime 

11 

12 

13def runcmd(cmd, output=False, error_ok=False): 

14 print('Executing:', cmd) 

15 try: 

16 if output: 

17 txt = subprocess.check_output(cmd, shell=True) 

18 return txt.decode('utf8') 

19 else: 

20 return subprocess.check_call(cmd, shell=True) 

21 except subprocess.CalledProcessError as err: 

22 if error_ok: 

23 print(f'Failed: {err}') 

24 print('Continuing...') 

25 else: 

26 raise 

27 

28 

29bash = runcmd 

30 

31 

32def py(cmd, output=False): 

33 return runcmd(f'python3 {cmd}') 

34 

35 

36def py2(cmd, output=False): 

37 return runcmd(f'python2 {cmd}') 

38 

39 

40def git(cmd, error_ok=False): 

41 cmd = f'git {cmd}' 

42 return runcmd(cmd, output=True, error_ok=error_ok) 

43 

44 

45versionfile = 'gpaw/__init__.py' 

46 

47 

48def get_version(): 

49 with open(versionfile) as fd: 

50 return re.search(r"__version__ = '(\S+)'", fd.read()).group(1) 

51 

52 

53def main(): 

54 p = argparse.ArgumentParser(description='Generate new release of GPAW.', 

55 epilog='Run from the root directory of GPAW.') 

56 p.add_argument('version', nargs='?', 

57 help='new version number') 

58 p.add_argument('--clean', action='store_true', 

59 help='delete release branch and tag') 

60 p.add_argument('--sign', action='store_true') 

61 p.add_argument('--wheel', action='store_true') 

62 args = p.parse_args() 

63 

64 try: 

65 current_version = get_version() 

66 except Exception as err: 

67 p.error('Cannot get version: {}. Are you in the root directory?' 

68 .format(err)) 

69 

70 print(f'Current version: {current_version}') 

71 

72 if not args.version: 

73 p.print_help() 

74 raise SystemExit 

75 

76 version = args.version 

77 

78 branchname = f'gpaw-{version}' 

79 current_version = get_version() 

80 

81 if args.clean: 

82 print(f'Cleaning {version}') 

83 git('checkout master') 

84 git(f'tag -d {version}', error_ok=True) 

85 git(f'branch -D {branchname}', error_ok=True) 

86 git('branch -D {}'.format('web-page'), error_ok=True) 

87 return 

88 

89 print(f'New release: {version}') 

90 

91 txt = git('status') 

92 branch = re.match(r'On branch (\S+)', txt).group(1) 

93 print(f'Currently on branch {repr(branch)}') 

94 if branch != 'master': 

95 git('checkout master') 

96 

97 git(f'checkout -b {branchname}') 

98 

99 majormiddle, minor = version.rsplit('.', 1) 

100 minor = int(minor) 

101 nextminor = minor + 1 

102 next_devel_version = f'{majormiddle}.{nextminor}b1' 

103 

104 def update_version(version): 

105 print(f'Editing {versionfile}: version {version}') 

106 new_versionline = f"__version__ = '{version}'\n" 

107 lines = [] 

108 ok = False 

109 with open(versionfile) as fd: 

110 for line in fd: 

111 if line.startswith('__version__'): 

112 ok = True 

113 line = new_versionline 

114 lines.append(line) 

115 assert ok 

116 with open(versionfile, 'w') as fd: 

117 for line in lines: 

118 fd.write(line) 

119 

120 update_version(version) 

121 

122 releasenotes = 'doc/releasenotes.rst' 

123 lines = [] 

124 

125 searchtxt = re.escape("""\ 

126Git master branch 

127================= 

128 

129:git:`master <>`. 

130""") 

131 

132 replacetxt = """\ 

133Git master branch 

134================= 

135 

136:git:`master <>`. 

137 

138* No changes yet 

139 

140 

141{header} 

142{underline} 

143 

144{date}: :git:`{version} <../{version}>` 

145""" 

146 

147 date = strftime('%d %B %Y').lstrip('0') 

148 header = f'Version {version}' 

149 underline = '=' * len(header) 

150 replacetxt = replacetxt.format(header=header, version=version, 

151 underline=underline, date=date) 

152 

153 print(f'Editing {releasenotes}') 

154 with open(releasenotes) as fd: 

155 txt = fd.read() 

156 txt, n = re.subn(searchtxt, replacetxt, txt, re.MULTILINE) 

157 assert n == 1 

158 

159 with open(releasenotes, 'w') as fd: 

160 fd.write(txt) 

161 

162 searchtxt = """\ 

163News 

164==== 

165""" 

166 

167 replacetxt = """\ 

168News 

169==== 

170 

171* :ref:`GPAW version {version} <releasenotes>` released ({date}). 

172""" 

173 

174 replacetxt = replacetxt.format(version=version, date=date) 

175 

176 frontpage = 'doc/index.rst' 

177 lines = [] 

178 print(f'Editing {frontpage}') 

179 with open(frontpage) as fd: 

180 txt = fd.read() 

181 txt, n = re.subn(searchtxt, replacetxt, txt) 

182 assert n == 1 

183 with open(frontpage, 'w') as fd: 

184 fd.write(txt) 

185 

186 installdoc = 'doc/install.rst' 

187 print(f'Editing {installdoc}') 

188 

189 with open(installdoc) as fd: 

190 txt = fd.read() 

191 

192 txt, nsub = re.subn(r'gpaw-\d+\.\d+.\d+', 

193 f'gpaw-{version}', txt) 

194 assert nsub > 0 

195 txt, nsub = re.subn(r'git clone -b \d+\.\d+.\d+', 

196 f'git clone -b {version}', txt) 

197 assert nsub == 1 

198 

199 with open(installdoc, 'w') as fd: 

200 fd.write(txt) 

201 

202 sphinxconf = 'doc/conf.py' 

203 print(f'Editing {sphinxconf}') 

204 comment = '# This line auto-edited by newrelease script' 

205 line1 = f"dev_version = '{next_devel_version}' {comment}\n" 

206 line2 = f"stable_version = '{version}' {comment}\n" 

207 lines = [] 

208 with open(sphinxconf) as fd: 

209 for line in fd: 

210 if re.match('dev_version = ', line): 

211 line = line1 

212 if re.match('stable_version = ', line): 

213 line = line2 

214 lines.append(line) 

215 with open(sphinxconf, 'w') as fd: 

216 fd.write(''.join(lines)) 

217 

218 git('add {}'.format(' '.join([versionfile, sphinxconf, installdoc, 

219 frontpage, releasenotes]))) 

220 git(f'commit -m "GPAW version {version}"') 

221 git('tag {0} {1} -m "gpaw-{1}"' 

222 .format('-s' if args.sign else '', 

223 version)) 

224 

225 py('setup.py sdist > setup_sdist.log') 

226 if args.wheel: 

227 py2('setup.py bdist_wheel > setup_bdist_wheel2.log') 

228 py('setup.py bdist_wheel > setup_bdist_wheel3.log') 

229 if args.sign: 

230 bash('gpg --armor --yes --detach-sign dist/gpaw-{}.tar.gz' 

231 .format(version)) 

232 git('checkout -b web-page') 

233 git('branch --set-upstream-to=origin/web-page') 

234 git(f'checkout {branchname}') 

235 update_version(next_devel_version) 

236 git(f'add {versionfile}') 

237 git('branch --set-upstream-to=master') 

238 git(f'commit -m "bump version number to {next_devel_version}"') 

239 

240 print() 

241 print('Automatic steps done.') 

242 print() 

243 print('Now is a good time to:') 

244 print(' * check the diff') 

245 print(' * run the tests') 

246 print(' * verify the web-page build') 

247 print() 

248 print('Remaining steps') 

249 print('===============') 

250 print(f'git show {version} # Inspect!') 

251 print('git checkout master') 

252 print(f'git merge {branchname}') 

253 print('twine upload ' 

254 'dist/gpaw-{v}.tar.gz ' 

255 'dist/gpaw-{v}-py2-none-any.whl ' 

256 'dist/gpaw-{v}-py3-none-any.whl ' 

257 'dist/gpaw-{v}.tar.gz.asc'.format(v=version)) 

258 print('git push --tags origin master # Assuming your remote is "origin"') 

259 print('git checkout web-page') 

260 print('git push --force origin web-page') 

261 

262 

263if __name__ == '__main__': 

264 main()