Skip to content
Snippets Groups Projects
gitlab_issue.py 9.01 KiB
Newer Older
  • Learn to ignore specific revisions
  • #!/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) # type: gitlab
    
                git = gitlab.Gitlab(server_url, login_token, ssl_verify=verify_ssl) # type: gitlab
    
            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)
                     }
    
    
        # Create issue and retry up to 3 times if that fails
        issue = False
        delay = random.randint(0, 200) / 100
        retries = 3
        while retries > 0:
            retries -= 1
            time.sleep(delay)
    
            try:
                issue = git.project_issues.create(arguments, project_id=project.pid)
            except Exception, e:
                pass
    
        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()