summaryrefslogtreecommitdiff
path: root/zuul/driver/zuul/__init__.py
blob: e381137a54bd04d704cd8163b59c44680e37451b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# Copyright 2016 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import logging

from zuul.driver import Driver, TriggerInterface
from zuul.driver.zuul.zuulmodel import ZuulTriggerEvent

from zuul.driver.zuul import zuultrigger

PARENT_CHANGE_ENQUEUED = 'parent-change-enqueued'
PROJECT_CHANGE_MERGED = 'project-change-merged'


class ZuulDriver(Driver, TriggerInterface):
    name = 'zuul'
    log = logging.getLogger("zuul.ZuulTrigger")

    def __init__(self):
        self.tenant_events = {}

    def registerScheduler(self, scheduler):
        self.sched = scheduler

    def reconfigure(self, tenant):
        events = set()
        self.tenant_events[tenant.name] = events
        for pipeline in tenant.layout.pipelines.values():
            for ef in pipeline.manager.event_filters:
                if not isinstance(ef.trigger, zuultrigger.ZuulTrigger):
                    continue
                if PARENT_CHANGE_ENQUEUED in ef._types:
                    events.add(PARENT_CHANGE_ENQUEUED)
                elif PROJECT_CHANGE_MERGED in ef._types:
                    events.add(PROJECT_CHANGE_MERGED)

    def onChangeMerged(self, tenant, change, source):
        # Called each time zuul merges a change
        if PROJECT_CHANGE_MERGED in self.tenant_events[tenant.name]:
            try:
                self._createProjectChangeMergedEvents(change, source)
            except Exception:
                self.log.exception(
                    "Unable to create project-change-merged events for "
                    "%s" % (change,))

    def onChangeEnqueued(self, tenant, change, pipeline):
        self.log.debug("onChangeEnqueued %s", self.tenant_events[tenant.name])
        # Called each time a change is enqueued in a pipeline
        if PARENT_CHANGE_ENQUEUED in self.tenant_events[tenant.name]:
            try:
                self._createParentChangeEnqueuedEvents(change, pipeline)
            except Exception:
                self.log.exception(
                    "Unable to create parent-change-enqueued events for "
                    "%s in %s" % (change, pipeline))

    def _createProjectChangeMergedEvents(self, change, source):
        changes = source.getProjectOpenChanges(
            change.project)
        for open_change in changes:
            self._createProjectChangeMergedEvent(open_change)

    def _createProjectChangeMergedEvent(self, change):
        event = ZuulTriggerEvent()
        event.type = PROJECT_CHANGE_MERGED
        event.trigger_name = self.name
        event.project_hostname = change.project.canonical_hostname
        event.project_name = change.project.name
        event.change_number = change.number
        event.branch = change.branch
        event.change_url = change.url
        event.patch_number = change.patchset
        event.ref = change.ref
        self.sched.addEvent(event)

    def _createParentChangeEnqueuedEvents(self, change, pipeline):
        self.log.debug("Checking for changes needing %s:" % change)
        if not hasattr(change, 'needed_by_changes'):
            self.log.debug("  %s does not support dependencies" % type(change))
            return

        # This is very inefficient, especially on systems with large
        # numbers of github installations.  This can be improved later
        # with persistent storage of dependency information.
        needed_by_changes = set(change.needed_by_changes)
        for source in self.sched.connections.getSources():
            self.log.debug("  Checking source: %s", source)
            needed_by_changes.update(
                source.getChangesDependingOn(change, None))
        self.log.debug("  Following changes: %s", needed_by_changes)

        for needs in needed_by_changes:
            self._createParentChangeEnqueuedEvent(needs, pipeline)

    def _createParentChangeEnqueuedEvent(self, change, pipeline):
        event = ZuulTriggerEvent()
        event.type = PARENT_CHANGE_ENQUEUED
        event.trigger_name = self.name
        event.pipeline_name = pipeline.name
        event.project_hostname = change.project.canonical_hostname
        event.project_name = change.project.name
        event.change_number = change.number
        event.branch = change.branch
        event.change_url = change.url
        event.patch_number = change.patchset
        event.ref = change.ref
        self.sched.addEvent(event)

    def getTrigger(self, connection_name, config=None):
        return zuultrigger.ZuulTrigger(self, config)

    def getTriggerSchema(self):
        return zuultrigger.getSchema()