def make_new_version(opts): LOGGER.info("Updating package version...") if not highlander([opts.major, opts.minor, opts.micro]): msg = "Can only specify one of --major, --minor or --micro" LOGGER.error(msg) raise RuntimeError(msg) fields = ['major', 'minor', 'micro'] mask = [opts.major, opts.minor, opts.micro] field = [x for x in itertools.compress(fields, mask)][0] config = load_configuration() current_version = config.package_version() # need to be on the latest develop repo_dir = repo_directory() curr_branch = current_branch(repo_dir) # make sure repo is clean if has_unstaged_changes(repo_dir): msg = ("Error: Unstaged changes are present on the branch {}" "Please commit them or clean up before proceeding" ).format(curr_branch) LOGGER.error(msg) raise RuntimeError(msg) # update cirrus conf new_version = bump_version_field(current_version, field) msg = "Bumping version from {prev} to {new} on branch {branch}".format( prev=current_version, new=new_version, branch=curr_branch) LOGGER.info(msg) config.update_package_version(new_version) changes = ['cirrus.conf'] if opts.bump: reqs_file = os.path.join(repo_dir, 'requirements.txt') for pkg, version in opts.bump: LOGGER.info("Bumping dependency {} to {}".format(pkg, version)) bump_package(reqs_file, pkg, version) changes.append(reqs_file) # update __version__ or equivalent version_file, version_attr = config.version_file() if version_file is not None: LOGGER.info('Updating {0} attribute in {1}'.format( version_file, version_attr)) update_version(version_file, new_version, version_attr) changes.append(version_file) # update files changed msg = "cirrus release: version bumped for {0}".format(curr_branch) LOGGER.info('Committing files: {0}'.format(','.join(changes))) LOGGER.info(msg) commit_files_optional_push(repo_dir, msg, not opts.no_remote, *changes)
def update_setup_py(opts): LOGGER.info("Updating setup.py...") repo_location = opts.repo s_py = os.path.join(repo_location, 'setup.py') if os.path.exists(s_py): backup_file(s_py) else: LOGGER.error("no setup.py found in {}".format(repo_location)) raise RuntimeError('{} not found'.format(s_py)) # render new template... write_setup_py(opts) # commit new file commit_files_optional_push(opts.repo, "git cirrus package update: setup.py", False, 'setup.py')
def commit_and_tag(opts, *files): """ add files, commit changes and verify that initial tag exists """ do_push = not opts.no_remote commit_files_optional_push(opts.repo, "git cirrus package init", do_push, *files) tags = get_tags(opts.repo) if opts.version not in tags: msg = ("tag {} not found, tagging {}...").format( opts.version, opts.master) LOGGER.info(msg) tag_release(opts.repo, opts.version, master=opts.master, push=do_push) branch(opts.repo, opts.develop, opts.develop)
def init_container(opts): """ Initialise a basic container-template setup for this package """ cirrus_conf = os.path.join(opts.repo, 'cirrus.conf') if not os.path.exists(cirrus_conf): msg = "No cirrus.conf found, need to init repo first?" LOGGER.error(msg) sys.exit(1) config = load_configuration(opts.repo) print "cirrus_conf=", cirrus_conf template_dir = os.path.join(opts.repo, opts.template_dir) if not os.path.exists(template_dir): LOGGER.info("Creating Template in {}".format(template_dir)) os.makedirs(template_dir) docker_file = os.path.join(template_dir, 'Dockerfile.mustache') dotfile = os.path.join(template_dir, '.dockerstache') pre_script = os.path.join(template_dir, 'pre_script.sh') post_script = os.path.join(template_dir, 'post_script.sh') context = os.path.join(template_dir, 'context.json') local_install = os.path.join(template_dir, 'local_pip_install.sh.mustache') pypi_install = os.path.join(template_dir, 'pypi_pip_install.sh.mustache') opts.context_file = os.path.join(opts.template_dir, 'context.json') # make sure repo is clean if has_unstaged_changes(opts.repo): msg = ("Error: Unstaged changes are present on the branch " "Please commit them or clean up before proceeding") LOGGER.error(msg) raise RuntimeError(msg) main_branch = config.gitflow_branch_name() LOGGER.info("checking out latest {} branch...".format(main_branch)) checkout_and_pull(opts.repo, main_branch, not opts.no_remote) venv_option = "" if opts.virtualenv: venv_option = ". {}/bin/activate".format(opts.virtualenv) with working_dir(template_dir): write_basic_dockerfile(opts, config, docker_file) write_json_file(dotfile, { "post_script": "post_script.sh", "pre_script": "pre_script.sh" }) write_json_file(context, {}) write_script(pre_script, DOCKER_PRE_SCRIPT) write_script(local_install, LOCAL_INSTALL_SCRIPT, virtualenv=venv_option) write_script( pypi_install, PYPI_INSTALL_SCRIPT, virtualenv=venv_option, pip_options=config.pip_options() if config.pip_options() else "") if opts.local_install: write_script(post_script, DOCKER_POST_SCRIPT, copy_dist=LOCAL_INSTALL_COMMAND.format( package=config.package_name())) else: write_script(post_script, DOCKER_POST_SCRIPT, copy_dist="") edit_cirrus_conf(opts, config) modified = [ cirrus_conf, docker_file, dotfile, pre_script, post_script, local_install, pypi_install, context ] LOGGER.info("commiting changes...") commit_files_optional_push(opts.repo, "git cirrus package container-init", not opts.no_remote, *modified)
def new_release(opts): """ _new_release_ - Create a new release branch in the local repo - Edit the conf to bump the version - Edit the history file with release notes """ LOGGER.info("Creating new release...") if not highlander([opts.major, opts.minor, opts.micro]): msg = "Can only specify one of --major, --minor or --micro" LOGGER.error(msg) raise RuntimeError(msg) fields = ['major', 'minor', 'micro'] mask = [opts.major, opts.minor, opts.micro] field = [x for x in itertools.compress(fields, mask)][0] config = load_configuration() # version bump: current_version = config.package_version() new_version = bump_version_field(current_version, field) # release branch branch_name = "{0}{1}".format(config.gitflow_release_prefix(), new_version) LOGGER.info('release branch is {0}'.format(branch_name)) # need to be on the latest develop repo_dir = repo_directory() # make sure the branch doesnt already exist on remote if remote_branch_exists(repo_dir, branch_name): msg = ("Error: branch {branch_name} already exists on the remote repo " "Please clean up that branch before proceeding\n" "git branch -d {branch_name}\n" "git push origin --delete {branch_name}\n").format( branch_name=branch_name) LOGGER.error(msg) raise RuntimeError(msg) # make sure repo is clean if has_unstaged_changes(repo_dir): msg = ("Error: Unstaged changes are present on the branch " "Please commit them or clean up before proceeding") LOGGER.error(msg) raise RuntimeError(msg) main_branch = config.gitflow_branch_name() checkout_and_pull(repo_dir, main_branch, pull=not opts.no_remote) # create release branch branch(repo_dir, branch_name, main_branch) # update cirrus conf config.update_package_version(new_version) changes = ['cirrus.conf'] if opts.bump: reqs_file = os.path.join(repo_dir, 'requirements.txt') for pkg, version in opts.bump: LOGGER.info("Bumping dependency {} to {}".format(pkg, version)) bump_package(reqs_file, pkg, version) changes.append(reqs_file) # update release notes file relnotes_file, relnotes_sentinel = config.release_notes() if (relnotes_file is not None) and (relnotes_sentinel is not None): LOGGER.info('Updating release notes in {0}'.format(relnotes_file)) relnotes = "Release: {0} Created: {1}\n".format( new_version, datetime.datetime.utcnow().isoformat()) relnotes += build_release_notes(repo_dir, current_version, config.release_notes_format()) update_file(relnotes_file, relnotes_sentinel, relnotes) changes.append(relnotes_file) # update __version__ or equivalent version_file, version_attr = config.version_file() if version_file is not None: LOGGER.info('Updating {0} attribute in {1}'.format( version_file, version_attr)) update_version(version_file, new_version, version_attr) changes.append(version_file) # update files changed msg = "cirrus release: new release created for {0}".format(branch_name) LOGGER.info('Committing files: {0}'.format(','.join(changes))) LOGGER.info(msg) commit_files_optional_push(repo_dir, msg, not opts.no_remote, *changes) return (new_version, field)
def bootstrap_repo(opts): """ bootstrap an empty repo with initial file and dir structure. This adds: - src/<package>/__init__.py - test/unit/<package>/example_test.py - requirements.txt - test-requirements.txt - tox.ini """ package = opts.package if opts.source is None: opts.source = 'src' files = [] src_dir = opts.source tests_dir = os.path.join(opts.tests) unit_dir = os.path.join(tests_dir, 'unit') init_files = [ os.path.join(tests_dir, '__init__.py'), os.path.join(unit_dir, '__init__.py'), ] for d in [src_dir, tests_dir, unit_dir]: os.makedirs(d) for i in init_files: with open(i, 'w') as handle: handle.write("#created by cirrus\n") files.append(i) src_inits = make_package_dir(src_dir, package) test_inits = make_package_dir(unit_dir, package) files.extend(src_inits) files.extend(test_inits) test_pkg_dir = os.path.dirname(test_inits[-1]) main_init = main_init_file(opts) with open(main_init, 'w') as handle: handle.write("#!/usr/bin/env python\n") handle.write("# created by cirrus\n") handle.write("__version__=\'{}\'\n".format(opts.version)) if not os.path.exists(opts.requirements): with open(opts.requirements, 'w') as handle: handle.write("requests\n") files.append(opts.requirements) if not os.path.exists(opts.test_requirements): with open(opts.test_requirements, 'w') as handle: handle.write("tox\n") handle.write("nose\n") handle.write("coverage\n") handle.write("mock\n") handle.write("pep8\n") handle.write("pytest\n") files.append(opts.test_requirements) if not os.path.exists('tox.ini'): if opts.python is not None: py_vers = opts.python.replace('python', 'py') py_vers = py_vers.replace('.', '') else: py_vers = "py{}{}".format(sys.version_info.major, sys.version_info.minor) with open('tox.ini', 'w') as handle: install_comm = "" if opts.use_pypirc: rcfile = PypircFile() pip_opts = rcfile.pip_options() LOGGER.info( "Adding pip options to tox.ini: {}".format(pip_opts)) install_comm = ("install_command = pip install " "{} {{opts}} {{packages}}").format(pip_opts) handle.write( TOXFILE.format(requirements=opts.requirements, test_requirements=opts.test_requirements, install_command=install_comm, testdir=opts.tests, python=py_vers)) files.append('tox.ini') template = os.path.join( os.path.dirname(inspect.getsourcefile(cirrus.templates)), 'sample_test.py.mustache') with open(template, 'r') as handle: templ = handle.read() sample_test = os.path.join(test_pkg_dir, 'sample_test.py') rendered = pystache.render(templ, {'package': opts.package}) with open(sample_test, 'w') as handle: handle.write(rendered) files.append(sample_test) commit_files_optional_push(opts.repo, "git cirrus package bootstrap", False, *files)
def bootstrap_repo(opts): """ bootstrap an empty repo with initial file and dir structure. This adds: - src/<package>/__init__.py - test/unit/<package>/example_test.py - requirements.txt - test-requirements.txt - tox.ini """ package = opts.package if opts.source is None: opts.source = 'src' files = [] src_dir = opts.source tests_dir = os.path.join(opts.tests) unit_dir = os.path.join(tests_dir, 'unit') init_files = [ os.path.join(tests_dir, '__init__.py'), os.path.join(unit_dir, '__init__.py'), ] for d in [src_dir, tests_dir, unit_dir]: os.makedirs(d) for i in init_files: with open(i, 'w') as handle: handle.write("#created by cirrus\n") files.append(i) src_inits = make_package_dir(src_dir, package) test_inits = make_package_dir(unit_dir, package) files.extend(src_inits) files.extend(test_inits) test_pkg_dir = os.path.dirname(test_inits[-1]) main_init = main_init_file(opts) with open(main_init, 'w') as handle: handle.write("#!/usr/bin/env python\n") handle.write("# created by cirrus\n") handle.write("__version__=\'{}\'\n".format(opts.version)) if not os.path.exists(opts.requirements): with open(opts.requirements, 'w') as handle: handle.write("requests\n") files.append(opts.requirements) if not os.path.exists(opts.test_requirements): with open(opts.test_requirements, 'w') as handle: handle.write("tox\n") handle.write("nose\n") handle.write("coverage\n") handle.write("mock\n") handle.write("pep8\n") files.append(opts.test_requirements) if not os.path.exists('tox.ini'): with open('tox.ini', 'w') as handle: handle.write( TOXFILE.format(requirements=opts.requirements, test_requirements=opts.test_requirements, testdir=opts.tests)) files.append('tox.ini') template = os.path.join( os.path.dirname(inspect.getsourcefile(cirrus.templates)), 'sample_test.py.mustache') with open(template, 'r') as handle: templ = handle.read() sample_test = os.path.join(test_pkg_dir, 'sample_test.py') rendered = pystache.render(templ, {'package': opts.package}) with open(sample_test, 'w') as handle: handle.write(rendered) files.append(sample_test) commit_files_optional_push(opts.repo, "git cirrus package bootstrap", False, *files)
def init_container(opts): """ Initialise a basic container-template setup for this package """ cirrus_conf = os.path.join(opts.repo, 'cirrus.conf') if not os.path.exists(cirrus_conf): msg = "No cirrus.conf found, need to init repo first?" LOGGER.error(msg) sys.exit(1) config = load_configuration(opts.repo) template_dir = os.path.join(opts.repo, opts.template_dir) if not os.path.exists(template_dir): LOGGER.info("Creating Template in {}".format(template_dir)) os.makedirs(template_dir) docker_file = os.path.join(template_dir, 'Dockerfile.mustache') dotfile = os.path.join(template_dir, '.dockerstache') pre_script = os.path.join(template_dir, 'pre_script.sh') post_script = os.path.join(template_dir, 'post_script.sh') context = os.path.join(template_dir, 'context.json') installer_script = os.path.join(template_dir, 'install_script.sh.mustache') opts.context_file = os.path.join(opts.template_dir, 'context.json') # make sure repo is clean if has_unstaged_changes(opts.repo): msg = ("Error: Unstaged changes are present on the branch " "Please commit them or clean up before proceeding") LOGGER.error(msg) raise RuntimeError(msg) main_branch = config.gitflow_branch_name() LOGGER.info("checking out latest {} branch...".format(main_branch)) checkout_and_pull(opts.repo, main_branch, not opts.no_remote) venv_option = "" if opts.virtualenv: venv_option = ". {}/bin/activate".format(opts.virtualenv) with working_dir(template_dir): write_basic_dockerfile(opts, config, docker_file) write_json_file( dotfile, { "post_script": "post_script.sh", "pre_script": "pre_script.sh", "inclusive": True, "excludes": ["post_script.sh", "post_script.sh", ".dockerstache"] }) write_json_file(context, {}) # render templates for container scripts template_context = { 'open_brace': '{{', 'close_brace': '}}', 'package': config.package_name(), 'virtualenv': venv_option, 'pip_options': config.pip_options() if config.pip_options() else "" } install_template = find_template('install_script.sh.mustache') pre_template = find_template('pre_script.sh.mustache') post_template = find_template('post_script.sh.mustache') renderer = pystache.Renderer() install_result = renderer.render_path(install_template, template_context) with open(installer_script, 'w') as handle: handle.write(install_result) post_result = renderer.render_path(post_template, template_context) with open(post_script, 'w') as handle: handle.write(post_result) pre_result = renderer.render_path(pre_template, template_context) with open(pre_script, 'w') as handle: handle.write(pre_result) make_executable(pre_script, opts.repo) make_executable(post_script, opts.repo) make_executable(installer_script, opts.repo) edit_cirrus_conf(opts, config) modified = [ cirrus_conf, docker_file, dotfile, pre_script, post_script, installer_script, context ] LOGGER.info("commiting changes...") commit_files_optional_push(opts.repo, "git cirrus package container-init", not opts.no_remote, *modified)
def init_container(opts): """ Initialise a basic container-template setup for this package """ cirrus_conf = os.path.join(opts.repo, 'cirrus.conf') if not os.path.exists(cirrus_conf): msg = "No cirrus.conf found, need to init repo first?" LOGGER.error(msg) sys.exit(1) config = load_configuration(opts.repo) template_dir = os.path.join(opts.repo, opts.template_dir) if not os.path.exists(template_dir): LOGGER.info("Creating Template in {}".format(template_dir)) os.makedirs(template_dir) docker_file = os.path.join(template_dir, 'Dockerfile.mustache') dotfile = os.path.join(template_dir, '.dockerstache') pre_script = os.path.join(template_dir, 'pre_script.sh') post_script = os.path.join(template_dir, 'post_script.sh') context = os.path.join(template_dir, 'context.json') installer_script = os.path.join(template_dir, 'install_script.sh.mustache') opts.context_file = os.path.join(opts.template_dir, 'context.json') # make sure repo is clean if has_unstaged_changes(opts.repo): msg = ( "Error: Unstaged changes are present on the branch " "Please commit them or clean up before proceeding" ) LOGGER.error(msg) raise RuntimeError(msg) main_branch = config.gitflow_branch_name() LOGGER.info("checking out latest {} branch...".format(main_branch)) checkout_and_pull(opts.repo, main_branch, not opts.no_remote) venv_option = "" if opts.virtualenv: venv_option = ". {}/bin/activate".format(opts.virtualenv) with working_dir(template_dir): write_basic_dockerfile(opts, config, docker_file) write_json_file(dotfile, { "post_script": "post_script.sh", "pre_script": "pre_script.sh", "inclusive": True, "excludes": ["post_script.sh", "post_script.sh", ".dockerstache"] }) write_json_file(context, {}) # render templates for container scripts template_context = { 'open_brace': '{{', 'close_brace': '}}', 'package': config.package_name(), 'virtualenv': venv_option, 'pip_options': config.pip_options() if config.pip_options() else "" } install_template = find_template('install_script.sh.mustache') pre_template = find_template('pre_script.sh.mustache') post_template = find_template('post_script.sh.mustache') renderer = pystache.Renderer() install_result = renderer.render_path(install_template, template_context) with open(installer_script, 'w') as handle: handle.write(install_result) post_result = renderer.render_path(post_template, template_context) with open(post_script, 'w') as handle: handle.write(post_result) pre_result = renderer.render_path(pre_template, template_context) with open(pre_script, 'w') as handle: handle.write(pre_result) make_executable(pre_script, opts.repo) make_executable(post_script, opts.repo) make_executable(installer_script, opts.repo) edit_cirrus_conf(opts, config) modified = [ cirrus_conf, docker_file, dotfile, pre_script, post_script, installer_script, context ] LOGGER.info("commiting changes...") commit_files_optional_push( opts.repo, "git cirrus package container-init", not opts.no_remote, *modified )