diff --git a/blackduck/Client.py b/blackduck/Client.py index 148b4bf..e11479c 100644 --- a/blackduck/Client.py +++ b/blackduck/Client.py @@ -257,6 +257,40 @@ def get_items(self, url, page_size=250, **kwargs): offset += page_size + def get_resource_by(self, field, value, name, parent=None, **kwargs): + params = { + 'q': [f"{field}:{value}"] + } + filtered = [i for i in self.get_resource(name, parent, params=params, **kwargs) if i.get(field) == value] + assert len(filtered) in [0,1], f"We either found the {field} or we didn't, but we should never find this many ({len(filtered)})" + + return filtered[0] if filtered else None + + def get_or_create_resource(self, field, value, name, parent=None, additional_data={}, **kwargs): + the_obj = self.get_resource_by(field, value, name, parent, **kwargs) + if the_obj: + return the_obj + else: + post_data = { + field: value + } + post_data.update(additional_data) + if parent: + url = parent['_meta']['href'] + f"/{name}" + else: + url = f"/api/{name}" + logger.debug(f"Trying to create object using url {url} and post_data {post_data}") + try: + r = self.session.post(url, json=post_data) + r.raise_for_status() + the_obj_url = r.headers['Location'] + except requests.HTTPError as err: + self.http_error_handler(err) + the_obj = self.session.get(the_obj_url).json() + logger.debug(f"Created object at {the_obj_url}") + return the_obj + + @staticmethod def http_error_handler(r): """Handle an unexpected HTTPError or Response by logging useful information. diff --git a/blackduck/__version__.py b/blackduck/__version__.py index 2fef3d7..4eaaf1f 100644 --- a/blackduck/__version__.py +++ b/blackduck/__version__.py @@ -1,3 +1,3 @@ -VERSION = (1, 0, 7) +VERSION = (1, 1, 0) __version__ = '.'.join(map(str, VERSION)) diff --git a/examples/client/crud_project.py b/examples/client/crud_project.py index b8420eb..535437a 100644 --- a/examples/client/crud_project.py +++ b/examples/client/crud_project.py @@ -52,6 +52,13 @@ project_url = bd.list_resources(project)['href'] print(f"project url: {project_url}") +# GET or CREATE +project = bd.get_or_create_resource(name='projects', field='name', value=project_name) +if project: + print(f"project found with name {args.project}") +else: + print(f"no project with name {args.project}") + # PUT project_data = { 'name': project_name, @@ -75,3 +82,31 @@ print("not found") else: bd.http_error_handler(err) + +# GET OR CREATE + +project = bd.get_or_create_resource( + name='projects', + field='name', + value=project_name, + params={ + 'description': 'My project description', + 'projectLevelAdjustments': True + } + ) +project_url = project['_meta']['href'] + +# DELETE +try: + r = bd.session.delete(project_url) + r.raise_for_status() + print("deleted project") +except requests.HTTPError as err: + if err.response.status_code == 404: + print("not found") + else: + bd.http_error_handler(err) + + + + diff --git a/examples/client/crud_version.py b/examples/client/crud_version.py new file mode 100644 index 0000000..9105cbd --- /dev/null +++ b/examples/client/crud_version.py @@ -0,0 +1,136 @@ +from blackduck import Client +from blackduck.constants import PROJECT_VERSION_SETTINGS, VERSION_DISTRIBUTION, VERSION_PHASES + +import argparse +import logging +import requests + +logging.basicConfig( + level=logging.DEBUG, + format="[%(asctime)s] {%(module)s:%(lineno)d} %(levelname)s - %(message)s" +) + +parser = argparse.ArgumentParser("Create, read, update, and delete a project") +parser.add_argument("--base-url", required=True, help="Hub server URL e.g. https://your.blackduck.url") +parser.add_argument("--token-file", dest='token_file', required=True, help="containing access token") +parser.add_argument("--no-verify", dest='verify', action='store_false', help="disable TLS certificate verification") +parser.add_argument("project", help="Project name") +parser.add_argument("version", help="Version name") +args = parser.parse_args() + +with open(args.token_file, 'r') as tf: + access_token = tf.readline().strip() + +bd = Client( + base_url=args.base_url, + token=access_token, + verify=args.verify +) + +project_name = args.project + +# POST project +project_data = { + 'name': project_name, + 'description': "some description", + 'projectLevelAdjustments': True, +} + +try: + r = bd.session.post("/api/projects", json=project_data) + r.raise_for_status() + print(f"created project {r.links['project']['url']}") +except requests.HTTPError as err: + # more fine grained error handling here; otherwise: + bd.http_error_handler(err) + +# GET project +params = { + 'q': [f"name:{project_name}"] +} + +project_obj = None +project_url = None +for project in bd.get_items("/api/projects", params=params): + if project['name'] == project_name: + project_obj = project + project_url = bd.list_resources(project)['href'] + print(f"project url: {project_url}") + +# POST version +version_data = { + 'versionName': args.version, + 'distribution': 'EXTERNAL', + 'phase': 'PLANNING' +} + +versions_url = project_url + "/versions" +try: + r = bd.session.post(versions_url, json=version_data) + r.raise_for_status() + version_url = r.headers['Location'] + print(f"created version {version_url}") +except requests.HTTPError as err: + # more fine grained error handling here; otherwise: + bd.http_error_handler(err) + +# GET or CREATE version + +version = bd.get_or_create_resource(field='versionName', value=args.version, name="versions", parent=project_obj) +print(f"Version {version['versionName']} was either found or created after initial POST") + +# DELETE version +try: + r = bd.session.delete(version_url) + r.raise_for_status() + print(f"deleted version {args.version}") +except requests.HTTPError as err: + if err.response.status_code == 404: + print("not found") + else: + bd.http_error_handler(err) + +# GET or CREATE version +additional_data = { + 'phase': 'PLANNING', + 'distribution': 'SAAS' +} +version = bd.get_or_create_resource(field='versionName', value=args.version, name="versions", parent=project_obj, additional_data=additional_data) +print(f"Version {version['versionName']} was either found or created after deleting the version") + +# DELETE project +try: + r = bd.session.delete(project_url) + r.raise_for_status() + print("deleted project") +except requests.HTTPError as err: + if err.response.status_code == 404: + print("not found") + else: + bd.http_error_handler(err) + + +# GET or CREATE project +additional_data = { + 'description': 'The project description, again', + 'projectLevelAdjustments': True +} + +project = bd.get_or_create_resource(field='name', value=args.project, name='projects', additional_data=additional_data) + +project_url = project['_meta']['href'] + +# DELETE project +try: + r = bd.session.delete(project_url) + r.raise_for_status() + print("deleted project") +except requests.HTTPError as err: + if err.response.status_code == 404: + print("not found") + else: + bd.http_error_handler(err) + + + + diff --git a/examples/client/update_version_settings.py b/examples/client/update_version_settings.py index e0d8022..2f920bc 100644 --- a/examples/client/update_version_settings.py +++ b/examples/client/update_version_settings.py @@ -73,19 +73,23 @@ def validate_settings(settings): verify=args.verify ) -params = { - 'q': [f"name:{args.project_name}"] -} -projects = [p for p in bd.get_resource('projects', params=params) if p['name'] == args.project_name] -assert len(projects) == 1, f"There should be one, and only one project named {args.project_name}. We found {len(projects)}" -project = projects[0] - -params = { - 'q': [f"versionName:{args.version_name}"] -} -versions = [v for v in bd.get_resource('versions', project, params=params) if v['versionName'] == args.version_name] -assert len(versions) == 1, f"There should be one, and only one version named {args.version_name}. We found {len(versions)}" -version = versions[0] +# params = { +# 'q': [f"name:{args.project_name}"] +# } +# projects = [p for p in bd.get_resource('projects', params=params) if p['name'] == args.project_name] +# assert len(projects) == 1, f"There should be one, and only one project named {args.project_name}. We found {len(projects)}" +# project = projects[0] + +project = bd.get_resource_by(name='projects', field='name', value=args.project_name) +version = bd.get_resource_by(name='versions', field='versionName', value=args.version_name, parent=project) +import pdb; pdb.set_trace() + +# params = { +# 'q': [f"versionName:{args.version_name}"] +# } +# versions = [v for v in bd.get_resource('versions', project, params=params) if v['versionName'] == args.version_name] +# assert len(versions) == 1, f"There should be one, and only one version named {args.version_name}. We found {len(versions)}" +# version = versions[0] logging.debug(f"Found {project['name']}:{version['versionName']}")