added more tests

include img in manifest
disclaimer in root cli script
add blinker to dev tools
version file included in package
cli bug fixes
This commit is contained in:
Matthew Scragg 2014-10-22 15:38:32 -05:00
parent 38e5ef85c0
commit bf3b3d3d74
13 changed files with 178 additions and 120 deletions

View file

@ -1,4 +1,5 @@
include requirements.txt VERSION LICENSE README.md
include requirements.txt LICENSE README.md
recursive-include realms/static/img *
recursive-include realms/static/fonts *
recursive-include realms/static/css *
recursive-include realms/static/js *

View file

@ -1 +0,0 @@
0.3.20

View file

@ -1,6 +1,14 @@
#!/usr/bin/env python
from realms.commands import cli
import pip
from realms.cli import cli
if __name__ == '__main__':
print
print "----------------------------------"
print "This script is for development.\n" \
"If you installed via pip, " \
"you should have realms-wiki in your PATH that should be used instead."
print "----------------------------------"
print
cli()

View file

@ -18,9 +18,10 @@ from flask.ext.assets import Environment, Bundle
from werkzeug.routing import BaseConverter
from werkzeug.exceptions import HTTPException
from realms.lib.util import to_canonical, remove_ext, mkdir_safe, gravatar_url, to_dict
from realms.lib.hook import HookModelMeta
from realms.lib.util import is_su, in_virtualenv
from .lib.util import to_canonical, remove_ext, mkdir_safe, gravatar_url, to_dict
from .lib.hook import HookModelMeta
from .lib.util import is_su, in_virtualenv
from .version import __version__
class Application(Flask):
@ -79,7 +80,7 @@ class Application(Flask):
if hasattr(sources.hooks, 'before_first_request'):
self.before_first_request(sources.hooks.before_first_request)
# print >> sys.stderr, ' * Ready in %.2fms' % (1000.0 * (time.time() - start_time))
# print >> sys.stderr, ' * Ready in %.2fms' % (1000.0 * (time.time() - start_time))
def make_response(self, rv):
if rv is None:
@ -200,17 +201,6 @@ def create_app(config=None):
return app
@click.group()
@click.pass_context
def cli(ctx):
# This could probably done better
if ctx.invoked_subcommand in ['setup', 'setup_upstart', 'pip']:
if not in_virtualenv() and not is_su():
# This does not account for people the have user level python installs
# that aren't virtual environments! Should be rare I think
click.secho("This command requires root privileges, use sudo or run as root.", fg='red')
sys.exit()
# Init plugins here if possible
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
@ -242,9 +232,6 @@ assets.register('main.css',
'css/style.css')
@click.group()
def cli():
pass

View file

@ -1,14 +1,40 @@
from realms import config, create_app, db, cli
from realms.lib.util import random_string, in_virtualenv, green, yellow, red
from realms import config, create_app, db, cli as cli_, __version__
from realms.lib.util import is_su, random_string, in_virtualenv, green, yellow, red
from subprocess import call, Popen
from multiprocessing import cpu_count
import click
import json
import sys
import os
import pip
app = create_app()
def print_version(ctx, param, value):
if not value or ctx.resilient_parsing:
return
green(__version__)
ctx.exit()
@click.group()
@click.option('--version', is_flag=True, callback=print_version,
expose_value=False, is_eager=True)
@click.pass_context
def cli(ctx):
# This could probably done better
if ctx.invoked_subcommand in ['setup', 'pip']:
if not in_virtualenv() and not is_su():
# This does not account for people the have user level python installs
# that aren't virtual environments! Should be rare I think
click.secho("This command requires root privileges, use sudo or run as root.", fg='red')
sys.exit()
if ctx.invoked_subcommand in ['setup_upstart']:
if not is_su():
click.secho("This command requires root privileges, use sudo or run as root.", fg='red')
sys.exit()
cli.add_command(cli_)
def get_user():
@ -117,37 +143,28 @@ def get_prefix():
return sys.prefix
def get_pip():
""" Get virtualenv path for pip
"""
if in_virtualenv():
return get_prefix() + '/bin/pip'
else:
return 'pip'
@cli.command()
@cli.command(name='pip')
@click.argument('cmd', nargs=-1)
def pip(cmd):
def pip_(cmd):
""" Execute pip commands, useful for virtualenvs
"""
call(get_pip() + ' ' + ' '.join(cmd), shell=True)
pip.main(cmd)
def install_redis():
call([get_pip(), 'install', 'redis'])
pip.main(['install', 'redis'])
def install_mysql():
call([get_pip(), 'install', 'MySQL-Python'])
pip.main(['install', 'MySQL-Python'])
def install_postgres():
call([get_pip(), 'install', 'psycopg2'])
pip.main(['install', 'psycopg2'])
def install_memcached():
call([get_pip(), 'install', 'python-memcached'])
pip.main(['install', 'python-memcached'])
@click.command()
@ -220,9 +237,9 @@ def dev(port):
""" Run development server
"""
green("Starting development server")
app.run(host="0.0.0.0",
port=port,
debug=True)
create_app().run(host="0.0.0.0",
port=port,
debug=True)
def start_server():
@ -235,7 +252,7 @@ def start_server():
green("Server started. Port: %s" % config.PORT)
Popen("gunicorn 'realms:create_app()' -b 0.0.0.0:%s -k gevent %s" %
(config.PORT, flags), shell=True, executable='/bin/bash')
(config.PORT, flags), shell=True, executable='/bin/bash')
def stop_server():
@ -308,21 +325,20 @@ def drop_db():
def test():
""" Run tests
"""
for mod in [('flask.ext.testing', 'Flask-Testing'), ('nose', 'nose')]:
for mod in [('flask.ext.testing', 'Flask-Testing'), ('nose', 'nose'), ('blinker', 'blinker')]:
if not module_exists(mod[0]):
call([get_pip(), 'install', mod[1]])
pip.main(['install', mod[1]])
nosetests = get_prefix() + "/bin/nosetests" if in_virtualenv() else "nosetests"
call([nosetests, config.APP_PATH])
call([nosetests, 'realms'])
@cli.command()
def version():
""" Output version
"""
with open(os.path.join(config.APP_PATH, 'VERSION')) as f:
click.echo(f.read().strip())
green(__version__)
if __name__ == '__main__':

View file

@ -12,8 +12,12 @@ class BaseTest(TestCase):
app.config['PRESERVE_CONTEXT_ON_EXCEPTION'] = False
app.config['WIKI_PATH'] = '/tmp/%s' % random_string(12)
app.config['DB_URI'] = 'sqlite:////tmp/%s.db' % random_string(12)
app.config.update(self.configure())
return app
def configure(self):
return {}
def tearDown(self):
call(['rm', '-rf', self.app.config['WIKI_PATH']])
call(['rm', '-f', self.app.config['DB_URI'][10:]])

View file

@ -20,7 +20,7 @@ def cname_to_filename(cname):
:return: str -- Filename
"""
return cname.lower() + ".md"
return cname + ".md"
def filename_to_cname(filename):
@ -71,25 +71,26 @@ class Wiki(HookMixin):
return username, email
def revert_page(self, name, commit_sha, message, username):
def revert_page(self, name, commit_sha, message, username, email):
"""Revert page to passed commit sha1
:param name: Name of page to revert.
:param commit_sha: Commit Sha1 to revert to.
:param message: Commit message.
:param username:
:param username: Committer name.
:param email: Committer email.
:return: Git commit sha1
"""
page = self.get_page(name, commit_sha)
if not page:
raise PageNotFound()
raise PageNotFound('Commit not found')
if not message:
commit_info = gittle.utils.git.commit_info(self.gittle[commit_sha.encode('latin-1')])
message = commit_info['message']
return self.write_page(name, page['data'], message=message, username=username)
return self.write_page(name, page['data'], message=message, username=username, email=email)
def write_page(self, name, content, message=None, create=False, username=None, email=None):
"""Write page to git repo

View file

@ -1,39 +1,72 @@
import json
from nose.tools import *
from flask import url_for
from realms.modules.wiki.models import Wiki, cname_to_filename, filename_to_cname
from realms.modules.wiki.models import cname_to_filename, filename_to_cname
from realms.lib.test import BaseTest
class WikiTest(BaseTest):
class WikiBaseTest(BaseTest):
def write_page(self, name, message=None, content=None):
return self.client.post(url_for('wiki.page_write', name=name),
data=dict(message=message, content=content))
def test_wiki_routes(self):
self.assert_200(self.client.get(url_for("wiki.create")))
""" Create a test page first!
for route in ['page', 'edit', 'history', 'index']:
rv = self.client.get(url_for("wiki.%s" % route, name='test'))
self.assert_200(rv, "wiki.%s: %s" % (route, rv.status_code))
"""
def test_write_page(self):
self.assert_200(
self.client.post(url_for('wiki.page_write', name='test'), data=dict(
content='testing',
message='test message'
)))
self.assert_200(self.client.get(url_for('wiki.page', name='test')))
def test_delete_page(self):
self.assert_200(self.client.delete(url_for('wiki.page_write', name='test')))
self.assert_status(self.client.get(url_for('wiki.page', name='test')), 302)
def test_revert(self):
pass
class UtilTest(WikiBaseTest):
def test_cname_to_filename(self):
eq_(cname_to_filename('test'), 'test.md')
def test_filename_to_cname(self):
eq_(filename_to_cname('test-1-2-3.md'), 'test-1-2-3')
eq_(filename_to_cname('test-1-2-3.md'), 'test-1-2-3')
class WikiTest(WikiBaseTest):
def test_routes(self):
self.assert_200(self.client.get(url_for("wiki.create")))
self.write_page('test', message='test message', content='testing')
for route in ['page', 'edit', 'history']:
rv = self.client.get(url_for("wiki.%s" % route, name='test'))
self.assert_200(rv, "wiki.%s: %s" % (route, rv.status_code))
self.assert_200(self.client.get(url_for('wiki.index')))
def test_write_page(self):
self.assert_200(self.write_page('test', message='test message', content='testing'))
rv = self.client.get(url_for('wiki.page', name='test'))
self.assert_200(rv)
self.assert_context('name', 'test')
eq_(self.get_context_variable('page')['info']['message'], 'test message')
eq_(self.get_context_variable('page')['data'], 'testing')
def test_history(self):
self.assert_200(self.client.get(url_for('wiki.history', name='test')))
def test_delete_page(self):
self.app.config['WIKI_LOCKED_PAGES'] = ['test']
self.assert_403(self.client.delete(url_for('wiki.page_write', name='test')))
self.app.config['WIKI_LOCKED_PAGES'] = []
self.assert_200(self.client.delete(url_for('wiki.page_write', name='test')))
rv = self.client.get(url_for('wiki.page', name='test'))
self.assert_status(rv, 302)
def test_revert(self):
rv1 = self.write_page('test', message='test message', content='testing_old')
self.write_page('test', message='test message', content='testing_new')
data = json.loads(rv1.data)
self.client.post(url_for('wiki.revert'), data=dict(name='test', commit=data['sha']))
self.client.get(url_for('wiki.page', name='test'))
eq_(self.get_context_variable('page')['data'], 'testing_old')
self.assert_404(self.client.post(url_for('wiki.revert'), data=dict(name='test', commit='does not exist')))
self.app.config['WIKI_LOCKED_PAGES'] = ['test']
self.assert_403(self.client.post(url_for('wiki.revert'), data=dict(name='test', commit=data['sha'])))
self.app.config['WIKI_LOCKED_PAGES'] = []
class RelativePathTest(WikiTest):
def configure(self):
return dict(RELATIVE_PATH='wiki')

View file

@ -1,7 +1,7 @@
from flask import abort, g, render_template, request, redirect, Blueprint, flash, url_for, current_app
from flask.ext.login import login_required, current_user
from realms.lib.util import to_canonical, remove_ext
from .models import PageNotFound
blueprint = Blueprint('wiki', __name__)
@ -28,19 +28,22 @@ def compare(name, fsha, dots, lsha):
@blueprint.route("/_revert", methods=['POST'])
@login_required
def revert():
name = request.form.get('name')
cname = to_canonical(request.form.get('name'))
commit = request.form.get('commit')
cname = to_canonical(name)
message = request.form.get('message', "Reverting %s" % cname)
if cname in current_app.config.get('WIKI_LOCKED_PAGES'):
return dict(error=True, message="Page is locked")
return dict(error=True, message="Page is locked"), 403
try:
sha = g.current_wiki.revert_page(cname,
commit,
message=message,
username=current_user.username,
email=current_user.email)
except PageNotFound as e:
return dict(error=True, message=e.message), 404
sha = g.current_wiki.revert_page(name,
commit,
message=message,
username=current_user.username,
email=current_user.email)
if sha:
flash("Page reverted")
@ -104,7 +107,7 @@ def page_write(name):
if request.method == 'POST':
# Create
if cname in current_app.config.get('WIKI_LOCKED_PAGES'):
return dict(error=True, message="Page is locked")
return dict(error=True, message="Page is locked"), 403
sha = g.current_wiki.write_page(cname,
request.form['content'],
@ -117,7 +120,7 @@ def page_write(name):
edit_cname = to_canonical(request.form['name'])
if edit_cname in current_app.config.get('WIKI_LOCKED_PAGES'):
return dict(error=True, message="Page is locked")
return dict(error=True, message="Page is locked"), 403
if edit_cname != cname.lower():
g.current_wiki.rename_page(cname, edit_cname)
@ -132,6 +135,9 @@ def page_write(name):
else:
# DELETE
if cname in current_app.config.get('WIKI_LOCKED_PAGES'):
return dict(error=True, message="Page is locked"), 403
sha = g.current_wiki.delete_page(name,
username=current_user.username,
email=current_user.email)

1
realms/version.py Normal file
View file

@ -0,0 +1 @@
__version__ = '0.3.24'

View file

@ -1,3 +1,4 @@
-r requirements.txt
Flask-Testing==0.4.2
nose==1.3.4
blinker==1.3

View file

@ -1,18 +1 @@
Flask==0.10.1
Flask-Assets==0.10
Flask-Cache==0.13.1
Flask-Login==0.2.11
Flask-SQLAlchemy==2.0
Flask-WTF==0.10.2
PyYAML==3.11
bcrypt==1.0.2
beautifulsoup4==4.3.2
click==3.3
gevent==1.0.1
ghdiff==0.4
gittle==0.4.0
gunicorn==19.1.1
itsdangerous==0.24
lxml==3.4.0
markdown2==2.3.0
simplejson==3.6.3
-e .

View file

@ -12,8 +12,8 @@ with open('README.md') as f:
with open('requirements.txt') as f:
required = f.read().splitlines()
with open('VERSION') as f:
VERSION = f.read().strip()
__version__ = None
exec(open('realms/version.py').read())
CLASSIFIERS = [
'Intended Audience :: Developers',
@ -23,10 +23,28 @@ CLASSIFIERS = [
'Topic :: Internet :: WWW/HTTP :: Dynamic Content']
setup(name='realms-wiki',
version=VERSION,
version=__version__,
packages=find_packages(),
install_requires=required,
#scripts=['realms-wiki'],
install_requires=[
'Flask==0.10.1',
'Flask-Assets==0.10',
'Flask-Cache==0.13.1',
'Flask-Login==0.2.11',
'Flask-SQLAlchemy==2.0',
'Flask-WTF==0.10.2',
'PyYAML==3.11',
'bcrypt==1.0.2',
'beautifulsoup4==4.3.2',
'click==3.3',
'gevent==1.0.1',
'ghdiff==0.4',
'gittle==0.4.0',
'gunicorn==19.1.1',
'itsdangerous==0.24',
'lxml==3.4.0',
'markdown2==2.3.0',
'simplejson==3.6.3'
],
entry_points={
'console_scripts': [
'realms-wiki = realms.cli:cli'