|
22 | 22 | from .git_helper import SSH_KEY_FILE
|
23 | 23 | import shlex
|
24 | 24 | import random
|
| 25 | +import weakref |
25 | 26 |
|
26 | 27 | STATUS_TO_PRIORITY = {
|
27 | 28 | 'success': 0,
|
@@ -343,7 +344,13 @@ def blocked_by_closed_tree(self):
|
343 | 344 | def start_testing(self, timeout):
|
344 | 345 | self.test_started = time.time() # FIXME: Save in the local database
|
345 | 346 | self.set_status('pending')
|
346 |
| - timer = Timer(timeout, self.timed_out) |
| 347 | + |
| 348 | + wm = weakref.WeakMethod(self.timed_out) |
| 349 | + def timed_out(): |
| 350 | + m = wm() |
| 351 | + if m: |
| 352 | + m() |
| 353 | + timer = Timer(timeout, timed_out) |
347 | 354 | timer.start()
|
348 | 355 | self.timeout_timer = timer
|
349 | 356 |
|
@@ -488,11 +495,20 @@ def parse_commands(body, username, repo_cfg, state, my_username, db, states,
|
488 | 495 | continue
|
489 | 496 |
|
490 | 497 | # Ignore WIP PRs
|
491 |
| - if any(map(state.title.startswith, [ |
492 |
| - 'WIP', 'TODO', '[WIP]', '[TODO]', |
493 |
| - ])): |
494 |
| - if realtime: |
495 |
| - state.add_comment(':clipboard: Looks like this PR is still in progress, ignoring approval') # noqa |
| 498 | + is_wip = False |
| 499 | + for wip_kw in ['WIP', 'TODO', '[WIP]', '[TODO]', '[DO NOT MERGE]']: |
| 500 | + if state.title.upper().startswith(wip_kw): |
| 501 | + if realtime: |
| 502 | + state.add_comment(( |
| 503 | + ':clipboard:' |
| 504 | + ' Looks like this PR is still in progress,' |
| 505 | + ' ignoring approval.\n\n' |
| 506 | + 'Hint: Remove **{}** from this PR\'s title when' |
| 507 | + ' it is ready for review.' |
| 508 | + ).format(wip_kw)) |
| 509 | + is_wip = True |
| 510 | + break |
| 511 | + if is_wip: |
496 | 512 | continue
|
497 | 513 |
|
498 | 514 | # Sometimes, GitHub sends the head SHA of a PR as 0000000
|
@@ -642,6 +658,14 @@ def parse_commands(body, username, repo_cfg, state, my_username, db, states,
|
642 | 658 | elif word in ['try', 'try-'] and realtime:
|
643 | 659 | if not _try_auth_verified():
|
644 | 660 | continue
|
| 661 | + if state.status == '' and state.approved_by: |
| 662 | + state.add_comment( |
| 663 | + ':no_good: ' |
| 664 | + 'Please do not `try` after a pull request has been `r+`ed.' |
| 665 | + ' If you need to `try`, unapprove (`r-`) it first.' |
| 666 | + ) |
| 667 | + continue |
| 668 | + |
645 | 669 | state.try_ = word == 'try'
|
646 | 670 |
|
647 | 671 | state.merge_sha = ''
|
@@ -833,6 +857,32 @@ def create_merge(state, repo_cfg, branch, logger, git_cfg,
|
833 | 857 | state.body)
|
834 | 858 |
|
835 | 859 | desc = 'Merge conflict'
|
| 860 | + comment = ( |
| 861 | + 'This pull request and the master branch diverged in a way that cannot' |
| 862 | + ' be automatically merged. Please rebase on top of the latest master' |
| 863 | + ' branch, and let the reviewer approve again.\n' |
| 864 | + '\n' |
| 865 | + '<details><summary>How do I rebase?</summary>\n\n' |
| 866 | + 'Assuming `self` is your fork and `upstream` is this repository,' |
| 867 | + ' you can resolve the conflict following these steps:\n\n' |
| 868 | + '1. `git checkout {branch}` *(switch to your branch)*\n' |
| 869 | + '2. `git fetch upstream master` *(retrieve the latest master)*\n' |
| 870 | + '3. `git rebase upstream/master -p` *(rebase on top of it)*\n' |
| 871 | + '4. Follow the on-screen instruction to resolve conflicts' |
| 872 | + ' (check `git status` if you got lost).\n' |
| 873 | + '5. `git push self {branch} --force-with-lease` *(update this PR)*\n\n' |
| 874 | + 'You may also read' |
| 875 | + ' [*Git Rebasing to Resolve Conflicts* by Drew Blessing](http://blessing.io/git/git-rebase/open-source/2015/08/23/git-rebasing-to-resolve-conflicts.html)' # noqa |
| 876 | + ' for a short tutorial.\n\n' |
| 877 | + 'Please avoid the ["**Resolve conflicts**" button](https://help.github.com/articles/resolving-a-merge-conflict-on-github/) on GitHub.' #noqa |
| 878 | + ' It uses `git merge` instead of `git rebase` which makes the PR commit' |
| 879 | + ' history more difficult to read.\n\n' |
| 880 | + 'Sometimes step 4 will complete without asking for resolution. This is' |
| 881 | + ' usually due to difference between how `Cargo.lock` conflict is' |
| 882 | + ' handled during merge and rebase. This is normal, and you should still' |
| 883 | + ' perform step 5 to update this PR.\n\n' |
| 884 | + '</details>\n\n' |
| 885 | + ).format(branch=state.head_ref.split(':', 1)[1]) |
836 | 886 |
|
837 | 887 | if git_cfg['local_git']:
|
838 | 888 |
|
@@ -861,6 +911,7 @@ def create_merge(state, repo_cfg, branch, logger, git_cfg,
|
861 | 911 | utils.silent_call(git_cmd('rebase', '--abort'))
|
862 | 912 | if utils.silent_call(git_cmd('rebase', base_sha)) == 0:
|
863 | 913 | desc = 'Auto-squashing failed'
|
| 914 | + comment = '' |
864 | 915 | else:
|
865 | 916 | ap = '<try>' if state.try_ else state.approved_by
|
866 | 917 | text = '\nCloses: #{}\nApproved by: {}'.format(state.num, ap)
|
@@ -903,22 +954,29 @@ def create_merge(state, repo_cfg, branch, logger, git_cfg,
|
903 | 954 | merge_base_sha, base_sha))
|
904 | 955 | except subprocess.CalledProcessError:
|
905 | 956 | desc = 'Auto-squashing failed'
|
| 957 | + comment = '' |
906 | 958 | ok = False
|
907 | 959 |
|
908 | 960 | if ok:
|
909 | 961 | utils.logged_call(git_cmd('checkout', '-B', branch, base_sha))
|
910 | 962 | try:
|
911 |
| - utils.logged_call(git_cmd( |
912 |
| - '-c', |
913 |
| - 'user.name=' + git_cfg['name'], |
914 |
| - '-c', |
915 |
| - 'user.email=' + git_cfg['email'], |
916 |
| - 'merge', |
917 |
| - 'heads/homu-tmp', |
918 |
| - '--no-ff', |
919 |
| - '-m', |
920 |
| - merge_msg)) |
921 |
| - except subprocess.CalledProcessError: |
| 963 | + subprocess.check_output( |
| 964 | + git_cmd( |
| 965 | + '-c', |
| 966 | + 'user.name=' + git_cfg['name'], |
| 967 | + '-c', |
| 968 | + 'user.email=' + git_cfg['email'], |
| 969 | + 'merge', |
| 970 | + 'heads/homu-tmp', |
| 971 | + '--no-ff', |
| 972 | + '-m', |
| 973 | + merge_msg), |
| 974 | + stderr=subprocess.STDOUT, |
| 975 | + universal_newlines=True) |
| 976 | + except subprocess.CalledProcessError as e: |
| 977 | + comment += '<details><summary>Error message</summary>\n\n```text\n' |
| 978 | + comment += e.output |
| 979 | + comment += '\n```\n\n</details>' |
922 | 980 | pass
|
923 | 981 | else:
|
924 | 982 | if ensure_merge_equal:
|
@@ -964,7 +1022,7 @@ def create_merge(state, repo_cfg, branch, logger, git_cfg,
|
964 | 1022 | desc,
|
965 | 1023 | context='homu')
|
966 | 1024 |
|
967 |
| - state.add_comment(':lock: ' + desc) |
| 1025 | + state.add_comment(':lock: {}\n\n{}'.format(desc, comment)) |
968 | 1026 | state.change_labels(LabelEvent.CONFLICT)
|
969 | 1027 |
|
970 | 1028 | return ''
|
|
0 commit comments