# HG changeset patch # User Anton Shestakov # Date 1686013033 10800 # Node ID fba501baf5cb478d08c8f64fc8b9949cf222e169 # Parent 499e4f1c83a875d2464ac24898f452e90cc83675 topic: find and report topic namespace changes in transactions diff -r 499e4f1c83a8 -r fba501baf5cb hgext3rd/topic/__init__.py --- a/hgext3rd/topic/__init__.py Wed Jun 07 19:57:24 2023 -0300 +++ b/hgext3rd/topic/__init__.py Mon Jun 05 21:57:13 2023 -0300 @@ -187,6 +187,7 @@ pycompat, registrar, scmutil, + smartset, templatefilters, util, ) @@ -269,6 +270,9 @@ configitem(b'_internal', b'tns-publish', default=False, ) +configitem(b'devel', b'tns-report-transactions', + default=lambda: [], +) configitem(b'experimental', b'topic-mode.server', default=configitems.dynamicdefault, ) @@ -430,6 +434,53 @@ or (missing and self.deleted()) ) +def find_affected_tns(repo, tr): + origrepolen = tr.changes[b'origrepolen'] + unfi = repo.unfiltered() + + affected = set() + # These are the new changesets that weren't in the repo before this + # transaction + for rev in smartset.spanset(repo, start=origrepolen): + ctx = unfi[rev] + tns = ctx.topic_namespace() + affected.add(tns) + + # These are the changesets obsoleted by this transaction + for rev in obsutil.getobsoleted(repo, tr): + ctx = unfi[rev] + tns = ctx.topic_namespace() + affected.add(tns) + + # Phase movements, we only care about changesets that move from or to + # public phase + for revs, (old, new) in tr.changes[b'phases']: + if old != phases.public and new != phases.public: + # new phase is public: publishing changesets + # old phase is public: e.g. hg phase --draft --force + continue + revs = [rev for rev in revs if rev < origrepolen] + for rev in revs: + ctx = unfi[rev] + tns = ctx.topic_namespace(force=True) + affected.add(tns) + + # We don't care about changesets without topic namespace + affected.discard(b'none') + + tr.changes[b'tns'] = affected + report_affected_tns(repo, tr) + +def report_affected_tns(repo, tr): + report = set(repo.ui.configlist(b'devel', b'tns-report-transactions')) + if b'*' not in report: + # * matches any transaction + if not any(trname in report for trname in tr._names): + return + + if tr.changes[b'tns']: + repo.ui.status(b'topic namespaces affected: %s\n' % b' '.join(sorted(tr.changes[b'tns']))) + def uisetup(ui): destination.modsetup(ui) discovery.modsetup(ui) @@ -742,6 +793,25 @@ else: tr.addvalidator(b'000-reject-publish', _validate) + if util.safehasattr(tr, '_validator'): + # hg <= 5.3 (36f08ae87ef6) + origvalidator = tr._validator + + def _validate(tr2): + repo = reporef() + find_affected_tns(repo, tr2) + + def validator(tr2): + result = origvalidator(tr2) + _validate(tr2) + return result + + if util.safehasattr(tr, '_validator'): + # hg <= 5.3 (36f08ae87ef6) + tr._validator = validator + else: + tr.addvalidator(b'000-find-affected-tns', _validate) + # real transaction start ct = self.currenttopic if not ct: diff -r 499e4f1c83a8 -r fba501baf5cb tests/test-namespaces-report.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-namespaces-report.t Mon Jun 05 21:57:13 2023 -0300 @@ -0,0 +1,175 @@ +Reporting affected topic namespaces in transactions + + $ . "$TESTDIR/testlib/common.sh" + + $ cat >> $HGRCPATH << EOF + > [extensions] + > evolve = + > topic = + > [phases] + > publish = no + > [devel] + > tns-report-transactions = push + > EOF + + $ hg init orig + +case 1: new changeset (draft with topic namespace) +topic namespace of that changeset is reported + + $ hg clone orig case-1 -q + $ cd orig + + $ echo apple > a + $ hg ci -qAm apple + + $ hg push ../case-1 + pushing to ../case-1 + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + + $ echo banana > b + $ hg debug-topic-namespace bob + marked working directory as topic namespace: bob + $ hg ci -qAm 'banana' + +XXX: should not require --new-branch + + $ hg push ../case-1 --new-branch + pushing to ../case-1 + searching for changes + adding changesets + adding manifests + adding file changes + topic namespaces affected: bob + added 1 changesets with 1 changes to 1 files + + $ cd .. + +case 2: obsmarker affecting known changeset +topic namespaces of both the precursor and the successor are affected + + $ hg clone orig case-2 -q + $ cd orig + + $ echo broccoli > b + $ hg debug-topic-namespace bruce + $ hg ci --amend -m 'broccoli' + +XXX: should not require --new-branch + + $ hg push ../case-2 --new-branch + pushing to ../case-2 + searching for changes + adding changesets + adding manifests + adding file changes + topic namespaces affected: bob bruce + added 1 changesets with 1 changes to 1 files (+1 heads) + 1 new obsolescence markers + obsoleted 1 changesets + + $ cd .. + +3 phase divergence resolution can point to a thing but not affect it (probably not affected) + + $ hg clone orig case-3 -q + $ cd orig + + $ hg debug-topic-namespace charlie + $ echo coconut > c + $ hg ci -qAm 'coconut' + + $ hg debug-topic-namespace carol + $ echo cloudberry > c + $ hg ci --amend -m 'cloudberry' + + $ hg phase --hidden -r 'desc("coconut")' --public + 1 new phase-divergent changesets + + $ hg evolve --phase-divergent + recreate:[4] cloudberry + atop:[3] coconut + committed as c398b3caf447 + working directory is now at c398b3caf447 + +XXX: should not require --new-branch + + $ hg push ../case-3 --new-branch + pushing to ../case-3 + searching for changes + adding changesets + adding manifests + adding file changes + topic namespaces affected: bruce carol + added 2 changesets with 2 changes to 1 files + 2 new obsolescence markers + + $ cd .. + +4 phase movement: publishing drafts +topic namespaces of published changesets are affected + + $ hg clone orig case-4 -q + $ cd orig + + $ hg push ../case-4 --publish + pushing to ../case-4 + searching for changes + no changes found + topic namespaces affected: carol + [1] + + $ cd .. + + $ cd .. + +6 phase movement: publishing secret changesets (that are known on the server) +topic namespaces of published changesets are affected + + $ hg clone orig case-6 -q + $ cd orig + + $ hg push ../case-6 -r . --publish + pushing to ../case-6 + searching for changes + no changes found + topic namespaces affected: dave + [1] + +previous topic namespace is resurrected... + + $ hg phase --secret --force -r . --config 'devel.tns-report-transactions=phase' + topic namespaces affected: dave + +...just to disappear again + + $ hg push ../case-6 -r . --config 'devel.tns-report-transactions=*' + pushing to ../case-6 + searching for changes + no changes found + topic namespaces affected: dave + [1] + + $ cd .. + +99 pushing obsmarker for an unknown changeset +doesn't affect any topic namespace, we report nothing + + $ hg clone orig case-99 -q + $ cd orig + + $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid "desc('dragonfruit')"` + 1 new obsolescence markers + + $ hg push ../case-99 + pushing to ../case-99 + searching for changes + no changes found + 1 new obsolescence markers + [1] + + $ cd ..