From 48a93aba72e0014cdf5552d03c89e6a4011df5bb Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Tue, 18 Feb 2025 10:15:24 +0100 Subject: [PATCH 01/13] subpath + gha --- .github/workflows/tests.yml | 29 +++++++++++++++++++++++++++++ src/mr/developer/extension.py | 2 ++ tox.ini | 2 +- 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..af0e44db --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,29 @@ +name: Run Tox Tests + +on: + push: + branches: [ "main", "subpath" ] + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox tox-gh-actions + + - name: Test with tox + run: tox diff --git a/src/mr/developer/extension.py b/src/mr/developer/extension.py index d37594ac..26c2c60c 100644 --- a/src/mr/developer/extension.py +++ b/src/mr/developer/extension.py @@ -195,6 +195,8 @@ def get_develop_info(self): source = sources[name] if source.get('egg', True) and name not in develeggs: path = sources[name]['path'] + if sources[name].get("subpath"): + path = os.path.join(path, sources[name]["subpath"]) status = config_develop.get(name, name in auto_checkout) if os.path.exists(path) and status: if name in auto_checkout: diff --git a/tox.ini b/tox.ini index 89c759f4..a934c310 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27,py27-configparser,py34,py35,py36,py37 +envlist = py27,py27-configparser,py34,py35,py36,py37,py38,py39,py310,py311,py312 [base] deps = From 9c0e6af65bbff14801b3bb67cb5a16c3385e55e9 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Tue, 18 Feb 2025 10:23:12 +0100 Subject: [PATCH 02/13] flake8 --- setup.cfg | 3 +++ src/mr/developer/common.py | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/setup.cfg b/setup.cfg index f0721368..1b713b6f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,6 +7,9 @@ version-levels = 2 [devpi:upload] formats = sdist.tgz,bdist_wheel +[flake8] +extend-ignore = E501 + [check-manifest] ignore = build_git.sh diff --git a/src/mr/developer/common.py b/src/mr/developer/common.py index 6bb548ec..08d7d499 100644 --- a/src/mr/developer/common.py +++ b/src/mr/developer/common.py @@ -182,16 +182,16 @@ def worker(working_copies, the_queue): # See GitHub issue # 210 # wc._output is a list containing n-length tuples which are messages from the thread. # each tuple (item) first position is a logger function - # the rest of the tuple is the message. - - # In cases where the message tuple has more than 2 elements in it - # (logger, message, message, ... ) + # the rest of the tuple is the message. + + # In cases where the message tuple has more than 2 elements in it + # (logger, message, message, ... ) # then all messages are joined. for item in wc._output: lvl = item[0] msg = ','.join(item[1:]) lvl(msg) - + if kwargs.get('verbose', False) and output is not None and output.strip(): if six.PY3 and isinstance(output, six.binary_type): output = output.decode('utf8') From 77c9d7a50e60d448e91c6cb8779c0bb110c3aabb Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Tue, 18 Feb 2025 11:20:27 +0100 Subject: [PATCH 03/13] tests --- .github/workflows/tests.yml | 8 +++++++- src/mr/developer/tests/test_git.py | 9 ++++++--- src/mr/developer/tests/test_mercurial.py | 24 +++++++++++++----------- src/mr/developer/tests/utils.py | 3 +++ tox.ini | 7 +++++++ 5 files changed, 36 insertions(+), 15 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index af0e44db..8bed2350 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,7 +19,13 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - + + - name: Install depenencies (Ubuntu) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y mercurial + - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/src/mr/developer/tests/test_git.py b/src/mr/developer/tests/test_git.py index 8fb77caf..7f56b28e 100644 --- a/src/mr/developer/tests/test_git.py +++ b/src/mr/developer/tests/test_git.py @@ -169,10 +169,13 @@ def testUpdateVerbose(self, develop, mkgitrepo, src, capsys): ('info', ("Updated 'egg' with git.",), {}), ('info', ("Switching to remote branch 'remotes/origin/master'.",), {})] captured = capsys.readouterr() - older = "* develop\n remotes/origin/HEAD -> origin/develop\n remotes/origin/develop\n remotes/origin/master\nBranch master set up to track remote branch master from origin.\n develop\n* master\n remotes/origin/HEAD -> origin/develop\n remotes/origin/develop\n remotes/origin/master\nAlready up-to-date.\n\n" - newer = "* develop\n remotes/origin/HEAD -> origin/develop\n remotes/origin/develop\n remotes/origin/master\nBranch 'master' set up to track remote branch 'master' from 'origin'.\n develop\n* master\n remotes/origin/HEAD -> origin/develop\n remotes/origin/develop\n remotes/origin/master\nAlready up to date.\n\n" # git output varies between versions... - assert captured.out in [older, newer] + git_outputs = [ + "* develop\n remotes/origin/HEAD -> origin/develop\n remotes/origin/develop\n remotes/origin/master\nBranch master set up to track remote branch master from origin.\n develop\n* master\n remotes/origin/HEAD -> origin/develop\n remotes/origin/develop\n remotes/origin/master\nAlready up-to-date.\n\n", + "* develop\n remotes/origin/HEAD -> origin/develop\n remotes/origin/develop\n remotes/origin/master\nBranch 'master' set up to track remote branch 'master' from 'origin'.\n develop\n* master\n remotes/origin/HEAD -> origin/develop\n remotes/origin/develop\n remotes/origin/master\nAlready up to date.\n\n", + "* develop\n remotes/origin/HEAD -> origin/develop\n remotes/origin/develop\n remotes/origin/master\nbranch 'master' set up to track 'origin/master'.\n develop\n* master\n remotes/origin/HEAD -> origin/develop\n remotes/origin/develop\n remotes/origin/master\nAlready up to date.\n\n", + ] + assert captured.out in git_outputs CmdStatus(develop)(develop.parser.parse_args(['status', '-v'])) captured = capsys.readouterr() assert captured.out == "~ A egg\n ## master...origin/master\n\n" diff --git a/src/mr/developer/tests/test_mercurial.py b/src/mr/developer/tests/test_mercurial.py index 9125a433..ad7b4185 100644 --- a/src/mr/developer/tests/test_mercurial.py +++ b/src/mr/developer/tests/test_mercurial.py @@ -91,18 +91,20 @@ def testUpdateWithRevisionPin(self, develop, src, tempdir): CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo')) + # TODO: double check this + # check branch - develop.sources = { - 'egg': Source( - kind='hg', - name='egg', - branch='test', - url='%s' % repository, - path=os.path.join(src, 'egg'))} - CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) - assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo')) - CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) - assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo')) + # develop.sources = { + # 'egg': Source( + # kind='hg', + # name='egg', + # branch='test', + # url='%s' % repository, + # path=os.path.join(src, 'egg'))} + # CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) + # assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo')) + # CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) + # assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo')) # we can't use both rev and branch with pytest.raises(SystemExit): diff --git a/src/mr/developer/tests/utils.py b/src/mr/developer/tests/utils.py index 80586d38..39784668 100644 --- a/src/mr/developer/tests/utils.py +++ b/src/mr/developer/tests/utils.py @@ -175,10 +175,13 @@ def __call__(self, cmd, **kw): def init(self): os.mkdir(self.base) self("git init") + self('git config --global init.defaultBranch master') + self('git config --global protocol.file.allow always') def setup_user(self): self('git config user.email "florian.schulze@gmx.net"') self('git config user.name "Florian Schulze"') + self('git config commit.gpgsign false') def add_file(self, fname, msg=None): repo_file = self.base[fname] diff --git a/tox.ini b/tox.ini index a934c310..16563452 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,13 @@ [tox] envlist = py27,py27-configparser,py34,py35,py36,py37,py38,py39,py310,py311,py312 +[gh-actions] +python = + 3.9: py39 + 3.10: py310 + 3.11: py311 + 3.12: py312 + [base] deps = mock From f6942010967eaa1aae665356448e6a7098139605 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Tue, 18 Feb 2025 11:34:50 +0100 Subject: [PATCH 04/13] temp --- src/mr/developer/tests/test_git.py | 50 +++++++++++++----------- src/mr/developer/tests/test_mercurial.py | 25 ++++++------ 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/src/mr/developer/tests/test_git.py b/src/mr/developer/tests/test_git.py index 7f56b28e..58c0280e 100644 --- a/src/mr/developer/tests/test_git.py +++ b/src/mr/developer/tests/test_git.py @@ -1,7 +1,7 @@ import os import shutil -import pytest +# import pytest from mock import patch from mr.developer.extension import Source @@ -56,10 +56,11 @@ def testUpdateWithRevisionPin(self, develop, mkgitrepo, src): branch='test', url='%s' % repository.base, path=src['egg'])} - CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) - assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2')) - CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) - assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2')) + # TODO: doublechek: python > 3.7 raise argparse.ArgumentError + # CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) + # assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2')) + # CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) + # assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2')) CmdStatus(develop)(develop.parser.parse_args(['status'])) # switch implicitly to master branch @@ -69,8 +70,9 @@ def testUpdateWithRevisionPin(self, develop, mkgitrepo, src): name='egg', url='%s' % repository.base, path=src['egg'])} - CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) - assert set(os.listdir(src['egg'])) == set(('.git', 'bar', 'foo')) + # TODO: doublechek: python > 3.7 raise argparse.ArgumentError + # CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) + # assert set(os.listdir(src['egg'])) == set(('.git', 'bar', 'foo')) # Switch to specific revision, then switch back to master branch. develop.sources = { @@ -80,30 +82,32 @@ def testUpdateWithRevisionPin(self, develop, mkgitrepo, src): rev=rev, url='%s' % repository.base, path=src['egg'])} - CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) - assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2')) + # TODO: doublechek: python > 3.7 raise argparse.ArgumentError + # CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) + # assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2')) develop.sources = { 'egg': Source( kind='git', name='egg', url='%s' % repository.base, path=src['egg'])} - CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) - assert set(os.listdir(src['egg'])) == set(('.git', 'bar', 'foo')) - - CmdStatus(develop)(develop.parser.parse_args(['status'])) + # TODO: doublechek: python > 3.7 raise argparse.ArgumentError + # CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) + # assert set(os.listdir(src['egg'])) == set(('.git', 'bar', 'foo')) + # CmdStatus(develop)(develop.parser.parse_args(['status'])) + # TODO: doublechek: python > 3.7 raise argparse.ArgumentError insetead of SystemExit # we can't use both rev and branch - with pytest.raises(SystemExit): - develop.sources = { - 'egg': Source( - kind='git', - name='egg', - branch='test', - rev=rev, - url='%s' % repository.base, - path=src['egg-failed'])} - CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) + # with pytest.raises(SystemExit): + # develop.sources = { + # 'egg': Source( + # kind='git', + # name='egg', + # branch='test', + # rev=rev, + # url='%s' % repository.base, + # path=src['egg-failed'])} + # CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) def testUpdateWithoutRevisionPin(self, develop, mkgitrepo, src, capsys): from mr.developer.commands import CmdCheckout diff --git a/src/mr/developer/tests/test_mercurial.py b/src/mr/developer/tests/test_mercurial.py index ad7b4185..7ef915e7 100644 --- a/src/mr/developer/tests/test_mercurial.py +++ b/src/mr/developer/tests/test_mercurial.py @@ -1,6 +1,6 @@ import os -import pytest +# import pytest from mock import patch from mr.developer.extension import Source @@ -91,7 +91,7 @@ def testUpdateWithRevisionPin(self, develop, src, tempdir): CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo')) - # TODO: double check this + # TODO: double check this test # check branch # develop.sources = { @@ -107,13 +107,14 @@ def testUpdateWithRevisionPin(self, develop, src, tempdir): # assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo')) # we can't use both rev and branch - with pytest.raises(SystemExit): - develop.sources = { - 'egg': Source( - kind='hg', - name='egg', - branch='test', - rev=rev, - url='%s' % repository, - path=os.path.join(src, 'egg-failed'))} - CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) + # TODO: doublechek: python > 3.7 raise argparse.ArgumentError insetead of SystemExit + # with pytest.raises(SystemExit): + # develop.sources = { + # 'egg': Source( + # kind='hg', + # name='egg', + # branch='test', + # rev=rev, + # url='%s' % repository, + # path=os.path.join(src, 'egg-failed'))} + # CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) From 12ee91ad997ee4291d5637b77c739600dec97290 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Tue, 18 Feb 2025 11:37:02 +0100 Subject: [PATCH 05/13] deps --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8bed2350..eebf5dda 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,7 +24,7 @@ jobs: if: runner.os == 'Linux' run: | sudo apt-get update - sudo apt-get install -y mercurial + sudo apt-get install -y mercurial subversion - name: Install dependencies run: | From 6b5f57fa2adcf39e66c315408b78f8ae2913548c Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Tue, 18 Feb 2025 15:57:19 +0100 Subject: [PATCH 06/13] fix tests --- .gitignore | 3 +- src/mr/developer/tests/test_git.py | 79 +++++++++++------------- src/mr/developer/tests/test_mercurial.py | 78 ++++++++++++++++------- 3 files changed, 91 insertions(+), 69 deletions(-) diff --git a/.gitignore b/.gitignore index 2e2b2e42..d2b69bcd 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ /include/ /.installed.cfg /lib/ -/parts/ \ No newline at end of file +/parts/ +/.python-version diff --git a/src/mr/developer/tests/test_git.py b/src/mr/developer/tests/test_git.py index 58c0280e..77ac260b 100644 --- a/src/mr/developer/tests/test_git.py +++ b/src/mr/developer/tests/test_git.py @@ -1,7 +1,7 @@ import os import shutil -# import pytest +import pytest from mock import patch from mr.developer.extension import Source @@ -29,7 +29,6 @@ def createDefaultContent(self, repository): def testUpdateWithRevisionPin(self, develop, mkgitrepo, src): from mr.developer.commands import CmdCheckout from mr.developer.commands import CmdUpdate - from mr.developer.commands import CmdStatus repository = mkgitrepo('repository') rev = self.createDefaultContent(repository) @@ -48,6 +47,13 @@ def testUpdateWithRevisionPin(self, develop, mkgitrepo, src): shutil.rmtree(src['egg']) + def testUpdateWithBranch(self, develop, mkgitrepo, src): + from mr.developer.commands import CmdCheckout + from mr.developer.commands import CmdUpdate + from mr.developer.commands import CmdStatus + repository = mkgitrepo('repository') + self.createDefaultContent(repository) + # check branch develop.sources = { 'egg': Source( @@ -56,58 +62,43 @@ def testUpdateWithRevisionPin(self, develop, mkgitrepo, src): branch='test', url='%s' % repository.base, path=src['egg'])} - # TODO: doublechek: python > 3.7 raise argparse.ArgumentError - # CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) - # assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2')) - # CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) - # assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2')) + CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) + assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2')) + CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) + assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2')) CmdStatus(develop)(develop.parser.parse_args(['status'])) - # switch implicitly to master branch - develop.sources = { - 'egg': Source( - kind='git', - name='egg', - url='%s' % repository.base, - path=src['egg'])} - # TODO: doublechek: python > 3.7 raise argparse.ArgumentError - # CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) - # assert set(os.listdir(src['egg'])) == set(('.git', 'bar', 'foo')) - - # Switch to specific revision, then switch back to master branch. - develop.sources = { - 'egg': Source( - kind='git', - name='egg', - rev=rev, - url='%s' % repository.base, - path=src['egg'])} - # TODO: doublechek: python > 3.7 raise argparse.ArgumentError - # CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) - # assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2')) + def testUpdateWithMain(self, develop, mkgitrepo, src): + from mr.developer.commands import CmdCheckout + from mr.developer.commands import CmdUpdate + repository = mkgitrepo('repository') + self.createDefaultContent(repository) develop.sources = { 'egg': Source( kind='git', name='egg', url='%s' % repository.base, path=src['egg'])} - # TODO: doublechek: python > 3.7 raise argparse.ArgumentError - # CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) - # assert set(os.listdir(src['egg'])) == set(('.git', 'bar', 'foo')) - # CmdStatus(develop)(develop.parser.parse_args(['status'])) + CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) + assert set(os.listdir(src['egg'])) == set(('.git', 'bar', 'foo')) + CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) + assert set(os.listdir(src['egg'])) == set(('.git', 'bar', 'foo')) - # TODO: doublechek: python > 3.7 raise argparse.ArgumentError insetead of SystemExit + def testRaiseExceptionUpdateWithRevisionAndBranch(self, develop, mkgitrepo, src): + from mr.developer.commands import CmdCheckout + repository = mkgitrepo('repository') + rev = self.createDefaultContent(repository) # we can't use both rev and branch - # with pytest.raises(SystemExit): - # develop.sources = { - # 'egg': Source( - # kind='git', - # name='egg', - # branch='test', - # rev=rev, - # url='%s' % repository.base, - # path=src['egg-failed'])} - # CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) + with pytest.raises(SystemExit): + develop.sources = { + 'egg': Source( + kind='git', + name='egg', + branch='test', + rev=rev, + url='%s' % repository.base, + path=src['egg-failed'])} + CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) def testUpdateWithoutRevisionPin(self, develop, mkgitrepo, src, capsys): from mr.developer.commands import CmdCheckout diff --git a/src/mr/developer/tests/test_mercurial.py b/src/mr/developer/tests/test_mercurial.py index 7ef915e7..b6ba6a55 100644 --- a/src/mr/developer/tests/test_mercurial.py +++ b/src/mr/developer/tests/test_mercurial.py @@ -1,6 +1,6 @@ import os -# import pytest +import pytest from mock import patch from mr.developer.extension import Source @@ -91,30 +91,60 @@ def testUpdateWithRevisionPin(self, develop, src, tempdir): CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo')) - # TODO: double check this test + def testUpdateWithBranch(self, develop, src, tempdir): + from mr.developer.commands import CmdCheckout + from mr.developer.commands import CmdUpdate + repository = tempdir['repository'] + os.mkdir(repository) + process = Process(cwd=repository) + process.check_call("hg init %s" % repository) + foo = repository['foo'] + foo.create_file('foo') + process.check_call("hg add %s" % foo, echo=False) + process.check_call("hg branch test", echo=False) + process.check_call("hg commit %s -m foo -u test" % foo, echo=False) # check branch - # develop.sources = { - # 'egg': Source( - # kind='hg', - # name='egg', - # branch='test', - # url='%s' % repository, - # path=os.path.join(src, 'egg'))} - # CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) - # assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo')) - # CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) - # assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo')) + develop.sources = { + 'egg': Source( + kind='hg', + name='egg', + branch='test', + url='%s' % repository, + path=os.path.join(src, 'egg'))} + CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) + assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo')) + CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg'])) + assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo')) + + def testUpdateRaiseWithRevAndBranch(self, develop, src, tempdir): + from mr.developer.commands import CmdCheckout + repository = tempdir['repository'] + os.mkdir(repository) + process = Process(cwd=repository) + process.check_call("hg init %s" % repository) + foo = repository['foo'] + foo.create_file('foo') + process.check_call("hg add %s" % foo, echo=False) + process.check_call("hg branch test", echo=False) + process.check_call("hg commit %s -m foo -u test" % foo, echo=False) + + # get comitted rev + lines = process.check_call("hg log %s" % foo, echo=False) + try: + # XXX older version + rev = lines[0].split()[1].split(b(':'))[1] + except Exception: + rev = lines[0].split()[1] # we can't use both rev and branch - # TODO: doublechek: python > 3.7 raise argparse.ArgumentError insetead of SystemExit - # with pytest.raises(SystemExit): - # develop.sources = { - # 'egg': Source( - # kind='hg', - # name='egg', - # branch='test', - # rev=rev, - # url='%s' % repository, - # path=os.path.join(src, 'egg-failed'))} - # CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) + with pytest.raises(SystemExit): + develop.sources = { + 'egg': Source( + kind='hg', + name='egg', + branch='test', + rev=rev, + url='%s' % repository, + path=os.path.join(src, 'egg-failed'))} + CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg'])) From 550b341dc65aca8f1617703aba587cb4a720b96a Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Tue, 18 Feb 2025 16:51:42 +0100 Subject: [PATCH 07/13] subpath test --- src/mr/developer/tests/conftest.py | 3 +++ src/mr/developer/tests/test_extension.py | 32 ++++++++++++++++++++++++ src/mr/developer/tests/utils.py | 4 +++ 3 files changed, 39 insertions(+) diff --git a/src/mr/developer/tests/conftest.py b/src/mr/developer/tests/conftest.py index a36306a4..2ee19c6e 100644 --- a/src/mr/developer/tests/conftest.py +++ b/src/mr/developer/tests/conftest.py @@ -8,6 +8,9 @@ class Path(str): def __getitem__(self, name): return Path(os.path.join(self, name)) + def create_dir(self): + os.makedirs(str(self)) + def create_file(self, *content): f = open(self, 'w') f.write('\n'.join(content)) diff --git a/src/mr/developer/tests/test_extension.py b/src/mr/developer/tests/test_extension.py index 0ebdb809..0ffed5b8 100644 --- a/src/mr/developer/tests/test_extension.py +++ b/src/mr/developer/tests/test_extension.py @@ -299,6 +299,38 @@ def testDevelopSourcesMix(self, buildout, extension): _exists.__exit__(None, None, None) assert develop == ['/normal/develop', '/develop/with/slash/', 'src/pkg.bar'] + def testDevelopMonorepo(self, buildout, extension): + buildout['sources'].update({ + 'pkg.bar': 'git dummy://foo subpath=bar'}) + buildout['buildout']['auto-checkout'] = 'pkg.bar' + _exists = patch('os.path.exists') + exists = _exists.__enter__() + try: + exists().return_value = True + (develop, develeggs, versions) = extension.get_develop_info() + finally: + _exists.__exit__(None, None, None) + assert develop == ['src/pkg.bar/bar'] + assert develeggs == {'pkg.bar': '/buildout/src/pkg.bar/bar'} + assert versions == {'pkg.bar': ''} + + def testDevelopMonorepoTwoRepos(self, buildout, extension): + buildout['sources'].update({ + 'pkg.bar': 'git dummy://monorepo subpath=bar', + 'pkg.foo': 'git dummy://monorepo subpath=foo', + }) + buildout['buildout']['auto-checkout'] = 'pkg.bar\npkg.foo' + _exists = patch('os.path.exists') + exists = _exists.__enter__() + try: + exists().return_value = True + (develop, develeggs, versions) = extension.get_develop_info() + finally: + _exists.__exit__(None, None, None) + assert develop == ['src/pkg.bar/bar', 'src/pkg.foo/foo'] + assert develeggs == {'pkg.bar': '/buildout/src/pkg.bar/bar', 'pkg.foo': '/buildout/src/pkg.foo/foo'} + assert versions == {'pkg.bar': '', 'pkg.foo': ''} + def testMissingSourceSection(self, buildout, extension): del buildout['sources'] assert extension.get_sources() == {} diff --git a/src/mr/developer/tests/utils.py b/src/mr/developer/tests/utils.py index 39784668..a8bfb836 100644 --- a/src/mr/developer/tests/utils.py +++ b/src/mr/developer/tests/utils.py @@ -191,6 +191,10 @@ def add_file(self, fname, msg=None): msg = fname self("git commit %s -m %s" % (repo_file, msg), echo=False) + def add_dir(self, dirname): + repo_dir = self.base[dirname] + repo_dir.create_dir() + def add_submodule(self, submodule, submodule_name): assert isinstance(submodule, GitRepo) self("git submodule add %s %s" % (submodule.url, submodule_name)) From 3b67a802bdd9ac2dd732f8c3697bb6865bf454f4 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Tue, 18 Feb 2025 17:11:34 +0100 Subject: [PATCH 08/13] readme --- README.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.rst b/README.rst index 1a366bd7..bae4ad7d 100644 --- a/README.rst +++ b/README.rst @@ -127,6 +127,9 @@ Common options those which start with the prefix. These two options currently only work for ``cvs`` and ``hg``. + The ``subpath`` option allows you to specify a subdirectory of a repository + as the source for the Python package, ideal for monorepos. + ``svn`` The ``url`` is one of the urls supported by subversion. From 0cc8365cd7536b7c86e3bbd4aaedeb702a040272 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Tue, 18 Feb 2025 17:13:12 +0100 Subject: [PATCH 09/13] changelog --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 3e416b5f..559dfbd9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,7 @@ Changelog 2.0.3 (unreleased) ------------------ -- Nothing changed yet. +* Add ``subpath`` option to specify a subdirectory of a repository. [mamico] 2.0.2 (2024-04-24) From 2d0f5bd7b8d1c6c15c941cc049a0edc23c8895b3 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Wed, 4 Jun 2025 22:35:38 +0200 Subject: [PATCH 10/13] Update tests.yml Co-authored-by: Maurits van Rees --- .github/workflows/tests.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index eebf5dda..b4e00c6b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,8 +2,14 @@ name: Run Tox Tests on: push: - branches: [ "main", "subpath" ] + branches: + - master + - main pull_request: + branches: + - master + - main + workflow_dispatch: jobs: test: From 19bd71311797e9cef192fbae8e86e01283457347 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Wed, 4 Jun 2025 22:35:46 +0200 Subject: [PATCH 11/13] Update tests.yml Co-authored-by: Maurits van Rees --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b4e00c6b..e394c815 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v3 From c83d24965b46a7433bc56a308b4ae4e2d010b01d Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Wed, 4 Jun 2025 22:35:53 +0200 Subject: [PATCH 12/13] Update tox.ini Co-authored-by: Maurits van Rees --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 16563452..6ac2f895 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27,py27-configparser,py34,py35,py36,py37,py38,py39,py310,py311,py312 +envlist = py39,py310,py311,py312,py313 [gh-actions] python = From 567f3e93d3b4031e56e2438b35a1fbc676817ad1 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Wed, 4 Jun 2025 22:36:00 +0200 Subject: [PATCH 13/13] Update tox.ini Co-authored-by: Maurits van Rees --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 6ac2f895..3d27478b 100644 --- a/tox.ini +++ b/tox.ini @@ -7,6 +7,7 @@ python = 3.10: py310 3.11: py311 3.12: py312 + 3.13: py313 [base] deps =