Beispiel #1
0
    def dodiff(tmproot):
        assert not (hascopies and len(MAR) > 1), \
                'dodiff cannot handle copies when diffing dirs'

        sa = [mod_a, add_a, rem_a]
        sb = [mod_b, add_b, rem_b]
        ctxs = [ctx1a, ctx1b, ctx2]

        # If more than one file, diff on working dir copy.
        copyworkingdir = len(MAR) > 1
        dirs, labels, fns_and_mtimes = snapshotset(repo, ctxs, sa, sb, cpy, 
                                                   tmproot, copyworkingdir)
        dir1a, dir1b, dir2 = dirs
        label1a, label1b, label2 = labels
        fns_and_mtime = fns_and_mtimes[2]

        if len(MAR) > 1 and label2 == '':
            label2 = 'working files'

        def getfile(fname, dir, label):
            file = os.path.join(tmproot, dir, fname)
            if os.path.isfile(file):
                return fname+label, file
            nullfile = os.path.join(tmproot, 'empty')
            fp = open(nullfile, 'w')
            fp.close()
            return _nonexistant+label, nullfile

        # If only one change, diff the files instead of the directories
        # Handle bogus modifies correctly by checking if the files exist
        if len(MAR) == 1:
            file2 = util.localpath(MAR.pop())
            if file2 in cto:
                file1 = util.localpath(cpy[file2])
            else:
                file1 = file2
            label1a, dir1a = getfile(file1, dir1a, label1a)
            if do3way:
                label1b, dir1b = getfile(file1, dir1b, label1b)
            label2, dir2 = getfile(file2, dir2, label2)
        if do3way:
            label1a += '[local]'
            label1b += '[other]'
            label2 += '[merged]'

        replace = dict(parent=dir1a, parent1=dir1a, parent2=dir1b,
                       plabel1=label1a, plabel2=label1b,
                       phash1=str(ctx1a), phash2=str(ctx1b),
                       repo=hglib.get_reponame(repo),
                       clabel=label2, child=dir2, chash=str(ctx2))
        launchtool(diffcmd, args, replace, True)

        # detect if changes were made to mirrored working files
        for copy_fn, working_fn, mtime in fns_and_mtime:
            if os.path.getmtime(copy_fn) != mtime:
                ui.debug('file changed while diffing. '
                         'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn))
                util.copyfile(copy_fn, working_fn)
Beispiel #2
0
def master_hook(ui, repo, **kwargs):
    ui.debug("running tamarin master_hook\n")
    ui.debug("kwargs: %s\n" % kwargs)
    # The mercurial hook script expects the equivalent of an exit code back from
    # this call:
    #   False = 0 = No Error : allow push
    #   True = 1 = Error : abort push
    error = False
    error = security_check(ui, repo, **kwargs) or error
    return error
def preoutgoing_hook(ui, repo, **kwargs):
    ui.debug('running tamarin preoutgoing_hook\n')
    ui.debug('kwargs: %s\n' % kwargs)
    operation = kwargs['source']

    # Like master_hook, return code False implies No Error, allow push.
    error = False
    error = error or heuristic_log_check(ui, repo, operation, **kwargs)

    return error
def master_hook(ui, repo, **kwargs):
    ui.debug('running tamarin master_hook\n')
    ui.debug('kwargs: %s\n' % kwargs)
    # The mercurial hook script expects the equivalent of an exit code back from
    # this call:
    #   False = 0 = No Error : allow push
    #   True = 1 = Error : abort push
    error = False
    error = security_check(ui, repo, **kwargs) or error
    return error
Beispiel #5
0
def preoutgoing_hook(ui, repo, **kwargs):
    ui.debug('running tamarin preoutgoing_hook\n')
    ui.debug('kwargs: %s\n' % kwargs)
    operation = kwargs['source']

    # Like master_hook, return code False implies No Error, allow push.
    error = False
    error = error or heuristic_log_check(ui, repo, operation, **kwargs)

    return error
Beispiel #6
0
def reposetup(ui, repo):
    # TODO: decide use of config section for this extension
    global _ui
    _ui = ui
    if not os.path.supports_unicode_filenames:
        ui.warn(_("[win32mbcs] cannot activate on this platform.\n"))
        return
    # install features of this extension
    install()
    ui.debug(_("[win32mbcs] activeted with encoding: %s\n") % util._encoding)
Beispiel #7
0
def reposetup(ui, repo):
    # TODO: decide use of config section for this extension
    global _ui
    _ui = ui
    if not os.path.supports_unicode_filenames:
        ui.warn(_("[win32mbcs] cannot activate on this platform.\n"))
        return
    # install features of this extension
    install()
    ui.debug(_("[win32mbcs] activeted with encoding: %s\n") % util._encoding)
Beispiel #8
0
def shortreponame(ui):
    name = ui.config('web', 'name')
    if not name:
        return
    src = ui.configsource('web', 'name')  # path:line
    if '/.hg/hgrc:' not in util.pconvert(src):
        # global web.name will set the same name to all repositories
        ui.debug('ignoring global web.name defined at %s\n' % src)
        return
    return name
Beispiel #9
0
def diff_check(ui, repo, **kwargs):
    ui.debug('running diff_check\n')

    # get all the change contexts for this commit
    # kwargs['node'] returns the first changecontext nodeid
    changecontexts = [repo[i] for i in range(repo[kwargs['node']].rev(), len(repo))]
    # check for tabs
    def tabCheck(line):
        tab = line.find('\t')
        if tab >= 0:    # find returns -1 if not found
            return True, tab
        return False, tab

    def windowsLineendingsCheck(line):
        if line.endswith('\r'):
            return True, len(line)-1
        return False, 0

    def trailingWhitespaceCheck(line):
        if len(line.strip()) > 1:   # skip empty lines (will have a +) see bug 600536
            m = re.match(r'\+.*?(\s+$)', line)
            if m:
                return True, m.start(1)
        return False, 0
    
    def securityCheck(line):
        loc = line.find('MARK_SECURITY_CHANGE')
        if loc != -1:
            # found security change ifdef
            return True, loc
        loc = line.find('SECURITYFIX_')
        if loc != -1:
            # found security change ifdef
            return True, loc
        return False, 0

    # check for tabs - exit if user chooses to abort
    if checkChangeCtxDiff(ui, repo, changecontexts, tabCheck,
                          'Tab', ('.cpp', '.c', '.h', '.as', '.abs', '.py')):
        return True

    if checkChangeCtxDiff(ui, repo, changecontexts, windowsLineendingsCheck,
                          'Windows line ending', ('.cpp', '.c', '.h', '.as', '.abs', '.py')):
        return True

    if checkChangeCtxDiff(ui, repo, changecontexts, trailingWhitespaceCheck,
                          'Trailing Whitespace', ('.cpp', '.c', '.h', '.as', '.abs', '.py')):
        return True

    if checkChangeCtxDiff(ui, repo, changecontexts, securityCheck,
                          'Security Check', ('.cpp', '.c', '.h', '.as', '.abs', '.py')):
        return True

    return False
def security_check(ui, repo, **kwargs):
    ui.debug('running security_check\n')
    error = False

    ui.pushbuffer()
    _quiet(
        ui, lambda: commands.log(ui,
                                 repo,
                                 rev=['%s:tip' % kwargs['node']],
                                 template='{node}\n',
                                 date=None,
                                 user=None,
                                 logfile=None))
    nodes = ui.popbuffer().split('\n')

    # reenable this code if we need to blacklist a node
    for node in nodes:
        if node.startswith('8555e8551203') or node.startswith('e09bb3ece6c7'):
            ui.warn('blacklisted changeid found: node %s is blacklisted\n' %
                    node)
            error = True  # fail the push

    # Look for blacklisted bugs
    blacklist = [
        # Serrano
        580489,
        604354,
        # Wasabi
        507624,
        # Cyril
        570049,
        628834,
    ]

    bugs = re.compile('(%s)' % '|'.join([str(bug) for bug in blacklist]))

    ui.pushbuffer()
    _quiet(
        ui, lambda: commands.log(ui,
                                 repo,
                                 rev=['%s:tip' % kwargs['node']],
                                 template='{desc}',
                                 date=None,
                                 user=None,
                                 logfile=None))
    descs = ui.popbuffer()

    searchDescs = bugs.search(descs)
    if searchDescs:
        ui.warn('blacklisted bug found: %s\n' % searchDescs.groups()[0])
        error = True

    return error
Beispiel #11
0
def expull(orig, repo, remote, *args, **kwargs):
    res = orig(repo, remote, *args, **kwargs)
    lock = repo.lock()
    try:
        try:
            path = repo._activepath(remote)
            if path:
                repo.saveremotebranches(path, remote.branchmap())
        except Exception, e:
            ui.debug('remote branches for path %s not saved: %s\n' % (path, e))
    finally:
        lock.release()
        return res
 def push(self, remote, *args, **kwargs):
     res = opush(remote, *args, **kwargs)
     lock = self.lock()
     try:
         try:
             path = self._activepath(remote)
             if path:
                 self.saveremotebranches(path, remote.branchmap())
         except Exception, e:
             ui.debug("remote branches for path %s not saved: %s\n" % (path, e))
     finally:
         lock.release()
         return res
Beispiel #13
0
def expush(orig, repo, remote, *args, **kwargs):
    res = orig(repo, remote, *args, **kwargs)
    lock = repo.lock()
    try:
        try:
            path = repo._activepath(remote)
            if path:
                repo.saveremotebranches(path, remote.branchmap())
        except Exception, e:
            ui.debug('remote branches for path %s not saved: %s\n'
                     % (path, e))
    finally:
        lock.release()
        return res
Beispiel #14
0
 def push(self, remote, *args, **kwargs):
     res = opush(remote, *args, **kwargs)
     lock = self.lock()
     try:
         try:
             path = self._activepath(remote)
             if path:
                 self.saveremotebranches(path, remote.branchmap())
         except Exception, e:
             ui.debug('remote branches for path %s not saved: %s\n' %
                      (path, e))
     finally:
         lock.release()
         return res
Beispiel #15
0
def security_check(ui, repo, **kwargs):
    ui.debug("running security_check\n")
    error = False

    ui.pushbuffer()
    _quiet(
        ui,
        lambda: commands.log(
            ui, repo, rev=["%s:tip" % kwargs["node"]], template="{node}\n", date=None, user=None, logfile=None
        ),
    )
    nodes = ui.popbuffer().split("\n")

    # reenable this code if we need to blacklist a node
    for node in nodes:
        if node.startswith("8555e8551203") or node.startswith("e09bb3ece6c7"):
            ui.warn("blacklisted changeid found: node %s is blacklisted\n" % node)
            error = True  # fail the push

    # Look for blacklisted bugs
    blacklist = [
        # Serrano
        580489,
        604354,
        # Wasabi
        507624,
        # Cyril
        570049,
        628834,
    ]

    bugs = re.compile("(%s)" % "|".join([str(bug) for bug in blacklist]))

    ui.pushbuffer()
    _quiet(
        ui,
        lambda: commands.log(
            ui, repo, rev=["%s:tip" % kwargs["node"]], template="{desc}", date=None, user=None, logfile=None
        ),
    )
    descs = ui.popbuffer()

    searchDescs = bugs.search(descs)
    if searchDescs:
        ui.warn("blacklisted bug found: %s\n" % searchDescs.groups()[0])
        error = True

    return error
def retrieve_pass_from_server(ui, uri, path, proposed_user):
    port = int(ui.config("hg4ideapass", "port", None, True))
    if port is None:
        raise util.Abort("No port was specified")
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    ui.debug("connecting ...")
    client.connect(("127.0.0.1", port))
    ui.debug("connected, sending data ...")

    send(client, "getpass")
    send(client, uri)
    send(client, path)
    send(client, proposed_user)
    user = receiveWithMessage(client, "http authorization required")
    password = receiveWithMessage(client, "http authorization required")
    return user, password
Beispiel #17
0
def retrieve_pass_from_server(ui, uri, path, proposed_user):
    port = int(ui.config(b'hg4ideapass', b'port', None, True))
    if port is None:
        raise error.Abort("No port was specified")
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    ui.debug("connecting ...")
    client.connect(('127.0.0.1', port))
    ui.debug("connected, sending data ...")

    send(client, "getpass")
    send(client, uri)
    send(client, path)
    send(client, proposed_user)
    user = receiveWithMessage(client, b"http authorization required")
    password = receiveWithMessage(client, b"http authorization required")
    return user, password
Beispiel #18
0
def find_branch_parent(ui, ctx):
    '''Find the parent revision of the 'ctx' branch.'''
    branchname = ctx.branch()
    
    getparent = lambda ctx: ctx.parents()[0]
    
    currctx = ctx
    while getparent(currctx) and currctx.branch() == branchname:
        currctx = getparent(currctx)
        ui.debug('currctx rev: %s; branch: %s\n' % (currctx.rev(), 
                                            currctx.branch()))
                                            
    # return the root of the repository if the first
    # revision is on the branch
    if not getparent(currctx) and currctx.branch() == branchname:
        return currctx._repo['000000000000']
    
    return currctx
Beispiel #19
0
def create_review_data(ui, repo, c, parent, rparent):
    'Returns a tuple of the diff and parent diff for the review.'
    diff = getdiff(ui, repo, c, parent)
    ui.debug('\n=== Diff from parent to rev ===\n')
    ui.debug(diff + '\n')

    if rparent != None and parent != rparent:
        parentdiff = getdiff(ui, repo, parent, rparent)
        ui.debug('\n=== Diff from rparent to parent ===\n')
        ui.debug(parentdiff + '\n')
    else:
        parentdiff = ''
    return diff, parentdiff
def master_hook(ui, repo, **kwargs):
    ui.debug('running tamarin master_hook\n')
    ui.debug('kwargs: %s\n' % kwargs)
    # The mercurial hook script expects the equivalent of an exit code back from
    # this call:
    #   False = 0 = No Error : allow push
    #   True = 1 = Error : abort push
    error = False
    error = error or diff_check(ui, repo, **kwargs)

    if error:
        # Save the commit message so it can be reused by user
        desc = repo[repo[kwargs['node']].rev()].description()
        ui.debug('Description: %s\n' % desc)
        try:
            f = open('%s/.hg/commit.save' % repo.root, 'w')
            f.write(desc)
            f.close()
            ui.warn(
                'Commit message saved to .hg/commit.save\nSaved message can be recommitted using -l .hg/commit.save\n'
            )
        except IOError:
            ui.warn('Error writing .hg/commit.save file')

    return error
Beispiel #21
0
def check_user_for_valid_email(ui, changeset, operation):
    user = changeset.user()
    ui.debug('\ncheck_user_for_valid_email: %s' % user)
    has_email = has_email_in_brackets(user)
    if not has_email:
        ui.warn('\nUser missing email address for changeset %s: \n  %s\n'
                % (changeset, user))
        response = prompt_yesno(ui, operation)
        if response == 0:
            ui.warn('Aborting %s due to user missing email.\n' % operation)
            return True;
    else:
        has_domain = has_email_with_domain(user)
        if not has_domain:
            ui.warn('\nUser email missing domain for changeset %s: \n  %s\n'
                    % (changeset, user))
            response = prompt_yesno(ui, operation)
            if response == 0:
                ui.warn('Aborting %s due to email without domain.\n' % operation)
                return True;

    return False;
def check_user_for_valid_email(ui, changeset, operation):
    user = changeset.user()
    ui.debug('\ncheck_user_for_valid_email: %s' % user)
    has_email = has_email_in_brackets(user)
    if not has_email:
        ui.warn('\nUser missing email address for changeset %s: \n  %s\n' %
                (changeset, user))
        response = prompt_yesno(ui, operation)
        if response == 0:
            ui.warn('Aborting %s due to user missing email.\n' % operation)
            return True
    else:
        has_domain = has_email_with_domain(user)
        if not has_domain:
            ui.warn('\nUser email missing domain for changeset %s: \n  %s\n' %
                    (changeset, user))
            response = prompt_yesno(ui, operation)
            if response == 0:
                ui.warn('Aborting %s due to email without domain.\n' %
                        operation)
                return True

    return False
def checkChangeCtxDiff(ui, repo, changecontexts, testFunc, testDesc,
                       fileEndings):
    '''Loop through each diff for each change and run the testFunc against each line'''
    ui.debug('Checking %s\n' % testDesc)
    for ctx in changecontexts:
        # Get the diff for each change and file
        for file in [f for f in ctx.files() if f.endswith(fileEndings)]:
            ui.debug('checking change: %s, file: %s\n' %
                     (short(ctx.node()), file))
            fmatch = matchfiles(repo, [file])
            # diff from this nodes parent to current node
            diff = ''.join(
                patch.diff(repo,
                           ctx.parents()[0].node(), ctx.node(),
                           fmatch)).split('\n')
            for i in range(3, len(diff)):  # start checking after diff header
                line = diff[i]
                if line.startswith('@@'):
                    diffLocation = line
                # only check new lines added/modified in the file
                if line.startswith('+'):
                    ui.debug('\nchecking line for %s: %s\n\n' %
                             (testDesc, line))
                    testResult, errorLocation = testFunc(line)
                    if testResult:
                        ui.warn(
                            '\n%s(s) found in %s for rev %s (change %s):\n' %
                            (testDesc, file, ctx.rev(), short(ctx.node())))
                        ui.warn('%s\n' % diffLocation)
                        ui.warn('%s\n' % line)
                        ui.warn(
                            '%s^\n' %
                            (' ' * errorLocation, ))  # show a pointer to error
                        try:
                            response = ui.promptchoice(
                                '(n)o, (y)es, (a)llow %ss for current file\n' %
                                testDesc +
                                'Are you sure you want to commit this change? [n]: ',
                                (('&No'), ('&Yes'), ('&Allow')), 0)
                        except AttributeError:
                            ui.warn(
                                'This commit hook requires that you have mercurial 1.4+ installed.  Please upgrade your hg installation.'
                            )
                            response = 0
                        if response == 1:
                            # next occurance in file
                            continue
                        elif response == 2:
                            # next file
                            break
                        else:
                            ui.warn('Aborting commit due to %s.\n' % testDesc)
                            # error = True
                            return True
    return False
Beispiel #24
0
def checkChangeCtxDiff(ui, repo, changecontexts, testFunc, testDesc, fileEndings):
    '''Loop through each diff for each change and run the testFunc against each line'''
    ui.debug('Checking %s\n' % testDesc)
    for ctx in changecontexts:
        # Get the diff for each change and file
        for file in [f for f in ctx.files() if f.endswith(fileEndings)]:
            ui.debug('checking change: %s, file: %s\n' % (short(ctx.node()), file))
            fmatch = matchfiles(repo,[file])
            # diff from this nodes parent to current node
            diff = ''.join(patch.diff(repo, ctx.parents()[0].node(), ctx.node(), fmatch)).split('\n')
            for i in range(3, len(diff)):    # start checking after diff header
                line = diff[i]
                if line.startswith('@@'):
                    diffLocation = line
                # only check new lines added/modified in the file
                if line.startswith('+'):
                    ui.debug('\nchecking line for %s: %s\n\n' % (testDesc, line))
                    testResult, errorLocation = testFunc(line)
                    if testResult:
                        ui.warn('\n%s(s) found in %s for rev %s (change %s):\n' %
                                (testDesc, file, ctx.rev(), short(ctx.node())))
                        ui.warn('%s\n' % diffLocation)
                        ui.warn('%s\n' % line)
                        ui.warn('%s^\n' % (' '*errorLocation,)) # show a pointer to error
                        try:
                            response = ui.promptchoice('(n)o, (y)es, (a)llow %ss for current file\n' % testDesc +
                                                    'Are you sure you want to commit this change? [n]: ' ,
                                                   (('&No'), ('&Yes'), ('&Allow')), 0)
                        except AttributeError:
                            ui.warn('This commit hook requires that you have mercurial 1.4+ installed.  Please upgrade your hg installation.')
                            response = 0
                        if response == 1:
                            # next occurance in file
                            continue
                        elif response == 2:
                            # next file
                            break
                        else:
                            ui.warn('Aborting commit due to %s.\n' % testDesc)
                            # error = True
                            return True
    return False
Beispiel #25
0
def master_hook(ui, repo, **kwargs):
    ui.debug('running tamarin master_hook\n')
    ui.debug('kwargs: %s\n' % kwargs)
    # The mercurial hook script expects the equivalent of an exit code back from
    # this call:
    #   False = 0 = No Error : allow push
    #   True = 1 = Error : abort push
    error = False
    error = error or diff_check(ui, repo, **kwargs)

    if error:
        # Save the commit message so it can be reused by user
        desc = repo[repo[kwargs['node']].rev()].description()
        ui.debug('Description: %s\n' % desc)
        try:
            f = open('%s/.hg/commit.save' % repo.root, 'w')
            f.write(desc)
            f.close()
            ui.warn('Commit message saved to .hg/commit.save\nSaved message can be recommitted using -l .hg/commit.save\n')
        except IOError:
            ui.warn('Error writing .hg/commit.save file')

    return error
def hook(ui, repo, **kwargs):
    # type: (ui, repo, **Text) -> None
    """
    Invoked by configuring a [hook] entry in .hg/hgrc.
    """
    hooktype = kwargs["hooktype"]
    node = kwargs["node"]

    ui.debug("Zulip: received {hooktype} event\n".format(hooktype=hooktype))

    if hooktype != "changegroup":
        ui.warn("Zulip: {hooktype} not supported\n".format(hooktype=hooktype))
        sys.exit(1)

    ctx = repo.changectx(node)
    branch = ctx.branch()

    # If `branches` isn't specified, notify on all branches.
    branch_whitelist = get_config(ui, "branches")
    branch_blacklist = get_config(ui, "ignore_branches")

    if branch_whitelist:
        # Only send notifications on branches we are watching.
        watched_branches = [
            b.lower().strip() for b in branch_whitelist.split(",")
        ]
        if branch.lower() not in watched_branches:
            ui.debug(
                "Zulip: ignoring event for {branch}\n".format(branch=branch))
            sys.exit(0)

    if branch_blacklist:
        # Don't send notifications for branches we've ignored.
        ignored_branches = [
            b.lower().strip() for b in branch_blacklist.split(",")
        ]
        if branch.lower() in ignored_branches:
            ui.debug(
                "Zulip: ignoring event for {branch}\n".format(branch=branch))
            sys.exit(0)

    # The first and final commits in the changeset.
    base = repo[node].rev()
    tip = len(repo)

    email = get_config(ui, "email")
    api_key = get_config(ui, "api_key")
    site = get_config(ui, "site")

    if not (email and api_key):
        ui.warn("Zulip: missing email or api_key configurations\n")
        ui.warn("in the [zulip] section of your .hg/hgrc.\n")
        sys.exit(1)

    stream = get_config(ui, "stream")
    # Give a default stream if one isn't provided.
    if not stream:
        stream = "commits"

    web_url = get_config(ui, "web_url")
    user = ctx.user()
    content = format_summary_line(web_url, user, base, tip, branch, node)
    content += format_commit_lines(web_url, repo, base, tip)

    subject = branch

    ui.debug("Sending to Zulip:\n")
    ui.debug(content + "\n")

    send_zulip(email, api_key, site, stream, subject, content)
Beispiel #27
0
def postreview(ui, repo, rev='.', **opts):
    '''post a changeset to a Review Board server

This command creates a new review request on a Review Board server, or updates
an existing review request, based on a changeset in the repository. If no
revision number is specified the parent revision of the working directory is
used.

By default, the diff uploaded to the server is based on the parent of the
revision to be reviewed. A different parent may be specified using the
--parent or --longdiff options. --parent r specifies the revision to use on the
left side while --longdiff looks at the upstream repository specified in .hg/hgrc
to find a common ancestor to use on the left side. --parent may need one of
the options below if the Review Board server can't see the parent.

If the parent revision is not available to the Review Board server (e.g. it
exists in your local repository but not in the one that Review Board has
access to) you must tell postreview how to determine the base revision
to use for a parent diff. The --outgoing, --outgoingrepo or --master options
may be used for this purpose. The --outgoing option is the simplest of these;
it assumes that the upstream repository specified in .hg/hgrc is the same as
the one known to Review Board. The other two options offer more control if
this is not the case. In these cases two diffs are uploaded to Review Board:
the first is the difference between Reviewboard's view of the repo and your
parent revision(left side), the second is the difference between your parent
revision and your review revision(right side). Only the second diff is
under review. If you wish to review all the changes local to your repo use
the --longdiff option above.

The --outgoing option recognizes the path entries 'reviewboard', 'default-push'
and 'default' in this order of precedence. 'reviewboard' may be used if the
repository accessible to Review Board is not the upstream repository.

The --git option causes postreview to generate diffs in Git extended format,
which includes information about file renames and copies. ReviewBoard 1.6 beta
2 or later is required in order to use this feature.

The --submit_as option allows to submit the review request as another user.
This requires that the actual logged in user is either a superuser or has the
"reviews.can_submit_as_another_user" permission.

The reviewboard extension may be configured by adding a [reviewboard] section
to your .hgrc or mercurial.ini file, or to the .hg/hgrc file of an individual
repository. The following options are available::

  [reviewboard]

  # REQUIRED
  server = <server_url>             # The URL of your ReviewBoard server

  # OPTIONAL
  http_proxy = <proxy_url>          # HTTP proxy to use for the connection
  user = <rb_username>              # Username to use for ReviewBoard
                                    # connections
  password = <rb_password>          # Password to use for ReviewBoard
                                    # connections
  repoid = <repoid>                 # ReviewBoard repository ID (normally only
                                    # useful in a repository-specific hgrc)
  target_groups = <groups>          # Default groups for new review requests
                                    # (comma-separated list)
  target_people = <users>           # Default users for new review requests
                                    # (comma-separated list)
  explicit_publish_update = <bool>  # If True, updates posted using the -e
                                    # option will not be published immediately
                                    # unless the -p option is also used
  launch_webbrowser = <bool>        # If True, new or updated requests will
                                    # always be shown in a web browser after
                                    # posting.

'''

    server = opts.get('server')
    if not server:
        server = ui.config('reviewboard', 'server')

    if not server:
        raise util.Abort(
            _('please specify a reviewboard server in your .hgrc file'))
    '''We are going to fetch the setting string from hg prefs, there we can set
    our own proxy, or specify 'none' to pass an empty dictionary to urllib2
    which overides the default autodetection when we want to force no proxy'''
    http_proxy = ui.config('reviewboard', 'http_proxy')
    if http_proxy:
        if http_proxy == 'none':
            proxy = {}
        else:
            proxy = {'http': http_proxy}
    else:
        proxy = None

    def getdiff(ui, repo, r, parent, opts):
        '''return diff for the specified revision'''
        output = ""
        if opts.get('git') or ui.configbool('diff', 'git'):
            # Git diffs don't include the revision numbers with each file, so
            # we have to put them in the header instead.
            output += "# Node ID " + node.hex(r.node()) + "\n"
            output += "# Parent  " + node.hex(parent.node()) + "\n"
        diffopts = patch.diffopts(ui, opts)
        for chunk in patch.diff(repo, parent.node(), r.node(), opts=diffopts):
            output += chunk
        return output

    parent = opts.get('parent')
    if parent:
        parent = repo[parent]
    else:
        parent = repo[rev].parents()[0]

    outgoing = opts.get('outgoing')
    outgoingrepo = opts.get('outgoingrepo')
    master = opts.get('master')
    repo_id_opt = opts.get('repoid')
    longdiff = opts.get('longdiff')

    if not repo_id_opt:
        repo_id_opt = ui.config('reviewboard', 'repoid')

    if master:
        rparent = repo[master]
    elif outgoingrepo:
        rparent = remoteparent(ui, repo, opts, rev, upstream=outgoingrepo)
    elif outgoing:
        rparent = remoteparent(ui, repo, opts, rev)
    elif longdiff:
        parent = remoteparent(ui, repo, opts, rev)
        rparent = None
    else:
        rparent = None

    ui.debug(_('Parent is %s\n' % parent))
    ui.debug(_('Remote parent is %s\n' % rparent))

    request_id = None

    if opts.get('existing'):
        request_id = opts.get('existing')

    fields = {}

    c = repo.changectx(rev)
    changesets_string = get_changesets_string(repo, parent, c)

    # Don't clobber the summary and description for an existing request
    # unless specifically asked for
    if opts.get('update') or not request_id:
        fields['summary'] = toascii(c.description().splitlines()[0])
        fields['description'] = toascii(changesets_string)
        fields['branch'] = toascii(c.branch())

    if opts.get('summary'):
        fields['summary'] = toascii(opts.get('summary'))

    if opts.get('description'):
        fields['description'] = toascii(opts.get('description'))

    diff = getdiff(ui, repo, c, parent, opts)
    ui.debug('\n=== Diff from parent to rev ===\n')
    ui.debug(diff + '\n')

    if rparent and parent != rparent:
        parentdiff = getdiff(ui, repo, parent, rparent, opts)
        ui.debug('\n=== Diff from rparent to parent ===\n')
        ui.debug(parentdiff + '\n')
    else:
        parentdiff = ''

    if opts.get('update') or not request_id:
        for field in ('target_groups', 'target_people', 'bugs_closed'):
            if opts.get(field):
                value = ','.join(opts.get(field))
            else:
                value = ui.config('reviewboard', field)
            if value:
                fields[field] = toascii(value)

    ui.status('\n%s\n' % changesets_string)
    ui.status('reviewboard:\t%s\n' % server)
    ui.status('\n')
    username = opts.get('username') or ui.config('reviewboard', 'user')
    if username:
        ui.status('username: %s\n' % username)
    password = opts.get('password') or ui.config('reviewboard', 'password')
    if password:
        ui.status('password: %s\n' % '**********')

    try:
        reviewboard = make_rbclient(server,
                                    username,
                                    password,
                                    proxy=proxy,
                                    apiver=opts.get('apiver'),
                                    trace=opts.get('apitrace'))
    except Exception, e:
        raise util.Abort(_(str(e)))
def postreview(ui, repo, rev='.', **opts):
    '''post a changeset to a Review Board server

This command creates a new review request on a Review Board server, or updates
an existing review request, based on a changeset in the repository. If no
revision number is specified the parent revision of the working directory is
used.

By default, the diff uploaded to the server is based on the parent of the
revision to be reviewed. A different parent may be specified using the
--parent or --longdiff options. --parent r specifies the revision to use on the
left side while --longdiff looks at the upstream repository specified in .hg/hgrc
to find a common ancestor to use on the left side. --parent may need one of
the options below if the Review Board server can't see the parent.

If the parent revision is not available to the Review Board server (e.g. it
exists in your local repository but not in the one that Review Board has
access to) you must tell postreview how to determine the base revision
to use for a parent diff. The --outgoing, --outgoingrepo or --master options
may be used for this purpose. The --outgoing option is the simplest of these;
it assumes that the upstream repository specified in .hg/hgrc is the same as
the one known to Review Board. The other two options offer more control if
this is not the case. In these cases two diffs are uploaded to Review Board:
the first is the difference between Reviewboard's view of the repo and your
parent revision(left side), the second is the difference between your parent
revision and your review revision(right side). Only the second diff is
under review. If you wish to review all the changes local to your repo use
the --longdiff option above.
'''

    server = ui.config('reviewboard', 'server')
    if not server:
        raise util.Abort(
                _('please specify a reviewboard server in your .hgrc file') )

    '''We are going to fetch the setting string from hg prefs, there we can set
    our own proxy, or specify 'none' to pass an empty dictionary to urllib2
    which overides the default autodetection when we want to force no proxy'''
    http_proxy = ui.config('reviewboard', 'http_proxy' )
    if http_proxy:
        if http_proxy == 'none':
            proxy = {}
        else:
            proxy = { 'http':http_proxy }
    else:
        proxy=None

    def getdiff(ui, repo, r, parent):
        '''return diff for the specified revision'''
        output = ""
        for chunk in patch.diff(repo, parent.node(), r.node()):
            output += chunk
        return output

    parent = opts.get('parent')
    if parent:
        parent = repo[parent]
    else:
        parent = repo[rev].parents()[0]

    outgoing = opts.get('outgoing')
    outgoingrepo = opts.get('outgoingrepo')
    master = opts.get('master')
    repo_id_opt = opts.get('repoid')
    longdiff = opts.get('longdiff')

    if not repo_id_opt:
        repo_id_opt = ui.config('reviewboard','repoid')


    if master:
        rparent = repo[master]
    elif outgoingrepo:
        rparent = remoteparent(ui, repo, rev, upstream=outgoingrepo)
    elif outgoing:
        rparent = remoteparent(ui, repo, rev)
    elif longdiff:
        parent = rparent = remoteparent(ui, repo, rev)
        rparent = None
    else:
        rparent = None


    ui.debug(_('Parent is %s\n' % parent))
    ui.debug(_('Remote parent is %s\n' % rparent))

    request_id = None

    if opts.get('existing'):
        request_id = opts.get('existing')

    fields = {}

    c = repo.changectx(rev)

    # Don't clobber the summary and description for an existing request
    # unless specifically asked for    
    if opts.get('update') or not request_id:
        fields['summary']       = c.description().splitlines()[0]
        fields['description']   = c.description()

    diff = getdiff(ui, repo, c, parent)
    ui.debug('\n=== Diff from parent to rev ===\n')
    ui.debug(diff + '\n')

    if rparent and parent != rparent:
        parentdiff = getdiff(ui, repo, parent, rparent)
        ui.debug('\n=== Diff from rparent to parent ===\n')
        ui.debug(parentdiff + '\n')
    else:
        parentdiff = ''

    for field in ('target_groups', 'target_people'):
        if opts.get(field):
            value = ','.join(opts.get(field))
        else:
            value = ui.config('reviewboard', field)
        if value:
            fields[field] = value

    reviewboard = ReviewBoard(server,proxy=proxy)

    ui.status('changeset:\t%s:%s "%s"\n' % (rev, c, c.description()) )
    ui.status('reviewboard:\t%s\n' % server)
    ui.status('\n')
    username = opts.get('username') or ui.config('reviewboard', 'user')
    if username:
        ui.status('username: %s\n' % username)
    password = opts.get('password') or ui.config('reviewboard', 'password')
    if password:
        ui.status('password: %s\n' % '**********')

    try:
        reviewboard.login(username, password)
    except ReviewBoardError, msg:
        raise util.Abort(_(msg))
Beispiel #29
0
def hook(ui, repo, **kwargs):
    # type: (ui, repo, Optional[Text]) -> None
    """
    Invoked by configuring a [hook] entry in .hg/hgrc.
    """
    hooktype = kwargs["hooktype"]
    node = kwargs["node"]

    ui.debug("Zulip: received {hooktype} event\n".format(hooktype=hooktype))

    if hooktype != "changegroup":
        ui.warn("Zulip: {hooktype} not supported\n".format(hooktype=hooktype))
        exit(1)

    ctx = repo.changectx(node)
    branch = ctx.branch()

    # If `branches` isn't specified, notify on all branches.
    branch_whitelist = get_config(ui, "branches")
    branch_blacklist = get_config(ui, "ignore_branches")

    if branch_whitelist:
        # Only send notifications on branches we are watching.
        watched_branches = [b.lower().strip() for b in branch_whitelist.split(",")]
        if branch.lower() not in watched_branches:
            ui.debug("Zulip: ignoring event for {branch}\n".format(branch=branch))
            exit(0)

    if branch_blacklist:
        # Don't send notifications for branches we've ignored.
        ignored_branches = [b.lower().strip() for b in branch_blacklist.split(",")]
        if branch.lower() in ignored_branches:
            ui.debug("Zulip: ignoring event for {branch}\n".format(branch=branch))
            exit(0)

    # The first and final commits in the changeset.
    base = repo[node].rev()
    tip = len(repo)

    email = get_config(ui, "email")
    api_key = get_config(ui, "api_key")
    site = get_config(ui, "site")

    if not (email and api_key):
        ui.warn("Zulip: missing email or api_key configurations\n")
        ui.warn("in the [zulip] section of your .hg/hgrc.\n")
        exit(1)

    stream = get_config(ui, "stream")
    # Give a default stream if one isn't provided.
    if not stream:
        stream = "commits"

    web_url = get_config(ui, "web_url")
    user = ctx.user()
    content = format_summary_line(web_url, user, base, tip, branch, node)
    content += format_commit_lines(web_url, repo, base, tip)

    subject = branch

    ui.debug("Sending to Zulip:\n")
    ui.debug(content + "\n")

    send_zulip(email, api_key, site, stream, subject, content)
Beispiel #30
0
def postreview(ui, repo, rev='.', **opts):
    '''post a changeset to a Review Board server

This command creates a new review request on a Review Board server, or updates
an existing review request, based on a changeset in the repository. If no
revision number is specified the parent revision of the working directory is
used.

By default, the diff uploaded to the server is based on the parent of the
revision to be reviewed. A different parent may be specified using the
--parent or --longdiff options. --parent r specifies the revision to use on the
left side while --longdiff looks at the upstream repository specified in .hg/hgrc
to find a common ancestor to use on the left side. --parent may need one of
the options below if the Review Board server can't see the parent.

If the parent revision is not available to the Review Board server (e.g. it
exists in your local repository but not in the one that Review Board has
access to) you must tell postreview how to determine the base revision
to use for a parent diff. The --outgoing, --outgoingrepo or --master options
may be used for this purpose. The --outgoing option is the simplest of these;
it assumes that the upstream repository specified in .hg/hgrc is the same as
the one known to Review Board. The other two options offer more control if
this is not the case. In these cases two diffs are uploaded to Review Board:
the first is the difference between Reviewboard's view of the repo and your
parent revision(left side), the second is the difference between your parent
revision and your review revision(right side). Only the second diff is
under review. If you wish to review all the changes local to your repo use
the --longdiff option above.

The --outgoing option recognizes the path entries 'reviewboard', 'default-push'
and 'default' in this order of precedence. 'reviewboard' may be used if the
repository accessible to Review Board is not the upstream repository.

The --git option causes postreview to generate diffs in Git extended format,
which includes information about file renames and copies. ReviewBoard 1.6 beta
2 or later is required in order to use this feature.

The --submit_as option allows to submit the review request as another user.
This requires that the actual logged in user is either a superuser or has the
"reviews.can_submit_as_another_user" permission.

The reviewboard extension may be configured by adding a [reviewboard] section
to your .hgrc or mercurial.ini file, or to the .hg/hgrc file of an individual
repository. The following options are available::

  [reviewboard]

  # REQUIRED
  server = <server_url>             # The URL of your ReviewBoard server

  # OPTIONAL
  http_proxy = <proxy_url>          # HTTP proxy to use for the connection
  user = <rb_username>              # Username to use for ReviewBoard
                                    # connections
  password = <rb_password>          # Password to use for ReviewBoard
                                    # connections
  repoid = <repoid>                 # ReviewBoard repository ID (normally only
                                    # useful in a repository-specific hgrc)
  target_groups = <groups>          # Default groups for new review requests
                                    # (comma-separated list)
  target_people = <users>           # Default users for new review requests
                                    # (comma-separated list)
  explicit_publish_update = <bool>  # If True, updates posted using the -e
                                    # option will not be published immediately
                                    # unless the -p option is also used
  launch_webbrowser = <bool>        # If True, new or updated requests will
                                    # always be shown in a web browser after
                                    # posting.

'''

    server = opts.get('server')
    if not server:
        server = ui.config('reviewboard', 'server')

    if not server:
        raise util.Abort(
                _('please specify a reviewboard server in your .hgrc file') )

    '''We are going to fetch the setting string from hg prefs, there we can set
    our own proxy, or specify 'none' to pass an empty dictionary to urllib2
    which overides the default autodetection when we want to force no proxy'''
    http_proxy = ui.config('reviewboard', 'http_proxy' )
    if http_proxy:
        if http_proxy == 'none':
            proxy = {}
        else:
            proxy = { 'http':http_proxy }
    else:
        proxy=None

    def getdiff(ui, repo, r, parent, opts):
        '''return diff for the specified revision'''
        output = ""
        if opts.get('git') or ui.configbool('diff', 'git'):
            # Git diffs don't include the revision numbers with each file, so
            # we have to put them in the header instead.
            output += "# Node ID " + node.hex(r.node()) + "\n"
            output += "# Parent  " + node.hex(parent.node()) + "\n"
        diffopts = patch.diffopts(ui, opts)
        for chunk in patch.diff(repo, parent.node(), r.node(), opts=diffopts):
            output += chunk
        return output

    parent = opts.get('parent')
    if parent:
        parent = repo[parent]
    else:
        parent = repo[rev].parents()[0]

    outgoing = opts.get('outgoing')
    outgoingrepo = opts.get('outgoingrepo')
    master = opts.get('master')
    repo_id_opt = opts.get('repoid')
    longdiff = opts.get('longdiff')

    if not repo_id_opt:
        repo_id_opt = ui.config('reviewboard','repoid')

    if master:
        rparent = repo[master]
    elif outgoingrepo:
        rparent = remoteparent(ui, repo, opts, rev, upstream=outgoingrepo)
    elif outgoing:
        rparent = remoteparent(ui, repo, opts, rev)
    elif longdiff:
        parent = remoteparent(ui, repo, opts, rev)
        rparent = None
    else:
        rparent = None

    ui.debug(_('Parent is %s\n' % parent))
    ui.debug(_('Remote parent is %s\n' % rparent))

    request_id = None

    if opts.get('existing'):
        request_id = opts.get('existing')

    fields = {}

    c = repo.changectx(rev)
    changesets_string = get_changesets_string(repo, parent, c)

    # Don't clobber the summary and description for an existing request
    # unless specifically asked for    
    if opts.get('update') or not request_id:
        fields['summary']       = toascii(c.description().splitlines()[0])
        fields['description']   = toascii(changesets_string)
        fields['branch']        = toascii(c.branch())

    if opts.get('summary'):
        fields['summary'] = toascii(opts.get('summary'))

    if opts.get('description'):
        fields['description'] = toascii(opts.get('description'))

    diff = getdiff(ui, repo, c, parent, opts)
    ui.debug('\n=== Diff from parent to rev ===\n')
    ui.debug(diff + '\n')

    if rparent and parent != rparent:
        parentdiff = getdiff(ui, repo, parent, rparent, opts)
        ui.debug('\n=== Diff from rparent to parent ===\n')
        ui.debug(parentdiff + '\n')
    else:
        parentdiff = ''

    if opts.get('update') or not request_id:
        for field in ('target_groups', 'target_people', 'bugs_closed'):
            if opts.get(field):
                value = ','.join(opts.get(field))
            else:
                value = ui.config('reviewboard', field)
            if value:
                fields[field] = toascii(value)

    ui.status('\n%s\n' % changesets_string)
    ui.status('reviewboard:\t%s\n' % server)
    ui.status('\n')
    username = opts.get('username') or ui.config('reviewboard', 'user')
    if username:
        ui.status('username: %s\n' % username)
    password = opts.get('password') or ui.config('reviewboard', 'password')
    if password:
        ui.status('password: %s\n' % '**********')

    try:
        reviewboard = make_rbclient(server, username, password, proxy=proxy,
                                    apiver=opts.get('apiver'),
                                    trace=opts.get('apitrace'))
    except Exception, e:
        raise util.Abort(_(str(e)))
def diff_check(ui, repo, **kwargs):
    ui.debug('running diff_check\n')

    # get all the change contexts for this commit
    # kwargs['node'] returns the first changecontext nodeid
    changecontexts = [
        repo[i] for i in range(repo[kwargs['node']].rev(), len(repo))
    ]

    # check for tabs
    def tabCheck(line):
        tab = line.find('\t')
        if tab >= 0:  # find returns -1 if not found
            return True, tab
        return False, tab

    def windowsLineendingsCheck(line):
        if line.endswith('\r'):
            return True, len(line) - 1
        return False, 0

    def trailingWhitespaceCheck(line):
        if len(line.strip()
               ) > 1:  # skip empty lines (will have a +) see bug 600536
            m = re.match(r'\+.*?(\s+$)', line)
            if m:
                return True, m.start(1)
        return False, 0

    def securityCheck(line):
        loc = line.find('MARK_SECURITY_CHANGE')
        if loc != -1:
            # found security change ifdef
            return True, loc
        loc = line.find('SECURITYFIX_')
        if loc != -1:
            # found security change ifdef
            return True, loc
        return False, 0

    # check for tabs - exit if user chooses to abort
    if checkChangeCtxDiff(ui, repo, changecontexts, tabCheck, 'Tab',
                          ('.cpp', '.c', '.h', '.as', '.abs', '.py')):
        return True

    if checkChangeCtxDiff(ui, repo, changecontexts, windowsLineendingsCheck,
                          'Windows line ending',
                          ('.cpp', '.c', '.h', '.as', '.abs', '.py')):
        return True

    if checkChangeCtxDiff(ui, repo, changecontexts, trailingWhitespaceCheck,
                          'Trailing Whitespace',
                          ('.cpp', '.c', '.h', '.as', '.abs', '.py')):
        return True

    if checkChangeCtxDiff(ui, repo, changecontexts, securityCheck,
                          'Security Check',
                          ('.cpp', '.c', '.h', '.as', '.abs', '.py')):
        return True

    return False
Beispiel #32
0
def postreview(ui, repo, rev='.', **opts):
    '''post a changeset to a Review Board server

This command creates a new review request on a Review Board server, or updates
an existing review request, based on a changeset in the repository. If no
revision number is specified the parent revision of the working directory is
used.

By default, the diff uploaded to the server is based on the parent of the
revision to be reviewed. A different parent may be specified using the
--parent option.  Alternatively you may specify --outgoingchanges to calculate
the parent based on the outgoing changesets or --branch to choose the parent
revision of the branch.

If the parent revision is not available to the Review Board server (e.g. it
exists in your local repository but not in the one that Review Board has
access to) you must tell postreview how to determine the base revision
to use for a parent diff. The --outgoing, --outgoingrepo or --master options
may be used for this purpose. The --outgoing option is the simplest of these;
it assumes that the upstream repository specified in .hg/hgrc is the same as
the one known to Review Board. The other two options offer more control if
this is not the case.

The --outgoing option recognizes the path entries 'reviewboard', 'default-push'
and 'default' in this order of precedence. 'reviewboard' may be used if the
repository accessible to Review Board is not the upstream repository.
'''

    '''
HG issue 3841 workaround
https://bitbucket.org/tortoisehg/thg/issue/3841/reviewboard-extension-error-unknown
'''
    oldin, oldout, olderr = sys.stdin, sys.stdout, sys.stderr
    sys.stdin, sys.stdout, sys.stderr = ui.fin, ui.fout, ui.ferr
    
    ui.status('postreview plugin, version %s\n' % __version__)
    
    # checks to see if the server was set
    find_server(ui, opts)
    
    check_parent_options(opts)
    
    rev_no = repo.revs(rev).first()
    c = repo[rev_no]

    rparent = find_rparent(ui, repo, c, opts)
    ui.debug('remote parent: %s\n' % rparent)
    
    parent  = find_parent(ui, repo, c, rparent, opts)
    ui.debug('parent: %s\n' % parent)

    if parent is None:
        msg = "Unable to determine parent revision for diff. "
        if opts.get('outgoingchanges'):
            msg += _("If using -g/--outgoingchanges, make sure you have some "
                     "(type 'hg out'). Did you forget to commit ('hg st')?")
        raise error.Abort(msg)

    diff, parentdiff = create_review_data(ui, repo, c, parent, rparent)

    send_review(ui, repo, c, parent, diff, parentdiff, opts)
    
    sys.stdin, sys.stdout, sys.stderr = oldin, oldout, olderr