Add images build step and finalize placeholder

Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
Joffrey F 2018-04-18 18:33:20 -07:00
parent 599456378b
commit e9f6abf8f4
2 changed files with 101 additions and 20 deletions

View File

@ -4,9 +4,11 @@ from __future__ import unicode_literals
import argparse import argparse
import os import os
import shutil
import sys import sys
import time import time
import docker
from jinja2 import Template from jinja2 import Template
from release.bintray import BintrayAPI from release.bintray import BintrayAPI
from release.const import BINTRAY_ORG from release.const import BINTRAY_ORG
@ -77,6 +79,15 @@ def monitor_pr_status(pr_data):
raise ScriptError('CI failure detected') raise ScriptError('CI failure detected')
def check_pr_mergeable(pr_data):
if not pr_data.mergeable:
print(
'WARNING!! PR #{} can not currently be merged. You will need to '
'resolve the conflicts manually before finalizing the release.'.format(pr_data.number)
)
return pr_data.mergeable
def create_release_draft(repository, version, pr_data, files): def create_release_draft(repository, version, pr_data, files):
print('Creating Github release draft') print('Creating Github release draft')
with open(os.path.join(os.path.dirname(__file__), 'release.md.tmpl'), 'r') as f: with open(os.path.join(os.path.dirname(__file__), 'release.md.tmpl'), 'r') as f:
@ -97,13 +108,51 @@ def create_release_draft(repository, version, pr_data, files):
return gh_release return gh_release
def print_final_instructions(gh_release): def build_images(repository, files, version):
print(""" print("Building release images...")
You're almost done! The following steps should be executed after you've repository.write_git_sha()
verified that everything is in order and are ready to make the release public: docker_client = docker.APIClient(**docker.utils.kwargs_from_env())
1. distdir = os.path.join(REPO_ROOT, 'dist')
2. os.makedirs(distdir, exist_ok=True)
3.""") shutil.copy(files['docker-compose-Linux-x86_64'][0], distdir)
print('Building docker/compose image')
logstream = docker_client.build(
REPO_ROOT, tag='docker/compose:{}'.format(version), dockerfile='Dockerfile.run',
decode=True
)
for chunk in logstream:
if 'error' in chunk:
raise ScriptError('Build error: {}'.format(chunk['error']))
if 'stream' in chunk:
print(chunk['stream'], end='')
print('Building test image (for UCP e2e)')
logstream = docker_client.build(
REPO_ROOT, tag='docker-compose-tests:tmp', decode=True
)
for chunk in logstream:
if 'error' in chunk:
raise ScriptError('Build error: {}'.format(chunk['error']))
if 'stream' in chunk:
print(chunk['stream'], end='')
container = docker_client.create_container(
'docker-compose-tests:tmp', entrypoint='tox'
)
docker_client.commit(container, 'docker/compose-tests:latest')
docker_client.tag('docker/compose-tests:latest', 'docker/compose-tests:{}'.format(version))
docker_client.remove_container(container, force=True)
docker_client.remove_image('docker-compose-tests:tmp', force=True)
def print_final_instructions(args):
print(
"You're almost done! Please verify that everything is in order and "
"you are ready to make the release public, then run the following "
"command:\n{exe} -b {user} finalize {version}".format(
exe=sys.argv[0], user=args.bintray_user, version=args.release
)
)
def resume(args): def resume(args):
@ -117,6 +166,7 @@ def resume(args):
pr_data = repository.find_release_pr(args.release) pr_data = repository.find_release_pr(args.release)
if not pr_data: if not pr_data:
pr_data = repository.create_release_pull_request(args.release) pr_data = repository.create_release_pull_request(args.release)
check_pr_mergeable(pr_data)
monitor_pr_status(pr_data) monitor_pr_status(pr_data)
downloader = BinaryDownloader(args.destination) downloader = BinaryDownloader(args.destination)
files = downloader.download_all(args.release) files = downloader.download_all(args.release)
@ -133,11 +183,12 @@ def resume(args):
raise ScriptError('Aborting release') raise ScriptError('Aborting release')
delete_assets(gh_release) delete_assets(gh_release)
upload_assets(gh_release, files) upload_assets(gh_release, files)
build_images(repository, files, args.release)
except ScriptError as e: except ScriptError as e:
print(e) print(e)
return 1 return 1
print_final_instructions(gh_release) print_final_instructions(args)
return 0 return 0
@ -163,19 +214,50 @@ def start(args):
repository = Repository(REPO_ROOT, args.repo or NAME) repository = Repository(REPO_ROOT, args.repo or NAME)
create_initial_branch(repository, args.release, args.base, args.bintray_user) create_initial_branch(repository, args.release, args.base, args.bintray_user)
pr_data = repository.create_release_pull_request(args.release) pr_data = repository.create_release_pull_request(args.release)
check_pr_mergeable(pr_data)
monitor_pr_status(pr_data) monitor_pr_status(pr_data)
downloader = BinaryDownloader(args.destination) downloader = BinaryDownloader(args.destination)
files = downloader.download_all(args.release) files = downloader.download_all(args.release)
gh_release = create_release_draft(repository, args.release, pr_data, files) gh_release = create_release_draft(repository, args.release, pr_data, files)
upload_assets(gh_release, files) upload_assets(gh_release, files)
build_images(repository, files, args.release)
except ScriptError as e: except ScriptError as e:
print(e) print(e)
return 1 return 1
print_final_instructions(gh_release) print_final_instructions(args)
return 0 return 0
def finalize(args):
try:
raise NotImplementedError()
except ScriptError as e:
print(e)
return 1
return 0
ACTIONS = [
'start',
'cancel',
'resume',
'finalize',
]
EPILOG = '''Example uses:
* Start a new feature release (includes all changes currently in master)
release.py -b user start 1.23.0
* Start a new patch release
release.py -b user --patch 1.21.0 start 1.21.1
* Cancel / rollback an existing release draft
release.py -b user cancel 1.23.0
* Restart a previously aborted patch release
release.py -b user -p 1.21.0 resume 1.21.1
'''
def main(): def main():
if 'GITHUB_TOKEN' not in os.environ: if 'GITHUB_TOKEN' not in os.environ:
print('GITHUB_TOKEN environment variable must be set') print('GITHUB_TOKEN environment variable must be set')
@ -189,18 +271,9 @@ def main():
description='Orchestrate a new release of docker/compose. This tool assumes that you have ' description='Orchestrate a new release of docker/compose. This tool assumes that you have '
'obtained a Github API token and Bintray API key and set the GITHUB_TOKEN and ' 'obtained a Github API token and Bintray API key and set the GITHUB_TOKEN and '
'BINTRAY_TOKEN environment variables accordingly.', 'BINTRAY_TOKEN environment variables accordingly.',
epilog='''Example uses: epilog=EPILOG, formatter_class=argparse.RawTextHelpFormatter)
* Start a new feature release (includes all changes currently in master)
release.py -b user start 1.23.0
* Start a new patch release
release.py -b user --patch 1.21.0 start 1.21.1
* Cancel / rollback an existing release draft
release.py -b user cancel 1.23.0
* Restart a previously aborted patch release
release.py -b user -p 1.21.0 resume 1.21.1''', formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument( parser.add_argument(
'action', choices=['start', 'resume', 'cancel'], 'action', choices=ACTIONS, help='The action to be performed for this release'
help='The action to be performed for this release'
) )
parser.add_argument('release', help='Release number, e.g. 1.9.0-rc1, 2.1.1') parser.add_argument('release', help='Release number, e.g. 1.9.0-rc1, 2.1.1')
parser.add_argument( parser.add_argument(
@ -227,6 +300,9 @@ def main():
return resume(args) return resume(args)
elif args.action == 'cancel': elif args.action == 'cancel':
return cancel(args) return cancel(args)
elif args.action == 'finalize':
return finalize(args)
print('Unexpected action "{}"'.format(args.action), file=sys.stderr) print('Unexpected action "{}"'.format(args.action), file=sys.stderr)
return 1 return 1

View File

@ -159,6 +159,10 @@ class Repository(object):
print('No open PR for this release branch.') print('No open PR for this release branch.')
return count return count
def write_git_sha(self):
with open(os.path.join(REPO_ROOT, 'compose', 'GITSHA'), 'w') as f:
f.write(self.git_repo.head.commit.hexsha[:7])
def get_contributors(pr_data): def get_contributors(pr_data):
commits = pr_data.get_commits() commits = pr_data.get_commits()
@ -175,6 +179,7 @@ def upload_assets(gh_release, files):
print('Uploading {}...'.format(filename)) print('Uploading {}...'.format(filename))
gh_release.upload_asset(filedata[0], content_type='application/octet-stream') gh_release.upload_asset(filedata[0], content_type='application/octet-stream')
gh_release.upload_asset('{}.sha256'.format(filedata[0]), content_type='text/plain') gh_release.upload_asset('{}.sha256'.format(filedata[0]), content_type='text/plain')
print('Uploading run.sh...')
gh_release.upload_asset( gh_release.upload_asset(
os.path.join(REPO_ROOT, 'script', 'run', 'run.sh'), content_type='text/plain' os.path.join(REPO_ROOT, 'script', 'run', 'run.sh'), content_type='text/plain'
) )