]>
git.agnieray.net Git - galette.git/blob - bin/release
3 import os
, sys
, argparse
, re
, git
, http
.client
, subprocess
4 import urlgrabber
.progress
, tarfile
, shutil
, gitdb
, time
, fnmatch
5 from datetime
import datetime
6 from termcolor
import colored
7 from urllib
.parse
import urlparse
9 galette_dl_repo
= 'http://download.tuxfamily.org/galette/'
10 local_dl_repo
= os
.path
.join(
12 os
.path
.dirname(os
.path
.abspath(__file__
))
25 nightly_version
= None
29 Display colored error message
31 print(colored(msg
, 'red', attrs
=['bold']))
33 def get_numeric_version(ver
):
35 Returns all numeric version
37 return re
.findall(r
'\d+', ver
)
39 def valid_version(ver
):
41 Check if provided version is valid.
43 Takes all digits in passed version, then reassemble them with dots
44 to check if it is the same as original given one.
46 return '.'.join(get_numeric_version(ver
)) == ver
48 def incr_version(ver
):
50 Increment version number
52 version
= get_numeric_version(ver
)
53 version
[-1] = str(int(version
[-1]) + 1)
56 def propose_version():
58 Propose new minor and major versions,
59 according to existing git tags
64 for tagref
in tagrefs
:
66 if valid_version(tag
.tag
):
67 #last minor version is always the last one :)
68 if tag
.tag
> last_minor
:
72 if len(tag
.tag
) == 5 and tag
.tag
> last_major
:
76 print('last minor: %s | last major %s' % (last_minor
, last_major
))
78 #no version provided. propose one
82 if len(last_minor
) == 5:
83 #if the latest is a major version
84 new_minor
= last_minor
+ ('.1')
86 new_minor
= '.'.join(incr_version(last_minor
))
88 new_major
= '.'.join(incr_version(last_major
))
90 print("""Proposed versions:
93 """ % (new_minor
, new_major
))
95 def get_latest_version():
97 Look for latest version
100 for tagref
in tagrefs
:
102 if tag
!= None and valid_version(tag
.tag
):
103 #last minor version is always the last one :)
104 if last
== None or tag
.tag
> last
:
109 def is_existing_version(ver
):
111 Look specified version exists
113 for tagref
in tagrefs
:
115 if valid_version(tag
.tag
):
120 def ask_user_confirm(msg
):
122 Ask user his confirmation
128 sys
.stdout
.write(msg
)
129 choice
= input().lower()
130 if choice
== 'y' or choice
== 'yes':
132 elif choice
== 'n' or choice
== 'no':
136 "Invalid input. Please enter 'yes' or 'no' (or 'y' or 'n')."
139 def get_rel_name(buildver
):
141 Build archive name from command line parameters
142 That would be used for git archiving prefix and archive name
148 archive_name
= 'galette-%s-%s-%s-%s' % (
151 now
.strftime('%Y%m%d'),
155 archive_name
= 'galette-dev'
157 archive_name
= 'galette-%s' % buildver
167 rel_name
= get_rel_name(ver
)
168 archive_name
= rel_name
+ '.tar.bz2'
169 galette_archive
= os
.path
.join(
175 #first check if a version
179 url
= galette_dl_repo
+ '/' + archive_name
180 urlasc
= '%s.asc' % url
181 parsed
= urlparse(url
)
182 ascparsed
= urlparse(urlasc
)
184 connection
= http
.client
.HTTPConnection(parsed
[1], 80)
185 connection
.request('HEAD', parsed
[2])
186 response
= connection
.getresponse()
187 exists
= response
.status
== 200
190 #also check from local repo
191 exists
= os
.path
.exists(galette_archive
)
195 connection
= http
.client
.HTTPConnection(ascparsed
[1], 80)
196 connection
.request('HEAD', ascparsed
[2])
197 response
= connection
.getresponse()
198 ascexists
= response
.status
== 200
201 #also check from local repo
202 ascexists
= os
.path
.exists(
205 archive_name
+ '.asc'
211 if exists
or ascexists
:
217 msg
= 'Relase %s already %sexists' % (rel_name
, loctxt
)
224 msg
+= ' and has been %ssigned!' % loctxt
226 msg
+= 'Release has been %ssigned!' % loctxt
228 msg
+= '\n\nYou will *NOT* build another one :)'
231 print('Building %s...' % rel_name
)
233 archive_cmd_pattern
= 'git archive --prefix=%s/ %s | bzip2 > %s'
234 if commit
and extra
or nightly
:
235 archive_cmd
= archive_cmd_pattern
% (
241 archive_cmd
= archive_cmd_pattern
% (
255 print('Release name: %s, %s: %s, Dest: %s' % (
261 print('Archive command: %s' % (archive_cmd
))
264 print('Archiving GIT commit %s' % commit
)
266 print('Archiving GIT tag %s' % ver
)
268 p1
= subprocess
.Popen(archive_cmd
, shell
=True)
271 print('Adding vendor libraries')
272 add_libs(rel_name
, galette_archive
)
275 do_sign(galette_archive
)
277 upload
= ask_user_confirm(
278 'Do you want to upload archive %s? [yes/No] ' % galette_archive
282 do_scp(galette_archive
)
284 def do_sign(archive
):
285 sign_cmd
= 'gpg --detach-sign --armor %s' % archive
286 p1
= subprocess
.Popen(sign_cmd
, shell
=True)
292 path
= 'galette/galette-repository/'
297 scp_cmd
= 'scp -i %s %s* ssh.tuxfamily.org:%s' % (ssh_key
, archive
, path
)
299 scp_cmd
= 'scp -r %s* ssh.tuxfamily.org:%s' % (archive
, path
)
301 p1
= subprocess
.Popen(scp_cmd
, shell
=True)
304 def add_libs(rel_name
, galette_archive
):
306 Add external libraries to the archive
307 Also write version for GALETTE_NIGHTLY value
309 galette
= tarfile
.open(galette_archive
, 'r|bz2', format
=tarfile
.GNU_FORMAT
)
310 src_dir
= os
.path
.join(local_dl_repo
, 'src')
311 if not os
.path
.exists(src_dir
):
313 galette
.extractall(path
=src_dir
)
316 #set galette nightly version
317 config_dir
= os
.path
.join(src_dir
, rel_name
, 'galette', 'config')
318 if nightly_version
!= None:
319 sed_cmd
= 'sed -e "s/GALETTE_NIGHTLY\', false/GALETTE_NIGHTLY\', \'%s\'/" -i versions.inc.php' % nightly_version
321 p1
= subprocess
.Popen(sed_cmd
, shell
=True, cwd
=config_dir
)
325 npm_dir
= os
.path
.join(src_dir
, rel_name
)
326 npm_cmd
= 'npm install --prefix %s' % npm_dir
328 p1
= subprocess
.Popen(npm_cmd
, shell
=True, cwd
=npm_dir
)
332 wp_cmd
= 'npm run first-build'
333 p1
= subprocess
.Popen(wp_cmd
, shell
=True, cwd
=npm_dir
)
336 #node modules are no longer needed
337 shutil
.rmtree(os
.path
.join(npm_dir
, 'node_modules'))
339 #UI sources and some built assets are no longer needed
340 shutil
.rmtree(os
.path
.join(npm_dir
, 'semantic'))
341 shutil
.rmtree(os
.path
.join(npm_dir
, 'ui'))
342 shutil
.rmtree(os
.path
.join(src_dir
, rel_name
, 'galette/webroot/themes/default/ui/components'))
343 shutil
.rmtree(os
.path
.join(src_dir
, rel_name
, 'galette/webroot/themes/default/ui/themes/basic'))
344 shutil
.rmtree(os
.path
.join(src_dir
, rel_name
, 'galette/webroot/themes/default/ui/themes/github'))
345 shutil
.rmtree(os
.path
.join(src_dir
, rel_name
, 'galette/webroot/themes/default/ui/themes/material'))
346 os
.remove(os
.path
.join(src_dir
, rel_name
, 'galette/webroot/themes/default/ui/semantic.js'))
347 os
.remove(os
.path
.join(src_dir
, rel_name
, 'galette/webroot/themes/default/ui/semantic.css'))
348 os
.remove(os
.path
.join(src_dir
, rel_name
, 'galette/webroot/themes/default/ui/semantic.rtl.css'))
350 #install php dependencies
351 composer_cmd
= 'composer install --ignore-platform-reqs --no-dev'
352 composer_dir
= os
.path
.join(src_dir
, rel_name
, 'galette')
354 p1
= subprocess
.Popen(composer_cmd
, shell
=True, cwd
=composer_dir
)
357 #cleaunp files not required in releases
366 '.composer-require-checker.config.json',
368 os
.path
.join('galette', 'composer.json'),
369 os
.path
.join('galette', 'composer.lock'),
370 os
.path
.join('galette', 'post_contribution_test.php')
373 if os
.path
.exists(os
.path
.join(src_dir
, rel_name
, td
)):
374 os
.remove(os
.path
.join(src_dir
, rel_name
, td
))
376 if os
.path
.exists(os
.path
.join(src_dir
, rel_name
, 'patches')):
377 shutil
.rmtree(os
.path
.join(src_dir
, rel_name
, 'patches'))
379 if os
.path
.exists(os
.path
.join(src_dir
, rel_name
, 'tests')):
380 shutil
.rmtree(os
.path
.join(src_dir
, rel_name
, 'tests'))
382 if os
.path
.exists(os
.path
.join(src_dir
, rel_name
, '.github')):
383 shutil
.rmtree(os
.path
.join(src_dir
, rel_name
, '.github'))
386 for root
, dirnames
, filenames
in os
.walk(os
.path
.join(composer_dir
, 'vendor')):
387 #remove git directories
388 for dirname
in fnmatch
.filter(dirnames
, '.git*'):
389 remove_dir
= os
.path
.join(composer_dir
, root
, dirname
)
390 shutil
.rmtree(remove_dir
)
391 #remove test directories
392 for dirname
in fnmatch
.filter(dirnames
, 'test?'):
393 remove_dir
= os
.path
.join(composer_dir
, root
, dirname
)
394 shutil
.rmtree(remove_dir
)
395 #remove examples directories
396 for dirname
in fnmatch
.filter(dirnames
, 'example?'):
397 remove_dir
= os
.path
.join(composer_dir
, root
, dirname
)
398 shutil
.rmtree(remove_dir
)
399 #remove doc directories
400 for dirname
in fnmatch
.filter(dirnames
, 'doc?'):
401 remove_dir
= os
.path
.join(composer_dir
, root
, dirname
)
402 shutil
.rmtree(remove_dir
)
403 #remove composer stuff
404 for filename
in fnmatch
.filter(filenames
, 'composer*'):
405 remove_file
= os
.path
.join(composer_dir
, root
, filename
)
406 os
.remove(remove_file
)
408 for dirname
in dirnames
:
409 #remove Faker useless languages
410 if root
.endswith('src/Faker/Provider'):
411 if dirname
not in ['en_US', 'fr_FR', 'de_DE']:
412 shutil
.rmtree(os
.path
.join(root
, dirname
))
413 #begin to remove tcpdf not used fonts
414 if root
.endswith('tcpdf/fonts'):
415 if dirname
!= 'dejavu-fonts-ttf-2.34':
416 shutil
.rmtree(os
.path
.join(root
, dirname
))
417 if root
.endswith('vendor'):
419 shutil
.rmtree(os
.path
.join(root
, dirname
))
421 for filename
in filenames
:
422 if os
.path
.islink(os
.path
.join(root
, filename
)):
423 os
.remove(os
.path
.join(root
, filename
))
424 #remove tcpdf not used fonts
425 if root
.endswith('tcpdf/fonts'):
427 'dejavusansbi.ctg.z',
442 os
.remove(os
.path
.join(root
, filename
))
444 galette
= tarfile
.open(galette_archive
, 'w|bz2', format
=tarfile
.GNU_FORMAT
)
446 for i
in os
.listdir(src_dir
):
448 os
.path
.join(src_dir
, i
),
453 shutil
.rmtree(src_dir
)
455 def valid_commit(repo
, c
):
457 Validate commit existance in repository
458 Also prepare version for GALETTE_NIGHTLY value
460 global commit
, nightly_version
463 dformat
= '%a, %d %b %Y %H:%M'
464 repo_commit
= repo
.commit(c
)
466 commit
= repo_commit
.hexsha
[:10]
468 nightly_version
= '%s (%s)' % (
470 time
.strftime('%Y-%m-%d %H:%M:%S GMT%z', time
.localtime(repo_commit
.committed_date
)),
473 print(colored("""Commit information:
482 time
.strftime(dformat
, time
.gmtime(repo_commit
.authored_date
)),
483 repo_commit
.committer
,
484 time
.strftime(dformat
, time
.gmtime(repo_commit
.committed_date
)),
486 ), None, 'on_grey', attrs
=['bold']))
488 except gitdb
.exc
.BadObject
:
495 global verbose
, tagrefs
, force
, extra
, assume_yes
, nightly
, sign
, ssh_key
497 parser
= argparse
.ArgumentParser(description
='Release Galette')
498 group
= parser
.add_mutually_exclusive_group()
502 help='Version to release'
507 help='Calculate and propose next possible versions',
513 help='Specify commit to archive (-v required)'
518 help='Extra version information (-c required)'
523 help='Assume YES to all questions. Be sure to understand what you are doing!',
529 help='Be more verbose',
535 help='Build nightly',
541 help='SSH key to be used for uploading',
543 parser
.add_argument('-f', action
='store_true')
544 args
= parser
.parse_args()
551 galette_repo
= os
.path
.dirname(os
.path
.dirname(os
.path
.abspath(__file__
)))
552 repo
= git
.Repo(galette_repo
)
556 force
= ask_user_confirm(
557 'Are you *REALLY* sure you mean -f when you typed -f? [yes/No] '
559 assume_yes
=args
.assume_yes
562 ssh_key
= args
.ssh_key
569 args
.commit
= repo
.commit('develop')
570 if valid_commit(repo
, args
.commit
):
576 print_err('Invalid commit ref %s' % args
.commit
)
577 elif (args
.extra
or args
.commit
) and (not args
.extra
or not args
.commit
or not args
.version
):
578 print_err('You have to specify --version --commit and --extra all together')
580 elif args
.commit
and args
.version
and args
.extra
:
581 if valid_commit(repo
, args
.commit
):
583 print('Commit is valid')
585 buildver
= args
.version
588 print_err('Invalid commit ref %s' % args
.commit
)
590 if not valid_version(args
.version
):
591 print_err('%s is not a valid version number!' % args
.version
)
594 #check if specified version exists
595 if not is_existing_version(args
.version
):
596 print_err('%s does not exist!' % args
.version
)
599 buildver
= args
.version
603 buildver
= get_latest_version()
607 build
= ask_user_confirm(
608 'Do you want to build Galette version %s? [Yes/no] ' % buildver
614 if __name__
== "__main__":