def ensure_tag_exists(kctx: kitipy.Context, tag: str): """Check if the given Git tag exists on both local copy and remote origin. This is mostly useful to ensure no invalid tag is going to be deployed. Args: kctx (kitipy.Context): Kitipy context. tag (str): Git tag to verify. Raises: ValueError: If the given Git tag does not exist either on local or remote origin. """ res = kctx.local( 'git ls-remote --exit-code --tags origin refs/tags/%s >/dev/null 2>&1' % (tag), check=False) if res.returncode != 0: kctx.fail("The given tag is not available on Git remote origin.") res = kctx.local( 'git ls-remote --exit-code --tags ./. refs/tags/%s >/dev/null 2>&1' % (tag), check=False) if res.returncode != 0: kctx.fail( "The given tag is not available in your local Git repo. Please fetch remote tags before running this task again." )
def run_playbook(kctx: Context, inventory: str, playbook: str, hosts: Optional[Tuple[str]] = None, tags: Optional[Tuple[str]] = None, ask_become_pass: bool = False): """Run a given Ansible playbook using ``ansible-playbook``. Args: kctx (kitipy.Context): Context to use to run the playbook. inventory (str): Path to Ansible host inventory. playbook (str): Path to the Ansible playbook to run. hosts (Optional[Tuple[str]]): List of targeted hosts. Use None to target all hosts (default value). tags (Optional[Tuple[str]]): List of targeted tags. Use None to apply all the tags (default value). ask_become_pass (bool): Whether ``--ask-become-pass`` should be added to the ``ansible-playbook`` command. """ cmd = 'ansible-playbook -i %s' % (inventory) if hosts is not None and len(hosts) > 0: cmd += ' -l ' + ','.join(hosts) if tags is not None and len(tags) > 0: cmd += ' -t ' + ','.join(tags) if ask_become_pass: cmd += ' --ask-become-pass' cmd += ' ' + playbook kctx.local(cmd)
def test_unit(kctx: kitipy.Context, report: bool, coverage: bool): # Be sure the SSH container used for tests purpose is up and running. # @TODO: add a common way to kitipy to wait for a port to be open kctx.invoke(kitipy.docker.tasks.up) expected_services = len(kctx.stack.config['services']) # @TODO: this won't work as is with Swarm, find how to generalize that sort of tests tester = lambda kctx: expected_services == kctx.stack.count_running_services( ) kitipy.wait_for(tester, interval=1, max_checks=5, label="Waiting for services start up...") # Host key might change if docker-compose down is used between two test run, # thus we start by removing any existing host key. kctx.local("ssh-keygen -R '[127.0.0.1]:2022' 1>/dev/null 2>&1") kctx.local("ssh-keygen -R '[127.0.0.1]:2023' 1>/dev/null 2>&1") kctx.local("ssh-keygen -R testhost 1>/dev/null 2>&1") # Ensure the private key has the right chmod or the task might fail. os.chmod("tests/.ssh/id_rsa", 0o0600) # Ensure first that we're actually able to connect to SSH hosts, or # tests will fail anyway. kctx.local('ssh -F tests/.ssh/config testhost /bin/true 1>/dev/null 2>&1') kctx.local('ssh -F tests/.ssh/config jumphost /bin/true 1>/dev/null 2>&1') kctx.local( 'ssh -F tests/.ssh/config testhost-via-jumphost /bin/true 1>/dev/null 2>&1' ) report_name = 'unit.xml' if report else None pytest(kctx, report_name, coverage, 'tests/unit/ -vv')
def pytest(kctx: kitipy.Context, report_name: Optional[str], coverage: bool, cmd: str, **args): env = os.environ.copy() env['PYTHONPATH'] = os.getcwd() args.setdefault('env', env) basecmd = 'pytest' if report_name: if not kctx.path_exists('.test-results'): os.mkdir('.test-results') basecmd += ' --junitxml=.test-results/%s' % (report_name) if coverage: basecmd += ' --cov=kitipy/' kctx.local('%s %s' % (basecmd, cmd), **args)
def format(kctx: kitipy.Context, show_diff, fix): """Run yapf to detect style divergences and fix them.""" if not show_diff and not fix: kctx.fail( "You can't use both --no-diff and --no-fix at the same time.") confirm_msg = 'Do you want to reformat your code using yapf?' dry_run = lambda: kctx.local('yapf --diff -r kitipy/ tests/ tasks*.py', check=False) apply = lambda: kctx.local('yapf -vv -p -i -r kitipy/ tests/ tasks*.py') kitipy.confirm_and_apply(dry_run, confirm_msg, apply, show_dry_run=show_diff, ask_confirm=fix is None, should_apply=fix if fix is not None else True)
def ensure_tag_is_recent(kctx: kitipy.Context, tag: str, last: int = 5): """Check if the given Git tag is recent enough (by default, one of the last five). Args: kctx (kitipy.Context): Kitipy Context. tag (str): Tag to look for. """ res = kctx.local( "git for-each-ref --format='%%(refname:strip=2)' --sort=committerdate 'refs/tags/*' 2>/dev/null | tail -n%d | grep %s >/dev/null 2>&1" % (last, tag), check=False, ) if res.returncode != 0: kctx.fail( 'This tag seems too old: at least %d new tags have been released since %s.' % (last, tag))
def lint(kctx: kitipy.Context): """Run mypy, a static type checker, to detect type errors.""" kctx.local('mypy -p kitipy')