-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
root
committed
Jun 11, 2017
1 parent
3ced7b8
commit 3fbb4ca
Showing
5 changed files
with
500 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.