diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | LICENSE | 202 | ||||
-rw-r--r-- | README.md | 24 | ||||
-rw-r--r-- | doc/conf.py | 216 | ||||
-rw-r--r-- | doc/index.rst | 45 | ||||
-rwxr-xr-x | git-review | 251 | ||||
-rwxr-xr-x | setup.py | 57 |
8 files changed, 799 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0dfcadf --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build +dist +git_review.egg-info @@ -0,0 +1 @@ +Monty Taylor <mordred@inaugust.com> @@ -0,0 +1,202 @@ +
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/README.md b/README.md new file mode 100644 index 0000000..b4ee04e --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# git-review: A git command for submitting branches to Gerrit + +git-review is a tool that helps submitting git branches to gerrit for review + +# Assumptions + +git-review, by default, looks for a git remote called gerrit, and submits +the current branch to HEAD:refs/for/master at that remote. + +# Usage + +Hack on some code, then: + + git review + +If you want to submit that code to a different target branch, then: + + git review branchname + +If you want to submit to a different remote: + + git -r my-remote review + + diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 0000000..57bfdaa --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- +# +# git-review documentation build configuration file, created by +# sphinx-quickstart on Mon Jul 18 13:42:23 2011. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os, datetime + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'git-review' +copyright = u'2011, OpenStack, LLC' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = "%d.%02d" % (datetime.datetime.now().year, datetime.datetime.now().month) +# The full version, including alpha/beta/rc tags. +release = "%d.%02d.%02d" % (datetime.datetime.now().year, datetime.datetime.now().month, datetime.datetime.now().day) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'OpenStackCIdoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'OpenStackCI.tex', u'git-review Documentation', + u'OpenStack, LLC', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'git-review', u'Submit changes to Gerrit for review', + [u'OpenStack, LLC'], 1) +] diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 0000000..6476fc1 --- /dev/null +++ b/doc/index.rst @@ -0,0 +1,45 @@ +.. git-review documentation master file, created by + sphinx-quickstart on Sun Sep 25 09:00:23 2011. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +========== +git-review +========== + +SYNOPSIS +-------- + +:program:`git-review` [:ref:`OPTIONS <git-review-options-label`] [*BRANCH*] + +DESCRIPTION +----------- + +:program:`git-review` automates and streamlines some of the tasks involve with +submitting local changes to a *Gerrit* server for review. + +.. _git-review-options-label: + +OPTIONS +------- + +.. program:: git-review + +.. option:: --topic, -t + + Sets the target topic for this change on the gerrit server. + +.. option:: --dry-run, -n + + Don't actually perform any commands that have direct effects. Print them + instead. + +.. option:: --no-rebase, -R + + Do not automatically perform a rebase before submitting the change to + gerrit. + +.. option:: --verbose, -v + + Turns on more verbose output. + diff --git a/git-review b/git-review new file mode 100755 index 0000000..d9617b7 --- /dev/null +++ b/git-review @@ -0,0 +1,251 @@ +#!/usr/bin/env python +# Copyright 2011 OpenStack, LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import commands +import optparse + +import os +import sys + +VERBOSE = False + + +def set_hooks_commit_msg(hostname="review.openstack.org"): + + top_dir = commands.getoutput('git rev-parse --show-toplevel') + target_file = os.path.join(top_dir, ".git/hooks/commit-msg") + source_location = "https://%s/tools/hooks/commit-msg" % hostname + + if os.path.exists(target_file) and os.access(target_file, os.X_OK): + return + + if not os.path.exists(target_file): + import urllib + if VERBOSE: + print "Fetching source_location: ", source_location + commit_msg = urllib.urlretrieve(source_location, target_file) + + if not os.access(target_file, os.X_OK): + os.chmod(target_file, os.path.stat.S_IREAD | os.path.stat.S_IEXEC) + + commands.getoutput("GIT_EDITOR=true git commit --amend") + + +def add_remote(username, hostname, port, project): + """ Returns the remote host that was found """ + + if username is None: + username = os.getenv("USERNAME") + if port is None: + port = 29418 + + remote_url = "ssh://%s@%s:%s/%s.git" % (username, hostname, port, project) + print "No remote set, testing %s" % remote_url + + ssh_cmd = "ssh -p%s -o StrictHostKeyChecking=no %s@%s gerrit ls-projects" + cmd = ssh_cmd % (port, username, hostname) + (status, ssh_outout) = commands.getstatusoutput(cmd) + if status == 0: + print "%s@%s:%s worked." % (username, hostname, port) + print "Creating a git remote called gerrit that maps to:" + print "\t%s" % remote_url + cmd = "git remote add -f gerrit %s" % remote_url + (status, remote_output) = commands.getstatusoutput(cmd) + + if status != 0: + raise Exception("Error running %s" % cmd) + + +def split_hostname(hostname): + + from urlparse import urlparse + + parsed_url = urlparse(fetch_url) + username = None + hostname = parsed_url.netloc + port = 22 + + if "@" in hostname: + (username, hostname) = hostname.split("@") + if ":" in hostname: + (hostname, port) = hostname.split(":") + + # Is origin an ssh location? Let's pull more info + if parsed_url.scheme == "ssh": + return (username, hostname, port) + else: + return (None, hostname, None) + + +def map_known_locations(hostname, team, project): + # Assume that if we don't know about it, it's a proper gerrit location + if VERBOSE: + print "Mapping %s, %s, %s to a gerrit" % (hostname, team, project) + + openstack_projects = ["nova", "swift", "glance", "keystone", "quantum", + "openstack-dashboard"] + if hostname == "github.com": + # Welp, OBVIOUSLY _this_ isn't a gerrit + if team is not None and team == "openstack" or \ + project in openstack_projects: + return ("review.openstack.org", "openstack/%s" % project) + else: + raise Exception("No possible way to guess given the input") + return hostname + + +def check_remote(): + + if "gerrit" in commands.getoutput("git remote").split("\n"): + + for remote in commands.getoutput("git branch -a").split("\n"): + if remote.strip() == "remotes/gerrit/master": + return + # We have the remote, but aren't set up to fetch. Fix it + if VERBOSE: + print "Setting up gerrit branch tracking for better rebasing" + commands.getoutput("git remote update gerrit") + return + + fetch_url = "" + for line in commands.getoutput("git remote show -n origin").split("\n"): + if line.strip().startswith("Fetch URL"): + fetch_url = ":".join(line.split(":")[1:]).strip() + + project_name = fetch_url.split("/")[-1] + if project_name.endswith(".git"): + project_name = project_name[:-4] + + hostname = None + team = None + username = None + port = None + + # Special-case git@github urls - the rest can be parsed with urlparse + if fetch_url.startswith("git@github.com"): + hostname = "github.com" + team = fetch_url.split(":")[1].split("/")[0] + else: + (username, hostname, port) = split_hostname(fetch_url) + + #try: + (hostname, project) = map_known_locations(hostname, team, project_name) + add_remote(username, hostname, port, project) + #except: + # print sys.exc_info()[2] + # print "We don't know where your gerrit is. Please manually create " + # print "a remote named gerrit and try again." + # sys.exit(1) + + return hostname + + +def rebase_changes(branch): + + cmd = "GIT_EDITOR=true git rebase -i gerrit/%s" % branch + (status, output) = commands.getstatusoutput(cmd) + if status != 0: + print "Couldn't run %s" % cmd + print output + sys.exit(1) + + +def assert_diverge(branch): + + cmd = "git diff gerrit/%s..HEAD" % branch + (status, output) = commands.getstatusoutput(cmd) + if len(output) == 0: + print "No changes between HEAD and gerrit/%s." % branch + print "Submitting for review would be pointless." + sys.exit(1) + if status != 0: + print "Had trouble running %s" % cmd + sys.exit(1) + + +def get_topic(): + + import re + + log_output = commands.getoutput("git show --format='%s %b'") + bug_re = r'\b([Bb]ug|[Ll][Pp])\s*[#:]?\s*(\d+)' + + match = re.search(bug_re, log_output) + if match is not None: + return match.group(2) + + bp_re = r'\b([Bb]lue[Pp]rint|[Bb][Pp])\s*[#:]?\s*([0-9a-zA-Z-_]+)' + match = re.search(bp_re, log_output) + if match is not None: + return match.group(2) + + for branch in commands.getoutput("git branch").split("\n"): + if branch.startswith('*'): + return branch.split()[1].strip() + + +def main(): + + usage = "git review [OPTIONS] ... [BRANCH]" + parser = optparse.OptionParser(usage=usage) + parser.add_option("-t", "--topic", dest="topic", + help="Topic to submit branch to") + parser.add_option("-n", "--dry-run", dest="dry", action="store_true", + help="Don't actually submit the branch for review") + parser.add_option("-R", "--no-rebase", dest="rebase", + action="store_false", + help="Don't rebase changes before submitting.") + parser.add_option("-v", "--verbose", dest="verbose", action="store_true", + help="Output more information about what's going on") + parser.set_defaults(dry=False, rebase=True, verbose=False) + + branch = "master" + (options, args) = parser.parse_args() + if len(args) > 0: + branch = args[0] + global VERBOSE + VERBOSE = options.verbose + + topic = options.topic + if topic is None: + topic = get_topic() + if VERBOSE: + print "Found topic '%s' from parsing changes." % topic + + drier = "" + if options.dry: + drier = "echo -e Please use the following command " \ + "to send your commits to review:\n\n" + + # TODO: when/should we do this so that it's not slow? + #cmd = "git fetch gerrit %s" % branch + #(status, output) = commands.getstatusoutput(cmd) + + hostname = check_remote() + + set_hooks_commit_msg(hostname) + + if options.rebase: + rebase_changes(branch) + assert_diverge(branch) + + cmd = "%s git push gerrit HEAD:refs/for/%s/%s" % (drier, branch, topic) + (status, output) = commands.getstatusoutput(cmd) + print output + sys.exit(status) + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..c1e58d1 --- /dev/null +++ b/setup.py @@ -0,0 +1,57 @@ +#!/usr/bin/python +# Copyright (c) 2010-2011 OpenStack, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from setuptools import setup, find_packages + +version = '1.0' + +cmdclass = {} + +# If Sphinx is installed on the box running setup.py, +# enable setup.py to build the documentation, otherwise, +# just ignore it +try: + from sphinx.setup_command import BuildDoc + + class local_BuildDoc(BuildDoc): + def run(self): + for builder in ['html', 'man']: + self.builder = builder + self.finalize_options() + BuildDoc.run(self) + cmdclass['build_sphinx'] = local_BuildDoc + +except: + pass + +setup( + name='git-review', + version=version, + description="Tool to submit code to Gerrit", + license='Apache License (2.0)', + classifiers=["Programming Language :: Python"], + keywords='git gerrit review', + author='OpenStack, LLC.', + author_email='openstack@lists.launchpad.net', + url='http://www.openstack.org', + include_package_data=True, + #packages=find_packages(exclude=['test', 'bin']), + scripts=['git-review'], + zip_safe=False, + cmdclass=cmdclass, + install_requires=['setuptools'], + test_suite='nose.collector', + ) |