app_store_connect 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78c441ea7e16744eee415f8b65fb1389436e28e1880a3b4687d60d67ed4e3388
4
- data.tar.gz: dc044031de07e8c2d7c5a543e5613a609d73d4fdfa753a3db71fec4370903b60
3
+ metadata.gz: 6bece2d6691fbb4f254b53de5001324dfe4d10840c8c0cf82a073f0260bde177
4
+ data.tar.gz: d45d001147d7694579c6c838a52fa376607d83cb82b82bc2481193f763cf4ed7
5
5
  SHA512:
6
- metadata.gz: b1361415a42d7ca66c345a6c43d97cf4d684c5f6b3aded20b148aeb1c769ceb58ae4a13a72b1a3fa8b9a228ac03158a47d952431d763450659c3595db750cae4
7
- data.tar.gz: 3672cc89f06df46185e84577309f9f5817f88e62bfe7b168a5eb67dabc9097361692627133719bab761a91ba8b3f4f1f5a9cb28e3c3c82340f7640a8b6253555
6
+ metadata.gz: 0e9cff4c10632c74fa8bc63a04b3cd24af7be3ee04bc0d9914da6e0fae3d421a6a802d429c7adc43ad1c8cf20761c296575041e73c78ab38ee2aa2bb0c4cf0b7
7
+ data.tar.gz: 8301b52487821ab284c8f0c6ccbdd87b1fc3361337239aec2569da1ae4bc8a9f894ebdda28bb849a2ad42403ab840f7586f19c012ef156c6cc611db48333379a
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- app_store_connect (0.6.0)
4
+ app_store_connect (0.7.0)
5
5
  activesupport (~> 5.2.3)
6
6
  httparty (~> 0.16)
7
7
  jwt (~> 2.1)
data/README.md CHANGED
@@ -23,15 +23,17 @@ Or install it yourself as:
23
23
  ## Usage
24
24
 
25
25
  ```ruby
26
- client = AppStoreConnect::Client.new(
26
+ AppStoreConnect.config = {
27
27
  issuer_id: issuer_id,
28
28
  key_id: key_id,
29
29
  private_key: private_key
30
- )
30
+ }
31
31
 
32
- client.apps
33
- client.app('1234')
34
- client.builds('1234')
32
+ app_store_connect = AppStoreConnect::Client.new
33
+
34
+ app_store_connect.apps
35
+ app_store_connect.app('1234')
36
+ app_store_connect.builds('1234')
35
37
  ```
36
38
 
37
39
  ## Development
data/bin/console CHANGED
@@ -5,4 +5,4 @@ require 'bundler/setup'
5
5
  require 'app_store_connect'
6
6
  require 'pry'
7
7
 
8
- Pry.start
8
+ Pry.start(AppStoreConnect::Client.new)
@@ -1,19 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './bundle_id_create_request/data'
4
-
5
3
  module AppStoreConnect
6
- class BundleIdCreateRequest
7
- attr_reader :data
8
-
9
- def initialize(*args)
10
- @data = Data.new(*args)
11
- end
4
+ class BundleIdCreateRequest < CreateRequest
5
+ data do
6
+ type 'bundleIds'
12
7
 
13
- def to_h
14
- {
15
- data: data.to_h
16
- }
8
+ attributes do
9
+ property :identifier, required: true
10
+ property :name, required: true
11
+ property :platform, required: true
12
+ property :seed_id
13
+ end
17
14
  end
18
15
  end
19
16
  end
@@ -2,75 +2,131 @@
2
2
 
3
3
  require 'active_support/all'
4
4
 
5
+ require 'app_store_connect/web_service_endpoint'
6
+
5
7
  module AppStoreConnect
6
- class Client
7
- ENDPOINT = 'https://api.appstoreconnect.apple.com/v1'
8
+ class Client # rubocop:disable Metrics/ClassLength
9
+ def initialize(**kwargs)
10
+ @options = options(**kwargs)
8
11
 
9
- def initialize(key_id:, issuer_id:, private_key:)
10
12
  @authorization = Authorization.new(
11
- private_key: private_key,
12
- key_id: key_id,
13
- issuer_id: issuer_id
13
+ private_key: @options[:private_key],
14
+ key_id: @options[:key_id],
15
+ issuer_id: @options[:issuer_id]
14
16
  )
17
+ @web_service_endpoints_by_name ||= begin
18
+ AppStoreConnect::Config::API['web_service_endpoints'].dup.map do |config|
19
+ [config.fetch('alias').to_sym, WebServiceEndpoint.new(**config.deep_symbolize_keys)]
20
+ end.to_h
21
+ end
15
22
  end
16
23
 
17
- def apps
18
- get('apps')
24
+ def respond_to_missing?(method_name, include_private = false)
25
+ web_service_endpoint_names.include?(method_name) || super
19
26
  end
20
27
 
21
- def app(id)
22
- get("apps/#{id}")
23
- end
28
+ def method_missing(method_name, *kwargs)
29
+ super unless web_service_endpoint_names.include?(method_name)
24
30
 
25
- def builds(app_id)
26
- get("apps/#{app_id}/builds")
27
- end
31
+ web_service_endpoint = web_service_endpoint_by(name: method_name)
28
32
 
29
- def build(app_id, build_id)
30
- get("apps/#{app_id}/builds/#{build_id}")
33
+ call(web_service_endpoint, *kwargs)
31
34
  end
32
35
 
33
- def invite_user(first_name:, last_name:, email:, roles:)
34
- invitation = UserInvitationCreateRequest.new(first_name, last_name, email, roles)
36
+ private
35
37
 
36
- post('userInvitations', invitation.body.to_json)
38
+ def web_service_endpoint_names
39
+ @web_service_endpoints_by_name.keys
37
40
  end
38
41
 
39
- def create_bundle_id(*args)
40
- request = BundleIdCreateRequest.new(*args)
42
+ def call(web_service_endpoint, **kwargs)
43
+ case web_service_endpoint.http_method
44
+ when :get
45
+ get(web_service_endpoint, **kwargs)
46
+ when :post
47
+ post(web_service_endpoint, **kwargs)
48
+ else
49
+ raise "invalid http method: #{web_service_endpoint.http_method}"
50
+ end
51
+ end
41
52
 
42
- post('bundleIds', body(request))
53
+ def build_url(web_service_endpoint, **kwargs)
54
+ web_service_endpoint
55
+ .url
56
+ .gsub(/(\{(\w+)\})/) { kwargs.fetch(Regexp.last_match(2).to_sym) }
43
57
  end
44
58
 
45
- def users(limit: 200)
46
- get('users', query_params: { 'limit' => limit })
59
+ def url_parameter_names(web_service_endpoint)
60
+ web_service_endpoint
61
+ .url
62
+ .scan(/(\{(\w+)\})/)
63
+ .map { |_, n| n.to_sym }
47
64
  end
48
65
 
49
- def user_invitations
50
- get('userInvitations')
66
+ def web_service_endpoint_by(name:)
67
+ @web_service_endpoints_by_name[name]
51
68
  end
52
69
 
53
- private
70
+ def env_options
71
+ {}.tap do |hash|
72
+ ENV.each do |key, value|
73
+ match = key.match(/APP_STORE_CONNECT_(?<name>[A-Z_]+)/)
74
+
75
+ next unless match
76
+
77
+ hash[match[:name].downcase.to_sym] = value
78
+ end
79
+ end
80
+ end
54
81
 
55
- def body(request)
82
+ def options(**kwargs)
83
+ AppStoreConnect.config.merge(kwargs.merge(env_options)).tap do |options|
84
+ %i[key_id issuer_id private_key].each do |key|
85
+ raise ArgumentError, "missing #{key}" unless options.keys.include?(key)
86
+ end
87
+ end
88
+ end
89
+
90
+ def build_body(request)
56
91
  request
57
- .to_hash
92
+ .to_h
58
93
  .deep_transform_keys { |k| k.to_s.camelize(:lower) }
59
94
  .to_json
60
95
  end
61
96
 
62
- def get(path, query_params: {})
63
- response = HTTParty.get("#{ENDPOINT}/#{path}", headers: headers, query: query_params)
97
+ def build_query(web_service_endpoint, **kwargs)
98
+ query_parameters = kwargs.dup.tap do |hash|
99
+ url_parameter_names(web_service_endpoint).each do |name|
100
+ hash.delete(name.to_sym)
101
+ end
102
+ end
103
+
104
+ query_parameters.to_query
105
+ end
106
+
107
+ def get(web_service_endpoint, **kwargs)
108
+ url = build_url(web_service_endpoint, **kwargs)
109
+ query = build_query(web_service_endpoint, **kwargs)
110
+
111
+ response = execute(:get, url, headers: headers, query: query)
64
112
 
65
113
  response['data']
66
114
  end
67
115
 
68
- def post(path, body)
69
- response = HTTParty.post("#{ENDPOINT}/#{path}", headers: headers, body: body)
116
+ def post(web_service_endpoint, **kwargs)
117
+ url = build_url(web_service_endpoint, **kwargs)
118
+ request = "AppStoreConnect::#{web_service_endpoint.http_body_type}".constantize.new(**kwargs)
119
+ body = build_body(request)
120
+
121
+ response = execute(:post, url, headers: headers, body: body)
70
122
 
71
123
  response
72
124
  end
73
125
 
126
+ def execute(http_method, url, **options)
127
+ HTTParty.send(http_method, url, options)
128
+ end
129
+
74
130
  def headers
75
131
  {
76
132
  'Authorization' => "Bearer #{@authorization.token}",
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppStoreConnect
4
+ class CreateRequest
5
+ include Object::Data
6
+
7
+ def initialize(**kwargs)
8
+ @data = Data.new(kwargs)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/concern'
4
+
5
+ module AppStoreConnect
6
+ module Object
7
+ module Attributes
8
+ extend ActiveSupport::Concern
9
+
10
+ class_methods do
11
+ def attributes(&block)
12
+ self::Attributes.class_eval(&block)
13
+ end
14
+ end
15
+
16
+ included do
17
+ attr_reader :attributes
18
+
19
+ klass = Class.new do |attributes|
20
+ include Object::Properties
21
+
22
+ attributes.define_method :initialize do |**kwargs|
23
+ self.class.properties.each do |name, options|
24
+ raise ArgumentError, "#{name} required" if options[:required] && !kwargs[name]
25
+
26
+ value = kwargs.fetch(name, options[:default])
27
+
28
+ instance_variable_set("@#{name}", value)
29
+ end
30
+ end
31
+
32
+ def to_h
33
+ {}.tap do |hash|
34
+ self.class.properties.keys.each do |name|
35
+ value = instance_variable_get("@#{name}")
36
+
37
+ hash[name] = value unless value.nil?
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ const_set('Attributes', klass)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/concern'
4
+
5
+ module AppStoreConnect
6
+ module Object
7
+ module Data
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ attr_reader :data
12
+
13
+ klass = Class.new do |data|
14
+ include Object::Attributes
15
+ include Object::Type
16
+
17
+ data.define_method :initialize do |**kwargs|
18
+ instance_variable_set('@attributes', data::Attributes.new(kwargs))
19
+ end
20
+
21
+ def to_h
22
+ {
23
+ attributes: attributes.to_h,
24
+ type: type
25
+ }
26
+ end
27
+ end
28
+
29
+ const_set('Data', klass)
30
+
31
+ def to_h
32
+ {
33
+ data: data.to_h
34
+ }
35
+ end
36
+ end
37
+
38
+ class_methods do
39
+ def data(&block)
40
+ self::Data.class_eval(&block)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/concern'
4
+
5
+ module AppStoreConnect
6
+ module Object
7
+ module Properties
8
+ extend ActiveSupport::Concern
9
+
10
+ class_methods do
11
+ def properties
12
+ @properties ||= {}
13
+ end
14
+
15
+ def property(name, options = {})
16
+ properties[name] = options
17
+
18
+ attr_accessor name.to_sym
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/concern'
4
+
5
+ module AppStoreConnect
6
+ module Object
7
+ module Type
8
+ extend ActiveSupport::Concern
9
+
10
+ class_methods do
11
+ def type(type)
12
+ @type = type
13
+
14
+ const_set('TYPE', type)
15
+ end
16
+ end
17
+
18
+ included do
19
+ def type
20
+ self.class.instance_variable_get('@type')
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -2,12 +2,20 @@
2
2
 
3
3
  module AppStoreConnect
4
4
  class UserInvitationCreateRequest < Struct.new(:first_name, :last_name, :email, :roles)
5
+ def initialize(kwargs)
6
+ super(kwargs[:first_name], kwargs[:last_name], kwargs[:email], kwargs[:roles])
7
+ end
8
+
5
9
  def body
6
10
  { 'data' =>
7
11
  { 'type' => 'userInvitations', 'attributes' =>
8
12
  { 'firstName' => first_name, 'lastName' => last_name, 'email' => email, 'roles' => roles, 'allAppsVisible' => true, 'provisioningAllowed' => true } } }
9
13
  end
10
14
 
15
+ def to_h
16
+ body
17
+ end
18
+
11
19
  def to_s
12
20
  body.to_json
13
21
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AppStoreConnect
4
- VERSION = '0.6.0'
4
+ VERSION = '0.7.0'
5
5
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppStoreConnect
4
+ class WebServiceEndpoint
5
+ def initialize(**options)
6
+ @options = options
7
+ end
8
+
9
+ def http_method
10
+ @options[:http_method].to_sym
11
+ end
12
+
13
+ def http_body_type
14
+ @options[:http_body_type]
15
+ end
16
+
17
+ def url
18
+ @options[:url]
19
+ end
20
+ end
21
+ end
@@ -5,6 +5,12 @@ require 'httparty'
5
5
 
6
6
  require 'app_store_connect/authorization'
7
7
  require 'app_store_connect/parser'
8
+
9
+ require 'app_store_connect/object/type'
10
+ require 'app_store_connect/object/attributes'
11
+ require 'app_store_connect/object/properties'
12
+ require 'app_store_connect/object/data'
13
+ require 'app_store_connect/create_request'
8
14
  require 'app_store_connect/client'
9
15
  require 'app_store_connect/bundle_id_create_request'
10
16
  require 'app_store_connect/user_invitation_create_request'
@@ -21,4 +27,12 @@ module AppStoreConnect
21
27
  Factory.register('enum', Factory::Builder::Enum)
22
28
 
23
29
  Parser.parse!(Config::API)
30
+
31
+ @config = {}
32
+
33
+ class << self
34
+ attr_reader :config
35
+
36
+ attr_writer :config
37
+ end
24
38
  end
data/lib/config/api.json CHANGED
@@ -1,4 +1,48 @@
1
1
  {
2
+ "web_service_endpoints": [
3
+ {
4
+ "alias": "apps",
5
+ "http_method": "get",
6
+ "url": "https://api.appstoreconnect.apple.com/v1/apps"
7
+ },
8
+ {
9
+ "alias": "app",
10
+ "http_method": "get",
11
+ "url": "https://api.appstoreconnect.apple.com/v1/apps/{id}"
12
+ },
13
+ {
14
+ "alias": "builds",
15
+ "http_method": "get",
16
+ "url": "https://api.appstoreconnect.apple.com/v1/apps/{id}/builds"
17
+ },
18
+ {
19
+ "alias": "build",
20
+ "http_method": "get",
21
+ "url": "https://api.appstoreconnect.apple.com/v1/builds/{id}"
22
+ },
23
+ {
24
+ "alias": "invite_user",
25
+ "url": "https://api.appstoreconnect.apple.com/v1/userInvitations",
26
+ "http_body_type": "UserInvitationCreateRequest",
27
+ "http_method": "post"
28
+ },
29
+ {
30
+ "alias": "create_bundle_id",
31
+ "url": "https://api.appstoreconnect.apple.com/v1/bundleIds",
32
+ "http_body_type": "BundleIdCreateRequest",
33
+ "http_method": "post"
34
+ },
35
+ {
36
+ "alias": "users",
37
+ "url": "https://api.appstoreconnect.apple.com/v1/users",
38
+ "http_method": "get"
39
+ },
40
+ {
41
+ "alias": "user_invitations",
42
+ "http_method": "get",
43
+ "url": "https://api.appstoreconnect.apple.com/v1/userInvitations"
44
+ }
45
+ ],
2
46
  "Type": {
3
47
  "CapabilityType": {
4
48
  "type": "enum",
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: app_store_connect
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyle Decot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-06 00:00:00.000000000 Z
11
+ date: 2019-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -219,17 +219,21 @@ files:
219
219
  - lib/app_store_connect.rb
220
220
  - lib/app_store_connect/authorization.rb
221
221
  - lib/app_store_connect/bundle_id_create_request.rb
222
- - lib/app_store_connect/bundle_id_create_request/data.rb
223
- - lib/app_store_connect/bundle_id_create_request/data/attributes.rb
224
222
  - lib/app_store_connect/client.rb
225
223
  - lib/app_store_connect/config.rb
224
+ - lib/app_store_connect/create_request.rb
226
225
  - lib/app_store_connect/factory.rb
227
226
  - lib/app_store_connect/factory/builder/enum.rb
227
+ - lib/app_store_connect/object/attributes.rb
228
+ - lib/app_store_connect/object/data.rb
229
+ - lib/app_store_connect/object/properties.rb
230
+ - lib/app_store_connect/object/type.rb
228
231
  - lib/app_store_connect/parser.rb
229
232
  - lib/app_store_connect/type.rb
230
233
  - lib/app_store_connect/type/enum.rb
231
234
  - lib/app_store_connect/user_invitation_create_request.rb
232
235
  - lib/app_store_connect/version.rb
236
+ - lib/app_store_connect/web_service_endpoint.rb
233
237
  - lib/config/api.json
234
238
  homepage: https://github.com/kyledecot/app_store_connect
235
239
  licenses:
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AppStoreConnect
4
- class BundleIdCreateRequest
5
- class Data
6
- class Attributes
7
- attr_accessor :identifier, :name, :platform, :seed_id
8
-
9
- def initialize(identifier:, name:, platform:, seed_id: nil)
10
- self.identifier = identifier
11
- self.name = name
12
- self.platform = platform
13
- self.seed_id = seed_id
14
- end
15
-
16
- def to_h
17
- {
18
- identifier: identifier,
19
- name: name,
20
- platform: platform
21
- }.tap do |hash|
22
- hash[:seed_id] = seed_id unless seed_id.nil?
23
- end
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative './data/attributes'
4
-
5
- module AppStoreConnect
6
- class BundleIdCreateRequest
7
- class Data
8
- TYPE = 'bundleIds'
9
-
10
- attr_reader :attributes
11
-
12
- def initialize(*args)
13
- @attributes = Attributes.new(*args)
14
- end
15
-
16
- def type
17
- TYPE
18
- end
19
-
20
- def to_h
21
- {
22
- attributes: attributes.to_h,
23
- type: type
24
- }
25
- end
26
- end
27
- end
28
- end