Skip to content
This repository has been archived by the owner on May 16, 2024. It is now read-only.

cross repository dependency management #159

Merged
merged 6 commits into from
Mar 20, 2015
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ install:
- cp -r ../maintainer-quality-tools/ $HOME
- mv tests/test_repo/* ./
- export PATH=$HOME/maintainer-quality-tools/travis:$PATH
- git clone https://github.com/OCA/partner-contact ${HOME}/department -b 8.0 # only used if VERSION not set in env
- travis_install_nightly 8.0 # only used if VERSION not set in env

script:
Expand Down
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@ To setup the TravisCI continuous integration for your project, just copy the
content of the [`/sample_files`](https://github.com/OCA/maintainer-quality-tools/tree/master/sample_files)
to your project’s root directory.

If your project depends on other OCA/Github repositories simply add the following under `before_install` section:
If your project depends on other OCA/Github repositories, create a file called `oca_dependencies.txt` at the root of your project and list the dependencies in there, one per line:

install:
- git clone https://github.com/OCA/a_project_x ${HOME}/a_project_x -b ${VERSION}
- git clone https://github.com/OCA/a_project_y ${HOME}/a_project_y -b ${VERSION}
project_name optional_repository_url optional_branch_name
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should put OCA_project_name and put the other two parameters enclosed by brackets, that it's the common terminology for regular expressions with optional parts.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's the common way for USAGE strings output when --help is passed as a command line option... In the context of an example configuration I tend to find my version clearer.

Waiting for more feedback on this.


The addons path used will automatically consider these repositories.

Expand Down
2 changes: 0 additions & 2 deletions sample_files/.travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ install:
- git clone --depth=1 https://github.com/OCA/maintainer-quality-tools.git ${HOME}/maintainer-quality-tools
- export PATH=${HOME}/maintainer-quality-tools/travis:${PATH}
- travis_install_nightly
# example: dependency
# - git clone --depth=1 https://github.com/OCA/webkit-tools -b ${VERSION} $HOME/webkit-tools

script:
- travis_run_tests
Expand Down
15 changes: 15 additions & 0 deletions sample_files/oca_dependencies.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# List the OCA project dependencies, one per line
# Add a repository url and branch if you need a forked version
#
# Examples
# ========
#
# To depend on the standard version of sale-workflow, use:
# sale-workflow
#
# To explicitely give the URL of a fork, and still use the version specified in
# .travis.yml, use:
# sale-workflow https://github.com/OCA/sale-workflow
#
# To provide both the URL and a branch, use:
# sale-workflow https://github.com/OCA/sale-workflow branchname
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want to also have hash support ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so: I have not seen any .travis.yml files in the OCA specifying a hash for a dependency branch. I expect most of the time to have only the branch name in the file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comments as in doc.

5 changes: 5 additions & 0 deletions tests/test_repo/oca_dependencies.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# List the OCA project dependencies, one per line
# Add a repository url and branch if you need a forked version

partner-contact https://github.com/OCA/partner-contact 8.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be also partner-contact to show a simple example. Then, you can put another line with a complete example for a personal repository.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a test, not an example. The example is in the sample_files/oca_dependencies.txt


100 changes: 100 additions & 0 deletions travis/clone_oca_dependencies
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/usr/bin/python
"""Usage: clone_oca_dependencies [<checkout_dir> <build_dir>]

Arguments:

checkout_dir: the directory in which the dependency repositories will be cloned
build_dir: the directory in which the tested repositories have been cloned

If no arguments are provided, default to the layout used in the OCA travis
configuration.

The program will process the file oca_dependencies.txt at the root of the
tested repository, and clone the dependency repositories in checkout_dir,
before recursively processing the oca_dependencies.txt files of the
dependencies.

The expected format for oca_dependencies.txt:

* comment lines start with # and are ignored
* a dependency line contains:
- the name of the OCA project
- (optional) the URL to the git repository (defaulting to the OCA repository)
- (optional) the name of the branch to use (defaulting to ${VERSION})
"""
from __future__ import print_function
import sys
import os
import os.path as osp
import subprocess
import logging


_logger = logging.getLogger()


def parse_depfile(depfile):
deps = []
for line in depfile:
line = line.strip()
if not line or line.startswith('#'):
continue
parts = line.split()
repo = parts[0]
if len(parts) > 2:
branch = parts[2]
else:
branch = os.environ.get('VERSION', '8.0')
if len(parts) > 1:
url = parts[1]
else:
url = 'https://github.com/OCA/%s' % repo
deps.append((repo, url, branch))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a matter of taste but I prefer named tuple for this kind of usage

return deps


def git_checkout(home, reponame, url, branch):
checkout_dir = osp.join(home, reponame)
if not osp.isdir(checkout_dir):
command = ['git', 'clone', '-q', url, '-b', branch, checkout_dir]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use depth=1 to clone faster.

_logger.info('Calling %s', ' '.join(command))
subprocess.check_call(command)
return checkout_dir


def run(home, build_dir):
dependencies = []
processed = set()
for repo in os.listdir(build_dir):
_logger.info('examining %s', repo)
processed.add(repo)
depfilename = osp.join(build_dir, repo, 'oca_dependencies.txt')
dependencies.append(depfilename)
for depfilename in dependencies:
try:
with open(depfilename) as depfile:
deps = parse_depfile(depfile)
except IOError:
deps = []
for depname, url, branch in deps:
_logger.info('* processing %s', depname)
if depname in processed:
continue
processed.add(depname)
checkout_dir = git_checkout(home, depname, url, branch)
new_dep_filename = osp.join(checkout_dir, 'oca_dependencies.txt')
if new_dep_filename not in dependencies:
dependencies.append(new_dep_filename)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like to modify a list when we are iterating through it with a for loop.
I prefer to use something like:

    while dependencies:
        depfilename = dependencies.pop()
        ...
        if new_dep_filename not in dependencies:
            dependencies.append(new_dep_filename)

(not exactly the same result as dependencies.pop() will process the dependencies from last to first but I don't think it is an issue here)

Maybe just appending to a list in the for is ok (remove is surely not), but still a bit troubling IMO.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appending to a list in a for loop is ok. Removing is ok too, as long as you remove after the current iteration element (which is also why appending to a list is perfectly safe: in this case I'm using the list as a queue of elements to be processed). It is even a very nice way to refactor a recursion to an interation 😸

There are checks in the code to avoid looping, which are not convenient to write if I pop() the elements from the queue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok 🙌

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should add dependencies recursively for each dependency, because main project can depend on a module of a repository that has dependencies because of another modules, but not the one we need.

Making this, we can increase a lot the build time (specially with those branches that has a lot of commits or branches - this will get worse with each Odoo version).

Each repository maintainer should resolve manually the dependency chain and add it to main project.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am with @pedrobaeza here. Repos are loose groups of modules, and I am not very keen to work too much on repo dependencies (a concept I'd like to get rid of eventually). We already have the proprietary odoo dependency resolution, and we're adding even another one.

Still, I understand how that makes life a bit easier, and I am not blocking it. Thanks!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree.

This will reduce breakage when other repositories' external dependencies change. And I personnally hate having to manually track these when a computer can perfectly do the job in my stead (and should do so).

@pedrobaeza Built time increase argument is void. The resulting clones are currently exactly the same as the one we are manually configuring, and the checkout time of OCA repositories is negligible compared to creating the base database.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gurneyalex, no if added dependencies (for new modules) are not used by our repository. For example, spanish localization uses base_location of partner-contact repository. Only that module. But module partner_relations needs web repository because it uses web_m2x_options and web_tree_many2one_clickable, and thus this dependency is added at partner-contact level.

The way you make it, it will download also project web, and the corresponding dependencies for it, and so on recursively, needing to download practically all OCA repos for each Travis test, when I only need for spanish localization to download partner-contact repo.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also agree with Pedro. I would rather see "nested" dependencies be explicitly declared. I also hope this gives incentive keep dependencies to a minimum and try to stay away from a "monolith".



if __name__ == '__main__':
if len(sys.argv) == 1:
home = os.environ['HOME']
build_dir = osp.join(home, 'build/OCA')
elif len(sys.argv) == 2 or len(sys.argv) > 3:
print(__doc__)
sys.exit(1)
else:
home = sys.argv[1]
build_dir = sys.argv[2]
run(home, build_dir)
14 changes: 9 additions & 5 deletions travis/travis_install_nightly
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash

pip install -q QUnitSuite flake8 coveralls pylint
pip install -q QUnitSuite flake8 coveralls pylint > /dev/null 2>&1

# We can exit here and do nothing if this only a LINT check
if [ "${LINT_CHECK}" == "1" ] ; then
Expand All @@ -18,20 +18,24 @@ IFS="/" read -a REPO <<< "${ODOO_REPO}"
ODOO_URL="https://github.com/${REPO[0]}/${REPO[1]}/archive/${VERSION}.tar.gz"

echo "Installing Odoo ${ODOO_URL}"
wget -O odoo.tar.gz ${ODOO_URL}
wget -nv -O odoo.tar.gz ${ODOO_URL}
tar -xf odoo.tar.gz -C ${HOME}

sudo apt-get -q -y install expect-dev # provides unbuffer utility
sudo apt-get -q -y install python-lxml # because pip installation is slooow
echo "Installing Python dependencies"
sudo apt-get -qq -y install expect-dev # provides unbuffer utility
sudo apt-get -qq -y install python-lxml # because pip installation is slooow

# Workaround to force using system site packages (see https://github.com/Shippable/support/issues/241#issuecomment-57947925)
rm $VIRTUAL_ENV/lib/python2.7/no-global-site-packages.txt
rm -f $VIRTUAL_ENV/lib/python2.7/no-global-site-packages.txt

pip install -q -r $(dirname ${BASH_SOURCE[0]})/requirements.txt

# Use reference .coveragerc
cp ${HOME}/maintainer-quality-tools/cfg/.coveragerc .

echo "Getting dependencies"
clone_oca_dependencies

# Expected directory structure:
#
# HOME/
Expand Down