2
2
"""
3
3
openlinter.py
4
4
5
- Early implementation for an open source project linter .
5
+ Console entry point for the openlinter package .
6
6
7
- See https://github.com/OpenNewsLabs/open-project-linter/issues/21 .
7
+ Functions
8
+ ---------
9
+ main
10
+ Main function of the linter--set up state and call checks.
11
+
12
+ get_current_script_dir
13
+ Inspect the stack to find the directory the current module is in.
14
+
15
+ parse_linter_args
16
+ Parse command-line arguments and set up the console interface.
17
+
18
+ get_rule_set
19
+ Read and parse the configuration file.
20
+
21
+ check_for_git_branches
22
+ Call the checks related to git branching and print the results.
23
+
24
+ check_multiple_git_commits
25
+ Call the check for multiple commits per branch and print the result.
8
26
"""
9
27
10
28
from __future__ import absolute_import
18
36
import openlinter .rules as rules
19
37
20
38
21
- def get_current_script_dir ():
22
- module_location = os .path .abspath (inspect .stack ()[0 ][1 ])
23
- return os .path .dirname (module_location )
24
-
25
-
26
- def parse_linter_args ():
27
- parser = argparse .ArgumentParser ()
28
- group = parser .add_mutually_exclusive_group ()
29
- group .add_argument ('-d' , '--directory' , help = "The local path to your repository's base directory. Defaults to the current working directory." ,
30
- default = os .getcwd ()
31
- )
32
- parser .add_argument ('-r' , '--rules' , help = 'The path to the rules configuration file, a YAML file containing the rules you would like to check for. Defaults to current-working-directory/openlinter/rules.yml.' ,
33
- default = os .path .join (get_current_script_dir (), 'rules.yml' )
34
- )
35
- parser .add_argument ('-v' , '--version' , action = 'version' , version = '0.4dev' )
36
- return parser .parse_args ()
37
-
38
-
39
- # FIXME: this is all not very functional or testable.
39
+ # FIXME: this could be more functional and testable.
40
40
def main ():
41
- # Set up parser and CLI
41
+ # Get command-line args and configuration data
42
42
args = parse_linter_args ()
43
-
44
- # Read in rules
45
- with open (args .rules , 'r' ) as f :
46
- text = f .read ()
47
-
48
- rule_set = yaml .safe_load (text )
43
+ rule_set = get_rule_set (args )
49
44
50
45
# Check directory/repository against rules
46
+ #######
47
+ # TODO: Consider architecture: how to handle the result (print to stdout
48
+ # as we go, or pass around a result object?), how to handle interface
49
+ # strings (hard-coded or able to change/localize easily).
50
+ #######
51
+
52
+ # Check for the presence of specified files
51
53
if 'files_exist' in rule_set :
52
- """
53
- # TODO: Consider architecture: how to handle the result (print to stdout
54
- # as we go, or pass around a result object?), how to handle interface
55
- # strings (hard-coded or able to change/localize easily).
56
- """
57
- # FIXME: also unfortunately nested
54
+ # FIXME: also unfortunately nested, breaking out functions will help
58
55
for files_to_check in rule_set ['files_exist' ]:
59
56
for f in files_to_check :
60
57
for name in files_to_check [f ]:
@@ -65,16 +62,14 @@ def main():
65
62
print (output )
66
63
break
67
64
# Otherwise note that none of the names exist?
68
- # TODO: could wrangle this a bit
69
- # brainwane/sumanah: should this say "no $name type file found"
70
- # or list the individual ones not present?
71
65
elif result is None :
72
66
output = '! {} exists but is empty' .format (name ,
73
67
args .directory )
74
68
else :
75
69
output = '! {} not found in {}' .format (name , args .directory )
76
70
print (output )
77
71
72
+ # Check for the presence of any code
78
73
if 'code_exists' in rule_set :
79
74
code_exists = rules .check_for_code (args .directory )
80
75
if code_exists :
@@ -83,6 +78,7 @@ def main():
83
78
output = '! no code files found'
84
79
print (output )
85
80
81
+ # Check for the presence of version control and git repo features
86
82
if 'version_control' in rule_set :
87
83
vcs = rules .detect_version_control (args .directory )
88
84
if vcs :
@@ -91,45 +87,138 @@ def main():
91
87
output = '! version control system not detected'
92
88
print (output )
93
89
94
- # Conditionals may need work here, TODO
95
- if 'detect_git_branches' in rule_set ['version_control' ] and vcs == 'git' :
96
- branches = rules . check_multiple_branches (args . directory )
97
- if branches :
98
- output = ' multiple git branches found'
90
+ # Might be better with a try/except with git.InvalidGitRepositoryError
91
+ if 'detect_git_branches' in rule_set ['version_control' ] and vcs == 'git' :
92
+ git_branch_info = check_for_git_branches (args , rule_set )
93
+ elif 'detect_git_branches' in rule_set [ 'version_control' ] :
94
+ print ( '! no git repository detected, could not check for git branches' )
99
95
else :
100
- output = '! fewer than 2 git branches found'
101
- print (output )
96
+ pass
102
97
103
- # check for a dev/feature branch
104
- # TODO: pull some of this out into a function
105
- develop = False
106
- for name in rule_set ['dev_branch_names' ]:
107
- if rules .check_for_develop_branch (args .directory , name ):
108
- develop = True
109
- output = ' development branch "{}" found' .format (name )
110
- print (output )
111
- if not develop :
112
- output = '! no development branch found'
113
- print (output )
114
-
115
- # Conditionals may need work here, TODO
116
- if 'multiple_git_commits' in rule_set ['version_control' ] and vcs == 'git' :
117
- multiple_commits = rules .check_for_multiple_commits (args .directory )
118
- if multiple_commits :
119
- output = ' multiple commits on a branch found'
98
+ if 'multiple_git_commits' in rule_set ['version_control' ] and vcs == 'git' :
99
+ # Currently doesn't return anything
100
+ multiple_commits = check_multiple_git_commits (args )
101
+ elif 'multiple_git_commits' in rule_set ['version_control' ]:
102
+ print ('! no git repository detected, could not check for multiple commits' )
120
103
else :
121
- output = '! one or fewer commits on each branch'
122
- print (output )
104
+ pass
123
105
124
- elif 'detect_git_branches' in rule_set ['version_control' ]:
125
- print ('! no git repository detected, could not check for git branches' )
106
+ #######
107
+ # Checks with new rules get added here
108
+ #######
126
109
110
+
111
+ def get_current_script_dir ():
112
+ """Inspect the stack to find the directory the current module is in.
113
+
114
+ Returns
115
+ -------
116
+ string
117
+ a string containing the path to the module location
118
+ """
119
+ module_location = os .path .abspath (inspect .stack ()[0 ][1 ])
120
+ return os .path .dirname (module_location )
121
+
122
+
123
+ def parse_linter_args ():
124
+ """Parse command-line arguments and set up the command-line
125
+ interface and help.
126
+
127
+ Defaults to current working directory for the directory arg and the
128
+ copy of rules.py in the directory this module is in for the rules arg.
129
+
130
+ Returns
131
+ -------
132
+ argparse.Namespace
133
+ object subclass with arguments as attributes for each given argument
134
+ """
135
+ parser = argparse .ArgumentParser ()
136
+ group = parser .add_mutually_exclusive_group ()
137
+ group .add_argument ('-d' , '--directory' , help = "The local path to your repository's base directory. Defaults to the current working directory." ,
138
+ default = os .getcwd ()
139
+ )
140
+ parser .add_argument ('-r' , '--rules' , help = 'The path to the rules configuration file, a YAML file containing the rules you would like to check for. Defaults to path/to/openlinter/rules.yml.' ,
141
+ default = os .path .join (get_current_script_dir (), 'rules.yml' )
142
+ )
143
+ parser .add_argument ('-v' , '--version' , action = 'version' , version = '1.0' )
144
+ return parser .parse_args ()
145
+
146
+
147
+ def get_rule_set (args ):
148
+ """Read and parse the config file at the location given when the
149
+ linter script is run.
150
+
151
+ Parameters
152
+ ----------
153
+ args : argparse.Namespace
154
+ Arguments input when script is called from the console
155
+
156
+ Returns
157
+ -------
158
+ dict
159
+ Contains structured data from the parsed configuration file
160
+ """
161
+ with open (args .rules , 'r' ) as f :
162
+ text = f .read ()
163
+ rule_set = yaml .safe_load (text )
164
+ return rule_set
165
+
166
+
167
+ def check_for_git_branches (args , rule_set ):
168
+ """Call the checks related to git branching (multiple branches and
169
+ appropriately named develop/feature branch) and print the results
170
+ to stdout.
171
+
172
+ Parameters
173
+ ----------
174
+ args : argparse.Namespace
175
+ Arguments input when script is called from the console
176
+ rule_set : dict
177
+ Contains the structured data from the parsed configuration file
178
+
179
+ Returns
180
+ -------
181
+ None
182
+ """
183
+ branches = rules .check_multiple_branches (args .directory )
184
+ if branches :
185
+ output = ' multiple git branches found'
127
186
else :
128
- pass
187
+ output = '! fewer than 2 git branches found'
188
+ print (output )
189
+
190
+ # check for a dev/feature branch
191
+ # TODO: pull some of this out into a function
192
+ develop = False
193
+ for name in rule_set ['dev_branch_names' ]:
194
+ if rules .check_for_develop_branch (args .directory , name ):
195
+ develop = True
196
+ output = ' development branch "{}" found' .format (name )
197
+ print (output )
198
+ if not develop :
199
+ output = '! no development branch found'
200
+ print (output )
201
+
129
202
130
- # Can add more features to check for in here
131
- # TODO: Could really use refactoring to handle results + output strings
132
- # better, and could pull individual conditionals out into functions
203
+ def check_multiple_git_commits (args ):
204
+ """Call the check for multiple commits on a branch and print the
205
+ result to stdout.
206
+
207
+ Parameters
208
+ ----------
209
+ args : argparse.Namespace
210
+ Arguments input when script is called from the console
211
+
212
+ Returns
213
+ -------
214
+ None
215
+ """
216
+ multiple_commits = rules .check_for_multiple_commits (args .directory )
217
+ if multiple_commits :
218
+ output = ' multiple commits on a branch found'
219
+ else :
220
+ output = '! one or fewer commits on each branch'
221
+ print (output )
133
222
134
223
135
224
if __name__ == '__main__' :
0 commit comments