asciidoctor-jira 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # Asciidoctor Jira Extension
2
+
3
+ [![CI](https://github.com/uniqueck/asciidoctor-jira/actions/workflows/build-js.yml/badge.svg?branch=main)](https://github.com/uniqueck/asciidoctor-jira/actions/workflows/build-js.yml)
4
+
5
+ A set of macros for [Asciidoctor.js](https://github.com/asciidoctor/asciidoctor.js) to integrate Jira!
6
+
7
+ * [Install](#install)
8
+ + [Antora Integration](#antora-integration)
9
+
10
+ ## Install
11
+
12
+ ### Antora Integration
13
+
14
+ If you are using [Antora](https://antora.org/), you can integrate Jira in your documentation site.
15
+
16
+ Install the extension in your playbook project:
17
+
18
+ $ npm i asciidoctor-jira
19
+
20
+ Register the extension in your playbook file:
21
+
22
+ ```yaml
23
+ asciidoc:
24
+ extensions:
25
+ - asciidoctor-jira
26
+ ```
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "asciidoctor-jira",
3
+ "author": "Constantin Krüger (https://github.com/uniqueck)",
4
+ "license": "MIT",
5
+ "version": "0.0.1",
6
+ "bugs": {
7
+ "url": "https://github.com/doctoolchain/asciidoctor-jira/issues"
8
+ },
9
+ "files": [
10
+ "src"
11
+ ],
12
+ "keywords": [
13
+ "asciidoctor",
14
+ "jira",
15
+ "javascript",
16
+ "extension"
17
+ ],
18
+ "main": "src/asciidoctor-jira.js",
19
+ "devDependencies": {
20
+ "@antora/site-generator-default": "^2.3.3",
21
+ "@asciidoctor/core": "^2.2.0",
22
+ "chai": "^4.3.4",
23
+ "cheerio": "0.22.0",
24
+ "dotenv": "^10.0.0",
25
+ "jest": "27.2",
26
+ "mocha": "^9.0.0",
27
+ "rimraf": "^3.0.2",
28
+ "shx": "^0.3.3",
29
+ "standard": "^16.0.2",
30
+ "sync-request": "^6.1.0"
31
+ },
32
+ "peerDependencies": {
33
+ "@asciidoctor/core": "^2.2.0"
34
+ },
35
+ "scripts": {
36
+ "test": "npm run test:antora",
37
+ "test:antora": "mocha --reporter json --reporter-option output=test-results.json test/antora/**.spec.js",
38
+ "lint": "standard src/**.js",
39
+ "lint-fix": "npm run lint -- --fix",
40
+ "clean": "shx rm -rf dist/*"
41
+ },
42
+ "engines": {
43
+ "node": ">=10"
44
+ }
45
+ }
package/src/Jira.js ADDED
@@ -0,0 +1,58 @@
1
+
2
+ const request = require('sync-request')
3
+
4
+ class Jira {
5
+ constructor (doc) {
6
+ this.doc = doc
7
+ }
8
+
9
+ searchIssues (jql) {
10
+ const data = { jql: jql, fields: 'created,resolutiondate,priority,summary,timeoriginalestimate,assignee,issuetype' }
11
+ let issues
12
+ try {
13
+ const jiraBaseUrl = this.doc.getAttribute('jira-host') || process.env.AJE_JIRABASEURL
14
+ const jiraRestApiSearchEndpoint = jiraBaseUrl + '/rest/api/2/search'
15
+ const jiraUserName = this.doc.getAttribute('jira-username') || process.env.AJE_USERNAME
16
+ const jiraApiToken = this.doc.getAttribute('jira-apitoken') || process.env.AJE_APITOKEN || process.env.AJE_PASSWORD
17
+ const auth = 'Basic ' + Buffer.from(jiraUserName + ':' + jiraApiToken).toString('base64')
18
+ const headers = {
19
+ authorization: auth
20
+ }
21
+ const res = request('GET', jiraRestApiSearchEndpoint, {
22
+ headers: headers,
23
+ qs: data
24
+ })
25
+ issues = JSON.parse(res.getBody('utf-8')).issues
26
+ } catch (err) {
27
+ console.log(err)
28
+ issues = null
29
+ }
30
+ return issues
31
+ }
32
+
33
+ searchIssue (issueKey) {
34
+ const data = { jql: 'issueKey=' + issueKey, fields: 'created,resolutiondate,priority,summary,timeoriginalestimate,assignee,issuetype' }
35
+ let result
36
+ try {
37
+ const jiraBaseUrl = this.doc.getAttribute('jira-host') || process.env.AJE_JIRABASEURL
38
+ const jiraRestApiSearchEndpoint = jiraBaseUrl + '/rest/api/2/search'
39
+ const jiraUserName = this.doc.getAttribute('jira-username') || process.env.AJE_USERNAME
40
+ const jiraApiToken = this.doc.getAttribute('jira-apitoken') || process.env.AJE_APITOKEN || process.env.AJE_PASSWORD
41
+ const auth = 'Basic ' + Buffer.from(jiraUserName + ':' + jiraApiToken).toString('base64')
42
+ const headers = {
43
+ authorization: auth
44
+ }
45
+ const res = request('GET', jiraRestApiSearchEndpoint, {
46
+ headers: headers,
47
+ qs: data
48
+ })
49
+ result = JSON.parse(res.getBody('utf-8')).issues[0]
50
+ } catch (err) {
51
+ console.log(err)
52
+ result = null
53
+ }
54
+ return result
55
+ }
56
+ }
57
+
58
+ module.exports = Jira
@@ -0,0 +1,76 @@
1
+ /* global
2
+ Opal
3
+ */
4
+
5
+ // @ts-check
6
+ const Jira = require('./Jira.js')
7
+ require('dotenv').config()
8
+
9
+ function jiraIssuesBlockMacro (context) {
10
+ return function () {
11
+ const self = this
12
+ self.named('jira')
13
+ self.positionalAttributes(['jql'])
14
+ self.process((parent, target, attrs) => {
15
+ const doc = parent.getDocument()
16
+ const jql = attrs.jql || "resolution='Unresolved' ORDER BY priority DESC, key ASC, duedate ASC"
17
+ const jiraClient = new Jira(doc)
18
+ const issues = jiraClient.searchIssues(jql)
19
+
20
+ const content = []
21
+ content.push('[options="header",cols="2,1,1,2,6"]')
22
+ content.push('|====')
23
+ content.push('|ID | Priority | Created | Assignee | Summary')
24
+
25
+ for (let i = 0; i < issues.length; i++) {
26
+ const issue = issues[i]
27
+ content.push('a|jira:' + issue.key + '[]')
28
+ content.push('|' + issue.fields.priority.name)
29
+ content.push('|' + issue.fields.created)
30
+ const assignee = issue.fields.assignee ? issue.fields.assignee.displayName : 'not assigned'
31
+ content.push('|' + assignee)
32
+ content.push('|' + issue.fields.summary)
33
+ }
34
+ content.push('|====')
35
+
36
+ self.parseContent(parent, content.join('\n'), Opal.hash(attrs))
37
+
38
+ return undefined
39
+ })
40
+ }
41
+ }
42
+
43
+ function jiraIssueInlineMacro (context) {
44
+ return function () {
45
+ const self = this
46
+ self.named('jira')
47
+ self.positionalAttributes(['format'])
48
+ self.process((parent, target, attrs) => {
49
+ const doc = parent.getDocument()
50
+ const displayFormat = attrs.format || doc.getAttribute('jira-inline-format') || 'short'
51
+ const issueKey = target
52
+ const jiraClient = new Jira(doc)
53
+ const issue = jiraClient.searchIssue(issueKey)
54
+ let title = issueKey
55
+ if (displayFormat === 'long') {
56
+ title += issue.fields.summary
57
+ }
58
+ const jiraBaseUrl = doc.getAttribute('jira-host') || process.env.AJE_JIRABASEURL
59
+ const issueLink = jiraBaseUrl + '/browse/' + issueKey
60
+ return self.createInline(parent, 'anchor', title, { type: 'link', target: issueLink }).convert()
61
+ })
62
+ }
63
+ }
64
+
65
+ module.exports.register = function register (registry, context = {}) {
66
+ if (typeof registry.register === 'function') {
67
+ registry.register(function () {
68
+ this.blockMacro(jiraIssuesBlockMacro(context))
69
+ this.inlineMacro(jiraIssueInlineMacro(context))
70
+ })
71
+ } else if (typeof registry.block === 'function') {
72
+ registry.blockMacro(jiraIssuesBlockMacro(context))
73
+ registry.inlineMacro(jiraIssueInlineMacro(context))
74
+ }
75
+ return registry
76
+ }