Skip to content
Snippets Groups Projects
gitlab_issue.py 8.67 KiB
Newer Older
#!/usr/bin/python

RETURN = '''# '''

import datetime
try:
    import gitlab
    HAS_GITLAB_PACKAGE = True
except:
    HAS_GITLAB_PACKAGE = False


class GitLabProject(object):

    namespace = ''
    nid = False
    pid = False
    is_user = False
    project = None

    def __init__(self, module, git):
        self._module = module
        self._gitlab = git

    def exists(self, group_name, project_name):
        if not self.findNamespace(group_name):
            return False

        project = self._gitlab.projects.get('%s/%s' % (self.namespace, project_name))
        if project:
            namespace = project.namespace
            if namespace.id == self.nid:
                if (not self.is_user and not hasattr(namespace, 'owner_id')) or (self.is_user and hasattr(namespace, 'owner_id')):
                    if project.name.lower() == project_name or project.path.lower() == project_name:
                        self.pid = project.id
                        self.project = project
                        return True

        return False

    def findNamespace(self, group_name):
        if self.nid:
            return True

        if group_name is not None:
            # Find the group, if group not exists we try for user
            group_name = unicode(group_name)
            for group in self._gitlab.namespaces.list(search=group_name):
                if group.path.lower() == group_name:
                    self.namespace = group_name
                    self.nid = group.id
                    return True

            user_name = group_name

        else:
            user_name = self._gitlab.user.username

        user_data = self._gitlab.users.list(username=user_name)
        for user in user_data:
            if hasattr(user, 'id'):
                self.namespace = user_name
                self.nid = user.id
                self.is_user = True
                return True

        return False

    def findIssues(self, title):
        return self.project.issues.list(state='opened')


class GitLabMilestone(object):

    mid = False

    def __init__(self, module, git):
        self._module = module
        self._gitlab = git

    def exists(self, project_id, milestone_name):
        if self.mid:
            return True

        if milestone_name is not None:
            milestone_name = unicode(milestone_name)
            found_milestones = self._gitlab.project_milestones.list(project_id=project_id)
            for milestone in found_milestones:
                if milestone.title.lower() == milestone_name:
                    self.mid = milestone.id
                    return True

        return False


class GitLabUser(object):

    uid = False

    def __init__(self, module, git):
        self._module = module
        self._gitlab = git

    def exists(self, username):
        if self.uid:
            return True

        if username is not None:
            username = unicode(username)
            found_user = self._gitlab.users.list(username=username)
            for user in found_user:
                if user.name.lower() == username or user.username.lower() == username:
                    self.uid = user.id
                    return True

        return False


def main():
    module = AnsibleModule(
        argument_spec=dict(
            server_url=dict(required=True),
            validate_certs=dict(required=False, default=True, type='bool', aliases=['verify_ssl']),
            login_user=dict(required=False, no_log=True),
            login_password=dict(required=False, no_log=True),
            login_token=dict(required=False, no_log=True),
            group=dict(required=False),
            name=dict(required=True),
            title=dict(required=True),
            append_timestamp=dict(required=False, default=False, type='bool'),
            description=dict(required=False),
            confidential=dict(required=False, default=False, type='bool'),
            assignee=dict(required=False),
            milestone=dict(required=False),
            labels=dict(required=False, type='list'),
            update=dict(required=False, default=False, type='bool'),
            close=dict(required=False, default=False, type='bool'),
        ),
        supports_check_mode=True
    )

    if not HAS_GITLAB_PACKAGE:
        module.fail_json(msg="Missing required gitlab module (check docs or install with: pip install python-gitlab")

    server_url = module.params['server_url']
    verify_ssl = module.params['validate_certs']
    login_user = module.params['login_user']
    login_password = module.params['login_password']
    login_token = module.params['login_token']
    group_name = module.params['group']
    project_name = module.params['name']
    title = module.params['title']
    append_timestamp = module.params['append_timestamp']
    description = module.params['description']
    confidential = module.params['confidential']
    assignee = module.params['assignee']
    milestone_name = module.params['milestone']
    labels = module.params['labels']
    update = module.params['update']
    close = module.params['close']

    # We need both login_user and login_password or login_token, otherwise we fail.
    if login_user is not None and login_password is not None:
        use_credentials = True
    elif login_token is not None:
        use_credentials = False
    else:
        module.fail_json(msg="No login credentials are given. Use login_user with login_password, or login_token")
        return

    # Gitlab API makes no difference between upper and lower cases, so we lower them.
    project_name = project_name.lower()
    if group_name is not None:
        group_name = group_name.lower()

    # Lets make an connection to the Gitlab server_url, with either login_user and login_password
    # or with login_token
    try:
        if use_credentials:
            git = gitlab.Gitlab(server_url, email=login_user, password=login_password, ssl_verify=verify_ssl)
        else:
            git = gitlab.Gitlab(server_url, login_token, ssl_verify=verify_ssl)
        git.auth()
    except Exception, e:
        module.fail_json(msg="Failed to connect to Gitlab server: %s " % e)
        return

    # Validate if project exists and get its ID
    project = GitLabProject(module, git)
    project_exists = project.exists(group_name, project_name)
    if not project_exists:
        module.fail_json(msg="Gitlab project does not exist")

    # Validate if user exists and get its ID
    user = GitLabUser(module, git)
    user_exists = user.exists(assignee)
    assignee_id = None
    if user_exists:
        assignee_id = user.uid

    # Validate if milestone exists and get its ID
    milestone = GitLabMilestone(module, git)
    milestone_exists = milestone.exists(project.pid, milestone_name)
    milestone_id = None
    if milestone_exists:
        milestone_id = milestone.mid


    if labels is None:
        labels = []

    if update:
        issues = project.findIssues(title)
        updated = 0
        if issues:
            for issue in issues:
                if issue.title.find(title) == 0:
                    updated += 1
                    if description:
                        git.project_issue_notes.create({'body': description}, project_id=project.pid, issue_id=issue.id)
                    if assignee_id:
                        issue.assignee_id = assignee_id
                    if milestone_id:
                        issue.milestone_id = milestone_id
                    for label in labels:
                        if label not in labels:
                            issue.labels.append(label)
                    if close:
                        issue.state_event = 'close'
                    issue.save()
        if updated > 0:
            module.exit_json(changed=True, result="Successfully updated %d issue(s) in project %s" % (updated, project_name))

        # If we haven't found an issue to update, we're going to create a new one

    if append_timestamp:
        title = "%s (%s)" % (title, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))

    # Creating the issue dict
    arguments = {"title": title,
                 "description": description,
                 "confidential": confidential,
                 "assignee_id": assignee_id,
                 "milestone_id": milestone_id,
                 "labels": ','.join(labels)
                 }

    issue = git.project_issues.create(arguments, project_id=project.pid)
    if issue:
        if close:
            issue.state_event = 'close'
            issue.save()
        module.exit_json(changed=True, result="Successfully created issue %s in project %s" % (title, project_name))
    else:
        module.fail_json(msg="Creating new issue failed", response=issue)

from ansible.module_utils.basic import *

if __name__ == '__main__':
    main()