Compare commits

...

34 commits

Author SHA1 Message Date
Camilo Nova
5a8531f82f
Merge pull request #31 from jazzband/jazzband/sync/default
Jazzband: Synced file(s) with jazzband/.github
2021-10-21 14:26:15 -05:00
jazzband-bot
0ddc447852 Jazzband: Created local 'CODE_OF_CONDUCT.md' from remote 'CODE_OF_CONDUCT.md' 2021-10-21 14:34:50 +00:00
Jannis Leidel
a1d5b7a844
Merge pull request #30 from jazzband/master-to-main
Rename Django's dev branch to main.
2021-03-09 13:33:58 +01:00
Jannis Leidel
9fcf06e85d
Rename Django's dev branch to main.
More information: https://groups.google.com/g/django-developers/c/tctDuKUGosc/
Refs: https://github.com/django/django/pull/14048
2021-03-09 13:33:38 +01:00
Camilo Nova
c0c859dfdd Merge pull request #29 from theatlantic/coverage-get-data
Add support for coverage 4.0.
2016-07-21 17:40:01 -05:00
Chris Barna
a858d0ab5a Add support for coverage 4.0.
* coverage._harvest_data() was renamed to coverage.get_data()
2016-07-21 15:05:08 -04:00
Camilo Nova
5037a98c1c Merge pull request #28 from adamchainz/readthedocs.io
Convert readthedocs links for their .org -> .io migration for hosted projects
2016-06-11 09:43:17 -05:00
Adam Chainz
03cb91ee03 Convert readthedocs links for their .org -> .io migration for hosted projects
As per [their blog post of the 27th April](https://blog.readthedocs.com/securing-subdomains/) ‘Securing subdomains’:

> Starting today, Read the Docs will start hosting projects from subdomains on the domain readthedocs.io, instead of on readthedocs.org. This change addresses some security concerns around site cookies while hosting user generated data on the same domain as our dashboard.

Test Plan: Manually visited all the links I’ve modified.
2016-06-11 10:58:46 +01:00
Simon Charette
ac32a48c60 Made CI install a version of virtualenv compatible with Python 3.2. 2016-02-03 22:07:09 -05:00
Simon Charette
f72e23da19 Merge pull request #26 from pinnokio/fix_dump_xml_in_results
Fix total_seconds invocation in dump_xml
2016-02-03 22:04:02 -05:00
Konstantin Lazarenko
61345906c7 Fix total_seconds invocation in dump_xml 2016-02-03 16:52:20 +02:00
Simon Charette
960dcfc1ad Updated the package classifiers. 2016-01-08 23:52:06 -05:00
Simon Charette
3376c56170 Added the TravisCI badge to the README. 2016-01-08 23:49:56 -05:00
Simon Charette
67829eb216 Added isort to CI. 2016-01-08 23:29:22 -05:00
Simon Charette
ea2b0d4464 Only install mock on version of Python not shipping it. 2016-01-08 23:16:19 -05:00
Simon Charette
05cc5c03b0 Added flake8 to CI. 2016-01-08 23:13:34 -05:00
Simon Charette
0842090e22 Adjusted TOX requirements on Python 3.2. 2016-01-08 22:59:33 -05:00
Simon Charette
8ac8db8d52 Removed support code for Django < 1.7. 2016-01-08 22:59:33 -05:00
Simon Charette
060a4344de Removed an unecessary requirements file. 2016-01-08 22:59:33 -05:00
Simon Charette
18796e1d78 Removed unused support code for Python 2.6. 2016-01-08 22:59:33 -05:00
Camilo Nova
3f37a73437 Merge pull request #24 from charettes/ci
Added CI
2016-01-08 08:47:39 -05:00
Simon Charette
65dbdd83c6 Added a TravisCI configuration file. 2016-01-08 01:58:49 -05:00
Simon Charette
cc6b2315f5 Made the required changes to make the tests pass on all supported Django versions. 2016-01-08 01:58:49 -05:00
Simon Charette
f0786c590b Added a TOX configuration to run CI against all supported Django versions. 2016-01-08 01:41:51 -05:00
Camilo Nova
b0757dc508 Update and rename README.rst to README.md 2016-01-07 16:38:32 -05:00
Camilo Nova
fab998bed3 Create CONTRIBUTING.md 2016-01-07 16:35:42 -05:00
Camilo Nova
a006230dcd Update README.rst 2016-01-07 11:57:39 -05:00
Camilo Nova
16016e8ac9 Update and rename README.md to README.rst 2016-01-07 11:56:35 -05:00
Camilo Nova
43443d0afc Added to jazzband 2016-01-07 11:54:48 -05:00
Camilo Nova
caab2ba679 Improved release docs 2016-01-07 08:16:39 -05:00
Camilo Nova
85583fe7ff Release 0.1.4 2016-01-07 08:13:37 -05:00
Camilo Nova
9495bd9fe6 Merge pull request #22 from theatlantic/django-18-compat
Make compatible with Django 1.8
2016-01-06 17:06:52 -05:00
Frankie Dintino
9f88b9f1fa Make compatible with Django 1.8
In Django 1.8, DiscoverRunner.option_list is replaced with the classmethod
DiscoverRunner.add_arguments()
2015-08-19 16:20:50 -04:00
Camilo Nova
3202fc742b Added developer instructions 2015-01-22 16:33:50 -05:00
24 changed files with 524 additions and 273 deletions

38
.travis.yml Normal file
View file

@ -0,0 +1,38 @@
sudo: no
language: python
env:
- TOXENV=flake8
- TOXENV=isort
- TOXENV=py27-1.7
- TOXENV=py27-1.8
- TOXENV=py27-1.9
- TOXENV=py27-main
- TOXENV=py32-1.7
- TOXENV=py32-1.8
- TOXENV=py33-1.7
- TOXENV=py33-1.8
- TOXENV=py34-1.7
- TOXENV=py34-1.8
- TOXENV=py34-1.9
- TOXENV=py34-main
matrix:
include:
- python: 3.5
env: TOXENV=py35-1.8
- python: 3.5
env: TOXENV=py35-1.9
- python: 3.5
env: TOXENV=py35-main
allow_failures:
- env: TOXENV=py27-main
- env: TOXENV=py34-main
- env: TOXENV=py35-main
install:
- pip install tox "virtualenv<14.0"
script:
- tox

46
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,46 @@
# Code of Conduct
As contributors and maintainers of the Jazzband projects, and in the interest of
fostering an open and welcoming community, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating documentation,
submitting pull requests or patches, and other activities.
We are committed to making participation in the Jazzband a harassment-free experience
for everyone, regardless of the level of experience, gender, gender identity and
expression, sexual orientation, disability, personal appearance, body size, race,
ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery
- Personal attacks
- Trolling or insulting/derogatory comments
- Public or private harassment
- Publishing other's private information, such as physical or electronic addresses,
without explicit permission
- Other unethical or unprofessional conduct
The Jazzband roadies have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are not
aligned to this Code of Conduct, or to ban temporarily or permanently any contributor
for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
By adopting this Code of Conduct, the roadies commit themselves to fairly and
consistently applying these principles to every aspect of managing the jazzband
projects. Roadies who do not follow or enforce the Code of Conduct may be permanently
removed from the Jazzband roadies.
This code of conduct applies both within project spaces and in public spaces when an
individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
contacting the roadies at `roadies@jazzband.co`. All complaints will be reviewed and
investigated and will result in a response that is deemed necessary and appropriate to
the circumstances. Roadies are obligated to maintain confidentiality with regard to the
reporter of an incident.
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version
1.3.0, available at [https://contributor-covenant.org/version/1/3/0/][version]
[homepage]: https://contributor-covenant.org
[version]: https://contributor-covenant.org/version/1/3/0/

3
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,3 @@
[![Jazzband](https://jazzband.co/static/img/jazzband.svg)](https://jazzband.co/)
This is a [Jazzband](https://jazzband.co/) project. By contributing you agree to abide by the [Contributor Code of Conduct](https://jazzband.co/docs/conduct) and follow the [guidelines](https://jazzband.co/docs/guidelines).

19
DEVEL.md Normal file
View file

@ -0,0 +1,19 @@
Developer instructions
======================
Here you can find some instructions when developing for this package.
Release a new version
---------------------
When you are ready to release a new version you need to follow these steps.
For example version 1.0.3:
1. Change the version number at ```discover_jenkins/__init__.py```
2. Commit ```git commit -m "Release 1.0.3"```
3. Tag ```git tag 1.0.3```
4. Push changes ```git push origin master```
5. Push tags ```git push --tags```
6. Upload release to Pypi ```python setup.py sdist upload```
7. Dance!

View file

@ -1,18 +1,20 @@
django-discover-jenkins
=======================
[![Downloads](https://pypip.in/v/django-discover-jenkins/badge.png)](https://crate.io/packages/django-discover-jenkins) [![Build Status](https://drone.io/github.com/lincolnloop/django-discover-jenkins/status.png)](https://drone.io/github.com/lincolnloop/django-discover-jenkins/latest) [![PyPi Downloads](https://pypip.in/d/django-discover-jenkins/badge.png)](https://crate.io/packages/django-discover-jenkins/)
[![Build Status](https://travis-ci.org/jazzband/django-discover-jenkins.svg?branch=master)](https://travis-ci.org/jazzband/django-discover-jenkins)
[![Jazzband](https://jazzband.co/static/img/badge.svg)](https://jazzband.co/)
A streamlined fork of django-jenkins designed to work with the default test command and the discover runner.
[Read the Docs](https://django-discover-jenkins.readthedocs.org/)
[Read the Docs](https://django-discover-jenkins.readthedocs.io/)
Why?
----
The overall goal is to run tests on Jenkins the same way you do on your local machine. This project is designed to take advantage of [django-discover-runner](https://github.com/jezdez/django-discover-runner/), which is the default test runner in Django 1.6. Instead of using a setting to list which apps should be tested, or accepting Django-specific test labels, it uses the official test discovery feature of the new unittest2.
The overall goal is to run tests on Jenkins the same way you do on your local machine. This project is designed to take advantage of https://github.com/jezdez/django-discover-runner/, which is the default test runner in Django 1.6. Instead of using a setting to list which apps should be tested, or accepting Django-specific test labels, it uses the official test discovery feature of the new unittest2.
Also, the original [django-jenkins](https://github.com/kmmbvnr/django-jenkins) project doesn't take advantage of improvements to testing introduced in Django 1.4. Special management commands are no longer needed, as test runners themselves can add options that are handled by the built-in `test` command.
Also, the original https://github.com/kmmbvnr/django-jenkins project doesn't take advantage of improvements to testing introduced in Django 1.4. Special management commands are no longer needed, as test runners themselves can add options that are handled by the built-in `test` command.
What's Changed?
@ -22,10 +24,3 @@ What's Changed?
* **No management commands are provided.** Since Django 1.4, the built in 'test' command has allowed the test runner to define additional options that the management command will accept.
* **It doesn't use signals.** Instead of using the event/callback style of signals and using `inspect.getmembers` to connect everything, the test runner simply checks for key methods on each task the same way Django's request handler checks for methods on middleware.
* **Not everything works yet.** Only a subset of the django-jenkins tasks have been ported at this point. I'd love to accept your pull requests to add more of them.
Who?
----
First and foremost, the authors of [django-jenkins](https://github.com/kmmbvnr/django-jenkins) are responsible for the basis of most of this code. I ([Brandon Konkle](https://github.com/bkonkle)) just took it apart and put it back together again in a different way, then fixed or reworked some things. Thank you to the contributors of that project!
For the full list of original authors and for the contributors to this project, see the AUTHORS.md file.

View file

@ -1,3 +1,3 @@
__author__ = 'Brandon Konkle'
__version__ = '0.1.3'
__version__ = '0.1.4'

View file

@ -2,15 +2,11 @@ import os
import traceback
from datetime import datetime
from itertools import groupby
from unittest import TextTestResult
from xml.sax.saxutils import XMLGenerator
from xml.sax.xmlreader import AttributesImpl
from django.utils.unittest import TextTestResult
from discover_jenkins.utils import total_seconds
try:
from django.utils.encoding import smart_text
except ImportError:
from django.utils.encoding import smart_unicode as smart_text
from django.utils.encoding import smart_text
STDOUT_LINE = '\nStdout:\n%s'
STDERR_LINE = '\nStderr:\n%s'
@ -176,9 +172,9 @@ class XMLTestResult(TextTestResult):
document.startDocument()
document.startElement('testsuites', AttributesImpl({}))
suites = groupby(self.testInfos,
key=lambda test_info: self.test_case_name(
test_info.test_method))
suites = groupby(
self.testInfos, key=lambda test_info: self.test_case_name(test_info.test_method)
)
for suite_name, suite in suites:
document.startElement('testsuite',
AttributesImpl({'name': suite_name}))
@ -187,26 +183,26 @@ class XMLTestResult(TextTestResult):
document.startElement('testcase', AttributesImpl({
'classname': suite_name,
'name': self.test_method_name(test_info.test_method),
'time': '%3f' % total_seconds(
test_info.end_time - test_info.start_time)
'time': '%3f' % (
test_info.end_time - test_info.start_time
).total_seconds()
}))
if test_info.result == TestInfo.RESULT.ERROR:
document.startElement('error', AttributesImpl({
'message': smart_text(test_info.err[1])
}))
document.characters(self._exc_info_to_string(
test_info.err, test_info.test_method))
document.characters(self._exc_info_to_string(test_info.err, test_info.test_method))
document.endElement('error')
elif test_info.result == TestInfo.RESULT.FAILURE:
document.startElement('failure', AttributesImpl({
'message': smart_text(test_info.err[1])
}))
document.characters(self._exc_info_to_string(
test_info.err, test_info.test_method).decode('utf-8'))
document.characters(
self._exc_info_to_string(test_info.err, test_info.test_method).decode('utf-8')
)
document.endElement('failure')
elif test_info.result == \
TestInfo.RESULT.UNEXPECTED_SUCCESS:
elif test_info.result == TestInfo.RESULT.UNEXPECTED_SUCCESS:
document.startElement('error', AttributesImpl({
'message': 'Unexpected success'
}))

View file

@ -1,20 +1,13 @@
import inspect
import unittest
from importlib import import_module
from optparse import make_option
import django
from django.core.exceptions import ImproperlyConfigured
from django.utils import unittest
from django.utils.importlib import import_module
try:
# Django 1.6
from django.test.runner import DiscoverRunner
except ImportError:
# Fallback to third-party app on Django 1.5
from discover_runner.runner import DiscoverRunner
from django.test.runner import DiscoverRunner
from .results import XMLTestResult
from .settings import TASKS, OUTPUT_DIR
from .settings import OUTPUT_DIR, TASKS
def get_tasks():
@ -55,22 +48,23 @@ class CIRunner(object):
A Django test runner mixin that runs tasks for Jenkins and dumps the
results to an XML file.
"""
option_list = get_task_options() + (
make_option(
'--jenkins',
action='store_true',
dest='jenkins',
default=False,
help='Process the Jenkins tasks from TEST_JENKINS_TASKS.'
),
make_option(
'--output-dir',
action='store',
dest='output_dir',
default=OUTPUT_DIR,
help='Top level of project for unittest discovery.'
),
)
if django.VERSION < (1, 8):
option_list = get_task_options() + (
make_option(
'--jenkins',
action='store_true',
dest='jenkins',
default=False,
help='Process the Jenkins tasks from TEST_JENKINS_TASKS.'
),
make_option(
'--output-dir',
action='store',
dest='output_dir',
default=OUTPUT_DIR,
help='Top level of project for unittest discovery.'
),
)
def __init__(self, jenkins=False, output_dir=None, **options):
super(CIRunner, self).__init__(**options)
@ -88,6 +82,20 @@ class CIRunner(object):
instance = task_class(output_dir=output_dir, **options)
self.tasks.append(instance)
@classmethod
def add_arguments(cls, parser):
task_classes = get_tasks()
for task_cls in task_classes:
if hasattr(task_cls, 'add_arguments'):
task_cls.add_arguments(parser)
parser.add_argument('--jenkins',
action='store_true', dest='jenkins', default=False,
help='Process the Jenkins tasks from TEST_JENKINS_TASKS.')
parser.add_argument('--output-dir',
action='store', dest='output_dir', default=OUTPUT_DIR,
help='Top level of project for unittest discovery.')
def setup_test_environment(self, **kwargs):
super(CIRunner, self).setup_test_environment(**kwargs)
if self.jenkins:
@ -130,4 +138,11 @@ class CIRunner(object):
class DiscoverCIRunner(CIRunner, DiscoverRunner):
"""The CIRunner mixin applied to the discover runner"""
option_list = DiscoverRunner.option_list + CIRunner.option_list
if django.VERSION < (1, 8):
option_list = DiscoverRunner.option_list + CIRunner.option_list
@classmethod
def add_arguments(cls, parser):
DiscoverRunner.add_arguments(parser)
CIRunner.add_arguments(parser)

View file

@ -1,6 +1,5 @@
from django.conf import settings
TASKS = getattr(settings, 'TEST_TASKS', (
'discover_jenkins.tasks.run_pylint.PyLintTask',
'discover_jenkins.tasks.with_coverage.CoverageTask',

View file

@ -1,21 +1,26 @@
# coding: utf-8
import os
import sys
from optparse import make_option
import django
import pep8
from flake8.engine import get_style_guide
from optparse import make_option
from discover_jenkins.tasks.run_pep8 import Pep8Task
from discover_jenkins.utils import get_app_locations
from ..utils import get_app_locations
from .run_pep8 import Pep8Task
class Flake8Task(Pep8Task):
option_list = Pep8Task.option_list + (
make_option(
'--max-complexity',
dest='max_complexity',
help='McCabe complexity threshold',
),
)
if django.VERSION < (1, 8):
option_list = Pep8Task.option_list + (
make_option(
'--max-complexity',
dest='max_complexity',
help='McCabe complexity threshold',
),
)
def __init__(self, **options):
super(Flake8Task, self).__init__(**options)
@ -31,6 +36,13 @@ class Flake8Task(Pep8Task):
if options['max_complexity']:
self.pep8_options['max_complexity'] = int(options['max_complexity'])
@classmethod
def add_arguments(cls, parser):
Pep8Task.add_arguments(parser)
parser.add_argument('--max-complexity',
dest='max_complexity',
help='McCabe complexity threshold')
def teardown_test_environment(self, **kwargs):
class JenkinsReport(pep8.BaseReport):
def error(instance, line_number, offset, text, check):

View file

@ -1,53 +1,56 @@
# -*- coding: utf-8 -*-
import os
import sys
import codecs
import fnmatch
import os
import subprocess
import sys
from optparse import make_option
import django
from django.conf import settings as django_settings
from ..settings import JSHINT_CHECKED_FILES, JSHINT_EXCLUDE, JSHINT_RCFILE
from ..utils import CalledProcessError, get_app_locations
from ..settings import JSHINT_CHECKED_FILES, JSHINT_RCFILE, JSHINT_EXCLUDE
class JSHintTask(object):
option_list = (
make_option(
"--jshint-no-staticdirs",
dest="jshint-no-staticdirs",
default=False,
action="store_true",
help="Don't check js files located in STATICFILES_DIRS settings"
),
make_option(
"--jshint-with-minjs",
dest="jshint_with-minjs",
default=False,
action="store_true",
help="Do not ignore .min.js files"
),
make_option(
"--jshint-exclude",
dest="jshint_exclude",
default=JSHINT_EXCLUDE,
help="Exclude patterns"
),
make_option(
'--jshint-stdout',
action='store_true',
dest='jshint_stdout',
default=False,
help='Print the jshint output instead of storing it in a file'
),
make_option(
'--jshint-rcfile',
dest='jshint_rcfile',
default=JSHINT_RCFILE,
help='Provide an rcfile for jshint'
),
)
if django.VERSION < (1, 8):
option_list = (
make_option(
"--jshint-no-staticdirs",
dest="jshint-no-staticdirs",
default=False,
action="store_true",
help="Don't check js files located in STATICFILES_DIRS settings"
),
make_option(
"--jshint-with-minjs",
dest="jshint_with-minjs",
default=False,
action="store_true",
help="Do not ignore .min.js files"
),
make_option(
"--jshint-exclude",
dest="jshint_exclude",
default=JSHINT_EXCLUDE,
help="Exclude patterns"
),
make_option(
'--jshint-stdout',
action='store_true',
dest='jshint_stdout',
default=False,
help='Print the jshint output instead of storing it in a file'
),
make_option(
'--jshint-rcfile',
dest='jshint_rcfile',
default=JSHINT_RCFILE,
help='Provide an rcfile for jshint'
),
)
def __init__(self, **options):
self.to_stdout = options['jshint_stdout']
@ -68,6 +71,24 @@ class JSHintTask(object):
if isinstance(self.exclude, str):
self.exclude = self.exclude.split(',')
@classmethod
def add_arguments(cls, parser):
parser.add_argument("--jshint-no-staticdirs",
dest="jshint-no-staticdirs", default=False, action="store_true",
help="Don't check js files located in STATICFILES_DIRS settings")
parser.add_argument("--jshint-with-minjs",
dest="jshint_with-minjs", default=False, action="store_true",
help="Do not ignore .min.js files")
parser.add_argument("--jshint-exclude",
dest="jshint_exclude", default=JSHINT_EXCLUDE,
help="Exclude patterns")
parser.add_argument('--jshint-stdout',
action='store_true', dest='jshint_stdout', default=False,
help='Print the jshint output instead of storing it in a file')
parser.add_argument('--jshint-rcfile',
dest='jshint_rcfile', default=JSHINT_RCFILE,
help='Provide an rcfile for jshint')
def teardown_test_environment(self, **kwargs):
files = [path for path in self.static_files_iterator()]

View file

@ -1,41 +1,46 @@
# -*- coding: utf-8 -*-
import os
import sys
import pep8
from optparse import make_option
import django
import pep8
from django.conf import settings
from discover_jenkins.utils import check_output, get_app_locations
from ..utils import get_app_locations
class Pep8Task(object):
option_list = (
make_option(
"--pep8-exclude",
dest="pep8-exclude",
default=pep8.DEFAULT_EXCLUDE + ",migrations",
help="exclude files or directories which match these "
"comma separated patterns (default: %s)" %
pep8.DEFAULT_EXCLUDE
),
make_option(
"--pep8-select", dest="pep8-select",
help="select errors and warnings (e.g. E,W6)",
),
make_option(
"--pep8-ignore", dest="pep8-ignore",
help="skip errors and warnings (e.g. E4,W)",
),
make_option(
"--pep8-max-line-length",
dest="pep8-max-line-length", type='int',
help="set maximum allowed line length (default: %d)" %
pep8.MAX_LINE_LENGTH
),
make_option(
"--pep8-rcfile", dest="pep8-rcfile",
help="PEP8 configuration file"
),
)
if django.VERSION < (1, 8):
option_list = (
make_option(
"--pep8-exclude",
dest="pep8-exclude",
default=pep8.DEFAULT_EXCLUDE + ",migrations",
help="exclude files or directories which match these "
"comma separated patterns (default: %s)" %
pep8.DEFAULT_EXCLUDE
),
make_option(
"--pep8-select", dest="pep8-select",
help="select errors and warnings (e.g. E,W6)",
),
make_option(
"--pep8-ignore", dest="pep8-ignore",
help="skip errors and warnings (e.g. E4,W)",
),
make_option(
"--pep8-max-line-length",
dest="pep8-max-line-length", type='int',
help="set maximum allowed line length (default: %d)" %
pep8.MAX_LINE_LENGTH
),
make_option(
"--pep8-rcfile", dest="pep8-rcfile",
help="PEP8 configuration file"
),
)
def __init__(self, **options):
if options.get('pep8_file_output', True):
@ -53,8 +58,26 @@ class Pep8Task(object):
if options['pep8-ignore']:
self.pep8_options['ignore'] = options['pep8-ignore'].split(',')
if options['pep8-max-line-length']:
self.pep8_options['max_line_length'] = \
options['pep8-max-line-length']
self.pep8_options['max_line_length'] = options['pep8-max-line-length']
@classmethod
def add_arguments(cls, parser):
parser.add_argument("--pep8-exclude",
dest="pep8-exclude",
default=pep8.DEFAULT_EXCLUDE + ",migrations",
help="exclude files or directories which match these "
"comma separated patterns (default: %s)" %
pep8.DEFAULT_EXCLUDE)
parser.add_argument("--pep8-select", dest="pep8-select",
help="select errors and warnings (e.g. E,W6)")
parser.add_argument("--pep8-ignore", dest="pep8-ignore",
help="skip errors and warnings (e.g. E4,W)")
parser.add_argument("--pep8-max-line-length",
dest="pep8-max-line-length", type=int,
help="set maximum allowed line length (default: %d)" %
pep8.MAX_LINE_LENGTH)
parser.add_argument("--pep8-rcfile", dest="pep8-rcfile",
help="PEP8 configuration file")
def teardown_test_environment(self, **kwargs):
locations = get_app_locations()

View file

@ -4,10 +4,11 @@ import os
import sys
from optparse import make_option
import django
from pylint import lint
from pylint.reporters.text import ParseableTextReporter
from ..settings import PYLINT_RCFILE, PROJECT_APPS
from ..settings import PROJECT_APPS, PYLINT_RCFILE
def default_config_path():
@ -21,21 +22,23 @@ def default_config_path():
class PyLintTask(object):
option_list = (
make_option(
"--pylint-rcfile",
dest="pylint_rcfile",
default=None,
help="pylint configuration file"
),
make_option(
"--pylint-errors-only",
dest="pylint_errors_only",
action="store_true",
default=False,
help="pylint output errors only mode"
),
)
if django.VERSION < (1, 8):
option_list = (
make_option(
"--pylint-rcfile",
dest="pylint_rcfile",
default=None,
help="pylint configuration file"
),
make_option(
"--pylint-errors-only",
dest="pylint_errors_only",
action="store_true",
default=False,
help="pylint output errors only mode"
),
)
def __init__(self, **options):
self.config_path = options['pylint_rcfile'] or default_config_path()
@ -49,6 +52,15 @@ class PyLintTask(object):
else:
self.output = sys.stdout
@classmethod
def add_arguments(cls, parser):
parser.add_argument("--pylint-rcfile",
dest="pylint_rcfile", default=None,
help="pylint configuration file")
parser.add_argument("--pylint-errors-only",
dest="pylint_errors_only", action="store_true", default=False,
help="pylint output errors only mode")
def teardown_test_environment(self, **kwargs):
if PROJECT_APPS:
args = ["--rcfile=%s" % self.config_path]

View file

@ -1,28 +1,33 @@
# -*- coding: utf-8 -*-
import os
import subprocess
import sys
from optparse import make_option
from discover_jenkins.utils import check_output, get_app_locations
import django
from ..utils import get_app_locations
class SlocCountTask(object):
option_list = (
make_option(
"--sloccount-with-migrations",
action="store_true",
default=False,
dest="sloccount_with_migrations",
help="Count migrations sloc."
),
make_option(
'--sloccount-stdout',
action='store_true',
dest='sloccount_stdout',
default=False,
help='Print the sloccount totals instead of saving them to a file'
),
)
if django.VERSION < (1, 8):
option_list = (
make_option(
"--sloccount-with-migrations",
action="store_true",
default=False,
dest="sloccount_with_migrations",
help="Count migrations sloc."
),
make_option(
'--sloccount-stdout',
action='store_true',
dest='sloccount_stdout',
default=False,
help='Print the sloccount totals instead of saving them to a file'
),
)
def __init__(self, **options):
self.with_migrations = options['sloccount_with_migrations']
@ -36,10 +41,19 @@ class SlocCountTask(object):
self.output = open(os.path.join(output_dir,
'sloccount.report'), 'w')
@classmethod
def add_arguments(cls, parser):
parser.add_argument("--sloccount-with-migrations",
action="store_true", default=False, dest="sloccount_with_migrations",
help="Count migrations sloc.")
parser.add_argument("--sloccount-stdout",
action="store_true", dest="sloccount_stdout", default=False,
help="Print the sloccount totals instead of saving them to a file")
def teardown_test_environment(self, **kwargs):
locations = get_app_locations()
report_output = check_output(
report_output = subprocess.check_output(
['sloccount', "--duplicates", "--wide", "--details"] + locations
)
report_output = report_output.decode('utf-8')

View file

@ -3,10 +3,15 @@
import os
from optparse import make_option
from coverage.control import coverage
import django
from .. import settings
try:
from coverage import coverage
except ImportError:
from coverage.control import coverage
def default_config_path():
rcfile = settings.COVERAGE_RCFILE
@ -16,42 +21,44 @@ def default_config_path():
class CoverageTask(object):
option_list = (
make_option(
"--coverage-rcfile",
dest="coverage_rcfile",
default="",
help="Specify configuration file."
),
make_option(
"--coverage-html-report",
dest="coverage_html_report_dir",
default=settings.COVERAGE_REPORT_HTML_DIR,
help="Directory to which HTML coverage report should be"
" written. If not specified, no report is generated."
),
make_option(
"--coverage-no-branch-measure",
action="store_false",
default=settings.COVERAGE_MEASURE_BRANCH,
dest="coverage_measure_branch",
help="Don't measure branch coverage."
),
make_option(
"--coverage-with-migrations",
action="store_true",
default=settings.COVERAGE_WITH_MIGRATIONS,
dest="coverage_with_migrations",
help="Don't measure migrations coverage."
),
make_option(
"--coverage-exclude",
action="append",
default=settings.COVERAGE_EXCLUDE_PATHS,
dest="coverage_excludes",
help="Paths to be excluded from coverage"
if django.VERSION < (1, 8):
option_list = (
make_option(
"--coverage-rcfile",
dest="coverage_rcfile",
default="",
help="Specify configuration file."
),
make_option(
"--coverage-html-report",
dest="coverage_html_report_dir",
default=settings.COVERAGE_REPORT_HTML_DIR,
help="Directory to which HTML coverage report should be"
" written. If not specified, no report is generated."
),
make_option(
"--coverage-no-branch-measure",
action="store_false",
default=settings.COVERAGE_MEASURE_BRANCH,
dest="coverage_measure_branch",
help="Don't measure branch coverage."
),
make_option(
"--coverage-with-migrations",
action="store_true",
default=settings.COVERAGE_WITH_MIGRATIONS,
dest="coverage_with_migrations",
help="Don't measure migrations coverage."
),
make_option(
"--coverage-exclude",
action="append",
default=settings.COVERAGE_EXCLUDE_PATHS,
dest="coverage_excludes",
help="Paths to be excluded from coverage"
)
)
)
def __init__(self, **options):
self.output_dir = options['output_dir']
@ -68,12 +75,40 @@ class CoverageTask(object):
config_file=options.get('coverage_rcfile') or default_config_path()
)
@classmethod
def add_arguments(cls, parser):
parser.add_argument("--coverage-rcfile",
dest="coverage_rcfile", default="",
help="Specify configuration file.")
parser.add_argument("--coverage-html-report",
dest="coverage_html_report_dir", default=settings.COVERAGE_REPORT_HTML_DIR,
help="Directory to which HTML coverage report should be"
" written. If not specified, no report is generated.")
parser.add_argument("--coverage-no-branch-measure",
action="store_false", default=settings.COVERAGE_MEASURE_BRANCH,
dest="coverage_measure_branch",
help="Don't measure branch coverage.")
parser.add_argument("--coverage-with-migrations",
action="store_true", default=settings.COVERAGE_WITH_MIGRATIONS,
dest="coverage_with_migrations",
help="Don't measure migrations coverage.")
parser.add_argument("--coverage-exclude",
action="append", default=settings.COVERAGE_EXCLUDE_PATHS,
dest="coverage_excludes",
help="Paths to be excluded from coverage")
def setup_test_environment(self, **kwargs):
self.coverage.start()
def teardown_test_environment(self, **kwargs):
self.coverage.stop()
self.coverage._harvest_data()
try:
self.coverage._harvest_data()
except AttributeError:
# coverage._harvest_data was renamed to coverage.get_data in
# coverage.py 4.0.
self.coverage.get_data()
morfs = [filename for filename in self.coverage.data.measured_files()
if self.want_file(filename)]

View file

@ -1,7 +1,6 @@
import os.path
import subprocess
from django.utils.importlib import import_module
from importlib import import_module
from discover_jenkins.settings import PROJECT_APPS
@ -16,28 +15,6 @@ class CalledProcessError(subprocess.CalledProcessError):
% (self.cmd, self.returncode, self.output))
def check_output(*popenargs, **kwargs):
"""
Backport from Python2.7
"""
if getattr(subprocess, 'check_output', None) is None:
if 'stdout' in kwargs or 'stderr' in kwargs:
raise ValueError('stdout or stderr argument not allowed, '
'it will be overridden.')
process = subprocess.Popen(stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
*popenargs, **kwargs)
output, err = process.communicate()
retcode = process.poll()
if retcode:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
raise CalledProcessError(retcode, cmd, output=output + '\n' + err)
return output
return subprocess.check_output(*popenargs, **kwargs)
def find_first_existing_executable(exe_list):
"""
Accepts list of [('executable_file_path', 'options')],
@ -55,15 +32,6 @@ def find_first_existing_executable(exe_list):
return filepath
def total_seconds(delta):
"""
Backport timedelta.total_seconds() from Python 2.7
"""
if getattr(delta, 'total_seconds', None) is None:
return delta.days * 86400.0 + delta.seconds + delta.microseconds * 1e-6
return delta.total_seconds()
def get_app_locations():
"""
Returns list of paths to tested apps

View file

@ -1,2 +1,13 @@
[flake8]
ignore = E123,E128,E402,W503,E731,W601
max-line-length = 119
exclude = docs,tests/test_project/test_app/migrations/*
[isort]
combine_as_imports=true
include_trailing_comma=true
multi_line_output=5
not_skip=__init__.py
[wheel]
universal = 1

View file

@ -46,10 +46,19 @@ setup(
"Development Status :: 3 - Alpha",
"Environment :: Web Environment",
"Framework :: Django",
"Framework :: Django :: 1.7",
"Framework :: Django :: 1.8",
"Framework :: Django :: 1.9",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: JavaScript",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.2",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
"Topic :: Software Development :: Libraries :: Python Modules",

View file

@ -1,6 +0,0 @@
django>=1.5
pylint>=0.23
coverage>=3.4
mock>=1.0.1
django-discover-runner>=1.0
flake8>=2.1.0

View file

@ -1,4 +1,5 @@
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
DEBUG = True
@ -47,9 +48,9 @@ LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {

View file

@ -1,9 +1,5 @@
from south.v2 import SchemaMigration
from django.db import migrations
class Migration(SchemaMigration):
def forwards(self, orm):
a = 1 # pyflakes/pylint violation
pass
def backwards(self, orm):
pass
class Migration(migrations.Migration):
a = 1 # pyflakes/pylint violation

View file

@ -1,7 +1,13 @@
from mock import MagicMock, patch
from unittest import skipIf
import django
from discover_jenkins import runner, tasks
from django.test import TestCase
from discover_jenkins import runner, tasks
try:
from unittest.mock import MagicMock, patch
except ImportError:
from mock import MagicMock, patch
class FakeTestRunner(object):
@ -24,7 +30,6 @@ class Runner(runner.CIRunner, FakeTestRunner):
class TestCIRunner(TestCase):
def test_get_tasks(self):
"""
Make sure the correct tasks are imported based on the
@ -37,6 +42,7 @@ class TestCIRunner(TestCase):
tasks.run_jshint.JSHintTask,
tasks.run_sloccount.SlocCountTask])
@skipIf(django.VERSION >= (1, 8), "optparse is not used on Django 1.8+")
def test_get_task_options(self):
"""
For now, just do a simple test to make sure the right number of options
@ -73,4 +79,3 @@ class TestCIRunner(TestCase):
cirun.teardown_test_environment()
self.assertTrue(mock_task.teardown_test_environment.called)

View file

@ -1,21 +1,12 @@
import os
from datetime import timedelta
from django.test import TestCase
import discover_jenkins
import test_project
from django.test import TestCase
class TestUtils(TestCase):
def test_total_seconds(self):
"""
The total_seconds util should show that 5 minutes is 300 seconds.
"""
delta = timedelta(minutes=5)
self.assertEqual(discover_jenkins.utils.total_seconds(delta), 300)
def test_app_locations(self):
"""
The app locations should come from the test_project settings.

48
tox.ini Normal file
View file

@ -0,0 +1,48 @@
[tox]
args_are_paths = false
envlist =
flake8,
isort,
py27-{1.7,1.8,1.9,main},
py32-{1.7,1.8},
py33-{1.7,1.8},
py34-{1.7,1.8,1.9,main},
py35-{1.8,1.9,main}
[testenv]
basepython =
py27: python2.7
py32: python3.2
py33: python3.3
py34: python3.4
py35: python3.5
usedevelop = true
setenv =
PYTHONPATH=tests
commands =
{envbindir}/python -Wonce tests/manage.py test tests
deps =
py32: coverage>=3.4,<4.0
{py27,py33,py34,py35}: coverage>=4.0
flake8>=2.1.0
{py27,py32}: mock>=1.0.1
py32: astroid==1.2
py32: logilab-common==0.62
py32: pylint==1.3
{py27,py33,py34,py35}: pylint>=0.23
1.7: Django>=1.7,<1.8
1.8: Django>=1.8,<1.9
1.9: Django>=1.9,<1.10
main: https://github.com/django/django/archive/main.tar.gz
[testenv:flake8]
basepython = python2.7
commands =
flake8
[testenv:isort]
basepython = python2.7
commands =
isort --recursive --check-only --diff discover_jenkins tests
deps =
isort