summaryrefslogtreecommitdiff
path: root/lib/gitlab/bitbucket_import/client.rb
blob: 9b83292ef33adceaa56417156d3252581d977254 (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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
module Gitlab
  module BitbucketImport
    class Client
      class Unauthorized < StandardError; end

      attr_reader :consumer, :api

      def self.from_project(project)
        import_data_credentials = project.import_data.credentials if project.import_data
        if import_data_credentials && import_data_credentials[:bb_session]
          token = import_data_credentials[:bb_session][:bitbucket_access_token]
          token_secret = import_data_credentials[:bb_session][:bitbucket_access_token_secret]
          new(token, token_secret)
        else
          raise Projects::ImportService::Error, "Unable to find project import data credentials for project ID: #{project.id}"
        end
      end

      def initialize(access_token = nil, access_token_secret = nil)
        @consumer = ::OAuth::Consumer.new(
          config.app_id,
          config.app_secret,
          bitbucket_options
        )

        if access_token && access_token_secret
          @api = ::OAuth::AccessToken.new(@consumer, access_token, access_token_secret)
        end
      end

      def request_token(redirect_uri)
        request_token = consumer.get_request_token(oauth_callback: redirect_uri)

        {
          oauth_token:              request_token.token,
          oauth_token_secret:       request_token.secret,
          oauth_callback_confirmed: request_token.callback_confirmed?.to_s
        }
      end

      def authorize_url(request_token, redirect_uri)
        request_token = ::OAuth::RequestToken.from_hash(consumer, request_token) if request_token.is_a?(Hash)

        if request_token.callback_confirmed?
          request_token.authorize_url
        else
          request_token.authorize_url(oauth_callback: redirect_uri)
        end
      end

      def get_token(request_token, oauth_verifier, redirect_uri)
        request_token = ::OAuth::RequestToken.from_hash(consumer, request_token) if request_token.is_a?(Hash)

        if request_token.callback_confirmed?
          request_token.get_access_token(oauth_verifier: oauth_verifier)
        else
          request_token.get_access_token(oauth_callback: redirect_uri)
        end
      end

      def user
        JSON.parse(get("/api/1.0/user").body)
      end

      def issues(project_identifier)
        all_issues = []
        offset = 0
        per_page = 50 # Maximum number allowed by Bitbucket
        index = 0

        begin
          issues = JSON.parse(get(issue_api_endpoint(project_identifier, per_page, offset)).body)
          # Find out how many total issues are present
          total = issues["count"] if index == 0
          all_issues.concat(issues["issues"])
          offset += issues["issues"].count
          index += 1
        end while all_issues.count < total

        all_issues
      end

      def issue_comments(project_identifier, issue_id)
        comments = JSON.parse(get("/api/1.0/repositories/#{project_identifier}/issues/#{issue_id}/comments").body)
        comments.sort_by { |comment| comment["utc_created_on"] }
      end

      def project(project_identifier)
        JSON.parse(get("/api/1.0/repositories/#{project_identifier}").body)
      end

      def find_deploy_key(project_identifier, key)
        JSON.parse(get("/api/1.0/repositories/#{project_identifier}/deploy-keys").body).find do |deploy_key|
          deploy_key["key"].chomp == key.chomp
        end
      end

      def add_deploy_key(project_identifier, key)
        deploy_key = find_deploy_key(project_identifier, key)
        return if deploy_key

        JSON.parse(api.post("/api/1.0/repositories/#{project_identifier}/deploy-keys", key: key, label: "GitLab import key").body)
      end

      def delete_deploy_key(project_identifier, key)
        deploy_key = find_deploy_key(project_identifier, key)
        return unless deploy_key

        api.delete("/api/1.0/repositories/#{project_identifier}/deploy-keys/#{deploy_key["pk"]}").code == "204"
      end

      def projects
        JSON.parse(get("/api/1.0/user/repositories").body).select { |repo| repo["scm"] == "git" }
      end

      def incompatible_projects
        JSON.parse(get("/api/1.0/user/repositories").body).reject { |repo| repo["scm"] == "git" }
      end

      private

      def get(url)
        response = api.get(url)
        raise Unauthorized if (400..499).include?(response.code.to_i)

        response
      end

      def issue_api_endpoint(project_identifier, per_page, offset)
        "/api/1.0/repositories/#{project_identifier}/issues?sort=utc_created_on&limit=#{per_page}&start=#{offset}"
      end

      def config
        Gitlab.config.omniauth.providers.find { |provider| provider.name == "bitbucket" }
      end

      def bitbucket_options
        OmniAuth::Strategies::Bitbucket.default_options[:client_options].symbolize_keys
      end
    end
  end
end