Package coprs :: Package views :: Package coprs_ns :: Module coprs_builds
[hide private]
[frames] | no frames]

Source Code for Module coprs.views.coprs_ns.coprs_builds

  1  import flask 
  2  from flask import request, render_template, stream_with_context 
  3   
  4  from copr_common.enums import StatusEnum 
  5  from coprs import app 
  6  from coprs import db 
  7  from coprs import forms 
  8  from coprs import helpers 
  9   
 10  from coprs.logic import builds_logic 
 11  from coprs.logic.builds_logic import BuildsLogic 
 12  from coprs.logic.complex_logic import ComplexLogic 
 13   
 14  from coprs.views.misc import (login_required, req_with_copr, send_build_icon) 
 15  from coprs.views.coprs_ns import coprs_ns 
 16   
 17  from coprs.exceptions import ( 
 18      ActionInProgressException, 
 19      BadRequest, 
 20      ConflictingRequest, 
 21      InsufficientRightsException, 
 22      UnrepeatableBuildException, 
 23  ) 
24 25 26 @coprs_ns.route("/build/<int:build_id>/") 27 -def copr_build_redirect(build_id):
28 build = ComplexLogic.get_build_safe(build_id) 29 copr = build.copr 30 return flask.redirect(helpers.copr_url("coprs_ns.copr_build", copr, build_id=build_id))
31
32 33 @coprs_ns.route("/build/<int:build_id>/status_image.png") 34 -def copr_build_icon(build_id):
35 return send_build_icon(BuildsLogic.get_by_id(int(build_id)).first())
36
37 38 ################################ Build detail ################################ 39 40 @coprs_ns.route("/<username>/<coprname>/build/<int:build_id>/") 41 @coprs_ns.route("/g/<group_name>/<coprname>/build/<int:build_id>/") 42 @req_with_copr 43 -def copr_build(copr, build_id):
44 return render_copr_build(build_id, copr)
45
46 47 -def render_copr_build(build_id, copr):
48 build = ComplexLogic.get_build_safe(build_id) 49 return render_template("coprs/detail/build.html", build=build, copr=copr)
50
51 52 ################################ Build table ################################ 53 54 @coprs_ns.route("/<username>/<coprname>/builds/") 55 @coprs_ns.route("/g/<group_name>/<coprname>/builds/") 56 @req_with_copr 57 -def copr_builds(copr):
58 flashes = flask.session.pop('_flashes', []) 59 dirname = flask.request.args.get('dirname') 60 builds_query = builds_logic.BuildsLogic.get_copr_builds_list(copr, dirname) 61 builds = builds_query.yield_per(1000) 62 response = flask.Response(stream_with_context(helpers.stream_template("coprs/detail/builds.html", 63 copr=copr, 64 builds=builds, 65 current_dirname=dirname, 66 flashes=flashes))) 67 68 flask.session.pop('_flashes', []) 69 return response
70
71 ################################ Url builds ################################ 72 73 @coprs_ns.route("/<username>/<coprname>/add_build/") 74 @coprs_ns.route("/g/<group_name>/<coprname>/add_build/") 75 @login_required 76 @req_with_copr 77 -def copr_add_build(copr, form=None):
78 return render_add_build( 79 copr, form, view='coprs_ns.copr_new_build')
80
81 82 -def render_add_build(copr, form, view):
83 if not form: 84 form = forms.BuildFormUrlFactory(copr.active_chroots)() 85 return flask.render_template("coprs/detail/add_build/url.html", 86 copr=copr, view=view, form=form)
87
88 89 @coprs_ns.route("/<username>/<coprname>/new_build/", methods=["POST"]) 90 @coprs_ns.route("/g/<group_name>/<coprname>/new_build/", methods=["POST"]) 91 @login_required 92 @req_with_copr 93 -def copr_new_build(copr):
94 return process_new_build_url( 95 copr, 96 "coprs_ns.copr_new_build", 97 url_on_success=helpers.copr_url("coprs_ns.copr_builds", copr))
98
99 100 -def process_new_build_url(copr, add_view, url_on_success):
101 def factory(**build_options): 102 pkgs = form.pkgs.data.split("\n") 103 for pkg in pkgs: 104 BuildsLogic.create_new_from_url( 105 flask.g.user, copr, pkg, 106 chroot_names=form.selected_chroots, 107 **build_options 108 ) 109 for pkg in pkgs: 110 flask.flash("New build has been created: {}".format(pkg), "success")
111 112 form = forms.BuildFormUrlFactory(copr.active_chroots)() 113 return process_new_build(copr, form, factory, render_add_build, 114 add_view, url_on_success, msg_on_success=False) 115
116 117 -def process_new_build(copr, form, create_new_build_factory, add_function, add_view, url_on_success, msg_on_success=True):
118 if form.validate_on_submit(): 119 build_options = { 120 "enable_net": form.enable_net.data, 121 "timeout": form.timeout.data, 122 "bootstrap": form.bootstrap.data, 123 "with_build_id": form.with_build_id.data, 124 "after_build_id": form.after_build_id.data, 125 } 126 127 try: 128 create_new_build_factory(**build_options) 129 db.session.commit() 130 except (ActionInProgressException, InsufficientRightsException, UnrepeatableBuildException, BadRequest) as e: 131 db.session.rollback() 132 flask.flash(str(e), "error") 133 else: 134 if msg_on_success: 135 flask.flash("New build has been created.", "success") 136 137 return flask.redirect(url_on_success) 138 else: 139 return add_function(copr, form, add_view)
140
141 142 ################################ SCM builds ######################################### 143 144 @coprs_ns.route("/<username>/<coprname>/add_build_scm/") 145 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_scm/") 146 @login_required 147 @req_with_copr 148 -def copr_add_build_scm(copr, form=None):
149 return render_add_build_scm( 150 copr, form, view='coprs_ns.copr_new_build_scm')
151
152 153 -def render_add_build_scm(copr, form, view, package=None):
154 if not form: 155 form = forms.BuildFormScmFactory(copr.active_chroots)() 156 return flask.render_template("coprs/detail/add_build/scm.html", 157 copr=copr, form=form, view=view, package=package)
158
159 160 @coprs_ns.route("/<username>/<coprname>/new_build_scm/", methods=["POST"]) 161 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_scm/", methods=["POST"]) 162 @login_required 163 @req_with_copr 164 -def copr_new_build_scm(copr):
165 view = 'coprs_ns.copr_new_build_scm' 166 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 167 return process_new_build_scm(copr, view, url_on_success)
168
169 170 -def process_new_build_scm(copr, add_view, url_on_success):
171 def factory(**build_options): 172 BuildsLogic.create_new_from_scm( 173 flask.g.user, 174 copr, 175 form.scm_type.data, 176 form.clone_url.data, 177 form.committish.data, 178 form.subdirectory.data, 179 form.spec.data, 180 form.srpm_build_method.data, 181 form.selected_chroots, 182 **build_options 183 )
184 form = forms.BuildFormScmFactory(copr.active_chroots)() 185 return process_new_build(copr, form, factory, render_add_build_scm, add_view, url_on_success) 186
187 ################################ DistGit builds ################################ 188 189 @coprs_ns.route("/<username>/<coprname>/add_build_distgit/") 190 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_distgit/") 191 @login_required 192 @req_with_copr 193 -def copr_add_build_distgit(copr, form=None):
194 """ GET request for distgit build """ 195 return render_add_build_distgit( 196 copr, form, view='coprs_ns.copr_new_build_distgit')
197
198 @coprs_ns.route("/<username>/<coprname>/new_build_distgit/", methods=["POST"]) 199 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_distgit/", methods=["POST"]) 200 @login_required 201 @req_with_copr 202 -def copr_new_build_distgit(copr):
203 """ POST request for distgit build """ 204 view = 'coprs_ns.copr_new_build_distgit' 205 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 206 return process_new_build_distgit(copr, view, url_on_success)
207
208 -def render_add_build_distgit(copr, form, view, package=None):
209 """ Render the distgit build form """ 210 if not form: 211 # pylint: disable=not-callable 212 form = forms.BuildFormDistGitSimpleFactory(copr.active_chroots)() 213 return flask.render_template("coprs/detail/add_build/distgit.html", 214 copr=copr, form=form, view=view, package=package)
215
216 -def process_new_build_distgit(copr, add_view, url_on_success):
217 """ Handle the POST data from distgit build form """ 218 def factory(**build_options): 219 BuildsLogic.create_new_from_distgit( 220 flask.g.user, 221 copr, 222 package_name=form.package_name.data, 223 distgit_name=form.distgit.data, 224 distgit_namespace=form.namespace.data, 225 committish=form.committish.data, 226 chroot_names=form.selected_chroots, 227 **build_options 228 )
229 # pylint: disable=not-callable 230 form = forms.BuildFormDistGitSimpleFactory(copr.active_chroots)() 231 return process_new_build(copr, form, factory, render_add_build_distgit, add_view, url_on_success) 232
233 ################################ PyPI builds ################################ 234 235 @coprs_ns.route("/<username>/<coprname>/add_build_pypi/") 236 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_pypi/") 237 @login_required 238 @req_with_copr 239 -def copr_add_build_pypi(copr, form=None):
240 return render_add_build_pypi( 241 copr, form, view='coprs_ns.copr_new_build_pypi')
242
243 244 -def render_add_build_pypi(copr, form, view, package=None):
245 if not form: 246 form = forms.BuildFormPyPIFactory(copr.active_chroots)() 247 return flask.render_template("coprs/detail/add_build/pypi.html", 248 copr=copr, form=form, view=view, package=package)
249
250 251 @coprs_ns.route("/<username>/<coprname>/new_build_pypi/", methods=["POST"]) 252 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_pypi/", methods=["POST"]) 253 @login_required 254 @req_with_copr 255 -def copr_new_build_pypi(copr):
256 view = 'coprs_ns.copr_new_build_pypi' 257 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 258 return process_new_build_pypi(copr, view, url_on_success)
259
260 261 -def process_new_build_pypi(copr, add_view, url_on_success):
262 def factory(**build_options): 263 BuildsLogic.create_new_from_pypi( 264 flask.g.user, 265 copr, 266 form.pypi_package_name.data, 267 form.pypi_package_version.data, 268 form.spec_template.data, 269 form.python_versions.data, 270 form.selected_chroots, 271 **build_options 272 )
273 form = forms.BuildFormPyPIFactory(copr.active_chroots)() 274 return process_new_build(copr, form, factory, render_add_build_pypi, add_view, url_on_success) 275
276 277 ############################### RubyGems builds ############################### 278 279 @coprs_ns.route("/<username>/<coprname>/add_build_rubygems/") 280 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_rubygems/") 281 @login_required 282 @req_with_copr 283 -def copr_add_build_rubygems(copr, form=None):
284 return render_add_build_rubygems( 285 copr, form, view='coprs_ns.copr_new_build_rubygems')
286
287 288 -def render_add_build_rubygems(copr, form, view, package=None):
289 if not form: 290 form = forms.BuildFormRubyGemsFactory(copr.active_chroots)() 291 return flask.render_template("coprs/detail/add_build/rubygems.html", 292 copr=copr, form=form, view=view, package=package)
293
294 295 @coprs_ns.route("/<username>/<coprname>/new_build_rubygems/", methods=["POST"]) 296 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_rubygems/", methods=["POST"]) 297 @login_required 298 @req_with_copr 299 -def copr_new_build_rubygems(copr):
300 view = 'coprs_ns.copr_new_build_rubygems' 301 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 302 return process_new_build_rubygems(copr, view, url_on_success)
303
304 305 -def process_new_build_rubygems(copr, add_view, url_on_success):
306 def factory(**build_options): 307 BuildsLogic.create_new_from_rubygems( 308 flask.g.user, 309 copr, 310 form.gem_name.data, 311 form.selected_chroots, 312 **build_options 313 )
314 form = forms.BuildFormRubyGemsFactory(copr.active_chroots)() 315 return process_new_build(copr, form, factory, render_add_build_rubygems, add_view, url_on_success) 316
317 ############################### Custom builds ############################### 318 319 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_custom/", methods=["POST"]) 320 @coprs_ns.route("/<username>/<coprname>/new_build_custom/", methods=["POST"]) 321 @login_required 322 @req_with_copr 323 -def copr_new_build_custom(copr):
324 """ Handle the build request and redirect back. """ 325 326 # TODO: parametric decorator for this view && url_on_success 327 view = 'coprs_ns.copr_new_build_custom' 328 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 329 330 def factory(**build_options): 331 BuildsLogic.create_new_from_custom( 332 flask.g.user, 333 copr, 334 form.script.data, 335 form.chroot.data, 336 form.builddeps.data, 337 form.resultdir.data, 338 chroot_names=form.selected_chroots, 339 **build_options 340 )
341 342 form = forms.BuildFormCustomFactory(copr.active_chroots)() 343 344 return process_new_build(copr, form, factory, render_add_build_custom, 345 view, url_on_success) 346
347 348 349 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_custom/") 350 @coprs_ns.route("/<username>/<coprname>/add_build_custom/") 351 @login_required 352 @req_with_copr 353 -def copr_add_build_custom(copr, form=None):
354 return render_add_build_custom(copr, form, 355 'coprs_ns.copr_new_build_custom')
356
357 -def render_add_build_custom(copr, form, view, package=None):
358 if not form: 359 form = forms.BuildFormCustomFactory(copr.active_chroots)() 360 return flask.render_template("coprs/detail/add_build/custom.html", 361 copr=copr, form=form, view=view)
362
363 364 ################################ Upload builds ################################ 365 366 @coprs_ns.route("/<username>/<coprname>/add_build_upload/") 367 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_upload/") 368 @login_required 369 @req_with_copr 370 -def copr_add_build_upload(copr, form=None):
371 return render_add_build_upload( 372 copr, form, view='coprs_ns.copr_new_build_upload')
373
374 375 -def render_add_build_upload(copr, form, view):
376 if not form: 377 form = forms.BuildFormUploadFactory(copr.active_chroots)() 378 return flask.render_template("coprs/detail/add_build/upload.html", 379 copr=copr, form=form, view=view)
380
381 382 @coprs_ns.route("/<username>/<coprname>/new_build_upload/", methods=["POST"]) 383 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_upload/", methods=["POST"]) 384 @login_required 385 @req_with_copr 386 -def copr_new_build_upload(copr):
387 view = 'coprs_ns.copr_new_build_upload' 388 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 389 return process_new_build_upload(copr, view, url_on_success)
390
391 392 -def process_new_build_upload(copr, add_view, url_on_success):
393 def factory(**build_options): 394 BuildsLogic.create_new_from_upload( 395 flask.g.user, copr, 396 f_uploader=lambda path: form.pkgs.data.save(path), 397 orig_filename=form.pkgs.data.filename, 398 chroot_names=form.selected_chroots, 399 **build_options 400 )
401 form = forms.BuildFormUploadFactory(copr.active_chroots)() 402 return process_new_build(copr, form, factory, render_add_build_upload, add_view, url_on_success) 403
404 405 ################################ Builds rebuilds ################################ 406 407 @coprs_ns.route("/<username>/<coprname>/new_build_rebuild/<int:build_id>/", methods=["POST"]) 408 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_rebuild/<int:build_id>/", methods=["POST"]) 409 @login_required 410 @req_with_copr 411 -def copr_new_build_rebuild(copr, build_id):
412 view='coprs_ns.copr_new_build' 413 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 414 return process_rebuild(copr, build_id, view=view, url_on_success=url_on_success)
415
416 417 -def process_rebuild(copr, build_id, view, url_on_success):
418 def factory(**build_options): 419 source_build = ComplexLogic.get_build_safe(build_id) 420 BuildsLogic.create_new_from_other_build( 421 flask.g.user, copr, source_build, 422 chroot_names=form.selected_chroots, 423 **build_options 424 )
425 # pylint: disable=not-callable 426 form = forms.BuildFormRebuildFactory.create_form_cls(copr.active_chroots)() 427 return process_new_build(copr, form, factory, render_add_build, view, url_on_success) 428
429 430 ################################ Repeat ################################ 431 432 @coprs_ns.route("/<username>/<coprname>/repeat_build/<int:build_id>/", methods=["GET", "POST"]) 433 @coprs_ns.route("/g/<group_name>/<coprname>/repeat_build/<int:build_id>/", methods=["GET", "POST"]) 434 @login_required 435 @req_with_copr 436 -def copr_repeat_build(copr, build_id):
437 return process_copr_repeat_build(build_id, copr)
438
439 440 -def process_copr_repeat_build(build_id, copr):
441 build = ComplexLogic.get_build_safe(build_id) 442 if not flask.g.user.can_build_in(build.copr): 443 flask.flash("You are not allowed to repeat this build.") 444 445 if build.source_type == helpers.BuildSourceEnum('upload'): 446 # If the original build's source is 'upload', we will show only the 447 # original build's chroots and skip import. 448 available_chroots = build.chroots 449 450 else: 451 # For all other sources, we will show all chroots enabled in the project 452 # and proceed with import. 453 available_chroots = copr.active_chroots 454 455 # pylint: disable=not-callable 456 form = forms.BuildFormRebuildFactory.create_form_cls(available_chroots)( 457 build_id=build_id, enable_net=build.enable_net) 458 459 # remove all checkboxes by default 460 for ch in available_chroots: 461 field = getattr(form, ch.name) 462 field.data = False 463 chroot_to_build = request.args.get("chroot") 464 app.logger.debug("got param chroot: {}".format(chroot_to_build)) 465 if chroot_to_build: 466 # set single checkbox if chroot query arg was provided 467 if hasattr(form, chroot_to_build): 468 getattr(form, chroot_to_build).data = True 469 else: 470 build_chroot_names = set(ch.name for ch in build.chroots) 471 build_failed_chroot_names = set(ch.name for ch in build.get_chroots_by_status([ 472 StatusEnum('failed'), StatusEnum('canceled'), 473 ])) 474 for ch in available_chroots: 475 # check checkbox on all the chroots that have not been (successfully) built before 476 if (ch.name not in build_chroot_names) or (ch.name in build_failed_chroot_names): 477 getattr(form, ch.name).data = True 478 return flask.render_template( 479 "coprs/detail/add_build/rebuild.html", 480 copr=copr, build=build, form=form)
481
482 483 ################################ Cancel ################################ 484 485 -def process_cancel_build(build):
486 try: 487 builds_logic.BuildsLogic.cancel_build(flask.g.user, build) 488 except (InsufficientRightsException, ConflictingRequest) as e: 489 flask.flash(str(e), "error") 490 else: 491 db.session.commit() 492 flask.flash("Build {} has been canceled successfully.".format(build.id)) 493 return flask.redirect(helpers.url_for_copr_builds(build.copr))
494
495 496 @coprs_ns.route("/<username>/<coprname>/cancel_build/<int:build_id>/", methods=["POST"]) 497 @coprs_ns.route("/g/<group_name>/<coprname>/cancel_build/<int:build_id>/", methods=["POST"]) 498 @login_required 499 @req_with_copr 500 -def copr_cancel_build(copr, build_id):
501 # only the user who ran the build can cancel it 502 build = ComplexLogic.get_build_safe(build_id) 503 return process_cancel_build(build)
504 505 506 ################################ Delete ################################ 507 508 @coprs_ns.route("/<username>/<coprname>/delete_build/<int:build_id>/", 509 methods=["POST"])
510 @login_required 511 -def copr_delete_build(username, coprname, build_id):
512 build = ComplexLogic.get_build_safe(build_id) 513 514 try: 515 builds_logic.BuildsLogic.delete_build(flask.g.user, build) 516 except (InsufficientRightsException, ActionInProgressException) as e: 517 flask.flash(str(e), "error") 518 else: 519 db.session.commit() 520 flask.flash("Build has been deleted successfully.") 521 522 return flask.redirect(helpers.url_for_copr_builds(build.copr))
523
524 ################################ xhr batch delete ################################ 525 526 @coprs_ns.route("/<username>/<coprname>/delete_builds/", methods=["POST"]) 527 @coprs_ns.route("/g/<group_name>/<coprname>/delete_builds/", methods=["POST"]) 528 @login_required 529 @req_with_copr 530 -def copr_delete_builds(copr):
531 build_ids = flask.request.form.getlist("build_ids[]") 532 533 to_delete = [] 534 for build_id in build_ids: 535 to_delete.append(int(build_id)) 536 537 try: 538 builds_logic.BuildsLogic.delete_builds(flask.g.user, to_delete) 539 540 db.session.commit() 541 build_ids_str = ", ".join(build_ids).strip(", ") 542 flask.flash("Builds {} have been deleted successfully.".format(build_ids_str), "success") 543 return flask.jsonify({"msg": "success"}) 544 except BadRequest as e: 545 flask.flash(e, "error") 546 return flask.jsonify({"msg": "error"})
547