1+ #!/usr/bin/env python
2+
3+ '''
4+ Purpose: Update project versions with licenses of their subprojects (components)
5+
6+ usage: update_project_with_component_licenses.py [-h] -u BASE_URL -t TOKEN_FILE [-nv]
7+
8+ options:
9+ -h, --help show this help message and exit
10+ -u BASE_URL, --base-url BASE_URL
11+ Hub server URL e.g. https://your.blackduck.url
12+ -t TOKEN_FILE, --token-file TOKEN_FILE
13+ containing access token
14+ -nv, --no-verify disable TLS certificate verification
15+ -p PROJECT_NAME, --project-name PROJECT_NAME
16+ Project Name
17+ -pv VERSION_NAME, --version-name VERSION_NAME
18+ Project Version Name
19+ '''
20+
21+ import argparse
22+ import json
23+ import logging
24+ import sys
25+ import requests
26+
27+ from pprint import pprint
28+ from blackduck import Client
29+ from collections import defaultdict
30+
31+ def parse_command_args ():
32+ parser = argparse .ArgumentParser ("update_project_with_component_licenses.py [-h] -u BASE_URL -t TOKEN_FILE [-nv] " )
33+ parser .add_argument ("-u" , "--base-url" , required = True , help = "Hub server URL e.g. https://your.blackduck.url" )
34+ parser .add_argument ("-t" , "--token-file" , dest = 'token_file' , required = True , help = "containing access token" )
35+ parser .add_argument ("-nv" , "--no-verify" , dest = 'no_verify' , action = 'store_false' , help = "disable TLS certificate verification" )
36+ parser .add_argument ("-p" , "--project_name" , required = True , help = "Provide Project Name here" )
37+ parser .add_argument ("-v" , "--version_name" ). help = "Provide Project Version here"
38+ return parser .parse_args ()
39+
40+ def main ():
41+ args = parse_command_args ()
42+ with open (args .token_file , 'r' ) as tf :
43+ access_token = tf .readline ().strip ()
44+ global bd
45+ bd = Client (base_url = args .base_url , token = access_token , verify = args .no_verify , timeout = 60.0 , retries = 4 )
46+ process_project_version (args .project_name , args .version_name , args )
47+
48+ def process_project_version (project_name , version_name , args ):
49+ #Validating only 1 Project
50+ params = {
51+ 'q' : [f"name:{ args .project_name } " ]
52+ }
53+ projects = [p for p in bd .get_resource ('projects' , params = params ) if p ['name' ] == args .project_name ]
54+ assert len (projects ) == 1 , f"There should be one, and only one project named { args .project_name } . We found { len (projects )} "
55+ project = projects [0 ]
56+
57+ #Validates only 1 Version
58+ params = {
59+ 'q' : [f"versionName:{ args .version_name } " ]
60+ }
61+ versions = [v for v in bd .get_resource ('versions' , project , params = params ) if v ['versionName' ] == args .version_name ]
62+ assert len (versions ) == 1 , f"There should be one, and only one version named { args .version_name } . We found { len (versions )} "
63+ version = versions [0 ]
64+
65+
66+
67+ #Return only sub-projects, not components
68+ components = (
69+ c for c in bd .get_resource ('components' ,version ) if c ['componentType' ] == "SUB_PROJECT"
70+ )
71+ for components in components :
72+ #JSON body
73+ body = defaultdict (list )
74+
75+ existing_licenses = []
76+
77+ #Defining subcomponents
78+ body ["componentName" ]= components ['componentName' ]
79+ body ["componentVersionName" ]= components ['componentVersionName' ]
80+ body ["component" ]= components ['component' ]
81+ body ["componentVersion" ]= components ['componentVersion' ]
82+ body ["componentType" ]= "SUB_PROJECT"
83+ pprint (components ['componentName' ])
84+ pprint (components ['componentVersionName' ])
85+ url = components ['_meta' ]['href' ]
86+ #Capture current License statement of components to add to
87+ if len (components ['licenses' ][0 ]['licenses' ]) > 0 :
88+ for i , v in enumerate (components ['licenses' ][0 ]['licenses' ]):
89+ parent_license_display = components ['licenses' ][0 ]['licenses' ][i ]['licenseDisplay' ]
90+ parent_license = components ['licenses' ][0 ]['licenses' ][i ]['license' ]
91+ addlicense = {"licenseDisplay" :parent_license_display ,"license" : parent_license }
92+ body ['licenses' ].append (addlicense )
93+ if parent_license_display not in existing_licenses :
94+ existing_licenses .append (parent_license_display )
95+ else :
96+ parent_license_display = components ['licenses' ][0 ]['licenses' ][0 ]['licenseDisplay' ]
97+ parent_license = components ['licenses' ][0 ]['licenses' ][0 ]['license' ]
98+ addlicense = {"licenseDisplay" :parent_license_display ,"license" : parent_license }
99+ body ['licenses' ].append (addlicense )
100+ if parent_license_display not in existing_licenses :
101+ existing_licenses .append (parent_license_display )
102+ #Retrieving componentName values
103+ subprojects = [p for p in bd .get_resource ('projects' ) if p ['name' ] == components ['componentName' ]]
104+ subproject = subprojects [0 ]
105+ subversions = [v for v in bd .get_resource ('versions' , subproject ) if v ['versionName' ] == components ['componentVersionName' ]]
106+ subversion = subversions [0 ]
107+ for subcomponent in bd .get_resource ('components' ,subversion ):
108+ #Parse through multiple licenses
109+ if len (subcomponent ['licenses' ][0 ]['licenses' ]) > 0 :
110+ for i , v in enumerate (subcomponent ['licenses' ][0 ]['licenses' ]):
111+ child_license_display = subcomponent ['licenses' ][0 ]['licenses' ][i ]['licenseDisplay' ]
112+ child_license = subcomponent ['licenses' ][0 ]['licenses' ][i ]['license' ]
113+ addlicense = {"licenseDisplay" :child_license_display ,"license" : child_license }
114+ if child_license_display not in existing_licenses :
115+ body ['licenses' ].append (addlicense )
116+ existing_licenses .append (child_license_display )
117+ #When only one license return it
118+ else :
119+ child_license_display = subcomponent ['licenses' ][0 ]['licenseDisplay' ]
120+ child_license = subcomponent ['licenses' ][0 ]['license' ]
121+ addlicense = {"licenseDisplay" :child_license_display ,"license" : child_license }
122+ if child_license_display not in existing_licenses :
123+ body ['licenses' ].append (addlicense )
124+ existing_licenses .append (child_license_display )
125+ pprint (dict (body ))
126+ try :
127+ r = bd .session .put (url ,json = (dict (body )))
128+ if r .status_code == 200 :
129+ print ("updated project" )
130+ except requests .HTTPError as err :
131+ bd .http_error_handler (err )
132+ if __name__ == "__main__" :
133+ sys .exit (main ())
0 commit comments