Skip to content

Commit 54d6477

Browse files
authored
Merge pull request #38 from radomirbosak/add-config-sections
Support multiple Jenkins instances in config file
2 parents c7a79f9 + b392550 commit 54d6477

4 files changed

Lines changed: 85 additions & 24 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,15 @@ Host, username and password may be specified either by the command line argument
3838

3939
**.jenkins-cli** example
4040
```txt
41+
[DEFAULT]
4142
host=http://localhost:8082/
4243
username=username
4344
password=******
45+
46+
[prod]
47+
host=https://production-jenkins.example.com/
48+
username=username
49+
password=xxxxxx
4450
```
4551

4652
# Commands overview:

jenkins_cli/cli.py

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
import socket
88
from xml.etree import ElementTree
99

10+
try:
11+
from ConfigParser import ConfigParser, NoSectionError
12+
except ImportError:
13+
from configparser import ConfigParser, NoSectionError
14+
15+
1016
STATUSES_COLOR = {'blue': {'symbol': 'S',
1117
'color': '\033[94m',
1218
'descr': 'Stable'},
@@ -87,12 +93,13 @@ class JenkinsCli(object):
8793
"%s branch set to: %s")
8894

8995
def __init__(self, args, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
90-
self.jenkins = self.auth(args.host, args.username, args.password, timeout)
96+
self.jenkins = self.auth(args.host, args.username, args.password,
97+
args.environment, timeout)
9198

9299
@classmethod
93-
def auth(cls, host=None, username=None, password=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
100+
def auth(cls, host=None, username=None, password=None, environment=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
94101
if host is None or username is None or password is None:
95-
settings_dict = cls.read_settings_from_file()
102+
settings_dict = cls.read_settings_from_file(environment)
96103
try:
97104
host = host or settings_dict['host']
98105
username = username or settings_dict.get('username', None)
@@ -102,26 +109,34 @@ def auth(cls, host=None, username=None, password=None, timeout=socket._GLOBAL_DE
102109
return jenkins.Jenkins(host, username, password, timeout)
103110

104111
@classmethod
105-
def read_settings_from_file(cls):
106-
try:
107-
current_folder = os.getcwd()
108-
filename = os.path.join(current_folder, cls.SETTINGS_FILE_NAME)
112+
def read_settings_from_file(cls, environment):
113+
# get config filename
114+
current_folder = os.getcwd()
115+
filename = os.path.join(current_folder, cls.SETTINGS_FILE_NAME)
116+
if not os.path.exists(filename):
117+
home_folder = os.path.expanduser("~")
118+
filename = os.path.join(home_folder, cls.SETTINGS_FILE_NAME)
109119
if not os.path.exists(filename):
110-
home_folder = os.path.expanduser("~")
111-
filename = os.path.join(home_folder, cls.SETTINGS_FILE_NAME)
112-
if not os.path.exists(filename):
113-
return {}
114-
f = open(filename, 'r')
115-
jenkins_settings = f.read()
120+
return {}
121+
122+
# use the DEFAULT section if no env is specified
123+
if not environment:
124+
environment = 'DEFAULT'
125+
126+
# read the config file
127+
config = ConfigParser()
128+
try:
129+
with open(filename, 'r') as f:
130+
config.readfp(f)
116131
except Exception as e:
117132
raise CliException('Error reading %s: %s' % (filename, e))
118133

119-
settings_dict = {}
120-
for setting_line in jenkins_settings.split('\n'):
121-
if "=" in setting_line:
122-
key, value = setting_line.split("=", 1)
123-
settings_dict[key.strip()] = value.strip()
124-
return settings_dict
134+
# return the variables as dict
135+
try:
136+
return dict(config.items(environment))
137+
except NoSectionError:
138+
raise CliException('%s section not found in .jenkins-cli config'
139+
' file' % environment)
125140

126141
def run_command(self, args):
127142
command = args.jenkins_command

jenkins_cli/cli_arguments.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ def load_parser():
2020
parser.add_argument('--username', metavar='username', help='Jenkins Username', default=None)
2121
parser.add_argument('--password', metavar='password', help='Jenkins Password', default=None)
2222
parser.add_argument('--version', '-v', action='version', version='jenkins-cli %s' % version)
23+
parser.add_argument('-e', '--environment',
24+
help='Which config section to use')
2325

2426
subparsers = parser.add_subparsers(title='Available commands', dest='jenkins_command')
2527

tests/test_cli.py

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,29 @@ def test_auth_has_file_settings(self, patched_init, read_settings_from_file):
7575

7676

7777
class TestCliFileUsing(fake_filesystem_unittest.TestCase):
78-
HOME_FILE_CONTENT = ("host =https://jenkins.host.com\n"
78+
HOME_FILE_CONTENT = ("[DEFAULT]\n"
79+
"host =https://jenkins.host.com\n"
7980
"username= username\n"
8081
"some weird settings = value = value")
8182

82-
LOCAL_FILE_CONTENT = ("host=http://jenkins.localhosthost.ua\n"
83+
LOCAL_FILE_CONTENT = ("[DEFAULT]\n"
84+
"host=http://jenkins.localhosthost.ua\n"
8385
"username=Denys\n"
8486
"password=myPassword\n"
8587
"other_setting=some_value")
8688

89+
MULTIENV_FILE_CONTENT = ("[DEFAULT]\n"
90+
"host =https://jenkins.host.com\n"
91+
"username= username\n"
92+
"some default settings = value = value\n"
93+
"\n"
94+
"[alternative]\n"
95+
"host=http://jenkins.localhosthost.ua\n"
96+
"username=Denys\n"
97+
"password=myPassword\n"
98+
"other_setting=some_value"
99+
)
100+
87101
def setUp(self):
88102
self.setUpPyfakefs()
89103

@@ -97,7 +111,7 @@ def test_read_settings_from_file(self):
97111
self.fs.CreateFile(home_folder_filename,
98112
contents=self.HOME_FILE_CONTENT)
99113
self.assertTrue(os.path.exists(home_folder_filename))
100-
settings_dict = JenkinsCli.read_settings_from_file()
114+
settings_dict = JenkinsCli.read_settings_from_file(environment=None)
101115
self.assertEqual(settings_dict,
102116
{"host": 'https://jenkins.host.com',
103117
"username": "username",
@@ -107,19 +121,43 @@ def test_read_settings_from_file(self):
107121
self.fs.CreateFile(local_folder_filename,
108122
contents=self.LOCAL_FILE_CONTENT)
109123
self.assertTrue(os.path.exists(local_folder_filename))
110-
settings_dict = JenkinsCli.read_settings_from_file()
124+
settings_dict = JenkinsCli.read_settings_from_file(environment=None)
111125
self.assertEqual(settings_dict,
112126
{"host": 'http://jenkins.localhosthost.ua',
113127
"username": "Denys",
114128
"password": "myPassword",
115129
"other_setting": "some_value"
116130
})
117131

132+
def test_read_settings_from_file_alt_environment(self):
133+
# make sure we are in the fake fs
134+
current_folder = os.getcwd()
135+
local_folder_filename = os.path.join(current_folder, JenkinsCli.SETTINGS_FILE_NAME)
136+
self.assertFalse(os.path.exists(local_folder_filename))
137+
138+
# create the fake config file
139+
self.fs.CreateFile(local_folder_filename,
140+
contents=self.MULTIENV_FILE_CONTENT)
141+
self.assertTrue(os.path.exists(local_folder_filename))
142+
143+
# read the config from the file
144+
settings_dict = JenkinsCli.read_settings_from_file(environment='alternative')
145+
146+
# test and that the alternative environment is used, with the missing
147+
# values being provided from the DEFAULT environmtne
148+
self.assertEqual(settings_dict,
149+
{"host": 'http://jenkins.localhosthost.ua',
150+
"username": "Denys",
151+
"password": "myPassword",
152+
"other_setting": "some_value",
153+
'some default settings': 'value = value'
154+
})
155+
118156

119157
class TestCliCommands(unittest.TestCase):
120158

121159
def setUp(self):
122-
self.args = Namespace(host='http://jenkins.host.com', username=None, password=None)
160+
self.args = Namespace(host='http://jenkins.host.com', username=None, password=None, environment=None)
123161
self.print_patcher = mock.patch('jenkins_cli.cli.print')
124162
self.patched_print = self.print_patcher.start()
125163

0 commit comments

Comments
 (0)