mini_toolbox.jenkins 源代码

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# 用于jenkins相关操作

__all__ = ['JenkinsTools']

import time
import charamel
from jenkinsapi.jenkins import Jenkins
from typing import Optional
from .logger import logger


[文档]class JenkinsTools(): """ 用于jenkins相关操作, 支持token Args: user (str): 用户名 token (str): 用户密码, 建议使用token server (str): jenkins服务器地址 """ def __init__(self, user: str, token: str, server: str): self.jenkins = Jenkins(baseurl=server, username=user, password=token, timeout=10) self.chardet = None
[文档] def build_job(self, job_name: str, params: Optional[dict] = None, poll: int = 20, bg=False, ccu=True) -> tuple: """ 调用执行job, 返回任务执行的状态信息 Args: job_name (str): jenkins的job名称 params (Optional[dict]): 用于参数化构建, 键值与job变量取交集生效 poll (int): 任务状态轮询周期, 默认为20s bg (bool): 后台执行,直接返回, 默认为False ccu (bool): 执行并发构建, 默认为True Returns: tuple: bg=False, ``(结果状态, 日志URL, 日志数据)``; bg=True, ``(job名称, 任务ID)`` """ # 是否并发构建 if not ccu: while self.jenkins[job_name].is_queued_or_running(): logger.debug('顺序执行, 5.2秒后重试') time.sleep(5.2) build_num = self.jenkins[job_name].get_next_build_number() self.jenkins.build_job(job_name, params=params) # 等待任务启动 while True: try: last_number = self.jenkins[job_name].get_last_buildnumber() if int(last_number) >= int(build_num): logger.debug('当前任务号已更新: 当前#{} 期望#{}'.format(last_number, build_num)) break else: logger.debug('当前任务号未更新, 2.5秒后重试: #{}'.format(last_number)) time.sleep(2.5) except Exception as err: logger.debug('未知异常, 5.2秒后重试: {}'.format(str(err))) time.sleep(5.2) # 后台执行, 直接返回 if bg: return (job_name, build_num) # 等待任务执行 while True: build_status, build_url, build_log = self.get_status(job_name, build_num) if build_status is None: logger.debug('任务执行中, {}秒后重试...'.format(poll)) time.sleep(poll) else: return (build_status, build_url, build_log)
[文档] def get_status(self, job_name: str, build_num: int, encoding: Optional[str] = None, errors: str = 'replace') -> tuple: """ 返回任务执行的状态信息 Args: job_name (str): jenkins的job名称 build_num (int): job的任务ID encoding (Optional[str]): 输出编码, 默认根据chardet自动判断, 建议默认 errors (str): 遇到错误时处理模式, 默认为 ``replace``, 可选: ``strict/ignore/replace`` Returns: tuple: ``(结果状态, 日志URL, 日志数据)`` """ try: build_task = self.jenkins[job_name].get_build(int(build_num)) except Exception as err: logger.debug('任务获取失败, 返回None, 异常信息: {} {}'.format(job_name, err)) return (None, None, None) build_status = build_task.get_status() build_url = build_task.get_build_url() + 'console' build_log = None if build_status is not None: if not self.chardet: self.chardet = charamel.Detector() build_log = build_task.get_console().encode('ISO-8859-1', errors=errors) encoding = self.chardet.detect(build_log) build_log = build_log.decode(encoding, errors=errors) logger.debug('任务执行状态: {} 任务地址: {}'.format(build_status, build_url)) logger.debug('任务日志编码: {} 详细日志: {}'.format(encoding, build_log)) return (build_status, build_url, build_log)
[文档] def has_job(self, job_name: str) -> bool: """ 返回任务执行的状态信息 Args: job_name (str): jenkins的job名称 Returns: bool: 是否存在 """ return self.jenkins.has_job(job_name)