Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: appengine/chromium_rietveld/codereview/views.py

Issue 1155513002: [Rietveld] Add support for patchset dependencies (Closed) Base URL: https://chromium.googlesource.com/infra/infra@master
Patch Set: Fix lint issues in test Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2008 Google Inc. 1 # Copyright 2008 Google Inc.
2 # 2 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); 3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License. 4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at 5 # You may obtain a copy of the License at
6 # 6 #
7 # http://www.apache.org/licenses/LICENSE-2.0 7 # http://www.apache.org/licenses/LICENSE-2.0
8 # 8 #
9 # Unless required by applicable law or agreed to in writing, software 9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, 10 # distributed under the License is distributed on an "AS IS" BASIS,
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 from oauth2client.appengine import _safe_html 71 from oauth2client.appengine import _safe_html
72 from oauth2client.appengine import CredentialsNDBModel 72 from oauth2client.appengine import CredentialsNDBModel
73 from oauth2client.appengine import StorageByKeyName 73 from oauth2client.appengine import StorageByKeyName
74 from oauth2client.appengine import xsrf_secret_key 74 from oauth2client.appengine import xsrf_secret_key
75 from oauth2client.client import AccessTokenRefreshError 75 from oauth2client.client import AccessTokenRefreshError
76 from oauth2client.client import OAuth2WebServerFlow 76 from oauth2client.client import OAuth2WebServerFlow
77 from oauth2client import xsrfutil 77 from oauth2client import xsrfutil
78 78
79 from codereview import auth_utils 79 from codereview import auth_utils
80 from codereview import buildbucket 80 from codereview import buildbucket
81 from codereview import dependency_utils
81 from codereview import engine 82 from codereview import engine
82 from codereview import library 83 from codereview import library
83 from codereview import models 84 from codereview import models
84 from codereview import models_chromium 85 from codereview import models_chromium
85 from codereview import net 86 from codereview import net
86 from codereview import notify_xmpp 87 from codereview import notify_xmpp
87 from codereview import patching 88 from codereview import patching
88 from codereview import utils 89 from codereview import utils
89 from codereview import common 90 from codereview import common
90 from codereview.exceptions import FetchError 91 from codereview.exceptions import FetchError
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 class UploadForm(forms.Form): 175 class UploadForm(forms.Form):
175 176
176 subject = forms.CharField(max_length=MAX_SUBJECT) 177 subject = forms.CharField(max_length=MAX_SUBJECT)
177 description = forms.CharField(max_length=MAX_DESCRIPTION, required=False) 178 description = forms.CharField(max_length=MAX_DESCRIPTION, required=False)
178 project = forms.CharField(required=False) 179 project = forms.CharField(required=False)
179 content_upload = forms.BooleanField(required=False) 180 content_upload = forms.BooleanField(required=False)
180 separate_patches = forms.BooleanField(required=False) 181 separate_patches = forms.BooleanField(required=False)
181 base = forms.CharField(max_length=MAX_URL, required=False) 182 base = forms.CharField(max_length=MAX_URL, required=False)
182 target_ref = forms.CharField(max_length=MAX_URL, required=False) 183 target_ref = forms.CharField(max_length=MAX_URL, required=False)
183 cq_dry_run = forms.BooleanField(required=False) 184 cq_dry_run = forms.BooleanField(required=False)
185 depends_on_patchset = forms.CharField(required=False)
184 data = forms.FileField(required=False) 186 data = forms.FileField(required=False)
185 issue = forms.IntegerField(required=False) 187 issue = forms.IntegerField(required=False)
186 reviewers = forms.CharField(max_length=MAX_REVIEWERS, required=False) 188 reviewers = forms.CharField(max_length=MAX_REVIEWERS, required=False)
187 cc = forms.CharField(max_length=MAX_CC, required=False) 189 cc = forms.CharField(max_length=MAX_CC, required=False)
188 private = forms.BooleanField(required=False, initial=False) 190 private = forms.BooleanField(required=False, initial=False)
189 send_mail = forms.BooleanField(required=False) 191 send_mail = forms.BooleanField(required=False)
190 base_hashes = forms.CharField(required=False) 192 base_hashes = forms.CharField(required=False)
191 commit = forms.BooleanField(required=False) 193 commit = forms.BooleanField(required=False)
192 repo_guid = forms.CharField(required=False, max_length=MAX_URL) 194 repo_guid = forms.CharField(required=False, max_length=MAX_URL)
193 195
(...skipping 823 matching lines...) Expand 10 before | Expand all | Expand 10 after
1017 return HttpResponseBadRequest( 1019 return HttpResponseBadRequest(
1018 'Only the issue owner can edit patchset titles') 1020 'Only the issue owner can edit patchset titles')
1019 1021
1020 patchset = request.patchset 1022 patchset = request.patchset
1021 patchset.message = request.POST.get('patchset_title') 1023 patchset.message = request.POST.get('patchset_title')
1022 patchset.put() 1024 patchset.put()
1023 1025
1024 return HttpResponse('OK', content_type='text/plain') 1026 return HttpResponse('OK', content_type='text/plain')
1025 1027
1026 1028
1029 @deco.access_control_allow_origin_star
1030 @deco.require_methods('POST')
1031 @deco.patchset_required
1032 @deco.json_response
1033 def get_depends_on_patchset(request):
1034 """/<issue>/get_depends_on_patchset- The patchset this patchset depends on."""
1035 response = {}
1036 if request.patchset.depends_on_patchset:
1037 # Verify that the depended upon issue is not closed.
1038 tokens = dependency_utils.get_dependency_tokens(
1039 request.patchset.depends_on_patchset)
1040 depends_on_issue = models.Issue.get_by_id(int(tokens[0]))
1041 if depends_on_issue and not depends_on_issue.closed:
1042 response = {
1043 'issue': tokens[0],
1044 'patchset': tokens[1],
1045 }
1046 return response
1047
1048
1027 @deco.admin_required 1049 @deco.admin_required
1028 @deco.user_key_required 1050 @deco.user_key_required
1029 @deco.xsrf_required 1051 @deco.xsrf_required
1030 def block_user(request): 1052 def block_user(request):
1031 """/user/<user>/block - Blocks a specific user.""" 1053 """/user/<user>/block - Blocks a specific user."""
1032 account = models.Account.get_account_for_user(request.user_to_show) 1054 account = models.Account.get_account_for_user(request.user_to_show)
1033 if request.method == 'POST': 1055 if request.method == 'POST':
1034 form = BlockForm(request.POST) 1056 form = BlockForm(request.POST)
1035 if form.is_valid(): 1057 if form.is_valid():
1036 account.blocked = form.cleaned_data['blocked'] 1058 account.blocked = form.cleaned_data['blocked']
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after
1430 issue.put() 1452 issue.put()
1431 1453
1432 if cq_dry_run: 1454 if cq_dry_run:
1433 commit_checked_msg = 'The CQ bit was checked by %s to run a CQ dry run' % ( 1455 commit_checked_msg = 'The CQ bit was checked by %s to run a CQ dry run' % (
1434 cq_dry_run_triggered_by) 1456 cq_dry_run_triggered_by)
1435 make_message(request, issue, commit_checked_msg, send_mail=False, 1457 make_message(request, issue, commit_checked_msg, send_mail=False,
1436 auto_generated=True).put() 1458 auto_generated=True).put()
1437 1459
1438 first_ps_id, _ = models.PatchSet.allocate_ids(1, parent=issue.key) 1460 first_ps_id, _ = models.PatchSet.allocate_ids(1, parent=issue.key)
1439 ps_key = ndb.Key(models.PatchSet, first_ps_id, parent=issue.key) 1461 ps_key = ndb.Key(models.PatchSet, first_ps_id, parent=issue.key)
1462 depends_on_patchset = (
1463 dependency_utils.mark_as_dependent_and_get_dependency_str(
1464 form.cleaned_data.get('depends_on_patchset'), issue.key.id(),
1465 ps_key.id()))
1440 patchset = models.PatchSet( 1466 patchset = models.PatchSet(
1441 issue_key=issue.key, data=data, url=url, key=ps_key) 1467 issue_key=issue.key, data=data, url=url, key=ps_key,
1468 depends_on_patchset=depends_on_patchset)
1442 patchset.put() 1469 patchset.put()
1443 1470
1444 if not separate_patches: 1471 if not separate_patches:
1445 try: 1472 try:
1446 patches = engine.ParsePatchSet(patchset) 1473 patches = engine.ParsePatchSet(patchset)
1447 except Exception: 1474 except Exception:
1448 # catch all exceptions happening in engine.ParsePatchSet, 1475 # catch all exceptions happening in engine.ParsePatchSet,
1449 # engine_utils.SplitPatch. With malformed diffs a variety of exceptions 1476 # engine_utils.SplitPatch. With malformed diffs a variety of exceptions
1450 # could happen there. 1477 # could happen there.
1451 logging.exception('Exception during patch parsing') 1478 logging.exception('Exception during patch parsing')
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1525 account = models.Account.get_account_for_user(request.user) 1552 account = models.Account.get_account_for_user(request.user)
1526 if account.blocked: 1553 if account.blocked:
1527 return None 1554 return None
1528 if not issue.edit_allowed: 1555 if not issue.edit_allowed:
1529 # This check is done at each call site but check again as a safety measure. 1556 # This check is done at each call site but check again as a safety measure.
1530 return None 1557 return None
1531 data, url, separate_patches = data_url 1558 data, url, separate_patches = data_url
1532 message = form.cleaned_data[message_key] 1559 message = form.cleaned_data[message_key]
1533 first_id, _ = models.PatchSet.allocate_ids(1, parent=issue.key) 1560 first_id, _ = models.PatchSet.allocate_ids(1, parent=issue.key)
1534 ps_key = ndb.Key(models.PatchSet, first_id, parent=issue.key) 1561 ps_key = ndb.Key(models.PatchSet, first_id, parent=issue.key)
1562
1563 depends_on_patchset = (
1564 dependency_utils.mark_as_dependent_and_get_dependency_str(
1565 form.cleaned_data.get('depends_on_patchset'), issue.key.id(),
1566 ps_key.id()))
1535 patchset = models.PatchSet( 1567 patchset = models.PatchSet(
1536 issue_key=issue.key, message=message, data=data, url=url, key=ps_key) 1568 issue_key=issue.key, message=message, data=data, url=url, key=ps_key,
1569 depends_on_patchset=depends_on_patchset)
1537 patchset.put() 1570 patchset.put()
1538 1571
1539 if not separate_patches: 1572 if not separate_patches:
1540 try: 1573 try:
1541 patches = engine.ParsePatchSet(patchset) 1574 patches = engine.ParsePatchSet(patchset)
1542 except Exception: 1575 except Exception:
1543 logging.exception('Exception during patchset parsing') 1576 logging.exception('Exception during patchset parsing')
1544 patches = [] 1577 patches = []
1545 if not patches: 1578 if not patches:
1546 patchset.key.delete() 1579 patchset.key.delete()
(...skipping 503 matching lines...) Expand 10 before | Expand all | Expand 10 after
2050 logging.info("Updating %d patches", len(patches)) 2083 logging.info("Updating %d patches", len(patches))
2051 ndb.put_multi(patches) 2084 ndb.put_multi(patches)
2052 2085
2053 2086
2054 @deco.require_methods('POST') 2087 @deco.require_methods('POST')
2055 @deco.issue_editor_required 2088 @deco.issue_editor_required
2056 @deco.xsrf_required 2089 @deco.xsrf_required
2057 def delete(request): 2090 def delete(request):
2058 """/<issue>/delete - Delete an issue. There is no way back.""" 2091 """/<issue>/delete - Delete an issue. There is no way back."""
2059 issue = request.issue 2092 issue = request.issue
2093 # Update the dependents to remove dependency on this issue.
2094 dependency_utils.remove_dependencies_from_all_patchsets(issue)
2095 # Remove this issue as a dependent.
2096 dependency_utils.remove_all_patchsets_as_dependents(issue)
2097
2060 tbd = [issue] 2098 tbd = [issue]
2061 for cls in [models.PatchSet, models.Patch, models.Comment, 2099 for cls in [models.PatchSet, models.Patch, models.Comment,
2062 models.Message, models.Content, models.TryJobResult]: 2100 models.Message, models.Content, models.TryJobResult]:
2063 tbd += cls.query(ancestor=issue.key) 2101 tbd += cls.query(ancestor=issue.key)
2064 ndb.delete_multi(entity.key for entity in tbd) 2102 ndb.delete_multi(entity.key for entity in tbd)
2065 return HttpResponseRedirect(reverse(mine)) 2103 return HttpResponseRedirect(reverse(mine))
2066 2104
2067 2105
2068 @deco.require_methods('POST') 2106 @deco.require_methods('POST')
2069 @deco.patchset_editor_required 2107 @deco.patchset_editor_required
2070 @deco.xsrf_required 2108 @deco.xsrf_required
2071 def delete_patchset(request): 2109 def delete_patchset(request):
2072 """/<issue>/patch/<patchset>/delete - Delete a patchset. 2110 """/<issue>/patch/<patchset>/delete - Delete a patchset.
2073 2111
2074 There is no way back. 2112 There is no way back.
2075 """ 2113 """
2076 # Log patchset deletion. 2114 # Log patchset deletion.
2077 patchset_num = 0 2115 patchset_num = 0
2078 for patchset in list(request.issue.patchsets): 2116 for patchset in list(request.issue.patchsets):
2079 patchset_num += 1 2117 patchset_num += 1
2080 if patchset.key.id() == request.patchset.key.id(): 2118 if patchset.key.id() == request.patchset.key.id():
2081 break 2119 break
2082 delete_msg = 'Patchset #%s (id:%s) has been deleted' % ( 2120 delete_msg = 'Patchset #%s (id:%s) has been deleted' % (
2083 patchset_num, request.patchset.key.id()) 2121 patchset_num, request.patchset.key.id())
2084 make_message(request, request.issue, delete_msg, send_mail=False, 2122 make_message(request, request.issue, delete_msg, send_mail=False,
2085 auto_generated=True).put() 2123 auto_generated=True).put()
2124 # Update all dependents of this patchset.
2125 dependency_utils.remove_dependencies(request.patchset)
2126 # Remove this patchset as a dependent.
2127 dependency_utils.remove_as_dependent(request.patchset)
2086 # Delete the patchset. 2128 # Delete the patchset.
2087 request.patchset.nuke() 2129 request.patchset.nuke()
2088 return HttpResponseRedirect(reverse(show, args=[request.issue.key.id()])) 2130 return HttpResponseRedirect(reverse(show, args=[request.issue.key.id()]))
2089 2131
2090 2132
2091 @deco.require_methods('POST') 2133 @deco.require_methods('POST')
2092 @deco.issue_editor_required 2134 @deco.issue_editor_required
2093 @deco.xsrf_required 2135 @deco.xsrf_required
2094 def close(request): 2136 def close(request):
2095 """/<issue>/close - Close an issue.""" 2137 """/<issue>/close - Close an issue."""
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
2363 values = { 2405 values = {
2364 'patchset': patchset.key.id(), 2406 'patchset': patchset.key.id(),
2365 'issue': issue.key.id(), 2407 'issue': issue.key.id(),
2366 'owner': library.get_nickname(issue.owner, True, request), 2408 'owner': library.get_nickname(issue.owner, True, request),
2367 'owner_email': issue.owner.email(), 2409 'owner_email': issue.owner.email(),
2368 'message': patchset.message, 2410 'message': patchset.message,
2369 'url': patchset.url, 2411 'url': patchset.url,
2370 'created': str(patchset.created), 2412 'created': str(patchset.created),
2371 'modified': str(patchset.modified), 2413 'modified': str(patchset.modified),
2372 'num_comments': patchset.num_comments, 2414 'num_comments': patchset.num_comments,
2415 'depends_on_patchset': patchset.depends_on_patchset,
2416 'dependent_patchsets': patchset.dependent_patchsets,
2373 'files': {}, 2417 'files': {},
2374 } 2418 }
2375 if (try_jobs): 2419 if (try_jobs):
2376 values['try_job_results'] = [ 2420 values['try_job_results'] = [
2377 t.to_dict() for t in patchset.try_job_results] 2421 t.to_dict() for t in patchset.try_job_results]
2378 2422
2379 all_no_base_file_keys_future = models.Content.query( 2423 all_no_base_file_keys_future = models.Content.query(
2380 models.Content.file_too_large == True, 2424 models.Content.file_too_large == True,
2381 ancestor=patchset.key).fetch_async(10000, keys_only=True, batch_size=1000) 2425 ancestor=patchset.key).fetch_async(10000, keys_only=True, batch_size=1000)
2382 patches_future = models.Patch.query(ancestor=patchset.key).fetch_async( 2426 patches_future = models.Patch.query(ancestor=patchset.key).fetch_async(
(...skipping 3005 matching lines...) Expand 10 before | Expand all | Expand 10 after
5388 return HttpResponseNotFound() 5432 return HttpResponseNotFound()
5389 tops = [] 5433 tops = []
5390 shame = [] 5434 shame = []
5391 for i in data: 5435 for i in data:
5392 if i.score == models.AccountStatsBase.NULL_SCORE: 5436 if i.score == models.AccountStatsBase.NULL_SCORE:
5393 shame.append(i) 5437 shame.append(i)
5394 else: 5438 else:
5395 tops.append(i) 5439 tops.append(i)
5396 return respond( 5440 return respond(
5397 request, 'leaderboard.html', {'tops': tops, 'shame': shame, 'when': when}) 5441 request, 'leaderboard.html', {'tops': tops, 'shame': shame, 'when': when})
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698