0
# Comments & Attachments
1
2
Comment management and file attachment operations for issues. This includes adding, updating, and retrieving comments, as well as managing file attachments with support for various file types.
3
4
## Capabilities
5
6
### Comment Management
7
8
Operations for managing issue comments including creation, retrieval, and updates.
9
10
```python { .api }
11
def comments(self, issue: Issue) -> list[Comment]:
12
"""
13
Get all comments for an issue.
14
15
Parameters:
16
- issue: Issue object or issue key
17
18
Returns:
19
List of Comment objects
20
"""
21
22
def comment(self, issue: Issue, comment: str) -> Comment:
23
"""
24
Get a specific comment by ID.
25
26
Parameters:
27
- issue: Issue object or issue key
28
- comment: Comment ID
29
30
Returns:
31
Comment object
32
"""
33
34
def add_comment(
35
self,
36
issue: Issue,
37
body: str,
38
visibility: dict = None,
39
is_internal: bool = False
40
) -> Comment:
41
"""
42
Add a comment to an issue.
43
44
Parameters:
45
- issue: Issue object or issue key
46
- body: Comment text content
47
- visibility: Visibility restrictions (role or group based)
48
- is_internal: Mark comment as internal (Service Desk)
49
50
Returns:
51
Created Comment object
52
"""
53
```
54
55
Usage examples:
56
```python
57
# Get all comments for an issue
58
issue = jira.issue('PROJ-123')
59
comments = jira.comments(issue)
60
for comment in comments:
61
print(f"Author: {comment.author.displayName}")
62
print(f"Created: {comment.created}")
63
print(f"Body: {comment.body}")
64
print("---")
65
66
# Add a simple comment
67
new_comment = jira.add_comment(
68
issue='PROJ-123',
69
body='This is a comment added via the API'
70
)
71
print(f"Added comment: {new_comment.id}")
72
73
# Add comment with visibility restrictions
74
restricted_comment = jira.add_comment(
75
issue='PROJ-123',
76
body='This comment is only visible to developers',
77
visibility={
78
'type': 'group',
79
'value': 'developers'
80
}
81
)
82
83
# Add internal comment (Service Desk)
84
internal_comment = jira.add_comment(
85
issue='SD-456',
86
body='Internal note for agents only',
87
is_internal=True
88
)
89
90
# Get specific comment
91
comment = jira.comment('PROJ-123', new_comment.id)
92
print(f"Comment body: {comment.body}")
93
```
94
95
### Comment Updates
96
97
Comments can be updated through the Comment resource object:
98
99
```python
100
# Update a comment
101
comment = jira.comment('PROJ-123', '12345')
102
comment.update(body='Updated comment text')
103
104
# Update comment with visibility
105
comment.update(
106
body='Updated restricted comment',
107
visibility={
108
'type': 'role',
109
'value': 'Administrators'
110
}
111
)
112
```
113
114
### Attachment Management
115
116
Operations for managing file attachments on issues.
117
118
```python { .api }
119
def attachment(self, id: str) -> Attachment:
120
"""
121
Get attachment by ID.
122
123
Parameters:
124
- id: Attachment ID
125
126
Returns:
127
Attachment object
128
"""
129
130
def attachment_meta(self) -> dict:
131
"""
132
Get attachment metadata including size limits and enabled status.
133
134
Returns:
135
Attachment metadata dictionary
136
"""
137
138
def add_attachment(self, issue: Issue, attachment: str, filename: str = None) -> Attachment:
139
"""
140
Add an attachment to an issue.
141
142
Parameters:
143
- issue: Issue object or issue key
144
- attachment: File path or file-like object
145
- filename: Custom filename (optional)
146
147
Returns:
148
Created Attachment object
149
"""
150
151
def delete_attachment(self, id: str) -> None:
152
"""
153
Delete an attachment.
154
155
Parameters:
156
- id: Attachment ID
157
"""
158
```
159
160
Usage examples:
161
```python
162
# Get attachment metadata
163
meta = jira.attachment_meta()
164
print(f"Attachments enabled: {meta['enabled']}")
165
print(f"Upload limit: {meta['uploadLimit']} bytes")
166
167
# Add file attachment
168
with open('document.pdf', 'rb') as f:
169
attachment = jira.add_attachment(
170
issue='PROJ-123',
171
attachment=f,
172
filename='requirements_document.pdf'
173
)
174
print(f"Uploaded attachment: {attachment.filename}")
175
176
# Add multiple attachments
177
files_to_upload = ['screenshot.png', 'log.txt', 'report.xlsx']
178
for file_path in files_to_upload:
179
with open(file_path, 'rb') as f:
180
attachment = jira.add_attachment('PROJ-123', f)
181
print(f"Uploaded: {attachment.filename}")
182
183
# Get attachment details
184
attachment = jira.attachment(attachment.id)
185
print(f"Filename: {attachment.filename}")
186
print(f"Size: {attachment.size} bytes")
187
print(f"MIME Type: {attachment.mimeType}")
188
print(f"Author: {attachment.author.displayName}")
189
print(f"Created: {attachment.created}")
190
191
# Delete attachment
192
jira.delete_attachment(attachment.id)
193
```
194
195
### Attachment Content Access
196
197
Retrieve attachment file content for processing or download.
198
199
```python
200
# Get attachment content as string (for text files)
201
attachment = jira.attachment('12345')
202
content = attachment.get()
203
print(content)
204
205
# Stream attachment content (for large files)
206
attachment = jira.attachment('12345')
207
with open(f'downloaded_{attachment.filename}', 'wb') as f:
208
for chunk in attachment.iter_content(chunk_size=8192):
209
f.write(chunk)
210
print(f"Downloaded: {attachment.filename}")
211
212
# Process image attachment
213
import io
214
from PIL import Image
215
216
attachment = jira.attachment('image_attachment_id')
217
if attachment.mimeType.startswith('image/'):
218
image_data = io.BytesIO()
219
for chunk in attachment.iter_content():
220
image_data.write(chunk)
221
image_data.seek(0)
222
223
image = Image.open(image_data)
224
print(f"Image size: {image.size}")
225
print(f"Image mode: {image.mode}")
226
```
227
228
### Remote Links
229
230
Manage remote links that connect issues to external resources.
231
232
```python { .api }
233
def remote_links(self, issue: Issue) -> list[dict]:
234
"""Get all remote links for an issue."""
235
236
def remote_link(self, issue: Issue, id: str) -> dict:
237
"""Get a specific remote link by ID."""
238
239
def add_remote_link(
240
self,
241
issue: Issue,
242
destination: str,
243
globalId: str = None,
244
application: dict = None,
245
relationship: str = None
246
) -> dict:
247
"""
248
Add a remote link to an issue.
249
250
Parameters:
251
- issue: Issue object or issue key
252
- destination: URL or destination object
253
- globalId: Global ID for the link
254
- application: Application information dictionary
255
- relationship: Relationship type
256
257
Returns:
258
Created remote link dictionary
259
"""
260
261
def add_simple_link(self, issue: Issue, object: dict) -> dict:
262
"""
263
Add a simple remote link to an issue.
264
265
Parameters:
266
- issue: Issue object or issue key
267
- object: Link object with URL and title
268
269
Returns:
270
Created remote link dictionary
271
"""
272
```
273
274
Usage examples:
275
```python
276
# Get all remote links for an issue
277
links = jira.remote_links('PROJ-123')
278
for link in links:
279
print(f"Title: {link['object']['title']}")
280
print(f"URL: {link['object']['url']}")
281
282
# Add simple remote link
283
simple_link = jira.add_simple_link(
284
issue='PROJ-123',
285
object={
286
'url': 'https://example.com/related-doc',
287
'title': 'Related Documentation'
288
}
289
)
290
291
# Add remote link with application info
292
app_link = jira.add_remote_link(
293
issue='PROJ-123',
294
destination='https://github.com/company/repo/pull/123',
295
application={
296
'type': 'com.atlassian.jira.plugins.github',
297
'name': 'GitHub'
298
},
299
relationship='implements'
300
)
301
302
# Get specific remote link
303
link = jira.remote_link('PROJ-123', simple_link['id'])
304
print(f"Link: {link['object']['title']} -> {link['object']['url']}")
305
```
306
307
## Comment Visibility Options
308
309
Control who can see comments using visibility restrictions:
310
311
### Group-based Visibility
312
```python
313
# Restrict to specific group
314
jira.add_comment(
315
issue='PROJ-123',
316
body='Visible only to developers',
317
visibility={
318
'type': 'group',
319
'value': 'developers'
320
}
321
)
322
```
323
324
### Role-based Visibility
325
```python
326
# Restrict to project role
327
jira.add_comment(
328
issue='PROJ-123',
329
body='Visible only to administrators',
330
visibility={
331
'type': 'role',
332
'value': 'Administrators'
333
}
334
)
335
```
336
337
## Attachment File Types
338
339
The library supports all file types that JIRA allows. Common examples:
340
341
```python
342
# Document files
343
jira.add_attachment('PROJ-123', open('document.pdf', 'rb'))
344
jira.add_attachment('PROJ-123', open('spreadsheet.xlsx', 'rb'))
345
jira.add_attachment('PROJ-123', open('presentation.pptx', 'rb'))
346
347
# Image files
348
jira.add_attachment('PROJ-123', open('screenshot.png', 'rb'))
349
jira.add_attachment('PROJ-123', open('diagram.jpg', 'rb'))
350
351
# Code files
352
jira.add_attachment('PROJ-123', open('script.py', 'rb'))
353
jira.add_attachment('PROJ-123', open('config.json', 'rb'))
354
355
# Archive files
356
jira.add_attachment('PROJ-123', open('logs.zip', 'rb'))
357
jira.add_attachment('PROJ-123', open('backup.tar.gz', 'rb'))
358
```
359
360
## Bulk Operations
361
362
Handle multiple comments or attachments efficiently:
363
364
```python
365
# Add multiple comments
366
comments_to_add = [
367
'First comment',
368
'Second comment with visibility',
369
'Third comment'
370
]
371
372
for i, comment_text in enumerate(comments_to_add):
373
visibility = None
374
if i == 1: # Second comment restricted
375
visibility = {'type': 'group', 'value': 'developers'}
376
377
jira.add_comment('PROJ-123', comment_text, visibility=visibility)
378
379
# Upload multiple related files
380
import os
381
log_dir = '/path/to/logs'
382
for filename in os.listdir(log_dir):
383
if filename.endswith('.log'):
384
with open(os.path.join(log_dir, filename), 'rb') as f:
385
jira.add_attachment('PROJ-123', f, filename=filename)
386
```
387
388
## Error Handling
389
390
Handle common attachment and comment errors:
391
392
```python
393
from jira import JIRAError
394
395
try:
396
# Attempt to add large attachment
397
with open('very_large_file.zip', 'rb') as f:
398
attachment = jira.add_attachment('PROJ-123', f)
399
except JIRAError as e:
400
if e.status_code == 413:
401
print("File too large for upload")
402
elif e.status_code == 403:
403
print("No permission to add attachments")
404
else:
405
print(f"Upload failed: {e.text}")
406
407
try:
408
# Attempt to add comment with invalid visibility
409
jira.add_comment(
410
'PROJ-123',
411
'Test comment',
412
visibility={'type': 'group', 'value': 'nonexistent-group'}
413
)
414
except JIRAError as e:
415
print(f"Comment creation failed: {e.text}")
416
```