Changeset 47343 in webkit


Ignore:
Timestamp:
Aug 16, 2009 5:30:53 PM (15 years ago)
Author:
ddkilzer@apple.com
Message:

WIP: bugzilla-tool: add land-commits command

Location:
trunk/WebKitTools/Scripts
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebKitTools/Scripts/bugzilla-tool

    r47294 r47343  
    5757    return "%d %s" % (count, noun)
    5858
     59REVIEWER_PLACEHOLDER = "NOBODY (OOPS!)"
     60
    5961def view_source_url(revision_number):
    6062     return "http://trac.webkit.org/changeset/%s" % revision_number
     
    9092    # inplace=1 creates a backup file and re-directs stdout to the file
    9193    for line in fileinput.FileInput(changelog_path, inplace=1):
    92         print line.replace("NOBODY (OOPS!)", reviewer.encode("utf-8")), # Trailing comma suppresses printing newline
     94        print line.replace(REVIEWER_PLACEHOLDER, reviewer.encode("utf-8")), # Trailing comma suppresses printing newline
    9395
    9496def modified_changelogs(scm):
     
    126128    # FIXME: We should sort and label the ChangeLog messages like commit-log-editor does.
    127129    return CommitMessage(''.join(changelog_messages).splitlines())
     130
     131def guess_reviewer_from_bug(bugs, bug_id):
     132    patches = bugs.fetch_reviewed_patches_from_bug(bug_id)
     133    if len(patches) != 1:
     134        log("%s reviewed patches on bug %s, cannot infer reviewer." % ("Too many" if len(patches) > 1 else "No", bug_id))
     135        return None
     136    patch = patches[0]
     137    reviewer = patch['reviewer']
     138    log('Guessing "%s" as reviewer from attachment %s on bug %s.' % (reviewer, patch['id'], bug_id))
     139    return reviewer
     140
     141def update_changelogs_with_reviewer(reviewer, bug_id, tool):
     142    if not reviewer:
     143        error("No reviewer available; can't update ChangeLogs.");
     144
     145    changelogs = modified_changelogs(tool.scm())
     146    for changelog_path in changelogs:
     147        set_reviewer_in_changelog(changelog_path, reviewer)
    128148
    129149
     
    217237
    218238def bug_comment_from_commit_text(scm, commit_text):
     239    if scm.dryrun:
     240        return commit_text
    219241    match = re.search(scm.commit_success_regexp(), commit_text, re.MULTILINE)
    220242    svn_revision = match.group('svn_revision')
     
    288310
    289311    @classmethod
    290     def build_and_commit(cls, scm, options):
     312    def build_and_commit(cls, scm, options, commit_message=None):
    291313        if options.build:
    292314            cls.build_webkit(quiet=options.quiet)
    293315            if options.test:
    294316                cls.run_webkit_tests(launch_safari=not options.commit_queue, quiet=options.quiet)
    295         commit_message = commit_message_for_this_commit(scm)
     317        if not commit_message:
     318            commit_message = commit_message_for_this_commit(scm)
    296319        commit_log = scm.commit_with_message(commit_message.message())
    297320        return bug_comment_from_commit_text(scm, commit_log)
    298321
    299322
    300 class LandAndUpdateBug(Command):
     323class LandCommitsAndUpdateBug(Command):
     324    def __init__(self):
     325        options = [
     326            make_option("-b", "--bug-id", action="store", type="string", dest="bug_id", help="Specify bug id if no URL is provided in the commit log."),
     327            make_option("-r", "--reviewer", action="store", type="string", dest="reviewer", help="Update ChangeLogs to say Reviewed by REVIEWER."),
     328        ]
     329        options += WebKitLandingScripts.land_options()
     330        Command.__init__(self, 'Lands a range of local commits and updates bugs.', 'COMMITISH', options=options, requires_local_commits=True)
     331
     332    def execute(self, options, args, tool):
     333        commit_ids = tool.scm().commit_ids_from_commitish_arguments(args)
     334
     335        if len(commit_ids) > 10:
     336            error("Are you sure you want to land %s local patches?" % (pluralize('patch', len(commit_ids))))
     337            # Could add a --patches-limit option.
     338
     339        for commit_id in commit_ids:
     340            commit_message = tool.scm().commit_message_for_local_commit(commit_id)
     341
     342            bug_id = options.bug_id or parse_bug_id(commit_message)
     343            if not bug_id:
     344                log("Skipping %s: No bug id found in commit log or specified with --bug-id." % commit_id)
     345                continue
     346
     347            reviewer = options.reviewer or guess_reviewer_from_bug(tool.bugs, bug_id)
     348            if not reviewer:
     349                error("No reviewer available; can't update ChangeLogs.");
     350
     351            patch = {
     352                'bug_id': bug_id,
     353                'commit_id': commit_id,
     354                'diff': tool.scm().create_patch_from_local_commit(commit_id),
     355                'reviewer': reviewer,
     356            }
     357
     358            commit_message.replace_text(REVIEWER_PLACEHOLDER, reviewer)
     359            update_changelogs_with_reviewer(reviewer, bug_id, tool)
     360
     361            log("Updating bug %s" % bug_id)
     362            comment_text = LandPatchesFromBugs.land_patches(bug_id, [patch], options, tool, commit_message)
     363
     364
     365class LandDiffAndUpdateBug(Command):
    301366    def __init__(self):
    302367        options = [
    303368            make_option("-r", "--reviewer", action="store", type="string", dest="reviewer", help="Update ChangeLogs to say Reviewed by REVIEWER."),
    304         ]
    305         options += WebKitLandingScripts.land_options()
     369            make_option("--no-close", action="store_false", dest="close_bug", default=True, help="Leave bug open after landing."),
     370            make_option("--no-build", action="store_false", dest="build", default=True, help="Commit without building first, implies --no-test."),
     371            make_option("--no-test", action="store_false", dest="test", default=True, help="Commit without running run-webkit-tests."),
     372        ]
    306373        Command.__init__(self, 'Lands the current working directory diff and updates the bug if provided.', '[BUGID]', options=options)
    307 
    308     def guess_reviewer_from_bug(self, bugs, bug_id):
    309         patches = bugs.fetch_reviewed_patches_from_bug(bug_id)
    310         if len(patches) != 1:
    311             log("%s on bug %s, cannot infer reviewer." % (pluralize("reviewed patch", len(patches)), bug_id))
    312             return None
    313         patch = patches[0]
    314         reviewer = patch['reviewer']
    315         log('Guessing "%s" as reviewer from attachment %s on bug %s.' % (reviewer, patch['id'], bug_id))
    316         return reviewer
    317 
    318     def update_changelogs_with_reviewer(self, reviewer, bug_id, tool):
    319         if not reviewer:
    320             if not bug_id:
    321                 log("No bug id provided and --reviewer= not provided.  Not updating ChangeLogs with reviewer.")
    322                 return
    323             reviewer = self.guess_reviewer_from_bug(tool.bugs, bug_id)
    324 
    325         if not reviewer:
    326             log("Failed to guess reviewer from bug %s and --reviewer= not provided.  Not updating ChangeLogs with reviewer." % bug_id)
    327             return
    328 
    329         changelogs = modified_changelogs(tool.scm())
    330         for changelog in changelogs:
    331             set_reviewer_in_changelog(changelog, reviewer)
    332374
    333375    def execute(self, options, args, tool):
     
    335377        os.chdir(tool.scm().checkout_root)
    336378
    337         self.update_changelogs_with_reviewer(options.reviewer, bug_id, tool)
     379        reviewer = options.reviewer or guess_reviewer_from_bug(tool.bugs, bug_id)
     380        update_changelogs_with_reviewer(reviewer, bug_id, tool)
    338381
    339382        comment_text = WebKitLandingScripts.build_and_commit(tool.scm(), options)
     
    358401
    359402    @classmethod
    360     def land_patches(cls, bug_id, patches, options, tool):
     403    def land_patches(cls, bug_id, patches, options, tool, commit_message=None):
    361404        try:
    362405            comment_text = ""
    363406            for patch in patches:
    364407                tool.scm().update_webkit() # Update before every patch in case the tree has changed
    365                 log("Applying %s from bug %s." % (patch['id'], bug_id))
     408                log("Applying %s from bug %s." % (patch.get('id') or patch.get('commit_id'), bug_id))
    366409                tool.scm().apply_patch(patch, force=options.commit_queue)
    367                 comment_text = WebKitLandingScripts.build_and_commit(tool.scm(), options)
    368                 tool.bugs.clear_attachment_flags(patch['id'], comment_text)
     410                comment_text = WebKitLandingScripts.build_and_commit(tool.scm(), options, commit_message)
     411                if patch.get('id'):
     412                    tool.bugs.clear_attachment_flags(patch['id'], comment_text)
     413                else:
     414                    tool.bugs.post_comment_to_bug(patch['bug_id'], comment_text)
    369415
    370416            if options.close_bug:
     
    608654            { 'name' : 'create-bug', 'object' : CreateBug() },
    609655            { 'name' : 'apply-patches', 'object' : ApplyPatchesFromBug() },
    610             { 'name' : 'land-diff', 'object' : LandAndUpdateBug() },
     656            { 'name' : 'land-commits', 'object' : LandCommitsAndUpdateBug() },
     657            { 'name' : 'land-diff', 'object' : LandDiffAndUpdateBug() },
    611658            { 'name' : 'land-patches', 'object' : LandPatchesFromBugs() },
    612659            { 'name' : 'commit-message', 'object' : CommitMessageForCurrentDiff() },
  • trunk/WebKitTools/Scripts/modules/scm.py

    r47111 r47343  
    7777        return "\n".join(self.message_lines) + "\n"
    7878
     79    def replace_text(self, placeholder, new_value):
     80        self.message_lines = map(lambda line: line.replace(placeholder, new_value), self.message_lines)
     81
    7982
    8083class ScriptError(Exception):
     
    124127        # It's possible that the patch was not made from the root directory.
    125128        # We should detect and handle that case.
    126         curl_process = subprocess.Popen(['curl', '--silent', '--show-error', patch['url']], stdout=subprocess.PIPE)
     129        patch_apply_process = None
    127130        args = [self.script_path('svn-apply'), '--reviewer', patch['reviewer']]
    128131        if force:
    129132            args.append('--force')
    130         patch_apply_process = subprocess.Popen(args, stdin=curl_process.stdout)
     133        if patch.get('url'):
     134            curl_process = subprocess.Popen(['curl', '--silent', '--show-error', patch['url']], stdout=subprocess.PIPE)
     135            patch_apply_process = subprocess.Popen(args, stdin=curl_process.stdout)
     136        elif patch.get('diff'):
     137            patch_apply_process = subprocess.Popen(args, stdin=subprocess.PIPE)
     138            patch_apply_process.communicate(patch['diff'])
     139        else:
     140            error("Unknown patch object.")
    131141
    132142        return_code = patch_apply_process.wait()
    133143        if return_code:
    134             raise ScriptError("Patch %s from bug %s failed to download and apply." % (patch['url'], patch['bug_id']))
     144            raise ScriptError("Patch %s from bug %s failed to download and apply." % (patch.get('url') or patch.get('commit_id'), patch['bug_id']))
    135145
    136146    def run_status_and_extract_filenames(self, status_command, status_regexp):
     
    376386                raise ScriptError("'...' is not supported (found in '%s'). Did you mean '..'?" % commitish)
    377387            elif '..' in commitish:
    378                 commit_ids += self.run_command(['git', 'rev-list', commitish]).splitlines()
     388                commit_ids += reversed(self.run_command(['git', 'rev-list', commitish]).splitlines())
    379389            else:
    380390                # Turn single commits or branch or tag names into commit ids.
Note: See TracChangeset for help on using the changeset viewer.