linked_issue.rb 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class GitLab
  3. class LinkedIssue
  4. STATES_MAPPING = {
  5. 'opened' => 'open'
  6. }.freeze
  7. QUERY = <<-GRAPHQL.freeze
  8. query($fullpath: ID!, $issue_id: String) {
  9. project(fullPath: $fullpath) {
  10. issue(iid: $issue_id) {
  11. iid
  12. webUrl
  13. title
  14. state
  15. milestone {
  16. title
  17. }
  18. assignees {
  19. edges {
  20. node {
  21. name
  22. }
  23. }
  24. }
  25. labels {
  26. edges {
  27. node {
  28. title
  29. color
  30. textColor
  31. description
  32. }
  33. }
  34. }
  35. }
  36. }
  37. }
  38. GRAPHQL
  39. attr_reader :client
  40. def initialize(client)
  41. @client = client
  42. end
  43. def find_by(url)
  44. @result = query_by_url(url)
  45. if @result.blank?
  46. new_url = query_new_url_by_rest_api(url)
  47. return if new_url.blank?
  48. @result = query_by_url(new_url)
  49. end
  50. return if @result.blank?
  51. to_h
  52. end
  53. private
  54. def to_h
  55. {
  56. id: @result['iid'],
  57. title: @result['title'],
  58. url: @result['webUrl'],
  59. icon_state: STATES_MAPPING.fetch(@result['state'], @result['state']),
  60. milestone: milestone,
  61. assignees: assignees,
  62. labels: labels,
  63. }
  64. end
  65. def assignees
  66. @result['assignees']['edges'].map do |assignee|
  67. assignee['node']['name']
  68. end
  69. end
  70. def labels
  71. @result['labels']['edges'].map do |label|
  72. {
  73. text_color: label['node']['textColor'],
  74. color: label['node']['color'],
  75. title: label['node']['title']
  76. }
  77. end
  78. end
  79. def milestone
  80. @result.dig('milestone', 'title')
  81. end
  82. def query_by_url(url)
  83. variables = variables(url)
  84. return if variables.blank?
  85. response = client.perform(
  86. query: GitLab::LinkedIssue::QUERY,
  87. variables: variables
  88. )
  89. response.dig('data', 'project', 'issue')
  90. end
  91. def query_new_url_by_rest_api(url)
  92. variables = variables(url)
  93. return if variables.blank?
  94. response = client.perform_rest_get_request(variables)
  95. return if response.blank?
  96. response['web_url']
  97. end
  98. def variables(url)
  99. if url !~ %r{^https?://([^/]+)/(.*)/-/issues/(\d+)$}
  100. raise Exceptions::UnprocessableEntity, __('Invalid GitLab issue link format')
  101. end
  102. host = $1
  103. fullpath = $2
  104. id = $3
  105. if client.endpoint_path.present?
  106. fullpath.sub!(client.endpoint_path, '')
  107. end
  108. if client.endpoint.exclude?(host)
  109. raise Exceptions::UnprocessableEntity, "Issue link doesn't match configured GitLab endpoint '#{client.endpoint}'"
  110. end
  111. {
  112. fullpath: fullpath,
  113. issue_id: id
  114. }
  115. end
  116. end
  117. end