Skip to content

Commit 004e2fd

Browse files
Merge branch 'master' into master
2 parents 6702173 + 17e28dd commit 004e2fd

12 files changed

Lines changed: 153 additions & 25 deletions

File tree

.github/workflows/tests.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Run Tox Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
- main
8+
- subpath
9+
pull_request:
10+
branches:
11+
- master
12+
- main
13+
workflow_dispatch:
14+
15+
jobs:
16+
test:
17+
runs-on: ubuntu-latest
18+
strategy:
19+
matrix:
20+
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
21+
22+
steps:
23+
- uses: actions/checkout@v3
24+
25+
- name: Set up Python ${{ matrix.python-version }}
26+
uses: actions/setup-python@v4
27+
with:
28+
python-version: ${{ matrix.python-version }}
29+
30+
- name: Install depenencies (Ubuntu)
31+
if: runner.os == 'Linux'
32+
run: |
33+
sudo apt-get update
34+
sudo apt-get install -y mercurial subversion
35+
36+
- name: Install dependencies
37+
run: |
38+
python -m pip install --upgrade pip
39+
pip install tox tox-gh-actions
40+
41+
- name: Test with tox
42+
run: tox

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@
1616
/include/
1717
/.installed.cfg
1818
/lib/
19-
/parts/
19+
/parts/
20+
/.python-version

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Changelog
1212
<https://github.com/fschulze/mr.developer/issues/125>`_.
1313
[janjaapdriessen]
1414

15+
- Add ``subpath`` option to specify a subdirectory of a repository. [mamico]
16+
1517

1618
2.0.4 (2025-07-17)
1719
------------------

README.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ Common options
127127
those which start with the prefix.
128128
These two options currently only work for ``cvs`` and ``hg``.
129129

130+
The ``subpath`` option allows you to specify a subdirectory of a repository
131+
as the source for the Python package, ideal for monorepos.
132+
130133
``svn``
131134
The ``url`` is one of the urls supported by subversion.
132135

setup.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ version-levels = 2
77
[devpi:upload]
88
formats = sdist.tgz,bdist_wheel
99

10+
[flake8]
11+
extend-ignore = E501
12+
1013
[check-manifest]
1114
ignore =
1215
build_git.sh

src/mr/developer/extension.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ def get_develop_info(self):
209209
source = sources[name]
210210
if source.get('egg', True) and name not in develeggs:
211211
path = sources[name]['path']
212+
if sources[name].get("subpath"):
213+
path = os.path.join(path, sources[name]["subpath"])
212214
status = config_develop.get(name, name in auto_checkout)
213215
if os.path.exists(path) and status:
214216
if name in auto_checkout:

src/mr/developer/tests/conftest.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ class Path(str):
88
def __getitem__(self, name):
99
return Path(os.path.join(self, name))
1010

11+
def create_dir(self):
12+
os.makedirs(str(self))
13+
1114
def create_file(self, *content):
1215
f = open(self, 'w')
1316
f.write('\n'.join(content))

src/mr/developer/tests/test_extension.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,38 @@ def testDevelopSourcesMix(self, buildout, extension):
300300
_exists.__exit__(None, None, None)
301301
assert develop == ['/normal/develop', '/develop/with/slash/', 'src/pkg.bar']
302302

303+
def testDevelopMonorepo(self, buildout, extension):
304+
buildout['sources'].update({
305+
'pkg.bar': 'git dummy://foo subpath=bar'})
306+
buildout['buildout']['auto-checkout'] = 'pkg.bar'
307+
_exists = patch('os.path.exists')
308+
exists = _exists.__enter__()
309+
try:
310+
exists().return_value = True
311+
(develop, develeggs, versions) = extension.get_develop_info()
312+
finally:
313+
_exists.__exit__(None, None, None)
314+
assert develop == ['src/pkg.bar/bar']
315+
assert develeggs == {'pkg.bar': '/buildout/src/pkg.bar/bar'}
316+
assert versions == {'pkg.bar': ''}
317+
318+
def testDevelopMonorepoTwoRepos(self, buildout, extension):
319+
buildout['sources'].update({
320+
'pkg.bar': 'git dummy://monorepo subpath=bar',
321+
'pkg.foo': 'git dummy://monorepo subpath=foo',
322+
})
323+
buildout['buildout']['auto-checkout'] = 'pkg.bar\npkg.foo'
324+
_exists = patch('os.path.exists')
325+
exists = _exists.__enter__()
326+
try:
327+
exists().return_value = True
328+
(develop, develeggs, versions) = extension.get_develop_info()
329+
finally:
330+
_exists.__exit__(None, None, None)
331+
assert develop == ['src/pkg.bar/bar', 'src/pkg.foo/foo']
332+
assert develeggs == {'pkg.bar': '/buildout/src/pkg.bar/bar', 'pkg.foo': '/buildout/src/pkg.foo/foo'}
333+
assert versions == {'pkg.bar': '', 'pkg.foo': ''}
334+
303335
def testMissingSourceSection(self, buildout, extension):
304336
del buildout['sources']
305337
assert extension.get_sources() == {}

src/mr/developer/tests/test_git.py

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ def createDefaultContent(self, repository):
2929
def testUpdateWithRevisionPin(self, develop, mkgitrepo, src):
3030
from mr.developer.commands import CmdCheckout
3131
from mr.developer.commands import CmdUpdate
32-
from mr.developer.commands import CmdStatus
3332
repository = mkgitrepo('repository')
3433
rev = self.createDefaultContent(repository)
3534

@@ -48,6 +47,13 @@ def testUpdateWithRevisionPin(self, develop, mkgitrepo, src):
4847

4948
shutil.rmtree(src['egg'])
5049

50+
def testUpdateWithBranch(self, develop, mkgitrepo, src):
51+
from mr.developer.commands import CmdCheckout
52+
from mr.developer.commands import CmdUpdate
53+
from mr.developer.commands import CmdStatus
54+
repository = mkgitrepo('repository')
55+
self.createDefaultContent(repository)
56+
5157
# check branch
5258
develop.sources = {
5359
'egg': Source(
@@ -62,37 +68,26 @@ def testUpdateWithRevisionPin(self, develop, mkgitrepo, src):
6268
assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2'))
6369
CmdStatus(develop)(develop.parser.parse_args(['status']))
6470

65-
# switch implicitly to master branch
71+
def testUpdateWithMain(self, develop, mkgitrepo, src):
72+
from mr.developer.commands import CmdCheckout
73+
from mr.developer.commands import CmdUpdate
74+
repository = mkgitrepo('repository')
75+
self.createDefaultContent(repository)
6676
develop.sources = {
6777
'egg': Source(
6878
kind='git',
6979
name='egg',
7080
url='%s' % repository.base,
7181
path=src['egg'])}
72-
CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg']))
82+
CmdCheckout(develop)(develop.parser.parse_args(['co', 'egg']))
7383
assert set(os.listdir(src['egg'])) == set(('.git', 'bar', 'foo'))
74-
75-
# Switch to specific revision, then switch back to master branch.
76-
develop.sources = {
77-
'egg': Source(
78-
kind='git',
79-
name='egg',
80-
rev=rev,
81-
url='%s' % repository.base,
82-
path=src['egg'])}
83-
CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg']))
84-
assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2'))
85-
develop.sources = {
86-
'egg': Source(
87-
kind='git',
88-
name='egg',
89-
url='%s' % repository.base,
90-
path=src['egg'])}
9184
CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg']))
9285
assert set(os.listdir(src['egg'])) == set(('.git', 'bar', 'foo'))
9386

94-
CmdStatus(develop)(develop.parser.parse_args(['status']))
95-
87+
def testRaiseExceptionUpdateWithRevisionAndBranch(self, develop, mkgitrepo, src):
88+
from mr.developer.commands import CmdCheckout
89+
repository = mkgitrepo('repository')
90+
rev = self.createDefaultContent(repository)
9691
# we can't use both rev and branch
9792
with pytest.raises(SystemExit):
9893
develop.sources = {
@@ -169,7 +164,13 @@ def testUpdateVerbose(self, develop, mkgitrepo, src, capsys):
169164
('info', ("Updated 'egg' with git.",), {}),
170165
('info', ("Switching to remote branch 'remotes/origin/master'.",), {})]
171166
captured = capsys.readouterr()
172-
assert "set up to track" in captured.out
167+
# git output varies between versions...
168+
git_outputs = [
169+
"* 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",
170+
"* 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",
171+
"* 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",
172+
]
173+
assert captured.out in git_outputs
173174
CmdStatus(develop)(develop.parser.parse_args(['status', '-v']))
174175
captured = capsys.readouterr()
175176
assert captured.out == "~ A egg\n ## master...origin/master\n\n"

src/mr/developer/tests/test_mercurial.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,19 @@ def testUpdateWithRevisionPin(self, develop, src, tempdir):
9191
CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg']))
9292
assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo'))
9393

94+
def testUpdateWithBranch(self, develop, src, tempdir):
95+
from mr.developer.commands import CmdCheckout
96+
from mr.developer.commands import CmdUpdate
97+
repository = tempdir['repository']
98+
os.mkdir(repository)
99+
process = Process(cwd=repository)
100+
process.check_call("hg init %s" % repository)
101+
foo = repository['foo']
102+
foo.create_file('foo')
103+
process.check_call("hg add %s" % foo, echo=False)
104+
process.check_call("hg branch test", echo=False)
105+
process.check_call("hg commit %s -m foo -u test" % foo, echo=False)
106+
94107
# check branch
95108
develop.sources = {
96109
'egg': Source(
@@ -104,6 +117,26 @@ def testUpdateWithRevisionPin(self, develop, src, tempdir):
104117
CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg']))
105118
assert set(os.listdir(os.path.join(src, 'egg'))) == set(('.hg', 'foo'))
106119

120+
def testUpdateRaiseWithRevAndBranch(self, develop, src, tempdir):
121+
from mr.developer.commands import CmdCheckout
122+
repository = tempdir['repository']
123+
os.mkdir(repository)
124+
process = Process(cwd=repository)
125+
process.check_call("hg init %s" % repository)
126+
foo = repository['foo']
127+
foo.create_file('foo')
128+
process.check_call("hg add %s" % foo, echo=False)
129+
process.check_call("hg branch test", echo=False)
130+
process.check_call("hg commit %s -m foo -u test" % foo, echo=False)
131+
132+
# get comitted rev
133+
lines = process.check_call("hg log %s" % foo, echo=False)
134+
try:
135+
# XXX older version
136+
rev = lines[0].split()[1].split(b(':'))[1]
137+
except Exception:
138+
rev = lines[0].split()[1]
139+
107140
# we can't use both rev and branch
108141
with pytest.raises(SystemExit):
109142
develop.sources = {

0 commit comments

Comments
 (0)