Module: Archsight::Import::Handlers::JiraBase

Included in:
JiraDiscover, JiraMetrics
Defined in:
lib/archsight/import/handlers/jira_base.rb

Overview

Shared module for Jira handlers

Provides common functionality for Jira API interactions including:

  • HTTP client with Bearer token authentication

  • User lookup and caching (email -> Jira username)

  • Project info lookup and caching

  • Team loading and email extraction

  • Rate limiting

Instance Method Summary collapse

Instance Method Details

#extract_team_emails(team) ⇒ Array<String>

Extract email addresses from a team’s annotations

Parameters:

Returns:

  • (Array<String>)

    Unique email addresses



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/archsight/import/handlers/jira_base.rb', line 117

def extract_team_emails(team)
  emails = []

  if (lead = team.annotations["team/lead"])
    email = extract_email(lead)
    emails << email if email
  end

  if (members = team.annotations["team/members"])
    members.each_line do |line|
      line = line.strip
      next if line.empty?

      email = extract_email(line)
      emails << email if email
    end
  end

  emails.compact.uniq
end

#find_jira_users(emails) ⇒ Array<String>

Find Jira usernames for a list of email addresses

Parameters:

  • emails (Array<String>)

    Email addresses to look up

Returns:

  • (Array<String>)

    Jira usernames



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/archsight/import/handlers/jira_base.rb', line 65

def find_jira_users(emails)
  users = []

  emails.each do |email|
    # Check cache first
    if @user_cache.key?(email)
      users << @user_cache[email] if @user_cache[email]
      next
    end

    rate_limit
    begin
      result = jira_get("/rest/api/2/user/search?username=#{CGI.escape(email)}&maxResults=1")

      if result&.any?
        user = result.first
        username = user["name"] || user["accountId"]
        @user_cache[email] = username
        users << username
      else
        @user_cache[email] = nil
      end
    rescue StandardError => e
      progress.warn("Error searching for user #{email}: #{e.message}")
      @user_cache[email] = nil
    end
  end

  users.compact.uniq
end

#get_project_info(project_key) ⇒ Hash?

Get project info from Jira API

Parameters:

  • project_key (String)

    Project key

Returns:

  • (Hash, nil)

    Project info or nil if not found



99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/archsight/import/handlers/jira_base.rb', line 99

def get_project_info(project_key)
  return @project_cache[project_key] if @project_cache.key?(project_key)

  rate_limit
  begin
    project = jira_get("/rest/api/2/project/#{project_key}")
    @project_cache[project_key] = project
    project
  rescue StandardError => e
    progress.warn("Error fetching project #{project_key}: #{e.message}")
    @project_cache[project_key] = nil
    nil
  end
end

#init_jira_client(host:, token:, rate_limit_ms: 100) ⇒ Object

Initialize Jira client

Parameters:

  • host (String)

    Jira host (e.g., “hosting-jira.1and1.org”)

  • token (String)

    Jira Bearer token

  • rate_limit_ms (Integer) (defaults to: 100)

    Rate limit delay in milliseconds



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/archsight/import/handlers/jira_base.rb', line 23

def init_jira_client(host:, token:, rate_limit_ms: 100)
  @jira_host = host
  @jira_token = token
  @rate_limit_ms = rate_limit_ms
  @jira_uri = URI("https://#{host}")
  @jira_http = Net::HTTP.new(@jira_uri.host, @jira_uri.port)
  @jira_http.use_ssl = true
  @jira_http.read_timeout = 120
  @user_cache = {}
  @project_cache = {}
end

#jira_get(path) ⇒ Hash, Array

Make a GET request to the Jira API

Parameters:

  • path (String)

    API path (e.g., “/rest/api/2/myself”)

Returns:

  • (Hash, Array)

    Parsed JSON response

Raises:

  • (RuntimeError)

    on HTTP errors



39
40
41
42
43
44
45
46
47
48
# File 'lib/archsight/import/handlers/jira_base.rb', line 39

def jira_get(path)
  request = Net::HTTP::Get.new(path)
  request["Authorization"] = "Bearer #{@jira_token}"
  request["Content-Type"] = "application/json"
  response = @jira_http.request(request)

  raise "Jira API error: #{response.code} #{response.message}" unless response.is_a?(Net::HTTPSuccess)

  JSON.parse(response.body)
end

#load_teams(ignored_teams: [], require_jira: false, require_no_jira: false) ⇒ Array<Archsight::Resources::Base>

Load teams from database with optional filter

Parameters:

  • ignored_teams (Array<String>) (defaults to: [])

    Team names to ignore

  • require_jira (Boolean) (defaults to: false)

    If true, only return teams WITH team/jira

  • require_no_jira (Boolean) (defaults to: false)

    If true, only return teams WITHOUT team/jira

Returns:



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/archsight/import/handlers/jira_base.rb', line 143

def load_teams(ignored_teams: [], require_jira: false, require_no_jira: false)
  teams = database.instances_by_kind("BusinessActor")

  filtered = teams.values.reject do |team|
    next true if ignored_teams.include?(team.name)
    next true if extract_team_emails(team).empty?

    jira_project = team.annotations["team/jira"]
    has_jira = jira_project && !jira_project.empty?

    next true if require_jira && !has_jira
    next true if require_no_jira && has_jira

    false
  end

  filtered.sort_by(&:name)
end

#parse_list_config(value) ⇒ Array<String>

Parse comma-separated config values

Parameters:

  • value (String, nil)

    Comma-separated values

Returns:

  • (Array<String>)

    Parsed array



165
166
167
168
169
# File 'lib/archsight/import/handlers/jira_base.rb', line 165

def parse_list_config(value)
  return [] if value.nil? || value.empty?

  value.split(",").map(&:strip)
end

#rate_limitObject

Apply rate limiting between API calls



172
173
174
# File 'lib/archsight/import/handlers/jira_base.rb', line 172

def rate_limit
  sleep(@rate_limit_ms / 1000.0)
end

#verify_jira_credentialsHash

Verify Jira credentials by calling /rest/api/2/myself

Returns:

  • (Hash)

    User info from Jira

Raises:

  • (RuntimeError)

    on authentication failure



53
54
55
56
57
58
59
60
# File 'lib/archsight/import/handlers/jira_base.rb', line 53

def verify_jira_credentials
  progress.update("Verifying Jira credentials...")
  user = jira_get("/rest/api/2/myself")
  progress.update("Authenticated as #{user["displayName"] || user["name"]}")
  user
rescue StandardError => e
  raise "Jira authentication failed: #{e.message}"
end