Browse Source

Init project

This commit includes everything that is required to beging work on project:

- Sets up tox
- Sets up unit/pep/coverage/doc jobs
- Introduce doc structure
- Adds entry point
- Adds tests directory
- Adds extra hacking rules
- Add test and project requirements
Boris Pavlovic 4 years ago
parent
commit
32605d6fe3

+ 6
- 0
.coveragerc View File

@@ -0,0 +1,6 @@
1
+[run]
2
+branch = True
3
+source = nerd-reviewer
4
+
5
+[report]
6
+ignore-errors = True

+ 26
- 37
.gitignore View File

@@ -1,54 +1,43 @@
1
-# Byte-compiled / optimized / DLL files
2
-__pycache__/
3 1
 *.py[cod]
4 2
 
5 3
 # C extensions
6 4
 *.so
7 5
 
8
-# Distribution / packaging
9
-.Python
10
-env/
11
-build/
12
-develop-eggs/
13
-dist/
14
-downloads/
15
-eggs/
16
-lib/
17
-lib64/
18
-parts/
19
-sdist/
20
-var/
21
-*.egg-info/
22
-.installed.cfg
6
+# Packages
23 7
 *.egg
24
-
25
-# PyInstaller
26
-#  Usually these files are written by a python script from a template
27
-#  before PyInstaller builds the exe, so as to inject date/other infos into it.
28
-*.manifest
29
-*.spec
8
+*.egg-info
9
+dist
10
+build
11
+eggs
12
+parts
13
+bin
14
+var
15
+sdist
16
+develop-eggs
17
+.installed.cfg
18
+lib
19
+lib64
30 20
 
31 21
 # Installer logs
32 22
 pip-log.txt
33
-pip-delete-this-directory.txt
34 23
 
35 24
 # Unit test / coverage reports
36
-htmlcov/
37
-.tox/
38 25
 .coverage
39
-.cache
26
+.tox
40 27
 nosetests.xml
41
-coverage.xml
28
+cover
29
+.testrepository
30
+*.sqlite
31
+.venv
32
+
33
+# Docs
34
+doc/source/_build/
42 35
 
43 36
 # Translations
44 37
 *.mo
45
-*.pot
46
-
47
-# Django stuff:
48
-*.log
49
-
50
-# Sphinx documentation
51
-docs/_build/
52 38
 
53
-# PyBuilder
54
-target/
39
+# Mr Developer
40
+.mr.developer.cfg
41
+.project
42
+.pydevproject
43
+*.swp

+ 4
- 0
.testr.conf View File

@@ -0,0 +1,4 @@
1
+[DEFAULT]
2
+test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 ${PYTHON:-python} -m subunit.run discover -t ./ ./tests/unit $LISTOPT $IDOPTION
3
+test_id_option=--load-list $IDFILE
4
+test_list_option=--list

+ 14
- 3
README.rst View File

@@ -1,4 +1,15 @@
1
-# NerdReviewer
1
+NerdReviewer - automates dull daily routine code reviews
2
+========================================================
2 3
 
3
-Nerd Code Reviewer Bot will analyze your commit and tell you 
4
-why nobody wants to review it. 
4
+
5
+Nerd Code Reviewer analyzes commits and tell authors where and why they
6
+code won't pass human code review process.
7
+
8
+Such automation optimizes work on open source projects and simplifies life
9
+of new contributors, because they will get interactive step by step guide
10
+how to make their patches attractive for project's maintainers.
11
+
12
+
13
+.. image:: doc/source/images/american_gothic.jpg
14
+   :alt: American Gothic
15
+   :width: 650 px

+ 177
- 0
doc/source/Makefile View File

@@ -0,0 +1,177 @@
1
+# Makefile for Sphinx documentation
2
+#
3
+
4
+# You can set these variables from the command line.
5
+SPHINXOPTS    =
6
+SPHINXBUILD   = sphinx-build
7
+PAPER         =
8
+BUILDDIR      = _build
9
+
10
+# User-friendly check for sphinx-build
11
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13
+endif
14
+
15
+# Internal variables.
16
+PAPEROPT_a4     = -D latex_paper_size=a4
17
+PAPEROPT_letter = -D latex_paper_size=letter
18
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
19
+# the i18n builder cannot share the environment and doctrees with the others
20
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
21
+
22
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
23
+
24
+help:
25
+	@echo "Please use \`make <target>' where <target> is one of"
26
+	@echo "  html       to make standalone HTML files"
27
+	@echo "  dirhtml    to make HTML files named index.html in directories"
28
+	@echo "  singlehtml to make a single large HTML file"
29
+	@echo "  pickle     to make pickle files"
30
+	@echo "  json       to make JSON files"
31
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
32
+	@echo "  qthelp     to make HTML files and a qthelp project"
33
+	@echo "  devhelp    to make HTML files and a Devhelp project"
34
+	@echo "  epub       to make an epub"
35
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
36
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
37
+	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
38
+	@echo "  text       to make text files"
39
+	@echo "  man        to make manual pages"
40
+	@echo "  texinfo    to make Texinfo files"
41
+	@echo "  info       to make Texinfo files and run them through makeinfo"
42
+	@echo "  gettext    to make PO message catalogs"
43
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
44
+	@echo "  xml        to make Docutils-native XML files"
45
+	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
46
+	@echo "  linkcheck  to check all external links for integrity"
47
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
48
+
49
+clean:
50
+	rm -rf $(BUILDDIR)/*
51
+
52
+html:
53
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
54
+	@echo
55
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
56
+
57
+dirhtml:
58
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
59
+	@echo
60
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
61
+
62
+singlehtml:
63
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
64
+	@echo
65
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
66
+
67
+pickle:
68
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
69
+	@echo
70
+	@echo "Build finished; now you can process the pickle files."
71
+
72
+json:
73
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
74
+	@echo
75
+	@echo "Build finished; now you can process the JSON files."
76
+
77
+htmlhelp:
78
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
79
+	@echo
80
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
81
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
82
+
83
+qthelp:
84
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
85
+	@echo
86
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
87
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
88
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/nerdreviewer.qhcp"
89
+	@echo "To view the help file:"
90
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/nerdreviewer.qhc"
91
+
92
+devhelp:
93
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
94
+	@echo
95
+	@echo "Build finished."
96
+	@echo "To view the help file:"
97
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/nerdreviewer"
98
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/nerdreviewer"
99
+	@echo "# devhelp"
100
+
101
+epub:
102
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
103
+	@echo
104
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
105
+
106
+latex:
107
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
108
+	@echo
109
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
110
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
111
+	      "(use \`make latexpdf' here to do that automatically)."
112
+
113
+latexpdf:
114
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
115
+	@echo "Running LaTeX files through pdflatex..."
116
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf
117
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
118
+
119
+latexpdfja:
120
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
121
+	@echo "Running LaTeX files through platex and dvipdfmx..."
122
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
123
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
124
+
125
+text:
126
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
127
+	@echo
128
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
129
+
130
+man:
131
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
132
+	@echo
133
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
134
+
135
+texinfo:
136
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
137
+	@echo
138
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
139
+	@echo "Run \`make' in that directory to run these through makeinfo" \
140
+	      "(use \`make info' here to do that automatically)."
141
+
142
+info:
143
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
144
+	@echo "Running Texinfo files through makeinfo..."
145
+	make -C $(BUILDDIR)/texinfo info
146
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
147
+
148
+gettext:
149
+	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
150
+	@echo
151
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
152
+
153
+changes:
154
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
155
+	@echo
156
+	@echo "The overview file is in $(BUILDDIR)/changes."
157
+
158
+linkcheck:
159
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
160
+	@echo
161
+	@echo "Link check complete; look for any errors in the above output " \
162
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
163
+
164
+doctest:
165
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
166
+	@echo "Testing of doctests in the sources finished, look at the " \
167
+	      "results in $(BUILDDIR)/doctest/output.txt."
168
+
169
+xml:
170
+	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
171
+	@echo
172
+	@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
173
+
174
+pseudoxml:
175
+	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
176
+	@echo
177
+	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

+ 250
- 0
doc/source/conf.py View File

@@ -0,0 +1,250 @@
1
+# -*- coding: utf-8 -*-
2
+#
3
+# Nerd Reviewer documentation build configuration file, created by
4
+# sphinx-quickstart on Fri Jan 10 23:19:18 2014.
5
+#
6
+# This file is execfile()d with the current directory set to its containing dir.
7
+#
8
+# Note that not all possible configuration values are present in this
9
+# autogenerated file.
10
+#
11
+# All configuration values have a default; values that are commented out
12
+# serve to show the default.
13
+
14
+import datetime
15
+import os
16
+import sys
17
+
18
+# If extensions (or modules to document with autodoc) are in another directory,
19
+# add these directories to sys.path here. If the directory is relative to the
20
+# documentation root, use os.path.abspath to make it absolute, like shown here.
21
+sys.path.extend([
22
+    os.path.abspath("../.."),
23
+])
24
+
25
+
26
+# -- General configuration -----------------------------------------------------
27
+
28
+# If your documentation needs a minimal Sphinx version, state it here.
29
+#needs_sphinx = "1.0"
30
+
31
+# Add any Sphinx extension module names here, as strings. They can be extensions
32
+# coming with Sphinx (named "sphinx.ext.*") or your custom ones.
33
+extensions = [
34
+    "sphinx.ext.autodoc",
35
+    "sphinx.ext.doctest",
36
+    "sphinx.ext.todo",
37
+    "sphinx.ext.coverage",
38
+    "sphinx.ext.ifconfig",
39
+    "sphinx.ext.viewcode",
40
+]
41
+todo_include_todos = True
42
+
43
+# Add any paths that contain templates here, relative to this directory.
44
+templates_path = ["_templates"]
45
+
46
+# The suffix of source filenames.
47
+source_suffix = ".rst"
48
+
49
+# The encoding of source files.
50
+#source_encoding = "utf-8-sig"
51
+
52
+# The master toctree document.
53
+master_doc = "index"
54
+
55
+# General information about the project.
56
+project = u"Nerd Reviewer"
57
+copyright = u"%d, Boris Pavlovic" % datetime.datetime.now().year
58
+
59
+# The version info for the project you're documenting, acts as replacement for
60
+# |version| and |release|, also used in various other places throughout the
61
+# built documents.
62
+#
63
+# The short X.Y version.
64
+version = "0.0.1"
65
+# The full version, including alpha/beta/rc tags.
66
+release = "0.0.1"
67
+
68
+# The language for content autogenerated by Sphinx. Refer to documentation
69
+# for a list of supported languages.
70
+#language = None
71
+
72
+# There are two options for replacing |today|: either, you set today to some
73
+# non-false value, then it is used:
74
+#today = ""
75
+# Else, today_fmt is used as the format for a strftime call.
76
+#today_fmt = "%B %d, %Y"
77
+
78
+# List of patterns, relative to source directory, that match files and
79
+# directories to ignore when looking for source files.
80
+exclude_patterns = ["**/README.rst"]
81
+
82
+# The reST default role (used for this markup: `text`) to use for all documents.
83
+#default_role = None
84
+
85
+# If true, "()" will be appended to :func: etc. cross-reference text.
86
+add_function_parentheses = True
87
+
88
+# If true, the current module name will be prepended to all description
89
+# unit titles (such as .. function::).
90
+add_module_names = True
91
+
92
+# If true, sectionauthor and moduleauthor directives will be shown in the
93
+# output. They are ignored by default.
94
+#show_authors = False
95
+
96
+# The name of the Pygments (syntax highlighting) style to use.
97
+pygments_style = "sphinx"
98
+
99
+# A list of ignored prefixes for module index sorting.
100
+#modindex_common_prefix = []
101
+
102
+
103
+# -- Options for HTML output ---------------------------------------------------
104
+
105
+# The theme to use for HTML and HTML Help pages.  See the documentation for
106
+# a list of builtin themes.
107
+html_theme = "default"
108
+
109
+# Theme options are theme-specific and customize the look and feel of a theme
110
+# further.  For a list of options available for each theme, see the
111
+# documentation.
112
+#html_theme_options = {}
113
+
114
+# Add any paths that contain custom themes here, relative to this directory.
115
+#html_theme_path = []
116
+
117
+# The name for this set of Sphinx documents.  If None, it defaults to
118
+# "<project> v<release> documentation".
119
+#html_title = None
120
+
121
+# A shorter title for the navigation bar.  Default is the same as html_title.
122
+#html_short_title = None
123
+
124
+# The name of an image file (relative to this directory) to place at the top
125
+# of the sidebar.
126
+#html_logo = None
127
+
128
+# The name of an image file (within the static path) to use as favicon of the
129
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
130
+# pixels large.
131
+#html_favicon = None
132
+
133
+# Add any paths that contain custom static files (such as style sheets) here,
134
+# relative to this directory. They are copied after the builtin static files,
135
+# so a file named "default.css" will overwrite the builtin "default.css".
136
+html_static_path = []
137
+
138
+# If not "", a "Last updated on:" timestamp is inserted at every page bottom,
139
+# using the given strftime format.
140
+git_cmd = "git log --pretty=format:'%ad, commit %h' --date=local -n1"
141
+html_last_updated_fmt = os.popen(git_cmd).read()
142
+
143
+# If true, SmartyPants will be used to convert quotes and dashes to
144
+# typographically correct entities.
145
+#html_use_smartypants = True
146
+
147
+# Custom sidebar templates, maps document names to template names.
148
+#html_sidebars = {}
149
+
150
+# Additional templates that should be rendered to pages, maps page names to
151
+# template names.
152
+#html_additional_pages = {}
153
+
154
+# If false, no module index is generated.
155
+#html_domain_indices = True
156
+
157
+# If false, no index is generated.
158
+#html_use_index = True
159
+
160
+# If true, the index is split into individual pages for each letter.
161
+#html_split_index = False
162
+
163
+# If true, links to the reST sources are added to the pages.
164
+#html_show_sourcelink = True
165
+
166
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
167
+#html_show_sphinx = True
168
+
169
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
170
+#html_show_copyright = True
171
+
172
+# If true, an OpenSearch description file will be output, and all pages will
173
+# contain a <link> tag referring to it.  The value of this option must be the
174
+# base URL from which the finished HTML is served.
175
+#html_use_opensearch = ""
176
+
177
+# This is the file name suffix for HTML files (e.g. ".xhtml").
178
+#html_file_suffix = None
179
+
180
+# Output file base name for HTML help builder.
181
+htmlhelp_basename = "%sdoc" % project
182
+
183
+
184
+# -- Options for LaTeX output --------------------------------------------------
185
+
186
+latex_elements = {
187
+# The paper size ("letterpaper" or "a4paper").
188
+#"papersize": "letterpaper",
189
+
190
+# The font size ("10pt", "11pt" or "12pt").
191
+#"pointsize": "10pt",
192
+
193
+# Additional stuff for the LaTeX preamble.
194
+#"preamble": "",
195
+}
196
+
197
+# Grouping the document tree into LaTeX files. List of tuples
198
+# (source start file, target name, title, author, documentclass [howto/manual]).
199
+latex_documents = [
200
+    ("index",
201
+     "%s.tex" % project,
202
+     u"%s Documentation" % project,
203
+     u"Boris Pavlovic", "manual"),
204
+]
205
+
206
+# The name of an image file (relative to this directory) to place at the top of
207
+# the title page.
208
+#latex_logo = None
209
+
210
+# For "manual" documents, if this is true, then toplevel headings are parts,
211
+# not chapters.
212
+#latex_use_parts = False
213
+
214
+# If true, show page references after internal links.
215
+#latex_show_pagerefs = False
216
+
217
+# If true, show URL addresses after external links.
218
+#latex_show_urls = False
219
+
220
+# Documents to append as an appendix to all manuals.
221
+#latex_appendices = []
222
+
223
+# If false, no module index is generated.
224
+#latex_domain_indices = True
225
+
226
+
227
+# If true, show URL addresses after external links.
228
+#man_show_urls = False
229
+
230
+
231
+# -- Options for Texinfo output ------------------------------------------------
232
+
233
+# Grouping the document tree into Texinfo files. List of tuples
234
+# (source start file, target name, title, author,
235
+#  dir menu entry, description, category)
236
+texinfo_documents = [
237
+  ("index", "Nerd Reviewer", u"Nerd Reviewer Documentation",
238
+   u"Nerd Reviewer Team", "Nerd Reviewer",
239
+   "Nerd Reviewer automates dull daily routine code reviews.",
240
+   "Miscellaneous"),
241
+]
242
+
243
+# Documents to append as an appendix to all manuals.
244
+#texinfo_appendices = []
245
+
246
+# If false, no module index is generated.
247
+#texinfo_domain_indices = True
248
+
249
+# How to display URL addresses: "footnote", "no", or "inline".
250
+#texinfo_show_urls = "footnote"

BIN
doc/source/images/american_gothic.jpg View File


+ 30
- 0
doc/source/index.rst View File

@@ -0,0 +1,30 @@
1
+..
2
+      Copyright 2015 Mirantis Inc. All Rights Reserved.
3
+
4
+      Licensed under the Apache License, Version 2.0 (the "License"); you may
5
+      not use this file except in compliance with the License. You may obtain
6
+      a copy of the License at
7
+
8
+          http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+      Unless required by applicable law or agreed to in writing, software
11
+      distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+      WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+      License for the specific language governing permissions and limitations
14
+      under the License.
15
+
16
+NerdReviewer - automates dull daily routine code reviews
17
+========================================================
18
+
19
+
20
+Nerd Code Reviewer analyzes commits and tell authors where and why they
21
+code won't pass human code review process.
22
+
23
+Such automation optimizes work on open source projects and simplifies life
24
+of new contributors, because they will get interactive step by step guide
25
+how to make their patches attractive for project's maintainers.
26
+
27
+
28
+.. image:: ./images/american_gothic.jpg
29
+   :alt: American Gothic
30
+   :width: 450 px

+ 0
- 0
nerdreviewer/__init__.py View File


+ 21
- 0
nerdreviewer/cmd/main.py View File

@@ -0,0 +1,21 @@
1
+# Copyright 2015: Boris Pavlovic
2
+# All Rights Reserved.
3
+#
4
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
+#    not use this file except in compliance with the License. You may obtain
6
+#    a copy of the License at
7
+#
8
+#         http://www.apache.org/licenses/LICENSE-2.0
9
+#
10
+#    Unless required by applicable law or agreed to in writing, software
11
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+#    License for the specific language governing permissions and limitations
14
+#    under the License.
15
+
16
+
17
+def main():
18
+    return "Hello world"
19
+
20
+if __name__ == "__main__":
21
+    main()

+ 10
- 0
requirements.txt View File

@@ -0,0 +1,10 @@
1
+# The order of packages is significant, because pip processes them in the order
2
+# of appearance. Changing the order has an impact on the overall integration
3
+# process, which may cause wedges in the gate later.
4
+jsonschema>=2.0.0,<3.0.0
5
+netaddr>=0.7.12
6
+pbr>=0.6,!=0.7,<1.0
7
+PyYAML>=3.1.0
8
+SQLAlchemy>=0.9.7,<=0.9.99
9
+sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
10
+six>=1.9.0

+ 37
- 0
setup.cfg View File

@@ -0,0 +1,37 @@
1
+[metadata]
2
+name = nerd-reviewer
3
+version = 0.0.1
4
+summary = Nerd Reviewer - automates dull daily routine code reviews
5
+description-file =
6
+    README.rst
7
+author = Boris Pavlovic
8
+author-email = boris@pavlovic.me
9
+home-page = http://boris-42.me
10
+classifier =
11
+    Intended Audience :: Developers
12
+    Intended Audience :: Information Technology
13
+    License :: OSI Approved :: Apache Software License
14
+    Operating System :: POSIX :: Linux
15
+    Programming Language :: Python
16
+    Programming Language :: Python :: 2
17
+    Programming Language :: Python :: 2.6
18
+    Programming Language :: Python :: 2.7
19
+    Programming Language :: Python :: 3.4
20
+
21
+[files]
22
+packages =
23
+    nerd-reviewer
24
+
25
+[entry_points]
26
+
27
+console_scripts =
28
+     nerd-reviewer = nerd_reviwer.cmd.main:main
29
+
30
+[global]
31
+setup-hooks =
32
+    pbr.hooks.setup_hook
33
+
34
+[build_sphinx]
35
+all_files = 1
36
+build-dir = doc/build
37
+source-dir = doc/source

+ 30
- 0
setup.py View File

@@ -0,0 +1,30 @@
1
+#!/usr/bin/env python
2
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
3
+#
4
+# Licensed under the Apache License, Version 2.0 (the "License");
5
+# you may not use this file except in compliance with the License.
6
+# You may obtain a copy of the License at
7
+#
8
+#    http://www.apache.org/licenses/LICENSE-2.0
9
+#
10
+# Unless required by applicable law or agreed to in writing, software
11
+# distributed under the License is distributed on an "AS IS" BASIS,
12
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
+# implied.
14
+# See the License for the specific language governing permissions and
15
+# limitations under the License.
16
+
17
+# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
18
+import setuptools
19
+
20
+# In python < 2.7.4, a lazy loading of package `pbr` will break
21
+# setuptools if some other modules registered functions in `atexit`.
22
+# solution from: http://bugs.python.org/issue15881#msg170215
23
+try:
24
+    import multiprocessing  # noqa
25
+except ImportError:
26
+    pass
27
+
28
+setuptools.setup(
29
+    setup_requires=['pbr'],
30
+    pbr=True)

+ 13
- 0
test-requirements.txt View File

@@ -0,0 +1,13 @@
1
+# The order of packages is significant, because pip processes them in the order
2
+# of appearance. Changing the order has an impact on the overall integration
3
+# process, which may cause wedges in the gate later.
4
+hacking>=0.9.2,<0.10
5
+
6
+coverage>=3.6
7
+discover
8
+mock>=1.0
9
+testrepository>=0.0.18
10
+testtools>=0.9.36,!=1.2.0
11
+
12
+oslosphinx>=2.2.0  # Apache-2.0
13
+oslotest>=1.2.0  # Apache-2.0

+ 0
- 0
tests/__init__.py View File


+ 0
- 0
tests/hacking/__init__.py View File


+ 251
- 0
tests/hacking/checks.py View File

@@ -0,0 +1,251 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+# not use this file except in compliance with the License. You may obtain
3
+# a copy of the License at
4
+#
5
+#      http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+# License for the specific language governing permissions and limitations
11
+# under the License.
12
+
13
+"""
14
+Guidelines for writing new hacking checks
15
+ - Use only for Rally specific tests. OpenStack general tests
16
+   should be submitted to the common 'hacking' module.
17
+ - Pick numbers in the range N3xx. Find the current test with
18
+   the highest allocated number and then pick the next value.
19
+ - Keep the test method code in the source file ordered based
20
+   on the N3xx value.
21
+ - List the new rule in the top level HACKING.rst file
22
+ - Add test cases for each new rule to tests/test_hacking.py
23
+"""
24
+
25
+import functools
26
+import re
27
+
28
+
29
+re_assert_true_instance = re.compile(
30
+    r"(.)*assertTrue\(isinstance\((\w|\.|\'|\"|\[|\])+, "
31
+    r"(\w|\.|\'|\"|\[|\])+\)\)")
32
+re_assert_equal_type = re.compile(
33
+    r"(.)*assertEqual\(type\((\w|\.|\'|\"|\[|\])+\), "
34
+    r"(\w|\.|\'|\"|\[|\])+\)")
35
+re_assert_equal_end_with_none = re.compile(r"assertEqual\(.*?,\s+None\)$")
36
+re_assert_equal_start_with_none = re.compile(r"assertEqual\(None,")
37
+re_assert_true_false_with_in_or_not_in = re.compile(
38
+    r"assert(True|False)\("
39
+    r"(\w|[][.'\"])+( not)? in (\w|[][.'\",])+(, .*)?\)")
40
+re_assert_true_false_with_in_or_not_in_spaces = re.compile(
41
+    r"assert(True|False)\((\w|[][.'\"])+( not)? in [\[|'|\"](\w|[][.'\", ])+"
42
+    r"[\[|'|\"](, .*)?\)")
43
+re_assert_equal_in_end_with_true_or_false = re.compile(
44
+    r"assertEqual\((\w|[][.'\"])+( not)? in (\w|[][.'\", ])+, (True|False)\)")
45
+re_assert_equal_in_start_with_true_or_false = re.compile(
46
+    r"assertEqual\((True|False), (\w|[][.'\"])+( not)? in (\w|[][.'\", ])+\)")
47
+
48
+
49
+def skip_ignored_lines(func):
50
+
51
+    @functools.wraps(func)
52
+    def wrapper(logical_line, filename):
53
+        line = logical_line.strip()
54
+        if not line or line.startswith("#") or line.endswith("# noqa"):
55
+            return
56
+        yield next(func(logical_line, filename))
57
+
58
+    return wrapper
59
+
60
+
61
+def _parse_assert_mock_str(line):
62
+    point = line.find(".assert_")
63
+
64
+    if point != -1:
65
+        end_pos = line[point:].find("(") + point
66
+        return point, line[point + 1: end_pos], line[: point]
67
+    else:
68
+        return None, None, None
69
+
70
+
71
+@skip_ignored_lines
72
+def check_assert_methods_from_mock(logical_line, filename):
73
+    """Ensure that ``assert_*`` methods from ``mock`` library is used correctly
74
+
75
+    N301 - base error number
76
+    N302 - related to nonexistent "assert_called"
77
+    N303 - related to nonexistent "assert_called_once"
78
+    """
79
+
80
+    correct_names = ["assert_any_call", "assert_called_once_with",
81
+                     "assert_called_with", "assert_has_calls"]
82
+    ignored_files = ["./tests/unit/test_hacking.py"]
83
+
84
+    if filename.startswith("./tests") and filename not in ignored_files:
85
+        pos, method_name, obj_name = _parse_assert_mock_str(logical_line)
86
+
87
+        if pos:
88
+            if method_name not in correct_names:
89
+                error_number = "N301"
90
+                msg = ("%(error_number)s:'%(method)s' is not present in `mock`"
91
+                       " library. %(custom_msg)s For more details, visit "
92
+                       "http://www.voidspace.org.uk/python/mock/ .")
93
+
94
+                if method_name == "assert_called":
95
+                    error_number = "N302"
96
+                    custom_msg = ("Maybe, you should try to use "
97
+                                  "'assertTrue(%s.called)' instead." %
98
+                                  obj_name)
99
+                elif method_name == "assert_called_once":
100
+                    # For more details, see a bug in Rally:
101
+                    #    https://bugs.launchpad.net/rally/+bug/1305991
102
+                    error_number = "N303"
103
+                    custom_msg = ("Maybe, you should try to use "
104
+                                  "'assertEqual(1, %(obj_name)s.call_count)' "
105
+                                  "or '%(obj_name)s.assert_called_once_with()'"
106
+                                  " instead." % {"obj_name": obj_name})
107
+                else:
108
+                    custom_msg = ("Correct 'assert_*' methods: '%s'."
109
+                                  % "', '".join(correct_names))
110
+
111
+                yield (pos, msg % {
112
+                    "error_number": error_number,
113
+                    "method": method_name,
114
+                    "custom_msg": custom_msg})
115
+
116
+
117
+@skip_ignored_lines
118
+def assert_true_instance(logical_line, filename):
119
+    """Check for assertTrue(isinstance(a, b)) sentences
120
+
121
+    N320
122
+    """
123
+    if re_assert_true_instance.match(logical_line):
124
+        yield (0, "N320 assertTrue(isinstance(a, b)) sentences not allowed, "
125
+                  "you should use assertIsInstance(a, b) instead.")
126
+
127
+
128
+@skip_ignored_lines
129
+def assert_equal_type(logical_line, filename):
130
+    """Check for assertEqual(type(A), B) sentences
131
+
132
+    N321
133
+    """
134
+    if re_assert_equal_type.match(logical_line):
135
+        yield (0, "N321 assertEqual(type(A), B) sentences not allowed, "
136
+                  "you should use assertIsInstance(a, b) instead.")
137
+
138
+
139
+@skip_ignored_lines
140
+def assert_equal_none(logical_line, filename):
141
+    """Check for assertEqual(A, None) or assertEqual(None, A) sentences
142
+
143
+    N322
144
+    """
145
+    res = (re_assert_equal_start_with_none.search(logical_line) or
146
+           re_assert_equal_end_with_none.search(logical_line))
147
+    if res:
148
+        yield (0, "N322 assertEqual(A, None) or assertEqual(None, A) "
149
+                  "sentences not allowed, you should use assertIsNone(A) "
150
+                  "instead.")
151
+
152
+
153
+@skip_ignored_lines
154
+def assert_true_or_false_with_in(logical_line, filename):
155
+    """Check assertTrue/False(A in/not in B) with collection contents.
156
+
157
+    Check for assertTrue/False(A in B), assertTrue/False(A not in B),
158
+    assertTrue/False(A in B, message) or assertTrue/False(A not in B, message)
159
+    sentences.
160
+
161
+    N323
162
+    """
163
+
164
+    res = (re_assert_true_false_with_in_or_not_in.search(logical_line) or
165
+           re_assert_true_false_with_in_or_not_in_spaces.search(logical_line))
166
+    if res:
167
+        yield (0, "N323 assertTrue/assertFalse(A in/not in B)sentences not "
168
+                  "allowed, you should use assertIn(A, B) or assertNotIn(A, B)"
169
+                  " instead.")
170
+
171
+
172
+@skip_ignored_lines
173
+def assert_equal_in(logical_line, filename):
174
+    """Check assertEqual(A in/not in B, True/False) with collection contents
175
+
176
+    Check for assertEqual(A in B, True/False), assertEqual(True/False, A in B),
177
+    assertEqual(A not in B, True/False) or assertEqual(True/False, A not in B)
178
+    sentences.
179
+
180
+    N324
181
+    """
182
+
183
+    res = (re_assert_equal_in_end_with_true_or_false.search(logical_line) or
184
+           re_assert_equal_in_start_with_true_or_false.search(logical_line))
185
+    if res:
186
+        yield (0, "N324: Use assertIn/NotIn(A, B) rather than "
187
+                  "assertEqual(A in/not in B, True/False) when checking "
188
+                  "collection contents.")
189
+
190
+
191
+@skip_ignored_lines
192
+def check_quotes(logical_line, filename):
193
+    """Check that single quotation marks are not used
194
+
195
+    N350
196
+    """
197
+
198
+    in_string = False
199
+    in_multiline_string = False
200
+    single_quotas_are_used = False
201
+
202
+    check_tripple = (
203
+        lambda line, i, char: (
204
+            i + 2 < len(line) and
205
+            (char == line[i] == line[i + 1] == line[i + 2])
206
+        )
207
+    )
208
+
209
+    i = 0
210
+    while i < len(logical_line):
211
+        char = logical_line[i]
212
+
213
+        if in_string:
214
+            if char == "\"":
215
+                in_string = False
216
+            if char == "\\":
217
+                i += 1  # ignore next char
218
+
219
+        elif in_multiline_string:
220
+            if check_tripple(logical_line, i, "\""):
221
+                i += 2  # skip next 2 chars
222
+                in_multiline_string = False
223
+
224
+        elif char == "#":
225
+            break
226
+
227
+        elif char == "'":
228
+            single_quotas_are_used = True
229
+            break
230
+
231
+        elif char == "\"":
232
+            if check_tripple(logical_line, i, "\""):
233
+                in_multiline_string = True
234
+                i += 3
235
+                continue
236
+            in_string = True
237
+
238
+        i += 1
239
+
240
+    if single_quotas_are_used:
241
+        yield (i, "N350 Remove Single quotes")
242
+
243
+
244
+def factory(register):
245
+    register(check_assert_methods_from_mock)
246
+    register(assert_true_instance)
247
+    register(assert_equal_type)
248
+    register(assert_equal_none)
249
+    register(assert_true_or_false_with_in)
250
+    register(assert_equal_in)
251
+    register(check_quotes)

+ 0
- 0
tests/unit/__init__.py View File


+ 25
- 0
tests/unit/test.py View File

@@ -0,0 +1,25 @@
1
+# Copyright 2015: Boris Pavlovic
2
+# All Rights Reserved.
3
+#
4
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
+#    not use this file except in compliance with the License. You may obtain
6
+#    a copy of the License at
7
+#
8
+#         http://www.apache.org/licenses/LICENSE-2.0
9
+#
10
+#    Unless required by applicable law or agreed to in writing, software
11
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+#    License for the specific language governing permissions and limitations
14
+#    under the License.
15
+
16
+import mock
17
+from oslotest import base
18
+
19
+
20
+class TestCase(base.BaseTestCase):
21
+    """Test case base class for all unit tests."""
22
+
23
+    def setUp(self):
24
+        super(TestCase, self).setUp()
25
+        self.addCleanup(mock.patch.stopall)

+ 24
- 0
tests/unit/test_noop.py View File

@@ -0,0 +1,24 @@
1
+# Copyright 2015: Boris Pavlovic
2
+# All Rights Reserved.
3
+#
4
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
+#    not use this file except in compliance with the License. You may obtain
6
+#    a copy of the License at
7
+#
8
+#         http://www.apache.org/licenses/LICENSE-2.0
9
+#
10
+#    Unless required by applicable law or agreed to in writing, software
11
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+#    License for the specific language governing permissions and limitations
14
+#    under the License.
15
+
16
+
17
+from tests.unit import test
18
+
19
+
20
+class NoopTestCase(test.TestCase):
21
+    """Test case base class for all unit tests."""
22
+
23
+    def test_noop(self):
24
+        self.assertEqual(4, 2 + 2)

+ 43
- 0
tox.ini View File

@@ -0,0 +1,43 @@
1
+[tox]
2
+minversion = 1.6
3
+skipsdist = True
4
+envlist = py26,py27,py33,py34,pep8
5
+
6
+[testenv]
7
+setenv = VIRTUAL_ENV={envdir}
8
+         LANG=en_US.UTF-8
9
+         LANGUAGE=en_US:en
10
+         LC_ALL=C
11
+         PYTHONHASHSEED=0
12
+deps = -r{toxinidir}/requirements.txt
13
+       -r{toxinidir}/test-requirements.txt
14
+install_command = pip install -U {opts} {packages}
15
+usedevelop = True
16
+commands = python setup.py testr --slowest --testr-args='{posargs}'
17
+distribute = false
18
+
19
+[testenv:pep8]
20
+commands = flake8
21
+distribute = false
22
+
23
+[testenv:venv]
24
+commands = {posargs}
25
+
26
+[testenv:cover]
27
+commands = python setup.py testr --coverage --testr-args='{posargs}'
28
+
29
+[testenv:docs]
30
+changedir = doc/source
31
+commands = make html
32
+
33
+[tox:jenkins]
34
+downloadcache = ~/cache/pip
35
+
36
+[flake8]
37
+ignore = E126,H703
38
+show-source = true
39
+builtins = _
40
+exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,tools,build,setup.py
41
+
42
+[hacking]
43
+local-check-factory = tests.hacking.checks.factory

Loading…
Cancel
Save