1 | # JavaScript Jira API Wrapper for NodeJS
|
2 |
|
3 | Node.JS module which provides easy-to-use access to the Jira REST API.
|
4 |
|
5 | ## Important Change in Version 1.0.0
|
6 |
|
7 | Starting with version 1.0.0, all functions and parameters utilize ```xxxId``` instead of ```xxxID```.
|
8 | Prior to this update, this naming convention was inconsistent and easily confused.
|
9 |
|
10 | Please update your code accordingly.
|
11 |
|
12 | ## Installation
|
13 |
|
14 | Install with [npm](http://npmjs.org/):
|
15 |
|
16 | ```
|
17 | $ npm install jira-connector
|
18 | ```
|
19 |
|
20 | Install via Git clone:
|
21 |
|
22 | ```
|
23 | $ git clone https://github.com/floralvikings/jira-connector.git
|
24 | $ cd jira-connector
|
25 | $ npm install
|
26 | ```
|
27 |
|
28 | ## Documentation
|
29 |
|
30 | The documentation for jira-connector can be found in the source; If you'd like to view
|
31 | the source as an HTML document, you can use [JSDoc](http://usejsdoc.org/) to generate these
|
32 | pages. Simply run:
|
33 |
|
34 | ```
|
35 | $ jsdoc -c jsdoc.json
|
36 | ```
|
37 |
|
38 | In the jira-connector source directory. This will create a ```docs``` directory, containing the HTML
|
39 | markup for the docs.
|
40 |
|
41 | Also, the [official Jira API docs](https://docs.atlassian.com/jira/REST/latest/) are very useful; many of
|
42 | the functions in jira-connector use the exact same format as the request bodies of these endpoints.
|
43 |
|
44 | ## Example
|
45 |
|
46 | Retrieve an issue from Jira, and print its summary to the console.
|
47 |
|
48 | ```javascript
|
49 |
|
50 | var JiraClient = require('jira-connector');
|
51 |
|
52 | var jira = new JiraClient( {
|
53 | host: 'jenjinstudios.atlassian.net'
|
54 | });
|
55 |
|
56 | jira.issue.getIssue({
|
57 | issueKey: 'JWR-19'
|
58 | }, function(error, issue) {
|
59 | console.log(issue.fields.summary);
|
60 | });
|
61 |
|
62 | ```
|
63 |
|
64 | First, the ```JiraApi``` class is imported from the ```jira-connector``` module. This class
|
65 | provides access to the Jira REST endpoints, organized into related classes.
|
66 |
|
67 | The ```issue``` property of the ```JiraApi``` class is used to retrieve and modify Jira Issues.
|
68 |
|
69 | All of the methods in the jira-connector API classes take two arguments; the ```opts``` and ```callback```.
|
70 |
|
71 | * The ```opts``` argument specifies the options that will be used when communicating with the Jira API. For a detailed
|
72 | list of options, see the documentation for the method into which you are passing the options.
|
73 | * The ```callback``` argument should be a function expecting two arguments; and error, and the results of the API
|
74 | request.
|
75 |
|
76 | ## Authentication
|
77 |
|
78 | Depending on the Jira instance to which you are connecting, authentication may or may not be required
|
79 | for various API calls.
|
80 |
|
81 | jira-connector supports two forms of authentication:
|
82 |
|
83 | ### Basic Authentication
|
84 |
|
85 | This is not recommended; it will require you to provide a username and password each time you connect to the
|
86 | Jira instance. However, jira-connector supports it for users who are unable to use OAuth.
|
87 |
|
88 | Example:
|
89 |
|
90 | ```javascript
|
91 | var JiraClient = require('jira-connector');
|
92 |
|
93 | var jira = new JiraClient( {
|
94 | host: 'jenjinstudios.atlassian.net',
|
95 | basic_auth: {
|
96 | username: 'SirUserOfName',
|
97 | password: 'Password123'
|
98 | }
|
99 | });
|
100 | ```
|
101 |
|
102 |
|
103 | ### Basic Authentication (Base64)
|
104 |
|
105 | Also not recommended, but slightly better than the above; it will require you to provide a Base64 encoded username
|
106 | and password (a Base64 encoding in the format of "username:password") each time you connect to the Jira instance.
|
107 |
|
108 | More examples [here](https://developer.atlassian.com/jiradev/jira-apis/jira-rest-apis/jira-rest-api-tutorials/jira-rest-api-example-basic-authentication).
|
109 |
|
110 | Example:
|
111 |
|
112 | ```javascript
|
113 | var JiraClient = require('jira-connector');
|
114 |
|
115 | var jira = new JiraClient( {
|
116 | host: 'jenjinstudios.atlassian.net',
|
117 | basic_auth: {
|
118 | base64: 'U2lyVXNlck9mTmFtZTpQYXNzd29yZDEyMw=='
|
119 | }
|
120 | });
|
121 |
|
122 | // Base64 encoding of 'SirUserOfName:Password123'
|
123 | ```
|
124 |
|
125 | ### OAuth Authentication
|
126 |
|
127 | This should be the preferred method of authentication; it is more secure and does not require disclosing
|
128 | your password.
|
129 |
|
130 | However, setting up OAuth access in Jira can be somewhat complicated; first the Jira administrator must create
|
131 | an Application Link; for instructions on how to do this, see
|
132 | [Linking to Another Application](https://confluence.atlassian.com/display/JIRA/Linking+to+Another+Application).
|
133 |
|
134 | [This example](https://developer.atlassian.com/display/JIRADEV/JIRA+REST+API+Example+-+OAuth+authentication) may also
|
135 | be helpful in configuring OAuth Access.
|
136 |
|
137 | Once the Application Link has been created, you will need the private key that corresponds to the public key used to
|
138 | create the link, and the consumer key that was provided when the link was created.
|
139 |
|
140 | Once you have this data, you will need to generate an OAuth token and secret for your account; jira-connector provides
|
141 | helper functions for exactly this purpose:
|
142 |
|
143 | ```javascript
|
144 | var JiraClient = require('./index.js');
|
145 |
|
146 | JiraClient.oauth_util.getAuthorizeURL({
|
147 | host: 'jenjinstudios.atlassian.net',
|
148 | oauth: {
|
149 | consumer_key: 'your-consumer-key',
|
150 | private_key: '-----BEGIN RSA PRIVATE KEY-----\n' +
|
151 | 'SomePrivateKeyHere\n' +
|
152 | '-----END RSA PRIVATE KEY-----'
|
153 | }
|
154 | }, function (error, oauth) {
|
155 | console.log(oauth);
|
156 | });
|
157 | ```
|
158 |
|
159 | This will output something similar to the following:
|
160 |
|
161 | ```javascript
|
162 | {
|
163 | url: 'https://jenjinstudios.atlassian.net/plugins/servlet/oauth/authorize?oauth_token=some-token-here',
|
164 | token: 'some-token-here',
|
165 | token_secret: 'some-secret-here'
|
166 | }
|
167 | ```
|
168 |
|
169 | You can then visit the specified URL, which will display a page asking you to allow or deny the request for access.
|
170 | Allowing access will display a verifier code. Once you have this code, you can swap out your current OAuth token
|
171 | for an Access Token with all the permissions of your account; jira-connector provides a function to help with this:
|
172 |
|
173 | ```javascript
|
174 | var JiraClient = require('./index.js');
|
175 |
|
176 | JiraClient.oauth_util.swapRequestTokenWithAccessToken({
|
177 | host: 'jenjinstudios.atlassian.net',
|
178 | oauth: {
|
179 | token: 'your-oauth-token',
|
180 | token_secret: 'your-token-secret',
|
181 | oauth_verifier: 'verifier-code-from-jira',
|
182 | consumer_key: 'your-consumer-key',
|
183 | private_key: '-----BEGIN RSA PRIVATE KEY-----\n' +
|
184 | 'SomePrivateKeyHere\n' +
|
185 | '-----END RSA PRIVATE KEY-----'
|
186 | }
|
187 | }, function (error, accessToken) {
|
188 | console.log(accessToken);
|
189 | });
|
190 | ```
|
191 |
|
192 | This will query Jira for an Access Token, which will then be printed to the screen. Finally, you're ready to access
|
193 | Jira with OAuth!
|
194 |
|
195 | ```javascript
|
196 | var JiraClient = require('./index.js');
|
197 |
|
198 | var jira = new JiraClient({
|
199 | host: 'jenjinstudios.atlassian.net',
|
200 | oauth: {
|
201 | consumer_key: 'your-consumer-key',
|
202 | private_key: '-----BEGIN RSA PRIVATE KEY-----\n' +
|
203 | 'SomePrivateKey\n' +
|
204 | '-----END RSA PRIVATE KEY-----',
|
205 | token: 'your-access-token',
|
206 | token_secret: 'your-token-secret'
|
207 | }
|
208 | });
|
209 |
|
210 | // Jira is now authenticted with your account!
|
211 | ```
|
212 |
|
213 | ### Cookie Jar
|
214 |
|
215 | You can also use a Cookie Jar for your request. It could be an easier way to prompt for a login only once, without the
|
216 | pain of setting up an OAuth method.
|
217 |
|
218 | For example, using `though-cookie-filestore`:
|
219 | ```javascript
|
220 | var JiraClient = require('../jira-connector'),
|
221 | FileCookieStore = require('tough-cookie-filestore'),
|
222 |
|
223 | request = require('request'),
|
224 | path = require('path');
|
225 |
|
226 | var jar = request.jar(new FileCookieStore(path.join(__dirname, 'cookies.json')));
|
227 |
|
228 | // For the first connection
|
229 | var jira = new JiraClient( {
|
230 | host: 'jenjinstudios.atlassian.net',
|
231 | basic_auth: {
|
232 | username: 'SirUserOfName',
|
233 | password: 'Password123'
|
234 | },
|
235 | cookie_jar: jar
|
236 | });
|
237 |
|
238 | // For the following connections
|
239 | var jira = new JiraClient( {
|
240 | host: 'jenjinstudios.atlassian.net',
|
241 | cookie_jar: jar
|
242 | });
|
243 | ```
|
244 |
|
245 | In this example, all your cookies are save in a file, `cookies.json`. Currently, the file **MUST** exist, it's a
|
246 | limitation from `though-cookie-filestore`...
|
247 |
|
248 | You can now only use the Cookie Jar for all the following request, as long as the file exists and the cookie
|
249 | is still valid!
|
250 |
|
251 | ## Supported API Calls
|
252 |
|
253 | * applicationProperties (/rest/api/2/application-properties)
|
254 | * getProperties
|
255 | * setProperty
|
256 | * attachment (/rest/api/2/atachment)
|
257 | * getAttachment
|
258 | * deleteAttachment
|
259 | * getGlobalAttachmentMetadata
|
260 | * auditing (/rest/api/2/auditing)
|
261 | * getAudits
|
262 | * createAudit
|
263 | * avatar (/rest/api/2/avatar) (Untested; use at your own peril)
|
264 | * getAvatars
|
265 | * createTemporaryAvatar
|
266 | * cropTemporaryAvatar
|
267 | * backlog (/rest/agile/1.0/backlog)
|
268 | * moveIssuesToBacklog
|
269 | * moveIssuesToBacklogForBoard
|
270 | * board (/rest/agile/1.0/board)
|
271 | * getAllBoards
|
272 | * createBoard
|
273 | * getBoard
|
274 | * deleteBoard
|
275 | * getIssuesForBacklog
|
276 | * getConfiguration
|
277 | * getEpics
|
278 | * getIssuesWithoutEpic
|
279 | * getIssuesForBoard
|
280 | * getReportsForBoard
|
281 | * getSprintsForBoard
|
282 | * comment (/rest/api/2/comment)
|
283 | * getCommentPropertyKeys
|
284 | * setCommentProperty
|
285 | * getCommentProperty
|
286 | * deleteCommentProperty
|
287 | * component (/rest/api/2/component)
|
288 | * getComponent
|
289 | * createComponent
|
290 | * editComponent
|
291 | * deleteComponent
|
292 | * getRelatedIssueCount
|
293 | * customFieldOption (/rest/api/2/customFieldOptions)
|
294 | * getCustomFieldOption
|
295 | * epic (/rest/agile/1.0/epic)
|
296 | * getIssuesWithoutEpic
|
297 | * removeIssuesFromEpic
|
298 | * getEpic
|
299 | * partiallyUpdateEpic
|
300 | * getIssuesForEpic
|
301 | * moveIssuesToEpic
|
302 | * rankEpics
|
303 | * dashboard (/rest/api/2/dashboard)
|
304 | * getAllDashboards
|
305 | * getDashboard
|
306 | * field (/rest/api/2/field)
|
307 | * getAllFields
|
308 | * createCustomField
|
309 | * filter (/rest/api/2/filter)
|
310 | * createFilter
|
311 | * getFilter
|
312 | * updateFilter
|
313 | * deleteFilter
|
314 | * getFilterColumns
|
315 | * setFilterColumns
|
316 | * resetFilterColumns
|
317 | * getDefaultShareScope
|
318 | * setDefaultShareScope
|
319 | * getFavoriteFilters
|
320 | * group (/rest/api/2/group)
|
321 | * createGroup
|
322 | * getGroup [DEPRECATED, use getMembers]
|
323 | * addUserToGroup
|
324 | * removeUserFromGroup
|
325 | * deleteGroup
|
326 | * getMembers
|
327 | * groups (/rest/api/2/groups)
|
328 | * findGroups
|
329 | * groupUserPicker (/rest/api/2/groupuserpicker)
|
330 | * findUsersAndGroups
|
331 | * issue (/rest/api/2/issue and /rest/agile/1.0/issue)
|
332 | * getIssue (agile api, set `opts.agile: true`)
|
333 | * getIssueEstimation (agile api)
|
334 | * setIssueEstimation (agile api)
|
335 | * setIssueRanks (agile api)
|
336 | * createIssue
|
337 | * getCreateMetadata
|
338 | * bulkCreate
|
339 | * getIssue
|
340 | * deleteIssue
|
341 | * editIssue
|
342 | * assignIssue
|
343 | * getComments
|
344 | * addComment
|
345 | * getComment
|
346 | * editComment
|
347 | * deleteComment
|
348 | * getEditMetadata
|
349 | * sendEmailNotification
|
350 | * getRemoteLinks
|
351 | * createRemoteLink
|
352 | * updateRemoteLink
|
353 | * deleteRemoteLink
|
354 | * getRemoteLinkByID
|
355 | * updateRemoteLinkByID
|
356 | * deleteRemoteLinkByID
|
357 | * getTransitions
|
358 | * transitionIssue
|
359 | * unvote
|
360 | * vote
|
361 | * getVotes
|
362 | * getWatchers
|
363 | * addWatcher
|
364 | * removeWatcher
|
365 | * getWorkLogs
|
366 | * addWorkLog
|
367 | * updateWorkLog
|
368 | * deleteWorkLog
|
369 | * addAttachment
|
370 | * getProperties
|
371 | * setProperty
|
372 | * getProperty
|
373 | * deleteProperty
|
374 | * getIssuePicker
|
375 | * issueLink (/rest/api/2/issueLink)
|
376 | * createIssueLink
|
377 | * getIssueLink
|
378 | * deleteIssueLink
|
379 | * issueLinkType (/rest/api/2/issueLinkType)
|
380 | * getAvailableTypes
|
381 | * createIssueLinkType
|
382 | * getIssueLinkType
|
383 | * deleteIssueLinkType
|
384 | * editIssueLinkType
|
385 | * issueType (/rest/api/2/issuetype)
|
386 | * getAllIssueTypes
|
387 | * getIssueType
|
388 | * createIssueType
|
389 | * deleteIssueType
|
390 | * updateIssueType
|
391 | * getAlternativeIssueTypes
|
392 | * jql (/rest/api/2/jql/autocompletedata)
|
393 | * getAutoCompleteData
|
394 | * labels (/rest/api/1.0/labels/suggest?query=)
|
395 | * getLabels
|
396 | * licenseRole (/rest/api/2/licenserole)
|
397 | * getAllLicenseRoles
|
398 | * getLicenseRole
|
399 | * editLicenseRole
|
400 | * licenseValidator (/rest/api/2/licenseValidator)
|
401 | * validateLicense
|
402 | * myPermissions (/rest/api/2/mypermissions)
|
403 | * getMyPermissions
|
404 | * myPreferences (/rest/api/2/mypreferences)
|
405 | * getPreference
|
406 | * editPreference
|
407 | * deletePreference
|
408 | * myself (/rest/api/2/myself)
|
409 | * getMyself
|
410 | * editMyslef
|
411 | * changePassword
|
412 | * password (/rest/api/2/password)
|
413 | * getPasswordPolicy
|
414 | * permissions (/rest/api/2/permissions)
|
415 | * getAllPermissions
|
416 | * permissionScheme (/rest/api/2/permissionscheme)
|
417 | * getAllPermissionSchemes
|
418 | * createPermissionScheme
|
419 | * getPermissionScheme
|
420 | * editPermissionScheme
|
421 | * deletePermissionScheme
|
422 | * getPermissionSchemeGrants
|
423 | * createPermissionGrantInScheme
|
424 | * deletePermissionGrantFromScheme
|
425 | * getPermissionSchemeGrantById
|
426 | * priority (/rest/api/2/priority)
|
427 | * getAllPriorities
|
428 | * getPriority
|
429 | * project (/rest/api/2/project)
|
430 | * getAllProjects
|
431 | * getProject
|
432 | * getComponents
|
433 | * getVersions
|
434 | * getStatuses
|
435 | * getRoles
|
436 | * getRole
|
437 | * updateRole
|
438 | * addToRole
|
439 | * projectCategory (/rest/api/2/projectCategory)
|
440 | * getAllProjectCategories
|
441 | * getProjectCategory
|
442 | * projectValidate (/rest/api/2/projectvalidate)
|
443 | * validateProjectKey
|
444 | * reindex (/rest/api/2/reindex)
|
445 | * doReindex
|
446 | * getReindex
|
447 | * resolution (/rest/api/2/resolution)
|
448 | * getAllResolutions
|
449 | * getResolution
|
450 | * roles (/rest/api/2/role) (a.k.a. ProjectRoles)
|
451 | * getAll
|
452 | * createRole
|
453 | * getRoleById
|
454 | * updateRole
|
455 | * deleteRole
|
456 | * getActors
|
457 | * addActors
|
458 | * removeActor
|
459 | * screens (/rest/api/2/screens)
|
460 | * getAvailableFields
|
461 | * getTabs
|
462 | * createTab
|
463 | * renameTab
|
464 | * deleteTab
|
465 | * addFieldToTab
|
466 | * getFieldsInTab
|
467 | * removeFieldFromTab
|
468 | * moveFieldOnTab
|
469 | * moveTabPosition
|
470 | * addFieldToDefaultTab
|
471 | * search (/rest/api/2/search)
|
472 | * search
|
473 | * securityLevel (/rest/api/2/securitylevel)
|
474 | * getSecurityLevel
|
475 | * serverInfo (/rest/api/2/serverInfo)
|
476 | * getServerInfo
|
477 | * settings (/rest/api/2/settings)
|
478 | * setBaseUrl
|
479 | * getIssueNavColumns
|
480 | * sprint (/rest/agile/1.0/sprint)
|
481 | * createSprint
|
482 | * getSprint
|
483 | * updateSprint
|
484 | * partiallyUpdateSprint
|
485 | * deleteSprint
|
486 | * getSprintIssues
|
487 | * moveSprintIssues
|
488 | * swapSprint
|
489 | * status (/rest/api/2/status)
|
490 | * getAllStatuses
|
491 | * getStatus
|
492 | * statusCategory (/rest/api/2/statuscategory)
|
493 | * getAllStatusCategories
|
494 | * getStatusCategory
|
495 | * user (/rest/api/2/user)
|
496 | * getUser
|
497 | * deleteUser
|
498 | * editUser
|
499 | * multiProjectSearchAssignable
|
500 | * searchAssignable
|
501 | * createTemporaryAvatar
|
502 | * convertTemporaryAvatar
|
503 | * deleteAvatar
|
504 | * getAvatars
|
505 | * getDefaultColumns
|
506 | * setDefaultColumns
|
507 | * resetDefaultColumns
|
508 | * changePassword
|
509 | * searchPermissions
|
510 | * searchPicker
|
511 | * search
|
512 | * viewIssueSearch
|
513 | * version (/rest/api/2/version)
|
514 | * createVersion
|
515 | * moveVersion
|
516 | * getVersion
|
517 | * editVersion
|
518 | * getRelatedIssueCounts
|
519 | * getUnresolvedIssueCount
|
520 | * getRemoteLinks
|
521 | * createRemoteLink
|
522 | * getRemoteLink
|
523 | * deleteRemoteLink
|
524 | * deleteVersion
|
525 | * deleteAllRemoteLinks
|
526 | * getGlobalRemoteLink
|
527 | * webhook (/rest/webhooks/1.0/webhook)
|
528 | * getAllWebhooks
|
529 | * getWebhook
|
530 | * createWebhook
|
531 | * deleteWebhook
|
532 | * workflow (/rest/api/2/workflow)
|
533 | * getWorkflows
|
534 | * workflowScheme (/rest/api/2/workflowscheme)
|
535 | * createWorkflowScheme
|
536 | * editWorkflowScheme
|
537 | * deleteWorkflowScheme
|
538 | * createDraft
|
539 | * getDefaultWorkflow
|
540 | * removeDefaultWorkflow
|
541 | * setDefaultWorkflow
|
542 | * getDraft
|
543 | * editDraft
|
544 | * deleteDraft
|
545 | * getDraftDefaultWorkflow
|
546 | * setDraftDefaultWorkflow
|
547 | * removeDraftDefaultWorkflow
|
548 | * getIssueType
|
549 | * removeIssueType
|
550 | * editIssueType
|
551 | * getDraftIssueType
|
552 | * editDraftIssueType
|
553 | * removeDraftIssueType
|
554 | * getWorkflow
|
555 | * editWorkflow
|
556 | * deleteWorkflow
|
557 | * getDraftWorkflow
|
558 | * editDraftWorkflow
|
559 | * deleteDraftWorkflow
|
560 | * worklog (/rest/api/2/worklog)
|
561 | * getWorklogDeleted
|
562 | * worklogList
|
563 | * getWorklogUpdated
|
564 |
|
565 | ## License
|
566 |
|
567 | [MIT license](http://opensource.org/licenses/MIT)
|