hgext3rd/topic/flow.py
author Pierre-Yves David <pierre-yves.david@octobus.net>
Mon, 27 May 2019 03:42:35 +0200
changeset 4647 228caeb8b7af
parent 4263 35130e428ebd
child 4743 92e3db149d7d
permissions -rw-r--r--
topic: add a simple option to reject publishing The option is pretty basic but it can be used as base to build larger feature. The main target for going in this direction is to be able to distinct between user that are "simple contributors" pushing topic for review and the "maintainers" or "automation" that can publish changesets.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
3157
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     1
from __future__ import absolute_import
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     2
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     3
from mercurial import (
3159
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
     4
    commands,
3157
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     5
    error,
3159
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
     6
    exchange,
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
     7
    extensions,
3157
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     8
    node,
3158
678a9802c56b topic: add an option to automatically publish topic-less changeset
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3157
diff changeset
     9
    phases,
3157
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    10
)
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    11
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    12
from mercurial.i18n import _
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    13
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    14
def enforcesinglehead(repo, tr):
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    15
    for name, heads in repo.filtered('visible').branchmap().iteritems():
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    16
        if len(heads) > 1:
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    17
            hexs = [node.short(n) for n in heads]
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    18
            raise error.Abort(_('%d heads on "%s"') % (len(heads), name),
f286eefbd20d topic: add an option to enforce a single head per name in a repository
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    19
                              hint=(', '.join(hexs)))
3158
678a9802c56b topic: add an option to automatically publish topic-less changeset
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3157
diff changeset
    20
678a9802c56b topic: add an option to automatically publish topic-less changeset
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3157
diff changeset
    21
def publishbarebranch(repo, tr):
678a9802c56b topic: add an option to automatically publish topic-less changeset
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3157
diff changeset
    22
    """Publish changeset without topic"""
678a9802c56b topic: add an option to automatically publish topic-less changeset
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3157
diff changeset
    23
    if 'node' not in tr.hookargs: # no new node
678a9802c56b topic: add an option to automatically publish topic-less changeset
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3157
diff changeset
    24
        return
678a9802c56b topic: add an option to automatically publish topic-less changeset
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3157
diff changeset
    25
    startnode = node.bin(tr.hookargs['node'])
678a9802c56b topic: add an option to automatically publish topic-less changeset
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3157
diff changeset
    26
    topublish = repo.revs('not public() and (%n:) - hidden() - topic()', startnode)
678a9802c56b topic: add an option to automatically publish topic-less changeset
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3157
diff changeset
    27
    if topublish:
678a9802c56b topic: add an option to automatically publish topic-less changeset
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3157
diff changeset
    28
        cl = repo.changelog
678a9802c56b topic: add an option to automatically publish topic-less changeset
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3157
diff changeset
    29
        nodes = [cl.node(r) for r in topublish]
678a9802c56b topic: add an option to automatically publish topic-less changeset
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3157
diff changeset
    30
        repo._phasecache.advanceboundary(repo, tr, phases.public, nodes)
3159
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    31
3235
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    32
def rejectuntopicedchangeset(repo, tr):
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    33
    """Reject the push if there are changeset without topic"""
3282
3675fe74521d topic: use 'hookargs' over 'tr.changes' for flow control
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3235
diff changeset
    34
    if 'node' not in tr.hookargs: # no new revs
3235
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    35
        return
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    36
3282
3675fe74521d topic: use 'hookargs' over 'tr.changes' for flow control
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3235
diff changeset
    37
    startnode = node.bin(tr.hookargs['node'])
3675fe74521d topic: use 'hookargs' over 'tr.changes' for flow control
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3235
diff changeset
    38
3235
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    39
    mode = repo.ui.config('experimental', 'topic-mode.server', 'ignore')
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    40
3282
3675fe74521d topic: use 'hookargs' over 'tr.changes' for flow control
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3235
diff changeset
    41
    untopiced = repo.revs('not public() and (%n:) - hidden() - topic()', startnode)
3235
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    42
    if untopiced:
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    43
        num = len(untopiced)
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    44
        fnode = repo[untopiced.first()].hex()[:10]
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    45
        if num == 1:
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    46
            msg = _("%s") % fnode
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    47
        else:
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    48
            msg = _("%s and %d more") % (fnode, num - 1)
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    49
        if mode == 'warning':
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    50
            fullmsg = _("pushed draft changeset without topic: %s\n")
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    51
            repo.ui.warn(fullmsg % msg)
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    52
        elif mode == 'enforce':
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    53
            fullmsg = _("rejecting draft changesets: %s")
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    54
            raise error.Abort(fullmsg % msg)
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    55
        else:
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    56
            repo.ui.warn(_("unknown 'topic-mode.server': %s\n" % mode))
8a772f0c54d9 topics: add a config to reject draft changeset without topic on a server
Pulkit Goyal <7895pulkit@gmail.com>
parents: 3226
diff changeset
    57
4647
228caeb8b7af topic: add a simple option to reject publishing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 4263
diff changeset
    58
def reject_publish(repo, tr):
228caeb8b7af topic: add a simple option to reject publishing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 4263
diff changeset
    59
    """prevent a transaction to be publish anything"""
228caeb8b7af topic: add a simple option to reject publishing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 4263
diff changeset
    60
    published = set()
228caeb8b7af topic: add a simple option to reject publishing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 4263
diff changeset
    61
    for r, (o, n) in tr.changes['phases'].items():
228caeb8b7af topic: add a simple option to reject publishing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 4263
diff changeset
    62
        if n == phases.public:
228caeb8b7af topic: add a simple option to reject publishing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 4263
diff changeset
    63
            published.add(r)
228caeb8b7af topic: add a simple option to reject publishing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 4263
diff changeset
    64
    if published:
228caeb8b7af topic: add a simple option to reject publishing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 4263
diff changeset
    65
        r = min(published)
228caeb8b7af topic: add a simple option to reject publishing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 4263
diff changeset
    66
        msg = "rejecting publishing of changeset %s" % repo[r]
228caeb8b7af topic: add a simple option to reject publishing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 4263
diff changeset
    67
        if len(published) > 1:
228caeb8b7af topic: add a simple option to reject publishing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 4263
diff changeset
    68
            msg += ' and %d others' % (len(published) - 1)
228caeb8b7af topic: add a simple option to reject publishing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 4263
diff changeset
    69
        raise error.Abort(msg)
228caeb8b7af topic: add a simple option to reject publishing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 4263
diff changeset
    70
3159
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    71
def wrappush(orig, repo, remote, *args, **kwargs):
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    72
    """interpret the --publish flag and pass it to the push operation"""
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    73
    newargs = kwargs.copy()
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    74
    if kwargs.pop('publish', False):
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    75
        opargs = kwargs.get('opargs')
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    76
        if opargs is None:
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    77
            opargs = {}
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    78
        newargs['opargs'] = opargs.copy()
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    79
        newargs['opargs']['publish'] = True
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    80
    return orig(repo, remote, *args, **newargs)
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    81
3204
a342c454ccf3 pusoperation: wrap pushoperation __init__ directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3159
diff changeset
    82
def extendpushoperation(orig, self, *args, **kwargs):
3159
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    83
    publish = kwargs.pop('publish', False)
3204
a342c454ccf3 pusoperation: wrap pushoperation __init__ directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3159
diff changeset
    84
    orig(self, *args, **kwargs)
a342c454ccf3 pusoperation: wrap pushoperation __init__ directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3159
diff changeset
    85
    self.publish = publish
3159
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    86
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    87
def wrapphasediscovery(orig, pushop):
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    88
    orig(pushop)
3226
5dfe4e5cf9e4 topic: use more protective code to access publishing code
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3204
diff changeset
    89
    if getattr(pushop, 'publish', False):
3159
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    90
        if not pushop.remotephases.publishing:
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    91
            unfi = pushop.repo.unfiltered()
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    92
            droots = pushop.remotephases.draftroots
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    93
            revset = '%ln and (not public() or %ln::)'
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    94
            future = list(unfi.set(revset, pushop.futureheads, droots))
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    95
            pushop.outdatedphases = future
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    96
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    97
def installpushflag(ui):
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
    98
    entry = extensions.wrapcommand(commands.table, 'push', wrappush)
4245
419801742d08 topic: only add --publish flag to push if it's not already there
Anton Shestakov <av6@dwimlabs.net>
parents: 3282
diff changeset
    99
    if not any(opt for opt in entry[1] if opt[1] == 'publish'): # hg <= 4.9
419801742d08 topic: only add --publish flag to push if it's not already there
Anton Shestakov <av6@dwimlabs.net>
parents: 3282
diff changeset
   100
        entry[1].append(('', 'publish', False,
419801742d08 topic: only add --publish flag to push if it's not already there
Anton Shestakov <av6@dwimlabs.net>
parents: 3282
diff changeset
   101
                         _('push the changeset as public')))
3204
a342c454ccf3 pusoperation: wrap pushoperation __init__ directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3159
diff changeset
   102
    extensions.wrapfunction(exchange.pushoperation, '__init__',
a342c454ccf3 pusoperation: wrap pushoperation __init__ directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3159
diff changeset
   103
                            extendpushoperation)
3159
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
   104
    extensions.wrapfunction(exchange, '_pushdiscoveryphase', wrapphasediscovery)
90515d0bfb08 push: add a --publish flag
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 3158
diff changeset
   105
    exchange.pushdiscoverymapping['phase'] = exchange._pushdiscoveryphase