From c1ac0e03d63a6c3eb762432a1b32760f64305993 Mon Sep 17 00:00:00 2001 From: Vsevolod Fedorov Date: Fri, 24 Nov 2023 12:33:48 +0300 Subject: [PATCH] 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 --- doc/source/definition.rst | 2 +- jenkins_jobs/defaults.py | 2 + jenkins_jobs/job.py | 30 ++++++----- jenkins_jobs/root_base.py | 53 ++++++++----------- jenkins_jobs/view.py | 5 +- tests/conftest.py | 33 +++++++----- tests/general/fixtures/folders001.yaml | 3 -- tests/general/fixtures/folders002.yaml | 3 -- .../folders-defaults-for-job-template.yaml | 19 +++++++ ...ute.yaml => folders-defaults-for-job.yaml} | 2 + .../folders-nested-job-template.yaml | 9 ++++ .../job_fixtures/folders-nested-job.yaml | 4 ++ .../folders-nested-job-template.xml} | 6 +++ .../folders-nested-job.xml} | 6 +++ ... => folders-defaults-for-job-template.xml} | 0 .../ruby-jobs/folders-defaults-for-job.xml | 22 ++++++++ 16 files changed, 134 insertions(+), 65 deletions(-) delete mode 100644 tests/general/fixtures/folders001.yaml delete mode 100644 tests/general/fixtures/folders002.yaml create mode 100644 tests/yamlparser/job_fixtures/folders-defaults-for-job-template.yaml rename tests/yamlparser/job_fixtures/{folders-attribute.yaml => folders-defaults-for-job.yaml} (72%) create mode 100644 tests/yamlparser/job_fixtures/folders-nested-job-template.yaml create mode 100644 tests/yamlparser/job_fixtures/folders-nested-job.yaml rename tests/{general/fixtures/folders/folders001.xml => yamlparser/job_fixtures/folders/test-nested-folder/folders-nested-job-template.xml} (65%) rename tests/{general/fixtures/folders/test-nested-folder/folders002.xml => yamlparser/job_fixtures/folders/test-nested-folder/folders-nested-job.xml} (65%) rename tests/yamlparser/job_fixtures/team1-jobs/ruby-jobs/{folders-attribute.xml => folders-defaults-for-job-template.xml} (100%) create mode 100644 tests/yamlparser/job_fixtures/team1-jobs/ruby-jobs/folders-defaults-for-job.xml diff --git a/doc/source/definition.rst b/doc/source/definition.rst index a45692f70..828a4950d 100644 --- a/doc/source/definition.rst +++ b/doc/source/definition.rst @@ -454,7 +454,7 @@ Job Name Example: Folder Attribute Example: -.. literalinclude:: /../../tests/yamlparser/job_fixtures/folders-attribute.yaml +.. literalinclude:: /../../tests/yamlparser/job_fixtures/folders-defaults-for-job.yaml .. _ids: diff --git a/jenkins_jobs/defaults.py b/jenkins_jobs/defaults.py index d771a5ba2..33ba1a482 100644 --- a/jenkins_jobs/defaults.py +++ b/jenkins_jobs/defaults.py @@ -28,6 +28,7 @@ job_contents_keys = { "pipeline-scm", "reporters", # General. + "description", "project-type", "folder", "node", @@ -89,6 +90,7 @@ job_contents_keys = { view_contents_keys = { # Common. + "description", "filter-executors", "filter-queue", # All diff --git a/jenkins_jobs/job.py b/jenkins_jobs/job.py index 7e5bfb3fd..56dd0f434 100644 --- a/jenkins_jobs/job.py +++ b/jenkins_jobs/job.py @@ -13,7 +13,6 @@ from dataclasses import dataclass from .errors import JenkinsJobsException -from .loc_loader import LocDict from .root_base import RootBase, NonTemplateRootMixin, TemplateRootMixin, Group from .defaults import split_contents_params, job_contents_keys @@ -49,21 +48,26 @@ class JobBase(RootBase): 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 - 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: - 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: - return self.name + name = expanded_contents["name"] + expanded_contents["name"] = f"{folder}/{name}" + return expanded_contents class Job(JobBase, NonTemplateRootMixin): diff --git a/jenkins_jobs/root_base.py b/jenkins_jobs/root_base.py index b6e6c58f9..4ae8593b9 100644 --- a/jenkins_jobs/root_base.py +++ b/jenkins_jobs/root_base.py @@ -52,7 +52,7 @@ class RootBase: description: str defaults_name: str params: dict - contents: dict + _contents: dict @property def id(self): @@ -65,19 +65,20 @@ class RootBase: def title(self): return str(self).capitalize() - def _format_description(self, params): - if self.description is None: - defaults = self._pick_defaults(self.defaults_name) - description = defaults.params.get("description") - else: - if type(self.description) is LocString: - description = str(self.description) - else: - description = self.description - if description is None and self._keep_descriptions: - return {} - expanded_desc = self._expander.expand(description, params) - return {"description": (expanded_desc or "") + MAGIC_MANAGE_STRING} + @property + def contents(self): + contents = self._contents.copy() + if self.description is not None: + contents["description"] = self.description + return contents + + def _expand_contents(self, contents, params): + expanded_contents = self._expander.expand(contents, params) + description = expanded_contents.get("description") + if description is not None or not self._keep_descriptions: + amended_description = (description or "") + MAGIC_MANAGE_STRING + expanded_contents["description"] = amended_description + return expanded_contents def _pick_defaults(self, name, merge_global=True): try: @@ -102,17 +103,14 @@ class NonTemplateRootMixin: def top_level_generate_items(self): try: defaults = self._pick_defaults(self.defaults_name, merge_global=False) - description = self._format_description(params={}) - raw_data = self._as_dict() - contents = self._expander.expand(raw_data, self.params) - data = LocDict.merge( + contents = LocDict.merge( defaults.contents, - contents, - description, + self.contents, pos=self.pos, ) + expanded_contents = self._expand_contents(contents, self.params) context = [Context(f"In {self}", self.pos)] - yield JobViewData(data, context) + yield JobViewData(expanded_contents, context) except JenkinsJobsException as x: raise x.with_context(f"In {self}", pos=self.pos) @@ -136,7 +134,8 @@ class TemplateRootMixin: item_params["id"] = self._id contents = LocDict.merge( defaults.contents, - self._as_dict(), + self.contents, + pos=self.pos, ) axes = list(enum_str_format_required_params(self.name, self.name.pos)) axes_defaults = dict(enum_str_format_param_defaults(self.name)) @@ -152,15 +151,9 @@ class TemplateRootMixin: key_pos=expanded_params.key_pos.get("exclude"), ): continue - description = self._format_description(expanded_params) - expanded_contents = self._expander.expand(contents, expanded_params) - data = LocDict.merge( - expanded_contents, - description, - pos=self.pos, - ) + expanded_contents = self._expand_contents(contents, expanded_params) context = [Context(f"In {self}", self.pos)] - yield JobViewData(data, context) + yield JobViewData(expanded_contents, context) except JenkinsJobsException as x: raise x.with_context(f"In {self}", pos=self.pos) diff --git a/jenkins_jobs/view.py b/jenkins_jobs/view.py index 12a138cdf..4ba9303aa 100644 --- a/jenkins_jobs/view.py +++ b/jenkins_jobs/view.py @@ -46,13 +46,14 @@ class ViewBase(RootBase): view_type, ) - def _as_dict(self): + @property + def contents(self): return LocDict.merge( { "name": self.name, "view-type": self.view_type, }, - self.contents, + super().contents, ) diff --git a/tests/conftest.py b/tests/conftest.py index b765afd3b..a2b14370d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -118,18 +118,24 @@ def expected_error(scenario): return None -def check_folder(scenario, jjb_config, input): - if "name" not in input: - return - if "folder" in input: - full_name = input["folder"] + "/" + input["name"] - else: - full_name = input["name"] - *dirs, name = full_name.split("/") - input_dir = scenario.in_path.parent - expected_out_dirs = [input_dir.joinpath(*dirs)] - actual_out_dirs = [path.parent for path in scenario.out_paths] - assert expected_out_dirs == actual_out_dirs +# Tests use output files directories as expected folder name. +def check_folders(scenario, job_xml_list): + root_dir = scenario.in_path.parent + + def name_parent(name): + *dirs, name = name.split("/") + return "/".join(dirs) + + def path_parent(path): + dir = str(path.relative_to(root_dir).parent) + if dir == ".": + 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 @@ -142,7 +148,6 @@ def check_generator(scenario, input, expected_output, jjb_config, registry, proj generator = Generator(registry) generator.gen_xml(xml, input) - check_folder(scenario, jjb_config, input) pretty_xml = XmlJob(xml, "fixturejob").output().decode() assert expected_output == pretty_xml @@ -188,6 +193,8 @@ def check_job(scenario, expected_output, jjb_config, registry): ) assert stripped_expected_output == pretty_xml + check_folders(scenario, job_xml_list) + return check diff --git a/tests/general/fixtures/folders001.yaml b/tests/general/fixtures/folders001.yaml deleted file mode 100644 index 948ccc6d0..000000000 --- a/tests/general/fixtures/folders001.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: test-folder -project-type: freestyle -folder: folders diff --git a/tests/general/fixtures/folders002.yaml b/tests/general/fixtures/folders002.yaml deleted file mode 100644 index b5626607b..000000000 --- a/tests/general/fixtures/folders002.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: test-folder -project-type: freestyle -folder: folders/test-nested-folder diff --git a/tests/yamlparser/job_fixtures/folders-defaults-for-job-template.yaml b/tests/yamlparser/job_fixtures/folders-defaults-for-job-template.yaml new file mode 100644 index 000000000..9c53bb2e6 --- /dev/null +++ b/tests/yamlparser/job_fixtures/folders-defaults-for-job-template.yaml @@ -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 diff --git a/tests/yamlparser/job_fixtures/folders-attribute.yaml b/tests/yamlparser/job_fixtures/folders-defaults-for-job.yaml similarity index 72% rename from tests/yamlparser/job_fixtures/folders-attribute.yaml rename to tests/yamlparser/job_fixtures/folders-defaults-for-job.yaml index 7346fa2f9..dd8d0f3a6 100644 --- a/tests/yamlparser/job_fixtures/folders-attribute.yaml +++ b/tests/yamlparser/job_fixtures/folders-defaults-for-job.yaml @@ -1,3 +1,5 @@ +# 'folders' attribute from defaults should be used (combined with job name) for jobs. + - defaults: name: team1 folder: team1-jobs diff --git a/tests/yamlparser/job_fixtures/folders-nested-job-template.yaml b/tests/yamlparser/job_fixtures/folders-nested-job-template.yaml new file mode 100644 index 000000000..b17c744b2 --- /dev/null +++ b/tests/yamlparser/job_fixtures/folders-nested-job-template.yaml @@ -0,0 +1,9 @@ +- job-template: + name: sample-job + project-type: freestyle + folder: folders/test-nested-folder + +- project: + name: sample-project + jobs: + - sample-job diff --git a/tests/yamlparser/job_fixtures/folders-nested-job.yaml b/tests/yamlparser/job_fixtures/folders-nested-job.yaml new file mode 100644 index 000000000..3e7da5739 --- /dev/null +++ b/tests/yamlparser/job_fixtures/folders-nested-job.yaml @@ -0,0 +1,4 @@ +- job: + name: sample-job + project-type: freestyle + folder: folders/test-nested-folder diff --git a/tests/general/fixtures/folders/folders001.xml b/tests/yamlparser/job_fixtures/folders/test-nested-folder/folders-nested-job-template.xml similarity index 65% rename from tests/general/fixtures/folders/folders001.xml rename to tests/yamlparser/job_fixtures/folders/test-nested-folder/folders-nested-job-template.xml index 1505db519..0570e10a5 100644 --- a/tests/general/fixtures/folders/folders001.xml +++ b/tests/yamlparser/job_fixtures/folders/test-nested-folder/folders-nested-job-template.xml @@ -1,9 +1,15 @@ + <!-- Managed by Jenkins Job Builder --> false false false false true + + + + + diff --git a/tests/general/fixtures/folders/test-nested-folder/folders002.xml b/tests/yamlparser/job_fixtures/folders/test-nested-folder/folders-nested-job.xml similarity index 65% rename from tests/general/fixtures/folders/test-nested-folder/folders002.xml rename to tests/yamlparser/job_fixtures/folders/test-nested-folder/folders-nested-job.xml index 1505db519..0570e10a5 100644 --- a/tests/general/fixtures/folders/test-nested-folder/folders002.xml +++ b/tests/yamlparser/job_fixtures/folders/test-nested-folder/folders-nested-job.xml @@ -1,9 +1,15 @@ + <!-- Managed by Jenkins Job Builder --> false false false false true + + + + + diff --git a/tests/yamlparser/job_fixtures/team1-jobs/ruby-jobs/folders-attribute.xml b/tests/yamlparser/job_fixtures/team1-jobs/ruby-jobs/folders-defaults-for-job-template.xml similarity index 100% rename from tests/yamlparser/job_fixtures/team1-jobs/ruby-jobs/folders-attribute.xml rename to tests/yamlparser/job_fixtures/team1-jobs/ruby-jobs/folders-defaults-for-job-template.xml diff --git a/tests/yamlparser/job_fixtures/team1-jobs/ruby-jobs/folders-defaults-for-job.xml b/tests/yamlparser/job_fixtures/team1-jobs/ruby-jobs/folders-defaults-for-job.xml new file mode 100644 index 000000000..2c57eb750 --- /dev/null +++ b/tests/yamlparser/job_fixtures/team1-jobs/ruby-jobs/folders-defaults-for-job.xml @@ -0,0 +1,22 @@ + + + + <!-- Managed by Jenkins Job Builder --> + false + false + false + false + true + + + + + rvm use --create ruby-2.3.0@rspec +bundle install +bundle exec rspec + + + + + +