Skip to content

Commit

Permalink
feat(jiraIssue): add initial implementation (#1)
Browse files Browse the repository at this point in the history
`jiraIssue()` is a Danger plugin that adds a JIRA issue link to the Danger pull request comment.
If a pull request title does not contain the supplied JIRA issue identifier (e.g. ABC-123),
then Danger will comment with a warning on the pull request asking the developer
to include the JIRA issue identifier in the pull request title.

Example usage:

```js
// dangerfile.js
import jiraIssue from 'danger-plugin-jira-issue'

jiraIssue({
  key: 'JIRA',
  url: 'https://myjira.atlassian.net/browse',
  emoji: ':paperclip:',
})
```

BREAKING CHANGE: this commit introduces functionality ready for a 1.0.0 release.
  • Loading branch information
macklinu committed May 12, 2017
1 parent d136089 commit 8638e2f
Show file tree
Hide file tree
Showing 14 changed files with 527 additions and 32 deletions.
4 changes: 4 additions & 0 deletions .esdoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"source": "./src",
"destination": "./docs"
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,6 @@ typings/

# Distributed source
dist/

# Generated documentation
docs/
7 changes: 7 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.babelrc
.editorconfig
.esdoc.json
.travis.yml
yarn.lock
node_modules/
src/
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ notifications:
node_js:
- '7'
- '6'
- '4'
before_script:
- npm prune
after_success:
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,21 @@ Install:
yarn add danger-plugin-jira-issue --dev
```

Import and invoke the `jiraIssue()` function in your `dangerfile.js` or `dangerfile.ts`:
At a glance:

```js
// dangerfile.js
import jiraIssue from 'danger-plugin-jira-issue'

jiraIssue({
// TODO options
key: 'JIRA',
url: 'https://myjira.atlassian.net/browse',
emoji: ':paperclip:',
})
```

See the [documentation](https://doc.esdoc.org/github.com/macklinu/danger-plugin-jira-issue/) for detailed information .

## Development

Install [Yarn](https://yarnpkg.com/en/), and install the dependencies - `yarn install`.
Expand Down
13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
"version": "0.0.0-development",
"description": "Danger plugin to link JIRA issue in pull request",
"main": "dist/index.js",
"types": "types/index.d.ts",
"scripts": {
"precommit": "lint-staged",
"commit": "git-cz",
"commitmsg": "validate-commit-msg",
"build": "babel src --out-dir dist --ignore __tests__,__mocks__",
"build": "babel src --out-dir dist --ignore *.test.js",
"test": "jest",
"predocs": "rm -rf docs/",
"docs": "esdoc -c .esdoc.json",
"prepublish": "npm run build",
"semantic-release": "semantic-release pre && npm publish && semantic-release post"
},
Expand All @@ -27,17 +30,23 @@
"url": "https://github.com/macklinu/danger-plugin-jira-issue/issues"
},
"homepage": "https://github.com/macklinu/danger-plugin-jira-issue#readme",
"engines": {
"node": ">= 6.0.0"
},
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-jest": "^20.0.1",
"babel-preset-es2015": "^6.24.1",
"commitizen": "^2.9.6",
"cz-conventional-changelog": "^2.0.0",
"esdoc": "^0.5.2",
"husky": "^0.13.3",
"jest": "^20.0.1",
"lint-staged": "^3.4.1",
"prettier": "^1.3.1",
"semantic-release": "^6.3.6",
"typescript": "^2.3.2",
"typings-tester": "^0.2.2",
"validate-commit-msg": "^2.12.1"
},
"config": {
Expand All @@ -47,7 +56,7 @@
},
"lint-staged": {
"*.js": [
"prettier --single-quote --trailing-comma=all --no-semi",
"prettier --single-quote --trailing-comma=all --no-semi --write",
"git add"
]
}
Expand Down
7 changes: 0 additions & 7 deletions src/__tests__/index.test.js

This file was deleted.

31 changes: 30 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,30 @@
export default function jiraIssue() {}
import { join } from 'path'

const link = (href, text) => `<a href="${href}">${text}</a>`

/**
* A Danger plugin to add a JIRA issue link to the Danger pull request comment.
* If a pull request title does not contain the supplied JIRA issue identifier (e.g. ABC-123),
* then Danger will comment with a warning on the pull request asking the developer
* to include the JIRA issue identifier in the pull request title.
*
* @param {Object} options - The JIRA options object.
* @param {string} options.key - The JIRA issue key (e.g. the ABC in ABC-123).
* @param {string} options.url - The JIRA instance issue base URL (e.g. https://jira.atlassian.com/browse/).
* @param {string} [options.emoji=':link:'] - The emoji to display with the JIRA issue link.
* See the possible emoji values, listed as keys in the [GitHub API `/emojis` response](https://api.github.com/emojis).
*/
export default function jiraIssue({ key, url, emoji = ':link:' } = {}) {
if (!url) throw Error(`'url' missing - must supply JIRA installation URL`)
if (!key) throw Error(`'key' missing - must supply JIRA issue key`)

const jiraKeyRegex = new RegExp(`^.*(${key}-[0-9]+).*$`, 'g')
const match = jiraKeyRegex.exec(danger.github.pr.title)
if (match) {
const jiraIssue = match[1]
const jiraUrl = link(join(url, jiraIssue), jiraIssue)
message(`${emoji} ${jiraUrl}`)
} else {
warn(`Please add the JIRA issue key to the PR title (e.g. ${key}-123)`)
}
}
84 changes: 84 additions & 0 deletions src/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import jiraIssue from '../'

describe('jiraIssue()', () => {
beforeEach(() => {
global.warn = jest.fn()
global.message = jest.fn()
})
afterEach(() => {
global.danger = undefined
global.warn = undefined
global.message = undefined
})
it('throws when supplied invalid configuration', () => {
expect(() => jiraIssue()).toThrow()
expect(() => jiraIssue({})).toThrow()
expect(() => jiraIssue({ key: 'ABC' })).toThrow()
expect(() => jiraIssue({ url: 'http://my.jira/browse' })).toThrow()
})
it('warns when PR title is missing JIRA issue key', () => {
global.danger = { github: { pr: { title: 'Change some things' } } }
jiraIssue({
key: 'ABC',
url: 'http://my.jira/browse',
})
expect(global.warn).toHaveBeenCalledWith(
'Please add the JIRA issue key to the PR title (e.g. ABC-123)',
)
})
it('adds the JIRA issue link to the messages table', () => {
global.danger = {
github: { pr: { title: '[ABC-808] Change some things' } },
}
jiraIssue({
key: 'ABC',
url: 'http://my.jira/browse',
})
expect(global.message).toHaveBeenCalledWith(
':link: <a href="http:/my.jira/browse/ABC-808">ABC-808</a>',
)
})
it('properly concatenates URL parts (trailing slash in url)', () => {
global.danger = {
github: { pr: { title: '[ABC-808] Change some things' } },
}
jiraIssue({
key: 'ABC',
url: 'http://my.jira/browse/',
})
expect(global.message).toHaveBeenCalledWith(
':link: <a href="http:/my.jira/browse/ABC-808">ABC-808</a>',
)
})
it('matches JIRA issue anywhere in title', () => {
global.danger = { github: { pr: { title: 'My changes - ABC-123' } } }
jiraIssue({
key: 'ABC',
url: 'http://my.jira/browse',
})
expect(global.message).toHaveBeenCalledWith(
':link: <a href="http:/my.jira/browse/ABC-123">ABC-123</a>',
)
})
it('does not match lowercase JIRA key in PR title', () => {
global.danger = {
github: { pr: { title: '[abc-808] Change some things' } },
}
jiraIssue({
key: 'ABC',
url: 'http://my.jira/browse',
})
expect(global.warn).toHaveBeenCalled()
})
it('honors custom emoji configuration', () => {
global.danger = { github: { pr: { title: '(ABC-123) Change stuff' } } }
jiraIssue({
key: 'ABC',
url: 'http://my.jira/browse',
emoji: ':paperclip:',
})
expect(global.message).toHaveBeenCalledWith(
':paperclip: <a href="http:/my.jira/browse/ABC-123">ABC-123</a>',
)
})
})
7 changes: 7 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
interface Options {
key: string
url: string
emoji?: string
}

export default function jiraIssue(options: Options): void
21 changes: 21 additions & 0 deletions types/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import jiraIssue from './'

jiraIssue({
key: 'JIRA',
url: 'https://my.jira.com/browse'
})

jiraIssue({
key: 'JIRA',
url: 'https://my.jira.com/browse',
emoji: ':dancer:'
})

// typings:expect-error
jiraIssue()

// typings:expect-error
jiraIssue({})

// typings:expect-error
jiraIssue({})
10 changes: 10 additions & 0 deletions types/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"sourceMap": false
}
}
8 changes: 8 additions & 0 deletions types/types.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { join } from 'path'
import { check } from 'typings-tester'

test('TypeScript types', () => {
expect(() => {
check([join(__dirname, 'test.ts')], join(__dirname, 'tsconfig.json'))
}).not.toThrow()
})
Loading

0 comments on commit 8638e2f

Please sign in to comment.