codes 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 34b56b7948df3498826c2deed30e0b559ee3b0ae
4
- data.tar.gz: 8c1e4e68aaaae4125efefcc4a7e57e88927ec011
3
+ metadata.gz: 5de44a06df82ccf5f52fb7012beb8fbb45ea091f
4
+ data.tar.gz: 3815b7cafc3affe3801c642b72227326d6d89af9
5
5
  SHA512:
6
- metadata.gz: aa064ec5e1229d765f377227dd26f138e89e8fdcf8a48ebae235dbec31a4eb19e0ae65a9034097dfe9d347ffd56c4cd5793355e0b35831c76257cb75369e3f8b
7
- data.tar.gz: 45e3a769ce73b7ac8fa38e18fa2853d39fd77b10fe42102debb1790e76b12bbca30ee31285085e58634deffc45613906565e565fe68226b09fe8862a1f9d36ff
6
+ metadata.gz: 12a724b931a13c7d6a04a4f5fa6370fd6bd5a2d67d252e4bad9619b0e68aa36c3929bac652267577f70c94706ec43e8360f6ff6361f58737e24d03a48df585c4
7
+ data.tar.gz: 22e7597ee1a3f194f4e4943432f682e0022aa956344fc25196863d685dd3de8bd8cdd0a270cbb397cc55b7ffc86b76870b6678ff2933de427fd36119cdff7bb9
data/bin/codes CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $:.push File.expand_path("../../lib", __FILE__)
3
+ $:.push File.expand_path('../../lib', __FILE__)
4
4
 
5
5
  require 'codes'
6
6
  require 'commander'
@@ -17,6 +17,43 @@ class CodesApplication
17
17
  end
18
18
 
19
19
  def run
20
+ prepare_command
21
+
22
+ command :download do |c|
23
+ c.syntax = 'codes download [num]'
24
+ c.description = 'Download [num] new promo codes from iTunes Connect'
25
+
26
+ c.action do |args, options|
27
+ username options
28
+ number_of_codes = count(args)
29
+ apple_id = apple_id(options)
30
+ app_identifier = bundle_id(options, apple_id)
31
+ format = download_format options
32
+
33
+ Codes::CodesRunner.download(number_of_codes: number_of_codes, app_identifier: app_identifier, apple_id: apple_id, output_file_path: options.output_file, format: format, country: options.country)
34
+ end
35
+ end
36
+
37
+ command :display do |c|
38
+ c.syntax = 'codes display'
39
+ c.description = 'Display remaining number of promo codes from iTunes Connect'
40
+
41
+ c.action do |args, options|
42
+ username options
43
+ apple_id = apple_id(options)
44
+ app_identifier = bundle_id(options, apple_id)
45
+
46
+ Codes::CodesRunner.display(app_identifier: app_identifier, apple_id: apple_id, output_file_path: options.output_file, country: options.country)
47
+ end
48
+ end
49
+ default_command :download
50
+
51
+ run!
52
+ end
53
+
54
+ private
55
+
56
+ def prepare_command
20
57
  program :version, Codes::VERSION
21
58
  program :description, 'CLI for \'codes\' - Create promo codes for iOS Apps using the command line'
22
59
  program :help, 'Author', 'Felix Krause <codes@krausefx.com>'
@@ -34,85 +71,48 @@ class CodesApplication
34
71
  global_option '-f', '--format STRING', 'If specified, modifies the format of the output to the specified format'
35
72
  global_option '-X', '--verbose', "If specified, defines the default output. Similar to -f \'#{download_verbose_format}\'"
36
73
  global_option '-x', '--urls', 'If specified, includes a full URL for each code that can be used to redeem that code.'
74
+ end
37
75
 
76
+ def count(args)
77
+ [args[0].to_i, 1].max # minimum of 1 code
78
+ end
38
79
 
39
- command :download do |c|
40
- c.syntax = "codes download [num]"
41
- c.description = "Download [num] new promo codes from iTunes Connect"
42
-
43
- c.action do |args, options|
44
- user = username options
45
- number_of_codes = count(args)
46
- apple_id = apple_id(options)
47
- app_identifier = bundle_id(options, apple_id)
48
- format = download_format options
49
-
50
- Codes::CodesRunner.download(number_of_codes: number_of_codes, app_identifier: app_identifier, apple_id: apple_id, output_file_path: options.output_file, format: format, country: options.country)
51
- end
52
- end
53
-
54
- command :display do |c|
55
- c.syntax = "codes display"
56
- c.description = "Display remaining number of promo codes from iTunes Connect"
57
-
58
- c.action do |args, options|
59
- user = username options
60
- apple_id = apple_id(options)
61
- app_identifier = bundle_id(options, apple_id)
62
-
63
- Codes::CodesRunner.display(app_identifier: app_identifier, apple_id: apple_id, output_file_path: options.output_file, country: options.country)
64
- end
65
- end
66
- default_command :download
67
-
68
- def count(args)
69
- [args[0].to_i, 1].max # minimum of 1 code
70
- end
71
-
72
- def username(options)
73
- user = options.username
74
- user ||= ENV["CODES_USERNAME"]
75
- user ||= CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
76
-
77
-
78
- CredentialsManager::PasswordManager.shared_manager(user) if user
80
+ def username(options)
81
+ user = options.username
82
+ user ||= ENV['CODES_USERNAME']
83
+ user ||= CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
79
84
 
80
- user
81
- end
85
+ CredentialsManager::PasswordManager.shared_manager(user) if user
82
86
 
83
- def download_format(options)
84
- verbose = options.X || options.verbose
85
- urls = options.x || options.urls
86
- format = options.f || options.format
87
- # backward compatibility...
88
- if urls && !format
89
- format = "%c - %u"
90
- end
91
- if verbose && !format
92
- format = download_verbose_format
93
- end
94
- format
95
- end
87
+ user
88
+ end
96
89
 
97
- def bundle_id(options, apple_id)
98
- app_identifier = options.app_identifier
99
- app_identifier ||= ENV["CODES_APP_IDENTIFIER"]
100
- app_identifier ||= CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)
101
- app_identifier ||= (FastlaneCore::ItunesSearchApi.fetch(apple_id)['bundleId'] rescue nil) if apple_id
102
- app_identifier ||= ask("App Identifier (Bundle ID, e.g. com.krausefx.app): ")
103
- app_identifier
104
- end
90
+ def download_format(options)
91
+ verbose = options.X || options.verbose
92
+ urls = options.x || options.urls
93
+ format = options.f || options.format
94
+ # backward compatibility...
95
+ format = '%c - %u' if urls && !format
96
+ format = download_verbose_format if verbose && !format
97
+ format
98
+ end
105
99
 
106
- def apple_id(options)
107
- apple_id = options.apple_id
108
- apple_id ||= ENV["CODES_APP_ID"]
109
- end
100
+ def bundle_id(options, apple_id)
101
+ app_identifier = options.app_identifier
102
+ app_identifier ||= ENV['CODES_APP_IDENTIFIER']
103
+ app_identifier ||= CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)
104
+ app_identifier ||= (FastlaneCore::ItunesSearchApi.fetch(apple_id)['bundleId'] rescue nil) if apple_id
105
+ app_identifier ||= ask('App Identifier (Bundle ID, e.g. com.krausefx.app): ')
106
+ app_identifier
107
+ end
110
108
 
111
- run!
109
+ def apple_id(options)
110
+ apple_id = options.apple_id
111
+ apple_id ||= ENV['CODES_APP_ID']
112
+ apple_id
112
113
  end
113
114
  end
114
115
 
115
-
116
116
  begin
117
117
  FastlaneCore::UpdateChecker.start_looking_for_update('codes')
118
118
  CodesApplication.new.run
@@ -6,7 +6,7 @@ require 'codes/itunes_connect'
6
6
  require 'fastlane_core'
7
7
 
8
8
  module Codes
9
- Helper = FastlaneCore::Helper
9
+ Helper = FastlaneCore::Helper
10
10
 
11
11
  DependencyChecker.check_dependencies
12
12
  end
@@ -3,6 +3,7 @@ module Codes
3
3
  def self.download(args)
4
4
  Codes::ItunesConnect.new.download args
5
5
  end
6
+
6
7
  def self.display(args)
7
8
  Codes::ItunesConnect.new.display args
8
9
  end
@@ -2,30 +2,30 @@ require 'fastlane_core/itunes_connect/itunes_connect'
2
2
 
3
3
  module Codes
4
4
  class ItunesConnect < FastlaneCore::ItunesConnect
5
+ PROMO_URL = 'https://itunesconnect.apple.com/WebObjects/iTunesConnect.woa/wa/LCAppPage/viewPromoCodes?adamId=[[app_id]]&platform=[[platform]]'
6
+ CODE_URL = 'https://buy.itunes.apple.com/WebObjects/MZFinance.woa/wa/redeemLandingPage?code=[[code]]'
5
7
 
6
- PROMO_URL = "https://itunesconnect.apple.com/WebObjects/iTunesConnect.woa/wa/LCAppPage/viewPromoCodes?adamId=[[app_id]]&platform=[[platform]]"
7
- CODE_URL = "https://buy.itunes.apple.com/WebObjects/MZFinance.woa/wa/redeemLandingPage?code=[[code]]"
8
-
8
+ # rubocop:disable Metrics/AbcSize
9
9
  def download(args)
10
10
  number_of_codes = args[:number_of_codes]
11
11
 
12
- code_or_codes = number_of_codes == 1 ? "code" : "codes"
13
- Helper.log.info "Downloading #{number_of_codes} promo #{code_or_codes}..."
12
+ code_or_codes = number_of_codes == 1 ? 'code' : 'codes'
13
+ Helper.log.info "Downloading #{number_of_codes} promo #{code_or_codes}..."
14
14
 
15
15
  fetch_app_data args
16
16
 
17
17
  # Use Pathname because it correctly handles the distinction between relative paths vs. absolute paths
18
18
  output_file_path = Pathname.new(args[:output_file_path]) if args[:output_file_path]
19
19
  output_file_path ||= Pathname.new(File.join(Dir.getwd, "#{@app_identifier || @app_id}_codes.txt"))
20
- raise "Insufficient permissions to write to output file".red if File.exists?(output_file_path) and not File.writable?(output_file_path)
21
- visit PROMO_URL.gsub("[[app_id]]", @app_id.to_s).gsub("[[platform]]", @platform)
20
+ fail 'Insufficient permissions to write to output file'.red if File.exist?(output_file_path) && !File.writable?(output_file_path)
21
+ visit PROMO_URL.gsub('[[app_id]]', @app_id.to_s).gsub('[[platform]]', @platform)
22
22
 
23
23
  begin
24
- text_fields = wait_for_elements("input[type=text]")
24
+ text_fields = wait_for_elements('input[type=text]')
25
25
  rescue
26
26
  raise "Could not open details page for app #{@app_identifier}. Are you sure you are using the correct apple account and have access to this app?".red
27
27
  end
28
- raise "There should only be a single text input field to specify the number of codes".red unless text_fields.count == 1
28
+ fail 'There should only be a single text input field to specify the number of codes'.red unless text_fields.count == 1
29
29
 
30
30
  text_fields.first.set(number_of_codes.to_s)
31
31
  click_next
@@ -33,83 +33,84 @@ module Codes
33
33
  # are there any errors ?
34
34
  errors = []
35
35
  begin
36
- errors = wait_for_elements("div[id=LCPurpleSoftwarePageWrapperErrorMessage]")
37
- rescue Exception
36
+ errors = wait_for_elements('div[id=LCPurpleSoftwarePageWrapperErrorMessage]')
37
+ rescue
38
38
  end
39
- raise errors.first.text.red unless errors.count == 0
39
+ fail errors.first.text.red unless errors.count == 0
40
40
 
41
- Helper.log.debug "Accepting the App Store Volume Custom Code Agreement"
42
- wait_for_elements("input[type=checkbox]").first.click
41
+ Helper.log.debug 'Accepting the App Store Volume Custom Code Agreement'
42
+ wait_for_elements('input[type=checkbox]').first.click
43
43
  click_next
44
44
 
45
45
  # the find(:xpath, "..") gets the parent element of the previous expression
46
46
  download_url = wait_for_elements("div[class='large-blue-rect-button']").first.find(:xpath, '..')['href']
47
47
 
48
48
  codes, request_date = download_codes(download_url)
49
-
49
+
50
50
  format = args[:format]
51
51
  codes = download_format(codes, format, request_date, app) if format
52
52
 
53
- bytes_written = File.write(output_file_path.to_s, codes, mode: "a+")
54
- Helper.log.warn "Could not write your codes to the codes.txt file, but you can still access them from iTunes Connect later" if bytes_written == 0
55
- Helper.log.info "Added generated codes to '#{output_file_path.to_s}'".green unless bytes_written == 0
53
+ bytes_written = File.write(output_file_path.to_s, codes, mode: 'a+')
54
+ Helper.log.warn 'Could not write your codes to the codes.txt file, but you can still access them from iTunes Connect later' if bytes_written == 0
55
+ Helper.log.info "Added generated codes to '#{output_file_path}'".green unless bytes_written == 0
56
56
 
57
57
  Helper.log.info "Your codes (requested #{request_date}) were successfully downloaded:".green
58
58
  puts codes
59
59
  end
60
+ # rubocop:enable Metrics/AbcSize
60
61
 
61
62
  def download_format(codes, format, request_date, app)
62
- format = format.gsub(/%([a-z])/, "%{\\1}") # %c => %{c}
63
-
64
- codes = codes.split("\n").map do |code|
65
- format % {
66
- c: code,
67
- b: app['bundleId'],
68
- d: request_date, # e.g. 20150520110716 / Cupertino timestamp...
69
- i: app['trackId'],
70
- n: "\'#{app['trackName']}\'",
71
- p: app_platform(app),
72
- u: CODE_URL.gsub("[[code]]", code)
73
- }
74
- end
75
- codes = codes.join("\n") + "\n"
63
+ format = format.gsub(/%([a-z])/, '%{\\1}') # %c => %{c}
64
+
65
+ codes = codes.split("\n").map do |code|
66
+ format % {
67
+ c: code,
68
+ b: app['bundleId'],
69
+ d: request_date, # e.g. 20150520110716 / Cupertino timestamp...
70
+ i: app['trackId'],
71
+ n: "\'#{app['trackName']}\'",
72
+ p: app_platform(app),
73
+ u: CODE_URL.gsub('[[code]]', code)
74
+ }
75
+ end
76
+ codes.join("\n") + "\n"
76
77
  end
77
78
 
78
79
  def app_platform(app)
79
- app['kind'] == "mac-software" ? "osx" : "ios"
80
+ app['kind'] == 'mac-software' ? 'osx' : 'ios'
80
81
  end
81
82
 
82
83
  def display(args)
83
- Helper.log.info "Displaying remaining number of codes promo"
84
+ Helper.log.info 'Displaying remaining number of codes promo'
84
85
 
85
86
  fetch_app_data args
86
87
 
87
88
  # Use Pathname because it correctly handles the distinction between relative paths vs. absolute paths
88
89
  output_file_path = Pathname.new(args[:output_file_path]) if args[:output_file_path]
89
90
  output_file_path ||= Pathname.new(File.join(Dir.getwd, "#{@app_identifier || @app_id}_codes_info.txt"))
90
- raise "Insufficient permissions to write to output file".red if File.exists?(output_file_path) and not File.writable?(output_file_path)
91
- visit PROMO_URL.gsub("[[app_id]]", @app_id.to_s).gsub("[[platform]]", @platform)
91
+ fail 'Insufficient permissions to write to output file'.red if File.exist?(output_file_path) && !File.writable?(output_file_path)
92
+ visit PROMO_URL.gsub('[[app_id]]', @app_id.to_s).gsub('[[platform]]', @platform)
92
93
 
93
94
  begin
94
- text_fields = wait_for_elements("input[type=text]")
95
+ text_fields = wait_for_elements('input[type=text]')
95
96
  rescue
96
97
  raise "Could not open details page for app #{app_identifier}. Are you sure you are using the correct apple account and have access to this app?".red
97
98
  end
98
- raise "There should only be a single text input field to specify the number of codes".red unless text_fields.count == 1
99
+ fail 'There should only be a single text input field to specify the number of codes'.red unless text_fields.count == 1
99
100
 
100
- remaining_divs = wait_for_elements("div#codes_0")
101
- raise "There should only be a single text div containing the number of remaining codes".red unless remaining_divs.count == 1
102
- remaining = remaining_divs.first.text.split(" ")[0]
101
+ remaining_divs = wait_for_elements('div#codes_0')
102
+ fail 'There should only be a single text div containing the number of remaining codes'.red unless remaining_divs.count == 1
103
+ remaining = remaining_divs.first.text.split(' ')[0]
103
104
 
104
- bytes_written = File.write(output_file_path.to_s, remaining, mode: "a+")
105
- Helper.log.warn "Could not write your codes to the codes_info.txt file, but you can still access them from iTunes Connect later" if bytes_written == 0
106
- Helper.log.info "Added information of quantity of remaining codes to '#{output_file_path.to_s}'".green unless bytes_written == 0
105
+ bytes_written = File.write(output_file_path.to_s, remaining, mode: 'a+')
106
+ Helper.log.warn 'Could not write your codes to the codes_info.txt file, but you can still access them from iTunes Connect later' if bytes_written == 0
107
+ Helper.log.info "Added information of quantity of remaining codes to '#{output_file_path}'".green unless bytes_written == 0
107
108
 
108
109
  puts remaining
109
110
  end
110
111
 
111
112
  def click_next
112
- wait_for_elements("input.continueActionButton").first.click
113
+ wait_for_elements('input.continueActionButton').first.click
113
114
  end
114
115
 
115
116
  def download_codes(url)
@@ -117,16 +118,16 @@ module Codes
117
118
  url = URI.join(host, url)
118
119
  Helper.log.debug "Downloading promo code file from #{url}"
119
120
 
120
- cookie_string = ""
121
+ cookie_string = ''
121
122
  page.driver.cookies.each do |key, cookie|
122
123
  cookie_string << "#{cookie.name}=#{cookie.value};"
123
124
  end
124
125
 
125
- page = open(url, "Cookie" => cookie_string)
126
- request_date = page.metas['content-disposition'][0].gsub(/.*filename=.*_(.*).txt/,"\\1")
126
+ page = open(url, 'Cookie' => cookie_string)
127
+ request_date = page.metas['content-disposition'][0].gsub(/.*filename=.*_(.*).txt/, '\\1')
127
128
  codes = page.read
128
129
 
129
- return codes, request_date
130
+ [codes, request_date]
130
131
  end
131
132
 
132
133
  private
@@ -138,8 +139,8 @@ module Codes
138
139
  @app_id = args[:apple_id]
139
140
  @app_id ||= (FastlaneCore::ItunesSearchApi.fetch_by_identifier(@app_identifier, @country)['trackId'] rescue nil)
140
141
 
141
- if @app_id.to_i == 0 or @app_identifier.to_s.length == 0
142
- raise "Could not find app using the following information: #{args}. Maybe the app is not in the store. Pass the Apple ID of the app as well!".red
142
+ if @app_id.to_i == 0 || @app_identifier.to_s.length == 0
143
+ fail "Could not find app using the following information: #{args}. Maybe the app is not in the store. Pass the Apple ID of the app as well!".red
143
144
  end
144
145
 
145
146
  app = FastlaneCore::ItunesSearchApi.fetch(@app_id, @country)
@@ -1,3 +1,3 @@
1
1
  module Codes
2
- VERSION = "0.4.0"
2
+ VERSION = '0.4.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felix Krause
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-03 00:00:00.000000000 Z
11
+ date: 2015-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fastlane_core
@@ -16,14 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.15.2
19
+ version: 0.16.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: 1.0.0
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: 0.15.2
29
+ version: 0.16.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.0
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: bundler
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -158,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
164
  version: '0'
159
165
  requirements: []
160
166
  rubyforge_project:
161
- rubygems_version: 2.4.5
167
+ rubygems_version: 2.4.6
162
168
  signing_key:
163
169
  specification_version: 4
164
170
  summary: Create promo codes for iOS Apps using the command line