Skip to content

Commit

Permalink
add code
Browse files Browse the repository at this point in the history
  • Loading branch information
root committed Jun 11, 2017
1 parent 3ced7b8 commit 3fbb4ca
Show file tree
Hide file tree
Showing 5 changed files with 500 additions and 31 deletions.
49 changes: 26 additions & 23 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
# Config file for automatic testing at travis-ci.org
# This file will be regenerated if you run travis_pypi_setup.py

language: python
python:
- 3.5
- 3.4
- 3.3
- 2.7
- 2.6

# command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors
install: pip install -U tox-travis

# command to run tests, e.g. python setup.py test
script: tox

# After you create the Github repo and add it to Travis, run the
# travis_pypi_setup.py script to finish PyPI deployment setup
# This file was autogenerated and will overwrite each time you run travis_pypi_setup.py
deploy:
provider: pypi
distributions: sdist bdist_wheel
user: 510908220
password:
secure: PLEASE_REPLACE_ME
on:
tags: true
repo: 510908220/lintjenkins
secure: !!binary |
VWZ0Nkl0TkFPVkVVZ0d1WUN3UEVZbWtKajdxNmYyd1pHY3ovejJLYU1HVWhUdjFZVG1YdVZOVnBx
aWo4UDNCZnRseHRndDh6M282YkRoVHhGQVNFUHJBVjBSc0NFbkFqMFF5ZUUvWHcxK0gzY1hWaUoy
dm5YdkJud3R1REVmV0liSW03Z01pS0VlajVwT3U2UVdpVkFUSUJrWEo4UlIzRVVZbE1CQzRpK3Zr
T1pXMnpTbCtOZnVwazQ4RUJHd25mYWMrQVNjcUNNR0t2aEtjSHg2cXR4WVRXdmxzOTBHSkdMckxL
Wm1xc1lQcUcvam85dU05eTEvVVFKMi9QeC9sd3UrRUhheFlrOXpIQkZ6MnY5bytDSHd6UXZXNUZB
VElYNGFVM1Q5NHJFWW5tQUNXZG82OGlNZW0zM0g3T1BDOFk1TmdPN3dqT1lxN0RBTDZwRHZOd2o5
Y1hBOFpPREVOS3VtWGc3OHRncUlTNVFUOXdYZFFybDlqdmdyazFDRUVINkEyN3FqSGVVUFRpYWRD
MEhjQXN3QUJZYnBhUVkySnlJSkplb0YzdmFlNVlKdUJzdmE0eWtpNC9uejlQTy9BWHFNSmRzU0hN
TEs2SjJhOXFFbjJoN0duYnBWaCt5ZlVQYzAvUzNtZHhnM2Q5TTN0VDBhMzFuTm94OFhReTZ3Skd5
dHVKSzZHVWJpWHhOS2pqUFMxdkVMYzJGc3Fpc2Z4SkJHZVNvRFQyWjF3Syt1bHRqY2VOSUhyU0hv
bWdST2svSHVydi9SOFd3a3ZtQ01nZDdjYXY1VGxIUER3RUtuYjMvZjd3aEkvYXhEUW41MEl3aDhU
S01VWUlKZmtRNUh4Nnh3NUJzVjBIemE3RTJ5SDI1OStQdDJjUTIxMmlNR29ralpnS3FZUFlXK3M9
true:
python: 2.7
repo: 510908220/lintjenkins
tags: true
install: pip install -U tox-travis
language: python
python:
- 3.5
- 3.4
- 3.3
- 2.7
- 2.6
script: tox
164 changes: 157 additions & 7 deletions lintjenkins/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,157 @@
# -*- coding: utf-8 -*-

"""Top-level package for lintjenkins."""

__author__ = """westdoorblowcola"""
__email__ = '510908220@qq.com'
__version__ = '0.1.0'
# -*- encoding: utf-8 -*-


import pendulum
try:
from urllib.parse import urljoin
except:
from urlparse import urljoin

from pyquery import PyQuery as pq
import jenkins

from . import template
from . import credentials


class LintException(Exception):
pass


class LintJobExistException(LintException):
pass


class LintJobFailedException(LintException):
pass


class LintJobRuningdException(LintException):
pass


class LintJenkins(object):

def __init__(self, jenkins_url, username, password):
self.jenkins_url = jenkins_url
self.username = username
self.password = password
self.jenkins_server = jenkins.Jenkins(
self.jenkins_url,
username=self.username,
password=self.password)
self.svn_credential_manager = credentials.SvnCredentialManager(
self.jenkins_url,
username=self.username,
password=self.password)

def add_job(self, svn, username, password, job_name, description=""):
"""
根据svn创建一个支持pylint的jenkins job,进行代码检查.
"""

# step1: 确保job不存在
if self.jenkins_server.job_exists(job_name):
raise LintJobExistException("lint job has exist")

# step2: 获取创建job需要的认证id
credential_id = self.svn_credential_manager.get_svn_credential(
svn,
username,
password)

# step3: 创建支持pylint检查代码的job
# description, remote, credentialsid
self.jenkins_server.create_job(
job_name, template.JOB_CONFIG_PYLINT % ("", svn, credential_id))

def delete_job(self, job_name):
# step1: 确保job不存在
if self.jenkins_server.job_exists(job_name):
raise LintJobExistException("lint job has exist")
self.jenkins_server.delete_job(job_name)

def get_build_numbers(self, job_name):
"""
以后需要获取全部job构建号.
"""
job_info = self.jenkins_server.get_job_info(
job_name, fetch_all_builds=True)
return [build['number'] for build in job_info['builds']]

def _get_job_violation(self, job_name, build_no):
"""
获取violations页面这里的. 由于目前没找到直接获取代码检查结果信息的接口,这里就暂时抓取页面提取信息
Type Violations Files in violation
pylint 845 (+6) 71 (+1)
这里只考虑pylint一种检查,如果是多种检查的话应该就需要修改代码了.
"""
def get_td_value(td_element):
"""
一般的值都是为<td>666</td>,当有颜色时(比如警格个数变化)会多一个<span>子元素.
"""
try:
text = td_element.find('span').text.strip()
except:
text = td_element.text.strip()
return int(text.split("(")[0].strip())

url = urljoin(self.jenkins_url,
"job/{job_name}/{build_no}/violations/".format(
job_name=job_name,
build_no=build_no)
)

d = pq(url)

td_elements = d(
"#main-panel > table:nth-child(3) > tbody > tr:nth-child(2) td")

return {
'violation_num': get_td_value(td_elements[1]),
'violation_file_num': get_td_value(td_elements[2])
}

def get_build_info(self, job_name, build_no):
"""
获取某一次构建信息
"""
job_build_info = self.jenkins_server.get_build_info(job_name, build_no)
result = job_build_info['result'] # FAILURE、UNSTABLE、SUCCESS、null
if result == 'FAILURE':
raise LintJobFailedException('build number is %s' % build_no)
if not result:
raise LintJobRuningdException('build number is %s' % build_no)

# 1. 基础构建信息
build_info = {
'datetime': pendulum.from_timestamp(job_build_info['timestamp'] / 1000, 'Asia/Shanghai').to_datetime_string(),
'duration': job_build_info['duration'] / 1000,
'result': job_build_info['result'],
'revisions': job_build_info['changeSet']['revisions'],
'commits': [],
'violation_info': {

},
'result_url': urljoin(
self.jenkins_url,
"job/{job_name}/{build_no}/violations/".format(
job_name=job_name,
build_no=build_no)
)
}

# 2. 开发者提交信息
for item in job_build_info['changeSet']['items']:
build_info['commits'].append({
'author': item['author']['fullName'],
'revision': item['revision'],
'msg': item['msg'],
'datetime': pendulum.from_timestamp(item['timestamp'] / 1000, 'Asia/Shanghai').to_datetime_string(),
'paths': item['paths']
})

# 3. 代码检查信息
build_info['violation_info'] = self._get_job_violation(
job_name, build_no)
return build_info
66 changes: 66 additions & 0 deletions lintjenkins/credentials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# -*- encoding:utf-8 -*-

"""
Jenkins 证书管理, 基于jenkinsapi. 目前实现功能:
1. 根据svn地址、用户名和密码获取证书id
使用:
jscm = SvnCredentialManager('http://ip:8080', username='username',
password='token')
print jscm.get_svn_credential("svn", 'username',
'password')
"""

import hashlib

import requests
from jenkinsapi.credential import UsernamePasswordCredential
from jenkinsapi.jenkins import Jenkins as JenkinsEx


class SvnCredentialManager(object):

def __init__(self, jenkins_url, username, password):
self.jenkins_url = jenkins_url
if self.jenkins_url[-1] == "/":
self.jenkins_url = self.jenkins_url[:-1]
self.jenkins = JenkinsEx(self.jenkins_url, username=username,
password=password)

def _get_svn_md5(self, svn):
m = hashlib.md5()
m.update(svn.encode('utf-8'))
return m.hexdigest()

def _get_or_create_svn_credential(self, svn, username, password):
creds_description = self._get_svn_md5(svn)
if creds_description not in self.jenkins.credentials.keys():
cred_dict = {
'description': creds_description,
'userName': username,
'password': password
}
self.jenkins.credentials[
creds_description] = UsernamePasswordCredential(cred_dict)

return self.jenkins.credentials[creds_description].credential_id

def _check_credential(self, svn, credential_id):
check_svn_url = "{jenkins_url}/job/tmp/descriptorByName/hudson.scm.SubversionSCM$ModuleLocation/checkCredentialsId".format(
jenkins_url=self.jenkins_url)

r = requests.get(check_svn_url, params={
'value': credential_id,
'remote': svn
})
return r.text == "<div/>"

def get_svn_credential(self, svn, username, password):
credential_id = self._get_or_create_svn_credential(
svn, username, password)
if not self._check_credential(svn, credential_id):
del self.jenkins.credentials[self._get_svn_md5(svn)]
raise Exception("check credential failed")
return credential_id

0 comments on commit 3fbb4ca

Please sign in to comment.