Class: Danger::DangerYajp

Inherits:
Plugin
  • Object
show all
Defined in:
lib/yajp/plugin.rb

Overview

Yet Another Jira Plugin (in short: yajp) 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. Like Danger, it requires environment variables to work:

* DANGER_JIRA_URL: the URL of the Jira server (ex: `https://jira.company.com/jira`)
* DANGER_JIRA_USER: the Jira user that will use the Jira API
* DANGER_JIRA_API_TOKEN: the token associated to the user (Jira Cloud) or the password of the user (Jira Server)

Examples:

Full example of a Dangerfile

issues = jira.find_issues('KEY')

if issues.empty?
  warn 'This PR does not contain any Jira issue.'
else
  issues.each do |issue|
    message "<a href='#{jira.issue_link(issue)}'>#{issue.key} - #{issue.summary}</a>"

    case issue.status.name
    when 'In Progress'
      jira.transition_and_update(issue, 10, assignee: { name: 'username' }, customfield_11005: 'example')
    when 'To Do', 'Blocked'
      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"
    end
  end
end

Access the Jira client of ‘jira-ruby` and list all Jira projects

jira.api.Project.all

See Also:

  • juliendms/danger-yajp

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dangerfile) ⇒ DangerYajp

Returns a new instance of DangerYajp.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/yajp/plugin.rb', line 45

def initialize(dangerfile)
  throw Error('The environment variable DANGER_JIRA_URL is required') if ENV['DANGER_JIRA_URL'].nil?

  super(dangerfile)
  url_parser = %r{(?<site>https?://[^/]+)(?<context_path>/.+)}.match(ENV['DANGER_JIRA_URL'])

  options = {
    username:       ENV['DANGER_JIRA_USER'],
    password:       ENV['DANGER_JIRA_API_TOKEN'],
    site:           url_parser[:site],
    context_path:   url_parser[:context_path],
    auth_type:      :basic
  }

  @api = JIRA::Client.new(options)
end

Instance Attribute Details

#apiJIRA::Client (readonly)

Give access to the Jira API via ‘jira-ruby` client.

Returns:

  • (JIRA::Client)

    Jira API client from ‘jira-ruby`



43
44
45
# File 'lib/yajp/plugin.rb', line 43

def api
  @api
end

Class Method Details

.instance_nameObject



62
63
64
# File 'lib/yajp/plugin.rb', line 62

def self.instance_name
  return 'jira'
end

Instance Method Details

#find_issues(key, search_title: true, search_commits: false, search_branch: false) ⇒ Array<JIRA::Issue>

Find Jira issues (keys) in the specified parameters of the PR.

Examples:

Find issues in project KEY from the name of the PR branch

jira.find_issues('KEY', search_title: false, search_branch: true)

Parameters:

  • key (Array<String>)

    An array of Jira project keys like ‘[’KEY’, ‘JIRA’]‘, or a single `String` with a Jira project key

  • search_title (Boolean) (defaults to: true)

    Option to search Jira issues from PR title, default ‘true`

  • search_commits (Boolean) (defaults to: false)

    Option to search Jira issues from from commit messages, default ‘false`

  • search_branch (Boolean) (defaults to: false)

    Option to search Jira issues from the name of the PR branch, default ‘false`

Returns:

  • (Array<JIRA::Issue>)

    An array containing all the unique issues found in the PR.



78
79
80
81
82
83
84
85
86
87
88
# File 'lib/yajp/plugin.rb', line 78

def find_issues(key, search_title: true, search_commits: false, search_branch: false)
  regexp = build_regexp_from_key(key)
  jira_issues = []

  jira_issues.concat(search_title(regexp)) if search_title
  jira_issues.concat(search_commits(regexp)) if search_commits
  jira_issues.concat(search_branch(regexp)) if search_branch
  jira_issues.concat(search_pr_body(regexp)) if jira_issues.empty?

  jira_issues.uniq.map { |issue_key| @api.Issue.find(issue_key) }
end

Get the browse URL of a Jira issue.

Parameters:

  • issue (JIRA::Issue)

Returns:

  • (String)

    the URL of the issue



187
188
189
# File 'lib/yajp/plugin.rb', line 187

def issue_link(issue)
  "#{ENV['DANGER_JIRA_URL']}/browse/#{issue.key}"
end

#split_transition_fields(issue, transition_id, **fields) ⇒ Hash

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`.

Parameters:

  • issue (JIRA::Issue)
  • transition_id (Integer)
  • fields (Hash)

    Fields to split

Returns:

  • (Hash)
    • :transition_fields [Hash] A hash containing the fields available in the transition screens

    • :other_fields [Hash] A hash containing the other fields



148
149
150
151
152
153
154
155
156
157
158
# File 'lib/yajp/plugin.rb', line 148

def split_transition_fields(issue, transition_id, **fields)
  transitions = issue.transitions.all.keep_if { |transition| transition.attrs['id'] == transition_id.to_s }
  transition_fields = transitions.first.attrs['fields']
  transition_data = {}

  fields.each_key do |field|
    transition_data[field] = fields.delete(field) if transition_fields&.key?(field.to_s)
  end

  { transition_fields: transition_data, other_fields: fields }
end

#transition(issue, transition_id, **fields) ⇒ Boolean

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. 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`.

Examples:

Transition the issue ‘my_issue` and set the fields `assignee` and `customfield_11005` available on the transition screens

jira.transition(my_issue, 10, assignee: { name: 'username' }, customfield_11005: 'example')

Parameters:

  • issue (Array<JIRA::Issue>)

    An array of issues, or a single ‘JIRA::Issue`

  • transition_id (Integer)
  • fields (Hash)

    Fields that can be updated on the transition screen

Returns:

  • (Boolean)

    ‘true` if all the issues were transitioned successfully, `false` otherwise.



102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/yajp/plugin.rb', line 102

def transition(issue, transition_id, **fields)
  issues = issue.kind_of?(Array) ? issue : [] << issue
  data = { transition: { id: transition_id.to_s } }
  data[:fields] = fields unless fields.empty?
  result = true

  issues.each do |key|
    result &= key.transitions.build.save(data)
  end

  return result
end

#transition_and_update(issue, transition_id, **fields) ⇒ Boolean

Transition and update the given issues. It will use the ‘split_transition_fields` method to provide the right fields for the transition action, and use the other fields with the update action.

Examples:

Transition the issue ‘my_issue` and set the fields `assignee` and `customfield_11005`

jira.transition_and_update(my_issue, 10, assignee: { name: 'username' }, customfield_11005: 'example')

Parameters:

  • issue (Array<JIRA::Issue>)

    An array of issues, or a single ‘JIRA::Issue`

  • transition_id (Integer)
  • fields (Hash)

    Fields to update

Returns:

  • (Boolean)

    ‘true` if all the issues were transitioned and updated successfully, `false` otherwise.



172
173
174
175
176
177
178
179
180
# File 'lib/yajp/plugin.rb', line 172

def transition_and_update(issue, transition_id, **fields)
  issues = issue.kind_of?(Array) ? issue : [] << issue
  result = issues.first.split_transition_fields(transition_id, fields)
  transition_fields = result[:transition_fields]
  fields = result[:other_fields]

  result = transition(issues, transition_id, **transition_fields)
  result & update(issues, **fields)
end

#update(issue, **fields) ⇒ Boolean

Update the given Jira issue(s).

Examples:

Update the issue ‘my_issue` and set the fields `assignee` and `customfield_11005`

jira.update(my_issue, assignee: { name: 'username' }, customfield_11005: 'example')

Parameters:

  • issue (Array<JIRA::Issue>)

    An array of issue, or a single ‘JIRA::Issue`

  • fields (Hash)

    Fields to update

Returns:

  • (Boolean)

    ‘true` if all the issues were updated successfully, `false` otherwise.



125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/yajp/plugin.rb', line 125

def update(issue, **fields)
  return if fields.empty?

  issues = issue.kind_of?(Array) ? issue : [] << issue
  result = true

  issues.each do |key|
    result &= key.save({ fields: fields })
  end

  return result
end