2011-09-13 12:20:23 -04:00
|
|
|
# Licensed to the Apache Software Foundation (ASF) under one or more
|
|
|
|
# contributor license agreements. See the NOTICE file distributed with
|
|
|
|
# this work for additional information regarding copyright ownership.
|
|
|
|
# The ASF licenses this file to You under the Apache License, Version 2.0
|
|
|
|
# (the "License"); you may not use this file except in compliance with
|
|
|
|
# the License. You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
2014-08-28 04:01:50 -04:00
|
|
|
import argparse
|
2011-09-13 12:20:23 -04:00
|
|
|
import datetime
|
|
|
|
import re
|
2013-04-17 15:35:47 -04:00
|
|
|
import time
|
2011-09-13 12:20:23 -04:00
|
|
|
import shutil
|
|
|
|
import os
|
|
|
|
import sys
|
2013-04-17 15:35:47 -04:00
|
|
|
import subprocess
|
2014-08-28 04:01:50 -04:00
|
|
|
import textwrap
|
2011-09-13 12:20:23 -04:00
|
|
|
|
|
|
|
LOG = '/tmp/release.log'
|
|
|
|
|
|
|
|
def log(msg):
|
2013-01-16 16:18:41 -05:00
|
|
|
f = open(LOG, mode='ab')
|
|
|
|
f.write(msg.encode('utf-8'))
|
2011-09-13 12:20:23 -04:00
|
|
|
f.close()
|
|
|
|
|
|
|
|
def run(command):
|
|
|
|
log('\n\n%s: RUN: %s\n' % (datetime.datetime.now(), command))
|
|
|
|
if os.system('%s >> %s 2>&1' % (command, LOG)):
|
|
|
|
msg = ' FAILED: %s [see log %s]' % (command, LOG)
|
2013-01-16 16:18:41 -05:00
|
|
|
print(msg)
|
2011-09-13 12:20:23 -04:00
|
|
|
raise RuntimeError(msg)
|
|
|
|
|
2013-04-17 15:35:47 -04:00
|
|
|
def runAndSendGPGPassword(command, password):
|
2013-06-08 13:00:25 -04:00
|
|
|
p = subprocess.Popen(command, shell=True, bufsize=0, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
|
2013-04-17 15:35:47 -04:00
|
|
|
f = open(LOG, 'ab')
|
|
|
|
while True:
|
2013-06-09 02:27:46 -04:00
|
|
|
p.stdout.flush()
|
2013-04-17 15:35:47 -04:00
|
|
|
line = p.stdout.readline()
|
|
|
|
if len(line) == 0:
|
|
|
|
break
|
|
|
|
f.write(line)
|
|
|
|
if line.find(b'Enter GPG keystore password:') != -1:
|
|
|
|
time.sleep(1.0)
|
|
|
|
p.stdin.write((password + '\n').encode('UTF-8'))
|
|
|
|
p.stdin.write('\n'.encode('UTF-8'))
|
|
|
|
|
|
|
|
result = p.poll()
|
|
|
|
if result != 0:
|
|
|
|
msg = ' FAILED: %s [see log %s]' % (command, LOG)
|
|
|
|
print(msg)
|
|
|
|
raise RuntimeError(msg)
|
|
|
|
|
2016-02-11 09:52:48 -05:00
|
|
|
def getGitRev():
|
|
|
|
status = os.popen('git status').read().strip()
|
2016-02-11 09:59:13 -05:00
|
|
|
if 'nothing to commit, working directory clean' not in status:
|
|
|
|
raise RuntimeError('git clone is dirty:\n\n%s' % status)
|
2016-02-11 10:07:05 -05:00
|
|
|
|
|
|
|
# TODO: we should also detect unpushed changes here? Something like "git cherry -v origin/branch_5_5"?
|
|
|
|
print(' git clone is clean')
|
2016-02-11 09:52:48 -05:00
|
|
|
return os.popen('git rev-parse HEAD').read().strip()
|
2011-09-13 12:20:23 -04:00
|
|
|
|
2014-08-30 11:48:16 -04:00
|
|
|
def prepare(root, version, gpgKeyID, gpgPassword):
|
2013-01-16 16:18:41 -05:00
|
|
|
print()
|
|
|
|
print('Prepare release...')
|
2011-09-13 12:20:23 -04:00
|
|
|
if os.path.exists(LOG):
|
|
|
|
os.remove(LOG)
|
|
|
|
|
|
|
|
os.chdir(root)
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' svn up...')
|
2011-09-13 12:20:23 -04:00
|
|
|
run('svn up')
|
|
|
|
|
2016-02-11 09:52:48 -05:00
|
|
|
rev = getGitRev()
|
|
|
|
print(' git rev: %s' % rev)
|
|
|
|
log('\nGIT rev: %s\n' % rev)
|
2011-09-13 12:20:23 -04:00
|
|
|
|
2014-08-30 11:48:16 -04:00
|
|
|
print(' ant clean test')
|
|
|
|
run('ant clean test')
|
2011-09-13 12:20:23 -04:00
|
|
|
|
2013-01-16 16:18:41 -05:00
|
|
|
open('rev.txt', mode='wb').write(rev.encode('UTF-8'))
|
2011-09-13 12:20:23 -04:00
|
|
|
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' lucene prepare-release')
|
2011-09-13 12:20:23 -04:00
|
|
|
os.chdir('lucene')
|
2013-07-22 15:34:43 -04:00
|
|
|
cmd = 'ant -Dversion=%s' % version
|
2012-04-08 14:22:14 -04:00
|
|
|
if gpgKeyID is not None:
|
|
|
|
cmd += ' -Dgpg.key=%s prepare-release' % gpgKeyID
|
|
|
|
else:
|
|
|
|
cmd += ' prepare-release-no-sign'
|
2013-04-17 15:35:47 -04:00
|
|
|
|
|
|
|
if gpgPassword is not None:
|
|
|
|
runAndSendGPGPassword(cmd, gpgPassword)
|
|
|
|
else:
|
|
|
|
run(cmd)
|
2012-04-08 14:22:14 -04:00
|
|
|
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' solr prepare-release')
|
2011-09-13 12:20:23 -04:00
|
|
|
os.chdir('../solr')
|
2013-07-22 15:34:43 -04:00
|
|
|
cmd = 'ant -Dversion=%s' % version
|
2012-04-08 14:22:14 -04:00
|
|
|
if gpgKeyID is not None:
|
|
|
|
cmd += ' -Dgpg.key=%s prepare-release' % gpgKeyID
|
|
|
|
else:
|
|
|
|
cmd += ' prepare-release-no-sign'
|
2013-04-17 15:35:47 -04:00
|
|
|
|
|
|
|
if gpgPassword is not None:
|
|
|
|
runAndSendGPGPassword(cmd, gpgPassword)
|
|
|
|
else:
|
|
|
|
run(cmd)
|
|
|
|
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' done!')
|
|
|
|
print()
|
2011-09-13 12:20:23 -04:00
|
|
|
return rev
|
|
|
|
|
|
|
|
def push(version, root, rev, rcNum, username):
|
2013-01-16 16:18:41 -05:00
|
|
|
print('Push...')
|
2011-09-13 12:20:23 -04:00
|
|
|
dir = 'lucene-solr-%s-RC%d-rev%s' % (version, rcNum, rev)
|
2013-04-17 07:19:25 -04:00
|
|
|
s = os.popen('ssh %s@people.apache.org "ls -ld public_html/staging_area/%s" 2>&1' % (username, dir)).read()
|
2013-01-16 16:18:41 -05:00
|
|
|
if 'no such file or directory' not in s.lower():
|
|
|
|
print(' Remove old dir...')
|
2011-09-13 12:20:23 -04:00
|
|
|
run('ssh %s@people.apache.org "chmod -R u+rwX public_html/staging_area/%s; rm -rf public_html/staging_area/%s"' %
|
|
|
|
(username, dir, dir))
|
|
|
|
run('ssh %s@people.apache.org "mkdir -p public_html/staging_area/%s/lucene public_html/staging_area/%s/solr"' % \
|
|
|
|
(username, dir, dir))
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' Lucene')
|
2011-09-13 12:20:23 -04:00
|
|
|
os.chdir('%s/lucene/dist' % root)
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' zip...')
|
2011-09-13 12:20:23 -04:00
|
|
|
if os.path.exists('lucene.tar.bz2'):
|
|
|
|
os.remove('lucene.tar.bz2')
|
|
|
|
run('tar cjf lucene.tar.bz2 *')
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' copy...')
|
2011-09-13 12:20:23 -04:00
|
|
|
run('scp lucene.tar.bz2 %s@people.apache.org:public_html/staging_area/%s/lucene' % (username, dir))
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' unzip...')
|
2011-09-13 12:20:23 -04:00
|
|
|
run('ssh %s@people.apache.org "cd public_html/staging_area/%s/lucene; tar xjf lucene.tar.bz2; rm -f lucene.tar.bz2"' % (username, dir))
|
|
|
|
os.remove('lucene.tar.bz2')
|
|
|
|
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' Solr')
|
2011-09-13 12:20:23 -04:00
|
|
|
os.chdir('%s/solr/package' % root)
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' zip...')
|
2011-09-13 12:20:23 -04:00
|
|
|
if os.path.exists('solr.tar.bz2'):
|
|
|
|
os.remove('solr.tar.bz2')
|
|
|
|
run('tar cjf solr.tar.bz2 *')
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' copy...')
|
2011-09-13 12:20:23 -04:00
|
|
|
run('scp solr.tar.bz2 %s@people.apache.org:public_html/staging_area/%s/solr' % (username, dir))
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' unzip...')
|
2011-09-13 12:20:23 -04:00
|
|
|
run('ssh %s@people.apache.org "cd public_html/staging_area/%s/solr; tar xjf solr.tar.bz2; rm -f solr.tar.bz2"' % (username, dir))
|
|
|
|
os.remove('solr.tar.bz2')
|
|
|
|
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' chmod...')
|
2011-09-13 12:20:23 -04:00
|
|
|
run('ssh %s@people.apache.org "chmod -R a+rX-w public_html/staging_area/%s"' % (username, dir))
|
|
|
|
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' done!')
|
2014-04-22 08:19:37 -04:00
|
|
|
url = 'http://people.apache.org/~%s/staging_area/%s' % (username, dir)
|
2012-04-08 14:22:14 -04:00
|
|
|
return url
|
|
|
|
|
|
|
|
def pushLocal(version, root, rev, rcNum, localDir):
|
2013-01-16 16:18:41 -05:00
|
|
|
print('Push local [%s]...' % localDir)
|
2012-04-08 14:22:14 -04:00
|
|
|
os.makedirs(localDir)
|
|
|
|
|
|
|
|
dir = 'lucene-solr-%s-RC%d-rev%s' % (version, rcNum, rev)
|
|
|
|
os.makedirs('%s/%s/lucene' % (localDir, dir))
|
|
|
|
os.makedirs('%s/%s/solr' % (localDir, dir))
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' Lucene')
|
2012-04-08 14:22:14 -04:00
|
|
|
os.chdir('%s/lucene/dist' % root)
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' zip...')
|
2012-04-08 14:22:14 -04:00
|
|
|
if os.path.exists('lucene.tar.bz2'):
|
|
|
|
os.remove('lucene.tar.bz2')
|
|
|
|
run('tar cjf lucene.tar.bz2 *')
|
|
|
|
|
|
|
|
os.chdir('%s/%s/lucene' % (localDir, dir))
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' unzip...')
|
2012-04-08 14:22:14 -04:00
|
|
|
run('tar xjf "%s/lucene/dist/lucene.tar.bz2"' % root)
|
|
|
|
os.remove('%s/lucene/dist/lucene.tar.bz2' % root)
|
2011-09-13 12:20:23 -04:00
|
|
|
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' Solr')
|
2012-04-08 14:22:14 -04:00
|
|
|
os.chdir('%s/solr/package' % root)
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' zip...')
|
2012-04-08 14:22:14 -04:00
|
|
|
if os.path.exists('solr.tar.bz2'):
|
|
|
|
os.remove('solr.tar.bz2')
|
|
|
|
run('tar cjf solr.tar.bz2 *')
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' unzip...')
|
2012-04-08 14:22:14 -04:00
|
|
|
os.chdir('%s/%s/solr' % (localDir, dir))
|
|
|
|
run('tar xjf "%s/solr/package/solr.tar.bz2"' % root)
|
|
|
|
os.remove('%s/solr/package/solr.tar.bz2' % root)
|
|
|
|
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' KEYS')
|
2012-04-08 14:22:14 -04:00
|
|
|
run('wget http://people.apache.org/keys/group/lucene.asc')
|
|
|
|
os.rename('lucene.asc', 'KEYS')
|
|
|
|
run('chmod a+r-w KEYS')
|
|
|
|
run('cp KEYS ../lucene')
|
|
|
|
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' chmod...')
|
2012-04-08 14:22:14 -04:00
|
|
|
os.chdir('..')
|
|
|
|
run('chmod -R a+rX-w .')
|
|
|
|
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' done!')
|
2012-04-08 14:22:14 -04:00
|
|
|
return 'file://%s/%s' % (os.path.abspath(localDir), dir)
|
2013-01-16 16:18:41 -05:00
|
|
|
|
2014-08-28 04:01:50 -04:00
|
|
|
def read_version(path):
|
|
|
|
version_props_file = os.path.join(path, 'lucene', 'version.properties')
|
|
|
|
return re.search(r'version\.base=(.*)', open(version_props_file).read()).group(1)
|
|
|
|
|
|
|
|
def parse_config():
|
|
|
|
epilogue = textwrap.dedent('''
|
|
|
|
Example usage for a Release Manager:
|
2016-02-11 10:08:29 -05:00
|
|
|
python3.2 -u buildAndPushRelease.py --push-remote mikemccand --sign 6E68DA61 --rc-num 1 /path/to/lucene_solr_4_7
|
2014-08-28 04:01:50 -04:00
|
|
|
''')
|
|
|
|
description = 'Utility to build, push, and test a release.'
|
|
|
|
parser = argparse.ArgumentParser(description=description, epilog=epilogue,
|
|
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
|
|
parser.add_argument('--no-prepare', dest='prepare', default=True, action='store_false',
|
|
|
|
help='Use the already built release in the provided checkout')
|
|
|
|
parser.add_argument('--push-remote', metavar='USERNAME',
|
|
|
|
help='Push the release to people.apache.org for the given user')
|
|
|
|
parser.add_argument('--push-local', metavar='PATH',
|
|
|
|
help='Push the release to the local path')
|
|
|
|
parser.add_argument('--sign', metavar='KEYID',
|
|
|
|
help='Sign the release with the given gpg key')
|
|
|
|
parser.add_argument('--rc-num', metavar='NUM', type=int, default=1,
|
|
|
|
help='Release Candidate number, required')
|
|
|
|
parser.add_argument('--smoke-test', metavar='PATH',
|
|
|
|
help='Run the smoker tester on the release in the given directory')
|
|
|
|
parser.add_argument('root', metavar='checkout_path',
|
|
|
|
help='Root of SVN checkout for lucene-solr')
|
|
|
|
config = parser.parse_args()
|
|
|
|
|
|
|
|
if config.push_remote is not None and config.push_local is not None:
|
|
|
|
parser.error('Cannot specify --push-remote and --push-local together')
|
|
|
|
if not config.prepare and config.sign:
|
|
|
|
parser.error('Cannot sign already built release')
|
|
|
|
if config.push_local is not None and os.path.exists(config.push_local):
|
|
|
|
parser.error('Cannot push to local path that already exists')
|
|
|
|
if config.rc_num <= 0:
|
|
|
|
parser.error('Release Candidate number must be a positive integer')
|
|
|
|
if not os.path.isdir(config.root):
|
|
|
|
# TODO: add additional svn check to ensure dir is a real lucene-solr checkout
|
|
|
|
parser.error('Root path is not a valid lucene-solr checkout')
|
|
|
|
|
|
|
|
config.version = read_version(config.root)
|
|
|
|
print('Building version: %s' % config.version)
|
|
|
|
|
|
|
|
if config.sign:
|
2013-04-17 15:35:47 -04:00
|
|
|
sys.stdout.flush()
|
|
|
|
import getpass
|
2014-08-28 04:01:50 -04:00
|
|
|
config.key_id = config.sign
|
|
|
|
config.key_password = getpass.getpass('Enter GPG keystore password: ')
|
|
|
|
else:
|
|
|
|
config.gpg_password = None
|
2013-04-17 15:35:47 -04:00
|
|
|
|
2014-08-28 04:01:50 -04:00
|
|
|
return config
|
|
|
|
|
|
|
|
def main():
|
|
|
|
c = parse_config()
|
2011-09-13 12:20:23 -04:00
|
|
|
|
2014-08-28 04:01:50 -04:00
|
|
|
if c.prepare:
|
2014-08-30 11:48:16 -04:00
|
|
|
rev = prepare(c.root, c.version, c.key_id, c.key_password)
|
2011-09-13 12:20:23 -04:00
|
|
|
else:
|
|
|
|
os.chdir(root)
|
2013-01-16 16:18:41 -05:00
|
|
|
rev = open('rev.txt', encoding='UTF-8').read()
|
2011-09-13 12:20:23 -04:00
|
|
|
|
2014-08-28 04:01:50 -04:00
|
|
|
if c.push_remote:
|
2015-01-24 14:12:00 -05:00
|
|
|
url = push(c.version, c.root, rev, c.rc_num, c.push_remote)
|
2014-08-28 04:01:50 -04:00
|
|
|
elif c.push_local:
|
2015-01-24 14:12:00 -05:00
|
|
|
url = pushLocal(c.version, c.root, rev, c.rc_num, c.push_local)
|
2012-04-08 14:22:14 -04:00
|
|
|
else:
|
2013-01-16 16:18:41 -05:00
|
|
|
url = None
|
2012-04-08 14:22:14 -04:00
|
|
|
|
|
|
|
if url is not None:
|
2013-01-16 16:18:41 -05:00
|
|
|
print(' URL: %s' % url)
|
2014-08-30 11:48:16 -04:00
|
|
|
print('Next set the PYTHON_EXEC env var and you can run the smoker tester:')
|
2015-06-10 15:04:43 -04:00
|
|
|
p = re.compile("(.*)\/")
|
|
|
|
m = p.match(sys.argv[0])
|
|
|
|
print(' $PYTHON_EXEC %ssmokeTestRelease.py %s' % (m.group(), url))
|
2013-01-16 16:18:41 -05:00
|
|
|
|
2011-09-13 12:20:23 -04:00
|
|
|
if __name__ == '__main__':
|
2013-01-16 16:18:41 -05:00
|
|
|
try:
|
|
|
|
main()
|
2014-08-28 04:01:50 -04:00
|
|
|
except KeyboardInterrupt:
|
|
|
|
print('Keyboard interrupt...exiting')
|
|
|
|
|