OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Enables directory-specific presubmit checks to run at upload and/or commit. | 6 """Enables directory-specific presubmit checks to run at upload and/or commit. |
7 """ | 7 """ |
8 | 8 |
9 __version__ = '1.8.0' | 9 __version__ = '1.8.0' |
10 | 10 |
(...skipping 18 matching lines...) Expand all Loading... |
29 import pickle # Exposed through the API. | 29 import pickle # Exposed through the API. |
30 import random | 30 import random |
31 import re # Exposed through the API. | 31 import re # Exposed through the API. |
32 import sys # Parts exposed through API. | 32 import sys # Parts exposed through API. |
33 import tempfile # Exposed through the API. | 33 import tempfile # Exposed through the API. |
34 import time | 34 import time |
35 import traceback # Exposed through the API. | 35 import traceback # Exposed through the API. |
36 import types | 36 import types |
37 import unittest # Exposed through the API. | 37 import unittest # Exposed through the API. |
38 import urllib2 # Exposed through the API. | 38 import urllib2 # Exposed through the API. |
| 39 import urlparse |
39 from warnings import warn | 40 from warnings import warn |
40 | 41 |
41 # Local imports. | 42 # Local imports. |
42 import auth | 43 import auth |
43 import fix_encoding | 44 import fix_encoding |
44 import gclient_utils | 45 import gclient_utils |
| 46 import gerrit_util |
45 import owners | 47 import owners |
46 import presubmit_canned_checks | 48 import presubmit_canned_checks |
47 import rietveld | 49 import rietveld |
48 import scm | 50 import scm |
49 import subprocess2 as subprocess # Exposed through the API. | 51 import subprocess2 as subprocess # Exposed through the API. |
50 | 52 |
51 | 53 |
52 # Ask for feedback only once in program lifetime. | 54 # Ask for feedback only once in program lifetime. |
53 _ASKED_FOR_FEEDBACK = False | 55 _ASKED_FOR_FEEDBACK = False |
54 | 56 |
(...skipping 1580 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1635 "system directories will also be searched.") | 1637 "system directories will also be searched.") |
1636 parser.add_option("--upstream", | 1638 parser.add_option("--upstream", |
1637 help="Git only: the base ref or upstream branch against " | 1639 help="Git only: the base ref or upstream branch against " |
1638 "which the diff should be computed.") | 1640 "which the diff should be computed.") |
1639 parser.add_option("--default_presubmit") | 1641 parser.add_option("--default_presubmit") |
1640 parser.add_option("--may_prompt", action='store_true', default=False) | 1642 parser.add_option("--may_prompt", action='store_true', default=False) |
1641 parser.add_option("--skip_canned", action='append', default=[], | 1643 parser.add_option("--skip_canned", action='append', default=[], |
1642 help="A list of checks to skip which appear in " | 1644 help="A list of checks to skip which appear in " |
1643 "presubmit_canned_checks. Can be provided multiple times " | 1645 "presubmit_canned_checks. Can be provided multiple times " |
1644 "to skip multiple canned checks.") | 1646 "to skip multiple canned checks.") |
| 1647 parser.add_option("--gerrit_url", help=optparse.SUPPRESS_HELP) |
| 1648 parser.add_option("--gerrit_fetch", help=optparse.SUPPRESS_HELP) |
1645 parser.add_option("--rietveld_url", help=optparse.SUPPRESS_HELP) | 1649 parser.add_option("--rietveld_url", help=optparse.SUPPRESS_HELP) |
1646 parser.add_option("--rietveld_email", help=optparse.SUPPRESS_HELP) | 1650 parser.add_option("--rietveld_email", help=optparse.SUPPRESS_HELP) |
1647 parser.add_option("--rietveld_fetch", action='store_true', default=False, | 1651 parser.add_option("--rietveld_fetch", action='store_true', default=False, |
1648 help=optparse.SUPPRESS_HELP) | 1652 help=optparse.SUPPRESS_HELP) |
1649 # These are for OAuth2 authentication for bots. See also apply_issue.py | 1653 # These are for OAuth2 authentication for bots. See also apply_issue.py |
1650 parser.add_option("--rietveld_email_file", help=optparse.SUPPRESS_HELP) | 1654 parser.add_option("--rietveld_email_file", help=optparse.SUPPRESS_HELP) |
1651 parser.add_option("--rietveld_private_key_file", help=optparse.SUPPRESS_HELP) | 1655 parser.add_option("--rietveld_private_key_file", help=optparse.SUPPRESS_HELP) |
1652 | 1656 |
1653 # TODO(phajdan.jr): Update callers and remove obsolete --trybot-json . | 1657 # TODO(phajdan.jr): Update callers and remove obsolete --trybot-json . |
1654 parser.add_option("--trybot-json", | 1658 parser.add_option("--trybot-json", |
1655 help="Output trybot information to the file specified.") | 1659 help="Output trybot information to the file specified.") |
1656 auth.add_auth_options(parser) | 1660 auth.add_auth_options(parser) |
1657 options, args = parser.parse_args(argv) | 1661 options, args = parser.parse_args(argv) |
1658 auth_config = auth.extract_auth_config_from_options(options) | 1662 auth_config = auth.extract_auth_config_from_options(options) |
1659 | 1663 |
1660 if options.verbose >= 2: | 1664 if options.verbose >= 2: |
1661 logging.basicConfig(level=logging.DEBUG) | 1665 logging.basicConfig(level=logging.DEBUG) |
1662 elif options.verbose: | 1666 elif options.verbose: |
1663 logging.basicConfig(level=logging.INFO) | 1667 logging.basicConfig(level=logging.INFO) |
1664 else: | 1668 else: |
1665 logging.basicConfig(level=logging.ERROR) | 1669 logging.basicConfig(level=logging.ERROR) |
1666 | 1670 |
| 1671 if (any((options.rietveld_url, options.rietveld_email_file, |
| 1672 options.rietveld_fetch, options.rietveld_private_key_file)) |
| 1673 and any((options.gerrit_url, options.gerrit_fetch))): |
| 1674 parser.error('Options for only codereview --rietveld_* or --gerrit_* ' |
| 1675 'allowed') |
| 1676 |
1667 if options.rietveld_email and options.rietveld_email_file: | 1677 if options.rietveld_email and options.rietveld_email_file: |
1668 parser.error("Only one of --rietveld_email or --rietveld_email_file " | 1678 parser.error("Only one of --rietveld_email or --rietveld_email_file " |
1669 "can be passed to this program.") | 1679 "can be passed to this program.") |
1670 | |
1671 if options.rietveld_email_file: | 1680 if options.rietveld_email_file: |
1672 with open(options.rietveld_email_file, "rb") as f: | 1681 with open(options.rietveld_email_file, "rb") as f: |
1673 options.rietveld_email = f.read().strip() | 1682 options.rietveld_email = f.read().strip() |
1674 | 1683 |
1675 change_class, files = load_files(options, args) | 1684 change_class, files = load_files(options, args) |
1676 if not change_class: | 1685 if not change_class: |
1677 parser.error('For unversioned directory, <files> is not optional.') | 1686 parser.error('For unversioned directory, <files> is not optional.') |
1678 logging.info('Found %d file(s).' % len(files)) | 1687 logging.info('Found %d file(s).' % len(files)) |
1679 | 1688 |
1680 rietveld_obj = None | 1689 rietveld_obj = None |
1681 if options.rietveld_url: | 1690 if options.rietveld_url: |
1682 # The empty password is permitted: '' is not None. | 1691 # The empty password is permitted: '' is not None. |
1683 if options.rietveld_private_key_file: | 1692 if options.rietveld_private_key_file: |
1684 rietveld_obj = rietveld.JwtOAuth2Rietveld( | 1693 rietveld_obj = rietveld.JwtOAuth2Rietveld( |
1685 options.rietveld_url, | 1694 options.rietveld_url, |
1686 options.rietveld_email, | 1695 options.rietveld_email, |
1687 options.rietveld_private_key_file) | 1696 options.rietveld_private_key_file) |
1688 else: | 1697 else: |
1689 rietveld_obj = rietveld.CachingRietveld( | 1698 rietveld_obj = rietveld.CachingRietveld( |
1690 options.rietveld_url, | 1699 options.rietveld_url, |
1691 auth_config, | 1700 auth_config, |
1692 options.rietveld_email) | 1701 options.rietveld_email) |
1693 if options.rietveld_fetch: | 1702 if options.rietveld_fetch: |
1694 assert options.issue | 1703 assert options.issue |
1695 props = rietveld_obj.get_issue_properties(options.issue, False) | 1704 props = rietveld_obj.get_issue_properties(options.issue, False) |
1696 options.author = props['owner_email'] | 1705 options.author = props['owner_email'] |
1697 options.description = props['description'] | 1706 options.description = props['description'] |
1698 logging.info('Got author: "%s"', options.author) | 1707 logging.info('Got author: "%s"', options.author) |
1699 logging.info('Got description: """\n%s\n"""', options.description) | 1708 logging.info('Got description: """\n%s\n"""', options.description) |
| 1709 |
| 1710 if options.gerrit_url and options.gerrit_fetch: |
| 1711 rietveld_obj = None |
| 1712 assert options.issue and options.patchset |
| 1713 props = gerrit_util.GetChangeDetail( |
| 1714 urlparse.urlparse(options.gerrit_url).netloc, str(options.issue), |
| 1715 ['ALL_REVISIONS']) |
| 1716 options.author = props['owner']['email'] |
| 1717 for rev, rev_info in props['revisions'].iteritems(): |
| 1718 if str(rev_info['_number']) == str(options.patchset): |
| 1719 options.description = gerrit_util.GetChangeDescriptionFromGitiles( |
| 1720 rev_info['fetch']['http']['url'], rev) |
| 1721 break |
| 1722 else: |
| 1723 print >> sys.stderr, ('Patchset %d was not found in Gerrit issue %d' % |
| 1724 options.patchset, options.issue) |
| 1725 return 2 |
| 1726 logging.info('Got author: "%s"', options.author) |
| 1727 logging.info('Got description: """\n%s\n"""', options.description) |
| 1728 |
1700 try: | 1729 try: |
1701 with canned_check_filter(options.skip_canned): | 1730 with canned_check_filter(options.skip_canned): |
1702 results = DoPresubmitChecks( | 1731 results = DoPresubmitChecks( |
1703 change_class(options.name, | 1732 change_class(options.name, |
1704 options.description, | 1733 options.description, |
1705 options.root, | 1734 options.root, |
1706 files, | 1735 files, |
1707 options.issue, | 1736 options.issue, |
1708 options.patchset, | 1737 options.patchset, |
1709 options.author, | 1738 options.author, |
(...skipping 17 matching lines...) Expand all Loading... |
1727 return 2 | 1756 return 2 |
1728 | 1757 |
1729 | 1758 |
1730 if __name__ == '__main__': | 1759 if __name__ == '__main__': |
1731 fix_encoding.fix_encoding() | 1760 fix_encoding.fix_encoding() |
1732 try: | 1761 try: |
1733 sys.exit(main()) | 1762 sys.exit(main()) |
1734 except KeyboardInterrupt: | 1763 except KeyboardInterrupt: |
1735 sys.stderr.write('interrupted\n') | 1764 sys.stderr.write('interrupted\n') |
1736 sys.exit(1) | 1765 sys.exit(1) |
OLD | NEW |