libv8 5.7.492.65.1 → 5.9.211.38.0beta0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +8 -2
- data/CHANGELOG.md +4 -0
- data/README.md +4 -3
- data/Rakefile +27 -10
- data/ext/libv8/builder.rb +4 -0
- data/lib/libv8/version.rb +1 -1
- data/libv8.gemspec +1 -1
- data/patches/0001-Build-a-standalone-static-library.patch +5 -5
- data/patches/0002-Don-t-compile-unnecessary-stuff.patch +20 -24
- data/patches/0003-Use-the-fPIC-flag-for-the-static-library.patch +5 -5
- data/patches/0004-Do-not-embed-debug-symbols-in-macOS-libraries.patch +5 -5
- data/patches/0005-Fix-GCC-7-build-errors.patch +147 -0
- data/scaleway.png +0 -0
- data/vendor/depot_tools/.gitattributes +52 -0
- data/vendor/depot_tools/.gitignore +10 -0
- data/vendor/depot_tools/README.md +7 -3
- data/vendor/depot_tools/apply_issue.bat +4 -3
- data/vendor/depot_tools/apply_issue.py +0 -10
- data/vendor/depot_tools/autoninja +12 -0
- data/vendor/depot_tools/autoninja.bat +9 -0
- data/vendor/depot_tools/autoninja.py +70 -0
- data/vendor/depot_tools/bootstrap/win/README.md +108 -26
- data/vendor/depot_tools/bootstrap/win/git-bash.template.sh +3 -3
- data/vendor/depot_tools/bootstrap/win/git.template.bat +2 -2
- data/vendor/depot_tools/bootstrap/win/manifest.txt +18 -0
- data/vendor/depot_tools/bootstrap/win/manifest_bleeding_edge.txt +18 -0
- data/vendor/depot_tools/bootstrap/win/python27.new.bat +49 -0
- data/vendor/depot_tools/bootstrap/win/win_tools.bat +55 -59
- data/vendor/depot_tools/bootstrap/win/win_tools.py +335 -0
- data/vendor/depot_tools/cipd +16 -2
- data/vendor/depot_tools/cipd.bat +20 -2
- data/vendor/depot_tools/cipd.ps1 +36 -22
- data/vendor/depot_tools/cipd_bin_setup.bat +6 -0
- data/vendor/depot_tools/cipd_bin_setup.sh +10 -0
- data/vendor/depot_tools/cipd_client_version +1 -1
- data/vendor/depot_tools/cipd_manifest.txt +9 -0
- data/vendor/depot_tools/cit.bat +12 -11
- data/vendor/depot_tools/clang-format.bat +4 -3
- data/vendor/depot_tools/clang_format_merge_driver.bat +12 -11
- data/vendor/depot_tools/commit_queue.bat +4 -3
- data/vendor/depot_tools/cpplint.bat +9 -3
- data/vendor/depot_tools/cpplint.py +3 -3
- data/vendor/depot_tools/depot-tools-auth.bat +4 -3
- data/vendor/depot_tools/download_from_google_storage.bat +5 -3
- data/vendor/depot_tools/download_from_google_storage.py +6 -1
- data/vendor/depot_tools/fetch.bat +5 -4
- data/vendor/depot_tools/fetch.py +4 -5
- data/vendor/depot_tools/gclient-new-workdir.py +82 -46
- data/vendor/depot_tools/gclient.bat +5 -4
- data/vendor/depot_tools/gclient.py +713 -319
- data/vendor/depot_tools/gclient_eval.py +284 -0
- data/vendor/depot_tools/gclient_utils.py +70 -4
- data/vendor/depot_tools/gerrit_client.py +26 -1
- data/vendor/depot_tools/gerrit_util.py +120 -127
- data/vendor/depot_tools/git-crrev-parse +1 -0
- data/vendor/depot_tools/git-gs +1 -1
- data/vendor/depot_tools/git_cl.py +731 -415
- data/vendor/depot_tools/git_common.py +23 -3
- data/vendor/depot_tools/git_drover.py +10 -1
- data/vendor/depot_tools/git_footers.py +62 -22
- data/vendor/depot_tools/git_hyper_blame.py +3 -2
- data/vendor/depot_tools/git_map.py +30 -3
- data/vendor/depot_tools/git_map_branches.py +18 -4
- data/vendor/depot_tools/git_number.py +8 -2
- data/vendor/depot_tools/git_retry.py +21 -0
- data/vendor/depot_tools/gn.bat +4 -3
- data/vendor/depot_tools/infra/config/cq.cfg +1 -5
- data/vendor/depot_tools/infra/config/recipes.cfg +18 -16
- data/vendor/depot_tools/led +12 -0
- data/vendor/depot_tools/led.bat +7 -0
- data/vendor/depot_tools/man/html/git-cl.html +9 -1
- data/vendor/depot_tools/man/html/git-drover.html +22 -18
- data/vendor/depot_tools/man/man1/git-cl.1 +8 -3
- data/vendor/depot_tools/man/man1/git-drover.1 +22 -20
- data/vendor/depot_tools/man/src/git-cl.txt +3 -0
- data/vendor/depot_tools/man/src/git-drover.txt +8 -0
- data/vendor/depot_tools/my_activity.py +8 -5
- data/vendor/depot_tools/owners.py +103 -11
- data/vendor/depot_tools/owners_finder.py +14 -2
- data/vendor/depot_tools/presubmit_canned_checks.py +25 -67
- data/vendor/depot_tools/presubmit_support.py +87 -35
- data/vendor/depot_tools/recipes/OWNERS +2 -0
- data/vendor/depot_tools/recipes/README.recipes.md +842 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/__init__.py +5 -3
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/api.py +181 -60
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/{example.expected → examples/full.expected}/apply_gerrit_ref.json +4 -2
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/basic.json +82 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/basic_with_branch_heads.json +149 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/buildbot.json +82 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/clobber.json +149 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/deprecated_got_revision_mapping.json +122 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/gerrit_no_rebase_patch_ref.json +149 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/gerrit_no_reset.json +149 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/no_shallow.json +149 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/reset_root_solution_revision.json +148 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/trychange.json +150 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/{example.expected → examples/full.expected}/trychange_oauth2.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/trychange_oauth2_buildbot.json +152 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/trychange_oauth2_json.json +150 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/trychange_oauth2_json_win.json +150 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob.json +156 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail.json +91 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch.json +118 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch_download.json +118 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_angle.json +202 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_angle_deprecated.json +158 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_feature_branch.json +196 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_v8.json +202 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_v8_feature_branch.json +202 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8.json +162 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8_head_by_default.json +162 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/with_tags.json +149 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/{example.py → examples/full.py} +46 -8
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/resources/bot_update.py +139 -133
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/test_api.py +25 -13
- data/vendor/depot_tools/recipes/recipe_modules/cipd/api.py +40 -9
- data/vendor/depot_tools/recipes/recipe_modules/cipd/{example.expected → examples/full.expected}/basic.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/{example.expected → examples/full.expected}/basic_pkg.json +1 -1
- data/vendor/depot_tools/recipes/recipe_modules/cipd/{example.expected → examples/full.expected}/describe-failed.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/{example.expected → examples/full.expected}/describe-many-instances.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/{example.expected → examples/full.expected}/mac64.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/{example.expected → examples/full.expected}/pkg_bad_file.json +1 -1
- data/vendor/depot_tools/recipes/recipe_modules/cipd/{example.expected → examples/full.expected}/pkg_bad_mode.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/{example.expected → examples/full.expected}/pkg_bad_verfile.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/{example.expected → examples/full.expected}/win64.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/{example.py → examples/full.py} +1 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/junk arch.json +7 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/junk bits.json +7 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_arm_32.json +14 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_arm_64.json +14 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_intel_32.json +14 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_intel_64.json +14 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_mips_64.json +14 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/mac_intel_64.json +14 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/win_intel_32.json +14 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/win_intel_64.json +14 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.py +59 -0
- data/vendor/depot_tools/recipes/recipe_modules/depot_tools/api.py +5 -0
- data/vendor/depot_tools/recipes/recipe_modules/depot_tools/{example.expected → examples/full.expected}/basic.json +7 -0
- data/vendor/depot_tools/recipes/recipe_modules/depot_tools/{example.expected → examples/full.expected}/win.json +7 -0
- data/vendor/depot_tools/recipes/recipe_modules/depot_tools/{example.py → examples/full.py} +2 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/__init__.py +1 -4
- data/vendor/depot_tools/recipes/recipe_modules/gclient/api.py +28 -14
- data/vendor/depot_tools/recipes/recipe_modules/gclient/config.py +10 -235
- data/vendor/depot_tools/recipes/recipe_modules/gclient/{example.expected → examples/full.expected}/basic.json +9 -9
- data/vendor/depot_tools/recipes/recipe_modules/gclient/{example.expected → examples/full.expected}/buildbot.json +9 -9
- data/vendor/depot_tools/recipes/recipe_modules/gclient/{example.expected → examples/full.expected}/revision.json +9 -9
- data/vendor/depot_tools/recipes/recipe_modules/gclient/{example.expected → examples/full.expected}/tryserver.json +9 -9
- data/vendor/depot_tools/recipes/recipe_modules/gclient/{example.py → examples/full.py} +5 -21
- data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/patch_project.py +45 -0
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/__init__.py +1 -0
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/api.py +97 -2
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/examples/full.expected/basic.json +283 -0
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/{example.py → examples/full.py} +31 -2
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/test_api.py +30 -1
- data/vendor/depot_tools/recipes/recipe_modules/git/__init__.py +1 -4
- data/vendor/depot_tools/recipes/recipe_modules/git/api.py +7 -35
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/basic.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/basic_branch.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/basic_file_name.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/basic_hash.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/basic_ref.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/basic_submodule_update_force.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/can_fail_build.json +1 -1
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/cannot_fail_build.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/cat-file_test.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/count-objects_delta.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/count-objects_failed.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/count-objects_with_bad_output.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/count-objects_with_bad_output_fails_build.json +1 -1
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/curl_trace_file.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/git-cache-checkout.json +6 -6
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/platform_win.json +223 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/rebase_failed.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/remote_not_origin.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.expected → examples/full.expected}/set_got_revision.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/git/{example.py → examples/full.py} +2 -1
- data/vendor/depot_tools/recipes/recipe_modules/git/resources/git_setup.py +12 -21
- data/vendor/depot_tools/recipes/recipe_modules/git_cl/__init__.py +1 -4
- data/vendor/depot_tools/recipes/recipe_modules/git_cl/api.py +13 -11
- data/vendor/depot_tools/recipes/recipe_modules/git_cl/{example.expected → examples/full.expected}/basic.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/git_cl/{example.py → examples/full.py} +4 -2
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/OWNERS +3 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/__init__.py +7 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/api.py +135 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/examples/full.expected/basic.json +537 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/examples/full.py +61 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/resources/gerrit_client.py +192 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/test_api.py +95 -0
- data/vendor/depot_tools/recipes/recipe_modules/gsutil/{example.expected → examples/full.expected}/basic.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/gsutil/{example.py → examples/full.py} +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/__init__.py +0 -3
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/{example.expected → examples/full.expected}/basic.json +3 -2
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/{example.expected → examples/full.expected}/paths_buildbot_linux.json +3 -2
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/{example.expected → examples/full.expected}/paths_buildbot_mac.json +3 -2
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/{example.expected → examples/full.expected}/paths_buildbot_win.json +3 -2
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/{example.expected → examples/full.expected}/paths_generic_linux.json +3 -2
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/{example.expected → examples/full.expected}/paths_generic_mac.json +3 -2
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/paths_generic_win.json +16 -0
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/paths_kitchen_linux.json +16 -0
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/paths_kitchen_mac.json +16 -0
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/paths_kitchen_win.json +16 -0
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/{example.py → examples/full.py} +2 -1
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/path_config.py +12 -3
- data/vendor/depot_tools/recipes/recipe_modules/presubmit/__init__.py +1 -0
- data/vendor/depot_tools/recipes/recipe_modules/presubmit/api.py +2 -2
- data/vendor/depot_tools/recipes/recipe_modules/presubmit/{example.expected → examples/full.expected}/basic.json +1 -1
- data/vendor/depot_tools/recipes/recipe_modules/presubmit/{example.py → examples/full.py} +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/rietveld/__init__.py +0 -4
- data/vendor/depot_tools/recipes/recipe_modules/rietveld/{example.expected → examples/full.expected}/basic.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/rietveld/{example.expected → examples/full.expected}/buildbot.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/rietveld/examples/full.expected/no_auth.json +27 -0
- data/vendor/depot_tools/recipes/recipe_modules/rietveld/{example.py → examples/full.py} +9 -1
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/__init__.py +3 -5
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/api.py +21 -96
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/{example.expected → examples/full.expected}/basic_tags.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/{example.expected → examples/full.expected}/set_failure_hash_with_no_steps.json +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch.json +56 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/{example.expected/with_gerrit_patch_deprecated.json → examples/full.expected/with_git_patch.json} +2 -2
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/{example.expected/with_gerrit_patch.json → examples/full.expected/with_git_patch_luci.json} +2 -2
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/{example.expected → examples/full.expected}/with_rietveld_patch.json +0 -20
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/{example.expected → examples/full.expected}/with_rietveld_patch_new.json +0 -20
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/{example.expected → examples/full.expected}/with_wrong_patch.json +1 -13
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/{example.expected → examples/full.expected}/with_wrong_patch_new.json +1 -13
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/{example.py → examples/full.py} +3 -17
- data/vendor/depot_tools/recipes/recipes.py +141 -96
- data/vendor/depot_tools/rietveld.py +8 -1
- data/vendor/depot_tools/roll-dep-svn.bat +12 -10
- data/vendor/depot_tools/roll-dep.bat +5 -3
- data/vendor/depot_tools/scm.py +8 -1
- data/vendor/depot_tools/setup_color.py +0 -0
- data/vendor/depot_tools/split_cl.py +193 -0
- data/vendor/depot_tools/third_party/schema/.editorconfig +15 -0
- data/vendor/depot_tools/third_party/schema/.gitignore +174 -0
- data/vendor/depot_tools/third_party/schema/.travis.yml +37 -0
- data/vendor/depot_tools/third_party/schema/LICENSE-MIT +19 -0
- data/vendor/depot_tools/third_party/schema/MANIFEST.in +1 -0
- data/vendor/depot_tools/third_party/schema/README.chromium +12 -0
- data/vendor/depot_tools/third_party/schema/README.rst +382 -0
- data/vendor/depot_tools/third_party/schema/__init__.py +1 -0
- data/vendor/depot_tools/third_party/schema/schema.py +338 -0
- data/vendor/depot_tools/third_party/schema/setup.cfg +5 -0
- data/vendor/depot_tools/third_party/schema/setup.py +30 -0
- data/vendor/depot_tools/third_party/schema/test_schema.py +556 -0
- data/vendor/depot_tools/third_party/schema/tox.ini +33 -0
- data/vendor/depot_tools/third_party/upload.py +4 -0
- data/vendor/depot_tools/update_depot_tools +4 -16
- data/vendor/depot_tools/update_depot_tools.bat +4 -17
- data/vendor/depot_tools/update_depot_tools_toggle.py +38 -0
- data/vendor/depot_tools/vpython +12 -0
- data/vendor/depot_tools/vpython.bat +7 -0
- data/vendor/depot_tools/win_toolchain/get_toolchain_if_necessary.py +17 -5
- data/vendor/depot_tools/win_toolchain/package_from_installed.py +63 -33
- metadata +161 -113
- data/vendor/depot_tools/bootstrap/gclient.bat +0 -22
- data/vendor/depot_tools/bootstrap/win/get_file.js +0 -119
- data/vendor/depot_tools/bootstrap/win/git_bootstrap.py +0 -193
- data/vendor/depot_tools/bootstrap/win/git_version.txt +0 -1
- data/vendor/depot_tools/bootstrap/win/git_version_bleeding_edge.txt +0 -1
- data/vendor/depot_tools/bootstrap/win/python276.new.bat +0 -8
- data/vendor/depot_tools/bootstrap/win/svn.new.bat +0 -4
- data/vendor/depot_tools/bootstrap/win/svnversion.new.bat +0 -4
- data/vendor/depot_tools/bootstrap/win/unzip.js +0 -91
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/basic.json +0 -53
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/basic_output_manifest.json +0 -60
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/basic_with_branch_heads.json +0 -54
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/buildbot.json +0 -53
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/clobber.json +0 -54
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/gerrit_no_rebase_patch_ref.json +0 -54
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/gerrit_no_reset.json +0 -54
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/no_shallow.json +0 -54
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/reset_root_solution_revision.json +0 -53
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/trychange.json +0 -55
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/trychange_oauth2_buildbot.json +0 -57
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/trychange_oauth2_json.json +0 -55
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/trychange_oauth2_json_win.json +0 -55
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/tryjob.json +0 -59
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/tryjob_fail.json +0 -62
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/tryjob_fail_patch.json +0 -83
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/tryjob_fail_patch_download.json +0 -84
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/tryjob_gerrit_angle.json +0 -60
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/tryjob_gerrit_angle_deprecated.json +0 -60
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/tryjob_v8.json +0 -62
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/example.expected/tryjob_v8_head_by_default.json +0 -62
- data/vendor/depot_tools/recipes/recipe_modules/gclient/bundle_extra_paths.txt +0 -4
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/example.expected/basic.json +0 -66
- data/vendor/depot_tools/recipes/recipe_modules/git/bundle_extra_paths.txt +0 -28
- data/vendor/depot_tools/recipes/recipe_modules/git/example.expected/platform_win.json +0 -237
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/example.expected/paths_generic_win.json +0 -15
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/example.expected/paths_kitchen_linux.json +0 -15
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/example.expected/paths_kitchen_mac.json +0 -15
- data/vendor/depot_tools/recipes/recipe_modules/infra_paths/example.expected/paths_kitchen_win.json +0 -15
- data/vendor/depot_tools/recipes/recipe_modules/presubmit/bundle_extra_paths.txt +0 -30
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/example.expected/with_git_patch.json +0 -109
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/example.expected/with_git_patch_luci.json +0 -8
@@ -39,6 +39,7 @@ while [ -n "$1" ]; do
|
|
39
39
|
fi
|
40
40
|
remote_ref="${ref/refs\/heads/refs\/remotes\/origin}"
|
41
41
|
remote_ref="${remote_ref/refs\/branch-heads/refs\/remotes\/branch-heads}"
|
42
|
+
remote_ref="${remote_ref//\\}"
|
42
43
|
num="${commit_pos#*@\{\#}"
|
43
44
|
num="${num%\}}"
|
44
45
|
if [ -z "$ref" -o -z "$num" ]; then
|
data/vendor/depot_tools/git-gs
CHANGED
@@ -6,4 +6,4 @@ git grep -n -e "$@" -- "*.h" "*.hpp" "*.cpp" "*.c" "*.cc" "*.cpp" "*.inl"\
|
|
6
6
|
"*.grd" "*.grdp" "*.idl" "*.m" "*.mm" "*.py" "*.sh" "*.cfg" "*.tac" "*.go"\
|
7
7
|
"*.vcproj" "*.vsprops" "*.make" "*.gyp" "*.gypi" "*.isolate" "*.java"\
|
8
8
|
"*.js" "*.html" "*.css" "*.ebuild" "*.pl" "*.pm" "*.yaml" "*.gn" "*.gni"\
|
9
|
-
"*.json" "DEPS" "*/DEPS" "*.mojom"
|
9
|
+
"*.json" "DEPS" "*/DEPS" "*.mojom" "*.proto"
|
@@ -59,6 +59,7 @@ import owners_finder
|
|
59
59
|
import presubmit_support
|
60
60
|
import rietveld
|
61
61
|
import scm
|
62
|
+
import split_cl
|
62
63
|
import subcommand
|
63
64
|
import subprocess2
|
64
65
|
import watchlists
|
@@ -90,7 +91,7 @@ settings = None
|
|
90
91
|
# Used by tests/git_cl_test.py to add extra logging.
|
91
92
|
# Inside the weirdly failing test, add this:
|
92
93
|
# >>> self.mock(git_cl, '_IS_BEING_TESTED', True)
|
93
|
-
# And scroll up to see the
|
94
|
+
# And scroll up to see the stack trace printed.
|
94
95
|
_IS_BEING_TESTED = False
|
95
96
|
|
96
97
|
|
@@ -273,7 +274,7 @@ def _git_set_branch_config_value(key, value, branch=None, **kwargs):
|
|
273
274
|
|
274
275
|
|
275
276
|
def _get_committer_timestamp(commit):
|
276
|
-
"""Returns
|
277
|
+
"""Returns Unix timestamp as integer of a committer in a commit.
|
277
278
|
|
278
279
|
Commit can be whatever git show would recognize, such as HEAD, sha1 or ref.
|
279
280
|
"""
|
@@ -305,6 +306,7 @@ def add_git_similarity(parser):
|
|
305
306
|
help='Disallows git from looking for copies.')
|
306
307
|
|
307
308
|
old_parser_args = parser.parse_args
|
309
|
+
|
308
310
|
def Parse(args):
|
309
311
|
options, args = old_parser_args(args)
|
310
312
|
|
@@ -324,10 +326,8 @@ def add_git_similarity(parser):
|
|
324
326
|
else:
|
325
327
|
_git_set_branch_config_value('git-find-copies', bool(options.find_copies))
|
326
328
|
|
327
|
-
print('Using %d%% similarity for rename/copy detection. '
|
328
|
-
'Override with --similarity.' % options.similarity)
|
329
|
-
|
330
329
|
return options, args
|
330
|
+
|
331
331
|
parser.parse_args = Parse
|
332
332
|
|
333
333
|
|
@@ -499,7 +499,7 @@ def _trigger_try_jobs(auth_config, changelist, buckets, options,
|
|
499
499
|
issue=changelist.GetIssue(),
|
500
500
|
patch=patchset)
|
501
501
|
|
502
|
-
shared_parameters_properties = changelist.
|
502
|
+
shared_parameters_properties = changelist.GetTryJobProperties(patchset)
|
503
503
|
shared_parameters_properties['category'] = category
|
504
504
|
if options.clobber:
|
505
505
|
shared_parameters_properties['clobber'] = True
|
@@ -611,7 +611,7 @@ def fetch_try_jobs(auth_config, changelist, buildbucket_host,
|
|
611
611
|
def print_try_jobs(options, builds):
|
612
612
|
"""Prints nicely result of fetch_try_jobs."""
|
613
613
|
if not builds:
|
614
|
-
print('No try jobs scheduled')
|
614
|
+
print('No try jobs scheduled.')
|
615
615
|
return
|
616
616
|
|
617
617
|
# Make a copy, because we'll be modifying builds dictionary.
|
@@ -626,7 +626,7 @@ def print_try_jobs(options, builds):
|
|
626
626
|
parameters = json.loads(b['parameters_json'])
|
627
627
|
name = parameters['builder_name']
|
628
628
|
except (ValueError, KeyError) as error:
|
629
|
-
print('WARNING:
|
629
|
+
print('WARNING: Failed to get builder name for build %s: %s' % (
|
630
630
|
b['id'], error))
|
631
631
|
name = None
|
632
632
|
builder_names_cache[b['id']] = name
|
@@ -858,9 +858,10 @@ class Settings(object):
|
|
858
858
|
return self._GetRietveldConfig('private', error_ok=True)
|
859
859
|
|
860
860
|
def GetIsGerrit(self):
|
861
|
-
"""Return true if this repo is
|
861
|
+
"""Return true if this repo is associated with gerrit code review system."""
|
862
862
|
if self.is_gerrit is None:
|
863
|
-
self.is_gerrit =
|
863
|
+
self.is_gerrit = (
|
864
|
+
self._GetConfig('gerrit.host', error_ok=True).lower() == 'true')
|
864
865
|
return self.is_gerrit
|
865
866
|
|
866
867
|
def GetSquashGerritUploads(self):
|
@@ -939,7 +940,7 @@ def _get_gerrit_project_config_file(remote_url):
|
|
939
940
|
'+refs/meta/config:refs/git_cl/meta/config'])
|
940
941
|
if error:
|
941
942
|
# Ref doesn't exist or isn't accessible to current user.
|
942
|
-
print('WARNING:
|
943
|
+
print('WARNING: Failed to fetch project config for %s: %s' %
|
943
944
|
(remote_url, error))
|
944
945
|
yield None
|
945
946
|
return
|
@@ -1038,34 +1039,53 @@ class _CQState(object):
|
|
1038
1039
|
|
1039
1040
|
|
1040
1041
|
class _ParsedIssueNumberArgument(object):
|
1041
|
-
def __init__(self, issue=None, patchset=None, hostname=None):
|
1042
|
+
def __init__(self, issue=None, patchset=None, hostname=None, codereview=None):
|
1042
1043
|
self.issue = issue
|
1043
1044
|
self.patchset = patchset
|
1044
1045
|
self.hostname = hostname
|
1046
|
+
assert codereview in (None, 'rietveld', 'gerrit')
|
1047
|
+
self.codereview = codereview
|
1045
1048
|
|
1046
1049
|
@property
|
1047
1050
|
def valid(self):
|
1048
1051
|
return self.issue is not None
|
1049
1052
|
|
1050
1053
|
|
1051
|
-
def ParseIssueNumberArgument(arg):
|
1054
|
+
def ParseIssueNumberArgument(arg, codereview=None):
|
1052
1055
|
"""Parses the issue argument and returns _ParsedIssueNumberArgument."""
|
1053
1056
|
fail_result = _ParsedIssueNumberArgument()
|
1054
1057
|
|
1055
1058
|
if arg.isdigit():
|
1056
|
-
return _ParsedIssueNumberArgument(issue=int(arg))
|
1059
|
+
return _ParsedIssueNumberArgument(issue=int(arg), codereview=codereview)
|
1057
1060
|
if not arg.startswith('http'):
|
1058
1061
|
return fail_result
|
1062
|
+
|
1059
1063
|
url = gclient_utils.UpgradeToHttps(arg)
|
1060
1064
|
try:
|
1061
1065
|
parsed_url = urlparse.urlparse(url)
|
1062
1066
|
except ValueError:
|
1063
1067
|
return fail_result
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1068
|
+
|
1069
|
+
if codereview is not None:
|
1070
|
+
parsed = _CODEREVIEW_IMPLEMENTATIONS[codereview].ParseIssueURL(parsed_url)
|
1071
|
+
return parsed or fail_result
|
1072
|
+
|
1073
|
+
results = {}
|
1074
|
+
for name, cls in _CODEREVIEW_IMPLEMENTATIONS.iteritems():
|
1075
|
+
parsed = cls.ParseIssueURL(parsed_url)
|
1076
|
+
if parsed is not None:
|
1077
|
+
results[name] = parsed
|
1078
|
+
|
1079
|
+
if not results:
|
1080
|
+
return fail_result
|
1081
|
+
if len(results) == 1:
|
1082
|
+
return results.values()[0]
|
1083
|
+
|
1084
|
+
if parsed_url.netloc and parsed_url.netloc.split('.')[0].endswith('-review'):
|
1085
|
+
# This is likely Gerrit.
|
1086
|
+
return results['gerrit']
|
1087
|
+
# Choose Rietveld as before if URL can parsed by either.
|
1088
|
+
return results['rietveld']
|
1069
1089
|
|
1070
1090
|
|
1071
1091
|
class GerritChangeNotExists(Exception):
|
@@ -1173,9 +1193,10 @@ class Changelist(object):
|
|
1173
1193
|
return self._codereview == 'gerrit'
|
1174
1194
|
|
1175
1195
|
def GetCCList(self):
|
1176
|
-
"""
|
1196
|
+
"""Returns the users cc'd on this CL.
|
1177
1197
|
|
1178
|
-
|
1198
|
+
The return value is a string suitable for passing to git cl with the --cc
|
1199
|
+
flag.
|
1179
1200
|
"""
|
1180
1201
|
if self.cc is None:
|
1181
1202
|
base_cc = settings.GetDefaultCCList()
|
@@ -1190,8 +1211,8 @@ class Changelist(object):
|
|
1190
1211
|
return self.cc
|
1191
1212
|
|
1192
1213
|
def SetWatchers(self, watchers):
|
1193
|
-
"""
|
1194
|
-
|
1214
|
+
"""Sets the list of email addresses that should be cc'd based on the changed
|
1215
|
+
files in this CL.
|
1195
1216
|
"""
|
1196
1217
|
self.watchers = watchers
|
1197
1218
|
|
@@ -1315,10 +1336,10 @@ class Changelist(object):
|
|
1315
1336
|
|
1316
1337
|
if upstream_git_obj is None:
|
1317
1338
|
if self.GetBranch() is None:
|
1318
|
-
print('ERROR:
|
1339
|
+
print('ERROR: Unable to determine current branch (detached HEAD?)',
|
1319
1340
|
file=sys.stderr)
|
1320
1341
|
else:
|
1321
|
-
print('ERROR:
|
1342
|
+
print('ERROR: No upstream branch.', file=sys.stderr)
|
1322
1343
|
return False
|
1323
1344
|
|
1324
1345
|
# Verify the commit we're diffing against is in our current branch.
|
@@ -1402,6 +1423,22 @@ class Changelist(object):
|
|
1402
1423
|
return '\n'.join([wrapper.fill(line) for line in lines])
|
1403
1424
|
return self.description
|
1404
1425
|
|
1426
|
+
def GetDescriptionFooters(self):
|
1427
|
+
"""Returns (non_footer_lines, footers) for the commit message.
|
1428
|
+
|
1429
|
+
Returns:
|
1430
|
+
non_footer_lines (list(str)) - Simple list of description lines without
|
1431
|
+
any footer. The lines do not contain newlines, nor does the list contain
|
1432
|
+
the empty line between the message and the footers.
|
1433
|
+
footers (list(tuple(KEY, VALUE))) - List of parsed footers, e.g.
|
1434
|
+
[("Change-Id", "Ideadbeef...."), ...]
|
1435
|
+
"""
|
1436
|
+
raw_description = self.GetDescription()
|
1437
|
+
msg_lines, _, footers = git_footers.split_footers(raw_description)
|
1438
|
+
if footers:
|
1439
|
+
msg_lines = msg_lines[:len(msg_lines)-1]
|
1440
|
+
return msg_lines, footers
|
1441
|
+
|
1405
1442
|
def GetPatchset(self):
|
1406
1443
|
"""Returns the patchset number as a int or None if not set."""
|
1407
1444
|
if self.patchset is None and not self.lookedup_patchset:
|
@@ -1434,6 +1471,12 @@ class Changelist(object):
|
|
1434
1471
|
self._codereview_impl.CodereviewServerConfigKey(),
|
1435
1472
|
codereview_server)
|
1436
1473
|
else:
|
1474
|
+
desc = self.GetDescription()
|
1475
|
+
if desc and git_footers.get_footer_change_id(desc):
|
1476
|
+
print('WARNING: The change patched into this branch has a Change-Id. '
|
1477
|
+
'Removing it.')
|
1478
|
+
RunGit(['commit', '--amend', '-m',
|
1479
|
+
git_footers.remove_footer(desc, 'Change-Id')])
|
1437
1480
|
# Reset all of these just to be clean.
|
1438
1481
|
reset_suffixes = [
|
1439
1482
|
'last-upload-hash',
|
@@ -1497,13 +1540,36 @@ class Changelist(object):
|
|
1497
1540
|
self.description = description
|
1498
1541
|
self.has_description = True
|
1499
1542
|
|
1543
|
+
def UpdateDescriptionFooters(self, description_lines, footers, force=False):
|
1544
|
+
"""Sets the description for this CL remotely.
|
1545
|
+
|
1546
|
+
You can get description_lines and footers with GetDescriptionFooters.
|
1547
|
+
|
1548
|
+
Args:
|
1549
|
+
description_lines (list(str)) - List of CL description lines without
|
1550
|
+
newline characters.
|
1551
|
+
footers (list(tuple(KEY, VALUE))) - List of footers, as returned by
|
1552
|
+
GetDescriptionFooters. Key must conform to the git footers format (i.e.
|
1553
|
+
`List-Of-Tokens`). It will be case-normalized so that each token is
|
1554
|
+
title-cased.
|
1555
|
+
"""
|
1556
|
+
new_description = '\n'.join(description_lines)
|
1557
|
+
if footers:
|
1558
|
+
new_description += '\n'
|
1559
|
+
for k, v in footers:
|
1560
|
+
foot = '%s: %s' % (git_footers.normalize_name(k), v)
|
1561
|
+
if not git_footers.FOOTER_PATTERN.match(foot):
|
1562
|
+
raise ValueError('Invalid footer %r' % foot)
|
1563
|
+
new_description += foot + '\n'
|
1564
|
+
self.UpdateDescription(new_description, force)
|
1565
|
+
|
1500
1566
|
def RunHook(self, committing, may_prompt, verbose, change):
|
1501
1567
|
"""Calls sys.exit() if the hook fails; returns a HookResults otherwise."""
|
1502
1568
|
try:
|
1503
1569
|
return presubmit_support.DoPresubmitChecks(change, committing,
|
1504
1570
|
verbose=verbose, output_stream=sys.stdout, input_stream=sys.stdin,
|
1505
1571
|
default_presubmit=None, may_prompt=may_prompt,
|
1506
|
-
rietveld_obj=self._codereview_impl.
|
1572
|
+
rietveld_obj=self._codereview_impl.GetRietveldObjForPresubmit(),
|
1507
1573
|
gerrit_obj=self._codereview_impl.GetGerritObjForPresubmit())
|
1508
1574
|
except presubmit_support.PresubmitFailure as e:
|
1509
1575
|
DieWithError(
|
@@ -1522,13 +1588,13 @@ class Changelist(object):
|
|
1522
1588
|
DieWithError('Failed to parse issue argument "%s". '
|
1523
1589
|
'Must be an issue number or a valid URL.' % issue_arg)
|
1524
1590
|
return self._codereview_impl.CMDPatchWithParsedIssue(
|
1525
|
-
parsed_issue_arg, reject, nocommit, directory)
|
1591
|
+
parsed_issue_arg, reject, nocommit, directory, False)
|
1526
1592
|
|
1527
1593
|
def CMDUpload(self, options, git_diff_args, orig_args):
|
1528
1594
|
"""Uploads a change to codereview."""
|
1595
|
+
custom_cl_base = None
|
1529
1596
|
if git_diff_args:
|
1530
|
-
|
1531
|
-
base_branch = git_diff_args[0]
|
1597
|
+
custom_cl_base = base_branch = git_diff_args[0]
|
1532
1598
|
else:
|
1533
1599
|
if self.GetBranch() is None:
|
1534
1600
|
DieWithError('Can\'t upload from detached HEAD state. Get on a branch!')
|
@@ -1537,6 +1603,16 @@ class Changelist(object):
|
|
1537
1603
|
base_branch = self.GetCommonAncestorWithUpstream()
|
1538
1604
|
git_diff_args = [base_branch, 'HEAD']
|
1539
1605
|
|
1606
|
+
# Warn about Rietveld deprecation for initial uploads to Rietveld.
|
1607
|
+
if not self.IsGerrit() and not self.GetIssue():
|
1608
|
+
print('=====================================')
|
1609
|
+
print('NOTICE: Rietveld is being deprecated. '
|
1610
|
+
'You can upload changes to Gerrit with')
|
1611
|
+
print(' git cl upload --gerrit')
|
1612
|
+
print('or set Gerrit to be your default code review tool with')
|
1613
|
+
print(' git config gerrit.host true')
|
1614
|
+
print('=====================================')
|
1615
|
+
|
1540
1616
|
# Fast best-effort checks to abort before running potentially
|
1541
1617
|
# expensive hooks if uploading is likely to fail anyway. Passing these
|
1542
1618
|
# checks does not guarantee that uploading will not fail.
|
@@ -1551,11 +1627,12 @@ class Changelist(object):
|
|
1551
1627
|
self.SetWatchers(watchlist.GetWatchersForPaths(files))
|
1552
1628
|
|
1553
1629
|
if not options.bypass_hooks:
|
1554
|
-
if options.reviewers or options.
|
1630
|
+
if options.reviewers or options.tbrs or options.add_owners_to:
|
1555
1631
|
# Set the reviewer list now so that presubmit checks can access it.
|
1556
1632
|
change_description = ChangeDescription(change.FullDescriptionText())
|
1557
1633
|
change_description.update_reviewers(options.reviewers,
|
1558
|
-
options.
|
1634
|
+
options.tbrs,
|
1635
|
+
options.add_owners_to,
|
1559
1636
|
change)
|
1560
1637
|
change.SetDescriptionText(change_description.description)
|
1561
1638
|
hook_results = self.RunHook(committing=False,
|
@@ -1583,7 +1660,7 @@ class Changelist(object):
|
|
1583
1660
|
confirm_or_exit(action='upload')
|
1584
1661
|
|
1585
1662
|
print_stats(options.similarity, options.find_copies, git_diff_args)
|
1586
|
-
ret = self.CMDUploadChange(options, git_diff_args, change)
|
1663
|
+
ret = self.CMDUploadChange(options, git_diff_args, custom_cl_base, change)
|
1587
1664
|
if not ret:
|
1588
1665
|
if options.use_commit_queue:
|
1589
1666
|
self.SetCQState(_CQState.COMMIT)
|
@@ -1614,51 +1691,42 @@ class Changelist(object):
|
|
1614
1691
|
return ret
|
1615
1692
|
|
1616
1693
|
def SetCQState(self, new_state):
|
1617
|
-
"""
|
1694
|
+
"""Updates the CQ state for the latest patchset.
|
1618
1695
|
|
1619
1696
|
Issue must have been already uploaded and known.
|
1620
1697
|
"""
|
1621
1698
|
assert new_state in _CQState.ALL_STATES
|
1622
1699
|
assert self.GetIssue()
|
1623
|
-
return self._codereview_impl.SetCQState(new_state)
|
1624
|
-
|
1625
|
-
def TriggerDryRun(self):
|
1626
|
-
"""Triggers a dry run and prints a warning on failure."""
|
1627
|
-
# TODO(qyearsley): Either re-use this method in CMDset_commit
|
1628
|
-
# and CMDupload, or change CMDtry to trigger dry runs with
|
1629
|
-
# just SetCQState, and catch keyboard interrupt and other
|
1630
|
-
# errors in that method.
|
1631
1700
|
try:
|
1632
|
-
self.SetCQState(
|
1633
|
-
print('scheduled CQ Dry Run on %s' % self.GetIssueURL())
|
1701
|
+
self._codereview_impl.SetCQState(new_state)
|
1634
1702
|
return 0
|
1635
1703
|
except KeyboardInterrupt:
|
1636
1704
|
raise
|
1637
1705
|
except:
|
1638
|
-
print('WARNING:
|
1706
|
+
print('WARNING: Failed to %s.\n'
|
1639
1707
|
'Either:\n'
|
1640
|
-
' *
|
1641
|
-
' *
|
1642
|
-
' * bug in this code (see stack trace below).\n'
|
1643
|
-
'Consider specifying which bots to trigger manually '
|
1644
|
-
'
|
1645
|
-
'
|
1646
|
-
'
|
1708
|
+
' * Your project has no CQ,\n'
|
1709
|
+
' * You don\'t have permission to change the CQ state,\n'
|
1710
|
+
' * There\'s a bug in this code (see stack trace below).\n'
|
1711
|
+
'Consider specifying which bots to trigger manually or asking your '
|
1712
|
+
'project owners for permissions or contacting Chrome Infra at:\n'
|
1713
|
+
'https://www.chromium.org/infra\n\n' %
|
1714
|
+
('cancel CQ' if new_state == _CQState.NONE else 'trigger CQ'))
|
1647
1715
|
# Still raise exception so that stack trace is printed.
|
1648
1716
|
raise
|
1649
1717
|
|
1650
1718
|
# Forward methods to codereview specific implementation.
|
1651
1719
|
|
1652
|
-
def AddComment(self, message):
|
1653
|
-
return self._codereview_impl.AddComment(message)
|
1720
|
+
def AddComment(self, message, publish=None):
|
1721
|
+
return self._codereview_impl.AddComment(message, publish=publish)
|
1654
1722
|
|
1655
|
-
def GetCommentsSummary(self):
|
1723
|
+
def GetCommentsSummary(self, readable=True):
|
1656
1724
|
"""Returns list of _CommentSummary for each comment.
|
1657
1725
|
|
1658
|
-
|
1659
|
-
|
1726
|
+
args:
|
1727
|
+
readable: determines whether the output is designed for a human or a machine
|
1660
1728
|
"""
|
1661
|
-
return self._codereview_impl.GetCommentsSummary()
|
1729
|
+
return self._codereview_impl.GetCommentsSummary(readable)
|
1662
1730
|
|
1663
1731
|
def CloseIssue(self):
|
1664
1732
|
return self._codereview_impl.CloseIssue()
|
@@ -1673,19 +1741,16 @@ class Changelist(object):
|
|
1673
1741
|
"""Get owner from codereview, which may differ from this checkout."""
|
1674
1742
|
return self._codereview_impl.GetIssueOwner()
|
1675
1743
|
|
1676
|
-
def GetApprovingReviewers(self):
|
1677
|
-
return self._codereview_impl.GetApprovingReviewers()
|
1678
|
-
|
1679
1744
|
def GetMostRecentPatchset(self):
|
1680
1745
|
return self._codereview_impl.GetMostRecentPatchset()
|
1681
1746
|
|
1682
1747
|
def CannotTriggerTryJobReason(self):
|
1683
|
-
"""Returns reason (str) if unable trigger
|
1748
|
+
"""Returns reason (str) if unable trigger try jobs on this CL or None."""
|
1684
1749
|
return self._codereview_impl.CannotTriggerTryJobReason()
|
1685
1750
|
|
1686
|
-
def
|
1687
|
-
"""Returns dictionary of properties to launch
|
1688
|
-
return self._codereview_impl.
|
1751
|
+
def GetTryJobProperties(self, patchset=None):
|
1752
|
+
"""Returns dictionary of properties to launch try job."""
|
1753
|
+
return self._codereview_impl.GetTryJobProperties(patchset=patchset)
|
1689
1754
|
|
1690
1755
|
def __getattr__(self, attr):
|
1691
1756
|
# This is because lots of untested code accesses Rietveld-specific stuff
|
@@ -1742,12 +1807,12 @@ class _ChangelistCodereviewBase(object):
|
|
1742
1807
|
raise NotImplementedError()
|
1743
1808
|
|
1744
1809
|
def _PostUnsetIssueProperties(self):
|
1745
|
-
"""Which branch-specific properties to erase when
|
1810
|
+
"""Which branch-specific properties to erase when unsetting issue."""
|
1746
1811
|
return []
|
1747
1812
|
|
1748
|
-
def
|
1813
|
+
def GetRietveldObjForPresubmit(self):
|
1749
1814
|
# This is an unfortunate Rietveld-embeddedness in presubmit.
|
1750
|
-
# For non-Rietveld
|
1815
|
+
# For non-Rietveld code reviews, this probably should return a dummy object.
|
1751
1816
|
raise NotImplementedError()
|
1752
1817
|
|
1753
1818
|
def GetGerritObjForPresubmit(self):
|
@@ -1758,30 +1823,23 @@ class _ChangelistCodereviewBase(object):
|
|
1758
1823
|
"""Update the description on codereview site."""
|
1759
1824
|
raise NotImplementedError()
|
1760
1825
|
|
1761
|
-
def AddComment(self, message):
|
1826
|
+
def AddComment(self, message, publish=None):
|
1762
1827
|
"""Posts a comment to the codereview site."""
|
1763
1828
|
raise NotImplementedError()
|
1764
1829
|
|
1765
|
-
def GetCommentsSummary(self):
|
1830
|
+
def GetCommentsSummary(self, readable=True):
|
1766
1831
|
raise NotImplementedError()
|
1767
1832
|
|
1768
1833
|
def CloseIssue(self):
|
1769
1834
|
"""Closes the issue."""
|
1770
1835
|
raise NotImplementedError()
|
1771
1836
|
|
1772
|
-
def GetApprovingReviewers(self):
|
1773
|
-
"""Returns a list of reviewers approving the change.
|
1774
|
-
|
1775
|
-
Note: not necessarily committers.
|
1776
|
-
"""
|
1777
|
-
raise NotImplementedError()
|
1778
|
-
|
1779
1837
|
def GetMostRecentPatchset(self):
|
1780
1838
|
"""Returns the most recent patchset number from the codereview site."""
|
1781
1839
|
raise NotImplementedError()
|
1782
1840
|
|
1783
1841
|
def CMDPatchWithParsedIssue(self, parsed_issue_arg, reject, nocommit,
|
1784
|
-
directory):
|
1842
|
+
directory, force):
|
1785
1843
|
"""Fetches and applies the issue.
|
1786
1844
|
|
1787
1845
|
Arguments:
|
@@ -1791,6 +1849,7 @@ class _ChangelistCodereviewBase(object):
|
|
1791
1849
|
nocommit: do not commit the patch, thus leave the tree dirty. Rietveld
|
1792
1850
|
only.
|
1793
1851
|
directory: switch to directory before applying the patch. Rietveld only.
|
1852
|
+
force: if true, overwrites existing local state.
|
1794
1853
|
"""
|
1795
1854
|
raise NotImplementedError()
|
1796
1855
|
|
@@ -1822,29 +1881,30 @@ class _ChangelistCodereviewBase(object):
|
|
1822
1881
|
"""
|
1823
1882
|
raise NotImplementedError()
|
1824
1883
|
|
1825
|
-
def CMDUploadChange(self, options,
|
1884
|
+
def CMDUploadChange(self, options, git_diff_args, custom_cl_base, change):
|
1826
1885
|
"""Uploads a change to codereview."""
|
1827
1886
|
raise NotImplementedError()
|
1828
1887
|
|
1829
1888
|
def SetCQState(self, new_state):
|
1830
|
-
"""
|
1889
|
+
"""Updates the CQ state for the latest patchset.
|
1831
1890
|
|
1832
1891
|
Issue must have been already uploaded and known.
|
1833
1892
|
"""
|
1834
1893
|
raise NotImplementedError()
|
1835
1894
|
|
1836
1895
|
def CannotTriggerTryJobReason(self):
|
1837
|
-
"""Returns reason (str) if unable trigger
|
1896
|
+
"""Returns reason (str) if unable trigger try jobs on this CL or None."""
|
1838
1897
|
raise NotImplementedError()
|
1839
1898
|
|
1840
1899
|
def GetIssueOwner(self):
|
1841
1900
|
raise NotImplementedError()
|
1842
1901
|
|
1843
|
-
def
|
1902
|
+
def GetTryJobProperties(self, patchset=None):
|
1844
1903
|
raise NotImplementedError()
|
1845
1904
|
|
1846
1905
|
|
1847
1906
|
class _RietveldChangelistImpl(_ChangelistCodereviewBase):
|
1907
|
+
|
1848
1908
|
def __init__(self, changelist, auth_config=None, codereview_host=None):
|
1849
1909
|
super(_RietveldChangelistImpl, self).__init__(changelist)
|
1850
1910
|
assert settings, 'must be initialized in _ChangelistCodereviewBase'
|
@@ -1927,8 +1987,8 @@ class _RietveldChangelistImpl(_ChangelistCodereviewBase):
|
|
1927
1987
|
return 'CL %s is private' % self.GetIssue()
|
1928
1988
|
return None
|
1929
1989
|
|
1930
|
-
def
|
1931
|
-
"""Returns dictionary of properties to launch
|
1990
|
+
def GetTryJobProperties(self, patchset=None):
|
1991
|
+
"""Returns dictionary of properties to launch try job."""
|
1932
1992
|
project = (self.GetIssueProperties() or {}).get('project')
|
1933
1993
|
return {
|
1934
1994
|
'issue': self.GetIssue(),
|
@@ -1938,16 +1998,13 @@ class _RietveldChangelistImpl(_ChangelistCodereviewBase):
|
|
1938
1998
|
'rietveld': self.GetCodereviewServer(),
|
1939
1999
|
}
|
1940
2000
|
|
1941
|
-
def GetApprovingReviewers(self):
|
1942
|
-
return get_approving_reviewers(self.GetIssueProperties())
|
1943
|
-
|
1944
2001
|
def GetIssueOwner(self):
|
1945
2002
|
return (self.GetIssueProperties() or {}).get('owner_email')
|
1946
2003
|
|
1947
|
-
def AddComment(self, message):
|
2004
|
+
def AddComment(self, message, publish=None):
|
1948
2005
|
return self.RpcServer().add_comment(self.GetIssue(), message)
|
1949
2006
|
|
1950
|
-
def GetCommentsSummary(self):
|
2007
|
+
def GetCommentsSummary(self, _readable=True):
|
1951
2008
|
summary = []
|
1952
2009
|
for message in self.GetIssueProperties().get('messages', []):
|
1953
2010
|
date = datetime.datetime.strptime(message['date'], '%Y-%m-%d %H:%M:%S.%f')
|
@@ -1961,17 +2018,18 @@ class _RietveldChangelistImpl(_ChangelistCodereviewBase):
|
|
1961
2018
|
return summary
|
1962
2019
|
|
1963
2020
|
def GetStatus(self):
|
1964
|
-
"""
|
2021
|
+
"""Applies a rough heuristic to give a simple summary of an issue's review
|
1965
2022
|
or CQ status, assuming adherence to a common workflow.
|
1966
2023
|
|
1967
2024
|
Returns None if no issue for this branch, or one of the following keywords:
|
1968
|
-
* 'error'
|
1969
|
-
* 'unsent'
|
1970
|
-
* 'waiting'
|
1971
|
-
* 'reply'
|
1972
|
-
* 'lgtm'
|
1973
|
-
* '
|
1974
|
-
* '
|
2025
|
+
* 'error' - error from review tool (including deleted issues)
|
2026
|
+
* 'unsent' - not sent for review
|
2027
|
+
* 'waiting' - waiting for review
|
2028
|
+
* 'reply' - waiting for owner to reply to review
|
2029
|
+
* 'not lgtm' - Code-Review label has been set negatively
|
2030
|
+
* 'lgtm' - LGTM from at least one approved reviewer
|
2031
|
+
* 'commit' - in the commit queue
|
2032
|
+
* 'closed' - closed
|
1975
2033
|
"""
|
1976
2034
|
if not self.GetIssue():
|
1977
2035
|
return None
|
@@ -1988,16 +2046,15 @@ class _RietveldChangelistImpl(_ChangelistCodereviewBase):
|
|
1988
2046
|
# Issue is in the commit queue.
|
1989
2047
|
return 'commit'
|
1990
2048
|
|
1991
|
-
|
1992
|
-
|
1993
|
-
|
1994
|
-
return '
|
2049
|
+
messages = props.get('messages') or []
|
2050
|
+
if not messages:
|
2051
|
+
# No message was sent.
|
2052
|
+
return 'unsent'
|
1995
2053
|
|
1996
|
-
if
|
1997
|
-
# Was LGTM'ed.
|
2054
|
+
if get_approving_reviewers(props):
|
1998
2055
|
return 'lgtm'
|
1999
|
-
|
2000
|
-
|
2056
|
+
elif get_approving_reviewers(props, disapproval=True):
|
2057
|
+
return 'not lgtm'
|
2001
2058
|
|
2002
2059
|
# Skip CQ messages that don't require owner's action.
|
2003
2060
|
while messages and messages[-1]['sender'] == COMMIT_BOT_EMAIL:
|
@@ -2011,9 +2068,6 @@ class _RietveldChangelistImpl(_ChangelistCodereviewBase):
|
|
2011
2068
|
# This is probably a CQ messages warranting user attention.
|
2012
2069
|
break
|
2013
2070
|
|
2014
|
-
if not messages:
|
2015
|
-
# No message was sent.
|
2016
|
-
return 'unsent'
|
2017
2071
|
if messages[-1]['sender'] != props.get('owner_email'):
|
2018
2072
|
# Non-LGTM reply from non-owner and not CQ bot.
|
2019
2073
|
return 'reply'
|
@@ -2065,7 +2119,7 @@ class _RietveldChangelistImpl(_ChangelistCodereviewBase):
|
|
2065
2119
|
def CodereviewServerConfigKey(cls):
|
2066
2120
|
return 'rietveldserver'
|
2067
2121
|
|
2068
|
-
def
|
2122
|
+
def GetRietveldObjForPresubmit(self):
|
2069
2123
|
return self.RpcServer()
|
2070
2124
|
|
2071
2125
|
def SetCQState(self, new_state):
|
@@ -2082,7 +2136,7 @@ class _RietveldChangelistImpl(_ChangelistCodereviewBase):
|
|
2082
2136
|
self.SetFlags({'commit': '1', 'cq_dry_run': '1'})
|
2083
2137
|
|
2084
2138
|
def CMDPatchWithParsedIssue(self, parsed_issue_arg, reject, nocommit,
|
2085
|
-
directory):
|
2139
|
+
directory, force):
|
2086
2140
|
# PatchIssue should never be called with a dirty tree. It is up to the
|
2087
2141
|
# caller to check this, but just in case we assert here since the
|
2088
2142
|
# consequences of the caller not checking this could be dire.
|
@@ -2125,23 +2179,26 @@ class _RietveldChangelistImpl(_ChangelistCodereviewBase):
|
|
2125
2179
|
return _ParsedIssueNumberArgument(
|
2126
2180
|
issue=int(match.group(1)),
|
2127
2181
|
patchset=int(match2.group(1)),
|
2128
|
-
hostname=parsed_url.netloc
|
2182
|
+
hostname=parsed_url.netloc,
|
2183
|
+
codereview='rietveld')
|
2129
2184
|
# Typical url: https://domain/<issue_number>[/[other]]
|
2130
2185
|
match = re.match('/(\d+)(/.*)?$', parsed_url.path)
|
2131
2186
|
if match:
|
2132
2187
|
return _ParsedIssueNumberArgument(
|
2133
2188
|
issue=int(match.group(1)),
|
2134
|
-
hostname=parsed_url.netloc
|
2189
|
+
hostname=parsed_url.netloc,
|
2190
|
+
codereview='rietveld')
|
2135
2191
|
# Rietveld patch: https://domain/download/issue<number>_<patchset>.diff
|
2136
2192
|
match = re.match(r'/download/issue(\d+)_(\d+).diff$', parsed_url.path)
|
2137
2193
|
if match:
|
2138
2194
|
return _ParsedIssueNumberArgument(
|
2139
2195
|
issue=int(match.group(1)),
|
2140
2196
|
patchset=int(match.group(2)),
|
2141
|
-
hostname=parsed_url.netloc
|
2197
|
+
hostname=parsed_url.netloc,
|
2198
|
+
codereview='rietveld')
|
2142
2199
|
return None
|
2143
2200
|
|
2144
|
-
def CMDUploadChange(self, options, args, change):
|
2201
|
+
def CMDUploadChange(self, options, args, custom_cl_base, change):
|
2145
2202
|
"""Upload the patch to Rietveld."""
|
2146
2203
|
upload_args = ['--assume_yes'] # Don't ask about untracked files.
|
2147
2204
|
upload_args.extend(['--server', self.GetCodereviewServer()])
|
@@ -2172,10 +2229,9 @@ class _RietveldChangelistImpl(_ChangelistCodereviewBase):
|
|
2172
2229
|
if options.title:
|
2173
2230
|
message = options.title + '\n\n' + message
|
2174
2231
|
change_desc = ChangeDescription(message)
|
2175
|
-
if options.reviewers or options.
|
2176
|
-
change_desc.update_reviewers(options.reviewers,
|
2177
|
-
options.
|
2178
|
-
change)
|
2232
|
+
if options.reviewers or options.add_owners_to:
|
2233
|
+
change_desc.update_reviewers(options.reviewers, options.tbrs,
|
2234
|
+
options.add_owners_to, change)
|
2179
2235
|
if not options.force:
|
2180
2236
|
change_desc.prompt(bug=options.bug, git_footer=False)
|
2181
2237
|
|
@@ -2261,6 +2317,11 @@ class _RietveldChangelistImpl(_ChangelistCodereviewBase):
|
|
2261
2317
|
project = settings.GetProject()
|
2262
2318
|
if project:
|
2263
2319
|
upload_args.extend(['--project', project])
|
2320
|
+
else:
|
2321
|
+
print()
|
2322
|
+
print('WARNING: Uploading without a project specified. Please ensure '
|
2323
|
+
'your repo\'s codereview.settings has a "PROJECT: foo" line.')
|
2324
|
+
print()
|
2264
2325
|
|
2265
2326
|
try:
|
2266
2327
|
upload_args = ['upload'] + upload_args + args
|
@@ -2307,7 +2368,7 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2307
2368
|
# This happens for internal stuff http://crbug.com/614312.
|
2308
2369
|
parsed = urlparse.urlparse(self.GetRemoteUrl())
|
2309
2370
|
if parsed.scheme == 'sso':
|
2310
|
-
print('WARNING: using non
|
2371
|
+
print('WARNING: using non-https URLs for remote is likely broken\n'
|
2311
2372
|
' Your current remote is: %s' % self.GetRemoteUrl())
|
2312
2373
|
self._gerrit_host = '%s.googlesource.com' % self._gerrit_host
|
2313
2374
|
self._gerrit_server = 'https://%s' % self._gerrit_host
|
@@ -2366,22 +2427,25 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2366
2427
|
if gerrit_auth and git_auth:
|
2367
2428
|
if gerrit_auth == git_auth:
|
2368
2429
|
return
|
2430
|
+
all_gsrc = cookie_auth.get_auth_header('d0esN0tEx1st.googlesource.com')
|
2369
2431
|
print((
|
2370
|
-
'WARNING:
|
2371
|
-
' Check your %s or %s file for credentials of hosts:\n'
|
2432
|
+
'WARNING: You have different credentials for Gerrit and git hosts:\n'
|
2372
2433
|
' %s\n'
|
2373
2434
|
' %s\n'
|
2374
|
-
'
|
2375
|
-
|
2376
|
-
|
2435
|
+
' Consider running the following command:\n'
|
2436
|
+
' git cl creds-check\n'
|
2437
|
+
' %s\n'
|
2438
|
+
' %s') %
|
2439
|
+
(git_host, self._gerrit_host,
|
2440
|
+
('Hint: delete creds for .googlesource.com' if all_gsrc else ''),
|
2377
2441
|
cookie_auth.get_new_password_message(git_host)))
|
2378
2442
|
if not force:
|
2379
2443
|
confirm_or_exit('If you know what you are doing', action='continue')
|
2380
2444
|
return
|
2381
2445
|
else:
|
2382
2446
|
missing = (
|
2383
|
-
[] if gerrit_auth else [self._gerrit_host] +
|
2384
|
-
[] if git_auth else [git_host])
|
2447
|
+
([] if gerrit_auth else [self._gerrit_host]) +
|
2448
|
+
([] if git_auth else [git_host]))
|
2385
2449
|
DieWithError('Credentials for the following hosts are required:\n'
|
2386
2450
|
' %s\n'
|
2387
2451
|
'These are read from %s (or legacy %s)\n'
|
@@ -2414,13 +2478,13 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2414
2478
|
return
|
2415
2479
|
logging.debug('change %s owner is %s, cookies user is %s',
|
2416
2480
|
self.GetIssue(), self.GetIssueOwner(), cookies_user)
|
2417
|
-
# Maybe user has linked accounts or
|
2481
|
+
# Maybe user has linked accounts or something like that,
|
2418
2482
|
# so ask what Gerrit thinks of this user.
|
2419
2483
|
details = gerrit_util.GetAccountDetails(self._GetGerritHost(), 'self')
|
2420
2484
|
if details['email'] == self.GetIssueOwner():
|
2421
2485
|
return
|
2422
2486
|
if not force:
|
2423
|
-
print('WARNING:
|
2487
|
+
print('WARNING: Change %s is owned by %s, but you authenticate to Gerrit '
|
2424
2488
|
'as %s.\n'
|
2425
2489
|
'Uploading may fail due to lack of permissions.' %
|
2426
2490
|
(self.GetIssue(), self.GetIssueOwner(), details['email']))
|
@@ -2431,7 +2495,7 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2431
2495
|
"""Which branch-specific properties to erase when unsetting issue."""
|
2432
2496
|
return ['gerritsquashhash']
|
2433
2497
|
|
2434
|
-
def
|
2498
|
+
def GetRietveldObjForPresubmit(self):
|
2435
2499
|
class ThisIsNotRietveldIssue(object):
|
2436
2500
|
def __nonzero__(self):
|
2437
2501
|
# This is a hack to make presubmit_support think that rietveld is not
|
@@ -2443,7 +2507,7 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2443
2507
|
print(
|
2444
2508
|
'You aren\'t using Rietveld at the moment, but Gerrit.\n'
|
2445
2509
|
'Using Rietveld in your PRESUBMIT scripts won\'t work.\n'
|
2446
|
-
'Please, either change your
|
2510
|
+
'Please, either change your PRESUBMIT to not use rietveld_obj.%s,\n'
|
2447
2511
|
'or use Rietveld for codereview.\n'
|
2448
2512
|
'See also http://crbug.com/579160.' % attr)
|
2449
2513
|
raise NotImplementedError()
|
@@ -2457,62 +2521,54 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2457
2521
|
or CQ status, assuming adherence to a common workflow.
|
2458
2522
|
|
2459
2523
|
Returns None if no issue for this branch, or one of the following keywords:
|
2460
|
-
* 'error'
|
2461
|
-
* 'unsent'
|
2462
|
-
* 'waiting'
|
2463
|
-
* 'reply'
|
2464
|
-
* '
|
2465
|
-
* '
|
2466
|
-
* '
|
2467
|
-
* 'closed' - abandoned
|
2524
|
+
* 'error' - error from review tool (including deleted issues)
|
2525
|
+
* 'unsent' - no reviewers added
|
2526
|
+
* 'waiting' - waiting for review
|
2527
|
+
* 'reply' - waiting for uploader to reply to review
|
2528
|
+
* 'lgtm' - Code-Review label has been set
|
2529
|
+
* 'commit' - in the commit queue
|
2530
|
+
* 'closed' - successfully submitted or abandoned
|
2468
2531
|
"""
|
2469
2532
|
if not self.GetIssue():
|
2470
2533
|
return None
|
2471
2534
|
|
2472
2535
|
try:
|
2473
|
-
data = self._GetChangeDetail([
|
2536
|
+
data = self._GetChangeDetail([
|
2537
|
+
'DETAILED_LABELS', 'CURRENT_REVISION', 'SUBMITTABLE'])
|
2474
2538
|
except (httplib.HTTPException, GerritChangeNotExists):
|
2475
2539
|
return 'error'
|
2476
2540
|
|
2477
2541
|
if data['status'] in ('ABANDONED', 'MERGED'):
|
2478
2542
|
return 'closed'
|
2479
2543
|
|
2480
|
-
|
2481
|
-
|
2482
|
-
|
2483
|
-
|
2484
|
-
|
2485
|
-
|
2486
|
-
|
2487
|
-
if vote_value != '0':
|
2488
|
-
# Add a '+' if the value is not 0 to match the values in the label.
|
2489
|
-
# The cq_label does not have negatives.
|
2490
|
-
vote_value = '+' + vote_value
|
2491
|
-
vote_text = cq_label.get('values', {}).get(vote_value, '')
|
2492
|
-
if vote_text.lower() == 'commit':
|
2493
|
-
return 'commit'
|
2494
|
-
|
2495
|
-
lgtm_label = data['labels'].get('Code-Review', {})
|
2496
|
-
if lgtm_label:
|
2497
|
-
if 'rejected' in lgtm_label:
|
2498
|
-
return 'not lgtm'
|
2499
|
-
if 'approved' in lgtm_label:
|
2500
|
-
return 'lgtm'
|
2544
|
+
if data['labels'].get('Commit-Queue', {}).get('approved'):
|
2545
|
+
# The section will have an "approved" subsection if anyone has voted
|
2546
|
+
# the maximum value on the label.
|
2547
|
+
return 'commit'
|
2548
|
+
|
2549
|
+
if data['labels'].get('Code-Review', {}).get('approved'):
|
2550
|
+
return 'lgtm'
|
2501
2551
|
|
2502
2552
|
if not data.get('reviewers', {}).get('REVIEWER', []):
|
2503
2553
|
return 'unsent'
|
2504
2554
|
|
2505
|
-
messages = data.get('messages', [])
|
2506
2555
|
owner = data['owner'].get('_account_id')
|
2507
|
-
|
2508
|
-
|
2556
|
+
messages = sorted(data.get('messages', []), key=lambda m: m.get('updated'))
|
2557
|
+
last_message_author = messages.pop().get('author', {})
|
2558
|
+
while last_message_author:
|
2509
2559
|
if last_message_author.get('email') == COMMIT_BOT_EMAIL:
|
2510
2560
|
# Ignore replies from CQ.
|
2561
|
+
last_message_author = messages.pop().get('author', {})
|
2511
2562
|
continue
|
2512
|
-
if last_message_author.get('_account_id')
|
2563
|
+
if last_message_author.get('_account_id') == owner:
|
2564
|
+
# Most recent message was by owner.
|
2565
|
+
return 'waiting'
|
2566
|
+
else:
|
2513
2567
|
# Some reply from non-owner.
|
2514
2568
|
return 'reply'
|
2515
|
-
|
2569
|
+
|
2570
|
+
# Somehow there are no messages even though there are reviewers.
|
2571
|
+
return 'unsent'
|
2516
2572
|
|
2517
2573
|
def GetMostRecentPatchset(self):
|
2518
2574
|
data = self._GetChangeDetail(['CURRENT_REVISION'])
|
@@ -2537,22 +2593,71 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2537
2593
|
gerrit_util.SetCommitMessage(self._GetGerritHost(), self.GetIssue(),
|
2538
2594
|
description, notify='NONE')
|
2539
2595
|
|
2540
|
-
def AddComment(self, message):
|
2596
|
+
def AddComment(self, message, publish=None):
|
2541
2597
|
gerrit_util.SetReview(self._GetGerritHost(), self.GetIssue(),
|
2542
|
-
msg=message)
|
2598
|
+
msg=message, ready=publish)
|
2543
2599
|
|
2544
|
-
def GetCommentsSummary(self):
|
2600
|
+
def GetCommentsSummary(self, readable=True):
|
2545
2601
|
# DETAILED_ACCOUNTS is to get emails in accounts.
|
2546
|
-
|
2602
|
+
messages = self._GetChangeDetail(
|
2603
|
+
options=['MESSAGES', 'DETAILED_ACCOUNTS']).get('messages', [])
|
2604
|
+
file_comments = gerrit_util.GetChangeComments(
|
2605
|
+
self._GetGerritHost(), self.GetIssue())
|
2606
|
+
|
2607
|
+
# Build dictionary of file comments for easy access and sorting later.
|
2608
|
+
# {author+date: {path: {patchset: {line: url+message}}}}
|
2609
|
+
comments = collections.defaultdict(
|
2610
|
+
lambda: collections.defaultdict(lambda: collections.defaultdict(dict)))
|
2611
|
+
for path, line_comments in file_comments.iteritems():
|
2612
|
+
for comment in line_comments:
|
2613
|
+
if comment.get('tag', '').startswith('autogenerated'):
|
2614
|
+
continue
|
2615
|
+
key = (comment['author']['email'], comment['updated'])
|
2616
|
+
if comment.get('side', 'REVISION') == 'PARENT':
|
2617
|
+
patchset = 'Base'
|
2618
|
+
else:
|
2619
|
+
patchset = 'PS%d' % comment['patch_set']
|
2620
|
+
line = comment.get('line', 0)
|
2621
|
+
url = ('https://%s/c/%s/%s/%s#%s%s' %
|
2622
|
+
(self._GetGerritHost(), self.GetIssue(), comment['patch_set'], path,
|
2623
|
+
'b' if comment.get('side') == 'PARENT' else '',
|
2624
|
+
str(line) if line else ''))
|
2625
|
+
comments[key][path][patchset][line] = (url, comment['message'])
|
2626
|
+
|
2547
2627
|
summary = []
|
2548
|
-
for msg in
|
2628
|
+
for msg in messages:
|
2629
|
+
# Don't bother showing autogenerated messages.
|
2630
|
+
if msg.get('tag') and msg.get('tag').startswith('autogenerated'):
|
2631
|
+
continue
|
2549
2632
|
# Gerrit spits out nanoseconds.
|
2550
2633
|
assert len(msg['date'].split('.')[-1]) == 9
|
2551
2634
|
date = datetime.datetime.strptime(msg['date'][:-3],
|
2552
2635
|
'%Y-%m-%d %H:%M:%S.%f')
|
2636
|
+
message = msg['message']
|
2637
|
+
key = (msg['author']['email'], msg['date'])
|
2638
|
+
if key in comments:
|
2639
|
+
message += '\n'
|
2640
|
+
for path, patchsets in sorted(comments.get(key, {}).items()):
|
2641
|
+
if readable:
|
2642
|
+
message += '\n%s' % path
|
2643
|
+
for patchset, lines in sorted(patchsets.items()):
|
2644
|
+
for line, (url, content) in sorted(lines.items()):
|
2645
|
+
if line:
|
2646
|
+
line_str = 'Line %d' % line
|
2647
|
+
path_str = '%s:%d:' % (path, line)
|
2648
|
+
else:
|
2649
|
+
line_str = 'File comment'
|
2650
|
+
path_str = '%s:0:' % path
|
2651
|
+
if readable:
|
2652
|
+
message += '\n %s, %s: %s' % (patchset, line_str, url)
|
2653
|
+
message += '\n %s\n' % content
|
2654
|
+
else:
|
2655
|
+
message += '\n%s ' % path_str
|
2656
|
+
message += '\n%s\n' % content
|
2657
|
+
|
2553
2658
|
summary.append(_CommentSummary(
|
2554
2659
|
date=date,
|
2555
|
-
message=
|
2660
|
+
message=message,
|
2556
2661
|
sender=msg['author']['email'],
|
2557
2662
|
# These could be inferred from the text messages and correlated with
|
2558
2663
|
# Code-Review label maximum, however this is not reliable.
|
@@ -2565,13 +2670,6 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2565
2670
|
def CloseIssue(self):
|
2566
2671
|
gerrit_util.AbandonChange(self._GetGerritHost(), self.GetIssue(), msg='')
|
2567
2672
|
|
2568
|
-
def GetApprovingReviewers(self):
|
2569
|
-
"""Returns a list of reviewers approving the change.
|
2570
|
-
|
2571
|
-
Note: not necessarily committers.
|
2572
|
-
"""
|
2573
|
-
raise NotImplementedError()
|
2574
|
-
|
2575
2673
|
def SubmitIssue(self, wait_for_merge=True):
|
2576
2674
|
gerrit_util.SubmitChange(self._GetGerritHost(), self.GetIssue(),
|
2577
2675
|
wait_for_merge=wait_for_merge)
|
@@ -2612,8 +2710,8 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2612
2710
|
return data
|
2613
2711
|
|
2614
2712
|
try:
|
2615
|
-
data = gerrit_util.GetChangeDetail(
|
2616
|
-
|
2713
|
+
data = gerrit_util.GetChangeDetail(
|
2714
|
+
self._GetGerritHost(), str(issue), options)
|
2617
2715
|
except gerrit_util.GerritError as e:
|
2618
2716
|
if e.http_status == 404:
|
2619
2717
|
raise GerritChangeNotExists(issue, self.GetCodereviewServer())
|
@@ -2625,9 +2723,12 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2625
2723
|
def _GetChangeCommit(self, issue=None):
|
2626
2724
|
issue = issue or self.GetIssue()
|
2627
2725
|
assert issue, 'issue is required to query Gerrit'
|
2628
|
-
|
2629
|
-
|
2630
|
-
|
2726
|
+
try:
|
2727
|
+
data = gerrit_util.GetChangeCommit(self._GetGerritHost(), str(issue))
|
2728
|
+
except gerrit_util.GerritError as e:
|
2729
|
+
if e.http_status == 404:
|
2730
|
+
raise GerritChangeNotExists(issue, self.GetCodereviewServer())
|
2731
|
+
raise
|
2631
2732
|
return data
|
2632
2733
|
|
2633
2734
|
def CMDLand(self, force, bypass_hooks, verbose):
|
@@ -2645,19 +2746,19 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2645
2746
|
last_upload = self._GitGetBranchConfigValue('gerritsquashhash')
|
2646
2747
|
# Note: git diff outputs nothing if there is no diff.
|
2647
2748
|
if not last_upload or RunGit(['diff', last_upload]).strip():
|
2648
|
-
print('WARNING:
|
2749
|
+
print('WARNING: Some changes from local branch haven\'t been uploaded.')
|
2649
2750
|
else:
|
2650
2751
|
if detail['current_revision'] == last_upload:
|
2651
2752
|
differs = False
|
2652
2753
|
else:
|
2653
|
-
print('WARNING:
|
2654
|
-
'patchset')
|
2754
|
+
print('WARNING: Local branch contents differ from latest uploaded '
|
2755
|
+
'patchset.')
|
2655
2756
|
if differs:
|
2656
2757
|
if not force:
|
2657
2758
|
confirm_or_exit(
|
2658
2759
|
'Do you want to submit latest Gerrit patchset and bypass hooks?\n',
|
2659
2760
|
action='submit')
|
2660
|
-
print('WARNING:
|
2761
|
+
print('WARNING: Bypassing hooks and submitting latest uploaded patchset.')
|
2661
2762
|
elif not bypass_hooks:
|
2662
2763
|
hook_results = self.RunHook(
|
2663
2764
|
committing=True,
|
@@ -2672,12 +2773,12 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2672
2773
|
links = self._GetChangeCommit().get('web_links', [])
|
2673
2774
|
for link in links:
|
2674
2775
|
if link.get('name') == 'gitiles' and link.get('url'):
|
2675
|
-
print('Landed as %s' % link.get('url'))
|
2776
|
+
print('Landed as: %s' % link.get('url'))
|
2676
2777
|
break
|
2677
2778
|
return 0
|
2678
2779
|
|
2679
2780
|
def CMDPatchWithParsedIssue(self, parsed_issue_arg, reject, nocommit,
|
2680
|
-
directory):
|
2781
|
+
directory, force):
|
2681
2782
|
assert not reject
|
2682
2783
|
assert not nocommit
|
2683
2784
|
assert not directory
|
@@ -2709,11 +2810,25 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2709
2810
|
|
2710
2811
|
fetch_info = revision_info['fetch']['http']
|
2711
2812
|
RunGit(['fetch', fetch_info['url'], fetch_info['ref']])
|
2712
|
-
|
2813
|
+
|
2814
|
+
if force:
|
2815
|
+
RunGit(['reset', '--hard', 'FETCH_HEAD'])
|
2816
|
+
print('Checked out commit for change %i patchset %i locally' %
|
2817
|
+
(parsed_issue_arg.issue, patchset))
|
2818
|
+
else:
|
2819
|
+
RunGit(['cherry-pick', 'FETCH_HEAD'])
|
2820
|
+
print('Committed patch for change %i patchset %i locally.' %
|
2821
|
+
(parsed_issue_arg.issue, patchset))
|
2822
|
+
print('Note: this created a local commit which does not have '
|
2823
|
+
'the same hash as the one uploaded for review. This will make '
|
2824
|
+
'uploading changes based on top of this branch difficult.\n'
|
2825
|
+
'If you want to do that, use "git cl patch --force" instead.')
|
2826
|
+
|
2827
|
+
self.SetIssue(parsed_issue_arg.issue)
|
2713
2828
|
self.SetPatchset(patchset)
|
2714
|
-
RunGit(['
|
2715
|
-
|
2716
|
-
|
2829
|
+
fetched_hash = RunGit(['rev-parse', 'FETCH_HEAD']).strip()
|
2830
|
+
self._GitSetBranchConfigValue('last-upload-hash', fetched_hash)
|
2831
|
+
self._GitSetBranchConfigValue('gerritsquashhash', fetched_hash)
|
2717
2832
|
return 0
|
2718
2833
|
|
2719
2834
|
@staticmethod
|
@@ -2733,7 +2848,8 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2733
2848
|
return _ParsedIssueNumberArgument(
|
2734
2849
|
issue=int(match.group(2)),
|
2735
2850
|
patchset=int(match.group(4)) if match.group(4) else None,
|
2736
|
-
hostname=parsed_url.netloc
|
2851
|
+
hostname=parsed_url.netloc,
|
2852
|
+
codereview='gerrit')
|
2737
2853
|
return None
|
2738
2854
|
|
2739
2855
|
def _GerritCommitMsgHookCheck(self, offer_removal):
|
@@ -2745,7 +2861,7 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2745
2861
|
data = gclient_utils.FileRead(hook)
|
2746
2862
|
if not('From Gerrit Code Review' in data and 'add_ChangeId()' in data):
|
2747
2863
|
return
|
2748
|
-
print('
|
2864
|
+
print('WARNING: You have Gerrit commit-msg hook installed.\n'
|
2749
2865
|
'It is not necessary for uploading with git cl in squash mode, '
|
2750
2866
|
'and may interfere with it in subtle ways.\n'
|
2751
2867
|
'We recommend you remove the commit-msg hook.')
|
@@ -2756,7 +2872,7 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2756
2872
|
else:
|
2757
2873
|
print('OK, will keep Gerrit commit-msg hook in place.')
|
2758
2874
|
|
2759
|
-
def CMDUploadChange(self, options,
|
2875
|
+
def CMDUploadChange(self, options, git_diff_args, custom_cl_base, change):
|
2760
2876
|
"""Upload the current branch to Gerrit."""
|
2761
2877
|
if options.squash and options.no_squash:
|
2762
2878
|
DieWithError('Can only use one of --squash or --no-squash')
|
@@ -2767,10 +2883,6 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2767
2883
|
elif options.no_squash:
|
2768
2884
|
options.squash = False
|
2769
2885
|
|
2770
|
-
# We assume the remote called "origin" is the one we want.
|
2771
|
-
# It is probably not worthwhile to support different workflows.
|
2772
|
-
gerrit_remote = 'origin'
|
2773
|
-
|
2774
2886
|
remote, remote_branch = self.GetRemoteBranch()
|
2775
2887
|
branch = GetTargetRef(remote, remote_branch, options.target_branch)
|
2776
2888
|
|
@@ -2788,11 +2900,20 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2788
2900
|
'failed to fetch description from current Gerrit change %d\n'
|
2789
2901
|
'%s' % (self.GetIssue(), self.GetIssueURL()))
|
2790
2902
|
if not title:
|
2791
|
-
|
2792
|
-
|
2793
|
-
|
2794
|
-
|
2795
|
-
|
2903
|
+
if options.message:
|
2904
|
+
# When uploading a subsequent patchset, -m|--message is taken
|
2905
|
+
# as the patchset title if --title was not provided.
|
2906
|
+
title = options.message.strip()
|
2907
|
+
else:
|
2908
|
+
default_title = RunGit(
|
2909
|
+
['show', '-s', '--format=%s', 'HEAD']).strip()
|
2910
|
+
if options.force:
|
2911
|
+
title = default_title
|
2912
|
+
else:
|
2913
|
+
title = ask_for_data(
|
2914
|
+
'Title for patchset [%s]: ' % default_title) or default_title
|
2915
|
+
if title == default_title:
|
2916
|
+
automatic_title = True
|
2796
2917
|
change_id = self._GetChangeDetail()['change_id']
|
2797
2918
|
while True:
|
2798
2919
|
footer_change_ids = git_footers.get_footer_change_id(message)
|
@@ -2800,7 +2921,7 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2800
2921
|
break
|
2801
2922
|
if not footer_change_ids:
|
2802
2923
|
message = git_footers.add_footer_change_id(message, change_id)
|
2803
|
-
print('WARNING: appended missing Change-Id to change description')
|
2924
|
+
print('WARNING: appended missing Change-Id to change description.')
|
2804
2925
|
continue
|
2805
2926
|
# There is already a valid footer but with different or several ids.
|
2806
2927
|
# Doing this automatically is non-trivial as we don't want to lose
|
@@ -2832,10 +2953,11 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2832
2953
|
if options.message:
|
2833
2954
|
message = options.message
|
2834
2955
|
else:
|
2835
|
-
message = CreateDescriptionFromLog(
|
2956
|
+
message = CreateDescriptionFromLog(git_diff_args)
|
2836
2957
|
if options.title:
|
2837
2958
|
message = options.title + '\n\n' + message
|
2838
2959
|
change_desc = ChangeDescription(message)
|
2960
|
+
|
2839
2961
|
if not options.force:
|
2840
2962
|
change_desc.prompt(bug=options.bug)
|
2841
2963
|
# On first upload, patchset title is always this string, while
|
@@ -2844,57 +2966,46 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2844
2966
|
automatic_title = True
|
2845
2967
|
if not change_desc.description:
|
2846
2968
|
DieWithError("Description is empty. Aborting...")
|
2847
|
-
|
2848
|
-
change_ids = git_footers.get_footer_change_id(message)
|
2969
|
+
change_ids = git_footers.get_footer_change_id(change_desc.description)
|
2849
2970
|
if len(change_ids) > 1:
|
2850
2971
|
DieWithError('too many Change-Id footers, at most 1 allowed.')
|
2851
2972
|
if not change_ids:
|
2852
2973
|
# Generate the Change-Id automatically.
|
2853
|
-
|
2854
|
-
|
2855
|
-
|
2856
|
-
change_ids = git_footers.get_footer_change_id(
|
2974
|
+
change_desc.set_description(git_footers.add_footer_change_id(
|
2975
|
+
change_desc.description,
|
2976
|
+
GenerateGerritChangeId(change_desc.description)))
|
2977
|
+
change_ids = git_footers.get_footer_change_id(change_desc.description)
|
2857
2978
|
assert len(change_ids) == 1
|
2858
2979
|
change_id = change_ids[0]
|
2859
2980
|
|
2860
|
-
|
2861
|
-
|
2862
|
-
|
2863
|
-
# squashed version.
|
2864
|
-
upstream_branch_name = scm.GIT.ShortBranchName(upstream_branch)
|
2865
|
-
# Check the squashed hash of the parent.
|
2866
|
-
parent = RunGit(['config',
|
2867
|
-
'branch.%s.gerritsquashhash' % upstream_branch_name],
|
2868
|
-
error_ok=True).strip()
|
2869
|
-
# Verify that the upstream branch has been uploaded too, otherwise
|
2870
|
-
# Gerrit will create additional CLs when uploading.
|
2871
|
-
if not parent or (RunGitSilent(['rev-parse', upstream_branch + ':']) !=
|
2872
|
-
RunGitSilent(['rev-parse', parent + ':'])):
|
2873
|
-
DieWithError(
|
2874
|
-
'\nUpload upstream branch %s first.\n'
|
2875
|
-
'It is likely that this branch has been rebased since its last '
|
2876
|
-
'upload, so you just need to upload it again.\n'
|
2877
|
-
'(If you uploaded it with --no-squash, then branch dependencies '
|
2878
|
-
'are not supported, and you should reupload with --squash.)'
|
2879
|
-
% upstream_branch_name, change_desc)
|
2880
|
-
else:
|
2881
|
-
parent = self.GetCommonAncestorWithUpstream()
|
2981
|
+
if options.reviewers or options.tbrs or options.add_owners_to:
|
2982
|
+
change_desc.update_reviewers(options.reviewers, options.tbrs,
|
2983
|
+
options.add_owners_to, change)
|
2882
2984
|
|
2985
|
+
remote, upstream_branch = self.FetchUpstreamTuple(self.GetBranch())
|
2986
|
+
parent = self._ComputeParent(remote, upstream_branch, custom_cl_base,
|
2987
|
+
options.force, change_desc)
|
2883
2988
|
tree = RunGit(['rev-parse', 'HEAD:']).strip()
|
2884
2989
|
ref_to_push = RunGit(['commit-tree', tree, '-p', parent,
|
2885
|
-
'-m',
|
2990
|
+
'-m', change_desc.description]).strip()
|
2886
2991
|
else:
|
2887
2992
|
change_desc = ChangeDescription(
|
2888
|
-
options.message or CreateDescriptionFromLog(
|
2993
|
+
options.message or CreateDescriptionFromLog(git_diff_args))
|
2889
2994
|
if not change_desc.description:
|
2890
2995
|
DieWithError("Description is empty. Aborting...")
|
2891
2996
|
|
2892
2997
|
if not git_footers.get_footer_change_id(change_desc.description):
|
2893
2998
|
DownloadGerritHook(False)
|
2894
|
-
change_desc.set_description(
|
2895
|
-
|
2999
|
+
change_desc.set_description(
|
3000
|
+
self._AddChangeIdToCommitMessage(options, git_diff_args))
|
3001
|
+
if options.reviewers or options.tbrs or options.add_owners_to:
|
3002
|
+
change_desc.update_reviewers(options.reviewers, options.tbrs,
|
3003
|
+
options.add_owners_to, change)
|
2896
3004
|
ref_to_push = 'HEAD'
|
2897
|
-
|
3005
|
+
# For no-squash mode, we assume the remote called "origin" is the one we
|
3006
|
+
# want. It is not worthwhile to support different workflows for
|
3007
|
+
# no-squash mode.
|
3008
|
+
parent = 'origin/%s' % branch
|
2898
3009
|
change_id = git_footers.get_footer_change_id(change_desc.description)[0]
|
2899
3010
|
|
2900
3011
|
assert change_desc
|
@@ -2908,16 +3019,28 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2908
3019
|
'single commit.')
|
2909
3020
|
confirm_or_exit(action='upload')
|
2910
3021
|
|
2911
|
-
if options.reviewers or options.
|
2912
|
-
change_desc.update_reviewers(options.reviewers, options.
|
2913
|
-
change)
|
3022
|
+
if options.reviewers or options.tbrs or options.add_owners_to:
|
3023
|
+
change_desc.update_reviewers(options.reviewers, options.tbrs,
|
3024
|
+
options.add_owners_to, change)
|
2914
3025
|
|
2915
3026
|
# Extra options that can be specified at push time. Doc:
|
2916
3027
|
# https://gerrit-review.googlesource.com/Documentation/user-upload.html
|
2917
3028
|
refspec_opts = []
|
2918
|
-
|
2919
|
-
|
2920
|
-
|
3029
|
+
|
3030
|
+
# By default, new changes are started in WIP mode, and subsequent patchsets
|
3031
|
+
# don't send email. At any time, passing --send-mail will mark the change
|
3032
|
+
# ready and send email for that particular patch.
|
3033
|
+
if options.send_mail:
|
3034
|
+
refspec_opts.append('ready')
|
3035
|
+
refspec_opts.append('notify=ALL')
|
3036
|
+
else:
|
3037
|
+
if not self.GetIssue():
|
3038
|
+
refspec_opts.append('wip')
|
3039
|
+
else:
|
3040
|
+
refspec_opts.append('notify=NONE')
|
3041
|
+
|
3042
|
+
# TODO(tandrii): options.message should be posted as a comment
|
3043
|
+
# if --send-mail is set on non-initial upload as Rietveld used to do it.
|
2921
3044
|
|
2922
3045
|
if title:
|
2923
3046
|
if not re.match(r'^[\w ]+$', title):
|
@@ -2931,24 +3054,8 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2931
3054
|
# reverse on its side.
|
2932
3055
|
refspec_opts.append('m=' + title.replace(' ', '_'))
|
2933
3056
|
|
2934
|
-
if options.send_mail:
|
2935
|
-
if not change_desc.get_reviewers():
|
2936
|
-
DieWithError('Must specify reviewers to send email.', change_desc)
|
2937
|
-
refspec_opts.append('notify=ALL')
|
2938
|
-
else:
|
2939
|
-
refspec_opts.append('notify=NONE')
|
2940
|
-
|
2941
|
-
reviewers = change_desc.get_reviewers()
|
2942
|
-
if reviewers:
|
2943
|
-
# TODO(tandrii): remove this horrible hack once (Poly)Gerrit fixes their
|
2944
|
-
# side for real (b/34702620).
|
2945
|
-
def clean_invisible_chars(email):
|
2946
|
-
return email.decode('unicode_escape').encode('ascii', 'ignore')
|
2947
|
-
refspec_opts.extend('r=' + clean_invisible_chars(email).strip()
|
2948
|
-
for email in reviewers)
|
2949
|
-
|
2950
3057
|
if options.private:
|
2951
|
-
refspec_opts.append('
|
3058
|
+
refspec_opts.append('private')
|
2952
3059
|
|
2953
3060
|
if options.topic:
|
2954
3061
|
# Documentation on Gerrit topics is here:
|
@@ -2971,7 +3078,11 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2971
3078
|
filter_fn=lambda _: sys.stdout.flush())
|
2972
3079
|
except subprocess2.CalledProcessError:
|
2973
3080
|
DieWithError('Failed to create a change. Please examine output above '
|
2974
|
-
'for the reason of the failure
|
3081
|
+
'for the reason of the failure.\n'
|
3082
|
+
'Hint: run command below to diagnose common Git/Gerrit '
|
3083
|
+
'credential problems:\n'
|
3084
|
+
' git cl creds-check\n',
|
3085
|
+
change_desc)
|
2975
3086
|
|
2976
3087
|
if options.squash:
|
2977
3088
|
regex = re.compile(r'remote:\s+https?://[\w\-\.\/]*/(\d+)\s.*')
|
@@ -2985,19 +3096,91 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
2985
3096
|
self.SetIssue(change_numbers[0])
|
2986
3097
|
self._GitSetBranchConfigValue('gerritsquashhash', ref_to_push)
|
2987
3098
|
|
3099
|
+
reviewers = sorted(change_desc.get_reviewers())
|
3100
|
+
|
2988
3101
|
# Add cc's from the CC_LIST and --cc flag (if any).
|
2989
|
-
|
3102
|
+
if not options.private:
|
3103
|
+
cc = self.GetCCList().split(',')
|
3104
|
+
else:
|
3105
|
+
cc = []
|
2990
3106
|
if options.cc:
|
2991
3107
|
cc.extend(options.cc)
|
2992
3108
|
cc = filter(None, [email.strip() for email in cc])
|
2993
3109
|
if change_desc.get_cced():
|
2994
3110
|
cc.extend(change_desc.get_cced())
|
2995
|
-
|
2996
|
-
|
2997
|
-
|
2998
|
-
|
3111
|
+
|
3112
|
+
gerrit_util.AddReviewers(
|
3113
|
+
self._GetGerritHost(), self.GetIssue(), reviewers, cc,
|
3114
|
+
notify=bool(options.send_mail))
|
3115
|
+
|
3116
|
+
if change_desc.get_reviewers(tbr_only=True):
|
3117
|
+
print('Adding self-LGTM (Code-Review +1) because of TBRs.')
|
3118
|
+
gerrit_util.SetReview(
|
3119
|
+
self._GetGerritHost(), self.GetIssue(),
|
3120
|
+
labels={'Code-Review': 1}, notify=bool(options.send_mail))
|
3121
|
+
|
2999
3122
|
return 0
|
3000
3123
|
|
3124
|
+
def _ComputeParent(self, remote, upstream_branch, custom_cl_base, force,
|
3125
|
+
change_desc):
|
3126
|
+
"""Computes parent of the generated commit to be uploaded to Gerrit.
|
3127
|
+
|
3128
|
+
Returns revision or a ref name.
|
3129
|
+
"""
|
3130
|
+
if custom_cl_base:
|
3131
|
+
# Try to avoid creating additional unintended CLs when uploading, unless
|
3132
|
+
# user wants to take this risk.
|
3133
|
+
local_ref_of_target_remote = self.GetRemoteBranch()[1]
|
3134
|
+
code, _ = RunGitWithCode(['merge-base', '--is-ancestor', custom_cl_base,
|
3135
|
+
local_ref_of_target_remote])
|
3136
|
+
if code == 1:
|
3137
|
+
print('\nWARNING: Manually specified base of this CL `%s` '
|
3138
|
+
'doesn\'t seem to belong to target remote branch `%s`.\n\n'
|
3139
|
+
'If you proceed with upload, more than 1 CL may be created by '
|
3140
|
+
'Gerrit as a result, in turn confusing or crashing git cl.\n\n'
|
3141
|
+
'If you are certain that specified base `%s` has already been '
|
3142
|
+
'uploaded to Gerrit as another CL, you may proceed.\n' %
|
3143
|
+
(custom_cl_base, local_ref_of_target_remote, custom_cl_base))
|
3144
|
+
if not force:
|
3145
|
+
confirm_or_exit(
|
3146
|
+
'Do you take responsibility for cleaning up potential mess '
|
3147
|
+
'resulting from proceeding with upload?',
|
3148
|
+
action='upload')
|
3149
|
+
return custom_cl_base
|
3150
|
+
|
3151
|
+
if remote != '.':
|
3152
|
+
return self.GetCommonAncestorWithUpstream()
|
3153
|
+
|
3154
|
+
# If our upstream branch is local, we base our squashed commit on its
|
3155
|
+
# squashed version.
|
3156
|
+
upstream_branch_name = scm.GIT.ShortBranchName(upstream_branch)
|
3157
|
+
|
3158
|
+
if upstream_branch_name == 'master':
|
3159
|
+
return self.GetCommonAncestorWithUpstream()
|
3160
|
+
|
3161
|
+
# Check the squashed hash of the parent.
|
3162
|
+
# TODO(tandrii): consider checking parent change in Gerrit and using its
|
3163
|
+
# hash if tree hash of latest parent revision (patchset) in Gerrit matches
|
3164
|
+
# the tree hash of the parent branch. The upside is less likely bogus
|
3165
|
+
# requests to reupload parent change just because it's uploadhash is
|
3166
|
+
# missing, yet the downside likely exists, too (albeit unknown to me yet).
|
3167
|
+
parent = RunGit(['config',
|
3168
|
+
'branch.%s.gerritsquashhash' % upstream_branch_name],
|
3169
|
+
error_ok=True).strip()
|
3170
|
+
# Verify that the upstream branch has been uploaded too, otherwise
|
3171
|
+
# Gerrit will create additional CLs when uploading.
|
3172
|
+
if not parent or (RunGitSilent(['rev-parse', upstream_branch + ':']) !=
|
3173
|
+
RunGitSilent(['rev-parse', parent + ':'])):
|
3174
|
+
DieWithError(
|
3175
|
+
'\nUpload upstream branch %s first.\n'
|
3176
|
+
'It is likely that this branch has been rebased since its last '
|
3177
|
+
'upload, so you just need to upload it again.\n'
|
3178
|
+
'(If you uploaded it with --no-squash, then branch dependencies '
|
3179
|
+
'are not supported, and you should reupload with --squash.)'
|
3180
|
+
% upstream_branch_name,
|
3181
|
+
change_desc)
|
3182
|
+
return parent
|
3183
|
+
|
3001
3184
|
def _AddChangeIdToCommitMessage(self, options, args):
|
3002
3185
|
"""Re-commits using the current message, assumes the commit hook is in
|
3003
3186
|
place.
|
@@ -3022,7 +3205,7 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
3022
3205
|
kwargs = {'labels': {'Commit-Queue': vote_map[new_state]}}
|
3023
3206
|
if new_state == _CQState.DRY_RUN:
|
3024
3207
|
# Don't spam everybody reviewer/owner.
|
3025
|
-
kwargs['notify'] =
|
3208
|
+
kwargs['notify'] = False
|
3026
3209
|
gerrit_util.SetReview(self._GetGerritHost(), self.GetIssue(), **kwargs)
|
3027
3210
|
|
3028
3211
|
def CannotTriggerTryJobReason(self):
|
@@ -3034,8 +3217,8 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
|
3034
3217
|
if data['status'] in ('ABANDONED', 'MERGED'):
|
3035
3218
|
return 'CL %s is closed' % self.GetIssue()
|
3036
3219
|
|
3037
|
-
def
|
3038
|
-
"""Returns dictionary of properties to launch
|
3220
|
+
def GetTryJobProperties(self, patchset=None):
|
3221
|
+
"""Returns dictionary of properties to launch try job."""
|
3039
3222
|
data = self._GetChangeDetail(['ALL_REVISIONS'])
|
3040
3223
|
patchset = int(patchset or self.GetPatchset())
|
3041
3224
|
assert patchset
|
@@ -3165,14 +3348,34 @@ class ChangeDescription(object):
|
|
3165
3348
|
lines.pop(-1)
|
3166
3349
|
self._description_lines = lines
|
3167
3350
|
|
3168
|
-
def update_reviewers(self, reviewers,
|
3169
|
-
"""Rewrites the R=/TBR= line(s) as a single line each.
|
3351
|
+
def update_reviewers(self, reviewers, tbrs, add_owners_to=None, change=None):
|
3352
|
+
"""Rewrites the R=/TBR= line(s) as a single line each.
|
3353
|
+
|
3354
|
+
Args:
|
3355
|
+
reviewers (list(str)) - list of additional emails to use for reviewers.
|
3356
|
+
tbrs (list(str)) - list of additional emails to use for TBRs.
|
3357
|
+
add_owners_to (None|'R'|'TBR') - Pass to do an OWNERS lookup for files in
|
3358
|
+
the change that are missing OWNER coverage. If this is not None, you
|
3359
|
+
must also pass a value for `change`.
|
3360
|
+
change (Change) - The Change that should be used for OWNERS lookups.
|
3361
|
+
"""
|
3170
3362
|
assert isinstance(reviewers, list), reviewers
|
3171
|
-
|
3363
|
+
assert isinstance(tbrs, list), tbrs
|
3364
|
+
|
3365
|
+
assert add_owners_to in (None, 'TBR', 'R'), add_owners_to
|
3366
|
+
assert not add_owners_to or change, add_owners_to
|
3367
|
+
|
3368
|
+
if not reviewers and not tbrs and not add_owners_to:
|
3172
3369
|
return
|
3173
|
-
reviewers = reviewers[:]
|
3174
3370
|
|
3175
|
-
|
3371
|
+
reviewers = set(reviewers)
|
3372
|
+
tbrs = set(tbrs)
|
3373
|
+
LOOKUP = {
|
3374
|
+
'TBR': tbrs,
|
3375
|
+
'R': reviewers,
|
3376
|
+
}
|
3377
|
+
|
3378
|
+
# Get the set of R= and TBR= lines and remove them from the description.
|
3176
3379
|
regexp = re.compile(self.R_LINE)
|
3177
3380
|
matches = [regexp.match(line) for line in self._description_lines]
|
3178
3381
|
new_desc = [l for i, l in enumerate(self._description_lines)
|
@@ -3180,29 +3383,27 @@ class ChangeDescription(object):
|
|
3180
3383
|
self.set_description(new_desc)
|
3181
3384
|
|
3182
3385
|
# Construct new unified R= and TBR= lines.
|
3183
|
-
|
3184
|
-
|
3386
|
+
|
3387
|
+
# First, update tbrs/reviewers with names from the R=/TBR= lines (if any).
|
3185
3388
|
for match in matches:
|
3186
3389
|
if not match:
|
3187
3390
|
continue
|
3188
|
-
|
3189
|
-
|
3190
|
-
|
3191
|
-
|
3192
|
-
r_names.extend(people)
|
3193
|
-
for name in r_names:
|
3194
|
-
if name not in reviewers:
|
3195
|
-
reviewers.append(name)
|
3196
|
-
if add_owners_tbr:
|
3391
|
+
LOOKUP[match.group(1)].update(cleanup_list([match.group(2).strip()]))
|
3392
|
+
|
3393
|
+
# Next, maybe fill in OWNERS coverage gaps to either tbrs/reviewers.
|
3394
|
+
if add_owners_to:
|
3197
3395
|
owners_db = owners.Database(change.RepositoryRoot(),
|
3198
|
-
|
3199
|
-
all_reviewers = set(tbr_names + reviewers)
|
3396
|
+
fopen=file, os_path=os.path)
|
3200
3397
|
missing_files = owners_db.files_not_covered_by(change.LocalPaths(),
|
3201
|
-
|
3202
|
-
|
3203
|
-
|
3204
|
-
|
3205
|
-
|
3398
|
+
(tbrs | reviewers))
|
3399
|
+
LOOKUP[add_owners_to].update(
|
3400
|
+
owners_db.reviewers_for(missing_files, change.author_email))
|
3401
|
+
|
3402
|
+
# If any folks ended up in both groups, remove them from tbrs.
|
3403
|
+
tbrs -= reviewers
|
3404
|
+
|
3405
|
+
new_r_line = 'R=' + ', '.join(sorted(reviewers)) if reviewers else None
|
3406
|
+
new_tbr_line = 'TBR=' + ', '.join(sorted(tbrs)) if tbrs else None
|
3206
3407
|
|
3207
3408
|
# Put the new lines in the description where the old first R= line was.
|
3208
3409
|
line_loc = next((i for i, match in enumerate(matches) if match), -1)
|
@@ -3322,13 +3523,14 @@ class ChangeDescription(object):
|
|
3322
3523
|
re.match(self.CHERRY_PICK_LINE, self._description_lines[-1])):
|
3323
3524
|
cp_line = self._description_lines.pop()
|
3324
3525
|
|
3325
|
-
top_lines,
|
3526
|
+
top_lines, footer_lines, _ = git_footers.split_footers(self.description)
|
3326
3527
|
|
3327
3528
|
# Original-ify all Cr- footers, to avoid re-lands, cherry-picks, or just
|
3328
3529
|
# user interference with actual footers we'd insert below.
|
3329
|
-
for i,
|
3330
|
-
|
3331
|
-
|
3530
|
+
for i, line in enumerate(footer_lines):
|
3531
|
+
k, v = git_footers.parse_footer(line) or (None, None)
|
3532
|
+
if k and k.startswith('Cr-'):
|
3533
|
+
footer_lines[i] = '%s: %s' % ('Cr-Original-' + k[len('Cr-'):], v)
|
3332
3534
|
|
3333
3535
|
# Add Position and Lineage footers based on the parent.
|
3334
3536
|
lineage = list(reversed(parent_footer_map.get('Cr-Branched-From', [])))
|
@@ -3340,30 +3542,32 @@ class ChangeDescription(object):
|
|
3340
3542
|
lineage.insert(0, '%s-%s@{#%d}' % (parent_hash, parent_position[0],
|
3341
3543
|
int(parent_position[1])))
|
3342
3544
|
|
3343
|
-
|
3344
|
-
|
3345
|
-
parsed_footers.extend(('Cr-Branched-From', v) for v in lineage)
|
3545
|
+
footer_lines.append('Cr-Commit-Position: %s@{#%d}' % (dest_ref, number))
|
3546
|
+
footer_lines.extend('Cr-Branched-From: %s' % v for v in lineage)
|
3346
3547
|
|
3347
3548
|
self._description_lines = top_lines
|
3348
3549
|
if cp_line:
|
3349
3550
|
self._description_lines.append(cp_line)
|
3350
3551
|
if self._description_lines[-1] != '':
|
3351
3552
|
self._description_lines.append('') # Ensure footer separator.
|
3352
|
-
self._description_lines.extend(
|
3553
|
+
self._description_lines.extend(footer_lines)
|
3353
3554
|
|
3354
3555
|
|
3355
|
-
def get_approving_reviewers(props):
|
3556
|
+
def get_approving_reviewers(props, disapproval=False):
|
3356
3557
|
"""Retrieves the reviewers that approved a CL from the issue properties with
|
3357
3558
|
messages.
|
3358
3559
|
|
3359
3560
|
Note that the list may contain reviewers that are not committer, thus are not
|
3360
3561
|
considered by the CQ.
|
3562
|
+
|
3563
|
+
If disapproval is True, instead returns reviewers who 'not lgtm'd the CL.
|
3361
3564
|
"""
|
3565
|
+
approval_type = 'disapproval' if disapproval else 'approval'
|
3362
3566
|
return sorted(
|
3363
3567
|
set(
|
3364
3568
|
message['sender']
|
3365
3569
|
for message in props['messages']
|
3366
|
-
if message[
|
3570
|
+
if message[approval_type] and message['sender'] in props['reviewers']
|
3367
3571
|
)
|
3368
3572
|
)
|
3369
3573
|
|
@@ -3520,7 +3724,7 @@ def GetRietveldCodereviewSettingsInteractively():
|
|
3520
3724
|
|
3521
3725
|
|
3522
3726
|
class _GitCookiesChecker(object):
|
3523
|
-
"""Provides
|
3727
|
+
"""Provides facilities for validating and suggesting fixes to .gitcookies."""
|
3524
3728
|
|
3525
3729
|
_GOOGLESOURCE = 'googlesource.com'
|
3526
3730
|
|
@@ -3535,6 +3739,7 @@ class _GitCookiesChecker(object):
|
|
3535
3739
|
default = gerrit_util.CookiesAuthenticator.get_gitcookies_path()
|
3536
3740
|
configured_path = RunGitSilent(
|
3537
3741
|
['config', '--global', 'http.cookiefile']).strip()
|
3742
|
+
configured_path = os.path.expanduser(configured_path)
|
3538
3743
|
if configured_path:
|
3539
3744
|
self._ensure_default_gitcookies_path(configured_path, default)
|
3540
3745
|
else:
|
@@ -3548,7 +3753,7 @@ class _GitCookiesChecker(object):
|
|
3548
3753
|
configured_path)
|
3549
3754
|
return
|
3550
3755
|
|
3551
|
-
print('WARNING:
|
3756
|
+
print('WARNING: You have configured custom path to .gitcookies: %s\n'
|
3552
3757
|
'Gerrit and other depot_tools expect .gitcookies at %s\n' %
|
3553
3758
|
(configured_path, default_path))
|
3554
3759
|
|
@@ -3646,6 +3851,12 @@ class _GitCookiesChecker(object):
|
|
3646
3851
|
prefix = git_host.split('.', 1)[0]
|
3647
3852
|
return prefix + '-review.' + self._GOOGLESOURCE
|
3648
3853
|
|
3854
|
+
def _get_counterpart_host(self, host):
|
3855
|
+
assert host.endswith(self._GOOGLESOURCE)
|
3856
|
+
git = self._canonical_git_googlesource_host(host)
|
3857
|
+
gerrit = self._canonical_gerrit_googlesource_host(git)
|
3858
|
+
return git if gerrit == host else gerrit
|
3859
|
+
|
3649
3860
|
def has_generic_host(self):
|
3650
3861
|
"""Returns whether generic .googlesource.com has been configured.
|
3651
3862
|
|
@@ -3671,14 +3882,14 @@ class _GitCookiesChecker(object):
|
|
3671
3882
|
|
3672
3883
|
def get_partially_configured_hosts(self):
|
3673
3884
|
return set(
|
3674
|
-
host
|
3675
|
-
self._get_git_gerrit_identity_pairs().iteritems()
|
3676
|
-
if None in
|
3885
|
+
(host if i1 else self._canonical_gerrit_googlesource_host(host))
|
3886
|
+
for host, (i1, i2) in self._get_git_gerrit_identity_pairs().iteritems()
|
3887
|
+
if None in (i1, i2) and host != '.' + self._GOOGLESOURCE)
|
3677
3888
|
|
3678
3889
|
def get_conflicting_hosts(self):
|
3679
3890
|
return set(
|
3680
|
-
host
|
3681
|
-
self._get_git_gerrit_identity_pairs().iteritems()
|
3891
|
+
host
|
3892
|
+
for host, (i1, i2) in self._get_git_gerrit_identity_pairs().iteritems()
|
3682
3893
|
if None not in (i1, i2) and i1 != i2)
|
3683
3894
|
|
3684
3895
|
def get_duplicated_hosts(self):
|
@@ -3705,61 +3916,83 @@ class _GitCookiesChecker(object):
|
|
3705
3916
|
return hosts
|
3706
3917
|
|
3707
3918
|
@staticmethod
|
3708
|
-
def
|
3919
|
+
def _format_hosts(hosts, extra_column_func=None):
|
3709
3920
|
hosts = sorted(hosts)
|
3710
3921
|
assert hosts
|
3711
3922
|
if extra_column_func is None:
|
3712
3923
|
extras = [''] * len(hosts)
|
3713
3924
|
else:
|
3714
3925
|
extras = [extra_column_func(host) for host in hosts]
|
3715
|
-
tmpl = '
|
3926
|
+
tmpl = '%%-%ds %%-%ds' % (max(map(len, hosts)), max(map(len, extras)))
|
3927
|
+
lines = []
|
3716
3928
|
for he in zip(hosts, extras):
|
3717
|
-
|
3718
|
-
|
3719
|
-
|
3720
|
-
def find_and_report_problems(self):
|
3721
|
-
"""Returns True if there was at least one problem, else False."""
|
3722
|
-
problems = [False]
|
3723
|
-
def add_problem():
|
3724
|
-
if not problems[0]:
|
3725
|
-
print('\n\n.gitcookies problem report:\n')
|
3726
|
-
problems[0] = True
|
3929
|
+
lines.append(tmpl % he)
|
3930
|
+
return lines
|
3727
3931
|
|
3932
|
+
def _find_problems(self):
|
3728
3933
|
if self.has_generic_host():
|
3729
|
-
|
3730
|
-
|
3731
|
-
|
3732
|
-
|
3934
|
+
yield ('.googlesource.com wildcard record detected',
|
3935
|
+
['Chrome Infrastructure team recommends to list full host names '
|
3936
|
+
'explicitly.'],
|
3937
|
+
None)
|
3733
3938
|
|
3734
3939
|
dups = self.get_duplicated_hosts()
|
3735
3940
|
if dups:
|
3736
|
-
|
3737
|
-
|
3738
|
-
|
3941
|
+
yield ('The following hosts were defined twice',
|
3942
|
+
self._format_hosts(dups),
|
3943
|
+
None)
|
3739
3944
|
|
3740
3945
|
partial = self.get_partially_configured_hosts()
|
3741
3946
|
if partial:
|
3742
|
-
|
3743
|
-
|
3744
|
-
|
3745
|
-
|
3947
|
+
yield ('Credentials should come in pairs for Git and Gerrit hosts. '
|
3948
|
+
'These hosts are missing',
|
3949
|
+
self._format_hosts(partial, lambda host: 'but %s defined' %
|
3950
|
+
self._get_counterpart_host(host)),
|
3951
|
+
partial)
|
3746
3952
|
|
3747
3953
|
conflicting = self.get_conflicting_hosts()
|
3748
3954
|
if conflicting:
|
3749
|
-
|
3750
|
-
|
3751
|
-
|
3752
|
-
|
3753
|
-
|
3955
|
+
yield ('The following Git hosts have differing credentials from their '
|
3956
|
+
'Gerrit counterparts',
|
3957
|
+
self._format_hosts(conflicting, lambda host: '%s vs %s' %
|
3958
|
+
tuple(self._get_git_gerrit_identity_pairs()[host])),
|
3959
|
+
conflicting)
|
3754
3960
|
|
3755
3961
|
wrong = self.get_hosts_with_wrong_identities()
|
3756
3962
|
if wrong:
|
3757
|
-
|
3758
|
-
|
3759
|
-
|
3760
|
-
|
3761
|
-
|
3762
|
-
|
3963
|
+
yield ('These hosts likely use wrong identity',
|
3964
|
+
self._format_hosts(wrong, lambda host: '%s but %s recommended' %
|
3965
|
+
(self._get_git_gerrit_identity_pairs()[host][0],
|
3966
|
+
self._EXPECTED_HOST_IDENTITY_DOMAINS[host])),
|
3967
|
+
wrong)
|
3968
|
+
|
3969
|
+
def find_and_report_problems(self):
|
3970
|
+
"""Returns True if there was at least one problem, else False."""
|
3971
|
+
found = False
|
3972
|
+
bad_hosts = set()
|
3973
|
+
for title, sublines, hosts in self._find_problems():
|
3974
|
+
if not found:
|
3975
|
+
found = True
|
3976
|
+
print('\n\n.gitcookies problem report:\n')
|
3977
|
+
bad_hosts.update(hosts or [])
|
3978
|
+
print(' %s%s' % (title , (':' if sublines else '')))
|
3979
|
+
if sublines:
|
3980
|
+
print()
|
3981
|
+
print(' %s' % '\n '.join(sublines))
|
3982
|
+
print()
|
3983
|
+
|
3984
|
+
if bad_hosts:
|
3985
|
+
assert found
|
3986
|
+
print(' You can manually remove corresponding lines in your %s file and '
|
3987
|
+
'visit the following URLs with correct account to generate '
|
3988
|
+
'correct credential lines:\n' %
|
3989
|
+
gerrit_util.CookiesAuthenticator.get_gitcookies_path())
|
3990
|
+
print(' %s' % '\n '.join(sorted(set(
|
3991
|
+
gerrit_util.CookiesAuthenticator().get_new_password_url(
|
3992
|
+
self._canonical_git_googlesource_host(host))
|
3993
|
+
for host in bad_hosts
|
3994
|
+
))))
|
3995
|
+
return found
|
3763
3996
|
|
3764
3997
|
|
3765
3998
|
def CMDcreds_check(parser, args):
|
@@ -3776,7 +4009,7 @@ def CMDcreds_check(parser, args):
|
|
3776
4009
|
checker.print_current_creds(include_netrc=True)
|
3777
4010
|
|
3778
4011
|
if not checker.find_and_report_problems():
|
3779
|
-
print('\nNo problems detected in your .gitcookies')
|
4012
|
+
print('\nNo problems detected in your .gitcookies file.')
|
3780
4013
|
return 0
|
3781
4014
|
return 1
|
3782
4015
|
|
@@ -3785,7 +4018,7 @@ def CMDcreds_check(parser, args):
|
|
3785
4018
|
def CMDconfig(parser, args):
|
3786
4019
|
"""Edits configuration for this tree."""
|
3787
4020
|
|
3788
|
-
print('WARNING: git cl config works for Rietveld only')
|
4021
|
+
print('WARNING: git cl config works for Rietveld only.')
|
3789
4022
|
# TODO(tandrii): remove this once we switch to Gerrit.
|
3790
4023
|
# See bugs http://crbug.com/637561 and http://crbug.com/600469.
|
3791
4024
|
parser.add_option('--activate-update', action='store_true',
|
@@ -3835,9 +4068,10 @@ def CMDbaseurl(parser, args):
|
|
3835
4068
|
def color_for_status(status):
|
3836
4069
|
"""Maps a Changelist status to color, for CMDstatus and other tools."""
|
3837
4070
|
return {
|
3838
|
-
'unsent': Fore.
|
4071
|
+
'unsent': Fore.YELLOW,
|
3839
4072
|
'waiting': Fore.BLUE,
|
3840
4073
|
'reply': Fore.YELLOW,
|
4074
|
+
'not lgtm': Fore.RED,
|
3841
4075
|
'lgtm': Fore.GREEN,
|
3842
4076
|
'commit': Fore.MAGENTA,
|
3843
4077
|
'closed': Fore.CYAN,
|
@@ -3865,7 +4099,7 @@ def get_cl_statuses(changes, fine_grained, max_processes=None):
|
|
3865
4099
|
|
3866
4100
|
if not fine_grained:
|
3867
4101
|
# Fast path which doesn't involve querying codereview servers.
|
3868
|
-
# Do not use
|
4102
|
+
# Do not use get_approving_reviewers(), since it requires an HTTP request.
|
3869
4103
|
for cl in changes:
|
3870
4104
|
yield (cl, 'waiting' if cl.GetIssueURL() else 'error')
|
3871
4105
|
return
|
@@ -4091,12 +4325,13 @@ def CMDstatus(parser, args):
|
|
4091
4325
|
"""Show status of changelists.
|
4092
4326
|
|
4093
4327
|
Colors are used to tell the state of the CL unless --fast is used:
|
4094
|
-
- Red not sent for review or broken
|
4095
4328
|
- Blue waiting for review
|
4096
|
-
- Yellow waiting for you to reply to review
|
4329
|
+
- Yellow waiting for you to reply to review, or not yet sent
|
4097
4330
|
- Green LGTM'ed
|
4331
|
+
- Red 'not LGTM'ed
|
4098
4332
|
- Magenta in the commit queue
|
4099
4333
|
- Cyan was committed, branch can be deleted
|
4334
|
+
- White error, or unknown status
|
4100
4335
|
|
4101
4336
|
Also see 'git cl comments'.
|
4102
4337
|
"""
|
@@ -4201,7 +4436,7 @@ def colorize_CMDstatus_doc():
|
|
4201
4436
|
def colorize_line(line):
|
4202
4437
|
for color in colors:
|
4203
4438
|
if color in line.upper():
|
4204
|
-
# Extract
|
4439
|
+
# Extract whitespace first and the leading '-'.
|
4205
4440
|
indent = len(line) - len(line.lstrip(' ')) + 1
|
4206
4441
|
return line[:indent] + getattr(Fore, color) + line[indent:] + Fore.RESET
|
4207
4442
|
return line
|
@@ -4211,8 +4446,11 @@ def colorize_CMDstatus_doc():
|
|
4211
4446
|
|
4212
4447
|
|
4213
4448
|
def write_json(path, contents):
|
4214
|
-
|
4215
|
-
json.dump(contents,
|
4449
|
+
if path == '-':
|
4450
|
+
json.dump(contents, sys.stdout)
|
4451
|
+
else:
|
4452
|
+
with open(path, 'w') as f:
|
4453
|
+
json.dump(contents, f)
|
4216
4454
|
|
4217
4455
|
|
4218
4456
|
@subcommand.usage('[issue_number]')
|
@@ -4225,7 +4463,8 @@ def CMDissue(parser, args):
|
|
4225
4463
|
help='Lookup the branch(es) for the specified issues. If '
|
4226
4464
|
'no issues are specified, all branches with mapped '
|
4227
4465
|
'issues will be listed.')
|
4228
|
-
parser.add_option('--json',
|
4466
|
+
parser.add_option('--json',
|
4467
|
+
help='Path to JSON output file, or "-" for stdout.')
|
4229
4468
|
_add_codereview_select_options(parser)
|
4230
4469
|
options, args = parser.parse_args(args)
|
4231
4470
|
_process_codereview_select_options(parser, options)
|
@@ -4233,7 +4472,6 @@ def CMDissue(parser, args):
|
|
4233
4472
|
if options.reverse:
|
4234
4473
|
branches = RunGit(['for-each-ref', 'refs/heads',
|
4235
4474
|
'--format=%(refname:short)']).splitlines()
|
4236
|
-
|
4237
4475
|
# Reverse issue lookup.
|
4238
4476
|
issue_branch_map = {}
|
4239
4477
|
for branch in branches:
|
@@ -4250,21 +4488,24 @@ def CMDissue(parser, args):
|
|
4250
4488
|
issue, ', '.join(issue_branch_map.get(int(issue)) or ('None',))))
|
4251
4489
|
if options.json:
|
4252
4490
|
write_json(options.json, result)
|
4491
|
+
return 0
|
4492
|
+
|
4493
|
+
if len(args) > 0:
|
4494
|
+
issue = ParseIssueNumberArgument(args[0], options.forced_codereview)
|
4495
|
+
if not issue.valid:
|
4496
|
+
DieWithError('Pass a url or number to set the issue, 0 to unset it, '
|
4497
|
+
'or no argument to list it.\n'
|
4498
|
+
'Maybe you want to run git cl status?')
|
4499
|
+
cl = Changelist(codereview=issue.codereview)
|
4500
|
+
cl.SetIssue(issue.issue)
|
4253
4501
|
else:
|
4254
4502
|
cl = Changelist(codereview=options.forced_codereview)
|
4255
|
-
|
4256
|
-
|
4257
|
-
|
4258
|
-
|
4259
|
-
|
4260
|
-
|
4261
|
-
cl.SetIssue(issue)
|
4262
|
-
print('Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()))
|
4263
|
-
if options.json:
|
4264
|
-
write_json(options.json, {
|
4265
|
-
'issue': cl.GetIssue(),
|
4266
|
-
'issue_url': cl.GetIssueURL(),
|
4267
|
-
})
|
4503
|
+
print('Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()))
|
4504
|
+
if options.json:
|
4505
|
+
write_json(options.json, {
|
4506
|
+
'issue': cl.GetIssue(),
|
4507
|
+
'issue_url': cl.GetIssueURL(),
|
4508
|
+
})
|
4268
4509
|
return 0
|
4269
4510
|
|
4270
4511
|
|
@@ -4275,8 +4516,12 @@ def CMDcomments(parser, args):
|
|
4275
4516
|
parser.add_option('-i', '--issue', dest='issue',
|
4276
4517
|
help='review issue id (defaults to current issue). '
|
4277
4518
|
'If given, requires --rietveld or --gerrit')
|
4519
|
+
parser.add_option('-m', '--machine-readable', dest='readable',
|
4520
|
+
action='store_false', default=True,
|
4521
|
+
help='output comments in a format compatible with '
|
4522
|
+
'editor parsing')
|
4278
4523
|
parser.add_option('-j', '--json-file',
|
4279
|
-
help='File to write JSON summary to')
|
4524
|
+
help='File to write JSON summary to, or "-" for stdout')
|
4280
4525
|
auth.add_auth_options(parser)
|
4281
4526
|
_add_codereview_select_options(parser)
|
4282
4527
|
options, args = parser.parse_args(args)
|
@@ -4293,16 +4538,15 @@ def CMDcomments(parser, args):
|
|
4293
4538
|
parser.error('--gerrit or --rietveld is required if --issue is specified')
|
4294
4539
|
|
4295
4540
|
cl = Changelist(issue=issue,
|
4296
|
-
|
4297
|
-
codereview=options.forced_codereview or (
|
4298
|
-
'rietveld' if issue else None),
|
4541
|
+
codereview=options.forced_codereview,
|
4299
4542
|
auth_config=auth_config)
|
4300
4543
|
|
4301
4544
|
if options.comment:
|
4302
4545
|
cl.AddComment(options.comment)
|
4303
4546
|
return 0
|
4304
4547
|
|
4305
|
-
summary = sorted(cl.GetCommentsSummary(
|
4548
|
+
summary = sorted(cl.GetCommentsSummary(readable=options.readable),
|
4549
|
+
key=lambda c: c.date)
|
4306
4550
|
for comment in summary:
|
4307
4551
|
if comment.disapproval:
|
4308
4552
|
color = Fore.RED
|
@@ -4348,10 +4592,10 @@ def CMDdescription(parser, args):
|
|
4348
4592
|
|
4349
4593
|
target_issue_arg = None
|
4350
4594
|
if len(args) > 0:
|
4351
|
-
target_issue_arg = ParseIssueNumberArgument(args[0]
|
4595
|
+
target_issue_arg = ParseIssueNumberArgument(args[0],
|
4596
|
+
options.forced_codereview)
|
4352
4597
|
if not target_issue_arg.valid:
|
4353
|
-
parser.
|
4354
|
-
return 1
|
4598
|
+
parser.error('invalid codereview url or CL id')
|
4355
4599
|
|
4356
4600
|
auth_config = auth.extract_auth_config_from_options(options)
|
4357
4601
|
|
@@ -4359,14 +4603,23 @@ def CMDdescription(parser, args):
|
|
4359
4603
|
'auth_config': auth_config,
|
4360
4604
|
'codereview': options.forced_codereview,
|
4361
4605
|
}
|
4606
|
+
detected_codereview_from_url = False
|
4362
4607
|
if target_issue_arg:
|
4363
4608
|
kwargs['issue'] = target_issue_arg.issue
|
4364
4609
|
kwargs['codereview_host'] = target_issue_arg.hostname
|
4610
|
+
if target_issue_arg.codereview and not options.forced_codereview:
|
4611
|
+
detected_codereview_from_url = True
|
4612
|
+
kwargs['codereview'] = target_issue_arg.codereview
|
4365
4613
|
|
4366
4614
|
cl = Changelist(**kwargs)
|
4367
|
-
|
4368
4615
|
if not cl.GetIssue():
|
4616
|
+
assert not detected_codereview_from_url
|
4369
4617
|
DieWithError('This branch has no associated changelist.')
|
4618
|
+
|
4619
|
+
if detected_codereview_from_url:
|
4620
|
+
logging.info('canonical issue/change URL: %s (type: %s)\n',
|
4621
|
+
cl.GetIssueURL(), target_issue_arg.codereview)
|
4622
|
+
|
4370
4623
|
description = ChangeDescription(cl.GetDescription())
|
4371
4624
|
|
4372
4625
|
if options.display:
|
@@ -4531,7 +4784,7 @@ def GetTargetRef(remote, remote_branch, target_branch):
|
|
4531
4784
|
return None
|
4532
4785
|
|
4533
4786
|
if target_branch:
|
4534
|
-
#
|
4787
|
+
# Canonicalize branch references to the equivalent local full symbolic
|
4535
4788
|
# refs, which are then translated into the remote full symbolic refs
|
4536
4789
|
# below.
|
4537
4790
|
if '/' not in target_branch:
|
@@ -4611,6 +4864,9 @@ def CMDupload(parser, args):
|
|
4611
4864
|
parser.add_option('-r', '--reviewers',
|
4612
4865
|
action='append', default=[],
|
4613
4866
|
help='reviewer email addresses')
|
4867
|
+
parser.add_option('--tbrs',
|
4868
|
+
action='append', default=[],
|
4869
|
+
help='TBR email addresses')
|
4614
4870
|
parser.add_option('--cc',
|
4615
4871
|
action='append', default=[],
|
4616
4872
|
help='cc email addresses')
|
@@ -4639,8 +4895,10 @@ def CMDupload(parser, args):
|
|
4639
4895
|
help='Topic to specify when uploading (Gerrit only)')
|
4640
4896
|
parser.add_option('--email', default=None,
|
4641
4897
|
help='email address to use to connect to Rietveld')
|
4642
|
-
parser.add_option('--tbr-owners', dest='
|
4643
|
-
help='add a set of OWNERS to TBR')
|
4898
|
+
parser.add_option('--tbr-owners', dest='add_owners_to', action='store_const',
|
4899
|
+
const='TBR', help='add a set of OWNERS to TBR')
|
4900
|
+
parser.add_option('--r-owners', dest='add_owners_to', action='store_const',
|
4901
|
+
const='R', help='add a set of OWNERS to R')
|
4644
4902
|
parser.add_option('-d', '--cq-dry-run', dest='cq_dry_run',
|
4645
4903
|
action='store_true',
|
4646
4904
|
help='Send the patchset to do a CQ dry run right after '
|
@@ -4661,6 +4919,7 @@ def CMDupload(parser, args):
|
|
4661
4919
|
return 1
|
4662
4920
|
|
4663
4921
|
options.reviewers = cleanup_list(options.reviewers)
|
4922
|
+
options.tbrs = cleanup_list(options.tbrs)
|
4664
4923
|
options.cc = cleanup_list(options.cc)
|
4665
4924
|
|
4666
4925
|
if options.message_file:
|
@@ -4679,6 +4938,31 @@ def CMDupload(parser, args):
|
|
4679
4938
|
return cl.CMDUpload(options, args, orig_args)
|
4680
4939
|
|
4681
4940
|
|
4941
|
+
@subcommand.usage('--description=<description file>')
|
4942
|
+
def CMDsplit(parser, args):
|
4943
|
+
"""Splits a branch into smaller branches and uploads CLs.
|
4944
|
+
|
4945
|
+
Creates a branch and uploads a CL for each group of files modified in the
|
4946
|
+
current branch that share a common OWNERS file. In the CL description and
|
4947
|
+
comment, the string '$directory', is replaced with the directory containing
|
4948
|
+
the shared OWNERS file.
|
4949
|
+
"""
|
4950
|
+
parser.add_option("-d", "--description", dest="description_file",
|
4951
|
+
help="A text file containing a CL description. ")
|
4952
|
+
parser.add_option("-c", "--comment", dest="comment_file",
|
4953
|
+
help="A text file containing a CL comment.")
|
4954
|
+
options, _ = parser.parse_args(args)
|
4955
|
+
|
4956
|
+
if not options.description_file:
|
4957
|
+
parser.error('No --description flag specified.')
|
4958
|
+
|
4959
|
+
def WrappedCMDupload(args):
|
4960
|
+
return CMDupload(OptionParser(), args)
|
4961
|
+
|
4962
|
+
return split_cl.SplitCl(options.description_file, options.comment_file,
|
4963
|
+
Changelist, WrappedCMDupload)
|
4964
|
+
|
4965
|
+
|
4682
4966
|
@subcommand.usage('DEPRECATED')
|
4683
4967
|
def CMDdcommit(parser, args):
|
4684
4968
|
"""DEPRECATED: Used to commit the current changelist via git-svn."""
|
@@ -4766,7 +5050,7 @@ def CMDland(parser, args):
|
|
4766
5050
|
|
4767
5051
|
if options.contributor:
|
4768
5052
|
if not re.match('^.*\s<\S+@\S+>$', options.contributor):
|
4769
|
-
print("Please provide
|
5053
|
+
print("Please provide contributor as 'First Last <email@example.com>'")
|
4770
5054
|
return 1
|
4771
5055
|
|
4772
5056
|
base_branch = args[0]
|
@@ -4824,7 +5108,8 @@ def CMDland(parser, args):
|
|
4824
5108
|
# contains the link to the Rietveld issue, while the Rietveld message contains
|
4825
5109
|
# the commit viewvc url.
|
4826
5110
|
if cl.GetIssue():
|
4827
|
-
change_desc.update_reviewers(
|
5111
|
+
change_desc.update_reviewers(
|
5112
|
+
get_approving_reviewers(cl.GetIssueProperties()), [])
|
4828
5113
|
|
4829
5114
|
commit_desc = ChangeDescription(change_desc.description)
|
4830
5115
|
if cl.GetIssue():
|
@@ -4996,7 +5281,10 @@ def PushToGitWithAutoRebase(remote, branch, original_description,
|
|
4996
5281
|
break
|
4997
5282
|
if IsFatalPushFailure(out):
|
4998
5283
|
print('Fatal push error. Make sure your .netrc credentials and git '
|
4999
|
-
'user.email are correct and you have push access to the repo
|
5284
|
+
'user.email are correct and you have push access to the repo.\n'
|
5285
|
+
'Hint: run command below to diangose common Git/Gerrit credential '
|
5286
|
+
'problems:\n'
|
5287
|
+
' git cl creds-check\n')
|
5000
5288
|
break
|
5001
5289
|
return code
|
5002
5290
|
|
@@ -5012,9 +5300,9 @@ def CMDpatch(parser, args):
|
|
5012
5300
|
parser.add_option('-b', dest='newbranch',
|
5013
5301
|
help='create a new branch off trunk for the patch')
|
5014
5302
|
parser.add_option('-f', '--force', action='store_true',
|
5015
|
-
help='
|
5303
|
+
help='overwrite state on the current or chosen branch')
|
5016
5304
|
parser.add_option('-d', '--directory', action='store', metavar='DIR',
|
5017
|
-
help='
|
5305
|
+
help='change to the directory DIR immediately, '
|
5018
5306
|
'before doing anything else. Rietveld only.')
|
5019
5307
|
parser.add_option('--reject', action='store_true',
|
5020
5308
|
help='failed patches spew .rej files rather than '
|
@@ -5044,7 +5332,6 @@ def CMDpatch(parser, args):
|
|
5044
5332
|
_process_codereview_select_options(parser, options)
|
5045
5333
|
auth_config = auth.extract_auth_config_from_options(options)
|
5046
5334
|
|
5047
|
-
|
5048
5335
|
if options.reapply:
|
5049
5336
|
if options.newbranch:
|
5050
5337
|
parser.error('--reapply works on the current branch only')
|
@@ -5070,6 +5357,22 @@ def CMDpatch(parser, args):
|
|
5070
5357
|
if len(args) != 1 or not args[0]:
|
5071
5358
|
parser.error('Must specify issue number or url')
|
5072
5359
|
|
5360
|
+
target_issue_arg = ParseIssueNumberArgument(args[0],
|
5361
|
+
options.forced_codereview)
|
5362
|
+
if not target_issue_arg.valid:
|
5363
|
+
parser.error('invalid codereview url or CL id')
|
5364
|
+
|
5365
|
+
cl_kwargs = {
|
5366
|
+
'auth_config': auth_config,
|
5367
|
+
'codereview_host': target_issue_arg.hostname,
|
5368
|
+
'codereview': options.forced_codereview,
|
5369
|
+
}
|
5370
|
+
detected_codereview_from_url = False
|
5371
|
+
if target_issue_arg.codereview and not options.forced_codereview:
|
5372
|
+
detected_codereview_from_url = True
|
5373
|
+
cl_kwargs['codereview'] = target_issue_arg.codereview
|
5374
|
+
cl_kwargs['issue'] = target_issue_arg.issue
|
5375
|
+
|
5073
5376
|
# We don't want uncommitted changes mixed up with the patch.
|
5074
5377
|
if git_common.is_dirty_git_tree('patch'):
|
5075
5378
|
return 1
|
@@ -5082,7 +5385,7 @@ def CMDpatch(parser, args):
|
|
5082
5385
|
elif not GetCurrentBranch():
|
5083
5386
|
DieWithError('A branch is required to apply patch. Hint: use -b option.')
|
5084
5387
|
|
5085
|
-
cl = Changelist(
|
5388
|
+
cl = Changelist(**cl_kwargs)
|
5086
5389
|
|
5087
5390
|
if cl.IsGerrit():
|
5088
5391
|
if options.reject:
|
@@ -5092,8 +5395,13 @@ def CMDpatch(parser, args):
|
|
5092
5395
|
if options.directory:
|
5093
5396
|
parser.error('--directory is not supported with Gerrit codereview.')
|
5094
5397
|
|
5095
|
-
|
5096
|
-
|
5398
|
+
if detected_codereview_from_url:
|
5399
|
+
print('canonical issue/change URL: %s (type: %s)\n' %
|
5400
|
+
(cl.GetIssueURL(), target_issue_arg.codereview))
|
5401
|
+
|
5402
|
+
return cl.CMDPatchWithParsedIssue(target_issue_arg, options.reject,
|
5403
|
+
options.nocommit, options.directory,
|
5404
|
+
options.force)
|
5097
5405
|
|
5098
5406
|
|
5099
5407
|
def GetTreeStatus(url=None):
|
@@ -5211,8 +5519,9 @@ def CMDtry(parser, args):
|
|
5211
5519
|
# then we default to triggering a CQ dry run (see http://crbug.com/625697).
|
5212
5520
|
if not buckets:
|
5213
5521
|
if options.verbose:
|
5214
|
-
print('git cl try with no bots now defaults to CQ
|
5215
|
-
|
5522
|
+
print('git cl try with no bots now defaults to CQ dry run.')
|
5523
|
+
print('Scheduling CQ dry run on: %s' % cl.GetIssueURL())
|
5524
|
+
return cl.SetCQState(_CQState.DRY_RUN)
|
5216
5525
|
|
5217
5526
|
for builders in buckets.itervalues():
|
5218
5527
|
if any('triggered' in b for b in builders):
|
@@ -5256,7 +5565,8 @@ def CMDtry_results(parser, args):
|
|
5256
5565
|
'--buildbucket-host', default='cr-buildbucket.appspot.com',
|
5257
5566
|
help='Host of buildbucket. The default host is %default.')
|
5258
5567
|
group.add_option(
|
5259
|
-
'--json', help='Path of JSON output file to write try job results to
|
5568
|
+
'--json', help=('Path of JSON output file to write try job results to,'
|
5569
|
+
'or "-" for stdout.'))
|
5260
5570
|
parser.add_option_group(group)
|
5261
5571
|
auth.add_auth_options(parser)
|
5262
5572
|
options, args = parser.parse_args(args)
|
@@ -5356,7 +5666,6 @@ def CMDset_commit(parser, args):
|
|
5356
5666
|
if options.clear:
|
5357
5667
|
state = _CQState.NONE
|
5358
5668
|
elif options.dry_run:
|
5359
|
-
# TODO(qyearsley): Use cl.TriggerDryRun.
|
5360
5669
|
state = _CQState.DRY_RUN
|
5361
5670
|
else:
|
5362
5671
|
state = _CQState.COMMIT
|
@@ -5438,7 +5747,7 @@ def CMDdiff(parser, args):
|
|
5438
5747
|
|
5439
5748
|
|
5440
5749
|
def CMDowners(parser, args):
|
5441
|
-
"""Interactively
|
5750
|
+
"""Interactively finds potential owners for reviewing."""
|
5442
5751
|
parser.add_option(
|
5443
5752
|
'--no-color',
|
5444
5753
|
action='store_true',
|
@@ -5463,9 +5772,10 @@ def CMDowners(parser, args):
|
|
5463
5772
|
return owners_finder.OwnersFinder(
|
5464
5773
|
[f.LocalPath() for f in
|
5465
5774
|
cl.GetChange(base_branch, None).AffectedFiles()],
|
5466
|
-
change.RepositoryRoot(),
|
5467
|
-
fopen=file, os_path=os.path,
|
5468
|
-
disable_color=options.no_color
|
5775
|
+
change.RepositoryRoot(),
|
5776
|
+
author, fopen=file, os_path=os.path,
|
5777
|
+
disable_color=options.no_color,
|
5778
|
+
override_files=change.OriginalOwnersFiles()).run()
|
5469
5779
|
|
5470
5780
|
|
5471
5781
|
def BuildGitDiffCmd(diff_type, upstream_commit, args):
|
@@ -5646,24 +5956,30 @@ def CMDformat(parser, args):
|
|
5646
5956
|
DieWithError("gn format failed on " + gn_diff_file +
|
5647
5957
|
"\nTry running 'gn format' on this file manually.")
|
5648
5958
|
|
5649
|
-
|
5650
|
-
os.path.join(
|
5651
|
-
os.path.join(
|
5652
|
-
|
5653
|
-
|
5654
|
-
|
5655
|
-
|
5656
|
-
|
5657
|
-
|
5658
|
-
|
5659
|
-
stdout = RunCommand(cmd, cwd=top_dir)
|
5660
|
-
if opts.diff:
|
5661
|
-
sys.stdout.write(stdout)
|
5662
|
-
if opts.dry_run and stdout:
|
5663
|
-
return_value = 2 # Not formatted.
|
5959
|
+
for xml_dir in GetDirtyMetricsDirs(diff_files):
|
5960
|
+
tool_dir = os.path.join(top_dir, xml_dir)
|
5961
|
+
cmd = [os.path.join(tool_dir, 'pretty_print.py'), '--non-interactive']
|
5962
|
+
if opts.dry_run or opts.diff:
|
5963
|
+
cmd.append('--diff')
|
5964
|
+
stdout = RunCommand(cmd, cwd=top_dir)
|
5965
|
+
if opts.diff:
|
5966
|
+
sys.stdout.write(stdout)
|
5967
|
+
if opts.dry_run and stdout:
|
5968
|
+
return_value = 2 # Not formatted.
|
5664
5969
|
|
5665
5970
|
return return_value
|
5666
5971
|
|
5972
|
+
def GetDirtyMetricsDirs(diff_files):
|
5973
|
+
xml_diff_files = [x for x in diff_files if MatchingFileType(x, ['.xml'])]
|
5974
|
+
metrics_xml_dirs = [
|
5975
|
+
os.path.join('tools', 'metrics', 'actions'),
|
5976
|
+
os.path.join('tools', 'metrics', 'histograms'),
|
5977
|
+
os.path.join('tools', 'metrics', 'rappor'),
|
5978
|
+
os.path.join('tools', 'metrics', 'ukm')]
|
5979
|
+
for xml_dir in metrics_xml_dirs:
|
5980
|
+
if any(file.startswith(xml_dir) for file in xml_diff_files):
|
5981
|
+
yield xml_dir
|
5982
|
+
|
5667
5983
|
|
5668
5984
|
@subcommand.usage('<codereview url or issue id>')
|
5669
5985
|
def CMDcheckout(parser, args):
|
@@ -5676,8 +5992,8 @@ def CMDcheckout(parser, args):
|
|
5676
5992
|
|
5677
5993
|
issue_arg = ParseIssueNumberArgument(args[0])
|
5678
5994
|
if not issue_arg.valid:
|
5679
|
-
parser.
|
5680
|
-
|
5995
|
+
parser.error('invalid codereview url or CL id')
|
5996
|
+
|
5681
5997
|
target_issue = str(issue_arg.issue)
|
5682
5998
|
|
5683
5999
|
def find_issues(issueprefix):
|