diff --git a/awx/main/migrations/0094_v360_webhook_mixin2.py b/awx/main/migrations/0094_v360_webhook_mixin2.py new file mode 100644 index 0000000000..ff4eb7abc1 --- /dev/null +++ b/awx/main/migrations/0094_v360_webhook_mixin2.py @@ -0,0 +1,44 @@ +# Generated by Django 2.2.4 on 2019-09-12 14:52 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0093_v360_personal_access_tokens'), + ] + + operations = [ + migrations.AddField( + model_name='job', + name='webhook_credential', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='jobs', to='main.Credential'), + ), + migrations.AddField( + model_name='job', + name='webhook_guid', + field=models.CharField(blank=True, max_length=128), + ), + migrations.AddField( + model_name='job', + name='webhook_service', + field=models.CharField(blank=True, choices=[('github', 'Github'), ('gitlab', 'Gitlab'), ('bitbucket', 'Bitbucket')], max_length=16), + ), + migrations.AddField( + model_name='workflowjob', + name='webhook_credential', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='workflowjobs', to='main.Credential'), + ), + migrations.AddField( + model_name='workflowjob', + name='webhook_guid', + field=models.CharField(blank=True, max_length=128), + ), + migrations.AddField( + model_name='workflowjob', + name='webhook_service', + field=models.CharField(blank=True, choices=[('github', 'Github'), ('gitlab', 'Gitlab'), ('bitbucket', 'Bitbucket')], max_length=16), + ), + ] diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index 97fae67511..40f60c7705 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -49,6 +49,7 @@ from awx.main.models.mixins import ( CustomVirtualEnvMixin, RelatedJobsMixin, WebhookMixin, + WebhookTemplateMixin, ) @@ -188,7 +189,7 @@ class JobOptions(BaseModel): return needed -class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, ResourceMixin, CustomVirtualEnvMixin, RelatedJobsMixin, WebhookMixin): +class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, ResourceMixin, CustomVirtualEnvMixin, RelatedJobsMixin, WebhookTemplateMixin): ''' A job template is a reusable job definition for applying a project (with playbook) to an inventory source with a given credential. @@ -485,7 +486,7 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour return UnifiedJob.objects.filter(unified_job_template=self) -class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskManagerJobMixin, CustomVirtualEnvMixin): +class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskManagerJobMixin, CustomVirtualEnvMixin, WebhookMixin): ''' A job applies a project (with playbook) to an inventory source with a given credential. It represents a single invocation of ansible-playbook with the diff --git a/awx/main/models/mixins.py b/awx/main/models/mixins.py index 2ab8fc786e..dddca05d6e 100644 --- a/awx/main/models/mixins.py +++ b/awx/main/models/mixins.py @@ -486,7 +486,7 @@ class RelatedJobsMixin(object): return [dict(id=t[0], type=mapping[t[1]]) for t in jobs.values_list('id', 'polymorphic_ctype_id')] -class WebhookMixin(models.Model): +class WebhookTemplateMixin(models.Model): class Meta: abstract = True @@ -529,3 +529,27 @@ class WebhookMixin(models.Model): update_fields.append('webhook_key') super().save(*args, **kwargs) + + +class WebhookMixin(models.Model): + class Meta: + abstract = True + + SERVICES = WebhookTemplateMixin.SERVICES + + webhook_service = models.CharField( + max_length=16, + choices=SERVICES, + blank=True + ) + webhook_credential = models.ForeignKey( + 'Credential', + blank=True, + null=True, + on_delete=models.SET_NULL, + related_name='%(class)ss' + ) + webhook_guid = models.CharField( + blank=True, + max_length=128 + ) diff --git a/awx/main/models/workflow.py b/awx/main/models/workflow.py index cc3133740e..e85e531aaf 100644 --- a/awx/main/models/workflow.py +++ b/awx/main/models/workflow.py @@ -33,6 +33,7 @@ from awx.main.models.mixins import ( SurveyJobMixin, RelatedJobsMixin, WebhookMixin, + WebhookTemplateMixin, ) from awx.main.models.jobs import LaunchTimeConfigBase, LaunchTimeConfig, JobTemplate from awx.main.models.credential import Credential @@ -359,7 +360,7 @@ class WorkflowJobOptions(LaunchTimeConfigBase): return new_workflow_job -class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, SurveyJobTemplateMixin, ResourceMixin, RelatedJobsMixin, WebhookMixin): +class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, SurveyJobTemplateMixin, ResourceMixin, RelatedJobsMixin, WebhookTemplateMixin): SOFT_UNIQUE_TOGETHER = [('polymorphic_ctype', 'name', 'organization')] FIELDS_TO_PRESERVE_AT_COPY = [ @@ -531,7 +532,7 @@ class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, SurveyJobTempl return WorkflowJob.objects.filter(workflow_job_template=self) -class WorkflowJob(UnifiedJob, WorkflowJobOptions, SurveyJobMixin, JobNotificationMixin): +class WorkflowJob(UnifiedJob, WorkflowJobOptions, SurveyJobMixin, JobNotificationMixin, WebhookMixin): class Meta: app_label = 'main' ordering = ('id',) diff --git a/awx/main/tests/functional/api/test_webhooks.py b/awx/main/tests/functional/api/test_webhooks.py index bbc3e353c9..20be437b89 100644 --- a/awx/main/tests/functional/api/test_webhooks.py +++ b/awx/main/tests/functional/api/test_webhooks.py @@ -1,7 +1,7 @@ import pytest from awx.api.versioning import reverse -from awx.main.models.mixins import WebhookMixin +from awx.main.models.mixins import WebhookTemplateMixin from awx.main.models.credential import Credential, CredentialType @@ -113,7 +113,7 @@ def test_post_webhook_key_wfjt(organization_factory, workflow_job_template_facto @pytest.mark.django_db @pytest.mark.parametrize( - "service", [s for s, _ in WebhookMixin.SERVICES] + "service", [s for s, _ in WebhookTemplateMixin.SERVICES] ) def test_set_webhook_service(organization_factory, job_template_factory, patch, service): objs = organization_factory("org", superusers=['admin']) @@ -132,7 +132,7 @@ def test_set_webhook_service(organization_factory, job_template_factory, patch, @pytest.mark.django_db @pytest.mark.parametrize( - "service", [s for s, _ in WebhookMixin.SERVICES] + "service", [s for s, _ in WebhookTemplateMixin.SERVICES] ) def test_unset_webhook_service(organization_factory, job_template_factory, patch, service): objs = organization_factory("org", superusers=['admin']) @@ -151,7 +151,7 @@ def test_unset_webhook_service(organization_factory, job_template_factory, patch @pytest.mark.django_db @pytest.mark.parametrize( - "service", [s for s, _ in WebhookMixin.SERVICES] + "service", [s for s, _ in WebhookTemplateMixin.SERVICES] ) def test_set_webhook_credential(organization_factory, job_template_factory, patch, service): objs = organization_factory("org", superusers=['admin']) @@ -177,7 +177,9 @@ def test_set_webhook_credential(organization_factory, job_template_factory, patc @pytest.mark.django_db @pytest.mark.parametrize( - "service,token", [(s, WebhookMixin.SERVICES[i - 1][0]) for i, (s, _) in enumerate(WebhookMixin.SERVICES)] + "service,token", [ + (s, WebhookTemplateMixin.SERVICES[i - 1][0]) for i, (s, _) in enumerate(WebhookTemplateMixin.SERVICES) + ] ) def test_set_wrong_service_webhook_credential(organization_factory, job_template_factory, patch, service, token): objs = organization_factory("org", superusers=['admin'])