danger-yajp 0.0.2 → 1.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17ad66f844e895f7e409c0576a5acb92cc040e19ae1aa1c5bb0e2cf2905bb144
4
- data.tar.gz: 4f0f8c655b370ecfbdf3f180400a63ec4b1beff3e1acd48f9737381f88c0a096
3
+ metadata.gz: 171560c106cee13af1c63bb6ab841c70503578850d3a88d1a5a4523c2de88e1a
4
+ data.tar.gz: f3243d0163c4a6d7f40596dcd72b7fd8d8a2ed3f8ef19454c3f4b49751c3125c
5
5
  SHA512:
6
- metadata.gz: b07a845fb824464a06a159419cf72580c7cd25867d18db56d61348dd097c42becfac016a9cc306648e42891d09a9ef66759a8c573dabf91fc92eb744f55f2b8f
7
- data.tar.gz: 48363be1c7b1d43659268b0447c81d1ed0c994a8445f319f6c4cc3544862c98f5ef76e4413e4d39ad0eaf0cd1d333ba382d5d085c12f1162ec7623411178c3c7
6
+ metadata.gz: '09526c08a590bbf1406eb835ce929083f491eb09289814457aa82ad4d32426fc6555dce7ee400459d32936ddc980d43db4fe583eea29d848750f2486a0a7834b'
7
+ data.tar.gz: 5cca801bdd4e3fd040c7d8b26730d98ccb2d11bc73c03e8577cd3f0d50e9093012e60316fa1fcef80b9ec631375ce80aaf3224b78001a3d3ee730c8c065a408a
@@ -0,0 +1,39 @@
1
+ name: Create release
2
+
3
+ on:
4
+ push:
5
+ branches: main
6
+
7
+ jobs:
8
+ build:
9
+ name: Retrieve version + create release
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - uses: actions/checkout@v2
14
+ with:
15
+ fetch-depth: 0
16
+
17
+ - name: Set up Ruby 2.6
18
+ uses: actions/setup-ruby@v1
19
+ with:
20
+ ruby-version: 2.6.x
21
+
22
+ - name: Retrieve version
23
+ id: version
24
+ run: |
25
+ version=$(ruby -e 'require "./lib/yajp/gem_version.rb"' -e 'puts Yajp::VERSION')
26
+ echo "TAG_NAME=$version" >> $GITHUB_ENV
27
+ latest_tag=$(git describe --tags --abbrev=0)
28
+ echo 'VERSION_DESCRIPTION<<EOF' >> $GITHUB_ENV
29
+ git log --pretty='format:%h %s' ${latest_tag}..HEAD >> $GITHUB_ENV
30
+ echo $'\nEOF' >> $GITHUB_ENV
31
+
32
+ - name: Create release
33
+ uses: actions/create-release@v1
34
+ env:
35
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36
+ with:
37
+ tag_name: ${{ env.TAG_NAME }}
38
+ release_name: v${{ env.TAG_NAME }}
39
+ body: ${{ env.VERSION_DESCRIPTION }}
@@ -4,6 +4,7 @@
4
4
 
5
5
  AllCops:
6
6
  TargetRubyVersion: 2.6
7
+ NewCops: enable
7
8
 
8
9
  Style/StringLiterals:
9
10
  EnforcedStyle: single_quotes
@@ -1,19 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- danger-yajp (0.0.2)
4
+ danger-yajp (1.0.0)
5
5
  danger-plugin-api
6
6
  jira-ruby
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activesupport (6.0.3.4)
11
+ activesupport (6.1.0)
12
12
  concurrent-ruby (~> 1.0, >= 1.0.2)
13
- i18n (>= 0.7, < 2)
14
- minitest (~> 5.1)
15
- tzinfo (~> 1.1)
16
- zeitwerk (~> 2.2, >= 2.2.2)
13
+ i18n (>= 1.6, < 2)
14
+ minitest (>= 5.1)
15
+ tzinfo (~> 2.0)
16
+ zeitwerk (~> 2.3)
17
17
  addressable (2.7.0)
18
18
  public_suffix (>= 2.0.2, < 5.0)
19
19
  ast (2.4.1)
@@ -29,8 +29,9 @@ GEM
29
29
  concurrent-ruby (1.1.7)
30
30
  cork (0.3.0)
31
31
  colored2 (~> 3.1)
32
- crack (0.4.4)
33
- danger (8.2.0)
32
+ crack (0.4.5)
33
+ rexml
34
+ danger (8.2.1)
34
35
  claide (~> 1.0)
35
36
  claide-plugins (>= 0.9.2)
36
37
  colored2 (~> 3.1)
@@ -46,14 +47,16 @@ GEM
46
47
  danger-plugin-api (1.0.0)
47
48
  danger (> 2.0)
48
49
  diff-lcs (1.4.4)
49
- faraday (1.1.0)
50
+ faraday (1.3.0)
51
+ faraday-net_http (~> 1.0)
50
52
  multipart-post (>= 1.2, < 3)
51
53
  ruby2_keywords
52
54
  faraday-http-cache (2.2.0)
53
55
  faraday (>= 0.8)
54
- ffi (1.13.1-x64-mingw32)
56
+ faraday-net_http (1.0.0)
57
+ ffi (1.14.2-x64-mingw32)
55
58
  formatador (0.2.5)
56
- git (1.7.0)
59
+ git (1.8.1)
57
60
  rchardet (~> 1.8)
58
61
  guard (2.16.2)
59
62
  formatador (>= 0.2.4)
@@ -70,9 +73,9 @@ GEM
70
73
  guard-compat (~> 1.1)
71
74
  rspec (>= 2.99.0, < 4.0)
72
75
  hashdiff (1.0.1)
73
- i18n (1.8.5)
76
+ i18n (1.8.7)
74
77
  concurrent-ruby (~> 1.0)
75
- jira-ruby (2.1.3)
78
+ jira-ruby (2.1.4)
76
79
  activesupport
77
80
  atlassian-jwt
78
81
  multipart-post
@@ -82,7 +85,7 @@ GEM
82
85
  rexml
83
86
  kramdown-parser-gfm (1.1.0)
84
87
  kramdown (~> 2.0)
85
- listen (3.2.1)
88
+ listen (3.4.0)
86
89
  rb-fsevent (~> 0.10, >= 0.10.3)
87
90
  rb-inotify (~> 0.9, >= 0.9.10)
88
91
  lumberjack (1.2.8)
@@ -96,50 +99,50 @@ GEM
96
99
  nenv (~> 0.1)
97
100
  shellany (~> 0.0)
98
101
  oauth (0.5.4)
99
- octokit (4.19.0)
102
+ octokit (4.20.0)
100
103
  faraday (>= 0.9)
101
104
  sawyer (~> 0.8.0, >= 0.5.3)
102
105
  open4 (1.3.4)
103
- parallel (1.19.2)
104
- parser (2.7.2.0)
106
+ parallel (1.20.1)
107
+ parser (3.0.0.0)
105
108
  ast (~> 2.4.1)
106
109
  pry (0.13.1)
107
110
  coderay (~> 1.1)
108
111
  method_source (~> 1.0)
109
112
  public_suffix (4.0.6)
110
113
  rainbow (3.0.0)
111
- rake (13.0.1)
114
+ rake (13.0.3)
112
115
  rb-fsevent (0.10.4)
113
116
  rb-inotify (0.10.1)
114
117
  ffi (~> 1.0)
115
118
  rchardet (1.8.0)
116
- regexp_parser (1.8.2)
119
+ regexp_parser (2.0.3)
117
120
  rexml (3.2.4)
118
121
  rspec (3.10.0)
119
122
  rspec-core (~> 3.10.0)
120
123
  rspec-expectations (~> 3.10.0)
121
124
  rspec-mocks (~> 3.10.0)
122
- rspec-core (3.10.0)
125
+ rspec-core (3.10.1)
123
126
  rspec-support (~> 3.10.0)
124
- rspec-expectations (3.10.0)
127
+ rspec-expectations (3.10.1)
125
128
  diff-lcs (>= 1.2.0, < 2.0)
126
129
  rspec-support (~> 3.10.0)
127
- rspec-mocks (3.10.0)
130
+ rspec-mocks (3.10.1)
128
131
  diff-lcs (>= 1.2.0, < 2.0)
129
132
  rspec-support (~> 3.10.0)
130
- rspec-support (3.10.0)
131
- rubocop (1.0.0)
133
+ rspec-support (3.10.1)
134
+ rubocop (1.7.0)
132
135
  parallel (~> 1.10)
133
136
  parser (>= 2.7.1.5)
134
137
  rainbow (>= 2.2.2, < 4.0)
135
- regexp_parser (>= 1.8)
138
+ regexp_parser (>= 1.8, < 3.0)
136
139
  rexml
137
- rubocop-ast (>= 0.6.0)
140
+ rubocop-ast (>= 1.2.0, < 2.0)
138
141
  ruby-progressbar (~> 1.7)
139
142
  unicode-display_width (>= 1.4.0, < 2.0)
140
- rubocop-ast (1.1.1)
143
+ rubocop-ast (1.4.0)
141
144
  parser (>= 2.7.1.5)
142
- ruby-progressbar (1.10.1)
145
+ ruby-progressbar (1.11.0)
143
146
  ruby2_keywords (0.0.2)
144
147
  sawyer (0.8.2)
145
148
  addressable (>= 2.3.5)
@@ -148,16 +151,15 @@ GEM
148
151
  terminal-table (1.8.0)
149
152
  unicode-display_width (~> 1.1, >= 1.1.1)
150
153
  thor (1.0.1)
151
- thread_safe (0.3.6)
152
- tzinfo (1.2.7)
153
- thread_safe (~> 0.1)
154
+ tzinfo (2.0.4)
155
+ concurrent-ruby (~> 1.0)
154
156
  unicode-display_width (1.7.0)
155
- webmock (3.9.3)
157
+ webmock (3.11.0)
156
158
  addressable (>= 2.3.6)
157
159
  crack (>= 0.3.2)
158
160
  hashdiff (>= 0.4.0, < 2.0.0)
159
- yard (0.9.25)
160
- zeitwerk (2.4.1)
161
+ yard (0.9.26)
162
+ zeitwerk (2.4.2)
161
163
 
162
164
  PLATFORMS
163
165
  x64-mingw32
@@ -169,10 +171,10 @@ DEPENDENCIES
169
171
  guard-rspec (~> 4.7)
170
172
  pry
171
173
  rake (~> 13.0)
172
- rspec (~> 3.9)
173
- rubocop (~> 1.0.0)
174
- webmock (~> 3.9)
175
- yard (~> 0.9.11)
174
+ rspec (~> 3)
175
+ rubocop (~> 1)
176
+ webmock (~> 3)
177
+ yard (~> 0.9)
176
178
 
177
179
  BUNDLED WITH
178
180
  2.1.4
data/README.md CHANGED
@@ -1,8 +1,10 @@
1
1
  # Yet Another Jira Plugin
2
2
 
3
- [![License](http://img.shields.io/badge/license-MIT-green.svg?style=flat)](LICENSE)
3
+ [![License](https://img.shields.io/github/license/juliendms/danger-yajp)](LICENSE)
4
+ [![Gem](https://img.shields.io/gem/v/danger-yajp)](https://rubygems.org/gems/danger-yajp)
5
+ [![Dependencies](https://img.shields.io/librariesio/release/rubygems/danger-yajp)](https://libraries.io/rubygems/danger-yajp)
4
6
 
5
- Yet Another Jira Plugin (in short: yajp) is a [Danger](https://danger.systems/ruby/) plugin that provides methods to easily find and manipulate issues from within the Dangerfile. The major difference with the existing Jira plugins is the ability to transition and update issues with the same feeling as manipulating PR data from Danger. This plugin was build in the same mind as Danger, meaning that you will find methods to easily manipulate Jira data, but no predefined warning and/or message.
7
+ Yet Another Jira Plugin (in short: yajp) is a [Danger](https://danger.systems/ruby/) plugin that provides methods to easily find and manipulate issues from within the Dangerfile. The major difference with the existing Jira plugins is the ability to transition and update issues with the same feeling as manipulating PR data from Danger. This plugin was build in the same mind as Danger, meaning that you will find methods to easily manipulate Jira data, but no predefined warning and/or message. It also does that by expanding the Issue class from `jira-ruby`.
6
8
 
7
9
  Inspired by [danger-jira](https://github.com/RestlessThinker/danger-jira), from which I borrowed the issue search, and by [danger-jira_sync](https://github.com/roverdotcom/danger-jira_sync) for their usage of the awesome [jira-ruby](https://github.com/sumoheavy/jira-ruby) gem.
8
10
 
@@ -16,12 +18,12 @@ gem 'danger-yajp'
16
18
 
17
19
  ## Usage
18
20
 
19
- You first need to define the environment variables `DANGER_JIRA_URL`, `DANGER_JIRA_USER` and `DANGER_JIRA_PASSWORD` in your CI environment, for example:
21
+ You first need to define the environment variables `DANGER_JIRA_URL`, `DANGER_JIRA_USER` and `DANGER_JIRA_API_TOKEN` in your CI environment, for example:
20
22
 
21
23
  ```
22
24
  DANGER_JIRA_URL: https://jira.company.com/jira
23
25
  DANGER_JIRA_USER: username
24
- DANGER_JIRA_PASSWORD: abcd12345
26
+ DANGER_JIRA_API_TOKEN: abcd12345
25
27
  ```
26
28
 
27
29
  ### Find issues
@@ -43,26 +45,40 @@ end
43
45
 
44
46
  ### Transition / update issues
45
47
 
46
- yajp allows to easily transition and update issues without the hassle of building custom json in the Dangerfile. The inputs are:
48
+ yajp allows to easily transition and update issues without the hassle of building custom json in the Dangerfile. The methods are available in the issue object, or to handle multiple issues in the plugin object. The inputs are:
47
49
 
48
- * An issue (from `jira-ruby`) or an array of issues
49
- * For the transition action, the ID of the transition
50
- * Any number of fields to be updated in the form: `key: value`
50
+ * For the transition action, the ID or name of the transition (which is not the name of the status)
51
+ * When using the methods from the plugin object, the issues to handled, which is by default the issues found when the command `find_issues` was last run.
52
+ * Any number of fields to be updated in a hash: `key: value`
51
53
 
54
+ Example 1: transition all the issues found after running `find_issues`:
52
55
  ```rb
53
- jira.transition(my_issue, 10, assignee: { name: 'username' }, customfield_11005: 'example')
56
+ jira.transition_all('done', assignee: { name: 'username' }, customfield_11005: 'example')
54
57
  ```
55
58
 
56
- The `transition` method only takes fields available in the transition screen. Use the `split_transition_fields` method to separate the fields available in the transition screen, or use the `transition_and_update` method to transition and update issues (and automatically dispatch the fields to the correct action).
59
+ Example 2: update a single issue:
60
+ ```rb
61
+ issue.update(assignee: { name: 'username' }, customfield_11005: 'example')
62
+ ```
63
+
64
+ The `transition` and `transition_all` methods only take fields available in the transition screen. Use the `split_transition_fields` method to separate the fields available in the transition screen, or use the `transition_and_update_all` method to transition and update issues (and automatically dispatch the fields to the correct action).
57
65
 
58
66
  > Transition IDs can be found in Jira under Project Workflow > Edit Workflow in Text Mode.
59
67
 
68
+ ### Reference the PR as a remote link
69
+
70
+ yajp can reference the PR as a remote link on Jira. It will use the icon of GitLab or Github depending on what you use. The remote link will use the URL of the PR as a `globalId` to not create duplicates. Optionnaly, you can specify the relationship with the issue (default is `relates to`), and the status, either as an object (eg. `{ "resolved": true, "icon": {...} }`) or as a boolean that will set the value of the property `resolved`. By default, no status is sent.
71
+
72
+ ```rb
73
+ jira.pr_as_remotelink(issue, false)
74
+ ```
75
+
60
76
  ### Issue URL
61
77
 
62
- Use `issue_link` to retrieve the browse URL of the Jira issue.
78
+ Use `link` to retrieve the browse URL of the Jira issue.
63
79
 
64
80
  ```rb
65
- message "<a href='#{jira.issue_link(issue)}'>#{issue.key} - #{issue.summary}</a>"
81
+ message "<a href='#{issue.link}'>#{issue.key} - #{issue.summary}</a>"
66
82
  ```
67
83
 
68
84
  ### API
@@ -82,13 +98,13 @@ if issues.empty?
82
98
  warn 'This PR does not contain any Jira issue.'
83
99
  else
84
100
  issues.each do |issue|
85
- message "<a href='#{jira.issue_link(issue)}'>#{issue.key} - #{issue.summary}</a>"
101
+ message "<a href='#{issue.link}'>#{issue.key} - #{issue.summary}</a>"
86
102
 
87
103
  case issue.status.name
88
104
  when 'In Progress'
89
- jira.transition_and_update(issue, 10, assignee: { name: 'username' }, customfield_11005: 'example')
105
+ jira.transition_and_update_all(10, issue: issue, assignee: { name: 'username' }, customfield_11005: 'example')
90
106
  when 'To Do', 'Blocked'
91
- warn "Issue <a href='#{jira.issue_link(issue)}'>#{issue.key}</a> is not in Dev status, please make sure the issue you're working on is in the correct status"
107
+ warn "Issue <a href='#{issue.link}'>#{issue.key}</a> is not in Dev status, please make sure the issue you're working on is in the correct status"
92
108
  end
93
109
  end
94
110
  end
@@ -29,12 +29,12 @@ Gem::Specification.new do |spec|
29
29
  spec.add_development_dependency 'rake', '~> 13.0'
30
30
 
31
31
  # Testing support
32
- spec.add_development_dependency 'rspec', '~> 3.9'
33
- spec.add_development_dependency 'webmock', '~> 3.9'
32
+ spec.add_development_dependency 'rspec', '~> 3'
33
+ spec.add_development_dependency 'webmock', '~> 3'
34
34
 
35
35
  # Linting code and docs
36
- spec.add_development_dependency 'rubocop', '~> 1.0.0'
37
- spec.add_development_dependency 'yard', '~> 0.9.11'
36
+ spec.add_development_dependency 'rubocop', '~> 1'
37
+ spec.add_development_dependency 'yard', '~> 0.9'
38
38
 
39
39
  # Makes testing easy via `bundle exec guard`
40
40
  spec.add_development_dependency 'guard', '~> 2.16'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Yajp
4
- VERSION = '0.0.2'
4
+ VERSION = '1.0.0'
5
5
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jira-ruby'
4
+
5
+ module Danger
6
+ # This class extends (aka monkey patch) the `JIRA::Resource::Issue` class with straightforward methods to easily transition and update issues.
7
+ #
8
+ class JIRA::Resource::Issue
9
+ # Get the browse URL of the issue.
10
+ #
11
+ # @return [String] the URL of the issue
12
+ #
13
+ def link
14
+ "#{ENV['DANGER_JIRA_URL']}/browse/#{key}"
15
+ end
16
+
17
+ # Update the issue.
18
+ #
19
+ # @example Update the fields `assignee` and `customfield_11005`
20
+ # issue.update(assignee: { name: 'username' }, customfield_11005: 'example')
21
+ #
22
+ # @param [Hash] fields Fields to update
23
+ #
24
+ # @return [Boolean] `true` if the issue was updated successfully, `false` otherwise.
25
+ #
26
+ def update(**fields)
27
+ return if fields.empty?
28
+
29
+ save({ fields: fields })
30
+ end
31
+
32
+ # Transition the issue using the ID or name of the transition. Transition IDs can be found in Jira under Project Workflow > Edit Workflow in Text Mode.
33
+ # The transition name is the text that appears on the issue screen to transition it.
34
+ # The fields that can be updated with this method are only the fields available in the transition screen of the transition. Otherwise use `transition_and_update`.
35
+ #
36
+ # @example Transition the issue and set the fields `assignee` and `customfield_11005` available on the transition screens
37
+ # jira.transition(my_issue, 10, assignee: { name: 'username' }, customfield_11005: 'example')
38
+ #
39
+ # @param [Integer, String] transition_id ID or name of the transition
40
+ # @param [Hash] fields Fields that can be updated on the transition screen
41
+ #
42
+ # @return [Boolean] `true` if the issue was transitioned successfully, `false` otherwise.
43
+ #
44
+ def transition(transition_id, **fields)
45
+ if transition_id.kind_of?(String)
46
+ transition_id = get_transition_id(transition_id)
47
+
48
+ return false if transition_id == -1
49
+ end
50
+ data = { transition: { id: transition_id.to_s } }
51
+ data[:fields] = fields unless fields.empty?
52
+
53
+ transitions.build.save(data)
54
+ end
55
+
56
+ # Retrieve the ID of the transition matching the given name.
57
+ #
58
+ # @param [String] name
59
+ #
60
+ # @return [Integer] the ID of the transition, or -1 if no match was found
61
+ #
62
+ def get_transition_id(name)
63
+ transitions.all.each do |transition|
64
+ return transition.id if transition.name.casecmp?(name)
65
+ end
66
+
67
+ return -1
68
+ end
69
+ end
70
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'jira-ruby'
3
+ require_relative 'issue'
4
4
 
5
5
  module Danger
6
6
  # Yet Another Jira Plugin (in short: yajp) provides methods to easily find and manipulate issues from within the Dangerfile.
@@ -18,13 +18,13 @@ module Danger
18
18
  # warn 'This PR does not contain any Jira issue.'
19
19
  # else
20
20
  # issues.each do |issue|
21
- # message "<a href='#{jira.issue_link(issue)}'>#{issue.key} - #{issue.summary}</a>"
21
+ # message "<a href='#{issue.link}'>#{issue.key} - #{issue.summary}</a>"
22
22
  #
23
23
  # case issue.status.name
24
24
  # when 'In Progress'
25
- # jira.transition_and_update(issue, 10, assignee: { name: 'username' }, customfield_11005: 'example')
25
+ # issue.transition(10, assignee: { name: 'username' }, customfield_11005: 'example')
26
26
  # when 'To Do', 'Blocked'
27
- # warn "Issue <a href='#{jira.issue_link(issue)}'>#{issue.key}</a> is not in Dev status, please make sure the issue you're working on is in the correct status"
27
+ # warn "Issue <a href='#{issue.link}'>#{issue.key}</a> is not in Dev status, please make sure the issue you're working on is in the correct status"
28
28
  # end
29
29
  # end
30
30
  # end
@@ -69,11 +69,11 @@ module Danger
69
69
  # jira.find_issues('KEY', search_title: false, search_branch: true)
70
70
  #
71
71
  # @param [Array<String>] key An array of Jira project keys like `['KEY', 'JIRA']`, or a single `String` with a Jira project key
72
- # @param [Boolean] search_title Option to search Jira issues from PR title, default `true`
73
- # @param [Boolean] search_commits Option to search Jira issues from from commit messages, default `false`
74
- # @param [Boolean] search_branch Option to search Jira issues from the name of the PR branch, default `false`
72
+ # @param [Boolean] search_title Option to search Jira issues from PR title
73
+ # @param [Boolean] search_commits Option to search Jira issues from from commit messages
74
+ # @param [Boolean] search_branch Option to search Jira issues from the name of the PR branch
75
75
  #
76
- # @return [Array<JIRA::Issue>] An array containing all the unique issues found in the PR.
76
+ # @return [Array<JIRA::Resource::Issue>] An array containing all the unique issues found in the PR.
77
77
  #
78
78
  def find_issues(key, search_title: true, search_commits: false, search_branch: false)
79
79
  regexp = build_regexp_from_key(key)
@@ -84,29 +84,28 @@ module Danger
84
84
  jira_issues.concat(search_branch(regexp)) if search_branch
85
85
  jira_issues.concat(search_pr_body(regexp)) if jira_issues.empty?
86
86
 
87
- jira_issues.uniq.map { |issue_key| @api.Issue.find(issue_key) }
87
+ @issues = jira_issues.uniq(&:downcase).map { |issue_key| @api.Issue.find(issue_key) }
88
88
  end
89
89
 
90
- # Transition the given Jira issue(s) using the ID of the transition. Transition IDs can be found in Jira under Project Workflow > Edit Workflow in Text Mode.
90
+ # Transition the given Jira issue(s) using the ID or name of the transition. Transition IDs can be found in Jira under Project Workflow > Edit Workflow in Text Mode.
91
+ # The transition name is the text that appears on the issue screen to transition it.
91
92
  # The fields that can be updated with this method are only the fields available in the transition screen of the transition. Otherwise use `transition_and_update`.
92
93
  #
93
- # @example Transition the issue `my_issue` and set the fields `assignee` and `customfield_11005` available on the transition screens
94
- # jira.transition(my_issue, 10, assignee: { name: 'username' }, customfield_11005: 'example')
94
+ # @example Transition the issue `my_issue` using the transition 'done' and set the fields `assignee` and `customfield_11005` available on the transition screens
95
+ # jira.transition_all(my_issue, 'done', assignee: { name: 'username' }, customfield_11005: 'example')
95
96
  #
96
- # @param [Array<JIRA::Issue>] issue An array of issues, or a single `JIRA::Issue`
97
- # @param [Integer] transition_id
97
+ # @param [Integer, String] transition_id ID or name of the transition
98
+ # @param [Array<JIRA::Resource::Issue>, JIRA::Resource::Issue] issue An array of issues, or a single issue
98
99
  # @param [Hash] fields Fields that can be updated on the transition screen
99
100
  #
100
101
  # @return [Boolean] `true` if all the issues were transitioned successfully, `false` otherwise.
101
102
  #
102
- def transition(issue, transition_id, **fields)
103
+ def transition_all(transition_id, issue: @issues, **fields)
103
104
  issues = issue.kind_of?(Array) ? issue : [] << issue
104
- data = { transition: { id: transition_id.to_s } }
105
- data[:fields] = fields unless fields.empty?
106
105
  result = true
107
106
 
108
107
  issues.each do |key|
109
- result &= key.transitions.build.save(data)
108
+ result &= key.transition(transition_id, **fields)
110
109
  end
111
110
 
112
111
  return result
@@ -115,21 +114,21 @@ module Danger
115
114
  # Update the given Jira issue(s).
116
115
  #
117
116
  # @example Update the issue `my_issue` and set the fields `assignee` and `customfield_11005`
118
- # jira.update(my_issue, assignee: { name: 'username' }, customfield_11005: 'example')
117
+ # jira.update_all(my_issue, assignee: { name: 'username' }, customfield_11005: 'example')
119
118
  #
120
- # @param [Array<JIRA::Issue>] issue An array of issue, or a single `JIRA::Issue`
119
+ # @param [Array<JIRA::Resource::Issue>, JIRA::Resource::Issue] issue An array of issue, or a single issue
121
120
  # @param [Hash] fields Fields to update
122
121
  #
123
122
  # @return [Boolean] `true` if all the issues were updated successfully, `false` otherwise.
124
123
  #
125
- def update(issue, **fields)
124
+ def update_all(issue: @issues, **fields)
126
125
  return if fields.empty?
127
126
 
128
127
  issues = issue.kind_of?(Array) ? issue : [] << issue
129
128
  result = true
130
129
 
131
130
  issues.each do |key|
132
- result &= key.save({ fields: fields })
131
+ result &= key.update(**fields)
133
132
  end
134
133
 
135
134
  return result
@@ -137,7 +136,7 @@ module Danger
137
136
 
138
137
  # Utility to split the given fields into fields that can be updated on the transition screen corresponding to the `transition_id` of the given `issue`.
139
138
  #
140
- # @param [JIRA::Issue] issue
139
+ # @param [JIRA::Resource::Issue] issue
141
140
  # @param [Integer] transition_id
142
141
  # @param [Hash] fields Fields to split
143
142
  #
@@ -161,31 +160,51 @@ module Danger
161
160
  # and use the other fields with the update action.
162
161
  #
163
162
  # @example Transition the issue `my_issue` and set the fields `assignee` and `customfield_11005`
164
- # jira.transition_and_update(my_issue, 10, assignee: { name: 'username' }, customfield_11005: 'example')
163
+ # jira.transition_and_update_all(my_issue, 10, assignee: { name: 'username' }, customfield_11005: 'example')
165
164
  #
166
- # @param [Array<JIRA::Issue>] issue An array of issues, or a single `JIRA::Issue`
167
165
  # @param [Integer] transition_id
166
+ # @param [Array<JIRA::Resource::Issue>, JIRA::Resource::Issue] issue An array of issues, or a single issue
168
167
  # @param [Hash] fields Fields to update
169
168
  #
170
169
  # @return [Boolean] `true` if all the issues were transitioned and updated successfully, `false` otherwise.
171
170
  #
172
- def transition_and_update(issue, transition_id, **fields)
171
+ def transition_and_update_all(transition_id, issue: @issues, **fields)
173
172
  issues = issue.kind_of?(Array) ? issue : [] << issue
174
173
  result = issues.first.split_transition_fields(transition_id, fields)
175
174
  transition_fields = result[:transition_fields]
176
175
  fields = result[:other_fields]
177
176
 
178
- result = transition(issues, transition_id, **transition_fields)
179
- result & update(issues, **fields)
177
+ result = transition(transition_id, issue: issues, **transition_fields)
178
+ result & update(issue: issues, **fields)
180
179
  end
181
180
 
182
- # Get the browse URL of a Jira issue.
181
+ # Add a remote link to the PR in the given Jira issues. It uses the link of the PR as the `globalId` of the remote link, thus avoiding to create duplicates each time the PR is updated.
182
+ #
183
+ # @param [Array<JIRA::Resource::Issue>, JIRA::Resource::Issue] issue An array of issues, or a single issue
184
+ # @param [<String>] relation Option to set the relationship of the remote link
185
+ # @param [<Hash>, <Boolean>] status Option to set the status property of the remote link, it can be <Hash> or a <Boolean> that will set the value of the property `resolved`
183
186
  #
184
- # @param [JIRA::Issue] issue
187
+ # @return [Boolean] `true` if all the remote links were added successfully, `false` otherwise.
185
188
  #
186
- # @return [String] the URL of the issue
187
- def issue_link(issue)
188
- "#{ENV['DANGER_JIRA_URL']}/browse/#{issue.key}"
189
+ def pr_as_remotelink(issue, relation: 'relates to', status: nil)
190
+ issues = issue.kind_of?(Array) ? issue : [] << issue
191
+ result = true
192
+
193
+ remote_link_prop = { object: { url: pr_link, title: vcs_host.pr_title, icon: link_icon } }
194
+ remote_link_prop[:globalId] = pr_link
195
+ remote_link_prop[:relationship] = relation
196
+
197
+ if status.kind_of?(Hash)
198
+ remote_link_prop[:object][:status] = status
199
+ elsif !status.nil?
200
+ remote_link_prop[:object][:status] = { resolved: status }
201
+ end
202
+
203
+ issues.each do |key|
204
+ result &= key.remotelink.build.save(remote_link_prop)
205
+ end
206
+
207
+ return result
189
208
  end
190
209
 
191
210
  private
@@ -196,9 +215,27 @@ module Danger
196
215
  github
197
216
  end
198
217
 
218
+ def pr_link
219
+ return @pr_link unless @pr_link.nil?
220
+
221
+ if defined? @dangerfile.gitlab
222
+ @pr_link = vcs_host.pr_json['web_url']
223
+ else
224
+ @pr_link = vcs_host.pr_json['html_url']
225
+ end
226
+
227
+ return @pr_link
228
+ end
229
+
230
+ def link_icon
231
+ return { title: 'Gitlab', url16x16: 'https://gitlab.com/favicon.ico' } if defined? @dangerfile.gitlab
232
+
233
+ { title: 'Github', url16x16: 'https://github.com/favicon.ico' }
234
+ end
235
+
199
236
  def build_regexp_from_key(key)
200
237
  keys = key.kind_of?(Array) ? key.join('|') : key
201
- return /((?:#{keys})-[0-9]+)/
238
+ return /((?:#{keys})-[0-9]+)/i
202
239
  end
203
240
 
204
241
  def search_title(regexp)
@@ -0,0 +1 @@
1
+ {"object":{"url":"https://github.com/test/pull/1234","title":"PR Title","icon":{"title":"Github","url16x16":"https://github.com/favicon.ico"},"status":{"resolved":true}},"globalId":"https://github.com/test/pull/1234","relationship":"relates to"}
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'spec_helper'
4
4
 
5
+ # rubocop:disable Metrics/ModuleLength
5
6
  module Danger
6
7
  describe Danger::DangerYajp do
7
8
  before do
@@ -46,9 +47,9 @@ module Danger
46
47
  end
47
48
 
48
49
  it 'can find jira issues via branch name' do
49
- allow(plugin).to receive_message_chain('github.branch_for_head').and_return('bugfix/WEB-126')
50
+ allow(plugin).to receive_message_chain('github.branch_for_head').and_return('bugfix/web-126')
50
51
  issues = plugin.search_branch(plugin.build_regexp_from_key('WEB'))
51
- expect(issues).to eq(['WEB-126'])
52
+ expect(issues).to eq(['web-126'])
52
53
  end
53
54
 
54
55
  it 'can find jira issues in pr body' do
@@ -61,17 +62,19 @@ module Danger
61
62
  issue = Object.new
62
63
 
63
64
  def issue.find(key)
64
- return key
65
+ # The find method in jira-ruby plugin is not case sensitive, hence the upcase.
66
+ return key.upcase
65
67
  end
66
68
 
67
69
  allow_any_instance_of(JIRA::Client).to receive(:Issue).and_return(issue)
68
70
 
69
71
  allow(plugin).to receive_message_chain('github.pr_title').and_return('Fix for WEB-128 and WEB-129')
70
- allow(plugin).to receive_message_chain('github.branch_for_head').and_return('bugfix/WEB-128')
72
+ allow(plugin).to receive_message_chain('github.branch_for_head').and_return('bugfix/web-128')
71
73
  issues = plugin.find_issues('WEB', search_branch: true)
72
74
  expect(issues).to eq(['WEB-128', 'WEB-129'])
73
75
  end
74
76
 
77
+ # rubocop:disable Naming/VariableNumber
75
78
  it 'can split transition field from other fields' do
76
79
  json = File.read("#{File.dirname(__FILE__)}/support/transitions.all.json")
77
80
  url = "#{ENV['DANGER_JIRA_URL']}/rest/api/2/issue/WEB-130/transitions"
@@ -89,13 +92,16 @@ module Danger
89
92
 
90
93
  it 'can transition an issue' do
91
94
  expected_json = '{"transition":{"id":"2"},"fields":{"assignee":{"name":"username"},"customfield_11005":"example"}}'
92
- url = "#{ENV['DANGER_JIRA_URL']}/rest/api/2/issue/WEB-131/transitions"
93
- issue = plugin.api.Issue.build
95
+ issue_id = Random.rand(1000)
96
+ url = "#{ENV['DANGER_JIRA_URL']}/rest/api/2/issue/#{issue_id}/transitions"
97
+ issue = plugin.api.Issue.build({ 'id' => issue_id, 'key' => 'WEB-131' })
98
+ transition_1 = issue.transitions.build({ 'id' => '2', 'name' => 'TEST' })
99
+ transition_2 = issue.transitions.build({ 'id' => '3', 'name' => 'FAKE' })
94
100
 
95
- allow(issue).to receive(:key_value).and_return('WEB-131')
101
+ allow_any_instance_of(JIRA::HasManyProxy).to receive(:all).and_return([transition_1, transition_2])
96
102
  stub = stub_request(:post, url).
97
103
  with(body: expected_json)
98
- result = plugin.transition(issue, 2, assignee: { name: 'username' }, customfield_11005: 'example')
104
+ result = plugin.transition_all('test', issue: issue, assignee: { name: 'username' }, customfield_11005: 'example')
99
105
 
100
106
  expect(stub).to have_been_requested.once
101
107
  expect(result).to be true
@@ -104,18 +110,37 @@ module Danger
104
110
  it 'can update issues' do
105
111
  expected_json = '{"fields":{"assignee":{"name":"username"},"customfield_11005":"example"}}'
106
112
  uri_template = Addressable::Template.new "#{ENV['DANGER_JIRA_URL']}/rest/api/2/issue/{issue}"
107
- issue1 = plugin.api.Issue.build
108
- issue2 = plugin.api.Issue.build
113
+ issue1 = plugin.api.Issue.build({ 'id' => Random.rand(1000), 'self' => "#{ENV['DANGER_JIRA_URL']}/rest/api/2/issue/WEB-132", 'key' => 'WEB-132' })
114
+ issue2 = plugin.api.Issue.build({ 'id' => Random.rand(1000), 'self' => "#{ENV['DANGER_JIRA_URL']}/rest/api/2/issue/WEB-133", 'key' => 'WEB-133' })
109
115
 
110
- allow(issue1).to receive(:key_value).and_return('WEB-132')
111
- allow(issue2).to receive(:key_value).and_return('WEB-133')
112
116
  stub = stub_request(:put, uri_template).
113
117
  with(body: expected_json)
114
- result = plugin.update([issue1, issue2], assignee: { name: 'username' }, customfield_11005: 'example')
118
+ result = plugin.update_all(issue: [issue1, issue2], assignee: { name: 'username' }, customfield_11005: 'example')
115
119
 
116
120
  expect(stub).to have_been_requested.twice
117
121
  expect(result).to be true
118
122
  end
123
+ # rubocop:enable Naming/VariableNumber
124
+
125
+ it 'can add remote link' do
126
+ pr_title = 'PR Title'
127
+ pr_json = { 'html_url' => 'https://github.com/test/pull/1234' }
128
+ url = "#{ENV['DANGER_JIRA_URL']}/rest/api/2/issue/WEB-134/remotelink"
129
+ json = File.read("#{File.dirname(__FILE__)}/support/remotelink.json")
130
+ issue = plugin.api.Issue.build
131
+
132
+ allow(issue).to receive(:key_value).and_return('WEB-134')
133
+ allow(dangerfile.github).to receive(:pr_json).and_return(pr_json)
134
+ allow(dangerfile.github).to receive(:pr_title).and_return(pr_title)
135
+
136
+ stub = stub_request(:post, url).
137
+ with(body: json)
138
+ result = plugin.pr_as_remotelink(issue, status: true)
139
+
140
+ expect(stub).to have_been_requested.once
141
+ expect(result).to be true
142
+ end
119
143
  end
120
144
  end
121
145
  end
146
+ # rubocop:enable Metrics/ModuleLength
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: danger-yajp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - juliendms
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-05 00:00:00.000000000 Z
11
+ date: 2021-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: danger-plugin-api
@@ -72,56 +72,56 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '3.9'
75
+ version: '3'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '3.9'
82
+ version: '3'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: webmock
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '3.9'
89
+ version: '3'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '3.9'
96
+ version: '3'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 1.0.0
103
+ version: '1'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 1.0.0
110
+ version: '1'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: yard
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 0.9.11
117
+ version: '0.9'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 0.9.11
124
+ version: '0.9'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: guard
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -171,6 +171,7 @@ executables: []
171
171
  extensions: []
172
172
  extra_rdoc_files: []
173
173
  files:
174
+ - ".github/workflows/create-tag.yml"
174
175
  - ".github/workflows/gem-push.yml"
175
176
  - ".gitignore"
176
177
  - ".rubocop.yml"
@@ -185,8 +186,10 @@ files:
185
186
  - lib/danger_plugin.rb
186
187
  - lib/danger_yajp.rb
187
188
  - lib/yajp/gem_version.rb
189
+ - lib/yajp/issue.rb
188
190
  - lib/yajp/plugin.rb
189
191
  - spec/spec_helper.rb
192
+ - spec/support/remotelink.json
190
193
  - spec/support/transitions.all.json
191
194
  - spec/yajp_spec.rb
192
195
  homepage: https://github.com/juliendms/danger-yajp
@@ -215,5 +218,6 @@ summary: Yet Another Jira Plugin is a danger plugin to find issues, access their
215
218
  and perform operations on them.
216
219
  test_files:
217
220
  - spec/spec_helper.rb
221
+ - spec/support/remotelink.json
218
222
  - spec/support/transitions.all.json
219
223
  - spec/yajp_spec.rb