Splits out staging. Finishes up on deploy.
authordsc <dsc@less.ly>
Wed, 9 May 2012 08:59:44 +0000 (01:59 -0700)
committerdsc <dsc@less.ly>
Wed, 9 May 2012 08:59:44 +0000 (01:59 -0700)
fabfile/__init__.py
fabfile/bundle.py
fabfile/deploy.py
fabfile/stages.py [new file with mode: 0644]
fabfile/util.py

index d720782..bb9bbaf 100644 (file)
@@ -2,24 +2,25 @@
 # -*- coding: utf-8 -*-
 "GraphKit Deployer"
 
-
 import sys
-from functools import wraps
 
 # Deal with the fact that we aren't *really* a Python project,
 # so we haven't declared python dependencies.
 try:
     from fabric.api import *
-    from path import path as p # fabric.api.path conflicts
+    from path import path as p # renamed to avoid conflict w/ fabric.api.path
+    import yaml
 except ImportError:
     print """ 
         ERROR: You're missing a dependency!
         To build this project using fabric, you'll need to install fabric (and some other stuff):
             
-            pip install -U fabric path.py
+            pip install -U fabric path.py PyYAML
         """
     sys.exit(1)
 
+from util import *
+
 
 
 ### Fabric Config
@@ -37,6 +38,7 @@ env.minify_cmd         = 'uglifyjs'
 env.dist               = p('dist')
 env.local_tmp          = p('tmp')
 env.work_dir           = env.local_tmp/env.dist
+
 env.browserify_js      = 'vendor/browserify.js'
 env.work_browserify_js = env.work_dir/env.browserify_js
 env.vendor_search_dirs = map(p, ['static', 'var', env.work_dir])
@@ -45,15 +47,34 @@ env.app_bundle         = env.work_dir/'js/kraken/app-bundle.js'
 env.app_bundle_min     = p(env.app_bundle.replace('.js', '.min.js'))
 
 
-# Rename to avoid conflicts when we make top-level wrapper tasks
+
+### Setup Staging Environments
+
+# We declare stubs here to use @task and have them show up at the top level
+import stages
+
+@task
+def prod():
+    "Set deploy environment to production."
+
+@task
+def stage():
+    "Set deploy environment to stage."
+    stages.stage()
+
+
+
+### Project Tasks
+
 import bundle
 import deploy
 
 
 @task(default=True)
-def gogogo():
+def gogogoo():
     """ Bundles and deploys the project. [Default]
     """
     bundle.bundle_all()
     deploy.full_deploy()
 
+
index 81553c8..81c44c8 100644 (file)
@@ -1,12 +1,12 @@
 #!/usr/bin/env fab
 # -*- coding: utf-8 -*-
+"Deploy Bundle Tasks"
 
 from fabric.api import *
 from fabric.colors import white, blue, cyan, green, yellow, red, magenta
-from util import *
 
+from util import *
 
-### Build Deploy Bundle
 
 @task(default=True)
 def bundle_all():
index d3e71bc..c5ca070 100644 (file)
@@ -1,77 +1,77 @@
 #!/usr/bin/env fab
 # -*- coding: utf-8 -*-
+"Deploy Tasks"
+
+from functools import wraps
 
 from fabric.api import *
 from fabric.colors import white, blue, cyan, green, yellow, red, magenta
 from fabric.contrib.project import rsync_project
+
+import stages
 from util import *
 
 
-### Deploy Environments
 
-# There should be a way to do this using stages.
-# See: http://tav.espians.com/fabric-python-with-cleaner-api-and-parallel-deployment-support.html
-# env.config_file = False
-# env.stages = ['prod', 'staging']
+### Helpers
 
-@task
-def prod():
-    """ Set deploy environment to production.
-    """
-    env.deploy_env = 'prod'
-    env.hosts      = ['reportcard2.pmtpa.wmflabs']
-    env.target_dir = '/srv/reportcard/kraken-ui'
-    env.owner      = 'www-data'
-    env.group      = 'www'
-
-@task
-def staging():
-    """ Set deploy environment to staging.
-    """
-    env.deploy_env = 'staging'
-    env.hosts      = ['less.ly']
-    env.target_dir = '/home/wmf/projects/kraken-ui'
-    env.user       = 'wmf'
-    env.owner      = 'wmf'
-    env.group      = 'www'
+def ensure_stage(fn):
+    "Decorator that ensures a stage is set."
+    
+    @wraps(fn)
+    def wrapper(*args, **kwargs):
+        if 'deploy_env' not in env:
+            abort(red('You must specify a staging environment (prod, stage) prior to deploy!', bold=True))
+        return fn(*args, **kwargs)
+    
+    return wrapper
 
 
 
 ### Deploy Tasks
 
 @task(default=True)
+@ensure_stage
 def full_deploy():
     """ Deploy the project.
     """
-    pass
+    fix_permissions()
+    update()
+    distribute()
+    fix_permissions()
+    restart_server()
 
 @task
-def fix_permissions():
+@ensure_stage
+def fix_permissions(user=None, group=None):
     """ Recursively fixes permissions on the deployment host.
     """
+    if user  is None: user  = env.owner
+    if group is None: group = env.group
     sudo('chmod -R g+w %(target_dir)s' % env)
-    sudo('chown -R %(owner)s:%(group)s %(target_dir)s' % env)
+    sudo('chown -R %s:%s %s' % (user, group, env.target_dir))
 
 @task
+@ensure_stage
 def update():
     """ Runs git pull on the deployment host.
     """
-    with cd(env.target_dir):
-        run('git pull')
+    with cd(env.target_dir): run('git pull')
 
 @task
+@ensure_stage
 def distribute():
     """ Copies `dist` package to deployment host.
     """
+    local("rsync -Caz -v %(work_dir)s %(user)s@%(host)s:%(target_dir)s/%(dist)s" % env)
     # TODO: make sure the following works.
     # rsync_project(local_dir=env.work_dir, remote_dir="%(user)s@%(host)s:%(target_dir)s/%(dist)s" % env)
-    local("rsync -Caz -v %(work_dir)s %(user)s@%(host)s:%(target_dir)s/%(dist)s" % env)
 
 @task
+@ensure_stage
 def restart_server():
     """ Restarts node.js server on the deployment host.
     """
-    # need to work on this for less.ly
-    sudo("supervisor restart reportcard")
+    sudo("supervisorctl restart reportcard")
 
 
diff --git a/fabfile/stages.py b/fabfile/stages.py
new file mode 100644 (file)
index 0000000..ebada51
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env fab
+# -*- coding: utf-8 -*-
+"Setup Staging Environments"
+
+from fabric.api import env
+
+__all__ = ('prod', 'stage',)
+
+# (otto) There should be a way to do this using stages.
+# See: http://tav.espians.com/fabric-python-with-cleaner-api-and-parallel-deployment-support.html
+# (dsc) ...except that most of those changes are not actually in Fabric :(
+
+# env.config_file = False
+# env.stages = ['prod', 'staging']
+
+
+# NOTE WELL: These do not have @task as they'd show up as "stages.prod",
+# and we want them at the top level. See __init__.py for the wrappers.
+# Unfortunately, we can't put them in __init__.py without preventing deploy.py
+# from importing them.
+
+def prod():
+    """ Set deploy environment to production.
+    """
+    env.deploy_env = 'prod'
+    env.hosts      = ['reportcard2.pmtpa.wmflabs']
+    env.target_dir = '/srv/reportcard/kraken-ui'
+    env.owner      = 'www-data'
+    env.group      = 'www'
+
+def stage():
+    """ Set deploy environment to stage.
+    """
+    env.deploy_env = 'stage'
+    env.hosts      = ['less.ly']
+    env.target_dir = '/home/wmf/projects/kraken-ui'
+    env.user       = 'wmf'
+    env.owner      = 'wmf'
+    env.group      = 'www'
+
index b61d664..befa087 100644 (file)
@@ -8,7 +8,7 @@ from functools import wraps
 from fabric.api import *
 from fabric.colors import white, blue, cyan, green, yellow, red, magenta
 
-__all__ = ('quietly', 'msg', 'coke', 'update_version',)
+__all__ = ('quietly', 'msg', 'make_wrapper', 'coke', 'update_version',)
 
 
 @contextmanager
@@ -38,6 +38,7 @@ def msg(txt, quiet=False):
     return outer
 
 
+
 ### Misc
 
 def coke(args, capture=False):