Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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 depenencies (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y mercurial subversion

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox tox-gh-actions

- name: Test with tox
run: tox
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@
/include/
/.installed.cfg
/lib/
/parts/
/parts/
/.python-version
2 changes: 1 addition & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
3 changes: 3 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ version-levels = 2
[devpi:upload]
formats = sdist.tgz,bdist_wheel

[flake8]
extend-ignore = E501

[check-manifest]
ignore =
build_git.sh
Expand Down
10 changes: 5 additions & 5 deletions src/mr/developer/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
2 changes: 2 additions & 0 deletions src/mr/developer/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions src/mr/developer/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
32 changes: 32 additions & 0 deletions src/mr/developer/tests/test_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -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() == {}
Expand Down
48 changes: 23 additions & 25 deletions src/mr/developer/tests/test_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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(
Expand All @@ -62,37 +68,26 @@ def testUpdateWithRevisionPin(self, develop, mkgitrepo, src):
assert set(os.listdir(src['egg'])) == set(('.git', 'foo', 'foo2'))
CmdStatus(develop)(develop.parser.parse_args(['status']))

# switch implicitly to master branch
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'])}
CmdUpdate(develop)(develop.parser.parse_args(['up', 'egg']))
CmdCheckout(develop)(develop.parser.parse_args(['co', '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'])}
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']))

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 = {
Expand Down Expand Up @@ -169,10 +164,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"
Expand Down
33 changes: 33 additions & 0 deletions src/mr/developer/tests/test_mercurial.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,19 @@ 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'))

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(
Expand All @@ -104,6 +117,26 @@ 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'))

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
with pytest.raises(SystemExit):
develop.sources = {
Expand Down
7 changes: 7 additions & 0 deletions src/mr/developer/tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 "[email protected]"')
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]
Expand All @@ -188,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))
Expand Down
9 changes: 8 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
[tox]
envlist = py27,py27-configparser,py34,py35,py36,py37
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 =
Expand Down