Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Spredzy/4278cfaba5f12b834bc530fe0a4fed2f to your computer and use it in GitHub Desktop.
Save Spredzy/4278cfaba5f12b834bc530fe0a4fed2f to your computer and use it in GitHub Desktop.
diff --git a/cli/__init__.py b/cli/__init__.py
index ce51245..fea8c0a 100644
--- a/cli/__init__.py
+++ b/cli/__init__.py
@@ -146,7 +146,7 @@ class CLI(with_metaclass(ABCMeta, object)):
Actually runs a child defined method using the execute_<action> pattern
"""
fn = getattr(self, "execute_%s" % self.action)
- fn()
+ return fn()
@abstractmethod
def run(self):
diff --git a/cli/galaxy.py b/cli/galaxy.py
index 3b0192d..bec5c22 100644
--- a/cli/galaxy.py
+++ b/cli/galaxy.py
@@ -53,7 +53,7 @@ class GalaxyCLI(CLI):
'''command to manage Ansible roles in shared repostories, the default of which is Ansible Galaxy *https://galaxy.ansible.com*.'''
SKIP_INFO_KEYS = ("name", "description", "readme_html", "related", "summary_fields", "average_aw_composite", "average_aw_score", "url" )
- VALID_ACTIONS = ("delete", "import", "info", "init", "install", "list", "login", "remove", "search", "setup")
+ VALID_ACTIONS = ("delete", "import", "info", "init", "install", "list", "login", "remove", "search", "setup", "validate")
def __init__(self, args):
self.api = None
@@ -110,9 +110,11 @@ class GalaxyCLI(CLI):
self.parser.add_option('--remove', dest='remove_id', default=None,
help='Remove the integration matching the provided ID value. Use --list to see ID values.')
self.parser.add_option('--list', dest="setup_list", action='store_true', default=False, help='List all of your integrations.')
+ elif self.action == "validate":
+ self.parser.set_usage("usage: %prog validate [options] role_name")
# options that apply to more than one action
- if self.action in ['init', 'info']:
+ if self.action in ['init', 'info', 'validate']:
self.parser.add_option( '--offline', dest='offline', default=False, action='store_true', help="Don't query the galaxy API when creating roles")
if self.action not in ("delete","import","init","login","setup"):
@@ -150,7 +152,7 @@ class GalaxyCLI(CLI):
super(GalaxyCLI, self).run()
self.api = GalaxyAPI(self.galaxy)
- self.execute()
+ return self.execute()
def exit_without_ignore(self, rc=1):
"""
@@ -185,6 +187,27 @@ class GalaxyCLI(CLI):
# execute actions
############################
+ def execute_validate(self):
+ """
+ Runs functions that validates the compliance of a role to be uploaded to Galaxy.
+ """
+
+ role = None
+ role_name = self.args.pop(0).strip() if self.args else None
+ roles_path = self.get_opt('roles_path')
+
+ for role_path in roles_path:
+ if os.path.exists('%s/%s' % (role_path, role_name)):
+ role = GalaxyRole(self.galaxy, role_name,
+ path='%s/%s' % (role_path, role_name))
+ break
+ if not role:
+ if os.path.exists(role_name):
+ role = GalaxyRole(self.galaxy, role_name,
+ path='%s' % role_name)
+
+ return 0 if role.is_valid() else 1
+
def execute_init(self):
"""
creates the skeleton framework of a role that complies with the galaxy metadata format.
diff --git a/galaxy/role.py b/galaxy/role.py
index 369c66d..b8b46dd 100644
--- a/galaxy/role.py
+++ b/galaxy/role.py
@@ -23,6 +23,8 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import datetime
+import glob
+import json
import os
import tarfile
import tempfile
@@ -364,3 +366,103 @@ class GalaxyRole(object):
}
"""
return dict(scm=self.scm, src=self.src, version=self.version, name=self.name)
+
+ def is_valid(self):
+ """
+ Run sanity check validation to ensure role is compliant with what is expected on Galaxy side
+ """
+
+ results = []
+
+ # ROLE001
+ role001_result = {
+ 'name': 'ROLE001',
+ 'description': 'Role has a meta/mail.yml file',
+ 'optional': False,
+ 'pass': os.path.exists('%s/meta/main.yml' % self.path)
+ }
+ results.append(role001_result)
+
+ # ROLE002
+ role002_result = {
+ 'name': 'ROLE002',
+ 'description': 'A LICENSE file is present in the role directory',
+ 'optional': True,
+ 'pass': os.path.exists('%s/LICENSE' % self.path)
+ }
+ results.append(role002_result)
+
+ # ROLE003
+ role003_result = {
+ 'name': 'ROLE003',
+ 'optional': False,
+ 'description': 'A README.md file is present in the role directory',
+ 'pass': os.path.exists('%s/README.md' % self.path)
+ }
+ results.append(role003_result)
+
+ # ROLE004
+ meta = yaml.load(open('%s/meta/main.yml' % self.path).read())
+ keys = ['author', 'description', 'license', 'min_ansible_version']
+ role004_result = {
+ 'name': 'ROLE004',
+ 'description': 'meta/main.yml contains basic necessary informations',
+ 'optional': False,
+ 'pass': set(keys) <= set(meta['galaxy_info'].keys())
+ }
+ results.append(role004_result)
+
+ # ROLE005
+ variables = {}
+ role_name = os.path.basename(self.path)
+ if role_name.startswith('ansible-role-'):
+ role_name = role_name.replace('ansible-role-', '')
+ role_name = role_name.replace('-', '_')
+ if os.path.isdir('%s/vars'):
+ for filename in glob.glob('*.yml'):
+ variables.update(yaml.load(open(filename, 'r').read()))
+ if os.path.isdir('%s/defaults' % self.path):
+ for filename in glob.glob('%s/defaults/*.yml' % self.path):
+ variables.update(yaml.load(open(filename, 'r').read()))
+
+ role005_result = {
+ 'name': 'ROLE005',
+ 'description': 'Variables in defaults/ and vars/ are preceded by role name: %s' % role_name,
+ 'optional': True,
+ 'pass': not len(
+ [v for v in variables.keys() if not v.startswith(role_name)]
+ )
+ }
+ results.append(role005_result)
+
+ # ROLE006
+ # TODO(spredzy): Handle the complex dependency format
+ #
+ if not self.options.offline:
+ meta = yaml.load(open('%s/meta/main.yml' % self.path).read())
+ result = True
+ fail_deps = []
+ if 'dependencies' in meta and meta['dependencies']:
+ for dep in meta['dependencies']:
+ url = 'https://galaxy.ansible.com/api/v1/roles/?namespace=%s&name=%s&format=json' % (dep.split('.')[0], dep.split('.')[1])
+ if json.loads(open_url(url).read())['count'] == 0:
+ fail_deps.append(dep)
+
+ result = not len(fail_deps)
+ role006_result = {
+ 'name': 'ROLE006',
+ 'optional': False,
+ 'description': 'The dependencies listed in meta/main.yml are in Galaxy',
+ 'pass': result
+ }
+ results.append(role006_result)
+
+ failed_results = [result for result in results if result['pass'] is False]
+ is_valid = not len(failed_results)
+
+ if is_valid:
+ display.v(str(results))
+ else:
+ display.display(str(failed_results))
+
+ return is_valid
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment