6265be3aee
git module used to check stderr for the string 'error' after calling switch_version(). This changes that to just look at the return code to determine whether the command failed. If the rc is not zero, the git module will call fail_json(). The problem is that git checkout will summarize the commit message, such as: HEAD is now at ea38409... removing artificial error When the string 'error' is the commit message, this check will erroneously think the command failed. This also removes the method switchLocalBranch() since it is no longer used.
192 lines
6 KiB
Python
Executable file
192 lines
6 KiB
Python
Executable file
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
|
|
#
|
|
# This file is part of Ansible
|
|
#
|
|
# Ansible is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Ansible is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
# I wanted to keep this simple at first, so for now this checks out
|
|
# from the given branch of a repo at a particular SHA or
|
|
# tag. Latest is not supported, you should not be doing
|
|
# that. Contribs welcome! -- MPD
|
|
|
|
import re
|
|
|
|
def get_version(dest):
|
|
''' samples the version of the git repo '''
|
|
os.chdir(dest)
|
|
cmd = "git show --abbrev-commit"
|
|
sha = os.popen(cmd).read().split("\n")
|
|
sha = sha[0].split()[1]
|
|
return sha
|
|
|
|
def clone(repo, dest):
|
|
''' makes a new git repo if it does not already exist '''
|
|
try:
|
|
os.makedirs(os.path.dirname(dest))
|
|
except:
|
|
pass
|
|
cmd = "git clone %s %s" % (repo, dest)
|
|
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
(out, err) = cmd.communicate()
|
|
rc = cmd.returncode
|
|
return (rc, out, err)
|
|
|
|
def reset(dest):
|
|
'''
|
|
Resets the index and working tree to HEAD.
|
|
Discards any changes to tracked files in working
|
|
tree since that commit.
|
|
'''
|
|
os.chdir(dest)
|
|
cmd = "git reset --hard HEAD"
|
|
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
(out, err) = cmd.communicate()
|
|
rc = cmd.returncode
|
|
return (rc, out, err)
|
|
|
|
def get_branches(module, dest):
|
|
os.chdir(dest)
|
|
branches = []
|
|
cmd = "git branch -a"
|
|
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
out, err = cmd.communicate()
|
|
if cmd.returncode != 0:
|
|
module.fail_json(msg="Could not determine branch data - received %s" % out)
|
|
for line in out.split('\n'):
|
|
branches.append(line.strip())
|
|
return branches
|
|
|
|
def is_remote_branch(module, dest, remote, branch):
|
|
branches = get_branches(module, dest)
|
|
rbranch = 'remotes/%s/%s' % (remote, branch)
|
|
if rbranch in branches:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def is_local_branch(module, dest, branch):
|
|
branches = get_branches(module, dest)
|
|
lbranch = '%s' % branch
|
|
if lbranch in branches:
|
|
return True
|
|
elif '* %s' % branch in branches:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def is_current_branch(module, dest, branch):
|
|
branches = get_branches(module, dest)
|
|
for b in branches:
|
|
if b.startswith('* '):
|
|
cur_branch = b
|
|
if branch == cur_branch or '* %s' % branch == cur_branch:
|
|
return True
|
|
else:
|
|
return True
|
|
|
|
def pull(module, repo, dest, version):
|
|
''' updates repo from remote sources '''
|
|
os.chdir(dest)
|
|
branches = get_branches(module, dest)
|
|
cur_branch = ''
|
|
for b in branches:
|
|
if b.startswith('* '):
|
|
cur_branch = b
|
|
if is_local_branch(module, dest, version) and not is_current_branch(module, dest, version):
|
|
(out, err) = switch_version(module, dest, remote, version)
|
|
|
|
cmd = "git pull -u origin"
|
|
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
out, err = cmd.communicate()
|
|
rc = cmd.returncode
|
|
return (rc, out, err)
|
|
|
|
def switch_version(module, dest, remote, version):
|
|
''' once pulled, switch to a particular SHA, tag, or branch '''
|
|
os.chdir(dest)
|
|
cmd = ''
|
|
if version != 'HEAD':
|
|
if not is_local_branch(module, dest, version) and is_remote_branch(module, dest, remote, version):
|
|
cmd = "git checkout --track -b %s %s/%s" % (version, remote, version)
|
|
else:
|
|
cmd = "git checkout --force %s" % version
|
|
else:
|
|
# is there a better way to do this?
|
|
cmd = "git rebase origin"
|
|
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
(out, err) = cmd.communicate()
|
|
rc = cmd.returncode
|
|
return (rc, out, err)
|
|
|
|
# ===========================================
|
|
|
|
def main():
|
|
module = AnsibleModule(
|
|
argument_spec = dict(
|
|
dest=dict(required=True),
|
|
repo=dict(required=True, aliases=['name']),
|
|
version=dict(default='HEAD'),
|
|
remote=dict(default='origin')
|
|
)
|
|
)
|
|
|
|
dest = module.params['dest']
|
|
repo = module.params['repo']
|
|
version = module.params['version']
|
|
remote = module.params['remote']
|
|
|
|
gitconfig = os.path.join(dest, '.git', 'config')
|
|
|
|
rc, out, err, status = (0, None, None, None)
|
|
|
|
# if there is no git configuration, do a clone operation
|
|
# else pull and switch the version
|
|
before = None
|
|
if not os.path.exists(gitconfig):
|
|
(rc, out, err) = clone(repo, dest)
|
|
if rc != 0:
|
|
module.fail_json(msg=err)
|
|
else:
|
|
# else do a pull
|
|
before = get_version(dest)
|
|
(rc, out, err) = reset(dest)
|
|
if rc != 0:
|
|
module.fail_json(msg=err)
|
|
(rc, out, err) = pull(module, repo, dest, version)
|
|
|
|
# handle errors from clone or pull
|
|
if out.find('error') != -1 or err.find('ERROR') != -1:
|
|
module.fail_json(msg=err)
|
|
|
|
# switch to version specified regardless of whether
|
|
# we cloned or pulled
|
|
(rc, out, err) = switch_version(module, dest, remote, version)
|
|
if rc != 0:
|
|
module.fail_json(msg=err)
|
|
|
|
# determine if we changed anything
|
|
after = get_version(dest)
|
|
changed = False
|
|
|
|
if before != after:
|
|
changed = True
|
|
|
|
module.exit_json(changed=changed, before=before, after=after)
|
|
|
|
# include magic from lib/ansible/module_common.py
|
|
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
|
main()
|