Exemple #1
0
def test_merge_downstream(wst, capsys):
    config.merge.branches = '1.0.x 2.0.x 3.0.x master'

    with temp_git_repo():
        run('git commit --allow-empty -m dummy-commit')
        run('git branch 3.0.x')
        run('git checkout -b 2.0.x')

        run('git commit --allow-empty -m new-commit')

        wst('merge --downstream')

        branches = run('git branch', return_output=True)
        changes = run('git log --oneline', return_output=True)

    out, _ = capsys.readouterr()

    assert out == """\
Merging 2.0.x into 3.0.x
Pushing 3.0.x
Merging 3.0.x into master
Pushing master
"""

    assert '* master' in branches
    assert 'new-commit' in changes
Exemple #2
0
def test_script_sanity(script):

    try:
        run([script, '-h'], stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as e:
        print(e.output)
        assert e.returncode == 0
Exemple #3
0
def remove_branch(branch, raises=False, remote=False, force=False):
    """ Removes branch """
    run(['git', 'branch', '-D' if force else '-d', branch], raises=raises)

    if remote:
        silent_run(['git', 'push',
                    default_remote(), '--delete', branch],
                   raises=raises)
Exemple #4
0
def local_commit(msg=None, amend=False, empty=False):
    cmd = ['git', 'commit']
    if amend:
        cmd.append('--amend')
    if empty:
        cmd.append('--allow-empty')
    if msg:
        cmd.extend(['-m', msg])
    run(cmd)
Exemple #5
0
def local_commit(msg=None, amend=False, empty=False):
    cmd = ['git', 'commit']
    if amend:
        cmd.append('--amend')
    if empty:
        cmd.append('--allow-empty')
    if msg:
        cmd.extend(['-m', msg])
    run(cmd)
Exemple #6
0
def prompt_with_editor(instruction):
    """ Prompt user with instruction in $EDITOR and return the response """

    with tempfile.NamedTemporaryFile(suffix='.tmp') as fh:
        fh.write('\n\n# ' + '\n# '.join(instruction.split('\n')))
        fh.flush()
        editor = os.environ.get('EDITOR', 'vim')
        run([editor, fh.name])
        return '\n'.join([l for l in open(fh.name).read().split('\n') if not l.startswith('#')]).strip()
Exemple #7
0
def temp_git_repo(name=None):
    with temp_dir() as tmpdir:
        if name:
            os.makedirs(name)
            os.chdir(name)

        run('git init')

        yield (tmpdir / name) if name else tmpdir
Exemple #8
0
    def install_editable_dependencies(self, tox, env, editable_products):
        name = product_name(tox.path)
        editable_products = expand_product_groups(editable_products)

        dependencies_output = self.show_installed_dependencies(tox, env, return_output=True)
        if not dependencies_output:
            log.debug('%s is not installed or there is no dependencies - skipping editable mode changes', name)
            return

        try:
            product_dependencies_list = json.loads(dependencies_output)
        except Exception as e:
            log.debug('Failed to get installed dependencies - skipping editable mode changes: %s', e)
            return

        product_dependencies = {}

        for dep, _, path in product_dependencies_list:
            product_dependencies[dep] = path

        available_products = [os.path.basename(r) for r in product_repos()]
        libs = [d for d in editable_products if d in available_products and d in product_dependencies and
                tox.envdir(env) in product_dependencies[d]]

        already_editable = [d for d in editable_products if d in product_dependencies and
                            tox.envdir(env) not in product_dependencies[d]]
        for lib in already_editable:
            click.echo('{} is already installed in editable mode.'.format(lib))

        not_dependent = [d for d in editable_products if d not in product_dependencies]
        for lib in not_dependent:
            log.debug('%s is not currently installed (not a dependency) and will be ignored.', lib)

        not_available = [d for d in editable_products if d not in not_dependent and d not in available_products]
        for lib in not_available:
            click.echo('{} is a dependency but not checked out in workspace, and so can not be installed in editable mode.'.format(lib))

        pip = tox.bindir(env, 'pip')

        for lib in libs:
            if not self.silent or self.debug:
                click.echo('{}: Installing {} in editable mode'.format(env, lib))

            with log_exception('An error occurred when installing %s in editable mode' % lib):
                run([pip, 'uninstall', lib, '-y'], raises=False, silent=not self.debug)

                lib_path = product_path(lib)
                if os.path.exists(os.path.join(lib_path, lib, 'setup.py')):
                    lib_path = os.path.join(lib_path, lib)
                run([pip, 'install', '--editable', lib_path], silent=not self.debug)
Exemple #9
0
    def submit(self):
        token = self.ui.userTokenLineEdit.text().strip()
        server_id = self.ui.serverIDLineEdit.text().strip()
        channel_checkbox = self.ui.checkBox.isChecked()

        if token == "" or server_id == "":
            message.create(
                QMessageBox.Warning,
                "Warning",
                "Token or Server ID is empty.",
            ).exec()
            return

        opts = [config.dscli_bin, "config", "-t", token, "-i", server_id]

        if channel_checkbox:
            opts.append("-d")

        result = process.run(opts)

        if result.returncode == 0:
            message.create(QMessageBox.Information, "Success",
                           "Settings saved successfully.").exec()
            self.close()
            return
        else:
            message.create(QMessageBox.Warning, "Error",
                           "Settings saved unsuccessfully.").exec()
            return
Exemple #10
0
    def refresh_list_impl(progress_callback):
        result = process.run([config.dscli_bin, "ls", "-l"])

        if result.returncode != 0:
            raise RuntimeError

        return result.stdout.decode()
Exemple #11
0
def test_merge_branch_skip_none(wst, capsys):
    """
        Test to check if merge_branch works when three commits are created, with no commits skipped.
        Fourth commit used so that all 3 commits on 3.0.x create merge commits.
    """
    config.merge.branches = '1.0.x 2.0.x 3.0.x master'
    with temp_git_repo():
        # Dummy commit
        run('git commit --allow-empty -m dummy-commit')
        run('git checkout -b 3.0.x')
        commit1_sha = make_commit("commit1")
        commit2_sha = make_commit("commit2")
        commit3_sha = make_commit("commit3")
        run('git checkout master')
        make_commit("commit4")
        wst('merge 3.0.x --skip-commits \'skip\' \'space separated example\'')

        changes = run('git log --oneline', return_output=True)
        assert f'Merge commit \'{commit1_sha[0:7]}\'' in changes
        assert f'Merge commit \'{commit2_sha[0:7]}\'' in changes
        assert f'Merge commit \'{commit3_sha[0:7]}\'' in changes
        assert 'commit1' in changes
        assert 'commit2' in changes
        assert 'commit3' in changes

        temp_git_dir_path = os.getcwd()
        assert os.path.isfile(os.path.join(temp_git_dir_path, "commit1.xml"))
        assert os.path.isfile(os.path.join(temp_git_dir_path, "commit2.xml"))
        assert os.path.isfile(os.path.join(temp_git_dir_path, "commit3.xml"))

    out, _ = capsys.readouterr()
    assert out.split('\n')[0] == 'Merging 3.0.x into master'
Exemple #12
0
def test_merge_branch_skip_all(wst, capsys):
    """
        Test to check if merge_branch works with three commits created on 3.0.x, with the all commits  skipped.
    """
    config.merge.branches = '1.0.x 2.0.x 3.0.x master'
    with temp_git_repo():
        # Dummy commit
        run('git commit --allow-empty -m dummy-commit')
        run('git checkout -b 3.0.x')
        skipped1_sha = make_commit("commit1", skip=True)
        skipped2_sha = make_commit("commit2", skip=True)
        skipped3_sha = make_commit("commit3", skip=True)
        run('git checkout master')
        wst('merge 3.0.x --skip-commits \'skip\' \'space separated example\'')

        changes = run('git log --oneline', return_output=True)
        # Change should have been in the log entry
        assert f'Merge commit {skipped1_sha[0:7]} into master (using strategy ours)' in changes
        assert f'Merge commit {skipped2_sha[0:7]} into master (using strategy ours)' in changes
        assert f'Merge commit {skipped3_sha[0:7]} into master (using strategy ours)' in changes
        assert '[skip]' in changes
        assert '[skip]' in changes
        assert '[skip]' in changes

        temp_git_dir_path = os.getcwd()
        assert not os.path.isfile(
            os.path.join(temp_git_dir_path, "commit1.xml"))
        assert not os.path.isfile(
            os.path.join(temp_git_dir_path, "commit2.xml"))
        assert not os.path.isfile(
            os.path.join(temp_git_dir_path, "commit3.xml"))

    out, _ = capsys.readouterr()
    assert out.split('\n')[0] == 'Merging 3.0.x into master'
Exemple #13
0
def ssh(ssh_args):
    """ Run ssh using the given args. Ansible hostname should be first|last arg. """

    if not ssh_args:
        click.echo('Hostname is required')
        sys.exit(1)

    # Find index of hostname
    ssh_args = list(ssh_args)
    host_index = None

    for i, arg in enumerate(ssh_args):
        if '@' in arg:
            host_index = i
            break

    if host_index is None:
        if ssh_args[0].startswith('-'):
            host_index = -1
        else:
            host_index = 0

    # Split out user/hostname
    if '@' in ssh_args[host_index]:
        user, host = arg.split('@')
    else:
        user, host = None, ssh_args[host_index]

    # Translate matching hostname and replace
    hosts = sorted(_hosts_matching(host), key=lambda h: h.name)
    if hosts:
        if len(hosts) > 1:
            click.echo('Found multiple matches and will use first one: ' + ', '.join(h.name for h in hosts))

        host = hosts[0].vars.get('ansible_host', hosts[0].name)
        ssh_args[host_index] = (user + '@' + host) if user else host

    # ssh to host
    try:
        run(['ssh'] + ssh_args)

    except Exception as e:
        sys.exit(1)
Exemple #14
0
def diff_repo(path=None, branch=None, context=None, return_output=False, name_only=False, color=False):
    cmd = ['git', 'diff']
    if name_only:
        cmd.append('--name-only')
    if color:
        cmd.append('--color')
    if branch:
        cmd.append(branch)
    if context:
        cmd.append(context)

    return run(cmd, cwd=path, return_output=return_output)
Exemple #15
0
def test_commit(wst):
    with temp_dir():
        with pytest.raises(SystemExit):
            wst('commit')
    config.merge.branches = '1.0.x 2.0.x 3.0.x master'
    with temp_git_repo():
        test_cleanrun
        with pytest.raises(SystemExit):
            wst('commit "no files to commit"')

    with temp_git_repo():
        run('git checkout -b 3.0.x')
        with open('new_file_commit1', 'w') as fp:
            fp.write('New World')
        run('git add -A')
        wst('commit "Add new file"')
        changes = run('git log --oneline', return_output=True)
        expected_commit_message = "Add new file"
        assert expected_commit_message in changes

        # test commit with branch
        with open('new_file_commit2', 'w') as fp:
            fp.write('Hello World')

        wst('commit "New Master file" --branch master')
        changes = run('git log --oneline', return_output=True)
        expected_commit_message = "New Master file"
        assert expected_commit_message in changes
Exemple #16
0
def test_merge_branch(wst, capsys):
    config.merge.branches = '1.0.x 2.0.x 3.0.x master'

    with temp_git_repo():
        run('git commit --allow-empty -m dummy-commit')

        run('git checkout -b 3.0.x')
        run('git commit --allow-empty -m new-commit')

        run('git checkout master')

        wst('merge 3.0.x')

        changes = run('git log --oneline', return_output=True)
        assert 'new-commit' in changes

    out, _ = capsys.readouterr()
    assert out.split('\n')[0] == 'Merging 3.0.x into master'
Exemple #17
0
def diff_repo(path=None,
              branch=None,
              context=None,
              return_output=False,
              name_only=False,
              color=False):
    cmd = ['git', 'diff']
    if name_only:
        cmd.append('--name-only')
    if color:
        cmd.append('--color')
    if branch:
        cmd.append(branch)
    if context:
        cmd.append(context)

    return run(cmd, cwd=path, return_output=return_output)
Exemple #18
0
def commit_logs(limit=None, repo=None, diff=False, show_revision=None, extra_args=None, to_pager=False):
    if show_revision:
        diff = True
        if not limit:
            limit = 1

    cmd = ['git', 'log', '--decorate']
    if show_revision:
        cmd.extend(['-U', show_revision])
    if limit:
        cmd.append('-%d' % limit)
    if diff:
        cmd.append('-c')
    if extra_args:
        cmd.extend(extra_args)

    return run(cmd, return_output=not to_pager, shell=to_pager, cwd=repo)
Exemple #19
0
def make_commit(name, skip=False):
    """
        Function to create a temporary file in current directory, and commit it using name as the commit message
        unless skip is True (in which case the commit message will have [skip] appended to the front of the commit name.
        Returns the SHA1 of the commit created.

        :param skip: [Optional] Append "[skip]" to the front of the commit message, for use in --skip-commits
    """
    run('touch {}.xml'.format(name))
    run('git add -A')
    msg = name

    if skip:
        msg = "[skip] {}".format(msg)

    run(['git', 'commit', '-m', msg])
    sha = run('git rev-parse --verify HEAD', return_output=True).strip()
    return sha
Exemple #20
0
def setup():
    extension = ".exe" if platform.system() == "Windows" else ""

    artifact_name = \
        f"dscli" \
        f"_{config.dscli_version}" \
        f"_{platform.system().lower()}" \
        f"_{'amd64' if platform.architecture()[0] == '64bit' else '386'}" \
        f".{'zip' if platform.system() == 'Windows' else 'tar.gz'}"

    response = requests.get(f"https://api.github.com/repos/darenliang/dscli/"
                            f"releases/tags/v{config.dscli_version}")

    release_info = response.json()

    if path.exists(f"{bin_folder}/dscli{extension}"):
        result = process.run([f"{bin_folder}/dscli{extension}", "-v"])
        version = result.stdout.decode()[len("dscli version "):]
        if version == config.dscli_version:
            return

    if not path.exists(bin_folder):
        os.makedirs(bin_folder)

    for asset in release_info["assets"]:
        if asset["name"] == artifact_name:
            urllib.request.urlretrieve(asset["browser_download_url"],
                                       f"{bin_folder}/{artifact_name}")
            break
    else:
        raise RuntimeError(f"Artifact not found: {artifact_name}")

    if platform.system() == "Windows":
        with zipfile.ZipFile(f"{bin_folder}/{artifact_name}", "r") as file:
            file.extractall(bin_folder)
    else:
        with tarfile.open(f"{bin_folder}/{artifact_name}", "r:gz") as file:
            file.extractall(bin_folder)

    artifact_path = pathlib.Path(f"{bin_folder}/{artifact_name}")
    artifact_path.unlink()
Exemple #21
0
def commit_logs(limit=None,
                repo=None,
                diff=False,
                show_revision=None,
                extra_args=None,
                to_pager=False):
    if show_revision:
        diff = True
        if not limit:
            limit = 1

    cmd = ['git', 'log', '--decorate']
    if show_revision:
        cmd.extend(['-U', show_revision])
    if limit:
        cmd.append('-%d' % limit)
    if diff:
        cmd.append('-c')
    if extra_args:
        cmd.extend(extra_args)

    return run(cmd, return_output=not to_pager, shell=to_pager, cwd=repo)
Exemple #22
0
    def rename_file(self):
        row_index = self.ui.tableView.currentIndex().row()
        if row_index == -1:
            return

        filename = \
            self.file_model.view[row_index][0]

        text, ok = QInputDialog.getText(self, f"Rename {filename}",
                                        "New filename:", QLineEdit.Normal,
                                        filename)
        if not ok or text == "" or text == filename:
            return

        result = process.run([config.dscli_bin, "mv", filename, text])

        if result.returncode != 0:
            message.create(QMessageBox.Warning, "Warning",
                           f"Failed to rename {filename} to {text}.").exec()
            return

        self.refresh_list()
Exemple #23
0
    def delete_file(self):
        row_index = self.ui.tableView.currentIndex().row()
        if row_index == -1:
            return

        filename = \
            self.file_model.view[row_index][0]

        reply = QMessageBox.question(self, f"Delete {filename}",
                                     f"Are you sure?",
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)

        if reply == QMessageBox.No:
            return

        result = process.run([config.dscli_bin, "rm", filename])

        if result.returncode != 0:
            message.create(QMessageBox.Warning, "Warning",
                           f"Failed to delete {filename}.").exec()
            return

        self.refresh_list()
Exemple #24
0
def test_run(capsys):
    with in_temp_dir():
        assert run('echo hello > hello.txt; echo world >> hello.txt',
                   shell=True)

        out = run('ls', return_output=True)
        assert out == 'hello.txt\n'

        out = run(['cat', 'hello.txt'], return_output=True)
        assert out == 'hello\nworld\n'

        with pytest.raises(RunError):
            run('blah')

        assert not run('blah', raises=False)

        assert silent_run('ls -l')
        out, _ = capsys.readouterr()
        assert out == ''
def test_status(wst, capsys):
    with temp_git_repo():
        wst('status')
        out, _ = capsys.readouterr()
        assert out == '# Branches: \n'

        run('git commit --allow-empty -m Dummy')
        wst('status')
        out, _ = capsys.readouterr()
        assert out == '# Branches: master\n'

        run('git checkout -b feature')
        wst('status')
        out, _ = capsys.readouterr()
        assert out == '# Branches: feature master\n'

        run('git checkout HEAD^0')
        wst('status')
        out, _ = capsys.readouterr()
        assert re.fullmatch('# Branches: \w+\* feature master\n', out)
Exemple #26
0
    def install_editable_dependencies(self, tox, env, editable_products):
        name = product_name(tox.path)
        editable_products = expand_product_groups(editable_products)

        dependencies_output = self.show_installed_dependencies(
            tox, env, return_output=True)
        if not dependencies_output:
            log.debug(
                '%s is not installed or there is no dependencies - skipping editable mode changes',
                name)
            return

        try:
            product_dependencies_list = json.loads(dependencies_output)
        except Exception as e:
            log.debug(
                'Failed to get installed dependencies - skipping editable mode changes: %s',
                e)
            return

        product_dependencies = {}

        for dep, _, path in product_dependencies_list:
            product_dependencies[dep] = path

        available_products = [os.path.basename(r) for r in product_repos()]
        libs = [
            d for d in editable_products
            if d in available_products and d in product_dependencies
            and tox.envdir(env) in product_dependencies[d]
        ]

        already_editable = [
            d for d in editable_products if d in product_dependencies
            and tox.envdir(env) not in product_dependencies[d]
        ]
        for lib in already_editable:
            click.echo('{} is already installed in editable mode.'.format(lib))

        not_dependent = [
            d for d in editable_products if d not in product_dependencies
        ]
        for lib in not_dependent:
            log.debug(
                '%s is not currently installed (not a dependency) and will be ignored.',
                lib)

        not_available = [
            d for d in editable_products
            if d not in not_dependent and d not in available_products
        ]
        for lib in not_available:
            click.echo(
                '{} is a dependency but not checked out in workspace, and so can not be installed in editable mode.'
                .format(lib))

        pip = tox.bindir(env, 'pip')

        for lib in libs:
            if not self.silent or self.debug:
                click.echo('{}: Installing {} in editable mode'.format(
                    env, lib))

            with log_exception(
                    'An error occurred when installing %s in editable mode' %
                    lib):
                run([pip, 'uninstall', lib, '-y'],
                    raises=False,
                    silent=not self.debug)

                lib_path = product_path(lib)
                if os.path.exists(os.path.join(lib_path, lib, 'setup.py')):
                    lib_path = os.path.join(lib_path, lib)
                run([pip, 'install', '--editable', lib_path],
                    silent=not self.debug)
Exemple #27
0
def stat_repo(path=None, return_output=False, with_color=False):
    if with_color:
        cmd = 'git -c color.status=always status'
    else:
        cmd = 'git status'
    return run(cmd, cwd=path, return_output=return_output)
Exemple #28
0
def diff_branch(right_branch, left_branch='master', path=None):
    cmd = 'git log %s..%s' % (left_branch, right_branch)

    return run(cmd, cwd=path, return_output=True)
Exemple #29
0
    def show_installed_dependencies(self, tox, env, return_output=False, filter_name=None):
        script_template = """
import json
import os
import sys

try:
    from pip._internal.utils.misc import get_installed_distributions

# pip < 10
except Exception:
    from pip import get_installed_distributions

# Required params to run this script
package = '%s'
json_output = %s
env = '%s'
filter_name = '%s'

cwd = os.getcwd()
workspace_dir = os.path.dirname(cwd)

try:
    libs = [(p.key, p.version, p.location) for p in get_installed_distributions()]
except Exception as e:
    print(e)
    sys.exit(1)

output = []

if not json_output:
    print(env + ':')

def strip_cwd(dir):
    if dir.startswith(cwd + '/'):
        dir = dir[len(cwd):].lstrip('/')
    elif dir.startswith(workspace_dir):
        dir = os.path.join('..', dir[len(workspace_dir):].lstrip('/'))
    return dir

for lib, version, location in sorted(libs):
    if filter_name and filter_name not in lib:
        continue
    if json_output:
        output.append((lib, version, location))
    else:
        output.append('  %%-25s %%-10s  %%s' %% (lib, version, strip_cwd(location)))

if json_output:
    print(json.dumps(output))
else:
    print('\\n'.join(output))
    """

        name = product_name(tox.path)
        filter_name = isinstance(filter_name, str) and filter_name or ''
        script = script_template % (name, return_output, env, filter_name)

        python = tox.bindir(env, 'python')

        if not os.path.exists(python):
            log.error('Test environment %s is not installed. Please run without -d / --show-dependencies to install it first.', env)
            sys.exit(1)

        return run([python, '-c', script], return_output=return_output, raises=False)
Exemple #30
0
def install(build_dir):
    args = ['install']
    return process.run('make', args, build_dir)
Exemple #31
0
def test_publish(wst, monkeypatch):
    silent_run_mock = Mock()
    config_mock = Mock()
    monkeypatch.setattr('workspace.commands.publish.LocalConfig', config_mock)
    monkeypatch.setattr('workspace.commands.publish.silent_run',
                        silent_run_mock)
    monkeypatch.setattr('workspace.commands.publish.run', silent_run_mock)

    config_mock().get.side_effect = ['repo', 'user', 'pass'] * 10

    with temp_git_repo() as cwd:
        wst('setup --product')

        # Patch release
        run('git commit --allow-empty -m change1')
        run('git commit --allow-empty -m change2')

        wst('publish')

        changes = open('docs/CHANGELOG.rst').read()
        assert changes == """\
Version 0.0.1
================================================================================

* change2
* change1
"""

        setup_py = open('setup.py').read().split('\n')
        assert setup_py[5] == "    version='0.0.2',"

        python = Path('~/.virtualenvs').expanduser() / Path(
            cwd).name / 'bin' / 'python'

        repo_path = '/private' + str(cwd)
        assert silent_run_mock.call_args_list == [
            call('rm -rf dist/*', cwd=repo_path, shell=True),
            call(f'{python} setup.py sdist bdist_wheel', cwd=repo_path),
            call('twine upload -r "pypi" -u "user" -p "pass" dist/*',
                 cwd=repo_path,
                 shell=True,
                 silent=2)
        ]

        # No changes
        with pytest.raises(SystemExit):
            wst('publish')

        # Minor release
        run('git commit --allow-empty -m feature1')

        wst('publish --minor')

        assert 'Bump minor version' in commit_logs()

        changes = open('docs/CHANGELOG.rst').read()
        print(changes)
        assert changes == """\
Version 0.1.0
================================================================================

* feature1

Version 0.0.1
================================================================================

* change2
* change1
"""
        setup_py = open('setup.py').read().split('\n')
        assert setup_py[5] == "    version='0.1.1',"

        # Major release
        run('git commit --allow-empty -m feature2')

        wst('publish --major')

        assert 'Bump major version' in commit_logs()

        changes = open('docs/CHANGELOG.rst').read()
        print(changes)
        assert changes == """\
Version 1.0.0
================================================================================

* feature2

Version 0.1.0
================================================================================

* feature1

Version 0.0.1
================================================================================

* change2
* change1
"""
        setup_py = open('setup.py').read().split('\n')
        assert setup_py[5] == "    version='1.0.1',"

        # Already published patch version will bump before publish
        run('git commit --allow-empty -m "Publish version 1.0.1"', shell=True)
        run('git commit --allow-empty -m bugfix1')

        wst('publish')

        changes = open('docs/CHANGELOG.rst').read()
        assert changes == """\
Version 1.0.2
================================================================================

* bugfix1

Version 1.0.0
--------------------------------------------------------------------------------

* feature2

Version 0.1.0
================================================================================

* feature1

Version 0.0.1
================================================================================

* change2
* change1
"""

        setup_py = open('setup.py').read().split('\n')
        assert setup_py[5] == "    version='1.0.3',"
Exemple #32
0
def temp_remote_git_repo():
    with temp_dir() as tmpdir:
        run('git clone https://github.com/maxzheng/remoteconfig.git')
        repo_dir = tmpdir / 'remoteconfig'
        os.chdir(repo_dir)
        yield repo_dir
Exemple #33
0
def test_merge_branch_with_whitelist(wst, capsys):
    config.merge.branches = '1.0.x 2.0.x 3.0.x master'

    with temp_git_repo():
        # Dummy commit
        run('git commit --allow-empty -m dummy-commit')

        run('git checkout -b 3.0.x')
        run('touch temp.xml')
        run('git add -A')
        # Commit 1
        run('git commit -m  [skip]')

        # commit 2
        run('touch temp2.xml')
        run('git add -A')
        run('git commit -m  commit2')

        run('git checkout master')

        wst('merge 3.0.x --skip-commits \'skip\' \'space separated example\'')

        changes = run('git log --oneline', return_output=True)
        # Change should have been in the log entry
        assert 'Merge branch \'3.0.x\'' in changes
        assert '[skip]' in changes
        assert 'commit2' in changes

    out, _ = capsys.readouterr()
    assert out.split('\n')[0] == 'Merging 3.0.x into master'
Exemple #34
0
def stat_repo(path=None, return_output=False, with_color=False):
    if with_color:
        cmd = 'git -c color.status=always status'
    else:
        cmd = 'git status'
    return run(cmd, cwd=path, return_output=return_output)
Exemple #35
0
def diff_branch(right_branch, left_branch='master', path=None):
    cmd = 'git log %s..%s' % (left_branch, right_branch)

    return run(cmd, cwd=path, return_output=True)
Exemple #36
0
def install(build_dir):
    args = ['install']
    return process.run('make', args, build_dir)
def test_publish(wst, monkeypatch):
    silent_run_mock = Mock()
    config_mock = Mock()
    monkeypatch.setattr('workspace.commands.publish.LocalConfig', config_mock)
    monkeypatch.setattr('workspace.commands.publish.silent_run', silent_run_mock)
    monkeypatch.setattr('workspace.commands.publish.run', silent_run_mock)

    config_mock().get.side_effect = ['repo', 'user', 'pass'] * 10

    with temp_git_repo() as cwd:
        wst('setup --product')

        # Patch release
        run('git commit --allow-empty -m change1')
        run('git commit --allow-empty -m change2')

        wst('publish')

        changes = open('docs/CHANGELOG.rst').read()
        assert changes == """\
Version 0.0.1
================================================================================

* change2
* change1
"""

        setup_py = open('setup.py').read().split('\n')
        assert setup_py[5] == "    version='0.0.2',"

        python = Path('~/.virtualenvs').expanduser() / Path(cwd).name / 'bin' / 'python'

        assert silent_run_mock.call_args_list == [
            call('rm -rf dist/*', cwd=str(cwd), shell=True),
            call(f'{python} setup.py sdist bdist_wheel', cwd=str(cwd)),
            call('twine upload -r "pypi" -u "user" -p "pass" dist/*', cwd=str(cwd), shell=True, silent=2)]

        # No changes
        with pytest.raises(SystemExit):
            wst('publish')

        # Minor release
        run('git commit --allow-empty -m feature1')

        wst('publish --minor')

        assert 'Bump minor version' in commit_logs()

        changes = open('docs/CHANGELOG.rst').read()
        print(changes)
        assert changes == """\
Version 0.1.0
================================================================================

* feature1

Version 0.0.1
================================================================================

* change2
* change1
"""
        setup_py = open('setup.py').read().split('\n')
        assert setup_py[5] == "    version='0.1.1',"

        # Major release
        run('git commit --allow-empty -m feature2')

        wst('publish --major')

        assert 'Bump major version' in commit_logs()

        changes = open('docs/CHANGELOG.rst').read()
        print(changes)
        assert changes == """\
Version 1.0.0
================================================================================

* feature2

Version 0.1.0
================================================================================

* feature1

Version 0.0.1
================================================================================

* change2
* change1
"""
        setup_py = open('setup.py').read().split('\n')
        assert setup_py[5] == "    version='1.0.1',"

        # Already published patch version will bump before publish
        run('git commit --allow-empty -m "Publish version 1.0.1"', shell=True)
        run('git commit --allow-empty -m bugfix1')

        wst('publish')

        changes = open('docs/CHANGELOG.rst').read()
        assert changes == """\
Version 1.0.2
================================================================================

* bugfix1

Version 1.0.0
--------------------------------------------------------------------------------

* feature2

Version 0.1.0
================================================================================

* feature1

Version 0.0.1
================================================================================

* change2
* change1
"""

        setup_py = open('setup.py').read().split('\n')
        assert setup_py[5] == "    version='1.0.3',"
Exemple #38
0
def run(source, dest, install_prefix):
    args = [source, '-DCMAKE_INSTALL_PREFIX={}'.format(install_prefix)]
    return process.run('cmake', args, dest)
Exemple #39
0
def hard_reset(to_commit):
    run(['git', 'reset', '--hard', to_commit])
Exemple #40
0
def hard_reset(to_commit):
    run(['git', 'reset', '--hard', to_commit])
Exemple #41
0
    def run(self):
        if self.minor and self.major:
            log.error('--minor and --major are mutually exclusive, please use only one.')
            return

        repo_check()

        pypirc = LocalConfig('~/.pypirc')
        repository = pypirc.get(self.repo, 'repository')
        username = pypirc.get(self.repo, 'username')
        password = pypirc.get(self.repo, 'password')
        repo_title = 'PyPI' if self.repo == 'pypi' else self.repo.title()

        if not repository:
            log.error('Please add repository / username to [%s] section in ~/.pypirc', self.repo)
            sys.exit(1)

        if not username:
            username = getpass.getuser('{} Username: '******'{} Password: '******'update')

        published_version, changes = self.changes_since_last_publish()

        if not changes:
            click.echo('There are no changes since last publish')
            sys.exit(0)

        silent_run('rm -rf dist/*', shell=True, cwd=repo_path())

        if self.major or self.minor:
            new_version, setup_file = self.bump_version(major=self.major, minor=self.minor)
            major_minor = 'major' if self.major else 'minor'
            self.commander.run('commit', msg=f'Bump {major_minor} version', files=[setup_file], push=2,
                               skip_style_check=True)

        else:
            current_version, setup_file = self.get_version()

            # Previously, we publish the current version in setup.py, so need to bump it first before
            # we can publish a new version.
            if published_version == current_version:
                new_version, setup_file = self.bump_version()
            else:
                new_version = current_version

        changelog_file = self.update_changelog(new_version, changes, self.minor or self.major)

        tox = ToxIni()
        envs = [e for e in tox.envlist if e != 'style']

        if envs:
            env = envs[0]
            if len(envs) > 1:
                log.debug('Found multiple default envs in tox.ini, will use first one to build: %s', env)

        else:
            click.echo('Odd, there are no default envs in tox.ini, so we can not build.')
            sys.exit(1)

        envdir = tox.envdir(env)
        python = os.path.join(envdir, 'bin', 'python')

        click.echo('Building source/built distribution')

        silent_run(f'{python} setup.py sdist bdist_wheel', cwd=repo_path())

        click.echo('Uploading to ' + repo_title)

        try:
            run('twine upload -r "{repo}" -u "{username}" -p "{password}" dist/*'.format(
                repo=self.repo,
                username=username,
                password=password), shell=True, cwd=repo_path(), silent=2)

        except Exception:
            sys.exit(1)

        self.bump_version()
        self.commander.run('commit', msg=PUBLISH_VERSION_PREFIX + new_version, push=2,
                           files=[setup_file, changelog_file],
                           skip_style_check=True)
def test_cleanrun(wst):
    config.clean.remove_products_older_than_days = 30

    with temp_dir():
        repos = ['repo', 'old_repo', 'old_repo_dirty']
        run('touch file; mkdir ' + ' '.join(repos), shell=True)
        for repo in repos:
            run('cd {}; git init; git commit --allow-empty -m "Initial commit"'.format(repo), shell=True)
            if repo.startswith('old'):
                run('touch -t 200001181205.09 ' + repo)
        run('cd old_repo_dirty; touch new_file', shell=True)
        run('ls -l')
        wst('clean')

        assert os.listdir() == ['old_repo_dirty', 'repo', 'file']

    with temp_git_repo():
        run('touch hello.py hello.pyc')
        wst('clean')

        assert os.listdir() == ['.git', 'hello.py']
Exemple #43
0
def remove_branch(branch, raises=False, remote=False, force=False):
    """ Removes branch """
    run(['git', 'branch', '-D' if force else '-d', branch], raises=raises)

    if remote:
        silent_run(['git', 'push', default_remote(), '--delete', branch], raises=raises)
Exemple #44
0
    def run(self):
        if self.minor and self.major:
            log.error('--minor and --major are mutually exclusive, please use only one.')
            return

        repo_check()

        pypirc = LocalConfig('~/.pypirc')
        repository = pypirc.get(self.repo, 'repository')
        username = pypirc.get(self.repo, 'username')
        password = pypirc.get(self.repo, 'password')
        repo_title = 'PyPI' if self.repo == 'pypi' else self.repo.title()

        if not repository:
            log.error('Please add repository / username to [%s] section in ~/.pypirc', self.repo)
            sys.exit(1)

        if not username:
            username = getpass.getuser('{} Username: '******'{} Password: '******'update')

        published_version, changes = self.changes_since_last_publish()

        if not changes:
            click.echo('There are no changes since last publish')
            sys.exit(0)

        silent_run('rm -rf dist/*', shell=True, cwd=repo_path())

        if self.major or self.minor:
            new_version, setup_file = self.bump_version(major=self.major, minor=self.minor)
            major_minor = 'major' if self.major else 'minor'
            self.commander.run('commit', msg=f'Bump {major_minor} version', files=[setup_file], push=2,
                               skip_style_check=True)

        else:
            current_version, setup_file = self.get_version()

            # Previously, we publish the current version in setup.py, so need to bump it first before
            # we can publish a new version.
            if published_version == current_version:
                new_version, setup_file = self.bump_version()
            else:
                new_version = current_version

        changelog_file = self.update_changelog(new_version, changes, self.minor or self.major)

        tox = ToxIni()
        envs = [e for e in tox.envlist if e != 'style']

        if envs:
            env = envs[0]
            if len(envs) > 1:
                log.debug('Found multiple default envs in tox.ini, will use first one to build: %s', env)

        else:
            click.echo('Odd, there are no default envs in tox.ini, so we can not build.')
            sys.exit(1)

        envdir = tox.envdir(env)
        python = os.path.join(envdir, 'bin', 'python')

        click.echo('Building source/built distribution')

        silent_run(f'{python} setup.py sdist bdist_wheel', cwd=repo_path())

        click.echo('Uploading to ' + repo_title)

        try:
            run('twine upload -r "{repo}" -u "{username}" -p "{password}" dist/*'.format(
                repo=self.repo,
                username=username,
                password=password), shell=True, cwd=repo_path(), silent=2)

        except Exception:
            sys.exit(1)

        self.bump_version()
        self.commander.run('commit', msg=PUBLISH_VERSION_PREFIX + new_version, push=2, files=[setup_file, changelog_file],
                           skip_style_check=True)
Exemple #45
0
    def run(self):
        if self.test_dependents:
            name = product_name()

            # Convert None to list for tuple([])
            if not self.env_or_file:
                self.env_or_file = []
            if not self.extra_args:
                self.extra_args = []

            test_args = (
              ('env_or_file', tuple(self.env_or_file)),
              ('return_output', True),
              ('num_processes', self.num_processes),
              ('silent', True),
              ('debug', self.debug),
              ('extra_args', tuple(self.extra_args))
            )

            test_repos = [repo_path()]
            test_repos.extend(r for r in repos(workspace_path()) if self.product_depends_on(r, name) and r not in test_repos)
            test_args = [(r, test_args, self.__class__) for r in test_repos]

            def test_done(result):
                name, output = result
                success, summary = self.summarize(output)

                if success:
                    click.echo('{}: {}'.format(name, summary))

                else:
                    temp_output_file = os.path.join(tempfile.gettempdir(), 'test-%s.out' % name)
                    with open(temp_output_file, 'w') as fp:
                        fp.write(output)
                    temp_output_file = 'See ' + temp_output_file

                    log.error('%s: %s', name, '\n\t'.join([summary, temp_output_file]))

            def show_remaining(completed, all_args):
                completed_repos = set(product_name(r) for r, _, _ in completed)
                all_repos = set(product_name(r) for r, _, _ in all_args)
                remaining_repos = sorted(list(all_repos - completed_repos))
                if len(remaining_repos):
                    repo = remaining_repos.pop()
                    more = '& %d more' % len(remaining_repos) if remaining_repos else ''
                    return '%s %s' % (repo, more)
                else:
                    return 'None'

            repo_results = parallel_call(test_repo, test_args, callback=test_done, show_progress=show_remaining, progress_title='Remaining')

            for result in list(repo_results.values()):
                if isinstance(result, tuple):
                    _, result = result
                success, _ = self.summarize(result)
                if not (success or self.return_output):
                    sys.exit(1)

            return dict(list(repo_results.values()))

        if not self.repo:
            self.repo = project_path()

        # Strip out venv bin path to python to avoid issues with it being removed when running tox
        if 'VIRTUAL_ENV' in os.environ:
            venv_bin = os.environ['VIRTUAL_ENV']
            os.environ['PATH'] = os.pathsep.join([p for p in os.environ['PATH'].split(os.pathsep)
                                                  if os.path.exists(p) and not p.startswith(venv_bin)])

        envs = []
        files = []

        if self.env_or_file:
            for ef in self.env_or_file:
                if os.path.exists(ef):
                    files.append(os.path.abspath(ef))
                else:
                    envs.append(ef)

        pytest_args = ''
        if self.match_test or self.num_processes is not None or files or self.extra_args:
            pytest_args = []
            if self.match_test:
                pytest_args.append('-k ' + self.match_test)
                if self.num_processes is None:  # Skip parallel for targeted test run / works better with pdb
                    self.num_processes = 0
            if self.num_processes is not None:
                pytest_args.append('-n ' + str(self.num_processes))
            if self.extra_args:
                pytest_args.extend(self.extra_args)
            if files:
                pytest_args.extend(files)
            pytest_args = ' '.join(pytest_args)
            os.environ['PYTESTARGS'] = pytest_args

        tox = ToxIni(self.repo, self.tox_ini)

        if not envs:
            envs = tox.envlist

            # Prefer 'test' over 'cover' when there are pytest args as cover is likely to fail and distract from
            # test results. And also remove style as user is focused on fixing a test, and style for the whole project
            # isn't interesting yet.
            if pytest_args:
                if 'cover' in envs:
                    python = tox.get(tox.envsection('cover'), 'basepython')
                    version = ''.join(python.strip('python').split('.')) if python else '36'
                    envs[envs.index('cover')] = 'py' + version
                if 'style' in envs:
                    envs.remove('style')

        env_commands = {}

        if self.install_only and not self.redevelop:
            self.redevelop = 1

        if self.show_dependencies:
            if 'style' in envs:
                envs.remove('style')
            for env in envs:
                self.show_installed_dependencies(tox, env, filter_name=self.show_dependencies)

        elif self.install_editable:
            if 'style' in envs:
                envs.remove('style')
            for env in envs:
                if len(envs) > 1:
                    print(env + ':')
                self.install_editable_dependencies(tox, env, editable_products=self.install_editable)

        elif self.redevelop:
            if self.tox_cmd:
                cmd = self.tox_cmd
            else:
                cmd = ['tox', '-c', tox.tox_ini]

            if envs:
                cmd.extend(['-e', ','.join(envs)])

            if self.redevelop > 1:
                cmd.append('-r')

            if self.install_only:
                cmd.append('--notest')

            output = run(cmd, cwd=self.repo, raises=not self.return_output, silent=self.silent, return_output=self.return_output)

            if not output:
                if self.return_output:
                    return False
                else:
                    sys.exit(1)

            for env in envs:
                env_commands[env] = ' '.join(cmd)

                # Touch envdir
                envdir = tox.envdir(env)
                if os.path.exists(envdir):
                    os.utime(envdir, None)

                # Strip entry version
                self._strip_version_from_entry_scripts(tox, env)

            if self.return_output:
                return output

        else:
            for env in envs:
                envdir = tox.envdir(env)

                def requirements_updated():
                    req_mtime = 0
                    requirements_files = ['requirements.txt', 'pinned.txt', 'tox.ini']
                    for req_file in requirements_files:
                        req_path = os.path.join(self.repo, req_file)
                        if os.path.exists(req_path):
                            req_mtime = max(req_mtime, os.stat(req_path).st_mtime)
                    return req_mtime > os.stat(envdir).st_mtime

                if not os.path.exists(envdir) or requirements_updated():
                    env_commands.update(
                        self.commander.run('test', env_or_file=[env], repo=self.repo, redevelop=True, tox_cmd=self.tox_cmd,
                                           tox_ini=self.tox_ini, tox_commands=self.tox_commands, match_test=self.match_test,
                                           num_processes=self.num_processes, silent=self.silent,
                                           debug=self.debug, extra_args=self.extra_args))
                    continue

                commands = self.tox_commands.get(env) or tox.commands(env)
                env_commands[env] = '\n'.join(commands)

                for command in commands:
                    full_command = os.path.join(envdir, 'bin', command)

                    command_path = full_command.split()[0]
                    if os.path.exists(command_path):
                        if 'pytest' in full_command or 'py.test' in full_command:
                            if 'PYTESTARGS' in full_command:
                                full_command = full_command.replace('{env:PYTESTARGS:}', pytest_args)
                            else:
                                full_command += ' ' + pytest_args
                        activate = '. ' + os.path.join(envdir, 'bin', 'activate')
                        output = run(activate + '; ' + full_command, shell=True, cwd=self.repo, raises=False, silent=self.silent,
                                     return_output=self.return_output)
                        if not output:
                            if self.return_output:
                                return False
                            else:
                                sys.exit(1)

                        if not self.silent and (len(envs) > 1 or env == 'style'):
                            click.secho(f'{env}: OK', fg='green')

                        if self.return_output:
                            return output
                    else:
                        log.error('%s does not exist', command_path)
                        if self.return_output:
                            return False
                        else:
                            sys.exit(1)

        return env_commands