Repository: ansible/awx
File: awx/main/models/mixins.py (Python)

Code before:
                return False
        return True


class TaskManagerUpdateOnLaunchMixin(TaskManagerUnifiedJobMixin):
    class Meta:
        abstract = True


class TaskManagerProjectUpdateMixin(TaskManagerUpdateOnLaunchMixin):
    class Meta:
        abstract = True

    def get_jobs_fail_chain(self):
        return list(self.unifiedjob_blocked_jobs.all())


class TaskManagerInventoryUpdateMixin(TaskManagerUpdateOnLaunchMixin):
    class Meta:
        abstract = True

    def get_jobs_fail_chain(self):
        return list(self.unifiedjob_blocked_jobs.all())

    def dependent_jobs_finished(self):
        for j in self.dependent_jobs.all():
            if j.status in ['pending', 'waiting', 'running']:
                return False
        return True


class ExecutionEnvironmentMixin(models.Model):
    class Meta:
        abstract = True

    execution_environment = models.ForeignKey(
        'ExecutionEnvironment',
        null=True,
        blank=True,
        default=None,
        on_delete=polymorphic.SET_NULL,
        related_name='%(class)ss',
        help_text=_('The container image to be used for execution.'),
    )

    def resolve_execution_environment(self):
        """
        Return the execution environment that should be used when executing a job.
        """
        if self.execution_environment is not None:
            return self.execution_environment

Review comment (suggestion):
This could be written more compactly

```
return not any(j.status in ['pending', 'waiting', 'running'] for j in self.dependent_jobs.all())
```

Code after:
class TaskManagerProjectUpdateMixin(TaskManagerUpdateOnLaunchMixin):
    class Meta:
        abstract = True

    def get_jobs_fail_chain(self):
        # project update can be a dependency of an inventory update, in which
        # case we need to fail the job that may have spawned the inventory
        # update.
        # The inventory update will fail, but since it is not running it will
        # not cascade fail to the job from the errback logic in apply_async. As
        # such we should capture it here.
        blocked_jobs = list(self.unifiedjob_blocked_jobs.all().prefetch_related("unifiedjob_blocked_jobs"))
        other_tasks = []
        for b in blocked_jobs:
            other_tasks += list(b.unifiedjob_blocked_jobs.all())
        return blocked_jobs + other_tasks


class TaskManagerInventoryUpdateMixin(TaskManagerUpdateOnLaunchMixin):
    class Meta:
        abstract = True

    def get_jobs_fail_chain(self):
        blocked_jobs = list(self.unifiedjob_blocked_jobs.all())
        other_updates = []
        if blocked_jobs:
            # blocked_jobs[0] is just a reference to a job that depends on this
            # inventory update.
            # We can look at the dependencies of this blocked job to find other
            # inventory sources that are safe to fail.
            # Since the dependencies could also include project updates,
            # we need to check for type.
            for dep in blocked_jobs[0].dependent_jobs.all():
                if type(dep) is type(self) and dep.id != self.id:
                    other_updates.append(dep)
        return blocked_jobs + other_updates


class ExecutionEnvironmentMixin(models.Model):
    class Meta:
        abstract = True

    execution_environment = models.ForeignKey(
        'ExecutionEnvironment',
        null=True,
        blank=True,
        default=None,
        on_delete=polymorphic.SET_NULL,
        related_name='%(class)ss',
        help_text=_('The container image to be used for execution.'),
    )