diff --git a/checkbox-ng/plainbox/impl/unit/template.py b/checkbox-ng/plainbox/impl/unit/template.py index 3df94fc07e..8941138ff9 100644 --- a/checkbox-ng/plainbox/impl/unit/template.py +++ b/checkbox-ng/plainbox/impl/unit/template.py @@ -27,6 +27,7 @@ from plainbox.i18n import gettext as _ from plainbox.i18n import gettext_noop as N_ +from plainbox.impl.decorators import instance_method_lru_cache from plainbox.impl.resource import ExpressionFailedError from plainbox.impl.resource import Resource from plainbox.impl.resource import ResourceProgram @@ -39,10 +40,12 @@ from plainbox.impl.unit.unit_with_id import UnitWithId from plainbox.impl.unit.unit_with_id import UnitWithIdValidator from plainbox.impl.unit.validators import CorrectFieldValueValidator +from plainbox.impl.unit.validators import PresentFieldValidator from plainbox.impl.unit.validators import ReferenceConstraint from plainbox.impl.unit.validators import UnitReferenceValidator from plainbox.impl.unit.validators import UniqueValueValidator from plainbox.impl.validation import Problem +from plainbox.impl.validation import Severity __all__ = ['TemplateUnit'] @@ -295,6 +298,40 @@ def template_imports(self): """ return self.get_record_value('template-imports') + @property + def template_summary(self): + """ + Value of the 'template-summary' field. + + This attribute stores the summary of a template, that is a human + readable name for that template. + """ + return self.get_record_value("template-summary") + + @instance_method_lru_cache(maxsize=None) + def tr_template_summary(self): + """ + Get the translated version of :meth:`template_summary`. + """ + return self.get_translated_record_value("template-summary") + + @property + def template_description(self): + """ + Value of the 'template-description' field. + + This attribute stores the definition of a template which can be used + to provide more information about this template. + """ + return self.get_record_value("template-description") + + @instance_method_lru_cache(maxsize=None) + def tr_template_description(self): + """ + Get the translated version of :meth:`template_description`. + """ + return self.get_translated_record_value("template-description") + @property def template_unit(self): """ @@ -488,6 +525,8 @@ class fields(SymbolDef): """Symbols for each field that a TemplateUnit can have.""" template_id = "template-id" + template_summary = "template-summary" + template_description = "template-description" template_unit = 'template-unit' template_resource = 'template-resource' template_filter = 'template-filter' @@ -507,6 +546,23 @@ class fields(SymbolDef): message=_("identifier cannot define a custom namespace"), onlyif=lambda unit: unit.get_record_value("template-id")), ], + fields.template_summary: [ + concrete_validators.translatable, + PresentFieldValidator(severity=Severity.advice), + CorrectFieldValueValidator( + lambda field: field.count("\n") == 0, + Problem.wrong, Severity.warning, + message=_("please use only one line"), + onlyif=lambda unit: unit.template_summary), + CorrectFieldValueValidator( + lambda field: len(field) <= 80, + Problem.wrong, Severity.warning, + message=_("please stay under 80 characters"), + onlyif=lambda unit: unit.template_summary) + ], + fields.template_description: [ + concrete_validators.translatable, + ], fields.template_unit: [ concrete_validators.untranslatable, ], diff --git a/checkbox-ng/plainbox/impl/unit/test_template.py b/checkbox-ng/plainbox/impl/unit/test_template.py index 180ddb2708..ead808f35d 100644 --- a/checkbox-ng/plainbox/impl/unit/test_template.py +++ b/checkbox-ng/plainbox/impl/unit/test_template.py @@ -223,6 +223,42 @@ def test_template_id__precedence_jinja2(self): "id": "job_id_{{ param }}", }).template_id, "template_id") + def test_template_summary(self): + self.assertEqual(TemplateUnit({ + "template-summary": "summary", + }).template_summary, "summary") + + def test_template_description(self): + self.assertEqual(TemplateUnit({ + "template-description": "description", + }).template_description, "description") + + def test_tr_template_summary(self): + template = TemplateUnit({ + "_template-summary": "summary", + }) + self.assertEqual(template.tr_template_summary(), "summary") + + def test_translated_template_summary(self): + """Ensure template_summary is populated with the translated field.""" + self.assertEqual(TemplateUnit({ + "_template-summary": "summary", + }).template_summary, "summary") + + def test_tr_template_description(self): + template = TemplateUnit({ + "_template-description": "description", + }) + self.assertEqual(template.tr_template_description(), "description") + + def test_translated_template_description(self): + """ + Ensure template_description is populated with the translated field. + """ + self.assertEqual(TemplateUnit({ + "_template-description": "description", + }).template_description, "description") + def test_template_resource__empty(self): self.assertEqual(TemplateUnit({}).template_resource, None) @@ -496,6 +532,50 @@ def test_template_unit__untranslatable(self): issue_list, self.unit_cls.Meta.fields.template_unit, Problem.unexpected_i18n, Severity.warning) + def test_template_summary__translatable(self): + issue_list = self.unit_cls({ + 'template-summary': 'template_summary' + }, provider=self.provider).check() + self.assertIssueFound(issue_list, + self.unit_cls.Meta.fields.template_summary, + Problem.expected_i18n, + Severity.warning) + + def test_template_summary__present(self): + issue_list = self.unit_cls({ + }, provider=self.provider).check() + self.assertIssueFound(issue_list, + self.unit_cls.Meta.fields.template_summary, + Problem.missing, + Severity.advice) + + def test_template_summary__one_line(self): + issue_list = self.unit_cls({ + 'template-summary': 'line1\nline2' + }, provider=self.provider).check() + self.assertIssueFound(issue_list, + self.unit_cls.Meta.fields.template_summary, + Problem.wrong, + Severity.warning) + + def test_template_summary__short_line(self): + issue_list = self.unit_cls({ + 'template-summary': 'x' * 81 + }, provider=self.provider).check() + self.assertIssueFound(issue_list, + self.unit_cls.Meta.fields.template_summary, + Problem.wrong, + Severity.warning) + + def test_template_description__translatable(self): + issue_list = self.unit_cls({ + 'template-description': 'template_description' + }, provider=self.provider).check() + self.assertIssueFound(issue_list, + self.unit_cls.Meta.fields.template_description, + Problem.expected_i18n, + Severity.warning) + def test_template_resource__untranslatable(self): issue_list = self.unit_cls({ '_template-resource': 'template_resource' diff --git a/docs/reference/units/template.rst b/docs/reference/units/template.rst index eeb013defc..109e99f088 100644 --- a/docs/reference/units/template.rst +++ b/docs/reference/units/template.rst @@ -41,6 +41,24 @@ Template-Specific Fields ``stress/reboot_{iterations}_times``, the computed ``template-id`` field will be ``stress/reboot_iterations_times``. +.. _Template template-summary field: + +``template-summary`` + A human readable name for the template. This value is available for + translation into other languages. It must be one line long, ideally it + should be short (50-70 characters max). + + This field is optional (Checkbox will only advise you to provide one when + running provider validation). + +.. _Template template-description field: + +``template-description`` + A long form description of what the template does or the kind of jobs it + instantiates. This value is available for translation into other languages. + + This field is optional. + .. _Template template-unit field: ``template-unit``