Exemplo n.º 1
0
    def branches(self):
        '''
        Collects all branches of the repository

        :returns: All branches
        :rtype: :class:`GitBranches`

        Signals current branch and a list of all other branches.
        '''
        res = dict(current=None, all=[])
        cmd = Command('git branch', cwd=self.location)
        if cmd():
            for elem in cmd.out:
                if '*' in elem:
                    elem = elem.replace('*', '')
                    res['current'] = elem.strip()
                res['all'].append(elem.strip())

        if res['current'] is None:
            cmd = Command('git symbolic-ref --short HEAD', cwd=self.location)
            if cmd():
                res['current'] = cmd.stdout
                res['all'].append(cmd.stdout)

        return GitBranches(**res)
Exemplo n.º 2
0
    def __call__(
            self,
            temp_branch_name=None, push_branch_name=None, remote_name=None
    ):
        '''
        Does a :meth:`cleanup <cleanup>` and tries to push afterwards.
        Will not push if something goes wrong with
        the :meth:`cleanup <cleanup>`.

        :param temp_branch_name: Name of the temporary branch
                                 (see :meth:`scrub`)
        :param push_branch_name: Name of the branch to push into.
                                 Will be set to class wide *master_branch* if
                                 set to ``None``
        :param remote_name: Name of the remote to pull from
                            (see :meth:`cleanup`)

        :returns: ``True`` if everything went well, ``False`` otherwise
        '''
        if push_branch_name is None:
            push_branch_name = self.master_branch
        if remote_name is None:
            remote_name = self.remote_name

        if not self.cleanup(
                branch_name=temp_branch_name,
                remote_name=remote_name
        ):
            return False

        cmd = Command('git push -u "{}" "{}"'.format(
            remote_name, push_branch_name
        ), cwd=self.location)
        return cmd()
Exemplo n.º 3
0
    def cleanup(self, branch_name=None, remote_name=None):
        '''
        Uses :meth:`scrub` to form a new commit and pulls afterwards.

        :param branch_name: Name of the temporary branch (see :meth:`scrub`)
        :param remote_name: Name of the remote to pull from. For best results
                            this should be some part of :meth:`remote_names`.
                            If left blank, class wide *remote_name* is taken.

        :returns: ``True`` on success, ``False`` otherwise
        '''
        if not self.scrub(branch_name=branch_name):
            return False

        if remote_name is None:
            remote_name = self.remote_name

        cmd = Command('git pull --tags "{}"'.format(
            remote_name
        ), cwd=self.location)
        if not cmd():
            if 'conflict' in cmd.stdout.lower():
                self._log.error(
                    'conflict detected while pulling from "%s" into "%s"',
                    remote_name, self.location
                )
            return False

        return True
Exemplo n.º 4
0
def test_cmd_cat_stdin():
    content = 'test test'
    res = Command('cat', cin=content)
    assert res() is True
    assert res.stderr == ''
    assert res.err == []
    assert res.stdout == content
    assert res.out == [content]
Exemplo n.º 5
0
def test_cmd_log_init(caplog):
    caplog.set_level(DEBUG)
    Command('echo')
    assert len(caplog.records) == 1

    rec = caplog.records[-1]
    assert rec.levelno == DEBUG
    assert 'command initialized:' in rec.msg
    assert 'echo' in rec.args[-1]
Exemplo n.º 6
0
    def tag(self, name):
        '''
        Stick tags onto commits.

        :param name: Tag name
        :returns: ``True`` if successful else ``False``
        '''
        cmd = Command('git tag "{}"'.format(name), cwd=self.location)
        return cmd()
Exemplo n.º 7
0
    def initialize(self, remote_url=None):
        '''
        Is called from inside :meth:`__init__` to prepare the repository.
        Checks :attr:`is_repo` first to bail out early.
        If no *remote_url* is given a new repository is initialized.
        Otherwise a clone from the *remote_url* is attempted.
        '''
        if self.is_repo:
            return True

        if remote_url is not None:
            cmd = Command('git clone "{}" -o "{}" .'.format(
                remote_url, self.remote_name
            ), cwd=self.location)
            return cmd()

        cmd = Command('git init', cwd=self.location)
        return cmd()
Exemplo n.º 8
0
def test_cmd_log_failed(caplog):
    caplog.set_level(ERROR)
    res = Command('this-is-not-a-command')
    assert not caplog.records
    res()
    assert len(caplog.records) == 1

    rec = caplog.records[-1]
    assert rec.levelno == ERROR
    assert 'command failed:' in rec.msg
    assert 'this-is-not-a-command' in rec.args[-1]
Exemplo n.º 9
0
def test_cmd_log_success(caplog):
    caplog.set_level(INFO)
    res = Command('echo')
    assert not caplog.records
    res()
    assert len(caplog.records) == 1

    rec = caplog.records[-1]
    assert rec.levelno == INFO
    assert 'command success:' in rec.msg
    assert 'echo' in rec.args[-1]
Exemplo n.º 10
0
    def scrub(self, branch_name=None):
        '''
        Uses :meth:`mutate` to handle all changes and commits them into
        a temporary branch. Will merge the branches back into the original
        branch afterwards.

        :param branch_name: Name of the temporary branch.
                            Will use the :func:`current hostname
                            <git_sh_sync.util.host.get_hostname>`
                            if left blank.
        :returns: ``True`` if everything went well (or there is nothing to do),
                  ``False`` otherwise
        '''
        if self.status.clean:
            return True

        branches = self.branches()
        hostname = get_hostname(short=True)
        if branch_name is None:
            branch_name = hostname

        self.checkout(branch_name)

        if not self.mutate():
            self._log.warning(
                'problems discovered, will not continue to clean "%s"',
                self.location
            )
            return False

        cmd = Command('git commit --message="{} auto commit"'.format(
            hostname
        ), cwd=self.location)
        cmd()

        self.checkout(branches.current)

        cmd = Command('git merge "{}" --message="{} auto merge"'.format(
            branch_name, hostname
        ), cwd=self.location)
        return cmd()
Exemplo n.º 11
0
    def remote_names(self):
        '''
        Emit names of the remotes.
        Do not confuse this property with the *remote_name*, which acts as
        a default value for cloning or pushing actions.

        :returns: Remote names
        :rtype: list
        '''
        cmd = Command('git remote show -n', cwd=self.location)
        cmd()
        return cmd.out
Exemplo n.º 12
0
def test_cmd_no_double():
    res = Command('echo')
    assert res.success is False
    assert res.launched is False

    assert res() is True
    assert res.success is True
    assert res.launched is True

    assert res() is False
    assert res.success is True
    assert res.launched is True
Exemplo n.º 13
0
def test_cmd_error():
    res = Command('this-is-not-a-command')
    assert res.code is None
    assert res.success is False
    assert res.launched is False

    assert res() is False
    assert res.code is None
    assert res.success is False
    assert res.launched is True

    assert isinstance(res.exc, OSError)
Exemplo n.º 14
0
    def tags(self):
        '''
        Query existing tags.

        :returns: Name of tags, newest first
        :rtype: list
        '''
        cmd = Command(
            'git tag --list --sort="-version:refname"',
            cwd=self.location
        )
        cmd()
        return cmd.out
Exemplo n.º 15
0
def test_cmd_ls_cwd(rootdir):
    files = ('makefile', 'README.rst', 'requirements.txt')
    res = Command('ls -1', cwd=rootdir.root)
    assert res() is True
    assert res.cmd == ['ls', '-1']
    assert res.cwd == rootdir.root
    assert res.code == 0
    assert res.success is True
    assert res.stderr == ''
    assert res.err == []
    for name in files:
        assert name in res.stdout
        assert name in res.out
Exemplo n.º 16
0
def test_cmd_echo():
    content = 'test test'
    res = Command('echo "{}"'.format(content))
    assert res() is True
    assert res.cmd == ['echo', content]
    assert res.cwd is None
    assert res.cin is None
    assert res.exc is None
    assert res.code == 0
    assert res.out == [content]
    assert res.stdout == content
    assert res.err == []
    assert res.stderr == ''
    assert res.success is True
    assert res.launched is True
Exemplo n.º 17
0
    def remote_url(self, remote=None):
        '''
        Retrieve URL of remote by name.

        :param remote: Remote name
        :returns: The URL as String or ``None`` if nothing was found
        '''
        if remote is None:
            remote = self.remote_name

        cmd = Command(
            'git remote get-url --push "{}"'.format(remote), cwd=self.location
        )
        if cmd():
            return cmd.stdout
        return None
Exemplo n.º 18
0
    def log(self, num=-1):
        '''
        Retrieve log of repository

        :param num: Limit length of output. Use negative for unlimited output.
        :returns: Log entries containing short-, full-hash and commit message.
        :rtype: list of :class:`GitLog`
        '''
        result = []
        cmd = Command('git log --max-count {} --format="{}"'.format(
            num, GIT_DIVIDER.join(['%h', '%H', '%B'])
        ), cwd=self.location)
        if cmd():
            for elem in (el for el in cmd.out if el):
                short, full, message = elem.split(GIT_DIVIDER)
                result.append(GitLog(short=short, full=full, message=message))
        return result
Exemplo n.º 19
0
    def checkout(self, treeish=None):
        '''
        Checkout a commit, tag or branch.

        :param treeish: Commit (short or full), tag or branch.
                        If left blank, *master_branch* is assumed
        :returns: ``True`` if successful else ``False``

        If *treeish* is neither a known commit, tag or branch, a new branch
        is created.
        '''
        if treeish is None:
            treeish = self.master_branch

        def is_known():
            '''
            Helper to optimize detection if *treeish* is a known
            tag, branch or commit.
            '''
            if treeish in self.tags:
                return True

            branches = self.branches()
            for branch in branches.all:
                if treeish in branch:
                    return True

            for log in self.log():
                if treeish in log.short:
                    return True
                if treeish in log.full:
                    return True
            return False

        line = (
            'git checkout "{}"' if is_known() else 'git checkout -b "{}"'
        ).format(treeish)

        cmd = Command(line, cwd=self.location)
        return cmd()
Exemplo n.º 20
0
    def status(self):
        '''
        Determines current status of the repository.

        :returns: Current status
        :rtype: :class:`GitStatus`

        Generates lists of changed files according to matching state.
        '''
        symbols = dict(
            conflicting='U', deleted='D', modified='M', untracked='?'
        )
        res = dict((key, []) for key in symbols)

        cmd = Command('git status --porcelain', cwd=self.location)
        if cmd():
            for elem in cmd.out:
                sym, _, tail = elem.partition(' ')
                for key, state in symbols.items():
                    if state in sym:
                        res[key].append(tail.strip())

        return GitStatus(**res, clean=not any(res.values()))
Exemplo n.º 21
0
 def add(elem):
     '''Helper to run git add onto one element'''
     cmd = Command('git add "{}"'.format(elem), cwd=self.location)
     return cmd()
Exemplo n.º 22
0
 def remove(elem):
     '''Helper to run git rm onto one element'''
     cmd = Command('git rm "{}"'.format(elem), cwd=self.location)
     return cmd()
Exemplo n.º 23
0
 def init(cmd, **kwargs):
     return Command(cmd, **kwargs)
Exemplo n.º 24
0
 def is_repo(self):
     '''
     Verifies if current :class:`Repository` is indeed a git repository.
     '''
     cmd = Command('git rev-parse --show-toplevel', cwd=self.location)
     return cmd() and cmd.stdout == self.location