Merge ~ec0/juju-lint:fix-snap-and-better-errors into juju-lint:master
- Git
- lp:~ec0/juju-lint
- fix-snap-and-better-errors
- Merge into master
Proposed by
James Hebden
Status: | Merged |
---|---|
Approved by: | James Troup |
Approved revision: | 5ae370127a4908793759c30456811af625a2a85c |
Merged at revision: | 0a72707edef77d9e82b20fb36199a7baf43261c1 |
Proposed branch: | ~ec0/juju-lint:fix-snap-and-better-errors |
Merge into: | juju-lint:master |
Diff against target: |
312 lines (+78/-64) 6 files modified
jujulint/cli.py (+21/-4) jujulint/config.py (+10/-10) jujulint/config_default.yaml (+18/-24) jujulint/lint.py (+26/-21) setup.py (+2/-5) snap/snapcraft.yaml (+1/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Troup | Pending | ||
Review via email: mp+384624@code.launchpad.net |
Commit message
Fix the snap, as it was not including the actual juju-lint library.
Also add more and better error handling around running juju-lint without a configuration file.
Support both absolute and config-relative paths for lint rules.
Description of the change
To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
Change successfully merged at revision 0a72707edef77d9
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/jujulint/cli.py b/jujulint/cli.py | |||
2 | index a75a7c3..68e7bb2 100755 | |||
3 | --- a/jujulint/cli.py | |||
4 | +++ b/jujulint/cli.py | |||
5 | @@ -21,8 +21,10 @@ from jujulint.config import Config | |||
6 | 21 | from jujulint.lint import Linter | 21 | from jujulint.lint import Linter |
7 | 22 | from jujulint.logging import Logger | 22 | from jujulint.logging import Logger |
8 | 23 | from jujulint.openstack import OpenStack | 23 | from jujulint.openstack import OpenStack |
9 | 24 | import os.path | ||
10 | 24 | import pkg_resources | 25 | import pkg_resources |
11 | 25 | import yaml | 26 | import yaml |
12 | 27 | import sys | ||
13 | 26 | 28 | ||
14 | 27 | 29 | ||
15 | 28 | class Cli: | 30 | class Cli: |
16 | @@ -35,9 +37,16 @@ class Cli: | |||
17 | 35 | self.config = Config() | 37 | self.config = Config() |
18 | 36 | self.logger = Logger(self.config["logging"]["loglevel"].get()) | 38 | self.logger = Logger(self.config["logging"]["loglevel"].get()) |
19 | 37 | self.version = pkg_resources.require("jujulint")[0].version | 39 | self.version = pkg_resources.require("jujulint")[0].version |
23 | 38 | self.lint_rules = "{}/{}".format( | 40 | rules_file = self.config["rules"]["file"].get() |
24 | 39 | self.config.config_dir(), self.config["rules"]["file"].get() | 41 | # handle absolute path provided |
25 | 40 | ) | 42 | if os.path.isfile(rules_file): |
26 | 43 | self.lint_rules = rules_file | ||
27 | 44 | elif os.path.isfile("{}/{}".format(self.config.config_dir(), rules_file)): | ||
28 | 45 | # default to relative path | ||
29 | 46 | self.lint_rules = "{}/{}".format(self.config.config_dir(), rules_file) | ||
30 | 47 | else: | ||
31 | 48 | self.logger.error("Cloud not locate rules file {}".format(rules_file)) | ||
32 | 49 | sys.exit(1) | ||
33 | 41 | 50 | ||
34 | 42 | def startup_message(self): | 51 | def startup_message(self): |
35 | 43 | """Print startup message to log.""" | 52 | """Print startup message to log.""" |
36 | @@ -45,14 +54,20 @@ class Cli: | |||
37 | 45 | ( | 54 | ( |
38 | 46 | "juju-lint version {} starting...\n" | 55 | "juju-lint version {} starting...\n" |
39 | 47 | "\t* Config directory: {}\n" | 56 | "\t* Config directory: {}\n" |
40 | 57 | "\t* Rules file: {}\n" | ||
41 | 48 | "\t* Log level: {}\n" | 58 | "\t* Log level: {}\n" |
42 | 49 | ).format( | 59 | ).format( |
43 | 50 | self.version, | 60 | self.version, |
44 | 51 | self.config.config_dir(), | 61 | self.config.config_dir(), |
45 | 62 | self.lint_rules, | ||
46 | 52 | self.config["logging"]["loglevel"].get(), | 63 | self.config["logging"]["loglevel"].get(), |
47 | 53 | ) | 64 | ) |
48 | 54 | ) | 65 | ) |
49 | 55 | 66 | ||
50 | 67 | def usage(self): | ||
51 | 68 | """Print program usage.""" | ||
52 | 69 | self.config.parser.print_help() | ||
53 | 70 | |||
54 | 56 | def audit_file(self, filename, cloud_type=None): | 71 | def audit_file(self, filename, cloud_type=None): |
55 | 57 | """Directly audit a YAML file.""" | 72 | """Directly audit a YAML file.""" |
56 | 58 | self.logger.debug("Starting audit of file {}".format(filename)) | 73 | self.logger.debug("Starting audit of file {}".format(filename)) |
57 | @@ -132,5 +147,7 @@ def main(): | |||
58 | 132 | cli.audit_file(manual_file, cloud_type=manual_type) | 147 | cli.audit_file(manual_file, cloud_type=manual_type) |
59 | 133 | else: | 148 | else: |
60 | 134 | cli.audit_file(manual_file) | 149 | cli.audit_file(manual_file) |
62 | 135 | else: | 150 | elif "clouds" in cli.config: |
63 | 136 | cli.audit_all() | 151 | cli.audit_all() |
64 | 152 | else: | ||
65 | 153 | cli.usage() | ||
66 | diff --git a/jujulint/config.py b/jujulint/config.py | |||
67 | index b4d1e1c..fb5497a 100644 | |||
68 | --- a/jujulint/config.py | |||
69 | +++ b/jujulint/config.py | |||
70 | @@ -29,8 +29,8 @@ class Config(Configuration): | |||
71 | 29 | """Wrap the initialisation of confuse's Configuration object providing defaults for our application.""" | 29 | """Wrap the initialisation of confuse's Configuration object providing defaults for our application.""" |
72 | 30 | super().__init__("juju-lint", __name__) | 30 | super().__init__("juju-lint", __name__) |
73 | 31 | 31 | ||
76 | 32 | parser = ArgumentParser(description="Sanity check one or more Juju models") | 32 | self.parser = ArgumentParser(description="Sanity check one or more Juju models") |
77 | 33 | parser.add_argument( | 33 | self.parser.add_argument( |
78 | 34 | "-l", | 34 | "-l", |
79 | 35 | "--log-level", | 35 | "--log-level", |
80 | 36 | type=str, | 36 | type=str, |
81 | @@ -39,7 +39,7 @@ class Config(Configuration): | |||
82 | 39 | help="The default log level, valid options are info, warn, error or debug", | 39 | help="The default log level, valid options are info, warn, error or debug", |
83 | 40 | dest="logging.loglevel", | 40 | dest="logging.loglevel", |
84 | 41 | ) | 41 | ) |
86 | 42 | parser.add_argument( | 42 | self.parser.add_argument( |
87 | 43 | "-d", | 43 | "-d", |
88 | 44 | "--output-dir", | 44 | "--output-dir", |
89 | 45 | type=str, | 45 | type=str, |
90 | @@ -48,7 +48,7 @@ class Config(Configuration): | |||
91 | 48 | help="The folder to use when saving gathered cloud data and lint reports.", | 48 | help="The folder to use when saving gathered cloud data and lint reports.", |
92 | 49 | dest="output.folder", | 49 | dest="output.folder", |
93 | 50 | ) | 50 | ) |
95 | 51 | parser.add_argument( | 51 | self.parser.add_argument( |
96 | 52 | "--dump-state", | 52 | "--dump-state", |
97 | 53 | type=str, | 53 | type=str, |
98 | 54 | help=( | 54 | help=( |
99 | @@ -57,14 +57,14 @@ class Config(Configuration): | |||
100 | 57 | ), | 57 | ), |
101 | 58 | dest="output.dump", | 58 | dest="output.dump", |
102 | 59 | ) | 59 | ) |
104 | 60 | parser.add_argument( | 60 | self.parser.add_argument( |
105 | 61 | "-c", | 61 | "-c", |
106 | 62 | "--config", | 62 | "--config", |
107 | 63 | default="lint-rules.yaml", | 63 | default="lint-rules.yaml", |
108 | 64 | help="File to read lint rules from. Defaults to `lint-rules.yaml`", | 64 | help="File to read lint rules from. Defaults to `lint-rules.yaml`", |
109 | 65 | dest="rules.file", | 65 | dest="rules.file", |
110 | 66 | ) | 66 | ) |
112 | 67 | parser.add_argument( | 67 | self.parser.add_argument( |
113 | 68 | "manual-file", | 68 | "manual-file", |
114 | 69 | metavar="manual-file", | 69 | metavar="manual-file", |
115 | 70 | nargs='?', | 70 | nargs='?', |
116 | @@ -75,7 +75,7 @@ class Config(Configuration): | |||
117 | 75 | "Setting this disables collection of data from remote or local clouds configured via config.yaml." | 75 | "Setting this disables collection of data from remote or local clouds configured via config.yaml." |
118 | 76 | ), | 76 | ), |
119 | 77 | ) | 77 | ) |
121 | 78 | parser.add_argument( | 78 | self.parser.add_argument( |
122 | 79 | "-t", | 79 | "-t", |
123 | 80 | "--cloud-type", | 80 | "--cloud-type", |
124 | 81 | help=( | 81 | help=( |
125 | @@ -83,13 +83,13 @@ class Config(Configuration): | |||
126 | 83 | ), | 83 | ), |
127 | 84 | dest="manual-type", | 84 | dest="manual-type", |
128 | 85 | ) | 85 | ) |
130 | 86 | parser.add_argument( | 86 | self.parser.add_argument( |
131 | 87 | "-o", | 87 | "-o", |
132 | 88 | "--override-subordinate", | 88 | "--override-subordinate", |
133 | 89 | dest="override.subordinate", | 89 | dest="override.subordinate", |
134 | 90 | help="override lint-rules.yaml, e.g. -o canonical-livepatch:all", | 90 | help="override lint-rules.yaml, e.g. -o canonical-livepatch:all", |
135 | 91 | ) | 91 | ) |
137 | 92 | parser.add_argument( | 92 | self.parser.add_argument( |
138 | 93 | "--logfile", | 93 | "--logfile", |
139 | 94 | "-L", | 94 | "-L", |
140 | 95 | default=None, | 95 | default=None, |
141 | @@ -97,5 +97,5 @@ class Config(Configuration): | |||
142 | 97 | dest="logging.file", | 97 | dest="logging.file", |
143 | 98 | ) | 98 | ) |
144 | 99 | 99 | ||
146 | 100 | args = parser.parse_args() | 100 | args = self.parser.parse_args() |
147 | 101 | self.set_args(args, dots=True) | 101 | self.set_args(args, dots=True) |
148 | diff --git a/jujulint/config_default.yaml b/jujulint/config_default.yaml | |||
149 | index 19cbe91..662df79 100644 | |||
150 | --- a/jujulint/config_default.yaml | |||
151 | +++ b/jujulint/config_default.yaml | |||
152 | @@ -1,30 +1,24 @@ | |||
153 | 1 | --- | 1 | --- |
159 | 2 | clouds: | 2 | # clouds: |
160 | 3 | # an example local Juju-deployed OpenStack | 3 | # an example local Juju-deployed OpenStack |
161 | 4 | cloud1: | 4 | # cloud1: |
162 | 5 | type: openstack | 5 | # type: openstack |
163 | 6 | access: local | 6 | # access: local |
164 | 7 | 7 | ||
170 | 8 | # an example remote Juju-deployed OpenStack | 8 | # an example remote Juju-deployed OpenStack |
171 | 9 | cloud2: | 9 | # cloud2: |
172 | 10 | type: openstack | 10 | # type: openstack |
173 | 11 | access: ssh | 11 | # access: ssh |
174 | 12 | host: 'ubuntu@openstack.example.fake' | 12 | # host: 'ubuntu@openstack.example.fake' |
175 | 13 | 13 | ||
190 | 14 | # an exported bundle | 14 | # an example remote Juju-deployed OpenStack where |
191 | 15 | yamlfile: | 15 | # Juju controllers are registered under user 'juju-user |
192 | 16 | type: openstack | 16 | # in this example cloud, so we sudo to that user |
193 | 17 | access: dump | 17 | # cloud3: |
194 | 18 | file: 'export.yaml' | 18 | # type: openstack |
195 | 19 | 19 | # access: ssh | |
196 | 20 | # an example remote Juju-deployed OpenStack where | 20 | # host: 'ubuntu@openstack2.example.fake' |
197 | 21 | # Juju controllers are registered under user 'juju-user | 21 | # sudo: 'juju-user' |
184 | 22 | # in this example cloud, so we sudo to that user | ||
185 | 23 | cloud3: | ||
186 | 24 | type: openstack | ||
187 | 25 | access: ssh | ||
188 | 26 | host: 'ubuntu@openstack2.example.fake' | ||
189 | 27 | sudo: 'juju-user' | ||
198 | 28 | 22 | ||
199 | 29 | logging: | 23 | logging: |
200 | 30 | level: INFO | 24 | level: INFO |
201 | diff --git a/jujulint/lint.py b/jujulint/lint.py | |||
202 | index 92e56d6..a132541 100755 | |||
203 | --- a/jujulint/lint.py | |||
204 | +++ b/jujulint/lint.py | |||
205 | @@ -19,6 +19,7 @@ | |||
206 | 19 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 19 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
207 | 20 | """Lint operations and rule processing engine.""" | 20 | """Lint operations and rule processing engine.""" |
208 | 21 | import collections | 21 | import collections |
209 | 22 | import os.path | ||
210 | 22 | import pprint | 23 | import pprint |
211 | 23 | import re | 24 | import re |
212 | 24 | 25 | ||
213 | @@ -84,30 +85,34 @@ class Linter: | |||
214 | 84 | 85 | ||
215 | 85 | def read_rules(self): | 86 | def read_rules(self): |
216 | 86 | """Read and parse rules from YAML, optionally processing provided overrides.""" | 87 | """Read and parse rules from YAML, optionally processing provided overrides.""" |
229 | 87 | with open(self.filename, "r") as yaml_file: | 88 | if os.path.isfile(self.filename): |
230 | 88 | self.lint_rules = yaml.safe_load(yaml_file) | 89 | with open(self.filename, "r") as yaml_file: |
231 | 89 | if self.overrides: | 90 | self.lint_rules = yaml.safe_load(yaml_file) |
232 | 90 | for override in self.overrides.split("#"): | 91 | if self.overrides: |
233 | 91 | (name, where) = override.split(":") | 92 | for override in self.overrides.split("#"): |
234 | 92 | self.logger.info( | 93 | (name, where) = override.split(":") |
235 | 93 | "[{}] [{}/{}] Overriding {} with {}".format( | 94 | self.logger.info( |
236 | 94 | self.cloud_name, | 95 | "[{}] [{}/{}] Overriding {} with {}".format( |
237 | 95 | self.controller_name, | 96 | self.cloud_name, |
238 | 96 | self.model_name, | 97 | self.controller_name, |
239 | 97 | name, | 98 | self.model_name, |
240 | 98 | where, | 99 | name, |
241 | 100 | where, | ||
242 | 101 | ) | ||
243 | 99 | ) | 102 | ) |
244 | 103 | self.lint_rules["subordinates"][name] = dict(where=where) | ||
245 | 104 | self.lint_rules["known charms"] = flatten_list(self.lint_rules["known charms"]) | ||
246 | 105 | self.logger.debug( | ||
247 | 106 | "[{}] [{}/{}] Lint Rules: {}".format( | ||
248 | 107 | self.cloud_name, | ||
249 | 108 | self.controller_name, | ||
250 | 109 | self.model_name, | ||
251 | 110 | pprint.pformat(self.lint_rules), | ||
252 | 100 | ) | 111 | ) |
253 | 101 | self.lint_rules["subordinates"][name] = dict(where=where) | ||
254 | 102 | self.lint_rules["known charms"] = flatten_list(self.lint_rules["known charms"]) | ||
255 | 103 | self.logger.debug( | ||
256 | 104 | "[{}] [{}/{}] Lint Rules: {}".format( | ||
257 | 105 | self.cloud_name, | ||
258 | 106 | self.controller_name, | ||
259 | 107 | self.model_name, | ||
260 | 108 | pprint.pformat(self.lint_rules), | ||
261 | 109 | ) | 112 | ) |
263 | 110 | ) | 113 | return True |
264 | 114 | self.logger.error("Rules file {} does not exist.".format(self.filename)) | ||
265 | 115 | return False | ||
266 | 111 | 116 | ||
267 | 112 | def process_subordinates(self, app_d, app_name): | 117 | def process_subordinates(self, app_d, app_name): |
268 | 113 | """Iterate over subordinates and run subordinate checks.""" | 118 | """Iterate over subordinates and run subordinate checks.""" |
269 | diff --git a/setup.py b/setup.py | |||
270 | index 4190e7a..b6b3dc9 100644 | |||
271 | --- a/setup.py | |||
272 | +++ b/setup.py | |||
273 | @@ -17,7 +17,6 @@ | |||
274 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
275 | 18 | """Setuptools packaging metadata for juju-lint.""" | 18 | """Setuptools packaging metadata for juju-lint.""" |
276 | 19 | 19 | ||
277 | 20 | import re | ||
278 | 21 | import setuptools | 20 | import setuptools |
279 | 22 | import warnings | 21 | import warnings |
280 | 23 | 22 | ||
281 | @@ -28,9 +27,7 @@ with open("README.md", "r") as fh: | |||
282 | 28 | 27 | ||
283 | 29 | setuptools.setup( | 28 | setuptools.setup( |
284 | 30 | name="jujulint", | 29 | name="jujulint", |
288 | 31 | use_scm_version={ | 30 | use_scm_version={"local_scheme": "node-and-date"}, |
286 | 32 | "local_scheme": "node-and-date", | ||
287 | 33 | }, | ||
289 | 34 | author="Canonical", | 31 | author="Canonical", |
290 | 35 | author_email="juju@lists.ubuntu.com", | 32 | author_email="juju@lists.ubuntu.com", |
291 | 36 | description="Linter for Juju models to compare deployments with configurable policy", | 33 | description="Linter for Juju models to compare deployments with configurable policy", |
292 | @@ -45,7 +42,7 @@ setuptools.setup( | |||
293 | 45 | "Intended Audience :: System Administrators", | 42 | "Intended Audience :: System Administrators", |
294 | 46 | ], | 43 | ], |
295 | 47 | python_requires=">=3.4", | 44 | python_requires=">=3.4", |
297 | 48 | py_modules=["jujulint"], | 45 | packages=["jujulint"], |
298 | 49 | entry_points={"console_scripts": ["juju-lint=jujulint.cli:main"]}, | 46 | entry_points={"console_scripts": ["juju-lint=jujulint.cli:main"]}, |
299 | 50 | setup_requires=["setuptools_scm"], | 47 | setup_requires=["setuptools_scm"], |
300 | 51 | ) | 48 | ) |
301 | diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml | |||
302 | index b8bd6da..9ec50ef 100644 | |||
303 | --- a/snap/snapcraft.yaml | |||
304 | +++ b/snap/snapcraft.yaml | |||
305 | @@ -22,6 +22,7 @@ parts: | |||
306 | 22 | requirements: | 22 | requirements: |
307 | 23 | - requirements.txt | 23 | - requirements.txt |
308 | 24 | source: . | 24 | source: . |
309 | 25 | source-type: git | ||
310 | 25 | override-build: | | 26 | override-build: | |
311 | 26 | snapcraftctl build | 27 | snapcraftctl build |
312 | 27 | echo "Version: $(python3 setup.py --version)" | 28 | echo "Version: $(python3 setup.py --version)" |
This merge proposal is being monitored by mergebot. Change the status to Approved to merge.