淘先锋技术网

首页 1 2 3 4 5 6 7

十四、Jenkins打包完成后,执行脚本,将版本发行包压缩上传禅道提交禅道版本

十三、禅道登录/提交版本/编辑版本接口 ,书接上回,在禅道中注册一个Jenkins账号,利用禅道的接口,提交到禅道中,具体代码如下

基本流程:
Jenkins打包完成==>执行python脚本==>包括打版本压缩包==>打源码压缩包==>新建或编辑版本==>上传发行包和源码包==>禅道版本新增完成

1. 代码上传Jenkins服务器 zentao_add_edit_version.py

代码上传Jenkins服务器 zentao_add_edit_version.py

在这里插入图片描述

# -*- coding: utf-8 -*-
"""
-------------------------------------------------------------------------------
File    : zentao_add_edit_version.py
Time    : 2023/4/11 12:05
author  : mojin
Email   : [email protected]
-------------------------------------------------------------------------------
"""


import requests
import datetime
import os

import sys
import time
import urllib.request
import shutil
import zipfile
import os,datetime
import logging
# 设置日志输出的格式
logging.basicConfig(format='%(asctime)s %(levelname)s-%(filename)s-[%(funcName)s] line %(lineno)d - %(message)s', level=logging.INFO)

class VersionManagement():
  '''
  打包完成后在禅道上传发行包,补充版本描述创建下个版本 用于fix bug

  '''
  def __init__(self):
    self.build_info=eval(sys.argv[1])

    # build_info = {
    #   'building_number': '%BUILD_NUMBER%',
    #   'execution': '105',
    #   'product': '35',
    #   'project_zt':'104',
    #   'build_name': '*v1.0.0.6.service.***',
    #   'build_name_keywords': '*,service',
    #   'scmPath': '%GIT_URL%',
    #   'filePath': '%GIT_URL%',
    #   'desc_doc': '%SCM_CHANGELOG%',
    #   'files_path': '%WORKSPACE%\\service-admin\\target\\service-admin.jar,%WORKSPACE%',
    #   'branch': 'dev',
    #   'project_name': '%PROJECT_NAME%',
    # }
    #
    build_info2 = {
      'building_number': '%BUILD_NUMBER%',#构建编号
      'execution': '105',#禅道迭代 id
      'product': '35',  #禅道产品id
      'project_zt': '104',  #产品 禅道项目id
      'build_name': '*v1.0.0.6.web.***',   #创建下个新版本的名称
      'build_name_keywords': '*,web',   #标识字符,用于找到在版本名称找到换个字符标书,编辑补充发行包和描述,下载地址等等信息
      'scmPath': '%GIT_URL%',  #代码地址
      'filePath': '%GIT_URL%',  #下载地址
      'desc_doc': '%SCM_CHANGELOG%',  # 版本描述
      'files_path': '%WORKSPACE%\\dist,%WORKSPACE%', #打包要删除的目录node_modules
      'branch': 'dev',  #分支
      'project_name': '%PROJECT_NAME%',  #项目名称
    }

    # self.build_info={
    #   'building_number':'265',
    #   'execution':'3',
    #   'product': '2',
    #   'build_name': '*v1.0.1.h5.***',
    #   'build_name_keywords': '*,h5',
    #   'scmPath': 'http://192.16***',
    #   'filePath': 'http://192***',
    #   'desc_doc': '*****变更记录************************************************************************************',
    #   'files_path': 'E:/java_xm/service-admin.jar,E:\\java_xm\\services',
    #   'branch':'dev',
    #   'project_name':'services',
    #   'version_txt_path':'services',
    # }
    # 'source_code_url':'http://192.168.1.******************chive/dev.zip',
    # 'source_code_zip':'service-services.zip'
    # self.dir_path = r'E:\java_xm\service\mobile\risk-pro'
    # self.zip_filename = 'service-mobile'

    self.building_number=self.build_info['building_number'] #构建编号
    self.execution=self.build_info['execution']  #禅道迭代 id
    self.product = self.build_info['product']  #禅道产品id
    self.project_zt=self.build_info['project_zt']  #产品 禅道项目id
    self.build_name=self.build_info['build_name']   #创建下个新版本的名称
    self.build_name_keywords = self.build_info['build_name_keywords']   #标识字符,用于找到在版本名称找到换个字符标书,编辑补充发行包和描述,下载地址等等信息
    self.scmPath=self.build_info['scmPath']   #代码地址
    self.filePath=self.build_info['filePath']  #下载地址
    self.desc_doc=self.build_info['desc_doc'] # 版本描述
    self.files_path=self.build_info['files_path'] #r'E:/java_xm/service-admin.jar,E:/java_xm/service-admin.jar' 附件路径
    self.branch=self.build_info['branch']  #代码分支
    self.project_name = self.build_info['project_name']  # jenkins项目名称
    self.exclude_dir=self.build_info.get('exclude_dir','node_modules') #打包要删除的目录node_modules
    self.version_file=self.build_info.get('version_file','')
    # self.source_code_zip=self.build_info['source_code_zip']  #源码包名
    # self.source_code_url =self.build_info['source_code_url'] #源码链接





    self.url ='http://192.168.1.52:81'
    self.account="jenkins"
    self.password='jenkins135766'
    # self.building_number='265' #构建编号
    # self.execution='3'  #迭代
    # self.product = '2'  #产品
    # self.build_name='*v1.0.1.h5.***'  #创建下个新版本的名称
    # self.build_name_keywords = '*,h5'  #标识字符,用于找到在版本名称找到换个字符标书,编辑补充发行包和描述,下载地址等等信息
    # self.scmPath='代码地址'  #代码地址
    # self.filePath='下载地址' #下载地址
    # self.desc_doc="[APP\n]"
    # self.files_path=r'E:/java_xm/service-admin.jar,E:/java_xm/service-admin.jar'

    self.file_path_list=[]
    self.Package_Name=''

    self.source_code_zip=''
    self.current_time = datetime.datetime.now().strftime("%Y-%m-%d")
    self.now_time=datetime.datetime.now().strftime("%Y%m%d%H%M%S")
    self.token=self.login()     #'fa7f18713d8921d98d84cffd567cb6a9'###self.login()
    self.headers = {
      'Token':  self.token,
      'Cookie': f'zentaosid= {self.token}'
    }

  def zipdir(self,dir_path,):
    """
    压缩指定路径中的所有文件和子目录到一个ZIP文件中。
    :param path: 要压缩的路径
    :param ziph: ZipFile对象,用于写入压缩文件
    :param exclude_dir: 要排除的目录名,默认为None表示不排除
    """
    # 创建 ZipFile 对象,并调用自定义的 zipdir() 函数进行压缩
    # zip_filename = self.Package_Name   #      self.Package_Name = f'{build_name}-{os.path.basename(file_path)}'
    zip_filename = f"{self.Package_Name}.zip"
    with zipfile.ZipFile(zip_filename, mode='w') as ziph:
      logging.info(f"正在将目录 {dir_path} 打包成 {zip_filename}...")
      # zipdir(dir_path, z, exclude_dir)

      for root, dirs, files in os.walk(dir_path):
        if self.exclude_dir and self.exclude_dir in dirs:
          dirs.remove(self.exclude_dir)  # 排除指定的目录
        for file in files:
          file_path = os.path.join(root, file)
          ziph.write(file_path, os.path.relpath(file_path, dir_path))

      zip_filename_path=r'./%s' % zip_filename

      self.file_path_list.append(zip_filename_path)

      return zip_filename_path



  def files_converting(self, dir_path):
    '''
    判断传来的参数是目录还是文件,是目录打包成压缩包输出路径,是文件直接输出路径

    :param dir_path:
    :return:
    '''
    if os.path.isfile(dir_path):

      file_name = os.path.basename(dir_path)

      new_path = f'{self.Package_Name}'


      logging.info(f'{dir_path},是一个文件')

      dir_path = [dir_path, new_path]
    elif os.path.isdir(dir_path):
      logging.info(f'{dir_path},是一个目录')
      zip_filename = f"{self.Package_Name}.zip"
      dir_path =[ self.zipdir(dir_path),zip_filename]
    else:
      logging.info('无法判断', dir_path, '是文件还是目录')
      raise
    logging.info(f'{dir_path}')
    return dir_path

  def changes(self):
    changes = ''
    #self.desc_doc = self.desc_doc.replace('[', '').replace(']', '')
    n=1
    logging.info(f'更新内容:{self.desc_doc}')
    for i in self.desc_doc.split('\n'):

      if i != '':
        #<p><span>1.描述描述描述</span></p
        changes = changes + f'<p><span>{n}.{i}</span></p'
        #changes= changes + f'{n}.{i}\n'
      n += 1
    if changes != '':
      changes= f'<p><span>变更记录:(AFS)</span></p{changes}'

    else:
      changes = f'<p><span>变更记录:(AFS)</span></p<p><span>本次没有发生变化</span></p'
    logging.info(f'更新内容:{changes}')
    return changes

  def requests_api(self,path,payload,method,parame_type,file=None):
    url = f"{self.url}/{path}"
    if parame_type=='josn':
      parameter={'josn':payload}

    elif parame_type=='data':
      parameter={'data':payload}
    elif parame_type=='params':
      parameter={'params':payload}
    else:
      logging.error(f'输入的参数类型[{parame_type}]不符合要求!!!!')
      raise

    if file==None:
      file={}


    try:
      response = requests.request(method, url, headers=self.headers,**parameter,files=file)
      resp_dic = response.json()
      #logging.info(response.status_code)

    except Exception as e:
      resp_dic={"response":f'{e}'}
      logging.error(f'请求失败:{resp_dic}')
      raise


    return resp_dic

  def login(self): #登录
    url = f"{self.url}/zentao/api.php/v1/tokens"

    payload={
      'account':self.account,
      'password':self.password
    }
    response = requests.request("POST", url, headers={}, json=payload)
    resp_dic=response.json()
    #logging.info(resp_dic)
    if resp_dic.get('token','')=='':
      logging.error(f'登录失败!{resp_dic}')
      raise
    return resp_dic['token']

  def executions_builds_list(self,): #获取版本列表
    path = f"zentao/api.php/v1/executions/{self.execution}/builds"
    payload = {}
    response = self.requests_api( path, payload, 'GET', 'data',)
    #logging.info(f'获取版本列表:{response}')
    return response

  #版本详情
  def builds_info(self):
    path = f"zentao/api.php/v1/builds/366"
    payload={}
    response = self.requests_api(path, payload, 'GET', 'data', )
    logging.info(response)
    return response


  def add_version(self): #新增版本
    path = f"zentao/build-create-{self.execution}.json"

    payload = {
               #'isIntegrated': 'no',
               'execution': f'{self.execution}',
               'product': f'{self.product}',
               'name': self.build_name.replace('.***',f'.{int(self.building_number)+1}.***'),
               'builder': 'Jenkins',
               'date': self.current_time,
               # 'scmPath': '代码地址',
               # 'filePath': '下载地址',
               # 'desc': '<p>1.描述描述描述</p><p><span>2.描述描述描述</span></p>',
               #  'uid': '643603d229574',
               'project': self.project_zt
               }

    response = self.requests_api(path, payload, 'POST', 'data', )
    logging.info(f'新增下个版本:{response}')
    return response


  def edit_version(self,id,edit=1): #编辑版本

    if edit==1: #编辑
      path = f"zentao/build-edit-{id}.json"
    elif edit==2: #新增
      path = f"zentao/build-create-{self.execution}.json"
    else:
      logging.error(f'edit参数异常[{edit}]!!)')
      raise

    #'*v1.0.0.6.web.***'
    build_name=self.build_name.replace('.***',f'.{self.building_number}.***').replace("*","")
    try:
      with open(self.version_file, "r") as f:
        build_name = f.read()
        logging.info(f'读取新的版本号:{build_name}')
    except Exception as e:
      logging.info(f'没有读取到新本号,出现异常({e})')
      raise
      # build_name = f'{build_name}{self.now_time}'
      # logging.info(f'生成新版本号:({build_name})')



    payload = {

      #'branch[]': ' 0',
      'execution': f'{self.execution}',
      'product': f'{self.product}',
      #.replace('.***',f'.{self.building_number}.***')
      'name': build_name,
      'builder': 'Jenkins',
      'date': self.current_time,
      'scmPath': self.scmPath,
      'filePath': self.filePath,
      'desc':self.changes(),  #'1.版本描述',
      # 'uid': '6437b2ec9764a'
      'project': self.project_zt
    }
    files=[]
    files_path_list=self.files_path.split(',')

    #files_path_list.append(self.source_code_zip)
    logging.info(f'{files_path_list}')

    for file_path in files_path_list:
      self.Package_Name = f'{build_name}-{os.path.basename(file_path)}'
      file_path = self.files_converting(file_path)



      n=1
      while True:
        if n>180:
          logging.error('打压缩包超时……………………')
          raise

        try:
          logging.info(file_path)
          files.append(('files[]', (file_path[1], open(file_path[0], 'rb'))))
          break
        except Exception as e:

          logging.info(f'{file_path}')
          logging.info(f'打压缩包中……{e}')
          time.sleep(1)

      n+=1

    response = self.requests_api(path, payload, 'POST', 'data', files) #""#
    logging.info(f'新增或编辑版本:{response}')


    return response

  def main(self):
    #self.download_source()
    version_exists=True #版本是否存在的标识 默认版本不存在True,成功找到版本后 编辑成功后 修改标识为False 版本存在
    for build in self.executions_builds_list()['builds']:
      keywords_lsit=[]
      for keywords in self.build_name_keywords.split(','): #匹配版本找到后获取到版本id 进行编辑
        keywords_lsit.append(keywords in build['name'] ) #所有的版本标识 都存在 为T

      if False not in keywords_lsit:  # 列表中没有False
        logging.info(f'获取到版本id【{build["id"]}】')  #获取到了版本id
        logging.info(f'版本信息:{build}')

        self.edit_version(build["id"])    #编辑版本
        version_exists=False   #编辑版本存在的
        break
    if version_exists: #当版本不存在时 创建新版本,输入完整的数据 发行包 源码等等
      self.edit_version('',edit = 2)


    self.add_version() #创建下个版本


    for file_path in self.file_path_list: #删除之前创建的压缩包

      if os.path.exists(file_path):
        os.remove(file_path)
        logging.info(f"删除上传完成的压缩包文件[{file_path}]")
      else:
        logging.info(f'压缩包file不存在[{file_path}]')






if __name__=="__main__":
  VersionMan=VersionManagement()
  VersionMan.main()






2. 配置Jenkins服务器 执行zentao_add_edit_version.py

在这里插入图片描述
在这里插入图片描述
Windows执行python3脚本:

cd ..
set build_info="{'building_number':'%BUILD_NUMBER%','execution':'108','product':'35','project_zt':'104','build_name':'*v1.1.0.h5.***','build_name_keywords':'*,h5','scmPath':'%GIT_URL%','filePath':'%GIT_URL%','desc_doc':'%SCM_CHANGELOG%','files_path':r'%WORKSPACE%\\risk-pro\\dist,%WORKSPACE%','branch':'release','project_name':'%PROJECT_NAME%','version_file':r'%WORKSPACE%\risk-pro\public\version.txt'}"
python  D:\anaconda\jks\zentao_add_edit_version.py %build_info%

centos7执行python3脚本:

source /usr/python/envs/everyday/bin/activate #激活虚拟环境
deactivate #退出虚拟环境

十六、centos7 下给python3创建虚拟环境

source /usr/python/envs/everyday/bin/activate
cd ..
build_info="{'building_number':'$BUILD_NUMBER','execution':'108','product':'35','project_zt':'104','build_name':'*v1.1.0.web.***','build_name_keywords':'*,web','scmPath':'$GIT_URL','filePath':'$GIT_URL','desc_doc':'$SCM_CHANGELOG','files_path':r'${WORKSPACE}/dist,$WORKSPACE','branch':'release','project_name':'$PROJECT_NAME','version_file':r'${WORKSPACE}/public/version.txt'}"
python3 /jenkins/jks/zentao_add_edit_version.py "$build_info"
deactivate

在这里插入图片描述

3. 版本创建/编辑完成

在这里插入图片描述

4. 提交BUG选择创建的版本

在这里插入图片描述