]> git.ipfire.org Git - pbs.git/blob - src/web/builds.py
builds: Add controls to easily report bugs to Bugzilla
[pbs.git] / src / web / builds.py
1 #!/usr/bin/python
2
3 import tornado.web
4
5 from ..errors import NoSuchDistroError
6 from .. import misc
7
8 from . import base
9 from . import ui_modules
10
11 class APIv1IndexHandler(base.APIMixin, base.BaseHandler):
12 # Allow users to create builds
13 allow_users = True
14
15 @tornado.web.authenticated
16 async def post(self):
17 # Fetch the upload
18 upload = self.get_argument_upload("upload_id")
19 if not upload:
20 raise tornado.web.HTTPError(404, "Could not find upload")
21
22 # Check permissions of the upload
23 if not upload.has_perm(self.current_user):
24 raise tornado.web.HTTPError(403, "No permission for using upload %s" % upload)
25
26 # Fetch the repository
27 repo_name = self.get_argument("repo", None)
28
29 # Did the uploader request to disable test builds?
30 disable_test_builds = self.get_argument_bool("disable_test_builds")
31
32 with self.db.transaction():
33 # Import the package
34 try:
35 package = await self.backend.packages.create(upload)
36
37 # If the distribution that is coded into the package could not be found,
38 # we will send that error to the user...
39 except NoSuchDistroError as e:
40 raise tornado.web.HTTPError(404, "Could not find distribution: %s" % e)
41
42 # Find the repository
43 repo = self.current_user.get_repo(package.distro, repo_name)
44 if not repo:
45 raise tornado.web.HTTPError(404, "Could not find repository")
46
47 # Create a new build
48 build = await self.backend.builds.create(repo, package,
49 owner=self.current_user, disable_test_builds=disable_test_builds)
50
51 # Delete the upload
52 await upload.delete()
53
54 # Send some data about the build
55 self.finish({
56 "uuid" : build.uuid,
57 "name" : "%s" % build,
58 })
59
60 # Launch all jobs (in the background)
61 self.backend.run_task(self.backend.builds.launch, [build])
62
63
64 class IndexHandler(base.BaseHandler):
65 def get(self):
66 # Pagination
67 offset = self.get_argument_int("offset", None) or 0
68 limit = self.get_argument_int("limit", None) or 25
69
70 # Filters
71 user = self.get_argument_user("user", None)
72
73 # Fetch the most recent builds
74 if user:
75 builds = self.backend.builds.get_by_user(user, limit=limit, offset=offset)
76 else:
77 builds = self.backend.builds.get_recent(limit=limit, offset=offset)
78
79 # Group builds by date
80 builds = misc.group(builds, lambda build: build.created_at.date())
81
82 self.render("builds/index.html", builds=builds, user=user,
83 limit=limit, offset=offset)
84
85
86 class ShowHandler(base.BaseHandler):
87 async def get(self, uuid):
88 build = self.backend.builds.get_by_uuid(uuid)
89 if not build:
90 raise tornado.web.HTTPError(404, "Could not find build %s" % uuid)
91
92 # Fetch any fixed Bugs
93 bugs = await build.get_bugs()
94
95 self.render("builds/show.html", build=build, pkg=build.pkg,
96 distro=build.distro, bugs=bugs)
97
98
99 class DeleteHandler(base.BaseHandler):
100 @tornado.web.authenticated
101 def get(self, uuid):
102 build = self.backend.builds.get_by_uuid(uuid)
103 if not build:
104 raise tornado.web.HTTPError(404, "Could not find build %s" % uuid)
105
106 # Check permissions
107 if not build.can_be_deleted(self.current_user):
108 raise tornado.web.HTTPError(403, "%s cannot delete build %s" \
109 % (self.current_user, build))
110
111 self.render("builds/delete.html", build=build)
112
113 @tornado.web.authenticated
114 async def post(self, uuid):
115 build = self.backend.builds.get_by_uuid(uuid)
116 if not build:
117 raise tornado.web.HTTPError(404, "Could not find build %s" % uuid)
118
119 # Check permissions
120 if not build.can_be_deleted(self.current_user):
121 raise tornado.web.HTTPError(403, "%s cannot delete build %s" \
122 % (self.current_user, build))
123
124 # Perform Deletion
125 with self.db.transaction():
126 await build.delete(self.current_user)
127
128 self.redirect("/builds")
129
130
131 class WatchHandler(base.BaseHandler):
132 @tornado.web.authenticated
133 def post(self, uuid):
134 build = self.backend.builds.get_by_uuid(uuid)
135 if not build:
136 raise tornado.web.HTTPError(404, "Could not find build %s" % uuid)
137
138 with self.db.transaction():
139 build.add_watcher(self.current_user)
140
141 self.redirect("/builds/%s" % build.uuid)
142
143
144 class UnwatchHandler(base.BaseHandler):
145 @tornado.web.authenticated
146 def post(self, uuid):
147 build = self.backend.builds.get_by_uuid(uuid)
148 if not build:
149 raise tornado.web.HTTPError(404, "Could not find build %s" % uuid)
150
151 with self.db.transaction():
152 build.remove_watcher(self.current_user)
153
154 self.redirect("/builds/%s" % build.uuid)
155
156
157 class CommentHandler(base.BaseHandler):
158 @tornado.web.authenticated
159 def post(self, uuid):
160 build = self.backend.builds.get_by_uuid(uuid)
161 if not build:
162 raise tornado.web.HTTPError(404, "Could not find build %s" % uuid)
163
164 text = self.get_argument("text")
165
166 # Add a new comment to the build
167 with self.db.transaction():
168 build.comment(self.current_user, text)
169
170 # Redirect to the build
171 self.redirect("/builds/%s" % build.uuid)
172
173
174 class BugHandler(base.BaseHandler):
175 @tornado.web.authenticated
176 async def get(self, uuid):
177 build = self.backend.builds.get_by_uuid(uuid)
178 if not build:
179 raise tornado.web.HTTPError(404, "Could not find build %s" % uuid)
180
181 # Fetch fields
182 fields = await self.backend.bugzilla.fields
183
184 self.render("builds/bug.html", build=build, fields=fields)
185
186 @tornado.web.authenticated
187 async def post(self, uuid):
188 build = self.backend.builds.get_by_uuid(uuid)
189 if not build:
190 raise tornado.web.HTTPError(404, "Could not find build %s" % uuid)
191
192 # Is the user connected to Bugzilla?
193 if not self.current_user.bugzilla:
194 raise tornado.web.HTTPError(400, "%s is not connected to Bugzilla" \
195 % self.current_user)
196
197 kwargs = {
198 # Summary & Description
199 "summary" : self.get_argument("summary"),
200 "description" : self.get_argument("description", None),
201 } | build.bugzilla_fields
202
203 # Create the bug
204 bug = await self.current_user.bugzilla.create_bug(**kwargs)
205
206 # Send the attachments
207 for job in build.jobs:
208 if not self.get_argument_bool("attach_log_%s" % job.uuid):
209 continue
210
211 # Open the logfile
212 try:
213 log = await job.open_log()
214 except FileNotFoundError as e:
215 log.warning("Could not open log file for %s" % job)
216 continue
217
218 # Attach it to the bug
219 await bug.attach(summary="Log file for %s" % job, filename="%s.log" % job,
220 data=log, content_type="text/plain")
221
222 self.render("builds/bug-created.html", build=build, bug=bug)
223
224
225 class GroupShowHandler(base.BaseHandler):
226 def get(self, uuid):
227 group = self.backend.builds.groups.get_by_uuid(uuid)
228 if not group:
229 raise tornado.web.HTTPError(404, "Could not find build group %s" % uuid)
230
231 self.render("builds/groups/show.html", group=group)
232
233
234 class ListModule(ui_modules.UIModule):
235 def render(self, builds):
236 return self.render_string("builds/modules/list.html", builds=builds)
237
238
239 class GroupListModule(ui_modules.UIModule):
240 def render(self, group, limit=None):
241 return self.render_string("builds/groups/modules/list.html",
242 group=group, limit=limit)
243
244
245 class WatchersModule(ui_modules.UIModule):
246 def render(self, build, watchers=None):
247 if watchers is None:
248 watchers = build.watchers
249
250 return self.render_string("builds/modules/watchers.html",
251 build=build, watchers=watchers)