Skip to content

Commit

Permalink
Merge branch 'aptivate-git_branch'
Browse files Browse the repository at this point in the history
  • Loading branch information
audreyfeldroy committed Aug 29, 2013
2 parents cf1fb09 + 895224f commit 293eb95
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 30 deletions.
1 change: 1 addition & 0 deletions cookiecutter/find.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def find_template(repo_dir):

repo_dir_contents = os.listdir(repo_dir)

project_template = None
for item in repo_dir_contents:
if 'cookiecutter' in item and \
'{{' in item and \
Expand Down
19 changes: 12 additions & 7 deletions cookiecutter/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,19 @@

logger = logging.getLogger(__name__)

def cookiecutter(input_dir):
def cookiecutter(input_dir, checkout=None):
"""
API equivalent to using Cookiecutter at the command line.
:param input_dir: A directory containing a project template dir,
:param input_dir: A directory containing a project template dir,
or a URL to git repo.
:param checkout: The branch, tag or commit ID to checkout after clone
"""

# If it's a git repo, clone and prompt
if input_dir.endswith('.git'):
got_repo_arg = True
repo_dir = git_clone(input_dir)
repo_dir = git_clone(input_dir, checkout)
project_template = find_template(repo_dir)
else:
got_repo_arg = False
Expand Down Expand Up @@ -77,17 +78,21 @@ def parse_cookiecutter_args(args):
'input_dir',
help='Cookiecutter project dir, e.g. cookiecutter-pypackage/'
)
parser.add_argument(
'-c', '--checkout',
help='branch, tag or commit to checkout after git clone'
)
return parser.parse_args(args)

def main():
""" Entry point for the package, as defined in setup.py. """

# Log info and above to console
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)

args = parse_cookiecutter_args(sys.argv[1:])
cookiecutter(args.input_dir)

cookiecutter(args.input_dir, args.checkout)

if __name__ == '__main__':
main()
15 changes: 11 additions & 4 deletions cookiecutter/vcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,38 @@
import logging
import os
import shutil
import subprocess
import sys

from .prompt import query_yes_no


def git_clone(repo):
def git_clone(repo, checkout=None):
"""
Clone a git repo to the current directory.
:param repo: Git repo URL ending with .git.
:param checkout: The branch, tag or commit ID to checkout after clone
"""


# Return repo dir
tail = os.path.split(repo)[1]
repo_dir = tail.rsplit('.git')[0]
logging.debug('repo_dir is {0}'.format(repo_dir))

if os.path.isdir(repo_dir):
ok_to_delete = query_yes_no("You've cloned {0} before. Is it okay to delete and re-clone it?".format(repo_dir))
ok_to_delete = query_yes_no(
"You've cloned {0} before. Is it okay to delete and re-clone it?".format(repo_dir),
default="yes"
)
if ok_to_delete:
shutil.rmtree(repo_dir)
else:
sys.exit()

os.system('git clone {0}'.format(repo))

if checkout is not None:
subprocess.check_call(['git', 'checkout', checkout], cwd=repo_dir)

return repo_dir
8 changes: 8 additions & 0 deletions docs/cookiecutter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ cookiecutter Package
:undoc-members:
:show-inheritance:

:mod:`prompt` Module
--------------------

.. automodule:: cookiecutter.prompt
:members:
:undoc-members:
:show-inheritance:

:mod:`utils` Module
-------------------

Expand Down
4 changes: 4 additions & 0 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ defined in the project's `cookiecutter.json`.
Then, Cookiecutter will generate a project from the template, using the values
that you entered. It will be placed in your current directory.

And if you want to specify a branch you can do that with::

$ cookiecutter https://github.com/audreyr/cookiecutter-pypackage.git --checkout develop

Or hook directly into the Cookiecutter API
------------------------------------------

Expand Down
1 change: 1 addition & 0 deletions requirements/test_26.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ mock
unittest2
ordereddict
simplejson
subprocess32
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
# Add Python 2.6 and 2.7-specific dependencies
if sys.version < '3':
test_requirements.append('mock')
test_requirements.append('subprocess32')

# There are no Python 3-specific dependencies to add

Expand Down
106 changes: 91 additions & 15 deletions tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,60 +8,136 @@
Tests for the Cookiecutter example repos.
"""

import errno
import os
import shutil
import sys
import unittest

PY3 = sys.version > '3'
if PY3:
from unittest.mock import patch
input_str = 'builtins.input'
from io import StringIO
else:
import __builtin__
from mock import patch
input_str = '__builtin__.raw_input'
from cStringIO import StringIO

if sys.version_info[:2] < (2, 7):
import unittest2 as unittest
import subprocess32 as subprocess
else:
import subprocess
import unittest

try:
travis = os.environ[u'TRAVIS']
except KeyError:
travis = False


@unittest.skip(reason='Works locally with tox but fails on Travis.')
@unittest.skipIf(condition=travis, reason='Works locally with tox but fails on Travis.')
class TestPyPackage(unittest.TestCase):

def test_cookiecutter_pypackage(self):
"""
Tests that https://github.com/audreyr/cookiecutter-pypackage.git works.
"""

os.system('git clone https://github.com/audreyr/cookiecutter-pypackage.git')
os.system('cookiecutter cookiecutter-pypackage/')
self.assertTrue(os.path.isfile('cookiecutter-pypackage/alotofeffort/README.rst'))
with subprocess.Popen(
'git clone https://github.com/audreyr/cookiecutter-pypackage.git',
stdin=subprocess.PIPE,
shell=True
) as proc:
proc.wait()

with subprocess.Popen(
'cookiecutter cookiecutter-pypackage/',
stdin=subprocess.PIPE,
shell=True
) as proc:
proc.wait()

self.assertTrue(os.path.isfile('cookiecutter-pypackage/boilerplate/README.rst'))

def tearDown(self):
if os.path.isdir('cookiecutter-pypackage'):
shutil.rmtree('cookiecutter-pypackage')

@unittest.skip(reason='Works locally with tox but fails on Travis.')
@unittest.skipIf(condition=travis, reason='Works locally with tox but fails on Travis.')
class TestJQuery(unittest.TestCase):

def test_cookiecutter_jquery(self):
"""
Tests that https://github.com/audreyr/cookiecutter-jquery.git works.
"""

os.system('git clone https://github.com/audreyr/cookiecutter-jquery.git')
os.system('cookiecutter cookiecutter-jquery/')
with subprocess.Popen(
'git clone https://github.com/audreyr/cookiecutter-jquery.git',
stdin=subprocess.PIPE,
shell=True
) as proc:
proc.wait()

with subprocess.Popen(
'cookiecutter cookiecutter-jquery/',
stdin=subprocess.PIPE,
shell=True
) as proc:
proc.wait()

self.assertTrue(os.path.isfile('cookiecutter-jquery/boilerplate/README.md'))

def tearDown(self):
if os.path.isdir('cookiecutter-jquery'):
shutil.rmtree('cookiecutter-jquery')

@unittest.skip(reason='Works locally with tox but fails on Travis.')
@unittest.skipIf(condition=travis, reason='Works locally with tox but fails on Travis.')
class TestExamplesRepoArg(unittest.TestCase):

def test_cookiecutter_pypackage_git(self):
os.system('cookiecutter https://github.com/audreyr/cookiecutter-pypackage.git')
self.assertTrue(os.path.isfile('alotofeffort/README.rst'))
with subprocess.Popen(
'cookiecutter https://github.com/audreyr/cookiecutter-pypackage.git',
stdin=subprocess.PIPE,
shell=True
) as proc:

# Just skip all the prompts
proc.communicate(input=b'\n\n\n\n\n\n\n\n\n\n\n\n')

self.assertTrue(os.path.isfile('boilerplate/README.rst'))

def tearDown(self):
if os.path.isdir('boilerplate'):
shutil.rmtree('boilerplate')

@unittest.skipIf(condition=travis, reason='Works locally with tox but fails on Travis.')
class TestGitBranch(unittest.TestCase):

def setUp(self):
if os.path.isdir('cookiecutter-pypackage'):
shutil.rmtree('cookiecutter-pypackage')

def test_branch(self):
with subprocess.Popen(
'cookiecutter -c console-script https://github.com/audreyr/cookiecutter-pypackage.git',
stdin=subprocess.PIPE,
shell=True
) as proc:

# Just skip all the prompts
proc.communicate(input=b'\n\n\n\n\n\n\n\n\n\n\n\n')

self.assertTrue(os.path.isfile('boilerplate/README.rst'))
self.assertTrue(os.path.isfile('boilerplate/boilerplate/main.py'))

def tearDown(self):
if os.path.isdir('alotofeffort'):
shutil.rmtree('alotofeffort')
if os.path.isdir('cookiecutter-pypackage'):
shutil.rmtree('cookiecutter-pypackage')
if os.path.isdir('boilerplate'):
shutil.rmtree('boilerplate')



if __name__ == '__main__':
unittest.main()
14 changes: 10 additions & 4 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
input_str = '__builtin__.raw_input'
from cStringIO import StringIO


# Log debug and above to console
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG)

Expand All @@ -51,17 +51,23 @@ def test_cookiecutter_no_slash(self):
self.assertTrue(os.path.isdir('tests/fake-repo-pre/fake-project'))
self.assertTrue(os.path.isfile('tests/fake-repo-pre/fake-project/README.rst'))
self.assertFalse(os.path.exists('tests/fake-repo-pre/fake-project/json/'))

def tearDown(self):
if os.path.isdir('tests/fake-repo-pre/fake-project'):
shutil.rmtree('tests/fake-repo-pre/fake-project')


class TestArgParsing(unittest.TestCase):

def test_parse_cookiecutter_args(self):
args = main.parse_cookiecutter_args(['project/'])
self.assertEqual(args.input_dir, 'project/')
self.assertEqual(args.checkout, None)

def test_parse_cookiecutter_args_with_branch(self):
args = main.parse_cookiecutter_args(['project/', '--checkout', 'develop'])
self.assertEqual(args.input_dir, 'project/')
self.assertEqual(args.checkout, 'develop')


class TestCookiecutterRepoArg(unittest.TestCase):
Expand All @@ -76,7 +82,7 @@ def test_cookiecutter_git(self):
self.assertTrue(os.path.isdir('boilerplate'))
self.assertTrue(os.path.isfile('boilerplate/README.rst'))
self.assertTrue(os.path.exists('boilerplate/setup.py'))

def tearDown(self):
if os.path.isdir('cookiecutter-pypackage'):
shutil.rmtree('cookiecutter-pypackage')
Expand Down
26 changes: 26 additions & 0 deletions tests/test_vcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@
Tests for `cookiecutter.vcs` module.
"""

import locale
import logging
import os
import shutil
import subprocess
import sys
import unittest

PY3 = sys.version > '3'
if PY3:
import subprocess
from unittest.mock import patch
input_str = 'builtins.input'
else:
import subprocess32 as subprocess
import __builtin__
from mock import patch
input_str = '__builtin__.raw_input'
Expand All @@ -29,6 +33,7 @@

# Log debug and above to console
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG)
encoding = locale.getdefaultlocale()[1]


class TestVCS(unittest.TestCase):
Expand All @@ -42,6 +47,27 @@ def test_git_clone(self):
if os.path.isdir('cookiecutter-pypackage'):
shutil.rmtree('cookiecutter-pypackage')

def test_git_clone_checkout(self):
repo_dir = vcs.git_clone(
'https://github.com/audreyr/cookiecutter-pypackage.git',
'console-script'
)
git_dir = 'cookiecutter-pypackage'
self.assertEqual(repo_dir, git_dir)
self.assertTrue(os.path.isfile(os.path.join('cookiecutter-pypackage', 'README.rst')))

with subprocess.Popen(
['git', 'symbolic-ref', 'HEAD'],
cwd=git_dir,
stdout=subprocess.PIPE
) as proc:
symbolic_ref = proc.communicate()[0]
branch = symbolic_ref.decode(encoding).strip().split('/')[-1]
self.assertEqual('console-script', branch)

if os.path.isdir(git_dir):
shutil.rmtree(git_dir)


class TestVCSPrompt(unittest.TestCase):

Expand Down

0 comments on commit 293eb95

Please sign in to comment.