Skip to content

Commit 417affd

Browse files
committed
Improved dn resource handling - Added dn_resource_scenario1/2/3 - added retrieving parent config in load_configs
1 parent 6db962b commit 417affd

69 files changed

Lines changed: 17178 additions & 16673 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

elmclient/_rm.py

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ def getModuleBindings( self ):
5050
raise Exception( "Save not implemented yet" )
5151
pass
5252

53+
class WrapperResource( resource.Resource ):
54+
name="Wrapper"
55+
5356
class ModuleStructureResource( resource.Resource ):
5457
name = "ModuleStructure"
5558

@@ -134,11 +137,13 @@ def encode( self, pythonvalue ):
134137
# decode an enumeration name to the corresponding URL
135138
# scan the enum urls in this property
136139
enumvalue_u = None
137-
for enum_u in self.properties[self.prop_u]['enums']:
138-
if self.enumers[enum_u]['name']==pythonvalue:
140+
# print( f"{self=}" )
141+
# for enum_u in self.enums[self.prop_u]:
142+
for enum_u in self.projorcomp.enums:
143+
if self.projorcomp.enums[enum_u]['name']==pythonvalue:
139144
enumvalue_u = enum_u
140145
if enumvalue_u is None:
141-
burp
146+
raise Exception( f"Enumeration vlue {pythonvalue} not found in typesystem!" )
142147
thetag=rdfxml.uri_to_tag( self.prop_u )
143148
result_x = ET.Element( thetag, { self.rdf_resource_tag: enumvalue_u } )
144149
# print( f"Encode {pythonvalue=} {result_x=} {ET.tostring( result_x )=}" )
@@ -240,6 +245,12 @@ def __init__(self, name, project_uri, app, is_optin=False, singlemode=False,defa
240245
'acp_serviceProvider',
241246
'rdf_type',
242247
'uses',
248+
'diagram',
249+
'diagramImage',
250+
'wrappedResource',
251+
'wrappedResourceContentType',
252+
'wrappedResourceRevision',
253+
243254
]
244255
# save a folder details, and return the new folder instance
245256
def _savefolder( self, parent, fname, folderuri ):
@@ -377,7 +388,7 @@ def find_folder( self, name_or_path_or_uri, force=False ):
377388

378389
# MUST be provided a path starting with / because if it were just a name we wouldn't know where to create it!
379390
# this will create any missing folders in the path to create the final folder
380-
# new folders are recorded so no need to reoaod the full folder hierarchy!
391+
# new folders are recorded so no need to reload the full folder hierarchy!
381392
def create_folder( self, path ):
382393
if not path.startswith( "/" ):
383394
raise Exception( f"You *must* provide a path starting with / for the new folder otherwise don't know where to create it! You provided {path}" )
@@ -753,22 +764,27 @@ def load_configs(self, cacheable=True, stopatnameoruri=None, verbose=False, incr
753764
else:
754765
raise Exception( f"Unrecognized configuration type {confmember_x.tag}" )
755766

767+
# use wasDerivedfrom to find the source or eaither a stream or baseline - there isn't one for the Initial Stream!
768+
theparent_u = rdfxml.xmlrdf_get_resource_uri( confmember_x,'./prov:wasDerivedFrom')
769+
# print( f"{theparent_u=}" )
756770

757771
if thisconfu in self._configurations:
758772
logger.debug( f"Skipping {thisconfu} because already defined" )
759773
# print( f"Skipping {thisconfu} because already defined" )
760774
else:
761775
logger.debug( f"Adding {conftitle}" )
762-
# print( f"Adding {conftitle}" )
776+
# print( f"Adding {conftitle} {theparent_u=}" )
777+
763778
self._configurations[thisconfu] = {
764779
'name': conftitle
765780
,'conftype': conftype
766781
,'confXml': confmember_x
767782
,'created': created
783+
,'parentConfig': theparent_u
768784
}
769785
# self._configurations[thisconfu] = self._components[self.project_uri]['configurations'][thisconfu]
770786
# use wasDerivedfrom to find the source or eaither a stream or baseline - there isn't one for the Initial Stream!
771-
theparent_u = rdfxml.xmlrdf_get_resource_uri( confmember_x,'./prov:wasDerivedFrom')
787+
# theparent_u = rdfxml.xmlrdf_get_resource_uri( confmember_x,'./prov:wasDerivedFrom')
772788
# print( f"{theparent_u=}" )
773789
if not theparent_u:
774790
# this is the initial stream
@@ -975,7 +991,7 @@ def list_configs( self ):
975991
return configs
976992

977993
# for RM, load the typesystem using the OSLC shape resources listed for the Requirements and Requirements Collection creation factories
978-
def _load_types(self,force=False):
994+
def _load_types(self,force=False, verbose=True ):
979995
logger.debug( f"load type {self=} {force=}" )
980996
# if already loaded, try to avoid reloading
981997
if self.typesystem_loaded and not force:
@@ -991,14 +1007,16 @@ def _load_types(self,force=False):
9911007
sx = self.get_services_xml(force=True)
9921008
if sx:
9931009
shapes_to_load = rdfxml.xml_find_elements(sx, './/oslc:resourceShape' )
994-
995-
pbar = tqdm.tqdm(initial=0, total=len(shapes_to_load),smoothing=1,unit=" results",desc="Loading DN shapes")
1010+
if verbose:
1011+
pbar = tqdm.tqdm(initial=0, total=len(shapes_to_load),smoothing=1,unit=" results",desc="Loading DN shapes")
9961012

9971013
for el in shapes_to_load:
9981014
self._load_type_from_resource_shape(el)
999-
pbar.update(1)
1015+
if verbose:
1016+
pbar.update(1)
10001017

1001-
pbar.close()
1018+
if verbose:
1019+
pbar.close()
10021020

10031021
else:
10041022
raise Exception( "services xml not found!" )
@@ -1183,6 +1201,12 @@ def mapUnknownProperty( self, property_name, property_uri, shape_uri ):
11831201
# add type to properties
11841202
self.register_property( property_name, property_uri, typeCodec=RDFURICodec, isMultiValued=True, shape_uri=shape_uri )
11851203
return True
1204+
elif property_uri=="http://www.ibm.com/xmlns/rm/public/1.0/wrappedResourceRevision" or property_uri=="http://www.ibm.com/xmlns/rm/public/1.0/wrappedResourceContentType" or property_uri=="http://www.ibm.com/xmlns/rm/public/1.0/wrappedResource" or property_uri=="http://www.ibm.com/xmlns/rdm/rdf/diagram" or property_uri=="http://www.ibm.com/xmlns/rdm/rdf/diagramImage":
1205+
# add property to shape
1206+
self.shapes[shape_uri]['properties'].append( property_uri )
1207+
# add type to properties
1208+
self.register_property( property_name, property_uri, typeCodec=RDFURICodec, isMultiValued=False, shape_uri=shape_uri )
1209+
return True
11861210
return False
11871211

11881212
# return a dictionary with all local component uri as key and name as value (so two components could have the same name?)
@@ -1886,11 +1910,11 @@ def find_pa_comp_from_config( self, configurl ):
18861910
return (pa_u,comp_u)
18871911

18881912
# load the typesystem using the OSLC shape resources listed for all the creation factories and query capabilities
1889-
def load_types(self, force=False):
1890-
self._load_types(force)
1913+
def load_types(self, force=False, verbose=True ):
1914+
self._load_types(force, verbose=verbose )
18911915

18921916
# load the typesystem using the OSLC shape resources
1893-
def _load_types(self,force=False):
1917+
def _load_types(self,force=False, verbose=True):
18941918
logger.debug( f"load type {self=} {force=}" )
18951919

18961920
# if already loaded, try to avoid reloading
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
##
2+
## © Copyright 2025- IBM Inc. All rights reserved
3+
# SPDX-License-Identifier: MIT
4+
##
5+
6+
#######################################################################################################
7+
#
8+
# elmclient DN Resources sample
9+
#
10+
# DN scenario 1: Find artifacts that are Stakeholder Requirements with Status set to "In Process" and add the word METERING at the start of the Title
11+
#
12+
13+
#parameters
14+
15+
jazzhost = 'https://jazz.ibm.com:9443'
16+
17+
username = 'ibm'
18+
password = 'ibm'
19+
20+
jtscontext = 'jts'
21+
rmcontext = 'rm'
22+
23+
# the project+compontent+config that will be updated
24+
proj = "rm_optin_p2"
25+
comp = proj
26+
conf = f"{comp} Initial Stream"
27+
28+
# provide on the commandline the id of an artifact in the project/component/configuration
29+
# also provide on the commandline a string (surrounded in " if it includes space) and this will be put on the front of the existing text of the artifact
30+
31+
import logging
32+
import os.path
33+
import sys
34+
import time
35+
36+
import lxml.etree as ET
37+
38+
import elmclient.server as elmserver
39+
import elmclient.utils as utils
40+
import elmclient.rdfxml as rdfxml
41+
42+
# setup logging - see levels in utils.py - TRACE,OFF means that a log of all http communication is put in the logs folder below wherever this example is run
43+
#loglevel = "INFO,INFO"
44+
loglevel = "TRACE,OFF"
45+
levels = [utils.loglevels.get(l,-1) for l in loglevel.split(",",1)]
46+
if len(levels)<2:
47+
# assert console logging level OFF if not provided
48+
levels.append(None)
49+
if -1 in levels:
50+
raise Exception( f'Logging level {loglevel} not valid - should be comma-separated one or two values from DEBUG, INFO, WARNING, ERROR, CRITICAL, OFF' )
51+
52+
utils.setup_logging( filelevel=levels[0], consolelevel=levels[1] )
53+
54+
logger = logging.getLogger(__name__)
55+
56+
utils.log_commandline( os.path.basename(sys.argv[0]) )
57+
58+
# caching control
59+
# 0=fully cached (but code below specifies queries aren't cached) - if you need to clear the cache, delet efolder .web_cache
60+
# 1=clear cache initially then continue with cache enabled
61+
# 2=clear cache and disable caching
62+
caching = 2
63+
64+
##################################################################################
65+
if __name__=="__main__":
66+
67+
#####################################################################################################
68+
# create our "server" which is how we connect to DOORS Next
69+
# first enable the proxy so if a proxy is running it can monitor the communication with server (this is ignored if proxy isn't running)
70+
elmserver.setupproxy(jazzhost,proxyport=8888)
71+
theserver = elmserver.JazzTeamServer(jazzhost, username, password, verifysslcerts=False, jtsappstring=f"jts:{jtscontext}", appstring='rm', cachingcontrol=caching)
72+
73+
#####################################################################################################
74+
# create the RM application interface
75+
dnapp = theserver.find_app( f"rm:{rmcontext}", ok_to_create=True )
76+
77+
#####################################################################################################
78+
# open the project
79+
p = dnapp.find_project(proj)
80+
81+
#####################################################################################################
82+
# find the component
83+
c = p.find_local_component(comp)
84+
print( f"{c=}" )
85+
comp_u = c.project_uri
86+
print( f"{comp_u=}" )
87+
88+
#####################################################################################################
89+
# select the configuration
90+
config_u = c.get_local_config(conf)
91+
print( f"{config_u=}" )
92+
c.set_local_config(config_u)
93+
94+
#####################################################################################################
95+
# find artifacts which are Stakeholder Requirements and have Status "In Process"
96+
artifacts = c.resourceQuery( "oslc:instanceShape='Stakeholder Requirement' and Status='In Process'", returnBaseArtifacts=True, returnBindings=False )
97+
98+
#####################################################################################################
99+
# go through the results looking for meter in the Title
100+
for i,a in enumerate( artifacts ):
101+
# filter for meter in the title
102+
if 'meter' in a.Title:
103+
104+
# print the resource (artifact) details
105+
print( f"**************************\nResult {i}\n{a}" )
106+
107+
# update the artifact Title
108+
a.Title ="METERING "+a.Title
109+
print( "Title is now "+a.Title )
110+
111+
# save the update back into DOORS Next
112+
a.put()
113+
print( f"{a.Identifier} {a._url} Updated in DOORS Next\n" )
114+
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
##
2+
## © Copyright 2025- IBM Inc. All rights reserved
3+
# SPDX-License-Identifier: MIT
4+
##
5+
6+
#######################################################################################################
7+
#
8+
# elmclient DN Resources sample
9+
#
10+
# DN scenario 2: Find artifacts that are Stakeholder Requirements with Status set to "In Process" and change their status to Approved
11+
#
12+
13+
#parameters
14+
15+
jazzhost = 'https://jazz.ibm.com:9443'
16+
17+
username = 'ibm'
18+
password = 'ibm'
19+
20+
jtscontext = 'jts'
21+
rmcontext = 'rm'
22+
23+
# the project+compontent+config that will be updated
24+
proj = "rm_optin_p2"
25+
comp = proj
26+
conf = f"{comp} Initial Stream"
27+
28+
# provide on the commandline the id of an artifact in the project/component/configuration
29+
# also provide on the commandline a string (surrounded in " if it includes space) and this will be put on the front of the existing text of the artifact
30+
31+
import logging
32+
import os.path
33+
import sys
34+
import time
35+
36+
import lxml.etree as ET
37+
38+
import elmclient.server as elmserver
39+
import elmclient.utils as utils
40+
import elmclient.rdfxml as rdfxml
41+
42+
# setup logging - see levels in utils.py - TRACE,OFF means that a log of all http communication is put in the logs folder below wherever this example is run
43+
#loglevel = "INFO,INFO"
44+
loglevel = "TRACE,OFF"
45+
levels = [utils.loglevels.get(l,-1) for l in loglevel.split(",",1)]
46+
if len(levels)<2:
47+
# assert console logging level OFF if not provided
48+
levels.append(None)
49+
if -1 in levels:
50+
raise Exception( f'Logging level {loglevel} not valid - should be comma-separated one or two values from DEBUG, INFO, WARNING, ERROR, CRITICAL, OFF' )
51+
52+
utils.setup_logging( filelevel=levels[0], consolelevel=levels[1] )
53+
54+
logger = logging.getLogger(__name__)
55+
56+
utils.log_commandline( os.path.basename(sys.argv[0]) )
57+
58+
# caching control
59+
# 0=fully cached (but code below specifies queries aren't cached) - if you need to clear the cache, delet efolder .web_cache
60+
# 1=clear cache initially then continue with cache enabled
61+
# 2=clear cache and disable caching
62+
caching = 0
63+
64+
##################################################################################
65+
if __name__=="__main__":
66+
67+
#####################################################################################################
68+
# create our "server" which is how we connect to DOORS Next
69+
# first enable the proxy so if a proxy is running it can monitor the communication with server (this is ignored if proxy isn't running)
70+
elmserver.setupproxy(jazzhost,proxyport=8888)
71+
theserver = elmserver.JazzTeamServer(jazzhost, username, password, verifysslcerts=False, jtsappstring=f"jts:{jtscontext}", appstring='rm', cachingcontrol=caching)
72+
73+
#####################################################################################################
74+
# create the RM application interface
75+
dnapp = theserver.find_app( f"rm:{rmcontext}", ok_to_create=True )
76+
77+
#####################################################################################################
78+
# open the project
79+
p = dnapp.find_project(proj)
80+
81+
#####################################################################################################
82+
# find the component
83+
c = p.find_local_component(comp)
84+
print( f"{c=}" )
85+
comp_u = c.project_uri
86+
print( f"{comp_u=}" )
87+
88+
#####################################################################################################
89+
# select the configuration
90+
config_u = c.get_local_config(conf)
91+
print( f"{config_u=}" )
92+
c.set_local_config(config_u)
93+
94+
#####################################################################################################
95+
# find artifacts which are Stakeholder Requirements and have Status "In Process"
96+
artifacts = c.resourceQuery( "oslc:instanceShape='Stakeholder Requirement' and Status='In Process'", returnBaseArtifacts=True, returnBindings=False )
97+
98+
for i,a in enumerate( artifacts ):
99+
# filter for meter in the title
100+
if 'meter' in a.Title:
101+
# print the resource (artifact) details
102+
print( f"**************************\nResult {i}\n{a}" )
103+
104+
# update the Status
105+
a.Status="Approved"
106+
107+
a.Title ="SET TO APPROVED "+a.Title
108+
print( "Title is now "+a.Title )
109+
110+
# save the update back into DOORS Next
111+
a.put()
112+
print( f"{a.Identifier} {a._url} Updated in DOORS Next" )
113+

0 commit comments

Comments
 (0)