Some tweaks to get closer to Python 3 compat
Convert to use idioms that work for both python 3 and python 2.6+ and ensure that a suitable version of dependencies is included for python 3 compatibility. Update python-jenkins to 0.3.3 as the earliest version that supports python 3 without any known regressions. Add an extra parser check for missing 'command' due to changes in how argparse works under python 3. Where contents should be retained, to access the first element of a dict in both python 2 and 3, 'next(iter(dict.items()))' is used as the standard idiom to replace 'dict.items()[0]' as 'items()' returns an iterator in python 3 which cannot be indexed. Using 'next(iter(..))' allows for both lists and iterators to be passed in without unnecessary conversion of iterators to lists which would be true of 'list(dict.items())[0]'. Alternatively, where further access to the data is not required, 'dict.popitem()' is used. Change-Id: If4b35e2ceee8239379700e22eb79a3eaa04d6f0f
This commit is contained in:
parent
c99cbccb8e
commit
1d7647fa85
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
import os
|
import os
|
||||||
|
import operator
|
||||||
import sys
|
import sys
|
||||||
import hashlib
|
import hashlib
|
||||||
import yaml
|
import yaml
|
||||||
|
@ -31,8 +32,9 @@ import logging
|
||||||
import copy
|
import copy
|
||||||
import itertools
|
import itertools
|
||||||
import fnmatch
|
import fnmatch
|
||||||
|
import six
|
||||||
from jenkins_jobs.errors import JenkinsJobsException
|
from jenkins_jobs.errors import JenkinsJobsException
|
||||||
import local_yaml
|
import jenkins_jobs.local_yaml as local_yaml
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
MAGIC_MANAGE_STRING = "<!-- Managed by Jenkins Job Builder -->"
|
MAGIC_MANAGE_STRING = "<!-- Managed by Jenkins Job Builder -->"
|
||||||
|
@ -82,7 +84,7 @@ def deep_format(obj, paramdict):
|
||||||
# limitations on the values in paramdict - the post-format result must
|
# limitations on the values in paramdict - the post-format result must
|
||||||
# still be valid YAML (so substituting-in a string containing quotes, for
|
# still be valid YAML (so substituting-in a string containing quotes, for
|
||||||
# example, is problematic).
|
# example, is problematic).
|
||||||
if isinstance(obj, basestring):
|
if hasattr(obj, 'format'):
|
||||||
try:
|
try:
|
||||||
result = re.match('^{obj:(?P<key>\w+)}$', obj)
|
result = re.match('^{obj:(?P<key>\w+)}$', obj)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
|
@ -142,7 +144,7 @@ class YamlParser(object):
|
||||||
" not a {cls}".format(fname=getattr(fp, 'name', fp),
|
" not a {cls}".format(fname=getattr(fp, 'name', fp),
|
||||||
cls=type(data)))
|
cls=type(data)))
|
||||||
for item in data:
|
for item in data:
|
||||||
cls, dfn = item.items()[0]
|
cls, dfn = next(iter(item.items()))
|
||||||
group = self.data.get(cls, {})
|
group = self.data.get(cls, {})
|
||||||
if len(item.items()) > 1:
|
if len(item.items()) > 1:
|
||||||
n = None
|
n = None
|
||||||
|
@ -209,7 +211,7 @@ class YamlParser(object):
|
||||||
for jobspec in project.get('jobs', []):
|
for jobspec in project.get('jobs', []):
|
||||||
if isinstance(jobspec, dict):
|
if isinstance(jobspec, dict):
|
||||||
# Singleton dict containing dict of job-specific params
|
# Singleton dict containing dict of job-specific params
|
||||||
jobname, jobparams = jobspec.items()[0]
|
jobname, jobparams = jobspec.popitem()
|
||||||
if not isinstance(jobparams, dict):
|
if not isinstance(jobparams, dict):
|
||||||
jobparams = {}
|
jobparams = {}
|
||||||
else:
|
else:
|
||||||
|
@ -225,7 +227,7 @@ class YamlParser(object):
|
||||||
for group_jobspec in group['jobs']:
|
for group_jobspec in group['jobs']:
|
||||||
if isinstance(group_jobspec, dict):
|
if isinstance(group_jobspec, dict):
|
||||||
group_jobname, group_jobparams = \
|
group_jobname, group_jobparams = \
|
||||||
group_jobspec.items()[0]
|
group_jobspec.popitem()
|
||||||
if not isinstance(group_jobparams, dict):
|
if not isinstance(group_jobparams, dict):
|
||||||
group_jobparams = {}
|
group_jobparams = {}
|
||||||
else:
|
else:
|
||||||
|
@ -275,7 +277,7 @@ class YamlParser(object):
|
||||||
expanded_values = {}
|
expanded_values = {}
|
||||||
for (k, v) in values:
|
for (k, v) in values:
|
||||||
if isinstance(v, dict):
|
if isinstance(v, dict):
|
||||||
inner_key = v.iterkeys().next()
|
inner_key = next(iter(v))
|
||||||
expanded_values[k] = inner_key
|
expanded_values[k] = inner_key
|
||||||
expanded_values.update(v[inner_key])
|
expanded_values.update(v[inner_key])
|
||||||
else:
|
else:
|
||||||
|
@ -295,6 +297,8 @@ class YamlParser(object):
|
||||||
# us guarantee a group of parameters will not be added a
|
# us guarantee a group of parameters will not be added a
|
||||||
# second time.
|
# second time.
|
||||||
uniq = json.dumps(expanded, sort_keys=True)
|
uniq = json.dumps(expanded, sort_keys=True)
|
||||||
|
if six.PY3:
|
||||||
|
uniq = uniq.encode('utf-8')
|
||||||
checksum = hashlib.md5(uniq).hexdigest()
|
checksum = hashlib.md5(uniq).hexdigest()
|
||||||
|
|
||||||
# Lookup the checksum
|
# Lookup the checksum
|
||||||
|
@ -364,7 +368,7 @@ class ModuleRegistry(object):
|
||||||
Mod = entrypoint.load()
|
Mod = entrypoint.load()
|
||||||
mod = Mod(self)
|
mod = Mod(self)
|
||||||
self.modules.append(mod)
|
self.modules.append(mod)
|
||||||
self.modules.sort(lambda a, b: cmp(a.sequence, b.sequence))
|
self.modules.sort(key=operator.attrgetter('sequence'))
|
||||||
if mod.component_type is not None:
|
if mod.component_type is not None:
|
||||||
self.modules_by_component_type[mod.component_type] = mod
|
self.modules_by_component_type[mod.component_type] = mod
|
||||||
|
|
||||||
|
@ -408,7 +412,7 @@ class ModuleRegistry(object):
|
||||||
|
|
||||||
if isinstance(component, dict):
|
if isinstance(component, dict):
|
||||||
# The component is a singleton dictionary of name: dict(args)
|
# The component is a singleton dictionary of name: dict(args)
|
||||||
name, component_data = component.items()[0]
|
name, component_data = next(iter(component.items()))
|
||||||
if template_data:
|
if template_data:
|
||||||
# Template data contains values that should be interpolated
|
# Template data contains values that should be interpolated
|
||||||
# into the component definition
|
# into the component definition
|
||||||
|
@ -610,7 +614,7 @@ class Builder(object):
|
||||||
self.load_files(input_fn)
|
self.load_files(input_fn)
|
||||||
self.parser.generateXML(names)
|
self.parser.generateXML(names)
|
||||||
|
|
||||||
self.parser.jobs.sort(lambda a, b: cmp(a.name, b.name))
|
self.parser.jobs.sort(key=operator.attrgetter('name'))
|
||||||
|
|
||||||
for job in self.parser.jobs:
|
for job in self.parser.jobs:
|
||||||
if names and not matches(job.name, names):
|
if names and not matches(job.name, names):
|
||||||
|
|
|
@ -14,12 +14,11 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import ConfigParser
|
from six.moves import configparser, StringIO
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
import cStringIO
|
|
||||||
|
|
||||||
from jenkins_jobs.builder import Builder
|
from jenkins_jobs.builder import Builder
|
||||||
from jenkins_jobs.errors import JenkinsJobsException
|
from jenkins_jobs.errors import JenkinsJobsException
|
||||||
|
@ -95,6 +94,8 @@ def main(argv=None):
|
||||||
|
|
||||||
parser = create_parser()
|
parser = create_parser()
|
||||||
options = parser.parse_args(argv)
|
options = parser.parse_args(argv)
|
||||||
|
if not options.command:
|
||||||
|
parser.error("Must specify a 'command' to be performed")
|
||||||
if (options.log_level is not None):
|
if (options.log_level is not None):
|
||||||
options.log_level = getattr(logging, options.log_level.upper(),
|
options.log_level = getattr(logging, options.log_level.upper(),
|
||||||
logger.getEffectiveLevel())
|
logger.getEffectiveLevel())
|
||||||
|
@ -115,9 +116,9 @@ def setup_config_settings(options):
|
||||||
'jenkins_jobs.ini')
|
'jenkins_jobs.ini')
|
||||||
if os.path.isfile(localconf):
|
if os.path.isfile(localconf):
|
||||||
conf = localconf
|
conf = localconf
|
||||||
config = ConfigParser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
## Load default config always
|
## Load default config always
|
||||||
config.readfp(cStringIO.StringIO(DEFAULT_CONF))
|
config.readfp(StringIO(DEFAULT_CONF))
|
||||||
if os.path.isfile(conf):
|
if os.path.isfile(conf):
|
||||||
logger.debug("Reading config from {0}".format(conf))
|
logger.debug("Reading config from {0}".format(conf))
|
||||||
conffp = open(conf, 'r')
|
conffp = open(conf, 'r')
|
||||||
|
@ -152,11 +153,11 @@ def execute(options, config):
|
||||||
# https://bugs.launchpad.net/openstack-ci/+bug/1259631
|
# https://bugs.launchpad.net/openstack-ci/+bug/1259631
|
||||||
try:
|
try:
|
||||||
user = config.get('jenkins', 'user')
|
user = config.get('jenkins', 'user')
|
||||||
except (TypeError, ConfigParser.NoOptionError):
|
except (TypeError, configparser.NoOptionError):
|
||||||
user = None
|
user = None
|
||||||
try:
|
try:
|
||||||
password = config.get('jenkins', 'password')
|
password = config.get('jenkins', 'password')
|
||||||
except (TypeError, ConfigParser.NoOptionError):
|
except (TypeError, configparser.NoOptionError):
|
||||||
password = None
|
password = None
|
||||||
|
|
||||||
builder = Builder(config.get('jenkins', 'url'),
|
builder = Builder(config.get('jenkins', 'url'),
|
||||||
|
|
|
@ -163,7 +163,7 @@ class LocalLoader(OrderedConstructor, yaml.Loader):
|
||||||
self.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
|
self.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
|
||||||
type(self).construct_yaml_map)
|
type(self).construct_yaml_map)
|
||||||
|
|
||||||
if isinstance(self.stream, file):
|
if hasattr(self.stream, 'name'):
|
||||||
self.search_path.add(os.path.normpath(
|
self.search_path.add(os.path.normpath(
|
||||||
os.path.dirname(self.stream.name)))
|
os.path.dirname(self.stream.name)))
|
||||||
self.search_path.add(os.path.normpath(os.path.curdir))
|
self.search_path.add(os.path.normpath(os.path.curdir))
|
||||||
|
|
|
@ -227,7 +227,7 @@ def ant(parser, xml_parent, data):
|
||||||
if type(data) is str:
|
if type(data) is str:
|
||||||
# Support for short form: -ant: "target"
|
# Support for short form: -ant: "target"
|
||||||
data = {'targets': data}
|
data = {'targets': data}
|
||||||
for setting, value in sorted(data.iteritems()):
|
for setting, value in sorted(data.items()):
|
||||||
if setting == 'targets':
|
if setting == 'targets':
|
||||||
targets = XML.SubElement(ant, 'targets')
|
targets = XML.SubElement(ant, 'targets')
|
||||||
targets.text = value
|
targets.text = value
|
||||||
|
|
|
@ -46,7 +46,7 @@ import xml.etree.ElementTree as XML
|
||||||
import jenkins_jobs.modules.base
|
import jenkins_jobs.modules.base
|
||||||
import jenkins_jobs.errors
|
import jenkins_jobs.errors
|
||||||
import logging
|
import logging
|
||||||
import ConfigParser
|
from six.moves import configparser
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -73,8 +73,8 @@ class HipChat(jenkins_jobs.modules.base.Base):
|
||||||
if self.authToken == '':
|
if self.authToken == '':
|
||||||
raise jenkins_jobs.errors.JenkinsJobsException(
|
raise jenkins_jobs.errors.JenkinsJobsException(
|
||||||
"Hipchat authtoken must not be a blank string")
|
"Hipchat authtoken must not be a blank string")
|
||||||
except (ConfigParser.NoSectionError,
|
except (configparser.NoSectionError,
|
||||||
jenkins_jobs.errors.JenkinsJobsException), e:
|
jenkins_jobs.errors.JenkinsJobsException) as e:
|
||||||
logger.fatal("The configuration file needs a hipchat section" +
|
logger.fatal("The configuration file needs a hipchat section" +
|
||||||
" containing authtoken:\n{0}".format(e))
|
" containing authtoken:\n{0}".format(e))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
|
@ -439,7 +439,7 @@ def cloverphp(parser, xml_parent, data):
|
||||||
|
|
||||||
metrics = data.get('metric-targets', [])
|
metrics = data.get('metric-targets', [])
|
||||||
# list of dicts to dict
|
# list of dicts to dict
|
||||||
metrics = dict(kv for m in metrics for kv in m.iteritems())
|
metrics = dict(kv for m in metrics for kv in m.items())
|
||||||
|
|
||||||
# Populate defaults whenever nothing has been filled by user.
|
# Populate defaults whenever nothing has been filled by user.
|
||||||
for default in default_metrics.keys():
|
for default in default_metrics.keys():
|
||||||
|
@ -889,7 +889,7 @@ def xunit(parser, xml_parent, data):
|
||||||
supported_types = []
|
supported_types = []
|
||||||
|
|
||||||
for configured_type in data['types']:
|
for configured_type in data['types']:
|
||||||
type_name = configured_type.keys()[0]
|
type_name = next(iter(configured_type.keys()))
|
||||||
if type_name not in implemented_types:
|
if type_name not in implemented_types:
|
||||||
logger.warn("Requested xUnit type '%s' is not yet supported",
|
logger.warn("Requested xUnit type '%s' is not yet supported",
|
||||||
type_name)
|
type_name)
|
||||||
|
@ -900,7 +900,7 @@ def xunit(parser, xml_parent, data):
|
||||||
# Generate XML for each of the supported framework types
|
# Generate XML for each of the supported framework types
|
||||||
xmltypes = XML.SubElement(xunit, 'types')
|
xmltypes = XML.SubElement(xunit, 'types')
|
||||||
for supported_type in supported_types:
|
for supported_type in supported_types:
|
||||||
framework_name = supported_type.keys()[0]
|
framework_name = next(iter(supported_type.keys()))
|
||||||
xmlframework = XML.SubElement(xmltypes,
|
xmlframework = XML.SubElement(xmltypes,
|
||||||
types_to_plugin_types[framework_name])
|
types_to_plugin_types[framework_name])
|
||||||
|
|
||||||
|
@ -924,9 +924,10 @@ def xunit(parser, xml_parent, data):
|
||||||
"Unrecognized threshold, should be 'failed' or 'skipped'")
|
"Unrecognized threshold, should be 'failed' or 'skipped'")
|
||||||
continue
|
continue
|
||||||
elname = "org.jenkinsci.plugins.xunit.threshold.%sThreshold" \
|
elname = "org.jenkinsci.plugins.xunit.threshold.%sThreshold" \
|
||||||
% t.keys()[0].title()
|
% next(iter(t.keys())).title()
|
||||||
el = XML.SubElement(xmlthresholds, elname)
|
el = XML.SubElement(xmlthresholds, elname)
|
||||||
for threshold_name, threshold_value in t.values()[0].items():
|
for threshold_name, threshold_value in \
|
||||||
|
next(iter(t.values())).items():
|
||||||
# Normalize and craft the element name for this threshold
|
# Normalize and craft the element name for this threshold
|
||||||
elname = "%sThreshold" % threshold_name.lower().replace(
|
elname = "%sThreshold" % threshold_name.lower().replace(
|
||||||
'new', 'New')
|
'new', 'New')
|
||||||
|
@ -3509,7 +3510,8 @@ def ruby_metrics(parser, xml_parent, data):
|
||||||
XML.SubElement(el, 'metric').text = 'TOTAL_COVERAGE'
|
XML.SubElement(el, 'metric').text = 'TOTAL_COVERAGE'
|
||||||
else:
|
else:
|
||||||
XML.SubElement(el, 'metric').text = 'CODE_COVERAGE'
|
XML.SubElement(el, 'metric').text = 'CODE_COVERAGE'
|
||||||
for threshold_name, threshold_value in t.values()[0].items():
|
for threshold_name, threshold_value in \
|
||||||
|
next(iter(t.values())).items():
|
||||||
elname = threshold_name.lower()
|
elname = threshold_name.lower()
|
||||||
XML.SubElement(el, elname).text = str(threshold_value)
|
XML.SubElement(el, elname).text = str(threshold_value)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -161,9 +161,9 @@ remoteName/\*')
|
||||||
data['remotes'] = [{data.get('name', 'origin'): data.copy()}]
|
data['remotes'] = [{data.get('name', 'origin'): data.copy()}]
|
||||||
for remoteData in data['remotes']:
|
for remoteData in data['remotes']:
|
||||||
huser = XML.SubElement(user, 'hudson.plugins.git.UserRemoteConfig')
|
huser = XML.SubElement(user, 'hudson.plugins.git.UserRemoteConfig')
|
||||||
remoteName = remoteData.keys()[0]
|
remoteName = next(iter(remoteData.keys()))
|
||||||
XML.SubElement(huser, 'name').text = remoteName
|
XML.SubElement(huser, 'name').text = remoteName
|
||||||
remoteParams = remoteData.values()[0]
|
remoteParams = next(iter(remoteData.values()))
|
||||||
if 'refspec' in remoteParams:
|
if 'refspec' in remoteParams:
|
||||||
refspec = remoteParams['refspec']
|
refspec = remoteParams['refspec']
|
||||||
else:
|
else:
|
||||||
|
@ -368,7 +368,7 @@ def store(parser, xml_parent, data):
|
||||||
pundles = XML.SubElement(scm, 'pundles')
|
pundles = XML.SubElement(scm, 'pundles')
|
||||||
for pundle_spec in pundle_specs:
|
for pundle_spec in pundle_specs:
|
||||||
pundle = XML.SubElement(pundles, '{0}.PundleSpec'.format(namespace))
|
pundle = XML.SubElement(pundles, '{0}.PundleSpec'.format(namespace))
|
||||||
pundle_type = pundle_spec.keys()[0]
|
pundle_type = next(iter(pundle_spec))
|
||||||
pundle_name = pundle_spec[pundle_type]
|
pundle_name = pundle_spec[pundle_type]
|
||||||
if pundle_type not in valid_pundle_types:
|
if pundle_type not in valid_pundle_types:
|
||||||
raise JenkinsJobsException(
|
raise JenkinsJobsException(
|
||||||
|
@ -507,9 +507,9 @@ def tfs(parser, xml_parent, data):
|
||||||
server.
|
server.
|
||||||
:arg str login: The user name that is registered on the server. The user
|
:arg str login: The user name that is registered on the server. The user
|
||||||
name must contain the name and the domain name. Entered as
|
name must contain the name and the domain name. Entered as
|
||||||
domain\\\user or user\@domain (optional).
|
domain\\\\user or user\@domain (optional).
|
||||||
**NOTE**: You must enter in at least two slashes for the
|
**NOTE**: You must enter in at least two slashes for the
|
||||||
domain\\\user format in JJB YAML. It will be rendered normally.
|
domain\\\\user format in JJB YAML. It will be rendered normally.
|
||||||
:arg str use-update: If true, Hudson will not delete the workspace at end
|
:arg str use-update: If true, Hudson will not delete the workspace at end
|
||||||
of each build. This causes the artifacts from the previous build to
|
of each build. This causes the artifacts from the previous build to
|
||||||
remain when a new build starts. (default true)
|
remain when a new build starts. (default true)
|
||||||
|
|
|
@ -91,7 +91,7 @@ def build_gerrit_triggers(xml_parent, data):
|
||||||
'hudsontrigger.events'
|
'hudsontrigger.events'
|
||||||
|
|
||||||
trigger_on_events = XML.SubElement(xml_parent, 'triggerOnEvents')
|
trigger_on_events = XML.SubElement(xml_parent, 'triggerOnEvents')
|
||||||
for config_key, tag_name in available_simple_triggers.iteritems():
|
for config_key, tag_name in available_simple_triggers.items():
|
||||||
if data.get(config_key, False):
|
if data.get(config_key, False):
|
||||||
XML.SubElement(trigger_on_events,
|
XML.SubElement(trigger_on_events,
|
||||||
'%s.%s' % (tag_namespace, tag_name))
|
'%s.%s' % (tag_namespace, tag_name))
|
||||||
|
@ -453,7 +453,7 @@ def pollurl(parser, xml_parent, data):
|
||||||
str(bool(check_content)).lower()
|
str(bool(check_content)).lower()
|
||||||
content_types = XML.SubElement(entry, 'contentTypes')
|
content_types = XML.SubElement(entry, 'contentTypes')
|
||||||
for entry in check_content:
|
for entry in check_content:
|
||||||
type_name = entry.keys()[0]
|
type_name = next(iter(entry.keys()))
|
||||||
if type_name not in valid_content_types:
|
if type_name not in valid_content_types:
|
||||||
raise JenkinsJobsException('check-content must be one of : %s'
|
raise JenkinsJobsException('check-content must be one of : %s'
|
||||||
% ', '.join(valid_content_types.
|
% ', '.join(valid_content_types.
|
||||||
|
|
|
@ -35,6 +35,8 @@ The above URL is the default.
|
||||||
http://ci.openstack.org/zuul/launchers.html#zuul-parameters
|
http://ci.openstack.org/zuul/launchers.html#zuul-parameters
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
|
||||||
def zuul():
|
def zuul():
|
||||||
"""yaml: zuul
|
"""yaml: zuul
|
||||||
|
@ -152,8 +154,8 @@ class Zuul(jenkins_jobs.modules.base.Base):
|
||||||
|
|
||||||
def handle_data(self, parser):
|
def handle_data(self, parser):
|
||||||
changed = False
|
changed = False
|
||||||
jobs = (parser.data.get('job', {}).values() +
|
jobs = itertools.chain(parser.data.get('job', {}).values(),
|
||||||
parser.data.get('job-template', {}).values())
|
parser.data.get('job-template', {}).values())
|
||||||
for job in jobs:
|
for job in jobs:
|
||||||
triggers = job.get('triggers')
|
triggers = job.get('triggers')
|
||||||
if not triggers:
|
if not triggers:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
argparse
|
argparse
|
||||||
|
six>=1.5.2
|
||||||
PyYAML
|
PyYAML
|
||||||
python-jenkins
|
python-jenkins>=0.3.3
|
||||||
pbr>=0.8.2,<1.0
|
pbr>=0.8.2,<1.0
|
||||||
|
|
|
@ -26,7 +26,7 @@ import json
|
||||||
import operator
|
import operator
|
||||||
import testtools
|
import testtools
|
||||||
import xml.etree.ElementTree as XML
|
import xml.etree.ElementTree as XML
|
||||||
from ConfigParser import ConfigParser
|
from six.moves import configparser
|
||||||
import jenkins_jobs.local_yaml as yaml
|
import jenkins_jobs.local_yaml as yaml
|
||||||
from jenkins_jobs.builder import XmlJob, YamlParser, ModuleRegistry
|
from jenkins_jobs.builder import XmlJob, YamlParser, ModuleRegistry
|
||||||
from jenkins_jobs.modules import (project_flow,
|
from jenkins_jobs.modules import (project_flow,
|
||||||
|
@ -86,7 +86,7 @@ class BaseTestCase(object):
|
||||||
|
|
||||||
def _read_yaml_content(self):
|
def _read_yaml_content(self):
|
||||||
yaml_filepath = os.path.join(self.fixtures_path, self.in_filename)
|
yaml_filepath = os.path.join(self.fixtures_path, self.in_filename)
|
||||||
with file(yaml_filepath, 'r') as yaml_file:
|
with open(yaml_filepath, 'r') as yaml_file:
|
||||||
yaml_content = yaml.load(yaml_file)
|
yaml_content = yaml.load(yaml_file)
|
||||||
return yaml_content
|
return yaml_content
|
||||||
|
|
||||||
|
@ -118,8 +118,7 @@ class BaseTestCase(object):
|
||||||
pub.gen_xml(parser, xml_project, yaml_content)
|
pub.gen_xml(parser, xml_project, yaml_content)
|
||||||
|
|
||||||
# Prettify generated XML
|
# Prettify generated XML
|
||||||
pretty_xml = unicode(XmlJob(xml_project, 'fixturejob').output(),
|
pretty_xml = XmlJob(xml_project, 'fixturejob').output().decode('utf-8')
|
||||||
'utf-8')
|
|
||||||
|
|
||||||
self.assertThat(
|
self.assertThat(
|
||||||
pretty_xml,
|
pretty_xml,
|
||||||
|
@ -137,7 +136,7 @@ class SingleJobTestCase(BaseTestCase):
|
||||||
yaml_filepath = os.path.join(self.fixtures_path, self.in_filename)
|
yaml_filepath = os.path.join(self.fixtures_path, self.in_filename)
|
||||||
|
|
||||||
if self.conf_filename:
|
if self.conf_filename:
|
||||||
config = ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
conf_filepath = os.path.join(self.fixtures_path,
|
conf_filepath = os.path.join(self.fixtures_path,
|
||||||
self.conf_filename)
|
self.conf_filename)
|
||||||
config.readfp(open(conf_filepath))
|
config.readfp(open(conf_filepath))
|
||||||
|
@ -152,8 +151,8 @@ class SingleJobTestCase(BaseTestCase):
|
||||||
parser.jobs.sort(key=operator.attrgetter('name'))
|
parser.jobs.sort(key=operator.attrgetter('name'))
|
||||||
|
|
||||||
# Prettify generated XML
|
# Prettify generated XML
|
||||||
pretty_xml = unicode("\n".join(job.output() for job in parser.jobs),
|
pretty_xml = u"\n".join(job.output().decode('utf-8')
|
||||||
'utf-8')
|
for job in parser.jobs)
|
||||||
|
|
||||||
self.assertThat(
|
self.assertThat(
|
||||||
pretty_xml,
|
pretty_xml,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import ConfigParser
|
from six.moves import configparser, StringIO
|
||||||
import cStringIO
|
import io
|
||||||
import codecs
|
import codecs
|
||||||
import mock
|
import mock
|
||||||
import testtools
|
import testtools
|
||||||
|
@ -22,15 +22,15 @@ class CmdTests(testtools.TestCase):
|
||||||
User passes no args, should fail with SystemExit
|
User passes no args, should fail with SystemExit
|
||||||
"""
|
"""
|
||||||
with mock.patch('sys.stderr'):
|
with mock.patch('sys.stderr'):
|
||||||
self.assertRaises(SystemExit, self.parser.parse_args, [])
|
self.assertRaises(SystemExit, cmd.main, [])
|
||||||
|
|
||||||
def test_non_existing_config_dir(self):
|
def test_non_existing_config_dir(self):
|
||||||
"""
|
"""
|
||||||
Run test mode and pass a non-existing configuration directory
|
Run test mode and pass a non-existing configuration directory
|
||||||
"""
|
"""
|
||||||
args = self.parser.parse_args(['test', 'foo'])
|
args = self.parser.parse_args(['test', 'foo'])
|
||||||
config = ConfigParser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config.readfp(cStringIO.StringIO(cmd.DEFAULT_CONF))
|
config.readfp(StringIO(cmd.DEFAULT_CONF))
|
||||||
self.assertRaises(IOError, cmd.execute, args, config)
|
self.assertRaises(IOError, cmd.execute, args, config)
|
||||||
|
|
||||||
def test_non_existing_config_file(self):
|
def test_non_existing_config_file(self):
|
||||||
|
@ -38,8 +38,8 @@ class CmdTests(testtools.TestCase):
|
||||||
Run test mode and pass a non-existing configuration file
|
Run test mode and pass a non-existing configuration file
|
||||||
"""
|
"""
|
||||||
args = self.parser.parse_args(['test', 'non-existing.yaml'])
|
args = self.parser.parse_args(['test', 'non-existing.yaml'])
|
||||||
config = ConfigParser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config.readfp(cStringIO.StringIO(cmd.DEFAULT_CONF))
|
config.readfp(StringIO(cmd.DEFAULT_CONF))
|
||||||
self.assertRaises(IOError, cmd.execute, args, config)
|
self.assertRaises(IOError, cmd.execute, args, config)
|
||||||
|
|
||||||
def test_non_existing_job(self):
|
def test_non_existing_job(self):
|
||||||
|
@ -52,8 +52,8 @@ class CmdTests(testtools.TestCase):
|
||||||
'cmd-001.yaml'),
|
'cmd-001.yaml'),
|
||||||
'invalid'])
|
'invalid'])
|
||||||
args.output_dir = mock.MagicMock()
|
args.output_dir = mock.MagicMock()
|
||||||
config = ConfigParser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config.readfp(cStringIO.StringIO(cmd.DEFAULT_CONF))
|
config.readfp(StringIO(cmd.DEFAULT_CONF))
|
||||||
cmd.execute(args, config) # probably better to fail here
|
cmd.execute(args, config) # probably better to fail here
|
||||||
|
|
||||||
def test_valid_job(self):
|
def test_valid_job(self):
|
||||||
|
@ -65,8 +65,8 @@ class CmdTests(testtools.TestCase):
|
||||||
'cmd-001.yaml'),
|
'cmd-001.yaml'),
|
||||||
'foo-job'])
|
'foo-job'])
|
||||||
args.output_dir = mock.MagicMock()
|
args.output_dir = mock.MagicMock()
|
||||||
config = ConfigParser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config.readfp(cStringIO.StringIO(cmd.DEFAULT_CONF))
|
config.readfp(StringIO(cmd.DEFAULT_CONF))
|
||||||
cmd.execute(args, config) # probably better to fail here
|
cmd.execute(args, config) # probably better to fail here
|
||||||
|
|
||||||
def test_console_output(self):
|
def test_console_output(self):
|
||||||
|
@ -74,15 +74,14 @@ class CmdTests(testtools.TestCase):
|
||||||
Run test mode and verify that resulting XML gets sent to the console.
|
Run test mode and verify that resulting XML gets sent to the console.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
console_out = cStringIO.StringIO()
|
console_out = io.BytesIO()
|
||||||
with mock.patch('sys.stdout', console_out):
|
with mock.patch('sys.stdout', console_out):
|
||||||
cmd.main(['test', os.path.join(self.fixtures_path,
|
cmd.main(['test', os.path.join(self.fixtures_path,
|
||||||
'cmd-001.yaml')])
|
'cmd-001.yaml')])
|
||||||
xml_content = u"%s" % codecs.open(os.path.join(self.fixtures_path,
|
xml_content = codecs.open(os.path.join(self.fixtures_path,
|
||||||
'cmd-001.xml'),
|
'cmd-001.xml'),
|
||||||
'r',
|
'r', 'utf-8').read()
|
||||||
'utf-8').read()
|
self.assertEqual(console_out.getvalue().decode('utf-8'), xml_content)
|
||||||
self.assertEqual(console_out.getvalue(), xml_content)
|
|
||||||
|
|
||||||
def test_config_with_test(self):
|
def test_config_with_test(self):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue