Commits

Mikhail Korobov committed e3c1836

Better command_is_available implementation. Fix #25.

Comments (0)

Files changed (4)

fab_deploy/django_commands.py

 def command_is_available(command):
     with settings(hide('warnings', 'running', 'stdout', 'stderr'), warn_only=True):
         output = run('python manage.py help ' + command)
-    return output.succeeded
+
+    if output.succeeded:
+        return True
+
+    # that's ugly
+    unknown_command_msg = "Unknown command: '%s'" % command
+    if unknown_command_msg in output:
+        return False
+
+    # re-raise the original exception
+    run('python manage.py help ' + command)
 
 @utils.inside_project
 def manage(command):
 
         fab manage:createsuperuser
     """
-    if not command_is_available(command):
-        warn('Management command "%s" is not available' % command)
+    command_name = command.split()[0]
+    if not command_is_available(command_name):
+        warn('Management command "%s" is not available' % command_name)
     else:
         run('python manage.py ' + command)
 

fab_deploy_tests/test_project/config.server.py

     }
 }
 INSTANCE_NAME = '{{ INSTANCE_NAME }}'
+{{ EXTRA }}

fab_deploy_tests/test_project/fabfile.py

         INSTANCE_NAME = 'bar',
     )
     update_env()
+
+def invalid_site():
+    env.hosts = ['foo@127.0.0.1:2222']
+    env.conf = dict(
+        DB_PASSWORD = '123',
+        VCS = 'none',
+        SERVER_NAME = 'invalid.example.com',
+        INSTANCE_NAME = 'invalid',
+        EXTRA = 'raise Exception()'
+    )
+    update_env()

fab_deploy_tests/tests/deploy.py

 from __future__ import absolute_import
 import os
+from fabric.api import *
+from fabtest import fab, vbox_urlopen, FabricAbortException
 from fab_deploy.utils import run_as
-from fabric.api import *
-from fabtest import fab, vbox_urlopen
 from fab_deploy.deploy import deploy_project, push, undeploy
 from fab_deploy.mysql import mysql_create_db
 from fab_deploy.apache import (apache_make_config, apache_make_wsgi,
                                apache_restart, apache_install)
+from fab_deploy.django_commands import command_is_available
 from .base import FabDeployTest
 from ..utils import setup_ssh, setup_sudo
-from ..test_project.fabfile import foo_site, bar_site
+from ..test_project.fabfile import foo_site, bar_site, invalid_site
 from ..test_project2.fabfile import foo_site as foo_site2
 
 def get_file_content(remote_file):
     def assertResponse(self, url, data):
         self.assertEqual(vbox_urlopen(url).read(), data)
 
+    def assertHttpError(self, url):
+        # FIXME: this should only catch BadStatusLine and urllib2.HttpError
+        self.assertRaises(Exception, vbox_urlopen, url)
+
     def assertNoFile(self, path):
         with(settings(warn_only=True)):
             res = get_file_content(path)
         with(settings(warn_only=True)):
             self.assertTrue(get_file_content(path))
 
+    def assertCommandAvailable(self, command):
+        result = fab(command_is_available, command)
+        self.assertTrue(result[0])
+
+    def assertCommandNotAvailable(self, command):
+        result = fab(command_is_available, command)
+        self.assertFalse(result[0])
+
+    def assertCommandFails(self, command):
+        self.assertRaises(FabricAbortException, fab,
+                          command_is_available, command)
+
     def setup_conf(self):
         self.cwd = os.getcwd()
         os.chdir(self.project)
 
 class DeployTest(FabDeployProjectTest):
 
+    def assertInstanceWorks(self, instance):
+        url = 'http://%s.example.com/instance/' % instance
+        self.assertResponse(url, instance)
+
+    def assertInstanceDoesntWork(self, instance):
+        url = 'http://%s.example.com/instance/' % instance
+        self.assertHttpError(url)
+
     def test_deploy(self):
+        self.assertCommandFails('syncdb')
+
         # deploy first site
         fab(foo_site)
         fab(deploy_project)
 
-        # first site works
-        self.assertResponse('http://foo.example.com/instance/', 'foo')
+        self.assertCommandAvailable('syncdb')
+        self.assertCommandNotAvailable('syncddb')
+
+        self.assertInstanceWorks('foo')
 
         # deploy second site
         fab(bar_site)
         fab(deploy_project)
 
-        # second site works
-        self.assertResponse('http://bar.example.com/instance/', 'bar')
-        # first site is still available
-        self.assertResponse('http://foo.example.com/instance/', 'foo')
+        self.assertInstanceWorks('bar')
+        self.assertInstanceWorks('foo')
+
+        # deploy improperly configured site
+        fab(invalid_site)
+
+        # config errors should not be silenced
+        self.assertRaises(FabricAbortException, fab, deploy_project)
+
+        # old sites still work
+        self.assertInstanceWorks('bar')
+        self.assertInstanceWorks('foo')
+        self.assertInstanceDoesntWork('invalid')
 
 
 class CustomLayoutDeployTest(FabDeployProjectTest):
         # check that updeploy disables the site
         # TODO: more undeploy tests
         fab(undeploy, confirm=False)
-        self.assertRaises(Exception, vbox_urlopen, url)
+        self.assertHttpError(url)
 
         # deploying project again should be possible
         fab(deploy_project)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.