Skip to content

Commit

Permalink
Initial commit; Version 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
justjkk committed Feb 17, 2015
0 parents commit 92e15ee
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*~
*.py[co]
*.egg-info
/build/
/dist/
66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Fab Polish

Run various checks against source code using Fabric

## Installation

`pip install fab-polish`

## Usage

### Minimal Usage

Create a `fabfile.py` in your source code with the following minimal code:

```python
from fabpolish import polish
from fabpolish.contrib import find_merge_conflict_leftovers
```

Now run `fab polish`. The above example runs a sniff that finds bad merge
commits by checking if symbols like '<<<<<<<' are present in the versioned
files.

### Writing Sniffs

You can create your own sniff by using the sniff decorator:

```python
from fabpolish import polish, sniff, local, info

@sniff(severity='critical', timing='fast')
def check_var_dump():
info("Checking var_dump statements...")
return local("! git grep 'var_dump'")
```

Severity can be 'critical', 'major', 'minor', 'info'. Default is 'critical'.
Timing can be 'slow', 'fast'. Default is 'fast'.

When using default values, the sniff decorator can be used without the function
call like so:

```python
@sniff
def your_sniff():
# code
```

Check https://github.com/practo/FabPolish/blob/master/fabpolish/contrib.py for more examples.

### Modifying Imported Sniffs

The severity, timing values can be altered for any sniff imported from contrib
using `update_sniff` function like follows:

```python
from fabpolish import update_sniff
from fabpolish.contrib import find_pep8_violations

update_sniff(find_pep8_violations, severity='major', timing='fast')
```

### Running All Sniffs

By default `fab polish` runs only fast-critical and fast-major sniffs. In a CI
environment, to run all the sniffs including slow, minor ones, run `fab polish:ci`
7 changes: 7 additions & 0 deletions fabfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from fabpolish import polish, update_sniff
from fabpolish.contrib import (
find_merge_conflict_leftovers,
find_pep8_violations
)

update_sniff(find_pep8_violations, severity='major', timing='fast')
125 changes: 125 additions & 0 deletions fabpolish/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import os
import sys

from functools import wraps

from fabric.api import lcd, local, settings, task, puts, hide
from fabric.colors import green

import fabfile

FABFILE_DIR = os.path.abspath(os.path.dirname(fabfile.__file__))

__version__ = '1.0.0'


def info(text):
puts(green(text))


def validate_severity(severity):
severity_options = ['critical', 'major', 'minor', 'info']
if severity not in severity_options:
raise ValueError('severity must be one of: ' + str(severity_options))


def validate_timing(timing):
timing_options = ['slow', 'fast']
if timing not in timing_options:
raise ValueError('timing must be one of: ' + str(timing_options))


_sniffs = []


def sniff(*args, **kwargs):
""" Decorator to collect sniffs and execute on polish
:param severity: Keyword argument only.
One of 'critical', 'major', 'minor', 'info'
Default: 'critical'
:type severity: str
:param timing: Keyword argument only. One of 'slow', 'fast'
Default: 'fast'
:type timing: str
"""
DEFAULT_SEVERITY = 'critical'
DEFAULT_TIMING = 'fast'
invoked = bool(not args or kwargs)
severity = kwargs.get('severity', DEFAULT_SEVERITY)
timing = kwargs.get('timing', DEFAULT_TIMING)
validate_severity(severity)
validate_timing(timing)

def decorator(func):
@task
@wraps(func)
def wrapper(*args, **kwargs):
with lcd(FABFILE_DIR), settings(hide('running')):
return func(*args, **kwargs)
_sniffs.append({
'severity': severity,
'timing': timing,
'function': wrapper
})
return wrapper
return decorator if invoked else decorator(args[0])


@task
def polish(env='dev'):
"""Polish code by running some or all sniffs
:param env: Environment to determine what all sniffs to run
Options: 'dev', 'ci'
Default: 'dev'
:type env: str
When environment is 'ci', all the sniffs registered are run.
When environment is 'dev', only fast-critical and fast-major
sniffs are run.
"""
results = list()
with settings(warn_only=True):
if env == 'ci':
sniffs_to_run = _sniffs
elif env == 'dev':
sniffs_to_run = []
for sniff in _sniffs:
if sniff['timing'] != 'fast':
continue
if sniff['severity'] not in ('critical', 'major'):
continue
sniffs_to_run.append(sniff)
else:
raise ValueError('env must be one of: ' + str(['dev', 'ci']))
for sniff in sniffs_to_run:
results.append(sniff['function']())

if any(result.failed for result in results):
sys.exit(1)


def update_sniff(function, severity=None, timing=None):
if type(function) == str:
function_name = function
else:
function_name = function.name
for sniff in _sniffs:
if sniff['function'].name == function_name:
break
else:
raise ValueError('function is not a sniff or is not loaded')
if severity is not None:
validate_severity(severity)
sniff['severity'] = severity
if timing is not None:
validate_timing(timing)
sniff['timing'] = timing


__all__ = [
'sniff',
'info',
'local',
'polish',
'update_sniff'
]
33 changes: 33 additions & 0 deletions fabpolish/contrib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from fabpolish import sniff, info, local


@sniff(severity='critical', timing='fast')
def find_merge_conflict_leftovers():
"""Find Merge conflict leftovers
"""
info('Finding merge conflict leftovers...')
return local("! git grep -P '^(<|=|>){7}(?![<=>])'")


@sniff(severity='major', timing='slow')
def find_php_syntax_errors():
"""Find syntax error in php files
"""
info('Finding syntax error in php files...')
return local(
"git ls-files -z | "
"grep -PZz '\.(php|phtml)$' | "
"xargs -0 -n 1 php -l >/tmp/debug"
)


@sniff(severity='minor', timing='slow')
def find_pep8_violations():
"""Run pep8 python coding standard check
"""
info('Running coding standards check for python files...')
return local(
"git ls-files -z | "
"grep -PZz '\.py$' | "
"xargs -0 pep8"
)
14 changes: 14 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from setuptools import setup

setup(name='fab-polish',
version='1.0.0',
description='Polish git versioned source code using Fabric',
url='https://github.com/practo/FabPolish',
author='J Kishore Kumar',
author_email='kishore@practo.com',
license='MIT',
packages=['fabpolish'],
install_requires=[
'fabric',
],
zip_safe=False)

0 comments on commit 92e15ee

Please sign in to comment.