Browse Source

Fixes #5015 - Gitlab/Github UI loses links when they are renamed.

Co-authored-by: Rolf Schmidt <rolf.schmidt@zammad.com>
Timo Triebensky 6 months ago
parent
commit
a8427ed9d3

+ 1 - 1
app/assets/javascripts/app/controllers/ticket_zoom/sidebar_git_issue.coffee

@@ -140,7 +140,7 @@ class App.SidebarGitIssue extends App.Controller
       id:    "#{@providerIdentifier}-#{@taskKey}"
       type:  'POST'
       url:   "#{@apiPath}/integration/#{@providerIdentifier}"
-      data: JSON.stringify(links: params.links)
+      data: JSON.stringify(ticket_id: @ticket?.id, links: params.links)
       success: (data, status, xhr) ->
         if data.response
 

+ 4 - 2
app/controllers/integration/github_controller.rb

@@ -24,10 +24,13 @@ class Integration::GitHubController < ApplicationController
     config = Setting.get('github_config')
 
     github = ::GitHub.new(config['endpoint'], config['api_token'])
+    data = github.issues_by_urls(params[:links])
+
+    github.fix_urls_for_ticket(params[:ticket_id], data[:url_replacements])
 
     render json: {
       result:   'ok',
-      response: github.issues_by_urls(params[:links]),
+      response: data[:issues],
     }
   rescue => e
     logger.error e
@@ -51,5 +54,4 @@ class Integration::GitHubController < ApplicationController
       result: 'ok',
     }
   end
-
 end

+ 4 - 2
app/controllers/integration/gitlab_controller.rb

@@ -24,10 +24,13 @@ class Integration::GitLabController < ApplicationController
     config = Setting.get('gitlab_config')
 
     gitlab = ::GitLab.new(config['endpoint'], config['api_token'], verify_ssl: config['verify_ssl'])
+    data = gitlab.issues_by_urls(params[:links])
+
+    gitlab.fix_urls_for_ticket(params[:ticket_id], data[:url_replacements])
 
     render json: {
       result:   'ok',
-      response: gitlab.issues_by_urls(params[:links]),
+      response: data[:issues],
     }
   rescue => e
     logger.error e
@@ -51,5 +54,4 @@ class Integration::GitLabController < ApplicationController
       result: 'ok',
     }
   end
-
 end

+ 2 - 2
i18n/zammad.pot

@@ -7634,7 +7634,7 @@ msgstr ""
 msgid "Invalid GitHub GraphQL API token"
 msgstr ""
 
-#: lib/github/linked_issue.rb:102
+#: lib/github/linked_issue.rb:104
 msgid "Invalid GitHub issue link format"
 msgstr ""
 
@@ -7642,7 +7642,7 @@ msgstr ""
 msgid "Invalid GitLab GraphQL API token"
 msgstr ""
 
-#: lib/gitlab/linked_issue.rb:102
+#: lib/gitlab/linked_issue.rb:122
 msgid "Invalid GitLab issue link format"
 msgstr ""
 

+ 24 - 0
lib/git_integration_base.rb

@@ -0,0 +1,24 @@
+# Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
+
+class GitIntegrationBase
+  attr_reader :client, :issue_type
+
+  def fix_urls_for_ticket(ticket_id, url_replacements)
+    return if ticket_id.blank?
+    return if url_replacements.blank?
+
+    ticket = Ticket.find_by(id: ticket_id)
+    return if ticket.blank?
+    return if ticket.preferences.blank?
+    return if ticket.preferences[issue_type].blank?
+    return if ticket.preferences[issue_type][:issue_links].blank?
+
+    ticket.with_lock do
+      new_issue_links = Array(ticket.preferences[issue_type][:issue_links])
+      new_issue_links.map! { |original_link| url_replacements[original_link].presence ? url_replacements[original_link] : original_link }
+
+      ticket.preferences[issue_type][:issue_links] = Array(new_issue_links).uniq
+      ticket.save!
+    end
+  end
+end

+ 15 - 6
lib/github.rb

@@ -1,10 +1,9 @@
 # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
 
-class GitHub
-  attr_reader :client
-
-  def initialize(endpoint, api_token)
-    @client = GitHub::HttpClient.new(endpoint, api_token)
+class GitHub < GitIntegrationBase
+  def initialize(endpoint, api_token) # rubocop:disable Lint/MissingSuper
+    @client     = GitHub::HttpClient.new(endpoint, api_token)
+    @issue_type = :github
   end
 
   def verify!
@@ -12,12 +11,22 @@ class GitHub
   end
 
   def issues_by_urls(urls)
-    urls.uniq.each_with_object([]) do |url, result|
+    url_replacements = {}
+    issues = urls.uniq.each_with_object([]) do |url, result|
       issue = issue_by_url(url)
       next if issue.blank?
 
+      if issue[:url] != url
+        url_replacements.store(url, issue[:url])
+      end
+
       result << issue
     end
+
+    {
+      issues:           issues,
+      url_replacements: url_replacements
+    }
   end
 
   def issue_by_url(url)

+ 3 - 1
lib/github/linked_issue.rb

@@ -15,6 +15,7 @@ class GitHub
            number
            title
            state
+           url
            milestone {
              title
            }
@@ -48,7 +49,7 @@ class GitHub
       @result = query_by_url(url)
       return if @result.blank?
 
-      to_h.merge(url: url)
+      to_h
     end
 
     private
@@ -57,6 +58,7 @@ class GitHub
       {
         id:         @result['number'].to_s,
         title:      @result['title'],
+        url:        @result['url'],
         icon_state: STATES_MAPPING.fetch(@result['state'], @result['state']),
         milestone:  milestone,
         assignees:  assignees,

+ 15 - 6
lib/gitlab.rb

@@ -1,10 +1,9 @@
 # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
 
-class GitLab
-  attr_reader :client
-
-  def initialize(endpoint, api_token, verify_ssl: true)
-    @client = GitLab::HttpClient.new(endpoint, api_token, verify_ssl: verify_ssl)
+class GitLab < GitIntegrationBase
+  def initialize(endpoint, api_token, verify_ssl: true) # rubocop:disable Lint/MissingSuper
+    @client     = GitLab::HttpClient.new(endpoint, api_token, verify_ssl: verify_ssl)
+    @issue_type = :gitlab
   end
 
   def verify!
@@ -12,12 +11,22 @@ class GitLab
   end
 
   def issues_by_urls(urls)
-    urls.uniq.each_with_object([]) do |url, result|
+    url_replacements = {}
+    issues = urls.uniq.each_with_object([]) do |url, result|
       issue = issue_by_url(url)
       next if issue.blank?
 
+      if issue[:url] != url
+        url_replacements.store(url, issue[:url])
+      end
+
       result << issue
     end
+
+    {
+      issues:           issues,
+      url_replacements: url_replacements
+    }
   end
 
   def issue_by_url(url)

+ 27 - 0
lib/gitlab/http_client.rb

@@ -52,6 +52,33 @@ class GitLab
       response.data
     end
 
+    def perform_rest_get_request(variables)
+      uri = URI.parse(endpoint)
+      return if uri.blank? || variables.blank?
+
+      response = UserAgent.get(
+        "#{uri.scheme}://#{uri.host}/api/v4/projects/#{ERB::Util.url_encode(variables[:fullpath])}/issues/#{variables[:issue_id]}",
+        {},
+        {
+          headers:      headers,
+          json:         true,
+          open_timeout: 6,
+          read_timeout: 16,
+          log:          {
+            facility: 'GitLab',
+          },
+          verify_ssl:   verify_ssl,
+        },
+      )
+
+      if !response.success?
+        Rails.logger.error response.error
+        return
+      end
+
+      JSON.parse(response.body)
+    end
+
     private
 
     def headers

+ 21 - 1
lib/gitlab/linked_issue.rb

@@ -12,6 +12,7 @@ class GitLab
         project(fullPath: $fullpath) {
           issue(iid: $issue_id) {
             iid
+            webUrl
             title
             state
             milestone {
@@ -47,9 +48,17 @@ class GitLab
 
     def find_by(url)
       @result = query_by_url(url)
+
+      if @result.blank?
+        new_url = query_new_url_by_rest_api(url)
+        return if new_url.blank?
+
+        @result = query_by_url(new_url)
+      end
+
       return if @result.blank?
 
-      to_h.merge(url: url)
+      to_h
     end
 
     private
@@ -58,6 +67,7 @@ class GitLab
       {
         id:         @result['iid'],
         title:      @result['title'],
+        url:        @result['webUrl'],
         icon_state: STATES_MAPPING.fetch(@result['state'], @result['state']),
         milestone:  milestone,
         assignees:  assignees,
@@ -97,6 +107,16 @@ class GitLab
       response.dig('data', 'project', 'issue')
     end
 
+    def query_new_url_by_rest_api(url)
+      variables = variables(url)
+      return if variables.blank?
+
+      response = client.perform_rest_get_request(variables)
+      return if response.blank?
+
+      response['web_url']
+    end
+
     def variables(url)
       if url !~ %r{^https?://([^/]+)/(.*)/-/issues/(\d+)$}
         raise Exceptions::UnprocessableEntity, __('Invalid GitLab issue link format')

Some files were not shown because too many files changed in this diff