class Meta: name = N_('file') validator_cls = FileUnitValidator class fields(SymbolDef): """ Symbols for each field that a FileUnit can have """ path = 'path' role = 'role' base = 'base' field_validators = { fields.path: [ CorrectFieldValueValidator( lambda value: os.path.splitext(value)[1] == '.pxu', Problem.deprecated, Severity.advice, onlyif=lambda unit: unit.role == FileRole.unit_source, message=_( "please use .pxu as an extension for all" " files with plainbox units, see: {}").format( 'http://plainbox.readthedocs.org/en/latest/author/' 'faq.html#faq-1')), ], fields.role: [ CorrectFieldValueValidator( lambda value: value in FileRole.get_all_symbols(), message=_('valid values are: {}').format(', '.join( str(sym) for sym in sorted(FileRole.get_all_symbols())))), ] }
class Meta: name = N_('category') class fields(SymbolDef): """ Symbols for each field that a JobDefinition can have """ name = 'name' field_validators = { fields.name: [ TranslatableFieldValidator, TemplateVariantFieldValidator, PresentFieldValidator, # We want the name to be a single line CorrectFieldValueValidator( lambda name: name.count("\n") == 0, Problem.wrong, Severity.warning, message=_("please use only one line"), onlyif=lambda unit: unit.name is not None), # We want the name to be relatively short CorrectFieldValueValidator( lambda name: len(name) <= 80, Problem.wrong, Severity.warning, message=_("please stay under 80 characters"), onlyif=lambda unit: unit.name is not None), ] }
class Meta: name = 'exporter' class fields(SymbolDef): """Symbols for each field that an Exporter can have.""" summary = 'summary' entry_point = 'entry_point' file_extension = 'file_extension' options = 'options' data = 'data' field_validators = { fields.summary: [ PresentFieldValidator(severity=Severity.advice), concrete_validators.translatable, concrete_validators.oneLine, concrete_validators.shortValue, ], fields.entry_point: [ concrete_validators.present, concrete_validators.untranslatable, CorrectFieldValueValidator( lambda entry_point: pkg_resources.load_entry_point( 'checkbox-ng', 'plainbox.exporter', entry_point), Problem.wrong, Severity.error), ], fields.file_extension: [ concrete_validators.present, concrete_validators.untranslatable, CorrectFieldValueValidator( lambda extension: re.search("^[\w\.\-]+$", extension), Problem.syntax_error, Severity.error), ], fields.options: [ concrete_validators.untranslatable, ], fields.data: [ concrete_validators.untranslatable, CorrectFieldValueValidator( lambda value, unit: json.loads(value), Problem.syntax_error, Severity.error, onlyif=lambda unit: unit.data), CorrectFieldValueValidator( lambda value, unit: os.path.isfile(os.path.join( unit.provider.data_dir, json.loads(value)['template'])), Problem.wrong, Severity.error, message=_("Jinja2 template not found"), onlyif=lambda unit: unit.entry_point == 'jinja2'), ], }
class Meta: name = N_('unit-with-id') class fields(SymbolDef): id = 'id' validator_cls = UnitWithIdValidator field_validators = { fields.id: [ # We don't want anyone marking id up for translation UntranslatableFieldValidator, # We want this field to be present at all times PresentFieldValidator, # We want each instance to have a different identifier TemplateVariantFieldValidator, # When checking in a globally, all units need an unique value UniqueValueValidator, # We want to have bare, namespace-less identifiers CorrectFieldValueValidator( lambda value, unit: ( "::" not in unit.get_record_value('id')), message=_("identifier cannot define a custom namespace"), onlyif=lambda unit: unit.get_record_value('id')), ] }
class Meta: name = 'manifest entry' class fields(SymbolDef): """ Symbols for each field that a TestPlan can have. """ name = 'name' value_type = 'value-type' value_unit = 'value-unit' resource_key = 'resource-key' field_validators = { fields.name: [ TranslatableFieldValidator, TemplateVariantFieldValidator, PresentFieldValidator, ], fields.value_type: [ UntranslatableFieldValidator, PresentFieldValidator(), CorrectFieldValueValidator( lambda value_type: value_type in ('bool', 'natural')), ], fields.value_unit: [ # OPTIONAL ], fields.resource_key: [ UntranslatableFieldValidator, ] }
class Meta: name = N_('unit-with-id') class fields(SymbolDef): id = 'id' validator_cls = UnitWithIdValidator field_validators = { fields.id: [ concrete_validators.untranslatable, concrete_validators.present, concrete_validators.templateVariant, UniqueValueValidator(), # We want to have bare, namespace-less identifiers CorrectFieldValueValidator( lambda value, unit: ("::" not in unit.get_record_value('id')), message=_("identifier cannot define a custom namespace"), onlyif=lambda unit: unit.get_record_value('id')), ] }
class Meta: name = N_('job') class fields(SymbolDef): """ Symbols for each field that a JobDefinition can have """ name = 'name' summary = 'summary' plugin = 'plugin' command = 'command' description = 'description' user = '******' environ = 'environ' estimated_duration = 'estimated_duration' depends = 'depends' after = 'after' requires = 'requires' shell = 'shell' imports = 'imports' flags = 'flags' category_id = 'category_id' purpose = 'purpose' steps = 'steps' verification = 'verification' qml_file = 'qml_file' certification_status = 'certification_status' field_validators = { fields.name: [ UntranslatableFieldValidator, TemplateVariantFieldValidator, DeprecatedFieldValidator( _("use 'id' and 'summary' instead of 'name'")), ], # NOTE: 'id' validators are "inherited" so we don't have it here fields.summary: [ TranslatableFieldValidator, TemplateVariantFieldValidator, PresentFieldValidator(severity=Severity.advice), # We want the summary to be a single line CorrectFieldValueValidator( lambda summary: summary.count("\n") == 0, Problem.wrong, Severity.warning, message=_("please use only one line"), onlyif=lambda unit: unit.summary is not None), # We want the summary to be relatively short CorrectFieldValueValidator( lambda summary: len(summary) <= 80, Problem.wrong, Severity.warning, message=_("please stay under 80 characters"), onlyif=lambda unit: unit.summary is not None), ], fields.plugin: [ UntranslatableFieldValidator, TemplateInvariantFieldValidator, PresentFieldValidator, CorrectFieldValueValidator( lambda plugin: ( plugin in JobDefinition.plugin.get_all_symbols()), message=_('valid values are: {}').format( ', '.join(str(sym) for sym in sorted( _PluginValues.get_all_symbols())))), CorrectFieldValueValidator( lambda plugin: plugin != 'local', Problem.deprecated, Severity.advice, message=_("please migrate to job templates, " "see plainbox-template-unit(7) for details")), CorrectFieldValueValidator( lambda plugin: plugin != 'user-verify', Problem.deprecated, Severity.advice, message=_("please migrate to user-interact-verify")), ], fields.command: [ UntranslatableFieldValidator, # All jobs except for manual must have a command PresentFieldValidator( message=_("command is mandatory for non-manual jobs"), onlyif=lambda unit: unit.plugin not in ('manual', 'qml')), # Manual jobs cannot have a command UselessFieldValidator( message=_("command on a manual or qml job makes no sense"), onlyif=lambda unit: unit.plugin in ('manual', 'qml')), # We don't want to refer to CHECKBOX_SHARE anymore CorrectFieldValueValidator( lambda command: "CHECKBOX_SHARE" not in command, Problem.deprecated, Severity.advice, message=_("please use PLAINBOX_PROVIDER_DATA" " instead of CHECKBOX_SHARE"), onlyif=lambda unit: unit.command is not None), # We don't want to refer to CHECKBOX_DATA anymore CorrectFieldValueValidator( lambda command: "CHECKBOX_DATA" not in command, Problem.deprecated, Severity.advice, message=_("please use PLAINBOX_SESSION_SHARE" " instead of CHECKBOX_DATA"), onlyif=lambda unit: unit.command is not None), # We want to catch silly mistakes that shlex can detect ShellProgramValidator, ], fields.description: [ TranslatableFieldValidator, TemplateVariantFieldValidator, # Description is mandatory for manual jobs PresentFieldValidator( message=_("manual jobs must have a description field, or a" " set of purpose, steps, and verification " "fields"), onlyif=lambda unit: unit.plugin == 'manual' and unit.purpose is None and unit.steps is None and unit.verification is None ), # Description or a set of purpose, steps and verification # fields is recommended for all other jobs PresentFieldValidator( severity=Severity.advice, message=_("all jobs should have a description field, or a " "set of purpose, steps and verification fields"), onlyif=lambda unit: ( 'simple' not in unit.get_flag_set() and unit.plugin != 'manual' and ( unit.purpose is None and unit.steps is None and unit.verification is None))), ], fields.purpose: [ TranslatableFieldValidator, PresentFieldValidator( severity=Severity.advice, message=("please use purpose, steps, and verification" " fields. See http://plainbox.readthedocs.org" "/en/latest/author/faq.html#faq-2"), onlyif=lambda unit: unit.startup_user_interaction_required and unit.get_record_value('summary') is None), ], fields.steps: [ TranslatableFieldValidator, PresentFieldValidator( severity=Severity.advice, message=("please use purpose, steps, and verification" " fields. See http://plainbox.readthedocs.org" "/en/latest/author/faq.html#faq-2"), onlyif=lambda unit: unit.startup_user_interaction_required), ], fields.verification: [ TranslatableFieldValidator, PresentFieldValidator( severity=Severity.advice, message=("please use purpose, steps, and verification" " fields. See http://plainbox.readthedocs.org" "/en/latest/author/faq.html#faq-2"), onlyif=lambda unit: unit.plugin in ( 'manual', 'user-verify', 'user-interact-verify')), ], fields.user: [ UntranslatableFieldValidator, TemplateInvariantFieldValidator, # User should be either None or 'root' CorrectFieldValueValidator( message=_("user can only be 'root'"), correct_fn=lambda user: user in (None, 'root')), # User is useless without a command to run UselessFieldValidator( message=_("user without a command makes no sense"), onlyif=lambda unit: unit.command is None) ], fields.environ: [ UntranslatableFieldValidator, TemplateInvariantFieldValidator, # Environ is useless without a command to run UselessFieldValidator( message=_("environ without a command makes no sense"), onlyif=lambda unit: unit.command is None), ], fields.estimated_duration: [ UntranslatableFieldValidator, TemplateInvariantFieldValidator, PresentFieldValidator( severity=Severity.advice, onlyif=lambda unit: 'simple' not in unit.get_flag_set() ), CorrectFieldValueValidator( lambda duration: float(duration) > 0, message="value must be a positive number", onlyif=lambda unit: ( unit.get_record_value('estimated_duration'))), ], fields.depends: [ UntranslatableFieldValidator, CorrectFieldValueValidator( lambda value, unit: ( unit.get_direct_dependencies() is not None)), UnitReferenceValidator( lambda unit: unit.get_direct_dependencies(), constraints=[ ReferenceConstraint( lambda referrer, referee: referee.unit == 'job', message=_("the referenced unit is not a job"))]) # TODO: should not refer to deprecated jobs, # onlyif job itself is not deprecated ], fields.after: [ UntranslatableFieldValidator, CorrectFieldValueValidator( lambda value, unit: ( unit.get_after_dependencies() is not None)), UnitReferenceValidator( lambda unit: unit.get_after_dependencies(), constraints=[ ReferenceConstraint( lambda referrer, referee: referee.unit == 'job', message=_("the referenced unit is not a job"))]) ], fields.requires: [ UntranslatableFieldValidator, CorrectFieldValueValidator( lambda value, unit: unit.get_resource_program(), onlyif=lambda unit: unit.requires is not None), UnitReferenceValidator( lambda unit: unit.get_resource_dependencies(), constraints=[ ReferenceConstraint( lambda referrer, referee: referee.unit == 'job', message=_("the referenced unit is not a job")), ReferenceConstraint( lambda referrer, referee: ( referee.plugin == 'resource'), onlyif=lambda referrer, referee: ( referee.unit == 'job'), message=_( "the referenced job is not a resource job")), ]), # TODO: should not refer to deprecated jobs, # onlyif job itself is not deprecated ], fields.shell: [ UntranslatableFieldValidator, TemplateInvariantFieldValidator, # Shell should be only '/bin/sh', or None (which gives bash) CorrectFieldValueValidator( lambda shell: shell in ('/bin/sh', '/bin/bash', 'bash'), message=_("only /bin/sh and /bin/bash are allowed")), ], fields.imports: [ UntranslatableFieldValidator, TemplateInvariantFieldValidator, CorrectFieldValueValidator( lambda value, unit: ( list(unit.get_imported_jobs()) is not None)), UnitReferenceValidator( lambda unit: [ job_id for job_id, identifier in unit.get_imported_jobs()], constraints=[ ReferenceConstraint( lambda referrer, referee: referee.unit == 'job', message=_("the referenced unit is not a job"))]), # TODO: should not refer to deprecated jobs, # onlyif job itself is not deprecated ], fields.category_id: [ UntranslatableFieldValidator, TemplateInvariantFieldValidator, UnitReferenceValidator( lambda unit: ( [unit.get_category_id()] if unit.category_id else ()), constraints=[ ReferenceConstraint( lambda referrer, referee: ( referee.unit == 'category'), message=_( "the referenced unit is not a category"))]), # TODO: should not refer to deprecated categories, # onlyif job itself is not deprecated ], fields.flags: [ UntranslatableFieldValidator, TemplateInvariantFieldValidator, CorrectFieldValueValidator( lambda value, unit: ( 'simple' in unit.get_flag_set() or 'preserve-locale' in unit.get_flag_set()), Problem.expected_i18n, Severity.advice, message=_( 'please ensure that the command supports' ' non-C locale then set the preserve-locale flag' ), onlyif=lambda unit: unit.command), CorrectFieldValueValidator( lambda value, unit: ( not ('explicit-fail' in unit.get_flag_set() and unit.plugin in { 'shell', 'user-interact', 'attachment', 'local', 'resource'})), Problem.useless, Severity.advice, message=_('explicit-fail makes no sense for job which ' 'outcome is automatically determined.') ), # The has-leftovers flag is useless without a command CorrectFieldValueValidator( lambda value, unit: ( 'has-leftovers' not in unit.get_flag_set()), Problem.useless, Severity.advice, message=_( 'has-leftovers makes no sense without a command' ), onlyif=lambda unit: unit.command is None), ], fields.qml_file: [ UntranslatableFieldValidator, TemplateInvariantFieldValidator, PresentFieldValidator( onlyif=lambda unit: unit.plugin == 'qml'), CorrectFieldValueValidator( lambda value: value.endswith('.qml'), Problem.wrong, Severity.advice, message=_('use the .qml extension for all QML files'), onlyif=lambda unit: (unit.plugin == 'qml' and unit.qml_file)), CorrectFieldValueValidator( lambda value, unit: os.path.isfile(unit.qml_file), message=_('please point to an existing QML file'), onlyif=lambda unit: (unit.plugin == 'qml' and unit.qml_file)), ], fields.certification_status: [ UntranslatableFieldValidator, TemplateInvariantFieldValidator, CorrectFieldValueValidator( lambda certification_status: ( certification_status in _CertificationStatusValues.get_all_symbols()), message=_('valid values are: {}').format( ', '.join(str(sym) for sym in sorted( _CertificationStatusValues.get_all_symbols())))), ], }
from plainbox.impl.unit.validators import PresentFieldValidator from plainbox.impl.unit.validators import TemplateInvariantFieldValidator from plainbox.impl.unit.validators import TemplateVariantFieldValidator from plainbox.impl.unit.validators import TranslatableFieldValidator from plainbox.impl.unit.validators import UntranslatableFieldValidator translatable = TranslatableFieldValidator() templateVariant = TemplateVariantFieldValidator() templateInvariant = TemplateInvariantFieldValidator() untranslatable = UntranslatableFieldValidator() present = PresentFieldValidator() localDeprecated = CorrectFieldValueValidator( lambda plugin: plugin != 'local', Problem.deprecated, Severity.advice, message=_("please migrate to job templates, see plainbox-template-unit(7)" " for details")) oneLine = CorrectFieldValueValidator( lambda field: field is not None and field.count("\n") == 0, Problem.wrong, Severity.warning, message=_("please use only one line")) shortValue = CorrectFieldValueValidator( lambda field: field is not None and len(field) <= 80, Problem.wrong, Severity.warning, message=_("please stay under 80 characters"))
class Meta: name = N_('template') class fields(SymbolDef): """Symbols for each field that a TemplateUnit can have.""" template_unit = 'template-unit' template_resource = 'template-resource' template_filter = 'template-filter' template_imports = 'template-imports' validator_cls = TemplateUnitValidator field_validators = { fields.template_unit: [ concrete_validators.untranslatable, CorrectFieldValueValidator( lambda value, unit: (unit.get_record_value('template-unit') is not None), Problem.missing, Severity.advice, message=_("template should explicitly define instantiated" " unit type")), ], fields.template_resource: [ concrete_validators.untranslatable, concrete_validators.present, UnitReferenceValidator( lambda unit: ([unit.resource_id] if unit.resource_id else []), constraints=[ ReferenceConstraint( lambda referrer, referee: referee.unit == 'job', message=_("the referenced unit is not a job")), ReferenceConstraint( lambda referrer, referee: (referee.plugin == 'resource'), onlyif=lambda referrer, referee: (referee.unit == 'job'), message=_( "the referenced job is not a resource job")), ]), # TODO: should not refer to deprecated job, # onlyif job itself is not deprecated ], fields.template_filter: [ concrete_validators.untranslatable, # All templates need a valid (or empty) template filter CorrectFieldValueValidator( lambda value, unit: unit.get_filter_program(), onlyif=lambda unit: unit.template_filter is not None), # TODO: must refer to the same job as template-resource ], fields.template_imports: [ concrete_validators.untranslatable, CorrectFieldValueValidator(lambda value, unit: (list( unit.get_imported_jobs()) is not None)), CorrectFieldValueValidator( lambda value, unit: (len(list(unit.get_imported_jobs())) in (0, 1)), message=_("at most one import statement is allowed")), # TODO: must refer to known or possibly-known job # TODO: should not refer to deprecated jobs, # onlyif job itself is not deprecated ], }
class Meta: name = 'test plan' class fields(SymbolDef): """ Symbols for each field that a TestPlan can have """ name = 'name' description = 'description' include = 'include' mandatory_include = 'mandatory_include' bootstrap_include = 'bootstrap_include' exclude = 'exclude' nested_part = 'nested_part' estimated_duration = 'estimated_duration' icon = 'icon' category_overrides = 'category-overrides' field_validators = { fields.name: [ concrete_validators.translatable, concrete_validators.templateVariant, concrete_validators.present, concrete_validators.oneLine, concrete_validators.shortValue, ], fields.description: [ concrete_validators.translatable, concrete_validators.templateVariant, PresentFieldValidator( severity=Severity.advice, onlyif=lambda unit: unit.virtual is False), ], fields.include: [ NonEmptyPatternIntersectionValidator(), concrete_validators.present, ], fields.mandatory_include: [ NonEmptyPatternIntersectionValidator(), NoBaseIncludeValidator(), ], fields.bootstrap_include: [ concrete_validators.untranslatable, NoBaseIncludeValidator(), UnitReferenceValidator( lambda unit: unit.get_bootstrap_job_ids(), constraints=[ ReferenceConstraint( lambda referrer, referee: referee.unit == 'job', message=_("the referenced unit is not a job")), ReferenceConstraint( lambda referrer, referee: (referee.plugin in ['local', 'resource']), message=_("only local and resource jobs are " "allowed in bootstrapping_include")) ]) ], fields.exclude: [ NonEmptyPatternIntersectionValidator(), ], fields.nested_part: [ NonEmptyPatternIntersectionValidator(), ], fields.estimated_duration: [ concrete_validators.untranslatable, concrete_validators.templateInvariant, PresentFieldValidator( severity=Severity.advice, onlyif=lambda unit: unit.virtual is False), CorrectFieldValueValidator( lambda duration, unit: unit.estimated_duration > 0, message="value must be a positive number", onlyif=lambda unit: (unit.virtual is False and unit.get_record_value( 'estimated_duration'))), ], fields.icon: [ concrete_validators.untranslatable, ], fields.category_overrides: [ # optional # valid # referring to jobs correctly # referring to categories correctly ], }
""" from plainbox.i18n import gettext as _ from plainbox.impl.unit.validators import CorrectFieldValueValidator from plainbox.impl.validation import Problem from plainbox.impl.validation import Severity from plainbox.impl.unit.validators import PresentFieldValidator from plainbox.impl.unit.validators import TemplateInvariantFieldValidator from plainbox.impl.unit.validators import TemplateVariantFieldValidator from plainbox.impl.unit.validators import TranslatableFieldValidator from plainbox.impl.unit.validators import UntranslatableFieldValidator translatable = TranslatableFieldValidator() templateVariant = TemplateVariantFieldValidator() templateInvariant = TemplateInvariantFieldValidator() untranslatable = UntranslatableFieldValidator() present = PresentFieldValidator() oneLine = CorrectFieldValueValidator( lambda field: field is not None and field.count("\n") == 0, Problem.wrong, Severity.warning, message=_("please use only one line")) shortValue = CorrectFieldValueValidator( lambda field: field is not None and len(field) <= 80, Problem.wrong, Severity.warning, message=_("please stay under 80 characters"))
class Meta: name = N_('job') class fields(SymbolDef): """ Symbols for each field that a JobDefinition can have """ name = 'name' summary = 'summary' plugin = 'plugin' command = 'command' description = 'description' user = '******' environ = 'environ' estimated_duration = 'estimated_duration' depends = 'depends' after = 'after' salvages = 'salvages' requires = 'requires' shell = 'shell' imports = 'imports' flags = 'flags' category_id = 'category_id' purpose = 'purpose' steps = 'steps' verification = 'verification' certification_status = 'certification_status' siblings = 'siblings' auto_retry = 'auto_retry' field_validators = { fields.name: [ concrete_validators.untranslatable, concrete_validators.templateVariant, DeprecatedFieldValidator( _("use 'id' and 'summary' instead of 'name'")), ], # NOTE: 'id' validators are "inherited" so we don't have it here fields.summary: [ concrete_validators.translatable, concrete_validators.templateVariant, PresentFieldValidator(severity=Severity.advice), concrete_validators.oneLine, concrete_validators.shortValue, ], fields.plugin: [ concrete_validators.untranslatable, concrete_validators.templateInvariant, concrete_validators.present, MemberOfFieldValidator(_PluginValues.get_all_symbols()), CorrectFieldValueValidator( lambda plugin: plugin != 'user-verify', Problem.deprecated, Severity.advice, message=_("please migrate to user-interact-verify")), ], fields.command: [ concrete_validators.untranslatable, # All jobs except for manual must have a command PresentFieldValidator( message=_("command is mandatory for non-manual jobs"), onlyif=lambda unit: unit.plugin != 'manual'), # Manual jobs cannot have a command UselessFieldValidator( message=_("command on a manual job makes no sense"), onlyif=lambda unit: unit.plugin == 'manual'), # We don't want to refer to CHECKBOX_SHARE anymore CorrectFieldValueValidator( lambda command: "CHECKBOX_SHARE" not in command, Problem.deprecated, Severity.advice, message=_("please use PLAINBOX_PROVIDER_DATA" " instead of CHECKBOX_SHARE"), onlyif=lambda unit: unit.command is not None), # We don't want to refer to CHECKBOX_DATA anymore CorrectFieldValueValidator( lambda command: "CHECKBOX_DATA" not in command, Problem.deprecated, Severity.advice, message=_("please use PLAINBOX_SESSION_SHARE" " instead of CHECKBOX_DATA"), onlyif=lambda unit: unit.command is not None), # We want to catch silly mistakes that shlex can detect ShellProgramValidator(), ], fields.description: [ concrete_validators.translatable, concrete_validators.templateVariant, # Description is mandatory for manual jobs PresentFieldValidator( message=_("manual jobs must have a description field, or a" " set of purpose, steps, and verification " "fields"), onlyif=lambda unit: unit.plugin == 'manual' and unit. purpose is None and unit.steps is None and unit. verification is None), # Description or a set of purpose, steps and verification # fields is recommended for all other jobs ], fields.purpose: [ concrete_validators.translatable, ], fields.steps: [ concrete_validators.translatable, ], fields.verification: [ concrete_validators.translatable, ], fields.user: [ concrete_validators.untranslatable, concrete_validators.templateInvariant, # User should be either None or 'root' CorrectFieldValueValidator( message=_("user can only be 'root'"), correct_fn=lambda user: user in (None, 'root')), # User is useless without a command to run UselessFieldValidator( message=_("user without a command makes no sense"), onlyif=lambda unit: unit.command is None) ], fields.environ: [ concrete_validators.untranslatable, # Environ is useless without a command to run UselessFieldValidator( message=_("environ without a command makes no sense"), onlyif=lambda unit: unit.command is None), ], fields.estimated_duration: [ concrete_validators.untranslatable, concrete_validators.templateInvariant, CorrectFieldValueValidator( lambda duration: float(duration) > 0, message="value must be a positive number", onlyif=lambda unit: (unit.get_record_value('estimated_duration'))), ], fields.depends: [ concrete_validators.untranslatable, CorrectFieldValueValidator(lambda value, unit: ( unit.get_direct_dependencies() is not None)), UnitReferenceValidator( lambda unit: unit.get_direct_dependencies(), constraints=[ ReferenceConstraint( lambda referrer, referee: referee.unit == 'job', message=_("the referenced unit is not a job")) ]) # TODO: should not refer to deprecated jobs, # onlyif job itself is not deprecated ], fields.after: [ concrete_validators.untranslatable, CorrectFieldValueValidator(lambda value, unit: ( unit.get_after_dependencies() is not None)), UnitReferenceValidator( lambda unit: unit.get_after_dependencies(), constraints=[ ReferenceConstraint( lambda referrer, referee: referee.unit == 'job', message=_("the referenced unit is not a job")) ]) ], fields.requires: [ concrete_validators.untranslatable, CorrectFieldValueValidator( lambda value, unit: unit.get_resource_program(), onlyif=lambda unit: unit.requires is not None), UnitReferenceValidator( lambda unit: unit.get_resource_dependencies(), constraints=[ ReferenceConstraint( lambda referrer, referee: referee.unit == 'job', message=_("the referenced unit is not a job")), ReferenceConstraint( lambda referrer, referee: (referee.plugin == 'resource'), onlyif=lambda referrer, referee: (referee.unit == 'job'), message=_( "the referenced job is not a resource job")), ]), # TODO: should not refer to deprecated jobs, # onlyif job itself is not deprecated ], fields.shell: [ concrete_validators.untranslatable, concrete_validators.templateInvariant, # Shell should be only '/bin/sh', or None (which gives bash) MemberOfFieldValidator( ['/bin/sh', '/bin/bash', 'bash'], message=_("only /bin/sh and /bin/bash are allowed")), ], fields.imports: [ concrete_validators.untranslatable, concrete_validators.templateInvariant, CorrectFieldValueValidator(lambda value, unit: (list( unit.get_imported_jobs()) is not None)), UnitReferenceValidator( lambda unit: [ job_id for job_id, identifier in unit.get_imported_jobs() ], constraints=[ ReferenceConstraint( lambda referrer, referee: referee.unit == 'job', message=_("the referenced unit is not a job")) ]), # TODO: should not refer to deprecated jobs, # onlyif job itself is not deprecated ], fields.category_id: [ concrete_validators.untranslatable, concrete_validators.templateInvariant, UnitReferenceValidator( lambda unit: ([unit.get_category_id()] if unit.category_id else ()), constraints=[ ReferenceConstraint( lambda referrer, referee: (referee.unit == 'category'), message=_("the referenced unit is not a category")) ]), # TODO: should not refer to deprecated categories, # onlyif job itself is not deprecated ], fields.flags: [ concrete_validators.untranslatable, concrete_validators.templateInvariant, ], fields.certification_status: [ concrete_validators.untranslatable, concrete_validators.templateInvariant, MemberOfFieldValidator( _CertificationStatusValues.get_all_symbols()), ], fields.siblings: [ concrete_validators.translatable, CorrectFieldValueValidator( lambda value, unit: json.loads(value), Problem.syntax_error, Severity.error, onlyif=lambda unit: unit.siblings), CorrectFieldValueValidator( lambda value, unit: type(json.loads(value)) is list, Problem.syntax_error, Severity.error, onlyif=lambda unit: unit.siblings), CorrectFieldValueValidator(lambda value, unit: all( [type(s) is dict for s in json.loads(value)]), Problem.syntax_error, Severity.error, onlyif=lambda unit: unit.siblings), CorrectFieldValueValidator( lambda value, unit: all([ all([ hasattr(JobDefinition, k.lstrip('_')) for k in s.keys() ]) for s in json.loads(value) ]), Problem.bad_reference, Severity.error, message=_('unknown override job field'), onlyif=lambda unit: unit.siblings), ], fields.auto_retry: [ concrete_validators.untranslatable, concrete_validators.templateInvariant, MemberOfFieldValidator(_AutoRetryValues.get_all_symbols()), ], }
class Meta: name = 'test plan' class fields(SymbolDef): """ Symbols for each field that a TestPlan can have """ name = 'name' description = 'description' include = 'include' mandatory_include = 'mandatory_include' bootstrap_include = 'bootstrap_include' exclude = 'exclude' estimated_duration = 'estimated_duration' icon = 'icon' category_overrides = 'category-overrides' field_validators = { fields.name: [ TranslatableFieldValidator, TemplateVariantFieldValidator, PresentFieldValidator, # We want the summary to be a single line CorrectFieldValueValidator( lambda name: name.count("\n") == 0, Problem.wrong, Severity.warning, message=_("please use only one line"), onlyif=lambda unit: unit.name is not None), # We want the summary to be relatively short CorrectFieldValueValidator( lambda name: len(name) <= 80, Problem.wrong, Severity.warning, message=_("please stay under 80 characters"), onlyif=lambda unit: unit.name is not None), ], fields.description: [ TranslatableFieldValidator, TemplateVariantFieldValidator, PresentFieldValidator( severity=Severity.advice, onlyif=lambda unit: unit.virtual is False), ], fields.include: [ NonEmptyPatternIntersectionValidator, PresentFieldValidator(), ], fields.mandatory_include: [ NonEmptyPatternIntersectionValidator, NoBaseIncludeValidator, ], fields.bootstrap_include: [ UntranslatableFieldValidator, NoBaseIncludeValidator, UnitReferenceValidator( lambda unit: unit.get_bootstrap_job_ids(), constraints=[ ReferenceConstraint( lambda referrer, referee: referee.unit == 'job', message=_("the referenced unit is not a job")), ReferenceConstraint( lambda referrer, referee: (referee.plugin in ['local', 'resource']), message=_("only local and resource jobs are " "allowed in bootstrapping_include")) ]) ], fields.exclude: [ NonEmptyPatternIntersectionValidator, ], fields.estimated_duration: [ UntranslatableFieldValidator, TemplateInvariantFieldValidator, PresentFieldValidator( severity=Severity.advice, onlyif=lambda unit: unit.virtual is False), CorrectFieldValueValidator( lambda duration, unit: unit.estimated_duration > 0, message="value must be a positive number", onlyif=lambda unit: (unit.virtual is False and unit.get_record_value( 'estimated_duration'))), ], fields.icon: [ UntranslatableFieldValidator, ], fields.category_overrides: [ # optional # valid # referring to jobs correctly # referring to categories correctly ], }
class Meta: name = 'exporter' class fields(SymbolDef): """Symbols for each field that an Exporter can have.""" summary = 'summary' entry_point = 'entry_point' file_extension = 'file_extension' options = 'options' data = 'data' field_validators = { fields.summary: [ PresentFieldValidator(severity=Severity.advice), TranslatableFieldValidator, # We want the summary to be a single line CorrectFieldValueValidator( lambda summary: summary.count("\n") == 0, Problem.wrong, Severity.warning, message=_("please use only one line"), onlyif=lambda unit: unit.summary is not None), # We want the summary to be relatively short CorrectFieldValueValidator( lambda summary: len(summary) <= 80, Problem.wrong, Severity.warning, message=_("please stay under 80 characters"), onlyif=lambda unit: unit.summary is not None), ], fields.entry_point: [ PresentFieldValidator, UntranslatableFieldValidator, CorrectFieldValueValidator( lambda entry_point: pkg_resources.load_entry_point( 'plainbox', 'plainbox.exporter', entry_point), Problem.wrong, Severity.error), ], fields.file_extension: [ PresentFieldValidator, UntranslatableFieldValidator, CorrectFieldValueValidator( lambda extension: re.search("^[\w\.\-]+$", extension), Problem.syntax_error, Severity.error), ], fields.options: [ UntranslatableFieldValidator, ], fields.data: [ UntranslatableFieldValidator, CorrectFieldValueValidator( lambda value, unit: json.loads(value), Problem.syntax_error, Severity.error, onlyif=lambda unit: unit.data), CorrectFieldValueValidator( lambda value, unit: os.path.isfile( os.path.join(unit.provider.data_dir, json.loads(value)['template'])), Problem.wrong, Severity.error, message=_("Jinja2 template not found"), onlyif=lambda unit: unit.entry_point == 'jinja2'), ], }