summaryrefslogtreecommitdiff
path: root/lib/atlassian/jira_connect/client.rb
blob: da24d0e20ee2d17004ef3a4804fa0c2b721bf1eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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
95
96
97
98
# frozen_string_literal: true

module Atlassian
  module JiraConnect
    class Client < Gitlab::HTTP
      def self.generate_update_sequence_id
        Gitlab::Metrics::System.monotonic_time.to_i
      end

      def initialize(base_uri, shared_secret)
        @base_uri = base_uri
        @shared_secret = shared_secret
      end

      def send_info(project:, update_sequence_id: nil, **args)
        common = { project: project, update_sequence_id: update_sequence_id }
        dev_info = args.slice(:commits, :branches, :merge_requests)
        build_info = args.slice(:pipelines)

        responses = []

        responses << store_dev_info(**common, **dev_info) if dev_info.present?
        responses << store_build_info(**common, **build_info) if build_info.present?
        raise ArgumentError, 'Invalid arguments' if responses.empty?

        responses.compact
      end

      private

      def store_build_info(project:, pipelines:, update_sequence_id: nil)
        return unless Feature.enabled?(:jira_sync_builds, project)

        builds = pipelines.map do |pipeline|
          build = Serializers::BuildEntity.represent(
            pipeline,
            update_sequence_id: update_sequence_id
          )
          next if build.issue_keys.empty?

          build
        end.compact
        return if builds.empty?

        post('/rest/builds/0.1/bulk', { builds: builds })
      end

      def store_dev_info(project:, commits: nil, branches: nil, merge_requests: nil, update_sequence_id: nil)
        repo = Serializers::RepositoryEntity.represent(
          project,
          commits: commits,
          branches: branches,
          merge_requests: merge_requests,
          user_notes_count: user_notes_count(merge_requests),
          update_sequence_id: update_sequence_id
        )

        post('/rest/devinfo/0.10/bulk', { repositories: [repo] })
      end

      def post(path, payload)
        uri = URI.join(@base_uri, path)

        self.class.post(uri, headers: headers(uri), body: metadata.merge(payload).to_json)
      end

      def headers(uri)
        {
          'Authorization' => "JWT #{jwt_token('POST', uri)}",
          'Content-Type' => 'application/json'
        }
      end

      def metadata
        { providerMetadata: { product: "GitLab #{Gitlab::VERSION}" } }
      end

      def user_notes_count(merge_requests)
        return unless merge_requests

        Note.count_for_collection(merge_requests.map(&:id), 'MergeRequest').map do |count_group|
          [count_group.noteable_id, count_group.count]
        end.to_h
      end

      def jwt_token(http_method, uri)
        claims = Atlassian::Jwt.build_claims(
          Atlassian::JiraConnect.app_key,
          uri,
          http_method,
          @base_uri
        )

        Atlassian::Jwt.encode(claims, @shared_secret)
      end
    end
  end
end