Beispiel #1
0
class JenkinsAPI(object):
    def __init__(self):
        self.__server = Jenkins(settings.JENKINS.get('URI'))

    def get_all_jobs(self):
        return self.__server.get_all_jobs()

    def get_next_build_number(self, name):
        return self.__server.get_job_info(name)['nextBuildNumber']

    def build_job(self, name, parameters=None):
        return self.__server.build_job(name=name, parameters=parameters)

    def get_build_info(self, name, build_number):
        try:
            return self.__server.get_build_info(name, build_number)
        except Exception as e:
            logger.exception(e)
            return None

    def get_build_console_output(self, name, number):
        try:
            return self.__server.get_build_console_output(name, number)
        except JenkinsException as e:
            logger.exception(e)
            return None

    def download_package(self, package_url, name, build_number):
        URI = settings.JENKINS.get('URI')
        download_url = '{}/job/{}/{}/artifact/{}'.format(
            URI, name, build_number, package_url)
        logger.debug(download_url)
        local_filename = download_url.split('/')[-1]
        code_path = os.path.join(settings.DEPLOY.get('CODE_PATH'), 'packages')
        local_full_filename = os.path.join(code_path, local_filename)

        # with requests.get(url, stream=True,
        # auth=HTTPBasicAuth("zhoujinliang", "117c911a35acf51e428e29f3ccb363f53f")) as r:
        with requests.get(download_url, stream=True) as r:
            r.raise_for_status()
            with open(local_full_filename, 'wb') as f:
                for chunk in r.iter_content(chunk_size=8192):
                    if chunk:  # filter out keep-alive new chunks
                        f.write(chunk)
        return local_full_filename

    def cancel_build(self, name, queue_id, build_number):
        try:
            self.__server.cancel_queue(queue_id)
            self.__server.stop_build(name, build_number)
        except Exception as e:
            logger.error(e)

    def test(self):
        return self.__server.cancel_queue(3590)
        # # return self.__server.stop_build('devops', 98)
        return self.__server.get_queue_info()
Beispiel #2
0
class JenkinsJobMonitor():
    def __init__(self, url, username, password, *args, **argvs):
        self._attach_server(url, username, password, *args, **argvs)

    def _attach_server(self, url, username, password, *args, **argvs):
        self.server = Jenkins(url=url,
                              username=username,
                              password=password,
                              *args,
                              **argvs)

    def _is_stuck(self, item):
        if item['pending'] == False and item['stuck'] == True:
            print(
                "Cancel 'stuck' job [name : {name}] [id : {job_id} [why: {why}]]"
                .format(name=item['task']['name'],
                        job_id=item['id'],
                        why=item['why']))
            return True
        else:
            return False

    def _cancel_jobs(self, build_id):
        self.server.cancel_queue(build_id)

    def cancel_stuck_jobs(self):
        if self.server.get_queue_info():
            for item in self.server.get_queue_info():
                if self._is_stuck(item):
                    self._cancel_jobs(item['id'])
        else:
            self.poll_flag = False

    def _is_timeout(self):
        pass

    def cancel_timeout_jobs(self):
        pass

    def poll_stuck(self):
        self.poll_flag = True
        while self.poll_flag:
            time.sleep(10)  # Timer maybe better.
            self.cancel_stuck_jobs()

    def poll_timeout(self):
        pass
Beispiel #3
0
class JenkinsBot(BotPlugin):
    """Basic Err integration with Jenkins CI"""

    min_err_version = '1.2.1'
    # max_err_version = '4.0.3'

    def get_configuration_template(self):
        return CONFIG_TEMPLATE

    def configure(self, configuration):
        if configuration is not None and configuration != {}:
            config = dict(chain(CONFIG_TEMPLATE.items(),
                                configuration.items()))
        else:
            config = CONFIG_TEMPLATE
        super(JenkinsBot, self).configure(config)
        return

    def check_configuration(self, configuration):
        self.log.debug(configuration)
        for c, v in configuration.items():
            if c == 'URL':
                if not validators.url(v):
                    raise ValidationException('JENKINS_URL is not a well formed URL')
            elif c in ['USERNAME', 'PASSWORD', 'RECEIVE_NOTIFICATION']:
                if len(v) == 0 or not isinstance(v, str):
                    raise ValidationException("{} is a required string config setting".format(c))
            elif c in ['CHATROOMS_NOTIFICATION']:
                if not isinstance(v, tuple):
                    raise ValidationException("{} should be of type tuple".format(c))
        return

    def connect_to_jenkins(self):
        """Connect to a Jenkins instance using configuration."""
        self.log.debug('Connecting to Jenkins ({0})'.format(
            self.config['URL']))
        self.jenkins = Jenkins(url=self.config['URL'],
                               username=self.config['USERNAME'],
                               password=self.config['PASSWORD'])
        return

    def broadcast(self, mess):
        """Shortcut to broadcast a message to all elligible chatrooms."""
        chatrooms = (self.config['CHATROOMS_NOTIFICATION']
                     if self.config['CHATROOMS_NOTIFICATION']
                     else self.bot_config.CHATROOM_PRESENCE)

        for room in chatrooms:
            self.send(self.build_identifier(room), mess)
        return

    @webhook(r'/jenkins/notification')
    def handle_notification(self, incoming_request):
        if not self.config['RECEIVE_NOTIFICATION']:
            return 'Notification handling is disabled.'

        self.log.debug(repr(incoming_request))
        self.broadcast(self.format_notification(incoming_request))
        return

    @botcmd
    def jenkins_list(self, mess, args):
        """List all jobs, optionally filter them using a search term."""
        self.connect_to_jenkins()
        return self.format_jobs([job for job in self.jenkins.get_jobs(folder_depth=None)
            if args.lower() in job['fullname'].lower()])

    @botcmd
    def jenkins_running(self, mess, args):
        """List all running jobs."""
        self.connect_to_jenkins()

        jobs = [job for job in self.jenkins.get_jobs()
                if 'anime' in job['color']]
        return self.format_running_jobs(jobs)

    @botcmd(split_args_with=None)
    def jenkins_param(self, mess, args):
        """List Parameters for a given job."""
        if len(args) == 0:
            return 'What Job would you like the parameters for?'

        self.connect_to_jenkins()

        job = self.jenkins.get_job_info(args[0])
        if job['actions'][1] != {}:
            job_param = job['actions'][1]['parameterDefinitions']
        elif job['actions'][0] != {}:
            job_param = job['actions'][0]['parameterDefinitions']
        else:
            job_param = []

        return self.format_params(job_param)

    @botcmd(split_args_with=None)
    def jenkins_build(self, mess, args):
        """Build a Jenkins Job with the given parameters
        Example: !jenkins build test_project FOO:bar
        """
        if len(args) == 0:  # No Job name
            return 'What job would you like to build?'

        self.connect_to_jenkins()
        params = self.build_parameters(args[1:])

        # Is it a parameterized job ?
        job = self.jenkins.get_job_info(args[0])
        if job['actions'][0] == {} and job['actions'][1] == {}:
            self.jenkins.build_job(args[0])
        else:
            self.jenkins.build_job(args[0], params)

        running_job = self.search_job(args[0])
        return 'Your job should begin shortly: {0}'.format(
            self.format_jobs(running_job))

    @botcmd(split_args_with=None)
    def build(self, mess, args):
        """Shortcut for jenkins_build"""
        return self.jenkins_build(mess, args)

    @botcmd
    def jenkins_unqueue(self, msg, args):
        """Cancel a queued job.
        Example !jenkins unqueue foo
        """
        self.connect_to_jenkins()

        try:
            queue = self.jenkins.get_queue_info()

            job = next((job for job in queue if job['task']['name'].lower() == args.lower()), None)

            if job:
                self.jenkins.cancel_queue(job['id'])
                return 'Unqueued job {0}'.format(job['task']['name'])
            else:
                return 'Could not find job {0}, but found the following: {1}'.format(
                    args, ', '.join(job['task']['name'] for job in queue))
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

    @botcmd(split_args_with=None)
    def jenkins_createjob(self, mess, args):
        """Create a Jenkins Job.
        Example: !jenkins createjob pipeline foo [email protected]:foo/bar.git
        """
        if len(args) < 2:  # No Job type or name
            return 'Oops, I need a type and a name for your new job.'

        if args[0] not in ('pipeline', 'multibranch'):
            return 'I\'m sorry, I can only create `pipeline` and \
                    `multibranch` jobs.'

        self.connect_to_jenkins()

        try:
            if args[0] == 'pipeline':
                self.jenkins.create_job(
                    args[1],
                    JENKINS_JOB_TEMPLATE_PIPELINE.format(repository=args[2]))

            elif args[0] == 'multibranch':
                repository = args[2].rsplit('/', maxsplit=2)[-2:]

                self.jenkins.create_job(
                    args[1],
                    JENKINS_JOB_TEMPLATE_MULTIBRANCH.format(
                        repo_owner=repository[0].split(':')[-1],
                        repo_name=repository[1].strip('.git')))
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)
        return 'Your job has been created: {0}/job/{1}'.format(
            self.config['URL'], args[1])

    @botcmd(split_args_with=None)
    def jenkins_deletejob(self, mess, args):
        """Delete a Jenkins Job.
        Example: !jenkins deletejob foo
        """
        if len(args) < 1:  # No job name
            return 'Oops, I need the name of the job you want me to delete.'

        self.connect_to_jenkins()

        try:
            self.jenkins.delete_job(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your job has been deleted.'

    @botcmd(split_args_with=None)
    def jenkins_enablejob(self, mess, args):
        """Enable a Jenkins Job.
        Example: !jenkins enablejob foo
        """
        if len(args) < 1:  # No job name
            return 'Oops, I need the name of the job you want me to enable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.enable_job(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your job has been enabled.'

    @botcmd(split_args_with=None)
    def jenkins_disablejob(self, mess, args):
        """Disable a Jenkins Job.
        Example: !jenkins disablejob foo
        """
        if len(args) < 1:  # No job name
            return 'Oops, I need the name of the job you want me to disable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.disable_job(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your job has been disabled.'

    @botcmd(split_args_with=None)
    def jenkins_createnode(self, mess, args):
        """Create a Jenkins Node with a JNLP Launcher with optionnal labels.
        Example: !jenkins createnode runner-foo-laptop /home/foo # without labels
        Example: !jenkins createnode runner-bar-laptop /home/bar linux docker # with labels
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need a name and a working dir for your new node.'

        self.connect_to_jenkins()

        try:
            self.jenkins.create_node(
                name=args[0],
                remoteFS=args[1],
                labels=' '.join(args[2:]),
                exclusive=True,
                launcher=LAUNCHER_JNLP)
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been created: {0}/computer/{1}'.format(
            self.config['URL'], args[0])

    @botcmd(split_args_with=None)
    def jenkins_deletenode(self, mess, args):
        """Delete a Jenkins Node.
        Example: !jenkins deletenode runner-foo-laptop
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need the name of the node you want me to delete.'

        self.connect_to_jenkins()

        try:
            self.jenkins.delete_node(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been deleted.'

    @botcmd(split_args_with=None)
    def jenkins_enablenode(self, mess, args):
        """Enable a Jenkins Node.
        Example: !jenkins enablenode runner-foo-laptop
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need the name of the node you want me to enable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.enable_node(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been enabled.'

    @botcmd(split_args_with=None)
    def jenkins_disablenode(self, mess, args):
        """Disable a Jenkins Node.
        Example: !jenkins disablenode runner-foo-laptop
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need the name of the node you want me to disable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.disable_node(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been disabled.'

    def search_job(self, search_term):
        self.log.debug('Querying Jenkins for job "{0}"'.format(search_term))
        return [job for job in self.jenkins.get_jobs(folder_depth=None)
                if search_term.lower() == job['fullname'].lower()]

    def format_running_jobs(self, jobs):
        if len(jobs) == 0:
            return 'No running jobs.'

        jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs]
        return '\n\n'.join(['%s (%s)\n%s' % (
            job['name'],
            job['lastBuild']['url'],
            job['healthReport'][0]['description'])
                            for job in jobs_info]).strip()

    @staticmethod
    def format_jobs(jobs):
        if len(jobs) == 0:
            return 'No jobs found.'

        max_length = max([len(job['fullname']) for job in jobs])
        return '\n'.join(
            ['%s (%s)' % (job['fullname'].ljust(max_length), job['url'])
             for job in jobs]).strip()

    @staticmethod
    def format_params(job):
        """Format job parameters."""
        if len(job) == 0:
            return 'This job is not parameterized.'
        PARAM_TEMPLATE = Template("""{% for p in params %}Type: {{p.type}}
Description: {{p.description}}
Default Value: {{p.defaultParameterValue.value}}
Parameter Name: {{p.name}}

{% endfor %}""")
        return PARAM_TEMPLATE.render({'params': job})

    @staticmethod
    def format_notification(body):
        body['fullname'] = body.get('fullname', body['name'])
        NOTIFICATION_TEMPLATE = Template("""Build #{{build.number}} \
{{build.status}} for Job {{fullname}} ({{build.full_url}})
{% if build.scm %}Based on {{build.scm.url}}/commit/{{build.scm.commit}} \
({{build.scm.branch}}){% endif %}""")
        return NOTIFICATION_TEMPLATE.render(body)

    @staticmethod
    def build_parameters(params):
        if len(params) > 0:
            return {param.split(':')[0]: param.split(':')[1]
                    for param in params}
        return {'': ''}
Beispiel #4
0
class JenkinsBot(BotPlugin):
    """Basic Err integration with Jenkins CI"""

    min_err_version = '1.2.1'

    # max_err_version = '4.0.3'

    def get_configuration_template(self):
        return CONFIG_TEMPLATE

    def configure(self, configuration):
        if configuration is not None and configuration != {}:
            config = dict(chain(CONFIG_TEMPLATE.items(),
                                configuration.items()))
        else:
            config = CONFIG_TEMPLATE
        super(JenkinsBot, self).configure(config)
        return

    def check_configuration(self, configuration):
        self.log.debug(configuration)
        for c, v in configuration.items():
            if c == 'URL':
                if not validators.url(v):
                    raise ValidationException(
                        'JENKINS_URL is not a well formed URL')
            elif c in ['USERNAME', 'PASSWORD', 'RECEIVE_NOTIFICATION']:
                if len(v) == 0 or not isinstance(v, str):
                    raise ValidationException(
                        "{} is a required string config setting".format(c))
            elif c in ['CHATROOMS_NOTIFICATION']:
                if not isinstance(v, tuple):
                    raise ValidationException(
                        "{} should be of type tuple".format(c))
        return

    def connect_to_jenkins(self):
        """Connect to a Jenkins instance using configuration."""
        self.log.debug('Connecting to Jenkins ({0})'.format(
            self.config['URL']))
        self.jenkins = Jenkins(url=self.config['URL'],
                               username=self.config['USERNAME'],
                               password=self.config['PASSWORD'])
        return

    def broadcast(self, mess):
        """Shortcut to broadcast a message to all elligible chatrooms."""
        chatrooms = (self.config['CHATROOMS_NOTIFICATION']
                     if self.config['CHATROOMS_NOTIFICATION'] else
                     self.bot_config.CHATROOM_PRESENCE)

        for room in chatrooms:
            self.send(self.build_identifier(room), mess)
        return

    @webhook(r'/jenkins/notification')
    def handle_notification(self, incoming_request):
        if not self.config['RECEIVE_NOTIFICATION']:
            return 'Notification handling is disabled.'

        self.log.debug(repr(incoming_request))
        self.broadcast(self.format_notification(incoming_request))
        return

    @botcmd
    def jenkins_list(self, mess, args):
        """List all jobs, optionally filter them using a search term."""
        self.connect_to_jenkins()
        return self.format_jobs([
            job for job in self.jenkins.get_jobs(folder_depth=None)
            if args.lower() in job['fullname'].lower()
        ])

    @botcmd
    def jenkins_running(self, mess, args):
        """List all running jobs."""
        self.connect_to_jenkins()

        jobs = [
            job for job in self.jenkins.get_jobs() if 'anime' in job['color']
        ]
        return self.format_running_jobs(jobs)

    @botcmd(split_args_with=None)
    def jenkins_param(self, mess, args):
        """List Parameters for a given job."""
        if len(args) == 0:
            return 'What Job would you like the parameters for?'

        self.connect_to_jenkins()

        job = self.jenkins.get_job_info(args[0])
        if job['actions'][1] != {}:
            job_param = job['actions'][1]['parameterDefinitions']
        elif job['actions'][0] != {}:
            job_param = job['actions'][0]['parameterDefinitions']
        else:
            job_param = []

        return self.format_params(job_param)

    @botcmd(split_args_with=None)
    def jenkins_build(self, mess, args):
        """Build a Jenkins Job with the given parameters
        Example: !jenkins build test_project FOO:bar
        """
        if len(args) == 0:  # No Job name
            return 'What job would you like to build?'

        self.connect_to_jenkins()
        params = self.build_parameters(args[1:])

        # Is it a parameterized job ?
        job = self.jenkins.get_job_info(args[0])
        if job['actions'][0] == {} and job['actions'][1] == {}:
            self.jenkins.build_job(args[0])
        else:
            self.jenkins.build_job(args[0], params)

        running_job = self.search_job(args[0])
        return 'Your job should begin shortly: {0}'.format(
            self.format_jobs(running_job))

    @botcmd(split_args_with=None)
    def build(self, mess, args):
        """Shortcut for jenkins_build"""
        return self.jenkins_build(mess, args)

    @botcmd
    def jenkins_unqueue(self, msg, args):
        """Cancel a queued job.
        Example !jenkins unqueue foo
        """
        self.connect_to_jenkins()

        try:
            queue = self.jenkins.get_queue_info()

            job = next((job for job in queue
                        if job['task']['name'].lower() == args.lower()), None)

            if job:
                self.jenkins.cancel_queue(job['id'])
                return 'Unqueued job {0}'.format(job['task']['name'])
            else:
                return 'Could not find job {0}, but found the following: {1}'.format(
                    args, ', '.join(job['task']['name'] for job in queue))
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

    @botcmd(split_args_with=None)
    def jenkins_createjob(self, mess, args):
        """Create a Jenkins Job.
        Example: !jenkins createjob pipeline foo [email protected]:foo/bar.git
        """
        if len(args) < 2:  # No Job type or name
            return 'Oops, I need a type and a name for your new job.'

        if args[0] not in ('pipeline', 'multibranch'):
            return 'I\'m sorry, I can only create `pipeline` and \
                    `multibranch` jobs.'

        self.connect_to_jenkins()

        try:
            if args[0] == 'pipeline':
                self.jenkins.create_job(
                    args[1],
                    JENKINS_JOB_TEMPLATE_PIPELINE.format(repository=args[2]))

            elif args[0] == 'multibranch':
                repository = args[2].rsplit('/', maxsplit=2)[-2:]

                self.jenkins.create_job(
                    args[1],
                    JENKINS_JOB_TEMPLATE_MULTIBRANCH.format(
                        repo_owner=repository[0].split(':')[-1],
                        repo_name=repository[1].strip('.git')))
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)
        return 'Your job has been created: {0}/job/{1}'.format(
            self.config['URL'], args[1])

    @botcmd(split_args_with=None)
    def jenkins_deletejob(self, mess, args):
        """Delete a Jenkins Job.
        Example: !jenkins deletejob foo
        """
        if len(args) < 1:  # No job name
            return 'Oops, I need the name of the job you want me to delete.'

        self.connect_to_jenkins()

        try:
            self.jenkins.delete_job(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your job has been deleted.'

    @botcmd(split_args_with=None)
    def jenkins_enablejob(self, mess, args):
        """Enable a Jenkins Job.
        Example: !jenkins enablejob foo
        """
        if len(args) < 1:  # No job name
            return 'Oops, I need the name of the job you want me to enable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.enable_job(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your job has been enabled.'

    @botcmd(split_args_with=None)
    def jenkins_disablejob(self, mess, args):
        """Disable a Jenkins Job.
        Example: !jenkins disablejob foo
        """
        if len(args) < 1:  # No job name
            return 'Oops, I need the name of the job you want me to disable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.disable_job(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your job has been disabled.'

    @botcmd(split_args_with=None)
    def jenkins_createnode(self, mess, args):
        """Create a Jenkins Node with a JNLP Launcher with optionnal labels.
        Example: !jenkins createnode runner-foo-laptop /home/foo # without labels
        Example: !jenkins createnode runner-bar-laptop /home/bar linux docker # with labels
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need a name and a working dir for your new node.'

        self.connect_to_jenkins()

        try:
            self.jenkins.create_node(name=args[0],
                                     remoteFS=args[1],
                                     labels=' '.join(args[2:]),
                                     exclusive=True,
                                     launcher=LAUNCHER_JNLP)
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been created: {0}/computer/{1}'.format(
            self.config['URL'], args[0])

    @botcmd(split_args_with=None)
    def jenkins_deletenode(self, mess, args):
        """Delete a Jenkins Node.
        Example: !jenkins deletenode runner-foo-laptop
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need the name of the node you want me to delete.'

        self.connect_to_jenkins()

        try:
            self.jenkins.delete_node(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been deleted.'

    @botcmd(split_args_with=None)
    def jenkins_enablenode(self, mess, args):
        """Enable a Jenkins Node.
        Example: !jenkins enablenode runner-foo-laptop
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need the name of the node you want me to enable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.enable_node(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been enabled.'

    @botcmd(split_args_with=None)
    def jenkins_disablenode(self, mess, args):
        """Disable a Jenkins Node.
        Example: !jenkins disablenode runner-foo-laptop
        """
        if len(args) < 1:  # No node name
            return 'Oops, I need the name of the node you want me to disable.'

        self.connect_to_jenkins()

        try:
            self.jenkins.disable_node(args[0])
        except JenkinsException as e:
            return 'Oops, {0}'.format(e)

        return 'Your node has been disabled.'

    def search_job(self, search_term):
        self.log.debug('Querying Jenkins for job "{0}"'.format(search_term))
        return [
            job for job in self.jenkins.get_jobs(folder_depth=None)
            if search_term.lower() == job['fullname'].lower()
        ]

    def format_running_jobs(self, jobs):
        if len(jobs) == 0:
            return 'No running jobs.'

        jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs]
        return '\n\n'.join([
            '%s (%s)\n%s' % (job['name'], job['lastBuild']['url'],
                             job['healthReport'][0]['description'])
            for job in jobs_info
        ]).strip()

    @staticmethod
    def format_jobs(jobs):
        if len(jobs) == 0:
            return 'No jobs found.'

        max_length = max([len(job['fullname']) for job in jobs])
        return '\n'.join([
            '%s (%s)' % (job['fullname'].ljust(max_length), job['url'])
            for job in jobs
        ]).strip()

    @staticmethod
    def format_params(job):
        """Format job parameters."""
        if len(job) == 0:
            return 'This job is not parameterized.'
        PARAM_TEMPLATE = Template("""{% for p in params %}Type: {{p.type}}
Description: {{p.description}}
Default Value: {{p.defaultParameterValue.value}}
Parameter Name: {{p.name}}

{% endfor %}""")
        return PARAM_TEMPLATE.render({'params': job})

    @staticmethod
    def format_notification(body):
        body['fullname'] = body.get('fullname', body['name'])
        NOTIFICATION_TEMPLATE = Template("""Build #{{build.number}} \
{{build.status}} for Job {{fullname}} ({{build.full_url}})
{% if build.scm %}Based on {{build.scm.url}}/commit/{{build.scm.commit}} \
({{build.scm.branch}}){% endif %}""")
        return NOTIFICATION_TEMPLATE.render(body)

    @staticmethod
    def build_parameters(params):
        if len(params) > 0:
            return {
                param.split(':')[0]: param.split(':')[1]
                for param in params
            }
        return {'': ''}
class JenkinsNotifier(BotPlugin):
    """JenkinsBot is an Err plugin to manage Jenkins CI jobs from your chat platform like Slack."""

    status = {'blue':'SUCCESS', 'blue_anime':'IN PROGRESS','red': 'FAILED', 'red_anime': 'IN PROGRESS', 'disabled':   'DISABLED', 'aborted':'ABORTED', 'notbuilt': 'NOTBUILT', 'yellow': 'UNSTABLE'}
    failedjobsstring = " "


    def __init__(self, bot, name):
        self.jenkins = Jenkins(JENKINS_URL, JENKINS_USERNAME, JENKINS_TOKEN)
        super().__init__(bot, name) 


    @botcmd(split_args_with=None)
    def jn_build(self, msg, args):
        """Build the job specified by jobName. You can add params!"""

        # Params are passed like "key1=value1 key2=value2"
        params = {}
        #try:
        #    for arg in args[1:]:
        #        params[arg.split('=', 1)[0]] = arg.split('=', 1)[1]
        #except IndexError:
        #    return "I don'G like that params! Try with this format: key1=value1 key2=value2..."
        jobName = ''.join([args[0],' ',args[1]]) #TODO handle jobname with spaces in it, space is cosidered argument splitter  
        try:
            self.jenkins.build_job(jobName, params)
        except NotFoundException:
            return ' '.join(["Sorry, I can't find the job. Typo maybe?"," ARGS=",jobName])

        return ' '.join(["The job", args[0].strip(), "has been sent to the queue to be built."])


    @botcmd
    def jn_cancel(self, msg, args):
        """Cancel a job in the queue by jobId."""

        try:
            self.jenkins.cancel_queue(args.strip())
        except NotFoundException:
            return "Sorry, I can't find the job. Maybe the ID does not exist."

        return "Job canceled from the queue."


    @botcmd
    def jn_list(self, msg, args):
        """List Jenkins jobs. You can filter with strings."""

        self.send(msg.to, "I'm getting the jobs list from Jenkins...")

        search_term = args.strip().lower()
        jobs = [job for job in self.jenkins.get_jobs()
                if search_term.lower() in job['name'].lower()]

        return self.format_jobs(jobs)


    @botcmd
    def jn_status(self, msg, args):
        """List Jenkins jobs with their current status."""

        self.send(msg.to, "I'm getting the jobs with status Jenkins...")

        search_term = args.strip().lower()
        jobs = [job for job in self.jenkins.get_jobs()
                if search_term.lower() in job['fullname'].lower()]

        return self.format_job_status(jobs)




    @botcmd
    def jn_describe(self, msg, args):
        """Describe the job specified by jobName."""

        try:
            job = self.jenkins.get_job_info(args.strip())
        except NotFoundException:
            return "Sorry, I can't find the job. Typo maybe?"

        return ''.join([
            'Name: ', job['name'], '\n',
            'URL: ', job['url'], '\n',
            'Description: ', 'None' if job['description'] is None else job['description'], '\n',
            'Next Build Number: ',
            str('None' if job['nextBuildNumber'] is None else job['nextBuildNumber']), '\n',
            'Last Successful Build Number: ',
            str('None' if job['lastBuild'] is None else job['lastBuild']['number']), '\n',
            'Last Successful Build URL: ',
            'None' if job['lastBuild'] is None else job['lastBuild']['url'], '\n'
        ])


    @botcmd
    def jn_running(self, msg, args):
        """List running jobs."""

        self.send(msg.to, "I will ask for the current running builds list!")

        jobs = self.jenkins.get_running_builds()

        return self.format_running_jobs(jobs)


    @botcmd(split_args_with=None)
    def jn_stop(self, msg, args):
        """Stop the building job specified by jobName and jobNumber."""

        try:
            int(args[1].strip())
        except ValueError:
            return "You have to specify the jobNumber: \"!jenkins stop <jobName> <jobNumber>"

        try:
            self.jenkins.stop_build(args[0].strip(), int(args[1].strip()))
        except NotFoundException:
            return "Sorry, I can't find the job. Typo maybe?"

        return ' '.join(["The job", args[0].strip(), "has been stopped."])


    @botcmd
    def jn_queue(self, msg, args):
        """List jobs in queue."""

        self.send(msg.to, "Getting the job queue...")

        jobs = self.jenkins.get_queue_info()

        return self.format_queue_jobs(jobs)


    @botcmd
    def jn_msgtimer(self, msg, args):
        """Sends messages at fix intervals."""
        yield "Starting timer"
        self.start_poller(5, self.my_callback)
        self.send(msg.to,
        "Boo! Bet you weren't expecting me, were you?", 
        )


    def my_callback(self):
        self.log.info('I am called every 5sec')
        self.send(self.build_identifier("#errbottestchannel"), "I am called every 5sec", )

    @botcmd 
    def jn_failed(self, msg, args):

        """List Jenkins jobs with failed status."""
        self.send(msg.to, "I'm getting the failed jobs ...")
        failedJobs = []
        search_term = args.strip().lower()
        jobs = [job for job in self.jenkins.get_jobs()
                if search_term.lower() in job['fullname'].lower()]
        for job in jobs:
            if self.status[job['color']] == 'FAILED':
               failedJobs.append(job)
        return self.format_job_status(failedJobs)



# SUPPORT FUNCTIONS START HERE

    def format_jobs(self, jobs):
        """Format jobs list"""

        if len(jobs) == 0:
            return "I haven't found any job."

        max_length = max([len(job['name']) for job in jobs])
        return '\n'.join(['%s (%s)' % (job['name'].ljust(max_length),
                                       job['url']) for job in jobs]).strip()


    def format_queue_jobs(self, jobs):
        """Format queue jobs list"""

        if len(jobs) == 0:
            return "It seems that there is not jobs in queue."

        return '\n'.join(['%s - %s (%s)' % (str(job['id']),
                                            job['task']['name'],
                                            job['task']['url']) for job in jobs]).strip()


    def format_running_jobs(self, jobs):
        """Format running jobs list"""

        if len(jobs) == 0:
            return "There is no running jobs!"

        return '\n'.join(['%s - %s (%s) - %s' % (str(job['number']),
                                                 job['name'],
                                                 job['url'],
                                                 job['executor']) for job in jobs]).strip()

    @botcmd
    def jn_queue(self, msg, args):
        """List jobs in queue."""

        self.send(msg.to, "Getting the job queue...")

        jobs = self.jenkins.get_queue_info()

        return self.format_queue_jobs(jobs)


    def format_jobs(self, jobs):
        """Format jobs list"""

        if len(jobs) == 0:
            return "I haven't found any job."

        max_length = max([len(job['name']) for job in jobs])
        return '\n'.join(['%s (%s)' % (job['name'].ljust(max_length),
                                       job['url']) for job in jobs]).strip()


    def format_queue_jobs(self, jobs):
        """Format queue jobs list"""

        if len(jobs) == 0:
            return "It seems that there is not jobs in queue."

        return '\n'.join(['%s - %s (%s)' % (str(job['id']),
                                            job['task']['name'],
                                            job['task']['url']) for job in jobs]).strip()


    def format_running_jobs(self, jobs):
        """Format running jobs list"""

        if len(jobs) == 0:
            return "There is no running jobs!"

        return '\n'.join(['%s - %s (%s) - %s' % (str(job['number']),
                                                 job['name'],
                                                 job['url'],
                                                 job['executor']) for job in jobs]).strip()

    def format_job_status(self, jobs):
        """Format job status"""

        if len(jobs) == 0:
            return "there are no jobs to return"
        return '\n'.join(['%s (%s)' % (job['fullname'], self.status[job['color']]) for job in jobs]).strip()
Beispiel #6
0
class JenkinsBot(BotPlugin):
    """JenkinsBot is an Err plugin to manage Jenkins CI jobs from your chat platform like Slack."""
    def __init__(self, bot):
        self.jenkins = Jenkins(JENKINS_URL, JENKINS_USERNAME, JENKINS_PASSWORD)
        super().__init__(bot)

    @botcmd(split_args_with=None)
    def jenkins_build(self, msg, args):
        """Build the job specified by jobName. You can add params!"""

        # Params are passed like "key1=value1 key2=value2"
        params = {}
        try:
            for arg in args[1:]:
                params[arg.split('=', 1)[0]] = arg.split('=', 1)[1]
        except IndexError:
            return "I don't like that params! Try with this format: key1=value1 key2=value2..."

        try:
            self.jenkins.build_job(args[0].strip(), params)
        except NotFoundException:
            return "Sorry, I can't find the job. Typo maybe?"

        return ' '.join([
            "The job", args[0].strip(),
            "has been sent to the queue to be built."
        ])

    @botcmd
    def jenkins_cancel(self, msg, args):
        """Cancel a job in the queue by jobId."""

        try:
            self.jenkins.cancel_queue(args.strip())
        except NotFoundException:
            return "Sorry, I can't find the job. Maybe the ID does not exist."

        return "Job canceled from the queue."

    @botcmd
    def jenkins_list(self, msg, args):
        """List Jenkins jobs. You can filter with strings."""

        self.send(msg.to, "I'm getting the jobs list from Jenkins...")

        search_term = args.strip().lower()
        jobs = [
            job for job in self.jenkins.get_jobs()
            if search_term.lower() in job['name'].lower()
        ]

        return self.format_jobs(jobs)

    @botcmd
    def jenkins_describe(self, msg, args):
        """Describe the job specified by jobName."""

        try:
            job = self.jenkins.get_job_info(args.strip())
        except NotFoundException:
            return "Sorry, I can't find the job. Typo maybe?"

        return ''.join([
            'Name: ', job['name'], '\n', 'URL: ', job['url'], '\n',
            'Description: ',
            'None' if job['description'] is None else job['description'], '\n',
            'Next Build Number: ',
            str('None'
                if job['nextBuildNumber'] is None else job['nextBuildNumber']),
            '\n', 'Last Successful Build Number: ',
            str('None' if job['lastBuild'] is None else job['lastBuild']
                ['number']), '\n', 'Last Successful Build URL: ',
            'None' if job['lastBuild'] is None else job['lastBuild']['url'],
            '\n'
        ])

    @botcmd
    def jenkins_running(self, msg, args):
        """List running jobs."""

        self.send(msg.to, "I will ask for the current running builds list!")

        jobs = self.jenkins.get_running_builds()

        return self.format_running_jobs(jobs)

    @botcmd(split_args_with=None)
    def jenkins_stop(self, msg, args):
        """Stop the building job specified by jobName and jobNumber."""

        try:
            int(args[1].strip())
        except ValueError:
            return "You have to specify the jobNumber: \"!jenkins stop <jobName> <jobNumber>"

        try:
            self.jenkins.stop_build(args[0].strip(), int(args[1].strip()))
        except NotFoundException:
            return "Sorry, I can't find the job. Typo maybe?"

        return ' '.join(["The job", args[0].strip(), "has been stopped."])

    @botcmd
    def jenkins_queue(self, msg, args):
        """List jobs in queue."""

        self.send(msg.to, "Getting the job queue...")

        jobs = self.jenkins.get_queue_info()

        return self.format_queue_jobs(jobs)

    def format_jobs(self, jobs):
        """Format jobs list"""

        if len(jobs) == 0:
            return "I haven't found any job."

        max_length = max([len(job['name']) for job in jobs])
        return '\n'.join([
            '%s (%s)' % (job['name'].ljust(max_length), job['url'])
            for job in jobs
        ]).strip()

    def format_queue_jobs(self, jobs):
        """Format queue jobs list"""

        if len(jobs) == 0:
            return "It seems that there is not jobs in queue."

        return '\n'.join([
            '%s - %s (%s)' %
            (str(job['id']), job['task']['name'], job['task']['url'])
            for job in jobs
        ]).strip()

    def format_running_jobs(self, jobs):
        """Format running jobs list"""

        if len(jobs) == 0:
            return "There is no running jobs!"

        return '\n'.join([
            '%s - %s (%s) - %s' %
            (str(job['number']), job['name'], job['url'], job['executor'])
            for job in jobs
        ]).strip()