Exemple #1
0
def finish(fast_forward: bool):
    """ Merge current feature branch into develop. """
    pretend = context.get('pretend', False)

    if not pretend and (git.staged() or git.unstaged()):
        log.err("You have uncommitted changes in your repo!\n"
                "You need to stash them before you merge the hotfix branch")
        sys.exit(1)

    branch = git.current_branch(refresh=True)
    base = common.get_base_branch()

    prompt = "<32>Merge <33>{}<32> into <33>{}<0>?".format(branch.name, base)
    if not click.confirm(shell.fmt(prompt)):
        log.info("Cancelled")
        return

    common.assert_branch_type('task')

    hooks.register.call('pre-task-finish', branch, base)

    # Merge task into it's base feature branch
    common.git_checkout(base)
    common.git_pull(base)
    common.git_merge(base, branch.name, no_ff=not fast_forward)

    # Cleanup
    common.git_branch_delete(branch.name)
    common.git_prune()

    common.git_checkout(base)

    hooks.register.call('post-task-finish', branch, base)
Exemple #2
0
def finish(fast_forward: bool):
    """ Merge current feature branch into develop. """
    pretend = context.get('pretend', False)

    if not pretend and (git.staged() or git.unstaged()):
        log.err("You have uncommitted changes in your repo!\n"
                "You need to stash them before you merge the feature branch")
        sys.exit(1)

    develop = conf.get('git.devel_branch', 'develop')
    branch = git.current_branch(refresh=True)

    common.assert_branch_type('feature')

    hooks.register.call('pre-feature-finish', branch)

    # Merge feature into develop
    common.git_checkout(develop)
    common.git_pull(develop)
    common.git_merge(develop, branch.name, no_ff=not fast_forward)

    # Cleanup
    common.git_branch_delete(branch.name)
    common.git_prune()

    common.git_checkout(develop)

    hooks.register.call('post-feature-finish', branch)
Exemple #3
0
def deploy(app_id, version, promote, quiet):
    # type: (str, str, bool, bool) -> None
    """ Deploy the app to AppEngine.

    Args:
        app_id (str):
            AppEngine App ID. Overrides config value app_id if given.
        version (str):
            AppEngine project version. Overrides config values if given.
        promote (bool):
            If set to **True** promote the current remote app version to the one
            that's being deployed.
        quiet (bool):
            If set to **True** this will pass the ``--quiet`` flag to gcloud
            command.
    """
    gae_app = GaeApp.for_branch(git.current_branch().name)

    if gae_app is None and None in (app_id, version):
        msg = ("Can't find an AppEngine app setup for branch <35>{}<32> and"
               "--project and --version were not given.")
        log.err(msg, git.current_branch().name)
        sys.exit(1)

    if version is not None:
        gae_app.version = version

    if app_id is not None:
        gae_app.app_id = app_id

    gae_app.deploy(promote, quiet)
Exemple #4
0
def add_hooks(pre_commit: str, pre_push: str):
    """ Add git hooks for commit and push to run linting and tests. """

    # Detect virtualenv the hooks should use

    # Detect virtualenv
    virtual_env = conf.get_env('VIRTUAL_ENV')
    if virtual_env is None:
        log.err("You are not inside a virtualenv")
        confirm_msg = (
            "Are you sure you want to use global python installation "
            "to run your git hooks? [y/N] "
        )
        click.prompt(confirm_msg, default='')
        if not click.confirm(confirm_msg):
            log.info("Cancelling")
            return

        load_venv = ''
    else:
        load_venv = 'source "{}/bin/activate"'.format(virtual_env)

    commit_hook = conf.proj_path('.git/hooks/pre-commit')
    push_hook = conf.proj_path('.git/hooks/pre-push')

    # Write pre-commit hook
    log.info("Adding pre-commit hook <33>{}", commit_hook)
    fs.write_file(commit_hook, util.remove_indent('''
        #!/bin/bash
        PATH="/opt/local/libexec/gnubin:$PATH"
        
        {load_venv}
        
        {command}
        
    '''.format(load_venv=load_venv, command=pre_commit)))

    # Write pre-push hook
    log.info("Adding pre-push hook: <33>{}", push_hook)
    fs.write_file(push_hook, util.remove_indent('''
        #!/bin/bash
        PATH="/opt/local/libexec/gnubin:$PATH"
        
        {load_venv}
        
        peltak test --allow-empty
        
        {command}
        
    '''.format(load_venv=load_venv, command=pre_push)))

    log.info("Making hooks executable")
    if not context.get('pretend', False):
        os.chmod(conf.proj_path('.git/hooks/pre-commit'), 0o755)
        os.chmod(conf.proj_path('.git/hooks/pre-push'), 0o755)
Exemple #5
0
def assert_on_branch(branch_name: str):
    """ Print error and exit if *branch_name* is not the current branch.

    Args:
        branch_name (str):
            The supposed name of the current branch.
    """
    branch = git.current_branch(refresh=True)

    if branch.name != branch_name:
        if context.get('pretend', False):
            log.info("Would assert that you're on a <33>{}<32> branch",
                     branch_name)
        else:
            log.err("You're not on a <33>{}<31> branch!", branch_name)
            sys.exit(1)
Exemple #6
0
def start(name: str):
    """ Start working on a new feature by branching off develop.

    This will create a new branch off develop called feature/<name>.

    Args:
        name (str):
            The name of the new feature.
    """
    branch = git.current_branch(refresh=True)
    task_branch = 'task/' + common.to_branch_name(name)

    if branch.type not in ('feature', 'hotfix'):
        log.err("Task branches can only branch off <33>feature<32> or "
                "<33>hotfix<32> branches")
        sys.exit(1)

    hooks.register.call('pre-task-start', name)
    common.git_checkout(task_branch, create=True)
    hooks.register.call('post-task-start', name)
Exemple #7
0
def assert_branch_type(branch_type: str):
    """ Print error and exit if the current branch is not of a given type.

    Args:
        branch_type (str):
            The branch type. This assumes the branch is in the '<type>/<title>`
            format.
    """
    branch = git.current_branch(refresh=True)

    if branch.type != branch_type:
        if context.get('pretend', False):
            log.info("Would assert that you're on a <33>{}/*<32> branch",
                     branch_type)
        else:
            log.err("Not on a <33>{}<31> branch!", branch_type)
            fmt = ("The branch must follow <33>{required_type}/<name><31>"
                   "format and your branch is called <33>{name}<31>.")
            log.err(fmt, required_type=branch_type, name=branch.name)
            sys.exit(1)
Exemple #8
0
def finish(fast_forward: bool):
    """ Merge current release into develop and master and tag it. """
    pretend = context.get('pretend', False)

    if not pretend and (git.staged() or git.unstaged()):
        log.err("You have uncommitted changes in your repo!\n"
                "You need to stash them before you merge the release branch")
        sys.exit(1)

    develop = conf.get('git.devel_branch', 'develop')
    master = conf.get('git.master_branch', 'master')
    branch = git.current_branch(refresh=True)

    common.assert_branch_type('release')

    hooks.register.call('pre-release-finish', branch)

    # Merge release into master
    common.git_checkout(develop)
    common.git_pull(develop)
    common.git_merge(develop, branch.name, no_ff=not fast_forward)

    # Merge release into develop
    common.git_checkout(master)
    common.git_pull(master)
    common.git_merge(master, branch.name, no_ff=not fast_forward)

    # Tag the release commit with version number
    tag(changelog())

    # Cleanup
    common.git_branch_delete(branch.name)
    common.git_prune()

    common.git_checkout(master)

    hooks.register.call('post-release-finish', branch)
Exemple #9
0
def choose_branch(exclude: Optional[Iterable[str]] = None) -> str:
    """ Show the user a menu to pick a branch from the existing ones.

    Args:
        exclude (list[str]):
            List of branch names to exclude from the menu. By default it will
            exclude master and develop branches. To show all branches pass an
            empty array here.

    Returns:
        str: The name of the branch chosen by the user. If the user inputs an
        invalid choice, he will be asked again (and again) until he picks a
        a valid branch.
    """
    if exclude is None:
        master = conf.get('git.master_branch', 'master')
        develop = conf.get('git.devel_branch', 'develop')
        exclude = {master, develop}

    branches = list(set(git.branches()) - set(exclude))

    # Print the menu
    for i, branch_name in enumerate(branches):
        shell.cprint('<90>[{}] <33>{}'.format(i + 1, branch_name))

    # Get a valid choice from the user
    choice = 0
    while choice < 1 or choice > len(branches):
        prompt = "Pick a base branch from the above [1-{}]".format(
            len(branches))
        choice = click.prompt(prompt, value_proc=int)  # type: ignore
        if not (1 <= choice <= len(branches)):
            fmt = "Invalid choice {}, you must pick a number between {} and {}"
            log.err(fmt.format(choice, 1, len(branches)))

    return branches[choice - 1]
Exemple #10
0
def gen_pypirc(username: Optional[str] = None, password: Optional[str] = None):
    """ Generate ~/.pypirc with the given credentials.

    Useful for CI builds. Can also get credentials through env variables
    ``PYPI_USER`` and ``PYPI_PASS``.

    Args:
        username (str):
            pypi username. If not given it will try to take it from the
            `` PYPI_USER`` env variable.
        password (str):
            pypi password. If not given it will try to take it from the
            `` PYPI_PASS`` env variable.
    """
    path = join(conf.get_env('HOME'), '.pypirc')
    username = username or conf.get_env('PYPI_USER', None)
    password = password or conf.get_env('PYPI_PASS', None)

    if username is None or password is None:
        log.err("You must provide $PYPI_USER and $PYPI_PASS")
        sys.exit(1)

    log.info("Generating <94>{}".format(path))

    fs.write_file(
        path,
        util.remove_indent('''
        [distutils]
        index-servers = pypi
        
        [pypi]
        repository: https://upload.pypi.org/legacy/
        username: {username}
        password: {password}
        
    '''.format(username=username, password=password)))
Exemple #11
0
def test_decorates_the_message(p_cprint):
    log.err('hello')

    p_cprint.assert_called_once_with('-- <31>hello<0>')
Exemple #12
0
def test_formatting_works(p_cprint, msg, args, kw, expected):
    log.err(msg, *args, **kw)

    p_cprint.assert_called_once_with(expected)