Skip to content

Commit 31948e1

Browse files
committed
Merge branch 'cli-tests'
2 parents 8416feb + 4100fab commit 31948e1

10 files changed

Lines changed: 443 additions & 59 deletions

File tree

.travis.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
language: "python"
2+
python:
3+
- "2.7"
4+
- "3.4"
5+
- "3.5"
6+
install:
7+
- pip install flake8 mock==1.3.0
8+
script:
9+
- flake8
10+
- python setup.py test

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include README.md

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# Jenkins command line interface
2+
[![PyPI version](https://badge.fury.io/py/jenkins-cli.svg)](https://badge.fury.io/py/jenkins-cli)
3+
[![Build Status](https://travis-ci.org/LD250/jenkins-cli-python.svg?branch=cli-tests)](https://travis-ci.org/LD250/jenkins-cli-python)
4+
[![Code Health](https://landscape.io/github/LD250/jenkins-cli-python/cli-tests/landscape.svg?style=flat)](https://landscape.io/github/LD250/jenkins-cli-python/cli-tests)
5+
[![Requirements Status](https://requires.io/github/LD250/jenkins-cli-python/requirements.svg?branch=cli-tests)](https://requires.io/github/LD250/jenkins-cli-python/requirements/?branch=cli-tests)
6+
17
# Install:
28
```bash
39
git clone https://github.com/LD250/jenkins-cli-python.git

jenkins_cli/__init__.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
def main():
88
parser = argparse.ArgumentParser(prog='jenkins',
9-
#usage='%(prog)s',
109
description='Server URL, Username and password may be specified either by the command line arguments '
1110
'or in configuration file (.jenkins-cli). Command line arguments has the highest priority, '
1211
'after that the .jenkins-cli file from current folder is taking into account. If there is no'
@@ -19,15 +18,14 @@ def main():
1918
subparsers = parser.add_subparsers(title='Available commands', dest='jenkins_command')
2019

2120
jobs_parser = subparsers.add_parser('jobs', help='Show all jobs and their status')
22-
jobs_parser.add_argument('-d', help='Show disabled jobs', default=False, action='store_true')
21+
jobs_parser.add_argument('-a', help='Show only active jobs', default=False, action='store_true')
2322

24-
q_parser = subparsers.add_parser('queue', help='Shows builds queue')
23+
subparsers.add_parser('queue', help='Shows builds queue')
2524

26-
b_parser = subparsers.add_parser('building', help='Build executor status')
25+
subparsers.add_parser('building', help='Build executor status')
2726

2827
start_parser = subparsers.add_parser('start', help='Start job')
2928
start_parser.add_argument('job_name', help='Job to start', nargs='*')
30-
#start_parser.add_argument('-s', help='Silent mode (return only build number)')
3129

3230
start_parser = subparsers.add_parser('info', help='Job info')
3331
start_parser.add_argument('job_name', help='Job to to get info for')
@@ -54,10 +52,7 @@ def main():
5452
except CliException as e:
5553
print(e)
5654
print("Read jenkins --help")
57-
# except Exception as e:
58-
# raise e
5955

6056

6157
if __name__ == "__main__":
6258
main()
63-

jenkins_cli/cli.py

Lines changed: 64 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
from __future__ import print_function
12
import os
2-
import time
3+
from time import time
34
import datetime
45
import jenkins
56
import socket
67
from xml.etree import ElementTree
78

8-
colors = {'blue': '\033[94m',
9+
COLORS = {'blue': '\033[94m',
910
'green': '\033[92m',
1011
'red': '\033[91m',
1112
'yellow': '\033[93m',
@@ -24,6 +25,14 @@ class CliException(Exception):
2425
class JenkinsCli(object):
2526
SETTINGS_FILE_NAME = '.jenkins-cli'
2627

28+
QUEUE_EMPTY_TEXT = "Building Queue is empty"
29+
30+
INFO_TEMPLATE = ("Last build name: %s (result: %s)\n"
31+
"Last success build name: %s\n"
32+
"Build started: %s\n"
33+
"Building now: %s\n"
34+
"%s branch set to: %s")
35+
2736
def __init__(self, args, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
2837
self.jenkins = self.auth(args.host, args.username, args.password, timeout)
2938

@@ -58,23 +67,23 @@ def read_settings_from_file(cls):
5867
for setting_line in jenkins_settings.split('\n'):
5968
if "=" in setting_line:
6069
key, value = setting_line.split("=", 1)
61-
settings_dict[key] = value
70+
settings_dict[key.strip()] = value.strip()
6271
return settings_dict
6372

6473
def run_command(self, args):
6574
command = args.jenkins_command
6675
getattr(self, command)(args)
6776

6877
def jobs(self, args):
69-
jobs = self.jenkins.get_jobs()
78+
jobs = self._get_jobs(args)
7079
for job in jobs:
71-
print("%s***%s %s" % (colors.get(job['color'], job['color']), colors['endcollor'], job['name']))
80+
print("%s***%s %s" % (COLORS.get(job['color'], job['color']), COLORS['endcollor'], job['name']))
7281

7382
def _get_jobs(self, args):
7483
jobs = self.jenkins.get_jobs()
75-
if not args.d:
84+
if args.a:
7685
jobs = [j for j in jobs if j.get('color') != 'disabled']
77-
jobs = sorted(jobs, key=lambda j: j.get('name'))
86+
# jobs = sorted(jobs, key=lambda j: j.get('name'))
7887
return jobs
7988

8089
def queue(self, args):
@@ -83,58 +92,63 @@ def queue(self, args):
8392
for job in jobs:
8493
print("%s %s" % (job['task']['name'], job['why']))
8594
else:
86-
print("Building Queue is empty")
95+
print(self.QUEUE_EMPTY_TEXT)
8796

8897
def _check_job(self, job_name):
8998
job_name = self.jenkins.get_job_name(job_name)
9099
if not job_name:
91100
raise CliException('Job name does not esist')
92101
return job_name
93102

103+
def _get_scm_name_and_node(self, xml_root):
104+
scm_name = 'UnknownSCM'
105+
branch_node = None
106+
try:
107+
scm = xml_root.find('scm')
108+
if scm.attrib['class'] == 'hudson.plugins.mercurial.MercurialSCM':
109+
scm_name = 'Mercurial'
110+
branch_node = scm.find('revision')
111+
elif scm.attrib['class'] == 'hudson.plugins.git.GitSCM':
112+
scm_name = 'Git'
113+
branch_node = scm.find('branches').find('hudson.plugins.git.BranchSpec').find('name')
114+
except AttributeError:
115+
pass
116+
return (scm_name, branch_node)
117+
94118
def info(self, args):
95119
job_name = self._check_job(args.job_name)
96120
job_info = self.jenkins.get_job_info(job_name, 1)
97121
if not job_info:
98122
job_info = {}
99123
last_build = job_info.get('lastBuild', {})
100124
last_success_build = job_info.get('lastSuccessfulBuild', {})
101-
#from pprint import pprint
102-
#pprint(job_info)
103-
info = ("Last build name: %s (result: %s)\n"
104-
"Last success build name: %s\n"
105-
"Build started: %s\n"
106-
"Building now: %s\n"
107-
"Mercurial branch set: %s")
108125
xml = self.jenkins.get_job_config(job_name)
109126
root = ElementTree.fromstring(xml.encode('utf-8'))
110-
rev = 'Not Known'
111-
scm = root.find('scm')
112-
if scm is not None:
113-
revision = scm.find('revision')
114-
if revision is not None:
115-
rev = revision.text
116-
print(info % (last_build.get('fullDisplayName', 'Not Built'),
117-
last_build.get('result', 'Not Built'),
118-
last_success_build.get('fullDisplayName', 'Not Built'),
119-
datetime.datetime.fromtimestamp(last_build['timestamp'] / 1000) if last_build else 'Not built',
120-
'Yes' if last_build.get('building') else 'No',
121-
rev))
127+
scm_name, branch_node = self._get_scm_name_and_node(root)
128+
if branch_node is not None:
129+
branch_name = branch_node.text
130+
else:
131+
branch_name = 'Unknown branch'
132+
print(self.INFO_TEMPLATE % (last_build.get('fullDisplayName', 'Not Built'),
133+
last_build.get('result', 'Not Built'),
134+
last_success_build.get('fullDisplayName', 'Not Built'),
135+
datetime.datetime.fromtimestamp(last_build['timestamp'] / 1000) if last_build else 'Not Built',
136+
'Yes' if last_build.get('building') else 'No',
137+
scm_name,
138+
branch_name))
122139

123140
def set_branch(self, args):
124141
job_name = self._check_job(args.job_name)
125142
xml = self.jenkins.get_job_config(job_name)
126143
root = ElementTree.fromstring(xml.encode('utf-8'))
127-
scm = root.find('scm')
128-
new_xml = None
129-
if scm is not None:
130-
revision = scm.find('revision')
131-
if revision is not None:
132-
revision.text = args.branch_name
133-
new_xml = ElementTree.tostring(root)
134-
self.jenkins.reconfig_job(job_name, new_xml)
135-
print('Done')
136-
if new_xml is None:
137-
print("Can not set revision info")
144+
scm_name, branch_node = self._get_scm_name_and_node(root)
145+
if branch_node is not None:
146+
branch_node.text = args.branch_name
147+
new_xml = ElementTree.tostring(root)
148+
self.jenkins.reconfig_job(job_name, new_xml)
149+
print('Done')
150+
else:
151+
print("Can't set branch name")
138152

139153
def start(self, args):
140154
for job in args.job_name:
@@ -146,8 +160,11 @@ def stop(self, args):
146160
job_name = self._check_job(args.job_name)
147161
info = self.jenkins.get_job_info(job_name)
148162
build_number = info['lastBuild'].get('number')
149-
stop_status = self.jenkins.stop_build(job_name, build_number)
150-
print("%s: %s" % (job_name, 'stoped' if not stop_status else stop_status))
163+
if build_number and info['lastBuild'].get('building'):
164+
stop_status = self.jenkins.stop_build(job_name, build_number)
165+
print("%s: %s" % (job_name, 'stopped' if not stop_status else stop_status))
166+
else:
167+
print("%s job is not running" % job_name)
151168

152169
def console(self, args):
153170
job_name = self._check_job(args.job_name)
@@ -173,17 +190,19 @@ def console(self, args):
173190
build_info = self.jenkins.get_build_info(job_name, build_number)
174191

175192
def building(self, args):
176-
args.d = False
193+
args.a = True
177194
jobs = [j for j in self._get_jobs(args) if 'anime' in j['color']]
178195
if jobs:
179196
for job in jobs:
180197
info = self.jenkins.get_job_info(job['name'])
181198
build_number = info['lastBuild'].get('number')
199+
eta = "unknown"
200+
display_name = job['name']
182201
if build_number:
183202
build_info = self.jenkins.get_build_info(job['name'], build_number)
184-
eta = (build_info['timestamp'] + build_info['estimatedDuration']) / 1000 - time.time()
185-
print("%s estimated time left %s" % (build_info['fullDisplayName'],
186-
datetime.timedelta(seconds=eta)))
203+
eta = (build_info['timestamp'] + build_info['estimatedDuration']) / 1000 - time()
204+
eta = datetime.timedelta(seconds=eta)
205+
display_name = build_info['fullDisplayName']
206+
print("%s estimated time left %s" % (display_name, eta))
187207
else:
188208
print("Nothing is building now")
189-

requirements.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
pbr==1.3.0
22
python-jenkins==0.4.12
33
six==1.9.0
4+
tox==2.3.1
5+
pyfakefs==2.7.0
6+
mock==1.3.0
7+
unittest2==1.1.0
8+
flake8==2.5.4

setup.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
11
import os
2+
import re
23
from setuptools import setup, find_packages
34

45
here = os.path.abspath(os.path.dirname(__file__))
56
with open(os.path.join(here, 'README.md')) as f:
67
README = f.read()
78

8-
exec(open(os.path.join(here, 'jenkins_cli/version.py')).read())
9+
version_file_content = open(os.path.join(here, 'jenkins_cli/version.py')).read()
10+
version_match = re.search(r"^version = ['\"]([^'\"]*)['\"]",
11+
version_file_content, re.M)
12+
if version_match:
13+
version = version_match.group(1)
14+
else:
15+
raise RuntimeError('Unable to find version string.')
916

10-
requires = ['pbr>=1.3.0',
17+
requires = ['pbr>=1.6.0',
1118
'python-jenkins==0.4.12',
1219
'six>=1.9.0']
1320

21+
tests_require = ['unittest2==1.1.0',
22+
'mock==1.3.0',
23+
'pyfakefs==2.7.0']
24+
1425
setup(
1526
name='jenkins-cli',
1627
version=version,
@@ -21,14 +32,19 @@
2132
license='http://opensource.org/licenses/MIT',
2233
classifiers=(
2334
'Natural Language :: English',
35+
'Environment :: Console',
36+
'Intended Audience :: Developers',
2437
'Programming Language :: Python',
25-
'Programming Language :: Python :: 3',
26-
'Programming Language :: Python :: 2',
38+
'Programming Language :: Python :: 2.7',
39+
'Programming Language :: Python :: 3.4',
40+
'Programming Language :: Python :: 3.5',
2741
'License :: OSI Approved :: MIT License',
2842
),
2943
packages=find_packages(),
3044
install_requires=requires,
31-
entry_points = {
32-
'console_scripts' : [ 'jenkins = jenkins_cli:main' ]
45+
tests_require=tests_require,
46+
test_suite="tests",
47+
entry_points={
48+
'console_scripts': ['jenkins = jenkins_cli:main']
3349
}
3450
)

tests/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)