Ejemplo n.º 1
0
    def merge_branches(self,
                       branch,
                       to_branch,
                       one_way=True,
                       working_dir='var/release'):

        if one_way is False:
            # first  merge to branch into the working branch
            out(
                1,
                blue("Pulling from {} and merging into {}".format(
                    to_branch, branch)))
            output = self.gitutils.git_merge_all(to_branch, branch.working_dir)

            if output is False:
                raise Exception("Aborting!! Could not run shell command :(")

        # Merge the from branch into the destination branch
        out(
            1,
            blue("Pulling from {} and merging into {}".format(
                branch, to_branch)))
        output = self.gitutils.git_merge_all(branch, to_branch, working_dir)

        if output is False:
            raise Exception("Aborting!! Could not run shell command :(")

        return True
Ejemplo n.º 2
0
    def main(self):
        """Parse arguments and then call the appropriate function(s)."""

        parser = argparse.ArgumentParser(
            description="""Merge one branch (-b) to another (-t)""")

        parser.add_argument('-b',
                            '--branch',
                            nargs='?',
                            metavar="branch",
                            required=True,
                            help="""branch to merge from""")

        parser.add_argument('-t',
                            '--to_branch',
                            nargs='?',
                            metavar="to_branch",
                            required=True,
                            help="""branch to merge into""")

        parser.add_argument(
            '-o',
            '--one-way',
            nargs='?',
            metavar="one_way",
            required=False,
            default="True",
            help="""Merge branch one way, or both ways if False""")

        parser.add_argument('-w',
                            '--working-dir',
                            nargs='?',
                            metavar="working_dir",
                            required=False,
                            default=None,
                            help="""Working Directory (to stage the merge)""")

        args = parser.parse_args()

        if args.working_dir is None:
            args.working_dir = self.default_working_dir

        try:
            self.merge_branches(args.branch, args.to_branch, args.one_way,
                                args.working_dir)

        except Exception as e:
            out(0, red(e))
Ejemplo n.º 3
0
    def main(self):
        """Parse arguments and then call the appropriate function(s)."""

        parser = argparse.ArgumentParser(description="""Pull multiple Git Repositories at once, on multiple servers.""")

        parser.add_argument('-p', '--path', nargs="*", metavar="path", default=None,
                            help="""update all repositories under this directory / path (or the directory itself,
                            if the given directory corresponds to a repo. eg. -p ots /srv/salt )""")

        parser.add_argument('-b', '--branch', metavar="branch", nargs='?', default=None,
                            help="""check the repo out on the specified branch if it's not on this branch yet.""")

        parser.add_argument('-f', '--force', nargs='?', default=False, metavar="force pull/checkout",
                            help="""force checkout / pull (discard local changes) if we're changing branches.""")

        parser.add_argument('-a', '--all', nargs='?', default=False, metavar="recurse through all directories",
                            help="""Recurse through all subdirectories to find git repos.""")

        parser.add_argument('-r', '--remote', nargs='?', default=None, metavar="remote location for gpull_local.py",
                            help="""Remote location of gpull_local.py, eg /usr/local/bin/gpull_local.py """)

        # get all aliases and sort them for help convenience
        all_aliases = sorted(
            list(self.server_aliases.keys()) +
            list(self.group_aliases.keys())
        )

        parser.add_argument('-s', '--servers', nargs="*", metavar="servers", default=None,
                            help="A list of server aliases to update. \n "
                                 "List of all available server aliases: {}".format(", ".join(all_aliases)))

        parser.add_argument('-u', '--remote-user', nargs='?', default=None, metavar="your ssh username",
                            help="""ssh into into git server with this user""")

        args = parser.parse_args()

        out(0, (yellow(bold("gpull") + ": remotely pull git repos")))

        if args.servers is not None:
            pw = getpass.getpass("Your ssh password:")  # Prompt user for ssh password
        else:
            pw = None  # No password needed to update your local folders

        gitutils = git_utils.GitUtils()
        gitutils.remote_pull(args.path, args.branch, args.force, args.servers, args.remote_user, pw, args.all,
                             args.remote)
Ejemplo n.º 4
0
    def email_changes(self, recipient, name):
        """
        Send an email if branches changed remotely
        :param recipient: string
        :param name: string
        :return: void
        """

        hostname = socket.gethostname()
        sender = self.email_from

        if name is None:
            name = "Someone"
        msg = name + " switched branches on " + hostname + ":"

        if self.branch_changes and len(self.branch_changes) > 0:

            for change in self.branch_changes:

                msg += "\n" + "-" * 60
                msg += "\n" + "Repository: " + change[0]
                msg += "\n" + "From: " + change[1]
                msg += "\n" + "To: " + change[2]
            msg += "\n" + "-" * 60
            # Create a text/plain message
            msg = MIMEText(msg)

            # me == the sender's email address
            # you == the recipient's email address
            msg['Subject'] = 'Repository branch change on ' + hostname
            msg['From'] = sender
            msg['To'] = recipient

            # Send the message via our own SMTP server, but don't include the
            # envelope header.
            try:
                s = smtplib.SMTP(self.email_host)
                s.sendmail(sender, [recipient], msg.as_string())
                s.quit()
            except Exception as e:
                print(e)
                out(
                    0,
                    red("Error sending email:\nMessage: " + str(e) + "\n") +
                    bold("Email Content:\n") + msg.as_string())
Ejemplo n.º 5
0
    def email_changes(self, recipient, name):
        """
        Send an email if branches changed remotely
        :param recipient: string
        :param name: string
        :return: void
        """

        hostname = socket.gethostname()
        sender = self.email_from

        if name is None:
            name = "Someone"
        msg = name + " switched branches on " + hostname + ":"

        if self.branch_changes and len(self.branch_changes) > 0:

            for change in self.branch_changes:

                msg += "\n" + "-" * 60
                msg += "\n" + "Repository: "+change[0]
                msg += "\n" + "From: "+change[1]
                msg += "\n" + "To: "+change[2]
            msg += "\n" + "-" * 60
            # Create a text/plain message
            msg = MIMEText(msg)

            # me == the sender's email address
            # you == the recipient's email address
            msg['Subject'] = 'Repository branch change on ' + hostname
            msg['From'] = sender
            msg['To'] = recipient

            # Send the message via our own SMTP server, but don't include the
            # envelope header.
            try:
                s = smtplib.SMTP(self.email_host)
                s.sendmail(sender, [recipient], msg.as_string())
                s.quit()
            except Exception as e:
                print(e)
                out(0, red("Error sending email:\nMessage: "+str(e)+"\n")+bold("Email Content:\n")+msg.as_string())
Ejemplo n.º 6
0
    def update_directory(self, dir_path, dir_name):
        """First, make sure the specified object is actually a directory, then
        determine whether the directory is a git repo on its own or a directory
        of git repositories. If the former, update the single repository; if the
        latter, update all repositories contained within."""

        dir_long_name = "{} '{}'".format('directory', bold(dir_path))

        if not self.is_valid_directory(dir_path):
            out(0, red(dir_long_name + " is not a valid directory"))
            return False

        if self.directory_is_git_repo(dir_path):
            out(
                0,
                yellow(dir_long_name.capitalize()) +
                yellow(" is a git repository:"))
            self.update_repository(dir_path, dir_name)

        elif self.all_dirs is False:
            # get the repos from git_repos_config and loop through them.
            for repo_name in self.config.repositories:
                repo_path = os.path.join(dir_path, repo_name)
                if self.directory_is_git_repo(repo_path):
                    self.update_repository(repo_path, repo_name)

        else:
            repositories = []

            for item in os.listdir(dir_path):
                repo_path = os.path.join(dir_path, item)
                repo_name = os.path.join(dir_name, item)
                if self.directory_is_git_repo(
                        repo_path):  # filter out non-repositories
                    repositories.append((repo_path, repo_name))

            num_of_repos = len(repositories)
            if num_of_repos == 1:
                out(
                    0,
                    yellow(dir_long_name.capitalize()) +
                    yellow(" contains 1 git repository:"))
            else:
                out(
                    0,
                    yellow(dir_long_name.capitalize()) + yellow(
                        " contains {} git repositories:".format(num_of_repos)))

            repositories.sort()  # go alphabetically instead of randomly
            for repo_path, repo_name in repositories:
                self.update_repository(repo_path, repo_name)
Ejemplo n.º 7
0
    def update_directory(self, dir_path, dir_name):
        """First, make sure the specified object is actually a directory, then
        determine whether the directory is a git repo on its own or a directory
        of git repositories. If the former, update the single repository; if the
        latter, update all repositories contained within."""

        dir_long_name = "{} '{}'".format('directory', bold(dir_path))

        if not self.is_valid_directory(dir_path):
            out(0, red(dir_long_name + " is not a valid directory"))
            return False

        if self.directory_is_git_repo(dir_path):
            out(0, yellow(dir_long_name.capitalize()) + yellow(" is a git repository:"))
            self.update_repository(dir_path, dir_name)

        elif self.all_dirs is False:
            # get the repos from git_repos_config and loop through them.
            for repo_name in self.config.repositories:
                repo_path = os.path.join(dir_path, repo_name)
                if self.directory_is_git_repo(repo_path):
                    self.update_repository(repo_path, repo_name)

        else:
            repositories = []
            
            for item in os.listdir(dir_path):
                repo_path = os.path.join(dir_path, item)
                repo_name = os.path.join(dir_name, item)
                if self.directory_is_git_repo(repo_path):  # filter out non-repositories
                    repositories.append((repo_path, repo_name))

            num_of_repos = len(repositories)
            if num_of_repos == 1:
                out(0, yellow(dir_long_name.capitalize()) + yellow(" contains 1 git repository:"))
            else:
                out(0, yellow(dir_long_name.capitalize()) + yellow(" contains {} git repositories:".format(num_of_repos)))

            repositories.sort()  # go alphabetically instead of randomly
            for repo_path, repo_name in repositories:
                self.update_repository(repo_path, repo_name)
Ejemplo n.º 8
0
        if one_way is False:
            # first  merge to branch into the working branch
            out(
                1,
                blue("Pulling from {} and merging into {}".format(
                    to_branch, branch)))
            output = self.gitutils.git_merge_all(to_branch, branch.working_dir)

            if output is False:
                raise Exception("Aborting!! Could not run shell command :(")

        # Merge the from branch into the destination branch
        out(
            1,
            blue("Pulling from {} and merging into {}".format(
                branch, to_branch)))
        output = self.gitutils.git_merge_all(branch, to_branch, working_dir)

        if output is False:
            raise Exception("Aborting!! Could not run shell command :(")

        return True


if __name__ == "__main__":
    try:
        StagePusher = GitMergeAll()
        StagePusher.main()
    except KeyboardInterrupt:
        out(0, "Stopped by user.")
Ejemplo n.º 9
0
            list(self.group_aliases.keys())
        )

        parser.add_argument('-s', '--servers', nargs="*", metavar="servers", default=None,
                            help="A list of server aliases to update. \n "
                                 "List of all available server aliases: {}".format(", ".join(all_aliases)))

        parser.add_argument('-u', '--remote-user', nargs='?', default=None, metavar="your ssh username",
                            help="""ssh into into git server with this user""")

        args = parser.parse_args()

        out(0, (yellow(bold("gpull") + ": remotely pull git repos")))

        if args.servers is not None:
            pw = getpass.getpass("Your ssh password:"******"__main__":
    try:
        GitPull = GitPull()
        GitPull.main()
    except KeyboardInterrupt:
        out(0, "Stopped by user.")
Ejemplo n.º 10
0
    def main(self):
        """Parse arguments and then call the appropriate function(s)."""

        parser = argparse.ArgumentParser(
            description=
            """Pull multiple Git Repositories at once, on multiple servers.""")

        parser.add_argument(
            '-p',
            '--path',
            nargs="*",
            metavar="path",
            default=None,
            help=
            """update all repositories under this directory / path (or the directory itself,
                            if the given directory corresponds to a repo. eg. -p ots /srv/salt )"""
        )

        parser.add_argument(
            '-b',
            '--branch',
            metavar="branch",
            nargs='?',
            default=None,
            help=
            """check the repo out on the specified branch if it's not on this branch yet."""
        )

        parser.add_argument(
            '-f',
            '--force',
            nargs='?',
            default=False,
            metavar="force pull/checkout",
            help=
            """force checkout / pull (discard local changes) if we're changing branches."""
        )

        parser.add_argument(
            '-a',
            '--all',
            nargs='?',
            default=False,
            metavar="recurse through all directories",
            help="""Recurse through all subdirectories to find git repos.""")

        parser.add_argument(
            '-r',
            '--remote',
            nargs='?',
            default=None,
            metavar="remote location for gpull_local.py",
            help=
            """Remote location of gpull_local.py, eg /usr/local/bin/gpull_local.py """
        )

        # get all aliases and sort them for help convenience
        all_aliases = sorted(
            list(self.server_aliases.keys()) + list(self.group_aliases.keys()))

        parser.add_argument('-s',
                            '--servers',
                            nargs="*",
                            metavar="servers",
                            default=None,
                            help="A list of server aliases to update. \n "
                            "List of all available server aliases: {}".format(
                                ", ".join(all_aliases)))

        parser.add_argument('-u',
                            '--remote-user',
                            nargs='?',
                            default=None,
                            metavar="your ssh username",
                            help="""ssh into into git server with this user""")

        args = parser.parse_args()

        out(0, (yellow(bold("gpull") + ": remotely pull git repos")))

        if args.servers is not None:
            pw = getpass.getpass(
                "Your ssh password:")  # Prompt user for ssh password
        else:
            pw = None  # No password needed to update your local folders

        gitutils = git_utils.GitUtils()
        gitutils.remote_pull(args.path, args.branch, args.force, args.servers,
                             args.remote_user, pw, args.all, args.remote)
Ejemplo n.º 11
0
    def update_repository(self, repo_path, repo_name):
        """
        Update a single git repository by pulling from the remote.
        :param repo_path:
        :param repo_name:
        :return: bool
        """
        out(1, bold(repo_name) + ":")

        # cd into our folder so git commands target the correct repo
        os.chdir(repo_path)
        try:
            # what branch are we on?
            curr_branch = self.exec_shell("git rev-parse --abbrev-ref HEAD")
        except subprocess.CalledProcessError as e:
            curr_branch = False
            out(2, yellow("warning: ") + e.output.decode('UTF-8'))

        # strip out spaces, new lines etc
        if curr_branch:
            curr_branch = curr_branch.strip(' \t\b\n\r')

        try:
            # check if there is anything to pull, but don't do it yet
            dry_fetch = self.exec_shell("git fetch --dry-run")
        except subprocess.CalledProcessError as e:
            out(2, red("Error: ") + "cannot fetch; do you have a remote repository configured correctly?\n" + e.output.decode('UTF-8'))
            return

        # if a specific branch was passed in, then make sure that's what we're on.
        if self.branch and curr_branch:
            branch = self.branch

            # if we're not on the required branch, then check it out.
            if branch != curr_branch:
                out(2, yellow("branch to switch from: " + curr_branch + "\nbranch to switch to: " + branch))
                try:
                    # need to fetch first
                    git_fetch_txt = self.exec_shell("git fetch")
                    if git_fetch_txt:
                        out(2, yellow(git_fetch_txt.strip()))
                except subprocess.CalledProcessError as e:
                    out(2, red("Could not fetch: \n" + e.output.decode('UTF-8')))
                    return False

                # get list of remote branches
                remote_branches = self.exec_shell("git branch -a")

                # see if the desired branch exists remotely, otherwise skip this process.
                if "remotes/origin/"+branch in remote_branches:
                    out(2, green('Attempting to switch branch from ' + curr_branch + ' to ' + branch))
                    if self.force:
                        git_checkout_txt = self.exec_shell("git checkout -f " + branch)
                        out(2, yellow(git_checkout_txt))
                    else:
                        try:
                            git_checkout_txt = self.exec_shell("git checkout " + branch)
                            out(2, yellow(git_checkout_txt))
                        except subprocess.CalledProcessError as e:
                            out(2, red("Could not check out branch: \n" + e.output.decode('UTF-8')))
                            return False
                    self.branch_changes.append([repo_name, curr_branch, branch])
                    # set curr_branch to the branch we just changed to.
                    curr_branch = branch
                else:
                    out(2, red("branch {} does not exist. skipping checkout.".format(branch, repo_path)))

        try:
            last_commit = self.exec_shell("git log -n 1 --pretty=\"%ar\"")
            last_commit = last_commit.strip(' \t\b\n\r')
        except subprocess.CalledProcessError:
            last_commit = "never"  # couldn't get a log, so no commits

        if not dry_fetch:
            # try git status, just to make sure a fetch didn't happen without a pull:
            status = self.exec_shell("git status -uno")
            if "Your branch is behind" not in status:
                out(2, blue("No new changes.") + " Last commit was {}.".format(last_commit))
                return False

        # stuffs have happened!
        out(2, "There are new changes upstream...")
        status = self.exec_shell("git status")

        if not status.endswith("nothing to commit (working directory clean)"):
            out(2, red("Warning: ") + "you have uncommitted changes in this repository!")
            if self.force:
                out(2, red("Since force is enabled, I will now reset your branch:"))
                reset_result = self.exec_shell("git reset --hard HEAD")
                out(2, green(reset_result))

        out(2, green("Pulling changes..."))
        try:
            result = self.exec_shell("git pull")
        except subprocess.CalledProcessError as e:
            try:
                # if pull fails to pull because remote branch is not configured correctly:
                if 'You asked me to pull without telling me which branch' in e.output or \
                        'Please specify which branch you want to merge with' in e.output:
                    set_remote_branch = self.exec_shell(
                        "git branch --set-upstream-to {} origin/{}".format(curr_branch, curr_branch))
                    out(2, green(set_remote_branch))
                    result = self.exec_shell("git pull")
                elif self.force and 'Your local changes to the following files would be overwritten' in e.output:
                    reset_result = self.exec_shell("git reset --hard HEAD")
                    out(2, green(reset_result))
                    result = self.exec_shell("git pull")
                else:
                    out(2, red(e.output))
                    return False
            except subprocess.CalledProcessError as e:
                out(2, red(e.output))
                return False

        if result:
            if 'Already up-to-date' in result:
                out(2, "No new changes in your branch. However, upstream the following changes happened:")
            else:
                out(2, "The following changes were made {}:".format(last_commit))

            out(2, blue(result))
Ejemplo n.º 12
0
    def update_repository(self, repo_path, repo_name):
        """
        Update a single git repository by pulling from the remote.
        :param repo_path:
        :param repo_name:
        :return: bool
        """
        out(1, bold(repo_name) + ":")

        # cd into our folder so git commands target the correct repo
        os.chdir(repo_path)
        try:
            # what branch are we on?
            curr_branch = self.exec_shell("git rev-parse --abbrev-ref HEAD")
        except subprocess.CalledProcessError as e:
            curr_branch = False
            out(2, yellow("warning: ") + e.output.decode('UTF-8'))

        # strip out spaces, new lines etc
        if curr_branch:
            curr_branch = curr_branch.strip(' \t\b\n\r')

        try:
            # check if there is anything to pull, but don't do it yet
            dry_fetch = self.exec_shell("git fetch --dry-run")
        except subprocess.CalledProcessError as e:
            out(
                2,
                red("Error: ") +
                "cannot fetch; do you have a remote repository configured correctly?\n"
                + e.output.decode('UTF-8'))
            return

        # if a specific branch was passed in, then make sure that's what we're on.
        if self.branch and curr_branch:
            branch = self.branch

            # if we're not on the required branch, then check it out.
            if branch != curr_branch:
                out(
                    2,
                    yellow("branch to switch from: " + curr_branch +
                           "\nbranch to switch to: " + branch))
                try:
                    # need to fetch first
                    git_fetch_txt = self.exec_shell("git fetch")
                    if git_fetch_txt:
                        out(2, yellow(git_fetch_txt.strip()))
                except subprocess.CalledProcessError as e:
                    out(2,
                        red("Could not fetch: \n" + e.output.decode('UTF-8')))
                    return False

                # get list of remote branches
                remote_branches = self.exec_shell("git branch -a")

                # see if the desired branch exists remotely, otherwise skip this process.
                if "remotes/origin/" + branch in remote_branches:
                    out(
                        2,
                        green('Attempting to switch branch from ' +
                              curr_branch + ' to ' + branch))
                    if self.force:
                        git_checkout_txt = self.exec_shell("git checkout -f " +
                                                           branch)
                        out(2, yellow(git_checkout_txt))
                    else:
                        try:
                            git_checkout_txt = self.exec_shell(
                                "git checkout " + branch)
                            out(2, yellow(git_checkout_txt))
                        except subprocess.CalledProcessError as e:
                            out(
                                2,
                                red("Could not check out branch: \n" +
                                    e.output.decode('UTF-8')))
                            return False
                    self.branch_changes.append(
                        [repo_name, curr_branch, branch])
                    # set curr_branch to the branch we just changed to.
                    curr_branch = branch
                else:
                    out(
                        2,
                        red("branch {} does not exist. skipping checkout.".
                            format(branch, repo_path)))

        try:
            last_commit = self.exec_shell("git log -n 1 --pretty=\"%ar\"")
            last_commit = last_commit.strip(' \t\b\n\r')
        except subprocess.CalledProcessError:
            last_commit = "never"  # couldn't get a log, so no commits

        if not dry_fetch:
            # try git status, just to make sure a fetch didn't happen without a pull:
            status = self.exec_shell("git status -uno")
            if "Your branch is behind" not in status:
                out(
                    2,
                    blue("No new changes.") +
                    " Last commit was {}.".format(last_commit))
                return False

        # stuffs have happened!
        out(2, "There are new changes upstream...")
        status = self.exec_shell("git status")

        if not status.endswith("nothing to commit (working directory clean)"):
            out(
                2,
                red("Warning: ") +
                "you have uncommitted changes in this repository!")
            if self.force:
                out(
                    2,
                    red("Since force is enabled, I will now reset your branch:"
                        ))
                reset_result = self.exec_shell("git reset --hard HEAD")
                out(2, green(reset_result))

        out(2, green("Pulling changes..."))
        try:
            result = self.exec_shell("git pull")
        except subprocess.CalledProcessError as e:
            try:
                # if pull fails to pull because remote branch is not configured correctly:
                if 'You asked me to pull without telling me which branch' in e.output or \
                        'Please specify which branch you want to merge with' in e.output:
                    set_remote_branch = self.exec_shell(
                        "git branch --set-upstream-to {} origin/{}".format(
                            curr_branch, curr_branch))
                    out(2, green(set_remote_branch))
                    result = self.exec_shell("git pull")
                elif self.force and 'Your local changes to the following files would be overwritten' in e.output:
                    reset_result = self.exec_shell("git reset --hard HEAD")
                    out(2, green(reset_result))
                    result = self.exec_shell("git pull")
                else:
                    out(2, red(e.output))
                    return False
            except subprocess.CalledProcessError as e:
                out(2, red(e.output))
                return False

        if result:
            if 'Already up-to-date' in result:
                out(
                    2,
                    "No new changes in your branch. However, upstream the following changes happened:"
                )
            else:
                out(2,
                    "The following changes were made {}:".format(last_commit))

            out(2, blue(result))