Story: 2010984 Fix folder tests and defaults for folders
Folders was not actually tested by tests. Fix tests and add more tests. Fix bug in code unearthed by now-working tests: defaults were not checked for job folders. Task: 49188 Change-Id: I922af7a28b0ec0c99ef3f8a17b3d5a9c10f2dce0
This commit is contained in:
parent
36ea222763
commit
c1ac0e03d6
@ -454,7 +454,7 @@ Job Name Example:
|
|||||||
|
|
||||||
Folder Attribute Example:
|
Folder Attribute Example:
|
||||||
|
|
||||||
.. literalinclude:: /../../tests/yamlparser/job_fixtures/folders-attribute.yaml
|
.. literalinclude:: /../../tests/yamlparser/job_fixtures/folders-defaults-for-job.yaml
|
||||||
|
|
||||||
|
|
||||||
.. _ids:
|
.. _ids:
|
||||||
|
@ -28,6 +28,7 @@ job_contents_keys = {
|
|||||||
"pipeline-scm",
|
"pipeline-scm",
|
||||||
"reporters",
|
"reporters",
|
||||||
# General.
|
# General.
|
||||||
|
"description",
|
||||||
"project-type",
|
"project-type",
|
||||||
"folder",
|
"folder",
|
||||||
"node",
|
"node",
|
||||||
@ -89,6 +90,7 @@ job_contents_keys = {
|
|||||||
|
|
||||||
view_contents_keys = {
|
view_contents_keys = {
|
||||||
# Common.
|
# Common.
|
||||||
|
"description",
|
||||||
"filter-executors",
|
"filter-executors",
|
||||||
"filter-queue",
|
"filter-queue",
|
||||||
# All
|
# All
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from .errors import JenkinsJobsException
|
from .errors import JenkinsJobsException
|
||||||
from .loc_loader import LocDict
|
|
||||||
from .root_base import RootBase, NonTemplateRootMixin, TemplateRootMixin, Group
|
from .root_base import RootBase, NonTemplateRootMixin, TemplateRootMixin, Group
|
||||||
from .defaults import split_contents_params, job_contents_keys
|
from .defaults import split_contents_params, job_contents_keys
|
||||||
|
|
||||||
@ -49,21 +48,26 @@ class JobBase(RootBase):
|
|||||||
folder,
|
folder,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _as_dict(self):
|
|
||||||
data = LocDict.merge(
|
|
||||||
{"name": self._full_name},
|
|
||||||
self.contents,
|
|
||||||
)
|
|
||||||
if self.project_type:
|
|
||||||
data["project-type"] = self.project_type
|
|
||||||
return data
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _full_name(self):
|
def contents(self):
|
||||||
|
contents = super().contents
|
||||||
|
contents["name"] = self.name
|
||||||
|
if self.project_type:
|
||||||
|
contents["project-type"] = self.project_type
|
||||||
if self.folder:
|
if self.folder:
|
||||||
return f"{self.folder}/{self.name}"
|
contents["folder"] = self.folder
|
||||||
|
return contents
|
||||||
|
|
||||||
|
def _expand_contents(self, contents, params):
|
||||||
|
expanded_contents = super()._expand_contents(contents, params)
|
||||||
|
try:
|
||||||
|
folder = expanded_contents["folder"]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
return self.name
|
name = expanded_contents["name"]
|
||||||
|
expanded_contents["name"] = f"{folder}/{name}"
|
||||||
|
return expanded_contents
|
||||||
|
|
||||||
|
|
||||||
class Job(JobBase, NonTemplateRootMixin):
|
class Job(JobBase, NonTemplateRootMixin):
|
||||||
|
@ -52,7 +52,7 @@ class RootBase:
|
|||||||
description: str
|
description: str
|
||||||
defaults_name: str
|
defaults_name: str
|
||||||
params: dict
|
params: dict
|
||||||
contents: dict
|
_contents: dict
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
@ -65,19 +65,20 @@ class RootBase:
|
|||||||
def title(self):
|
def title(self):
|
||||||
return str(self).capitalize()
|
return str(self).capitalize()
|
||||||
|
|
||||||
def _format_description(self, params):
|
@property
|
||||||
if self.description is None:
|
def contents(self):
|
||||||
defaults = self._pick_defaults(self.defaults_name)
|
contents = self._contents.copy()
|
||||||
description = defaults.params.get("description")
|
if self.description is not None:
|
||||||
else:
|
contents["description"] = self.description
|
||||||
if type(self.description) is LocString:
|
return contents
|
||||||
description = str(self.description)
|
|
||||||
else:
|
def _expand_contents(self, contents, params):
|
||||||
description = self.description
|
expanded_contents = self._expander.expand(contents, params)
|
||||||
if description is None and self._keep_descriptions:
|
description = expanded_contents.get("description")
|
||||||
return {}
|
if description is not None or not self._keep_descriptions:
|
||||||
expanded_desc = self._expander.expand(description, params)
|
amended_description = (description or "") + MAGIC_MANAGE_STRING
|
||||||
return {"description": (expanded_desc or "") + MAGIC_MANAGE_STRING}
|
expanded_contents["description"] = amended_description
|
||||||
|
return expanded_contents
|
||||||
|
|
||||||
def _pick_defaults(self, name, merge_global=True):
|
def _pick_defaults(self, name, merge_global=True):
|
||||||
try:
|
try:
|
||||||
@ -102,17 +103,14 @@ class NonTemplateRootMixin:
|
|||||||
def top_level_generate_items(self):
|
def top_level_generate_items(self):
|
||||||
try:
|
try:
|
||||||
defaults = self._pick_defaults(self.defaults_name, merge_global=False)
|
defaults = self._pick_defaults(self.defaults_name, merge_global=False)
|
||||||
description = self._format_description(params={})
|
contents = LocDict.merge(
|
||||||
raw_data = self._as_dict()
|
|
||||||
contents = self._expander.expand(raw_data, self.params)
|
|
||||||
data = LocDict.merge(
|
|
||||||
defaults.contents,
|
defaults.contents,
|
||||||
contents,
|
self.contents,
|
||||||
description,
|
|
||||||
pos=self.pos,
|
pos=self.pos,
|
||||||
)
|
)
|
||||||
|
expanded_contents = self._expand_contents(contents, self.params)
|
||||||
context = [Context(f"In {self}", self.pos)]
|
context = [Context(f"In {self}", self.pos)]
|
||||||
yield JobViewData(data, context)
|
yield JobViewData(expanded_contents, context)
|
||||||
except JenkinsJobsException as x:
|
except JenkinsJobsException as x:
|
||||||
raise x.with_context(f"In {self}", pos=self.pos)
|
raise x.with_context(f"In {self}", pos=self.pos)
|
||||||
|
|
||||||
@ -136,7 +134,8 @@ class TemplateRootMixin:
|
|||||||
item_params["id"] = self._id
|
item_params["id"] = self._id
|
||||||
contents = LocDict.merge(
|
contents = LocDict.merge(
|
||||||
defaults.contents,
|
defaults.contents,
|
||||||
self._as_dict(),
|
self.contents,
|
||||||
|
pos=self.pos,
|
||||||
)
|
)
|
||||||
axes = list(enum_str_format_required_params(self.name, self.name.pos))
|
axes = list(enum_str_format_required_params(self.name, self.name.pos))
|
||||||
axes_defaults = dict(enum_str_format_param_defaults(self.name))
|
axes_defaults = dict(enum_str_format_param_defaults(self.name))
|
||||||
@ -152,15 +151,9 @@ class TemplateRootMixin:
|
|||||||
key_pos=expanded_params.key_pos.get("exclude"),
|
key_pos=expanded_params.key_pos.get("exclude"),
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
description = self._format_description(expanded_params)
|
expanded_contents = self._expand_contents(contents, expanded_params)
|
||||||
expanded_contents = self._expander.expand(contents, expanded_params)
|
|
||||||
data = LocDict.merge(
|
|
||||||
expanded_contents,
|
|
||||||
description,
|
|
||||||
pos=self.pos,
|
|
||||||
)
|
|
||||||
context = [Context(f"In {self}", self.pos)]
|
context = [Context(f"In {self}", self.pos)]
|
||||||
yield JobViewData(data, context)
|
yield JobViewData(expanded_contents, context)
|
||||||
except JenkinsJobsException as x:
|
except JenkinsJobsException as x:
|
||||||
raise x.with_context(f"In {self}", pos=self.pos)
|
raise x.with_context(f"In {self}", pos=self.pos)
|
||||||
|
|
||||||
|
@ -46,13 +46,14 @@ class ViewBase(RootBase):
|
|||||||
view_type,
|
view_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _as_dict(self):
|
@property
|
||||||
|
def contents(self):
|
||||||
return LocDict.merge(
|
return LocDict.merge(
|
||||||
{
|
{
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
"view-type": self.view_type,
|
"view-type": self.view_type,
|
||||||
},
|
},
|
||||||
self.contents,
|
super().contents,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,18 +118,24 @@ def expected_error(scenario):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def check_folder(scenario, jjb_config, input):
|
# Tests use output files directories as expected folder name.
|
||||||
if "name" not in input:
|
def check_folders(scenario, job_xml_list):
|
||||||
return
|
root_dir = scenario.in_path.parent
|
||||||
if "folder" in input:
|
|
||||||
full_name = input["folder"] + "/" + input["name"]
|
def name_parent(name):
|
||||||
else:
|
*dirs, name = name.split("/")
|
||||||
full_name = input["name"]
|
return "/".join(dirs)
|
||||||
*dirs, name = full_name.split("/")
|
|
||||||
input_dir = scenario.in_path.parent
|
def path_parent(path):
|
||||||
expected_out_dirs = [input_dir.joinpath(*dirs)]
|
dir = str(path.relative_to(root_dir).parent)
|
||||||
actual_out_dirs = [path.parent for path in scenario.out_paths]
|
if dir == ".":
|
||||||
assert expected_out_dirs == actual_out_dirs
|
return ""
|
||||||
|
else:
|
||||||
|
return dir
|
||||||
|
|
||||||
|
actual_dirs = list(sorted(set(name_parent(jx.name) for jx in job_xml_list)))
|
||||||
|
expected_dirs = list(sorted(path_parent(path) for path in scenario.out_paths))
|
||||||
|
assert expected_dirs == actual_dirs
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -142,7 +148,6 @@ def check_generator(scenario, input, expected_output, jjb_config, registry, proj
|
|||||||
|
|
||||||
generator = Generator(registry)
|
generator = Generator(registry)
|
||||||
generator.gen_xml(xml, input)
|
generator.gen_xml(xml, input)
|
||||||
check_folder(scenario, jjb_config, input)
|
|
||||||
pretty_xml = XmlJob(xml, "fixturejob").output().decode()
|
pretty_xml = XmlJob(xml, "fixturejob").output().decode()
|
||||||
assert expected_output == pretty_xml
|
assert expected_output == pretty_xml
|
||||||
|
|
||||||
@ -188,6 +193,8 @@ def check_job(scenario, expected_output, jjb_config, registry):
|
|||||||
)
|
)
|
||||||
assert stripped_expected_output == pretty_xml
|
assert stripped_expected_output == pretty_xml
|
||||||
|
|
||||||
|
check_folders(scenario, job_xml_list)
|
||||||
|
|
||||||
return check
|
return check
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
name: test-folder
|
|
||||||
project-type: freestyle
|
|
||||||
folder: folders
|
|
@ -1,3 +0,0 @@
|
|||||||
name: test-folder
|
|
||||||
project-type: freestyle
|
|
||||||
folder: folders/test-nested-folder
|
|
@ -0,0 +1,19 @@
|
|||||||
|
# 'folders' attribute from defaults should be used (combined with job name) for job templates.
|
||||||
|
|
||||||
|
- defaults:
|
||||||
|
name: team1
|
||||||
|
folder: team1-jobs
|
||||||
|
|
||||||
|
- job:
|
||||||
|
name: ruby-jobs/sample-job
|
||||||
|
defaults: team1
|
||||||
|
builders:
|
||||||
|
- shell: |
|
||||||
|
rvm use --create ruby-2.3.0@rspec
|
||||||
|
bundle install
|
||||||
|
bundle exec rspec
|
||||||
|
|
||||||
|
- project:
|
||||||
|
name: sample-project
|
||||||
|
jobs:
|
||||||
|
- ruby-jobs/sample-job
|
@ -1,3 +1,5 @@
|
|||||||
|
# 'folders' attribute from defaults should be used (combined with job name) for jobs.
|
||||||
|
|
||||||
- defaults:
|
- defaults:
|
||||||
name: team1
|
name: team1
|
||||||
folder: team1-jobs
|
folder: team1-jobs
|
@ -0,0 +1,9 @@
|
|||||||
|
- job-template:
|
||||||
|
name: sample-job
|
||||||
|
project-type: freestyle
|
||||||
|
folder: folders/test-nested-folder
|
||||||
|
|
||||||
|
- project:
|
||||||
|
name: sample-project
|
||||||
|
jobs:
|
||||||
|
- sample-job
|
4
tests/yamlparser/job_fixtures/folders-nested-job.yaml
Normal file
4
tests/yamlparser/job_fixtures/folders-nested-job.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
- job:
|
||||||
|
name: sample-job
|
||||||
|
project-type: freestyle
|
||||||
|
folder: folders/test-nested-folder
|
@ -1,9 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<project>
|
<project>
|
||||||
<actions/>
|
<actions/>
|
||||||
|
<description><!-- Managed by Jenkins Job Builder --></description>
|
||||||
<keepDependencies>false</keepDependencies>
|
<keepDependencies>false</keepDependencies>
|
||||||
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
|
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
|
||||||
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
|
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
|
||||||
<concurrentBuild>false</concurrentBuild>
|
<concurrentBuild>false</concurrentBuild>
|
||||||
<canRoam>true</canRoam>
|
<canRoam>true</canRoam>
|
||||||
|
<properties/>
|
||||||
|
<scm class="hudson.scm.NullSCM"/>
|
||||||
|
<builders/>
|
||||||
|
<publishers/>
|
||||||
|
<buildWrappers/>
|
||||||
</project>
|
</project>
|
@ -1,9 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<project>
|
<project>
|
||||||
<actions/>
|
<actions/>
|
||||||
|
<description><!-- Managed by Jenkins Job Builder --></description>
|
||||||
<keepDependencies>false</keepDependencies>
|
<keepDependencies>false</keepDependencies>
|
||||||
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
|
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
|
||||||
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
|
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
|
||||||
<concurrentBuild>false</concurrentBuild>
|
<concurrentBuild>false</concurrentBuild>
|
||||||
<canRoam>true</canRoam>
|
<canRoam>true</canRoam>
|
||||||
|
<properties/>
|
||||||
|
<scm class="hudson.scm.NullSCM"/>
|
||||||
|
<builders/>
|
||||||
|
<publishers/>
|
||||||
|
<buildWrappers/>
|
||||||
</project>
|
</project>
|
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<project>
|
||||||
|
<actions/>
|
||||||
|
<description><!-- Managed by Jenkins Job Builder --></description>
|
||||||
|
<keepDependencies>false</keepDependencies>
|
||||||
|
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
|
||||||
|
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
|
||||||
|
<concurrentBuild>false</concurrentBuild>
|
||||||
|
<canRoam>true</canRoam>
|
||||||
|
<properties/>
|
||||||
|
<scm class="hudson.scm.NullSCM"/>
|
||||||
|
<builders>
|
||||||
|
<hudson.tasks.Shell>
|
||||||
|
<command>rvm use --create ruby-2.3.0@rspec
|
||||||
|
bundle install
|
||||||
|
bundle exec rspec
|
||||||
|
</command>
|
||||||
|
</hudson.tasks.Shell>
|
||||||
|
</builders>
|
||||||
|
<publishers/>
|
||||||
|
<buildWrappers/>
|
||||||
|
</project>
|
Loading…
Reference in New Issue
Block a user