Skip to content

Commit a68cd57

Browse files
committed
fixed using a specific config, build 0.27.0 - new eamples of dncompare, validate, trsreader (UNFINISHED!)
Incorporated suggestions from wulmer to allow use in docker PR #69 Also incorporated wulmer's PR #67
1 parent 053008c commit a68cd57

Some content is hidden

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

77 files changed

+16838
-15004
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.26.2
2+
current_version = 0.27.0
33
commit = True
44
tag = True
55

README.md

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,17 @@
88

99
SPDX-License-Identifier: MIT
1010

11-
version="0.26.2"
11+
version="0.27.0"
1212

1313
What's New?
1414
===========
1515

16+
02-Dec-2024
17+
* Added examples dncompare, validate, trsreader (this is VERY UNFINISHED!) - see the code in the examples folder
18+
* Fixed oslcquery working from a specific config using -F
19+
* Fixed oslcquery when trying to select a scoped attribute like `oslc:rm:uses{dcterms:identifier}` wasn't working - note that DN doesn't appear to support retreiving primary text of all artifacts in a module using `oslc:rm:uses{jazz_rm:primaryText}` - text isn't returned
20+
* Some (unfinished!) internal preparation for demonstrator of the new in 7.1 type query capability https://jazz.net/wiki/bin/view/Main/DNGTypeAPI
21+
1622
11-Dec-2023
1723
* Added _validate.py to provide the Validate API, available on all apps (may need to restrict this to just ccm/gc/qm/rm?)
1824
* Added examples/validate.py as an example of using the validate API - for most options refer to oslcquery readme
@@ -153,45 +159,34 @@ This code provides examples of using various ELM APIs:
153159

154160
* DN
155161

156-
** Process - `elmclient`
157-
158-
** OSLC including OSLC Query - `oslcquery.py` for user use, internally `oslcqueryapi.py` implements OSLC Query parsing and querying
159-
160-
** Module Structure - `dn_simple_modulestructure.py` - currently external to `elmclient`
161-
162-
** ReqIF - `reqif_io.py` - currently reqif API is external to `elmclient`
163-
164-
** Reportable REST (incomplete for qm and ccm) - `represt.py` for user use, internally for each application in `_rm.py`, `_ccm.py`, `_qm.py`
165-
162+
* Process - `elmclient`
163+
* OSLC including OSLC Query - `oslcquery.py` for user use, internally `oslcqueryapi.py` implements OSLC Query parsing and querying
164+
* Module Structure - `dn_simple_modulestructure.py` - currently external to `elmclient`
165+
* ReqIF - `reqif_io.py` - currently reqif API is external to `elmclient`
166+
* Reportable REST (incomplete for qm and ccm) - `represt.py` for user use, internally for each application in `_rm.py`, `_ccm.py`, `_qm.py`
166167

167168
* ETM
168169

169-
** Process - `elmclient`
170-
171-
** OSLC including OSLC Query - `oslcquery.py` for user use, internally `oslcqueryapi.py` implements OSLC Query parsing and querying
172-
173-
** Reportable REST (incomplete for qm and ccm) - `represt.py` for user use, internally for each application in `_rm.py`, `_ccm.py`, `_qm.py`
174-
170+
* Process - `elmclient`
171+
* OSLC including OSLC Query - `oslcquery.py` for user use, internally `oslcqueryapi.py` implements OSLC Query parsing and querying
172+
* Reportable REST (incomplete for qm and ccm) - `represt.py` for user use, internally for each application in `_rm.py`, `_ccm.py`, `_qm.py`
175173

176174
* EWM
177175

178-
** Process - `elmclient`
179-
180-
** OSLC including OSLC Query - `oslcquery.py` for user use, internally `oslcqueryapi.py` implements OSLC Query parsing and querying
181-
182-
** Reportable REST (incomplete for qm and ccm) - `represt.py` for user use, internally for each application in `_rm.py`, `_ccm.py`, `_qm.py`
176+
* Process - `elmclient`
177+
* OSLC including OSLC Query - `oslcquery.py` for user use, internally `oslcqueryapi.py` implements OSLC Query parsing and querying
178+
* Reportable REST (incomplete for qm and ccm) - `represt.py` for user use, internally for each application in `_rm.py`, `_ccm.py`, `_qm.py`
183179

184180

185181
* GCM
186182

187-
** Process - `elmclient`
188-
189-
** OSLC including OSLC Query - `oslcquery.py` for user use, internally `oslcqueryapi.py` implements OSLC Query parsing and querying
183+
* Process - `elmclient`
184+
* OSLC including OSLC Query - `oslcquery.py` for user use, internally `oslcqueryapi.py` implements OSLC Query parsing and querying
190185

191186

192187
Reporting issues, and contributing
193188
==================================
194189

195190
If you find a problem with elmclient you can report it on the github issues https://github.com/IBM/ELM-Python-Client/issues - note this is just for issues with elmclient code. All other issues will likely be closed immediately.
196191

197-
You can do a pull request to propose updates - there's no guarantee of if/when/how these will be merged but we certainly hope to benefit from contributions!
192+
You can do a pull request to propose updates - there's no guarantee of if/when/how these will be merged but we certainly hope to benefit from contributions!

elmclient/__meta__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
app = 'elmoslcquery'
1111
description = 'Commandline OSLC query for ELM'
12-
version = '0.26.2'
12+
version = '0.27.0'
1313
license = 'MIT'
1414
author_name = 'Ian Barnard'
1515
author_mail = '[email protected]'

elmclient/_ccm.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ def is_type_uri(self, uri):
252252

253253
def resolve_uri_to_name(self, uri, trytouseasid=False):
254254
logger.info( f"resolve_uri_to_name {uri=}" )
255+
# return self.__super__.resolve_uri_to_name(self, uri, trytouseasid=True)
255256
if not uri:
256257
result = None
257258
return result

elmclient/_qm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def load_components_and_configurations(self,force=False):
107107

108108
components_uri = rdfxml.xmlrdf_get_resource_uri(cmsp_xml, './/rdf:Description/rdf:type[@rdf:resource="http://open-services.net/ns/core#QueryCapability"]/../oslc:resourceType[@rdf:resource="http://open-services.net/ns/config#Component"]/../oslc:queryBase')
109109
logger.info( f"{components_uri=}" )
110-
print( f"{components_uri=}" )
110+
# print( f"{components_uri=}" )
111111
# get all components
112112
crx = self.execute_get_xml( components_uri, intent="Retrieve component definition" )
113113
logger.info( f"{crx=}" )

elmclient/_queryparser.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ def do_oslcand(self, s):
244244

245245
def term(self, s):
246246
# if RHS (or for in any of the items in RHS list) is a valueidentifier without a prefix, this uses the lhs to resolve the valueidentifier, i.e. as context for attribute value names
247-
# or if RHS is an untyped literal then LHS is used to appy ^^type:name to it to make it a typedliteral
247+
# or if RHS is an untyped literal then LHS is used to apply ^^type:name to it to make it a typedliteral
248248
# check if first elem is a property identifier, and if so see if value(s) are identifiers if so resolve them in context of the first identifier (e.g. for enum values)
249249
logger.info( f"Term {type(s)} {s}" )
250250
identifier, op, value = s
@@ -539,10 +539,11 @@ def scoped_term(self, s):
539539

540540
# from https://tools.oasis-open.org/version-control/svn/oslc-core/trunk/specs/oslc-core.html#selectiveProperties
541541
# with slight tweaks to implement identifier
542+
# NOTE that for oslc.select NAME can be terminated by { or } to allow for nested properties
542543
_select_grammar ="""
543544
select_terms : properties
544545
properties : property ("," property)*
545-
property : dottedname | identifier | wildcard | nested_prop
546+
property : dottedname | nested_prop | identifier | wildcard
546547
dottedname : NAME "." NAME
547548
nested_prop : (identifier | wildcard) "{" properties "}"
548549
wildcard : "*"
@@ -551,7 +552,7 @@ def scoped_term(self, s):
551552
| "'" SPACYNAME "'"
552553
553554
URI_REF_ESC : /<https?:.*>/
554-
NAME : /[a-zA-Z0-9_][^, ]*/
555+
NAME : /[a-zA-Z0-9_][^, {}]*/
555556
SPACYNAME : /[a-zA-Z0-9_][^']*/
556557
"""
557558

@@ -583,13 +584,17 @@ def __init__(self, resolverobject):
583584
self.prefixes = {} # prefixes used (will have to be added to oslc.prefix) - NOTE the key is the uri, the value is the prefix!
584585

585586
def select_terms(self,s):
587+
logger.info( f"select_terms {s=} {s[0]=}" )
586588
return s[0]
587589

588590
def select_term(self,s):
591+
logger.info( f"select_term {s=} {s[0]=}" )
589592
return s
590593

591594
def nested_prop( self,s):
595+
logger.info( f"nested_prop {s=} {s[0]=}" )
592596
result = s[0]+"{"+",".join(s[1])+"}"
597+
logger.info( f"nested_prop {result=}" )
593598
return result
594599

595600
def wildcard(self,s):
@@ -623,15 +628,18 @@ def identifier(self, s):
623628
logger.info( f"identifier {s=} {s[0]=}" )
624629
if len(s) == 1:
625630
resultname = s[0].value
631+
logger.info( f"{resultname=}" )
626632
elif len(s) > 1:
627633
# a prefixed name
628634
resultname = ":".join([s[0].value, s[1].value])
629635
if s[0].value in rdfxml.RDF_DEFAULT_PREFIX:
630636
self.prefixes[rdfxml.RDF_DEFAULT_PREFIX[s[0].value]]=s[0].value
637+
logger.info( f"Added prefix {s[0].value=}" )
631638
else:
632639
raise Exception( f"Prefix in orderby '{s[0].value}' not found!" )
633640
# look it up and if necessary store to mapping
634641
if ":" not in resultname:
642+
logger.info( "storing {resultname=}" )
635643
if self.resolverobject.resolve_property_name_to_uri is not None:
636644
result1 = self.resolverobject.resolve_property_name_to_uri(resultname)
637645
if result1 is None:
@@ -647,6 +655,7 @@ def identifier(self, s):
647655
# a prefixed name is assumed to be usable directly (the prefix has been added to prefixes)
648656
prefix = resultname.split( ":",1 )[0]
649657
self.prefixes[rdfxml.RDF_DEFAULT_PREFIX[prefix]] = prefix
658+
logger.info( f"Added prefix {prefix=}" )
650659
result = resultname
651660
logger.info( f"identifier1 {result=}" )
652661
return result

elmclient/_rm.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ def load_configs(self, cacheable=True):
516516
thisconfu = confmember.get("{%s}resource" % rdfxml.RDF_DEFAULT_PREFIX["rdf"])
517517
self._confs_to_load.append(thisconfu)
518518
# print( f" Adding {thisconfu=}" )
519+
# print( f" Now {self._confs_to_load=}" )
519520

520521
# maybe it's got configuration(s)
521522
confmembers_x = list( set( rdfxml.xml_find_elements(configs_xml, './/oslc_config:Configuration') + rdfxml.xml_find_elements(configs_xml, './/oslc_config:Stream') + rdfxml.xml_find_elements(configs_xml, './/oslc_config:Baseline') + rdfxml.xml_find_elements(configs_xml, './/oslc_config:ChangeSet') ) )
@@ -541,7 +542,7 @@ def load_configs(self, cacheable=True):
541542
created = rdfxml.xmlrdf_get_resource_uri(confmember_x, './dcterms:created', exceptionifnotfound=True)
542543
# print( f"{conftitle=}" )
543544
# print( f"{created=}" )
544-
if confmember_x.tag == '{http://open-services.net/ns/config#}Changeset':
545+
if confmember_x.tag == '{http://open-services.net/ns/config#}ChangeSet':
545546
conftype = "ChangeSet"
546547
ischangeset=True
547548
elif confmember_x.tag == '{http://open-services.net/ns/config#}Baseline':
@@ -624,6 +625,7 @@ def load_configs(self, cacheable=True):
624625

625626
def get_local_config(self, name_or_uri, global_config_uri=None):
626627
logger.info( f"GLC {self=} {name_or_uri=}" )
628+
# print( f"GLC {self=} {name_or_uri=} {global_config_uri=}" )
627629
if global_config_uri:
628630
# gc and local config both specified - try to avoid loading all the local configs by using the gc tree to locate the local config
629631
gc_contribs = self.get_gc_contributions(global_config_uri)
@@ -650,12 +652,15 @@ def get_local_config(self, name_or_uri, global_config_uri=None):
650652
filter="ChangeSet"
651653
name_or_uri = name_or_uri[2:]
652654
for cu, cd in self._configurations.items():
655+
# print( f"{cu=} {cd=}" )
653656
if filter and cd['conftype'] != filter:
654657
continue
655658
if cu == name_or_uri or cd['name'] == name_or_uri:
656659
if result:
657660
raise Exception( f"Config {name_or_uri} isn't unique - you could try prefixing it with S: for stream, B: for baseline, or C: for changeset")
658661
result = cu
662+
# print( f"GLC {result} {self=} {name_or_uri=}" )
663+
659664
return result
660665

661666
def list_configs( self ):

elmclient/_typesystem.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ def get_enum_id( self, enum_name, property_uri ):
293293
for enum_uri in self.properties[property_uri]['enums']:
294294
if self.enums[enum_uri]['name']==enum_name:
295295
result = self.enums[enum_uri]['id'] or enum_uri
296-
result = enum_uri
296+
# result = enum_uri # this makes ccm queries for e.g. rc:cm:type=Defect not work - ccm doens't like getting a URI - # unfortunately I can't remember why I added this line :-(
297297
break
298298
logger.info( f"get_enum_id {enum_name=} {property_uri=} {result=}" )
299299
return result

elmclient/examples/reqif_io.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
import elmclient._app as _app
3737
import elmclient.utils as utils
3838

39+
# disable caching completely
40+
cachecontrol=2
41+
3942
############################################################################
4043

4144
def reqif_main():
@@ -71,7 +74,7 @@ def reqif_main():
7174
parser.add_argument("-P", "--password", default=PASSWORD, help=f"User password default '{PASSWORD}' - can be set using env variable OUERY_PASSWORD - set to PROMPT to be prompted at runtime")
7275
parser.add_argument('-T', '--certs', action="store_true", help="Verify SSL certificates")
7376
parser.add_argument("-U", "--username", default=USER, help="User id - can be set using environment variable QUERY_USER")
74-
parser.add_argument('-W', '--cachecontrol', action='count', default=0, help="Used once -W erases cache then continues with caching enabled. Used twice -WW wipes cache and disables caching. Otherwise caching is continued from previous run(s).")
77+
# parser.add_argument('-W', '--cachecontrol', action='count', default=0, help="Used once -W erases cache then continues with caching enabled. Used twice -WW wipes cache and disables caching. Otherwise caching is continued from previous run(s).")
7578
parser.add_argument('-Z', '--proxyport', default=8888, type=int, help='Port for proxy default is 8888 - used if found to be active - set to 0 to disable')
7679

7780
# saved credentials
@@ -206,7 +209,7 @@ def reqif_main():
206209
approots['jts']='jts'
207210

208211
# create our "server"
209-
theserver = server.JazzTeamServer(args.jazzurl, args.username, args.password, verifysslcerts=args.certs,appstring=f"jts:{approots['jts']}",cachingcontrol=args.cachecontrol)
212+
theserver = server.JazzTeamServer(args.jazzurl, args.username, args.password, verifysslcerts=args.certs,appstring=f"jts:{approots['jts']}",cachingcontrol=cachecontrol)
210213

211214
# create all our apps
212215
for appdom,approot in approots.items():
@@ -440,7 +443,7 @@ def getmatchingdefs(alldefs,definitionnames):
440443

441444
# execute post content
442445
logger.info('Uploading package {ifile}...')
443-
response = queryon.execute_post_content(pkg_factory_u, data=body, headers={'Content-Type': content_type, 'userMimeType': 'application/zip', 'filename':os.path.basename(ifile),'Accept': '*/*','X-Requested-With': None,'Origin': 'https://jazz.ibm.com:9443', 'OSLC-Core-Version': None}, intent="Initiate reqif export " )
446+
response = queryon.execute_post_content(pkg_factory_u, data=body, headers={'Content-Type': content_type, 'userMimeType': 'application/zip', 'filename':os.path.basename(ifile),'Accept': '*/*','X-Requested-With': None,'Origin': 'https://jazz.ibm.com:9443', 'OSLC-Core-Version': None}, intent="Initiate reqif import - upload the reqif file" )
444447

445448
print( f"Triggering import for {os.path.basename(ifile)}" )
446449

@@ -465,7 +468,7 @@ def getmatchingdefs(alldefs,definitionnames):
465468
</rdf:RDF>"""
466469

467470
logger.debug( f"{content=}" )
468-
response = queryon.execute_post_rdf_xml( import_factory_u, data=content, cacheable=False, headers={'net.jazz.jfs.owning-context': queryon.project_uri, 'OSLC-Core-Version': None}, intent="Initiate reqif import" )
471+
response = queryon.execute_post_rdf_xml( import_factory_u, data=content, cacheable=False, headers={'net.jazz.jfs.owning-context': queryon.project_uri, 'OSLC-Core-Version': None}, intent="Initiate reqif import of the uploaded file" )
469472
logger.debug( f" {response.status_code=} {response=}" )
470473
location = response.headers.get('Location')
471474
if response.status_code == 202 and location is not None:

elmclient/examples/trsreader.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@
66
#
77
# Read and process TRS base and changelog pages
88
#
9-
# NOTE: UNFINISHED WORK IN PROGRESS!
9+
#################################################
10+
#################################################
11+
# NOTE: VERY VERY UNFINISHED WORK IN PROGRESS!
12+
#################################################
13+
#################################################
1014
#
1115
# NOTE this requires that your user has the license trs_consumer assigned, which allows access to the TRS.
1216
# __DON'T__ reassign a license from lqe_user to yourself because then LQE will stop working!
1317
#
1418
# If you have the trs license you can access all the content in the TRS,
15-
# BUT note that the TRS basically contains URLs pointing at e.g. DOORS Next resources, so there are no text of artifacts, etc., but you can say that a resource is in a certain configuration
19+
# BUT note that the TRS basically contains URLs pointing at e.g. DOORS Next resources, so there is no text of artifacts, etc., but you can say that a resource is in a certain configuration
1620
# AND note that retrieving the data from DOORS Next is constrained by the access right of your user
1721
#
1822

elmclient/httpops.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -722,17 +722,23 @@ def _jsa_login(self, auth_url):
722722
auth_url_response = self._session.get(str(auth_url)) # Load up them cookies!
723723
self.log_redirection_history( auth_url_response, intent="JAS Authorize step 3",donotlogbody=True )
724724
if auth_url_response.status_code == 200:
725-
login_url = auth_url_response.url # Take the redirected URL and login action URL
726-
logger.debug( f"1 {login_url=}" )
727-
if auth_url != login_url:
728-
content_text = to_text(auth_url_response)
729-
# print content
730-
auth_form_parser = _FormParser()
731-
auth_form_parser.feed(content_text)
732-
if auth_form_parser.action:
733-
login_url = urllib.parse.urljoin(login_url, auth_form_parser.action)
734-
logger.debug( f"2 {login_url=}" )
735-
self._authorize(login_url)
725+
if True:
726+
# use basic auth - 3iii in https://jazz.net/wiki/bin/view/Main/NativeClientAuthentication
727+
username, password = self.get_user_password(auth_url)
728+
auth_url_response = self._session.get( str(auth_url), auth=(username, password) ) # Load up them cookies!
729+
else:
730+
# use form auth
731+
login_url = auth_url_response.url # Take the redirected URL and login action URL
732+
logger.debug( f"1 {login_url=}" )
733+
if auth_url != login_url:
734+
content_text = to_text(auth_url_response)
735+
# print content
736+
auth_form_parser = _FormParser()
737+
auth_form_parser.feed(content_text)
738+
if auth_form_parser.action:
739+
login_url = urllib.parse.urljoin(login_url, auth_form_parser.action)
740+
logger.debug( f"2 {login_url=}" )
741+
self._authorize(login_url)
736742
else:
737743
logger.error('''Something about JSA OIDC login has changed since this script was written. I can no longer determine where to authorize myself.''')
738744
raise Exception("Authorize not possible (1)")

0 commit comments

Comments
 (0)