summaryrefslogtreecommitdiffstats
path: root/subcmds/upload.py
diff options
context:
space:
mode:
authorDoug Anderson <dianders@google.com>2011-03-04 11:54:18 -0800
committerShawn O. Pearce <sop@google.com>2011-03-11 11:53:23 -0800
commit37282b4b9c5b1d9a1ff07f7f0686a81b65a0a5c6 (patch)
treeaba568b85d38de4cfef90cd771169c9422aef09c /subcmds/upload.py
parent835cd6888f16ff30a3428adfa3a775efad918880 (diff)
downloadgit-repo-37282b4b9c5b1d9a1ff07f7f0686a81b65a0a5c6.tar.gz
Support repo-level pre-upload hook and prep for future hooks.v1.7.4
All repo-level hooks are expected to live in a single project at the top level of that project. The name of the hooks project is provided in the manifest.xml. The manifest also lists which hooks are enabled to make it obvious if a file somehow failed to sync down (or got deleted). Before running any hook, we will prompt the user to make sure that it is OK. A user can deny running the hook, allow once, or allow "forever" (until hooks change). This tries to keep with the git spirit of not automatically running anything on the user's computer that got synced down. Note that individual repo commands can add always options to avoid these prompts as they see fit (see below for the 'upload' options). When hooks are run, they are loaded into the current interpreter (the one running repo) and their main() function is run. This mechanism is used (instead of using subprocess) to make it easier to expand to a richer hook interface in the future. During loading, the interpreter's sys.path is updated to contain the directory containing the hooks so that hooks can be split into multiple files. The upload command has two options that control hook behavior: - no-verify=False, verify=False (DEFAULT): If stdout is a tty, can prompt about running upload hooks if needed. If user denies running hooks, the upload is cancelled. If stdout is not a tty and we would need to prompt about upload hooks, upload is cancelled. - no-verify=False, verify=True: Always run upload hooks with no prompt. - no-verify=True, verify=False: Never run upload hooks, but upload anyway (AKA bypass hooks). - no-verify=True, verify=True: Invalid Sample bit of manifest.xml code for enabling hooks (assumes you have a project named 'hooks' where hooks are stored): <repo-hooks in-project="hooks" enabled-list="pre-upload" /> Sample main() function in pre-upload.py in hooks directory: def main(project_list, **kwargs): print ('These projects will be uploaded: %s' % ', '.join(project_list)) print ('I am being a good boy and ignoring anything in kwargs\n' 'that I don\'t understand.') print 'I fail 50% of the time. How flaky.' if random.random() <= .5: raise Exception('Pre-upload hook failed. Have a nice day.') Change-Id: I5cefa2cd5865c72589263cf8e2f152a43c122f70
Diffstat (limited to 'subcmds/upload.py')
-rw-r--r--subcmds/upload.py46
1 files changed, 40 insertions, 6 deletions
diff --git a/subcmds/upload.py b/subcmds/upload.py
index 20822096..c561b8aa 100644
--- a/subcmds/upload.py
+++ b/subcmds/upload.py
@@ -19,7 +19,8 @@ import sys
19 19
20from command import InteractiveCommand 20from command import InteractiveCommand
21from editor import Editor 21from editor import Editor
22from error import UploadError 22from error import HookError, UploadError
23from project import RepoHook
23 24
24UNUSUAL_COMMIT_THRESHOLD = 5 25UNUSUAL_COMMIT_THRESHOLD = 5
25 26
@@ -120,6 +121,29 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
120 type='string', action='append', dest='cc', 121 type='string', action='append', dest='cc',
121 help='Also send email to these email addresses.') 122 help='Also send email to these email addresses.')
122 123
124 # Options relating to upload hook. Note that verify and no-verify are NOT
125 # opposites of each other, which is why they store to different locations.
126 # We are using them to match 'git commit' syntax.
127 #
128 # Combinations:
129 # - no-verify=False, verify=False (DEFAULT):
130 # If stdout is a tty, can prompt about running upload hooks if needed.
131 # If user denies running hooks, the upload is cancelled. If stdout is
132 # not a tty and we would need to prompt about upload hooks, upload is
133 # cancelled.
134 # - no-verify=False, verify=True:
135 # Always run upload hooks with no prompt.
136 # - no-verify=True, verify=False:
137 # Never run upload hooks, but upload anyway (AKA bypass hooks).
138 # - no-verify=True, verify=True:
139 # Invalid
140 p.add_option('--no-verify',
141 dest='bypass_hooks', action='store_true',
142 help='Do not run the upload hook.')
143 p.add_option('--verify',
144 dest='allow_all_hooks', action='store_true',
145 help='Run the upload hook without prompting.')
146
123 def _SingleBranch(self, opt, branch, people): 147 def _SingleBranch(self, opt, branch, people):
124 project = branch.project 148 project = branch.project
125 name = branch.name 149 name = branch.name
@@ -313,17 +337,27 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
313 reviewers = [] 337 reviewers = []
314 cc = [] 338 cc = []
315 339
340 for project in project_list:
341 avail = project.GetUploadableBranches()
342 if avail:
343 pending.append((project, avail))
344
345 if pending and (not opt.bypass_hooks):
346 hook = RepoHook('pre-upload', self.manifest.repo_hooks_project,
347 self.manifest.topdir, abort_if_user_denies=True)
348 pending_proj_names = [project.name for (project, avail) in pending]
349 try:
350 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names)
351 except HookError, e:
352 print >>sys.stderr, "ERROR: %s" % str(e)
353 return
354
316 if opt.reviewers: 355 if opt.reviewers:
317 reviewers = _SplitEmails(opt.reviewers) 356 reviewers = _SplitEmails(opt.reviewers)
318 if opt.cc: 357 if opt.cc:
319 cc = _SplitEmails(opt.cc) 358 cc = _SplitEmails(opt.cc)
320 people = (reviewers,cc) 359 people = (reviewers,cc)
321 360
322 for project in project_list:
323 avail = project.GetUploadableBranches()
324 if avail:
325 pending.append((project, avail))
326
327 if not pending: 361 if not pending:
328 print >>sys.stdout, "no branches ready for upload" 362 print >>sys.stdout, "no branches ready for upload"
329 elif len(pending) == 1 and len(pending[0][1]) == 1: 363 elif len(pending) == 1 and len(pending[0][1]) == 1: