blob: 6fb2d6672a4f4f7127a935a2811a2cfa36f0d37c [file] [log] [blame]
James E. Blair6bacffb2018-01-05 13:45:25 -08001#!/usr/bin/env python
2
3# Copyright 2018 Red Hat, Inc.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17import re
18
19
20class FakeUser(object):
21 def __init__(self, login):
22 self.login = login
23 self.name = "Github User"
24 self.email = "github.user@example.com"
25
26
27class FakeBranch(object):
28 def __init__(self, branch='master'):
29 self.name = branch
30
31
32class FakeStatus(object):
33 def __init__(self, state, url, description, context, user):
34 self._state = state
35 self._url = url
36 self._description = description
37 self._context = context
38 self._user = user
39
40 def as_dict(self):
41 return {
42 'state': self._state,
43 'url': self._url,
44 'description': self._description,
45 'context': self._context,
46 'creator': {
47 'login': self._user
48 }
49 }
50
51
52class FakeCommit(object):
53 def __init__(self):
54 self._statuses = []
55
56 def set_status(self, state, url, description, context, user):
57 status = FakeStatus(
58 state, url, description, context, user)
59 # always insert a status to the front of the list, to represent
60 # the last status provided for a commit.
61 self._statuses.insert(0, status)
62
63 def statuses(self):
64 return self._statuses
65
66
67class FakeRepository(object):
68 def __init__(self):
69 self._branches = [FakeBranch()]
70 self._commits = {}
71
72 def branches(self, protected=False):
73 if protected:
74 # simulate there is no protected branch
75 return []
76 return self._branches
77
78 def create_status(self, sha, state, url, description, context,
79 user='zuul'):
80 # Since we're bypassing github API, which would require a user, we
81 # default the user as 'zuul' here.
82 commit = self._commits.get(sha, None)
83 if commit is None:
84 commit = FakeCommit()
85 self._commits[sha] = commit
86 commit.set_status(state, url, description, context, user)
87
88 def commit(self, sha):
89 commit = self._commits.get(sha, None)
90 if commit is None:
91 commit = FakeCommit()
92 self._commits[sha] = commit
93 return commit
94
95
96class FakeLabel(object):
97 def __init__(self, name):
98 self.name = name
99
100
101class FakeIssue(object):
102 def __init__(self, fake_pull_request):
103 self._fake_pull_request = fake_pull_request
104
105 def pull_request(self):
106 return FakePull(self._fake_pull_request)
107
108 def labels(self):
109 return [FakeLabel(l)
110 for l in self._fake_pull_request.labels]
111
112
113class FakeFile(object):
114 def __init__(self, filename):
115 self.filename = filename
116
117
118class FakePull(object):
119 def __init__(self, fake_pull_request):
120 self._fake_pull_request = fake_pull_request
121
122 def issue(self):
123 return FakeIssue(self._fake_pull_request)
124
125 def files(self):
126 return [FakeFile(fn)
127 for fn in self._fake_pull_request.files]
128
129 def as_dict(self):
130 pr = self._fake_pull_request
131 connection = pr.github
132 data = {
133 'number': pr.number,
134 'title': pr.subject,
135 'url': 'https://%s/%s/pull/%s' % (
136 connection.server, pr.project, pr.number
137 ),
138 'updated_at': pr.updated_at,
139 'base': {
140 'repo': {
141 'full_name': pr.project
142 },
143 'ref': pr.branch,
144 },
145 'mergeable': True,
146 'state': pr.state,
147 'head': {
148 'sha': pr.head_sha,
149 'repo': {
150 'full_name': pr.project
151 }
152 },
153 'merged': pr.is_merged,
154 'body': pr.body
155 }
156 return data
157
158
159class FakeIssueSearchResult(object):
160 def __init__(self, issue):
161 self.issue = issue
162
163
164class FakeGithub(object):
165 def __init__(self, pull_requests):
166 self._pull_requests = pull_requests
167 self._repos = {}
168
169 def user(self, login):
170 return FakeUser(login)
171
172 def repository(self, owner, proj):
173 return self._repos.get((owner, proj), None)
174
175 def repo_from_project(self, project):
176 # This is a convenience method for the tests.
177 owner, proj = project.split('/')
178 return self.repository(owner, proj)
179
180 def addProject(self, project):
181 owner, proj = project.name.split('/')
182 self._repos[(owner, proj)] = FakeRepository()
183
184 def pull_request(self, owner, project, number):
185 fake_pr = self._pull_requests[number]
186 return FakePull(fake_pr)
187
188 def search_issues(self, query):
189 def tokenize(s):
190 return re.findall(r'[\w]+', s)
191
192 parts = tokenize(query)
193 terms = set()
194 results = []
195 for part in parts:
196 kv = part.split(':', 1)
197 if len(kv) == 2:
198 if kv[0] in set('type', 'is', 'in'):
199 # We only perform one search now and these aren't
200 # important; we can honor these terms later if
201 # necessary.
202 continue
203 terms.add(part)
204
205 for pr in self._pull_requests.values():
206 if not pr.body:
207 body = set()
208 else:
209 body = set(tokenize(pr.body))
210 if terms.intersection(body):
211 issue = FakeIssue(pr)
212 results.append(FakeIssueSearchResult(issue))
213
214 return results