Skip to content

Commit 6991b22

Browse files
committed
added convenience methods for attachments, revamped context handling to correct some scoping defects and to allow pan-workspace operations by supplying project=None keyword arg to the 4 main REST ops; added details convenience method for returned entities to have a more organized output format
1 parent 84e5215 commit 6991b22

File tree

8 files changed

+696
-0
lines changed

8 files changed

+696
-0
lines changed

dists/pyral-0.9.1.tar.gz

120 KB
Binary file not shown.

dists/pyral-0.9.1.zip

143 KB
Binary file not shown.

examples/builddefs.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/usr/bin/env python
2+
3+
##################################################################################################
4+
#
5+
# builddefs.py - get build defs for a workspace/project context
6+
#
7+
USAGE = """
8+
Usage: python builddefs.py
9+
"""
10+
##################################################################################################
11+
12+
import sys, os
13+
14+
from pyral import Rally, rallySettings
15+
16+
##################################################################################################
17+
18+
# BUILD_DEFINITION
19+
#Creation Date DATE Required ReadOnly BakedIn Visible
20+
#Object ID INTEGER Required ReadOnly BakedIn Visible
21+
#Name STRING Required Settable BakedIn Visible
22+
#Project OBJECT Required Settable BakedIn Visible
23+
#Subscription OBJECT Optional ReadOnly BakedIn Visible
24+
#Workspace OBJECT Optional Settable BakedIn Visible
25+
#Description STRING Optional Settable BakedIn Visible
26+
#Builds COLLECTION Optional ReadOnly BakedIn Visible
27+
#LastBuild OBJECT Optional ReadOnly BakedIn Visible
28+
#LastStatus STRING Optional ReadOnly BakedIn Visible
29+
#Projects COLLECTION Optional Settable BakedIn Visible
30+
#Uri STRING Optional Settable BakedIn Visible
31+
32+
33+
# load up with Workspace / Project combinations appropriate for your environment
34+
#wps = [ ('Fluffy Bunny', 'Jasperex'),
35+
# ('Hoonerville', 'Engine Parts'),
36+
# ('BurntNoodles', 'Farina'),
37+
# ]
38+
39+
wps = [('WHuffaovc', 'Progicbadf')] # pronounced "dubya-peas" for Workspace-Projects
40+
41+
##################################################################################################
42+
43+
def main(args):
44+
options = [opt for opt in args if opt.startswith('--')]
45+
46+
server, user, password, workspace, project = rallySettings(options)
47+
rally = Rally(server, user, password, workspace=workspace)
48+
rally.enableLogging("rally.history.blddefs")
49+
50+
for workspace, project in wps:
51+
print "workspace: %s project: %s" % (workspace, project)
52+
rally.setWorkspace(workspace)
53+
response = rally.get('BuildDefinition', fetch=True,
54+
order='Name',
55+
workspace=workspace,
56+
project=project)
57+
if response.errors:
58+
print response.errors
59+
sys.exit(9)
60+
61+
for builddef in response:
62+
if builddef.Project.Name != project:
63+
continue
64+
if builddef.LastStatus == "NO BUILDS":
65+
print "NO BUILDS"
66+
continue
67+
#print builddef.oid, builddef.Name, builddef.LastStatus
68+
lbt = builddef.LastBuild.CreationDate.split('T')
69+
last_build_time = "%s %s" % (lbt[0], lbt[1][:5] )
70+
bd_name = "%-24.24s" % builddef.Name
71+
status = "%-10.10s" % builddef.LastStatus
72+
print builddef.oid, builddef.CreationDate[:10], \
73+
bd_name, status, last_build_time, len(builddef.Builds)
74+
75+
print "\n"
76+
77+
##################################################################################################
78+
##################################################################################################
79+
80+
if __name__ == "__main__":
81+
main(sys.argv[1:])

examples/creattach.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#!/usr/bin/env python
2+
3+
#################################################################################################
4+
#
5+
# creattach.py -- Associate a file with an Artifact as an Attachment
6+
#
7+
USAGE = """
8+
Usage: py creattach.py <ArtifactIdentifier> <filename>
9+
"""
10+
#################################################################################################
11+
12+
import sys
13+
import re
14+
import base64
15+
16+
from pyral import Rally, rallySettings
17+
18+
#################################################################################################
19+
20+
errout = sys.stderr.write
21+
22+
ARTY_FOR_PREFIX = {'S' : 'UserStory', 'US' : 'UserStory', 'DE' : 'Defect', 'TC' : 'TestCase'}
23+
24+
COMMON_ATTRIBUTES = ['_type', 'oid', '_ref', '_CreatedAt', '_hydrated', 'Name']
25+
26+
ATTACHMENT_ATTRIBUTES = ['oid', 'ObjectID', '_type', '_ref', '_CreatedAt', 'Name',
27+
'CreationDate', 'Description',
28+
'Content', 'ContentType', 'Size',
29+
'Subscription',
30+
'Workspace',
31+
'Artifact',
32+
'User'
33+
]
34+
35+
ATTACHMENT_CONTENT_ATTRS = """
36+
Workspace ref
37+
38+
Content base64 content
39+
"""
40+
41+
ATTACHMENT_IMPORTANT_ATTRS = """
42+
Subscription ref (supplied at creation)
43+
Workspace ref (supplied at creation)
44+
45+
Name STRING Required (name of the file, like foo.txt or ThePlan.doc)
46+
User ref to User Required Settable (User who added the object)
47+
48+
Content ref to AttachmentContent
49+
Size INTEGER Required
50+
ContentType STRING Required
51+
52+
53+
Artifact ref to Artifact (optional field)
54+
55+
Description TEXT Optional
56+
57+
"""
58+
59+
ATTACHMENT_CREATION_ATTACHING_SEQUENCE = """
60+
1) Create the AttachmentContent item with content in base64 encoding
61+
Get the oid of this created item back
62+
63+
2) Create the Attachment item
64+
using the ref to newly created AttachmentContent item.
65+
you also have to set
66+
the User ref (from the person who "uploaded" the AttachmentContent
67+
the Name of the file associated with the AttachmentContent.Content
68+
the Size of the base64 encoded stuff
69+
the ContentType (mime type, like text/xml, text/html, etc.)
70+
71+
unclear at this time if you can set the Artifact ref ...
72+
73+
you could also provide Description text
74+
75+
"""
76+
77+
#################################################################################################
78+
79+
def main(args):
80+
options = [opt for opt in args if opt.startswith('--')]
81+
args = [arg for arg in args if arg not in options]
82+
server, user, password, workspace, project = rallySettings(options)
83+
print " ".join(["|%s|" % item for item in [server, user, '********', workspace, project]])
84+
rally = Rally(server, user, password, workspace=workspace, version="1.30") # specify the Rally server and credentials
85+
rally.enableLogging('rally.hist.creattach') # name of file you want logging to go to
86+
87+
if len(args) != 2:
88+
errout('ERROR: You must supply an Artifact identifier and an attachment file name')
89+
errout(USAGE)
90+
sys.exit(1)
91+
92+
target, attachment_file_name = args
93+
artifact = validateTarget(rally, target)
94+
95+
me = rally.getUserInfo(username=user).pop(0)
96+
#print "%s user oid: %s" % (user, me.oid)
97+
98+
att_content = base64.encodestring(open(attachment_file_name, 'r').read())
99+
ac_size = len(att_content)
100+
ac_info = {"Content" : att_content}
101+
102+
ac = rally.create('AttachmentContent', ac_info, project=None)
103+
#print "created AttachmentContent: %s with size of %d" % (ac.oid, ac_size)
104+
105+
attachment_info = {
106+
#"Subscription" : subs.ref , (will default to current)
107+
#"Workspace" : wksp.ref , (will default to current)
108+
109+
"Name" : attachment_file_name,
110+
"Content" : ac.ref, #ref to AttachmentContent
111+
"Size" : ac_size,
112+
"ContentType" : 'text/plain',
113+
114+
"User" : me.ref,
115+
116+
"Artifact" : artifact.ref # (optional field)
117+
}
118+
119+
att = rally.create('Attachment', attachment_info, project=None)
120+
print "created Attachment: %s with Name: %s" % (att.oid, att.Name)
121+
122+
#################################################################################################
123+
124+
def validateTarget(rally, target):
125+
mo = re.match('^(S|US|DE|TC)\d+$', target)
126+
if not mo:
127+
errout("Target artifact identification flawed, invalid FormattedID value\n")
128+
sys.exit(2)
129+
prefix = mo.group(1)
130+
entity = ARTY_FOR_PREFIX.get(prefix, None)
131+
if not entity:
132+
errout("Target artifact identification flawed, unknown prefix: %s\n" % prefix)
133+
sys.exit(3)
134+
135+
ident_query = 'FormattedID = %s' % target
136+
response = rally.get(entity, fetch=True, query=ident_query, project=None)
137+
138+
if response.errors:
139+
errout("Request could not be successfully serviced, error code: %d\n" % response.status_code)
140+
errout("\n".join(response.errors))
141+
sys.exit(4)
142+
143+
if response.resultCount == 0:
144+
errout('No item found for %s %s\n' % (entity, target))
145+
sys.exit(5)
146+
elif response.resultCount > 1:
147+
errout('ERROR: more than 1 item returned matching your criteria for the target\n')
148+
sys.exit(6)
149+
150+
artifact = response.next()
151+
152+
return artifact
153+
154+
#################################################################################################
155+
#################################################################################################
156+
157+
if __name__ == '__main__':
158+
main(sys.argv[1:])
159+

examples/get_attachments.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env python
2+
3+
#################################################################################################
4+
#
5+
# get_attachments.py -- Get the the contents of all of attachments associated with a
6+
# specific instance of a Rally type identified either by an OID
7+
# or a FormattedID value
8+
#
9+
USAGE = """
10+
Usage: py get_attachments <entity_name> <OID | FormattedID>
11+
"""
12+
#################################################################################################
13+
14+
import sys
15+
import re
16+
import string
17+
18+
from pyral import Rally, rallySettings
19+
20+
#################################################################################################
21+
22+
errout = sys.stderr.write
23+
24+
STORY_ALIASES = ['Story', 'UserStory', 'User Story']
25+
26+
OID_PATT = re.compile(r'^\d+$')
27+
FORMATTED_ID_PATT = re.compile(r'[A-Z]+\d+')
28+
29+
COMMON_ATTRIBUTES = ['_type', 'oid', '_ref', '_CreatedAt', '_hydrated', 'Name']
30+
31+
#################################################################################################
32+
33+
def main(args):
34+
options = [opt for opt in args if opt.startswith('--')]
35+
args = [arg for arg in args if arg not in options]
36+
server, user, password, workspace, project = rallySettings(options)
37+
print " ".join(["|%s|" % item for item in [server, user, '********', workspace, project]])
38+
rally = Rally(server, user, password, workspace=workspace)
39+
rally.enableLogging('rally.hist.getattachs') # name of file you want logging to go to
40+
41+
if len(args) != 2:
42+
errout(USAGE)
43+
sys.exit(2)
44+
entity_name, ident = args
45+
if entity_name in STORY_ALIASES:
46+
entity_name = 'HierarchicalRequirement'
47+
48+
mo = OID_PATT.match(ident)
49+
if mo:
50+
ident_query = 'ObjectID = %s' % ident
51+
else:
52+
mo = FORMATTED_ID_PATT.match(ident)
53+
if mo:
54+
ident_query = 'FormattedID = "%s"' % ident
55+
else:
56+
errout('ERROR: Unable to determine ident scheme for %s\n' % ident)
57+
sys.exit(3)
58+
59+
response = rally.get(entity_name, fetch=True, query=ident_query,
60+
workspace=workspace, project=project)
61+
62+
if response.errors:
63+
errout("Request could not be successfully serviced, error code: %d\n" % response.status_code)
64+
errout("\n".join(response.errors))
65+
sys.exit(1)
66+
67+
if response.resultCount == 0:
68+
errout('No item found for %s %s\n' % (entity_name, ident))
69+
sys.exit(4)
70+
elif response.resultCount > 1:
71+
errout('WARNING: more than 1 item returned matching your criteria\n')
72+
73+
artifact = response.next()
74+
attachments = rally.getAttachments(artifact)
75+
for attachment in attachments:
76+
print "-" * 32
77+
print attachment.Name
78+
print "~" * len(attachment.Name)
79+
print attachment.Content
80+
print ""
81+
print "=" * 64
82+
83+
#################################################################################################
84+
#################################################################################################
85+
86+
if __name__ == '__main__':
87+
main(sys.argv[1:])

0 commit comments

Comments
 (0)