mirror of
https://github.com/ansible/awx.git
synced 2026-01-09 23:12:08 -03:30
adding prompt-to-launch field on Labels field in Workflow Templates; with necessary UI and testing changes
Co-authored-by: Keith Grant <keithjgrant@gmail.com>
This commit is contained in:
parent
4e665ca77f
commit
663ef2cc64
@ -3199,7 +3199,7 @@ class JobRelaunchSerializer(BaseSerializer):
|
||||
return attrs
|
||||
|
||||
|
||||
class JobCreateScheduleSerializer(BaseSerializer):
|
||||
class JobCreateScheduleSerializer(LabelsListMixin, BaseSerializer):
|
||||
|
||||
can_schedule = serializers.SerializerMethodField()
|
||||
prompts = serializers.SerializerMethodField()
|
||||
@ -3230,6 +3230,8 @@ class JobCreateScheduleSerializer(BaseSerializer):
|
||||
if 'credentials' in ret:
|
||||
all_creds = [self._summarize('credential', cred) for cred in ret['credentials']]
|
||||
ret['credentials'] = all_creds
|
||||
if 'labels' in ret:
|
||||
ret['labels'] = self._summary_field_labels(obj)
|
||||
return ret
|
||||
except JobLaunchConfig.DoesNotExist:
|
||||
return {'all': _('Unknown, job may have been ran before launch configurations were saved.')}
|
||||
@ -3402,6 +3404,9 @@ class WorkflowJobTemplateSerializer(JobTemplateMixin, LabelsListMixin, UnifiedJo
|
||||
limit = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
||||
scm_branch = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
||||
|
||||
skip_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
||||
job_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
||||
|
||||
class Meta:
|
||||
model = WorkflowJobTemplate
|
||||
fields = (
|
||||
@ -3420,6 +3425,11 @@ class WorkflowJobTemplateSerializer(JobTemplateMixin, LabelsListMixin, UnifiedJo
|
||||
'webhook_service',
|
||||
'webhook_credential',
|
||||
'-execution_environment',
|
||||
'ask_labels_on_launch',
|
||||
'ask_skip_tags_on_launch',
|
||||
'ask_tags_on_launch',
|
||||
'skip_tags',
|
||||
'job_tags',
|
||||
)
|
||||
|
||||
def get_related(self, obj):
|
||||
@ -3458,12 +3468,13 @@ class WorkflowJobTemplateSerializer(JobTemplateMixin, LabelsListMixin, UnifiedJo
|
||||
def validate_extra_vars(self, value):
|
||||
return vars_validate_or_raise(value)
|
||||
|
||||
# posting
|
||||
def validate(self, attrs):
|
||||
attrs = super(WorkflowJobTemplateSerializer, self).validate(attrs)
|
||||
|
||||
# process char_prompts, these are not direct fields on the model
|
||||
mock_obj = self.Meta.model()
|
||||
for field_name in ('scm_branch', 'limit'):
|
||||
for field_name in ('scm_branch', 'limit', 'skip_tags', 'job_tags'):
|
||||
if field_name in attrs:
|
||||
setattr(mock_obj, field_name, attrs[field_name])
|
||||
attrs.pop(field_name)
|
||||
@ -3489,6 +3500,9 @@ class WorkflowJobSerializer(LabelsListMixin, UnifiedJobSerializer):
|
||||
limit = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
||||
scm_branch = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
||||
|
||||
skip_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
||||
job_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
||||
|
||||
class Meta:
|
||||
model = WorkflowJob
|
||||
fields = (
|
||||
@ -3508,6 +3522,8 @@ class WorkflowJobSerializer(LabelsListMixin, UnifiedJobSerializer):
|
||||
'webhook_service',
|
||||
'webhook_credential',
|
||||
'webhook_guid',
|
||||
'skip_tags',
|
||||
'job_tags',
|
||||
)
|
||||
|
||||
def get_related(self, obj):
|
||||
@ -4333,6 +4349,10 @@ class WorkflowJobLaunchSerializer(BaseSerializer):
|
||||
scm_branch = serializers.CharField(required=False, write_only=True, allow_blank=True)
|
||||
workflow_job_template_data = serializers.SerializerMethodField()
|
||||
|
||||
labels = serializers.PrimaryKeyRelatedField(many=True, queryset=Label.objects.all(), required=False, write_only=True)
|
||||
skip_tags = serializers.CharField(required=False, write_only=True, allow_blank=True)
|
||||
job_tags = serializers.CharField(required=False, write_only=True, allow_blank=True)
|
||||
|
||||
class Meta:
|
||||
model = WorkflowJobTemplate
|
||||
fields = (
|
||||
@ -4352,8 +4372,22 @@ class WorkflowJobLaunchSerializer(BaseSerializer):
|
||||
'workflow_job_template_data',
|
||||
'survey_enabled',
|
||||
'ask_variables_on_launch',
|
||||
'ask_labels_on_launch',
|
||||
'labels',
|
||||
'ask_skip_tags_on_launch',
|
||||
'ask_tags_on_launch',
|
||||
'skip_tags',
|
||||
'job_tags',
|
||||
)
|
||||
read_only_fields = (
|
||||
'ask_inventory_on_launch',
|
||||
'ask_variables_on_launch',
|
||||
'ask_skip_tags_on_launch',
|
||||
'ask_labels_on_launch',
|
||||
'ask_limit_on_launch',
|
||||
'ask_scm_branch_on_launch',
|
||||
'ask_tags_on_launch',
|
||||
)
|
||||
read_only_fields = ('ask_inventory_on_launch', 'ask_variables_on_launch')
|
||||
|
||||
def get_survey_enabled(self, obj):
|
||||
if obj:
|
||||
@ -4361,10 +4395,15 @@ class WorkflowJobLaunchSerializer(BaseSerializer):
|
||||
return False
|
||||
|
||||
def get_defaults(self, obj):
|
||||
|
||||
defaults_dict = {}
|
||||
for field_name in WorkflowJobTemplate.get_ask_mapping().keys():
|
||||
if field_name == 'inventory':
|
||||
defaults_dict[field_name] = dict(name=getattrd(obj, '%s.name' % field_name, None), id=getattrd(obj, '%s.pk' % field_name, None))
|
||||
elif field_name == 'labels':
|
||||
for label in obj.labels.all():
|
||||
label_dict = {"id": label.id, "name": label.name}
|
||||
defaults_dict.setdefault(field_name, []).append(label_dict)
|
||||
else:
|
||||
defaults_dict[field_name] = getattr(obj, field_name)
|
||||
return defaults_dict
|
||||
@ -4373,6 +4412,7 @@ class WorkflowJobLaunchSerializer(BaseSerializer):
|
||||
return dict(name=obj.name, id=obj.id, description=obj.description)
|
||||
|
||||
def validate(self, attrs):
|
||||
|
||||
template = self.instance
|
||||
|
||||
accepted, rejected, errors = template._accept_or_ignore_job_kwargs(**attrs)
|
||||
@ -4390,6 +4430,7 @@ class WorkflowJobLaunchSerializer(BaseSerializer):
|
||||
WFJT_inventory = template.inventory
|
||||
WFJT_limit = template.limit
|
||||
WFJT_scm_branch = template.scm_branch
|
||||
|
||||
super(WorkflowJobLaunchSerializer, self).validate(attrs)
|
||||
template.extra_vars = WFJT_extra_vars
|
||||
template.inventory = WFJT_inventory
|
||||
|
||||
@ -3197,13 +3197,17 @@ class WorkflowJobTemplateLaunch(RetrieveAPIView):
|
||||
data['extra_vars'] = extra_vars
|
||||
modified_ask_mapping = models.WorkflowJobTemplate.get_ask_mapping()
|
||||
modified_ask_mapping.pop('extra_vars')
|
||||
for field_name, ask_field_name in obj.get_ask_mapping().items():
|
||||
|
||||
for field, ask_field_name in modified_ask_mapping.items():
|
||||
if not getattr(obj, ask_field_name):
|
||||
data.pop(field_name, None)
|
||||
elif field_name == 'inventory':
|
||||
data[field_name] = getattrd(obj, "%s.%s" % (field_name, 'id'), None)
|
||||
data.pop(field, None)
|
||||
elif isinstance(getattr(obj.__class__, field).field, ForeignKey):
|
||||
data[field] = getattrd(obj, "%s.%s" % (field, 'id'), None)
|
||||
elif isinstance(getattr(obj.__class__, field).field, ManyToManyField):
|
||||
data[field] = [item.id for item in getattr(obj, field).all()]
|
||||
else:
|
||||
data[field_name] = getattr(obj, field_name)
|
||||
data[field] = getattr(obj, field)
|
||||
|
||||
return data
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
@ -107,4 +107,20 @@ class Migration(migrations.Migration):
|
||||
blank=True, editable=False, related_name='joblaunchconfigs', through='main.JobLaunchConfigInstanceGroupMembership', to='main.InstanceGroup'
|
||||
),
|
||||
),
|
||||
# added WFJT prompts
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplate',
|
||||
name='ask_labels_on_launch',
|
||||
field=awx.main.fields.AskForField(blank=True, default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplate',
|
||||
name='ask_skip_tags_on_launch',
|
||||
field=awx.main.fields.AskForField(blank=True, default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplate',
|
||||
name='ask_tags_on_launch',
|
||||
field=awx.main.fields.AskForField(blank=True, default=False),
|
||||
),
|
||||
]
|
||||
|
||||
@ -227,15 +227,6 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
|
||||
blank=True,
|
||||
default=False,
|
||||
)
|
||||
ask_limit_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
)
|
||||
ask_tags_on_launch = AskForField(blank=True, default=False, allows_field='job_tags')
|
||||
ask_skip_tags_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
)
|
||||
ask_job_type_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
@ -244,20 +235,11 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
|
||||
blank=True,
|
||||
default=False,
|
||||
)
|
||||
ask_inventory_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
)
|
||||
ask_credential_on_launch = AskForField(blank=True, default=False, allows_field='credentials')
|
||||
ask_scm_branch_on_launch = AskForField(blank=True, default=False, allows_field='scm_branch')
|
||||
ask_execution_environment_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
)
|
||||
ask_labels_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
)
|
||||
ask_forks_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
|
||||
@ -104,6 +104,33 @@ class SurveyJobTemplateMixin(models.Model):
|
||||
default=False,
|
||||
)
|
||||
survey_spec = prevent_search(JSONBlob(default=dict, blank=True))
|
||||
|
||||
ask_inventory_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
)
|
||||
ask_limit_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
)
|
||||
ask_scm_branch_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
allows_field='scm_branch',
|
||||
)
|
||||
ask_labels_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
)
|
||||
ask_tags_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
allows_field='job_tags',
|
||||
)
|
||||
ask_skip_tags_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
)
|
||||
ask_variables_on_launch = AskForField(blank=True, default=False, allows_field='extra_vars')
|
||||
|
||||
def survey_password_variables(self):
|
||||
|
||||
@ -422,6 +422,7 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique, ExecutionEn
|
||||
if unified_job.__class__ in activity_stream_registrar.models:
|
||||
activity_stream_create(None, unified_job, True)
|
||||
unified_job.log_lifecycle("created")
|
||||
|
||||
return unified_job
|
||||
|
||||
@classmethod
|
||||
|
||||
@ -29,7 +29,7 @@ from awx.main.models import prevent_search, accepts_json, UnifiedJobTemplate, Un
|
||||
from awx.main.models.notifications import NotificationTemplate, JobNotificationMixin
|
||||
from awx.main.models.base import CreatedModifiedModel, VarsDictProperty
|
||||
from awx.main.models.rbac import ROLE_SINGLETON_SYSTEM_ADMINISTRATOR, ROLE_SINGLETON_SYSTEM_AUDITOR
|
||||
from awx.main.fields import ImplicitRoleField, AskForField, JSONBlob
|
||||
from awx.main.fields import ImplicitRoleField, JSONBlob
|
||||
from awx.main.models.mixins import (
|
||||
ResourceMixin,
|
||||
SurveyJobTemplateMixin,
|
||||
@ -385,7 +385,7 @@ class WorkflowJobOptions(LaunchTimeConfigBase):
|
||||
@classmethod
|
||||
def _get_unified_job_field_names(cls):
|
||||
r = set(f.name for f in WorkflowJobOptions._meta.fields) | set(
|
||||
['name', 'description', 'organization', 'survey_passwords', 'labels', 'limit', 'scm_branch']
|
||||
['name', 'description', 'organization', 'survey_passwords', 'labels', 'limit', 'scm_branch', 'job_tags', 'skip_tags']
|
||||
)
|
||||
r.remove('char_prompts') # needed due to copying launch config to launch config
|
||||
return r
|
||||
@ -425,26 +425,28 @@ class WorkflowJobOptions(LaunchTimeConfigBase):
|
||||
class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, SurveyJobTemplateMixin, ResourceMixin, RelatedJobsMixin, WebhookTemplateMixin):
|
||||
|
||||
SOFT_UNIQUE_TOGETHER = [('polymorphic_ctype', 'name', 'organization')]
|
||||
FIELDS_TO_PRESERVE_AT_COPY = ['labels', 'organization', 'instance_groups', 'workflow_job_template_nodes', 'credentials', 'survey_spec']
|
||||
FIELDS_TO_PRESERVE_AT_COPY = [
|
||||
'labels',
|
||||
'organization',
|
||||
'instance_groups',
|
||||
'workflow_job_template_nodes',
|
||||
'credentials',
|
||||
'survey_spec',
|
||||
'skip_tags',
|
||||
'job_tags',
|
||||
]
|
||||
|
||||
class Meta:
|
||||
app_label = 'main'
|
||||
|
||||
ask_inventory_on_launch = AskForField(
|
||||
notification_templates_approvals = models.ManyToManyField(
|
||||
"NotificationTemplate",
|
||||
blank=True,
|
||||
default=False,
|
||||
related_name='%(class)s_notification_templates_for_approvals',
|
||||
)
|
||||
ask_limit_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
admin_role = ImplicitRoleField(
|
||||
parent_role=['singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR, 'organization.workflow_admin_role'],
|
||||
)
|
||||
ask_scm_branch_on_launch = AskForField(
|
||||
blank=True,
|
||||
default=False,
|
||||
)
|
||||
notification_templates_approvals = models.ManyToManyField("NotificationTemplate", blank=True, related_name='%(class)s_notification_templates_for_approvals')
|
||||
|
||||
admin_role = ImplicitRoleField(parent_role=['singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR, 'organization.workflow_admin_role'])
|
||||
execute_role = ImplicitRoleField(
|
||||
parent_role=[
|
||||
'admin_role',
|
||||
|
||||
@ -210,7 +210,7 @@ def mk_workflow_job_template(name, extra_vars='', spec=None, organization=None,
|
||||
if extra_vars:
|
||||
extra_vars = json.dumps(extra_vars)
|
||||
|
||||
wfjt = WorkflowJobTemplate(name=name, extra_vars=extra_vars, organization=organization, webhook_service=webhook_service)
|
||||
wfjt = WorkflowJobTemplate.objects.create(name=name, extra_vars=extra_vars, organization=organization, webhook_service=webhook_service)
|
||||
|
||||
if spec:
|
||||
wfjt.survey_spec = spec
|
||||
|
||||
@ -706,7 +706,7 @@ def jt_linked(organization, project, inventory, machine_credential, credential,
|
||||
|
||||
@pytest.fixture
|
||||
def workflow_job_template(organization):
|
||||
wjt = WorkflowJobTemplate(name='test-workflow_job_template', organization=organization)
|
||||
wjt = WorkflowJobTemplate.objects.create(name='test-workflow_job_template', organization=organization)
|
||||
wjt.save()
|
||||
|
||||
return wjt
|
||||
|
||||
@ -287,12 +287,25 @@ class TestWorkflowJobTemplatePrompts:
|
||||
@pytest.fixture
|
||||
def wfjt_prompts(self):
|
||||
return WorkflowJobTemplate.objects.create(
|
||||
ask_inventory_on_launch=True, ask_variables_on_launch=True, ask_limit_on_launch=True, ask_scm_branch_on_launch=True
|
||||
ask_variables_on_launch=True,
|
||||
ask_inventory_on_launch=True,
|
||||
ask_tags_on_launch=True,
|
||||
ask_labels_on_launch=True,
|
||||
ask_limit_on_launch=True,
|
||||
ask_scm_branch_on_launch=True,
|
||||
ask_skip_tags_on_launch=True,
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
def prompts_data(self, inventory):
|
||||
return dict(inventory=inventory, extra_vars={'foo': 'bar'}, limit='webservers', scm_branch='release-3.3')
|
||||
return dict(
|
||||
inventory=inventory,
|
||||
extra_vars={'foo': 'bar'},
|
||||
limit='webservers',
|
||||
scm_branch='release-3.3',
|
||||
job_tags='foo',
|
||||
skip_tags='bar',
|
||||
)
|
||||
|
||||
def test_apply_workflow_job_prompts(self, workflow_job_template, wfjt_prompts, prompts_data, inventory):
|
||||
# null or empty fields used
|
||||
@ -300,6 +313,9 @@ class TestWorkflowJobTemplatePrompts:
|
||||
assert workflow_job.limit is None
|
||||
assert workflow_job.inventory is None
|
||||
assert workflow_job.scm_branch is None
|
||||
assert workflow_job.job_tags is None
|
||||
assert workflow_job.skip_tags is None
|
||||
assert len(workflow_job.labels.all()) is 0
|
||||
|
||||
# fields from prompts used
|
||||
workflow_job = workflow_job_template.create_unified_job(**prompts_data)
|
||||
@ -307,15 +323,21 @@ class TestWorkflowJobTemplatePrompts:
|
||||
assert workflow_job.limit == 'webservers'
|
||||
assert workflow_job.inventory == inventory
|
||||
assert workflow_job.scm_branch == 'release-3.3'
|
||||
assert workflow_job.job_tags == 'foo'
|
||||
assert workflow_job.skip_tags == 'bar'
|
||||
|
||||
# non-null fields from WFJT used
|
||||
workflow_job_template.inventory = inventory
|
||||
workflow_job_template.limit = 'fooo'
|
||||
workflow_job_template.scm_branch = 'bar'
|
||||
workflow_job_template.job_tags = 'baz'
|
||||
workflow_job_template.skip_tags = 'dinosaur'
|
||||
workflow_job = workflow_job_template.create_unified_job()
|
||||
assert workflow_job.limit == 'fooo'
|
||||
assert workflow_job.inventory == inventory
|
||||
assert workflow_job.scm_branch == 'bar'
|
||||
assert workflow_job.job_tags == 'baz'
|
||||
assert workflow_job.skip_tags == 'dinosaur'
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_process_workflow_job_prompts(self, inventory, workflow_job_template, wfjt_prompts, prompts_data):
|
||||
@ -340,12 +362,19 @@ class TestWorkflowJobTemplatePrompts:
|
||||
ask_limit_on_launch=True,
|
||||
scm_branch='bar',
|
||||
ask_scm_branch_on_launch=True,
|
||||
job_tags='foo',
|
||||
skip_tags='bar',
|
||||
),
|
||||
user=org_admin,
|
||||
expect=201,
|
||||
)
|
||||
wfjt = WorkflowJobTemplate.objects.get(id=r.data['id'])
|
||||
assert wfjt.char_prompts == {'limit': 'foooo', 'scm_branch': 'bar'}
|
||||
assert wfjt.char_prompts == {
|
||||
'limit': 'foooo',
|
||||
'scm_branch': 'bar',
|
||||
'job_tags': 'foo',
|
||||
'skip_tags': 'bar',
|
||||
}
|
||||
assert wfjt.ask_scm_branch_on_launch is True
|
||||
assert wfjt.ask_limit_on_launch is True
|
||||
|
||||
@ -355,6 +384,67 @@ class TestWorkflowJobTemplatePrompts:
|
||||
assert r.data['limit'] == 'prompt_limit'
|
||||
assert r.data['scm_branch'] == 'prompt_branch'
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_set_all_ask_for_prompts_false_from_post(self, post, organization, inventory, org_admin):
|
||||
'''
|
||||
Tests default behaviour and values of ask_for_* fields on WFJT via POST
|
||||
'''
|
||||
r = post(
|
||||
url=reverse('api:workflow_job_template_list'),
|
||||
data=dict(
|
||||
name='workflow that tests ask_for prompts',
|
||||
organization=organization.id,
|
||||
inventory=inventory.id,
|
||||
job_tags='',
|
||||
skip_tags='',
|
||||
),
|
||||
user=org_admin,
|
||||
expect=201,
|
||||
)
|
||||
wfjt = WorkflowJobTemplate.objects.get(id=r.data['id'])
|
||||
|
||||
assert wfjt.ask_inventory_on_launch is False
|
||||
assert wfjt.ask_labels_on_launch is False
|
||||
assert wfjt.ask_limit_on_launch is False
|
||||
assert wfjt.ask_scm_branch_on_launch is False
|
||||
assert wfjt.ask_skip_tags_on_launch is False
|
||||
assert wfjt.ask_tags_on_launch is False
|
||||
assert wfjt.ask_variables_on_launch is False
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_set_all_ask_for_prompts_true_from_post(self, post, organization, inventory, org_admin):
|
||||
'''
|
||||
Tests behaviour and values of ask_for_* fields on WFJT via POST
|
||||
'''
|
||||
r = post(
|
||||
url=reverse('api:workflow_job_template_list'),
|
||||
data=dict(
|
||||
name='workflow that tests ask_for prompts',
|
||||
organization=organization.id,
|
||||
inventory=inventory.id,
|
||||
job_tags='',
|
||||
skip_tags='',
|
||||
ask_inventory_on_launch=True,
|
||||
ask_labels_on_launch=True,
|
||||
ask_limit_on_launch=True,
|
||||
ask_scm_branch_on_launch=True,
|
||||
ask_skip_tags_on_launch=True,
|
||||
ask_tags_on_launch=True,
|
||||
ask_variables_on_launch=True,
|
||||
),
|
||||
user=org_admin,
|
||||
expect=201,
|
||||
)
|
||||
wfjt = WorkflowJobTemplate.objects.get(id=r.data['id'])
|
||||
|
||||
assert wfjt.ask_inventory_on_launch is True
|
||||
assert wfjt.ask_labels_on_launch is True
|
||||
assert wfjt.ask_limit_on_launch is True
|
||||
assert wfjt.ask_scm_branch_on_launch is True
|
||||
assert wfjt.ask_skip_tags_on_launch is True
|
||||
assert wfjt.ask_tags_on_launch is True
|
||||
assert wfjt.ask_variables_on_launch is True
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_workflow_ancestors(organization):
|
||||
|
||||
@ -11,6 +11,7 @@ from awx.api.serializers import (
|
||||
from awx.main.models import Job, WorkflowJobTemplateNode, WorkflowJob, WorkflowJobNode, WorkflowJobTemplate, Project, Inventory, JobTemplate
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@mock.patch('awx.api.serializers.UnifiedJobTemplateSerializer.get_related', lambda x, y: {})
|
||||
class TestWorkflowJobTemplateSerializerGetRelated:
|
||||
@pytest.fixture
|
||||
@ -58,6 +59,7 @@ class TestWorkflowNodeBaseSerializerGetRelated:
|
||||
assert 'unified_job_template' not in related
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@mock.patch('awx.api.serializers.BaseSerializer.get_related', lambda x, y: {})
|
||||
class TestWorkflowJobTemplateNodeSerializerGetRelated:
|
||||
@pytest.fixture
|
||||
@ -146,6 +148,7 @@ class TestWorkflowJobTemplateNodeSerializerCharPrompts:
|
||||
assert WFJT_serializer.instance.limit == 'webservers'
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@mock.patch('awx.api.serializers.BaseSerializer.validate', lambda self, attrs: attrs)
|
||||
class TestWorkflowJobTemplateNodeSerializerSurveyPasswords:
|
||||
@pytest.fixture
|
||||
@ -162,7 +165,7 @@ class TestWorkflowJobTemplateNodeSerializerSurveyPasswords:
|
||||
|
||||
def test_set_survey_passwords_create(self, jt):
|
||||
serializer = WorkflowJobTemplateNodeSerializer()
|
||||
wfjt = WorkflowJobTemplate(name='fake-wfjt')
|
||||
wfjt = WorkflowJobTemplate.objects.create(name='fake-wfjt')
|
||||
attrs = serializer.validate({'unified_job_template': jt, 'workflow_job_template': wfjt, 'extra_data': {'var1': 'secret_answer'}})
|
||||
assert 'survey_passwords' in attrs
|
||||
assert 'var1' in attrs['survey_passwords']
|
||||
@ -171,7 +174,7 @@ class TestWorkflowJobTemplateNodeSerializerSurveyPasswords:
|
||||
|
||||
def test_set_survey_passwords_modify(self, jt):
|
||||
serializer = WorkflowJobTemplateNodeSerializer()
|
||||
wfjt = WorkflowJobTemplate(name='fake-wfjt')
|
||||
wfjt = WorkflowJobTemplate.objects.create(name='fake-wfjt')
|
||||
serializer.instance = WorkflowJobTemplateNode(workflow_job_template=wfjt, unified_job_template=jt)
|
||||
attrs = serializer.validate({'unified_job_template': jt, 'workflow_job_template': wfjt, 'extra_data': {'var1': 'secret_answer'}})
|
||||
assert 'survey_passwords' in attrs
|
||||
@ -181,7 +184,7 @@ class TestWorkflowJobTemplateNodeSerializerSurveyPasswords:
|
||||
|
||||
def test_use_db_answer(self, jt, mocker):
|
||||
serializer = WorkflowJobTemplateNodeSerializer()
|
||||
wfjt = WorkflowJobTemplate(name='fake-wfjt')
|
||||
wfjt = WorkflowJobTemplate.objects.create(name='fake-wfjt')
|
||||
serializer.instance = WorkflowJobTemplateNode(workflow_job_template=wfjt, unified_job_template=jt, extra_data={'var1': '$encrypted$foooooo'})
|
||||
with mocker.patch('awx.main.models.mixins.decrypt_value', return_value='foo'):
|
||||
attrs = serializer.validate({'unified_job_template': jt, 'workflow_job_template': wfjt, 'extra_data': {'var1': '$encrypted$'}})
|
||||
@ -196,7 +199,7 @@ class TestWorkflowJobTemplateNodeSerializerSurveyPasswords:
|
||||
with that particular var omitted so on launch time the default takes effect
|
||||
"""
|
||||
serializer = WorkflowJobTemplateNodeSerializer()
|
||||
wfjt = WorkflowJobTemplate(name='fake-wfjt')
|
||||
wfjt = WorkflowJobTemplate.objects.create(name='fake-wfjt')
|
||||
jt.survey_spec['spec'][0]['default'] = '$encrypted$bar'
|
||||
attrs = serializer.validate({'unified_job_template': jt, 'workflow_job_template': wfjt, 'extra_data': {'var1': '$encrypted$'}})
|
||||
assert 'survey_passwords' in attrs
|
||||
|
||||
@ -259,13 +259,14 @@ def test_survey_encryption_defaults(survey_spec_factory, question_type, default,
|
||||
|
||||
|
||||
@pytest.mark.survey
|
||||
@pytest.mark.django_db
|
||||
class TestWorkflowSurveys:
|
||||
def test_update_kwargs_survey_defaults(self, survey_spec_factory):
|
||||
"Assure that the survey default over-rides a JT variable"
|
||||
spec = survey_spec_factory('var1')
|
||||
spec['spec'][0]['default'] = 3
|
||||
spec['spec'][0]['required'] = False
|
||||
wfjt = WorkflowJobTemplate(name="test-wfjt", survey_spec=spec, survey_enabled=True, extra_vars="var1: 5")
|
||||
wfjt = WorkflowJobTemplate.objects.create(name="test-wfjt", survey_spec=spec, survey_enabled=True, extra_vars="var1: 5")
|
||||
updated_extra_vars = wfjt._update_unified_job_kwargs({}, {})
|
||||
assert 'extra_vars' in updated_extra_vars
|
||||
assert json.loads(updated_extra_vars['extra_vars'])['var1'] == 3
|
||||
@ -277,7 +278,7 @@ class TestWorkflowSurveys:
|
||||
spec['spec'][0]['required'] = False
|
||||
spec['spec'][1]['required'] = True
|
||||
spec['spec'][2]['required'] = False
|
||||
wfjt = WorkflowJobTemplate(name="test-wfjt", survey_spec=spec, survey_enabled=True, extra_vars="question2: hiworld")
|
||||
wfjt = WorkflowJobTemplate.objects.create(name="test-wfjt", survey_spec=spec, survey_enabled=True, extra_vars="question2: hiworld")
|
||||
assert wfjt.variables_needed_to_start == ['question2']
|
||||
assert not wfjt.can_start_without_user_input()
|
||||
|
||||
@ -311,6 +312,6 @@ class TestExtraVarsNoPrompt:
|
||||
self.process_vars_and_assert(jt, provided_vars, valid)
|
||||
|
||||
def test_wfjt_extra_vars_counting(self, provided_vars, valid):
|
||||
wfjt = WorkflowJobTemplate(name='foo', extra_vars={'tmpl_var': 'bar'})
|
||||
wfjt = WorkflowJobTemplate.objects.create(name='foo', extra_vars={'tmpl_var': 'bar'})
|
||||
prompted_fields, ignored_fields, errors = wfjt._accept_or_ignore_job_kwargs(extra_vars=provided_vars)
|
||||
self.process_vars_and_assert(wfjt, provided_vars, valid)
|
||||
|
||||
@ -94,7 +94,7 @@ def workflow_job_unit():
|
||||
|
||||
@pytest.fixture
|
||||
def workflow_job_template_unit():
|
||||
return WorkflowJobTemplate(name='workflow')
|
||||
return WorkflowJobTemplate.objects.create(name='workflow')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@ -151,6 +151,7 @@ def test_node_getter_and_setters():
|
||||
assert node.job_type == 'check'
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestWorkflowJobCreate:
|
||||
def test_create_no_prompts(self, wfjt_node_no_prompts, workflow_job_unit, mocker):
|
||||
mock_create = mocker.MagicMock()
|
||||
@ -183,6 +184,7 @@ class TestWorkflowJobCreate:
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@mock.patch('awx.main.models.workflow.WorkflowNodeBase.get_parent_nodes', lambda self: [])
|
||||
class TestWorkflowJobNodeJobKWARGS:
|
||||
"""
|
||||
@ -231,4 +233,12 @@ class TestWorkflowJobNodeJobKWARGS:
|
||||
|
||||
|
||||
def test_get_ask_mapping_integrity():
|
||||
assert list(WorkflowJobTemplate.get_ask_mapping().keys()) == ['extra_vars', 'inventory', 'limit', 'scm_branch']
|
||||
assert list(WorkflowJobTemplate.get_ask_mapping().keys()) == [
|
||||
'inventory',
|
||||
'limit',
|
||||
'scm_branch',
|
||||
'labels',
|
||||
'job_tags',
|
||||
'skip_tags',
|
||||
'extra_vars',
|
||||
]
|
||||
|
||||
@ -196,6 +196,7 @@ def test_jt_can_add_bad_data(user_unit):
|
||||
assert not access.can_add({'asdf': 'asdf'})
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestWorkflowAccessMethods:
|
||||
@pytest.fixture
|
||||
def workflow(self, workflow_job_template_factory):
|
||||
|
||||
@ -16,8 +16,12 @@ import CredentialsStep from './steps/CredentialsStep';
|
||||
import CredentialPasswordsStep from './steps/CredentialPasswordsStep';
|
||||
import OtherPromptsStep from './steps/OtherPromptsStep';
|
||||
import PreviewStep from './steps/PreviewStep';
|
||||
import executionEnvironmentHelpTextStrings from 'screens/ExecutionEnvironment/shared/ExecutionEnvironment.helptext';
|
||||
import { ExecutionEnvironment } from 'types';
|
||||
import ExecutionEnvironmentStep from './steps/ExecutionEnvironmentStep';
|
||||
|
||||
jest.mock('../../api/models/Inventories');
|
||||
jest.mock('../../api/models/ExecutionEnvironments');
|
||||
jest.mock('../../api/models/CredentialTypes');
|
||||
jest.mock('../../api/models/Credentials');
|
||||
jest.mock('../../api/models/JobTemplates');
|
||||
@ -150,13 +154,14 @@ describe('LaunchPrompt', () => {
|
||||
const wizard = await waitForElement(wrapper, 'Wizard');
|
||||
const steps = wizard.prop('steps');
|
||||
|
||||
expect(steps).toHaveLength(6);
|
||||
expect(steps).toHaveLength(7);
|
||||
expect(steps[0].name.props.children).toEqual('Inventory');
|
||||
expect(steps[1].name.props.children).toEqual('Credentials');
|
||||
expect(steps[2].name.props.children).toEqual('Credential passwords');
|
||||
expect(steps[3].name.props.children).toEqual('Other prompts');
|
||||
expect(steps[4].name.props.children).toEqual('Survey');
|
||||
expect(steps[5].name.props.children).toEqual('Preview');
|
||||
expect(steps[3].name.props.children).toEqual('Execution Environment');
|
||||
expect(steps[4].name.props.children).toEqual('Other prompts');
|
||||
expect(steps[5].name.props.children).toEqual('Survey');
|
||||
expect(steps[6].name.props.children).toEqual('Preview');
|
||||
expect(wizard.find('WizardHeader').prop('title')).toBe('Launch | Foobar');
|
||||
expect(wizard.find('WizardHeader').prop('description')).toBe(
|
||||
'Foo Description'
|
||||
|
||||
@ -22,12 +22,18 @@ const jobTemplateData = {
|
||||
allow_simultaneous: false,
|
||||
ask_credential_on_launch: false,
|
||||
ask_diff_mode_on_launch: false,
|
||||
ask_execution_environment_on_launch: false,
|
||||
ask_forks_on_launch: false,
|
||||
ask_instance_groups_on_launch: false,
|
||||
ask_inventory_on_launch: false,
|
||||
ask_job_slice_count_on_launch: false,
|
||||
ask_job_type_on_launch: false,
|
||||
ask_labels_on_launch: false,
|
||||
ask_limit_on_launch: false,
|
||||
ask_scm_branch_on_launch: false,
|
||||
ask_skip_tags_on_launch: false,
|
||||
ask_tags_on_launch: false,
|
||||
ask_timeout_on_launch: false,
|
||||
ask_variables_on_launch: false,
|
||||
ask_verbosity_on_launch: false,
|
||||
ask_execution_environment_on_launch: false,
|
||||
|
||||
@ -35,13 +35,18 @@ const mockJobTemplate = {
|
||||
allow_simultaneous: false,
|
||||
ask_scm_branch_on_launch: false,
|
||||
ask_diff_mode_on_launch: false,
|
||||
ask_execution_environment_on_launch: false,
|
||||
ask_forks_on_launch: false,
|
||||
ask_instance_groups_on_launch: false,
|
||||
ask_variables_on_launch: false,
|
||||
ask_limit_on_launch: false,
|
||||
ask_tags_on_launch: false,
|
||||
ask_skip_tags_on_launch: false,
|
||||
ask_job_type_on_launch: false,
|
||||
ask_labels_on_launch: false,
|
||||
ask_verbosity_on_launch: false,
|
||||
ask_inventory_on_launch: false,
|
||||
ask_job_slice_count_on_launch: false,
|
||||
ask_credential_on_launch: false,
|
||||
ask_execution_environment_on_launch: false,
|
||||
ask_forks_on_launch: false,
|
||||
|
||||
@ -82,7 +82,7 @@ describe('<WorkflowJobTemplateAdd/>', () => {
|
||||
test('calls workflowJobTemplatesAPI with correct information on submit', async () => {
|
||||
await act(async () => {
|
||||
wrapper.find('input#wfjt-name').simulate('change', {
|
||||
target: { value: 'Alex', name: 'name' },
|
||||
target: { value: 'Alex Singh', name: 'name' },
|
||||
});
|
||||
|
||||
wrapper.find('LabelSelect').find('SelectToggle').simulate('click');
|
||||
@ -104,18 +104,23 @@ describe('<WorkflowJobTemplateAdd/>', () => {
|
||||
wrapper.find('form').simulate('submit');
|
||||
});
|
||||
await expect(WorkflowJobTemplatesAPI.create).toHaveBeenCalledWith({
|
||||
name: 'Alex',
|
||||
name: 'Alex Singh',
|
||||
allow_simultaneous: false,
|
||||
ask_inventory_on_launch: false,
|
||||
ask_labels_on_launch: false,
|
||||
ask_limit_on_launch: false,
|
||||
ask_scm_branch_on_launch: false,
|
||||
ask_skip_tags_on_launch: false,
|
||||
ask_tags_on_launch: false,
|
||||
ask_variables_on_launch: false,
|
||||
description: '',
|
||||
extra_vars: '---',
|
||||
inventory: undefined,
|
||||
job_tags: '',
|
||||
limit: null,
|
||||
organization: undefined,
|
||||
scm_branch: '',
|
||||
skip_tags: '',
|
||||
webhook_credential: undefined,
|
||||
webhook_service: '',
|
||||
webhook_url: '',
|
||||
|
||||
@ -161,6 +161,7 @@ describe('<WorkflowJobTemplateEdit/>', () => {
|
||||
expect(WorkflowJobTemplatesAPI.update).toHaveBeenCalledWith(6, {
|
||||
name: 'Alex',
|
||||
description: 'Apollo and Athena',
|
||||
skip_tags: '',
|
||||
inventory: 1,
|
||||
organization: 1,
|
||||
scm_branch: 'main',
|
||||
@ -174,6 +175,11 @@ describe('<WorkflowJobTemplateEdit/>', () => {
|
||||
ask_limit_on_launch: false,
|
||||
ask_scm_branch_on_launch: false,
|
||||
ask_variables_on_launch: false,
|
||||
ask_labels_on_launch: false,
|
||||
ask_skip_tags_on_launch: false,
|
||||
ask_tags_on_launch: false,
|
||||
job_tags: '',
|
||||
skip_tags: '',
|
||||
});
|
||||
wrapper.update();
|
||||
await expect(WorkflowJobTemplatesAPI.disassociateLabel).toBeCalledWith(6, {
|
||||
@ -273,16 +279,21 @@ describe('<WorkflowJobTemplateEdit/>', () => {
|
||||
expect(WorkflowJobTemplatesAPI.update).toBeCalledWith(6, {
|
||||
allow_simultaneous: false,
|
||||
ask_inventory_on_launch: false,
|
||||
ask_labels_on_launch: false,
|
||||
ask_limit_on_launch: false,
|
||||
ask_scm_branch_on_launch: false,
|
||||
ask_skip_tags_on_launch: false,
|
||||
ask_tags_on_launch: false,
|
||||
ask_variables_on_launch: false,
|
||||
description: 'bar',
|
||||
extra_vars: '---',
|
||||
inventory: 1,
|
||||
job_tags: '',
|
||||
limit: '5000',
|
||||
name: 'Foo',
|
||||
organization: 1,
|
||||
scm_branch: 'devel',
|
||||
skip_tags: '',
|
||||
webhook_credential: null,
|
||||
webhook_service: '',
|
||||
webhook_url: '',
|
||||
|
||||
@ -18,6 +18,7 @@ const wfHelpTextStrings = () => ({
|
||||
webhookKey: t`Webhook services can use this as a shared secret.`,
|
||||
webhookCredential: t`Optionally select the credential to use to send status updates back to the webhook service.`,
|
||||
webhookService: t`Select a webhook service.`,
|
||||
skipTags: t`Skip tags are useful when you have a large playbook, and you want to skip specific parts of a play or task. Use commas to separate multiple tags. Refer to the documentation for details on the usage of tags.`,
|
||||
enabledOptions: (
|
||||
<>
|
||||
<p>{t`Concurrent jobs: If enabled, simultaneous runs of this workflow job template will be allowed.`}</p>
|
||||
|
||||
@ -27,6 +27,7 @@ import CheckboxField from 'components/FormField/CheckboxField';
|
||||
import Popover from 'components/Popover';
|
||||
import { WorkFlowJobTemplate } from 'types';
|
||||
import LabelSelect from 'components/LabelSelect';
|
||||
import { TagMultiSelect } from 'components/MultiSelect';
|
||||
import WebhookSubForm from './WebhookSubForm';
|
||||
import getHelpText from './WorkflowJobTemplate.helptext';
|
||||
|
||||
@ -59,6 +60,8 @@ function WorkflowJobTemplateForm({
|
||||
const [, webhookKeyMeta, webhookKeyHelpers] = useField('webhook_key');
|
||||
const [, webhookCredentialMeta, webhookCredentialHelpers] =
|
||||
useField('webhook_credential');
|
||||
const [skipTagsField, , skipTagsHelpers] = useField('skip_tags');
|
||||
const [jobTagsField, , jobTagsHelpers] = useField('job_tags');
|
||||
|
||||
useEffect(() => {
|
||||
if (enableWebhooks) {
|
||||
@ -167,7 +170,6 @@ function WorkflowJobTemplateForm({
|
||||
}}
|
||||
/>
|
||||
</FieldWithPrompt>
|
||||
|
||||
<FieldWithPrompt
|
||||
fieldId="wfjt-scm-branch"
|
||||
label={t`Source control branch`}
|
||||
@ -184,14 +186,11 @@ function WorkflowJobTemplateForm({
|
||||
aria-label={t`source control branch`}
|
||||
/>
|
||||
</FieldWithPrompt>
|
||||
</FormColumnLayout>
|
||||
<FormFullWidthLayout>
|
||||
<FieldWithPrompt
|
||||
fieldId="template-labels"
|
||||
label={t`Labels`}
|
||||
fieldId="template-labels"
|
||||
promptId="template-ask-labels-on-launch"
|
||||
promptName="ask_labels_on_launch"
|
||||
tooltip={helpText.labels}
|
||||
>
|
||||
<LabelSelect
|
||||
value={labelsField.value}
|
||||
@ -200,16 +199,42 @@ function WorkflowJobTemplateForm({
|
||||
createText={t`Create`}
|
||||
/>
|
||||
</FieldWithPrompt>
|
||||
</FormFullWidthLayout>
|
||||
<FormFullWidthLayout>
|
||||
<VariablesField
|
||||
id="wfjt-variables"
|
||||
name="extra_vars"
|
||||
label={t`Variables`}
|
||||
promptId="template-ask-variables-on-launch"
|
||||
tooltip={helpText.variables}
|
||||
/>
|
||||
</FormFullWidthLayout>
|
||||
<FormFullWidthLayout>
|
||||
<VariablesField
|
||||
id="wfjt-variables"
|
||||
name="extra_vars"
|
||||
label={t`Variables`}
|
||||
promptId="template-ask-variables-on-launch"
|
||||
tooltip={helpText.variables}
|
||||
/>
|
||||
</FormFullWidthLayout>
|
||||
<FormColumnLayout>
|
||||
<FieldWithPrompt
|
||||
fieldId="template-tags"
|
||||
label={t`Job Tags`}
|
||||
promptId="template-ask-tags-on-launch"
|
||||
promptName="ask_tags_on_launch"
|
||||
tooltip={helpText.jobTags}
|
||||
>
|
||||
<TagMultiSelect
|
||||
value={jobTagsField.value}
|
||||
onChange={(value) => jobTagsHelpers.setValue(value)}
|
||||
/>
|
||||
</FieldWithPrompt>
|
||||
</FormColumnLayout>
|
||||
<FieldWithPrompt
|
||||
fieldId="template-skip-tags"
|
||||
label={t`Skip Tags`}
|
||||
promptId="template-ask-skip-tags-on-launch"
|
||||
promptName="ask_skip_tags_on_launch"
|
||||
tooltip={helpText.skipTags}
|
||||
>
|
||||
<TagMultiSelect
|
||||
value={skipTagsField.value}
|
||||
onChange={(value) => skipTagsHelpers.setValue(value)}
|
||||
/>
|
||||
</FieldWithPrompt>
|
||||
</FormColumnLayout>
|
||||
<FormGroup fieldId="options" label={t`Options`}>
|
||||
<FormCheckboxLayout isInline>
|
||||
<Checkbox
|
||||
@ -282,6 +307,8 @@ const FormikApp = withFormik({
|
||||
extra_vars: template.extra_vars || '---',
|
||||
limit: template.limit || '',
|
||||
scm_branch: template.scm_branch || '',
|
||||
skip_tags: template.skip_tags || '',
|
||||
job_tags: template.job_tags || '',
|
||||
allow_simultaneous: template.allow_simultaneous || false,
|
||||
webhook_credential: template?.summary_fields?.webhook_credential || null,
|
||||
webhook_service: template.webhook_service || '',
|
||||
@ -290,6 +317,8 @@ const FormikApp = withFormik({
|
||||
ask_inventory_on_launch: template.ask_inventory_on_launch || false,
|
||||
ask_variables_on_launch: template.ask_variables_on_launch || false,
|
||||
ask_scm_branch_on_launch: template.ask_scm_branch_on_launch || false,
|
||||
ask_skip_tags_on_launch: template.ask_skip_tags_on_launch || false,
|
||||
ask_tags_on_launch: template.ask_tags_on_launch || false,
|
||||
webhook_url: template?.related?.webhook_receiver
|
||||
? `${urlOrigin}${template.related.webhook_receiver}`
|
||||
: '',
|
||||
|
||||
@ -189,7 +189,9 @@ describe('<WorkflowJobTemplateForm/>', () => {
|
||||
'FieldWithPrompt[label="Inventory"]',
|
||||
'FieldWithPrompt[label="Limit"]',
|
||||
'FieldWithPrompt[label="Source control branch"]',
|
||||
'FormGroup[label="Labels"]',
|
||||
'FieldWithPrompt[label="Labels"]',
|
||||
'FieldWithPrompt[label="Skip Tags"]',
|
||||
'FieldWithPrompt[label="Job Tags"]',
|
||||
'VariablesField',
|
||||
];
|
||||
|
||||
|
||||
@ -47,6 +47,16 @@ options:
|
||||
description:
|
||||
- Variables which will be made available to jobs ran inside the workflow.
|
||||
type: dict
|
||||
job_tags:
|
||||
description:
|
||||
- Comma separated list of the tags to use for the job template.
|
||||
type: str
|
||||
ask_tags_on_launch:
|
||||
description:
|
||||
- Prompt user for job tags on launch.
|
||||
type: bool
|
||||
aliases:
|
||||
- ask_tags
|
||||
organization:
|
||||
description:
|
||||
- Organization the workflow job template exists in.
|
||||
@ -85,6 +95,22 @@ options:
|
||||
description:
|
||||
- Prompt user for limit on launch of this workflow job template
|
||||
type: bool
|
||||
ask_labels_on_launch:
|
||||
description:
|
||||
- Prompt user for labels on launch.
|
||||
type: bool
|
||||
aliases:
|
||||
- ask_labels
|
||||
ask_skip_tags_on_launch:
|
||||
description:
|
||||
- Prompt user for job tags to skip on launch.
|
||||
type: bool
|
||||
aliases:
|
||||
- ask_skip_tags
|
||||
skip_tags:
|
||||
description:
|
||||
- Comma separated list of the tags to skip for the job template.
|
||||
type: str
|
||||
webhook_service:
|
||||
description:
|
||||
- Service that webhook requests will be accepted from
|
||||
@ -665,11 +691,15 @@ def main():
|
||||
copy_from=dict(),
|
||||
description=dict(),
|
||||
extra_vars=dict(type='dict'),
|
||||
job_tags=dict(),
|
||||
skip_tags=dict(),
|
||||
organization=dict(),
|
||||
survey_spec=dict(type='dict', aliases=['survey']),
|
||||
survey_enabled=dict(type='bool'),
|
||||
allow_simultaneous=dict(type='bool'),
|
||||
ask_variables_on_launch=dict(type='bool'),
|
||||
ask_labels_on_launch=dict(type='bool', aliases=['ask_labels']),
|
||||
ask_skip_tags_on_launch=dict(type='bool', aliases=['ask_skip_tags']),
|
||||
inventory=dict(),
|
||||
limit=dict(),
|
||||
scm_branch=dict(),
|
||||
@ -752,7 +782,11 @@ def main():
|
||||
'ask_scm_branch_on_launch',
|
||||
'ask_limit_on_launch',
|
||||
'ask_variables_on_launch',
|
||||
'ask_labels_on_launch',
|
||||
'ask_skip_tags_on_launch',
|
||||
'webhook_service',
|
||||
'job_tags',
|
||||
'skip_tags',
|
||||
):
|
||||
field_val = module.params.get(field_name)
|
||||
if field_val is not None:
|
||||
|
||||
@ -18,6 +18,8 @@ def test_create_workflow_job_template(run_module, admin_user, organization, surv
|
||||
'survey_spec': survey_spec,
|
||||
'survey_enabled': True,
|
||||
'state': 'present',
|
||||
'job_tags': '',
|
||||
'skip_tags': '',
|
||||
},
|
||||
admin_user,
|
||||
)
|
||||
@ -35,7 +37,16 @@ def test_create_workflow_job_template(run_module, admin_user, organization, surv
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_modify_no_survey(run_module, admin_user, organization, survey_spec):
|
||||
result = run_module('workflow_job_template', {'name': 'foo-workflow', 'organization': organization.name}, admin_user)
|
||||
result = run_module(
|
||||
'workflow_job_template',
|
||||
{
|
||||
'name': 'foo-workflow',
|
||||
'organization': organization.name,
|
||||
'job_tags': '',
|
||||
'skip_tags': '',
|
||||
},
|
||||
admin_user,
|
||||
)
|
||||
assert not result.get('failed', False), result.get('msg', result)
|
||||
assert result.get('changed', False), result
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user