fastlane/fastlane 29792
🚀 The easiest way to automate building and releasing your iOS and Android apps
fastlane/ci 2094
Open source, self hosted, mobile optimized CI powered by fastlane
fastlane/examples 1247
📝 A collection of example fastlane setups
Instantly create a simple signup page for TestFlight beta testers
The unofficial documentation of the iTunes Connect JSON API
Get a notification once your iTunes Connect build is finished processing
fastlane/docs 187
All the fastlane docs
fastlane/fastlane-plugin-firebase_test_lab 63
Test your app with Firebase Test Lab with ease using fastlane
Hosting the latest frameit frames via GitHub Pages
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
describe Spaceship::ConnectAPI::TestFlight::Client do- let(:client) { Spaceship::ConnectAPI::TestFlight::Client.instance }+ let(:client) { Spaceship::ConnectAPI::TestFlight::Client.new }
nit: Rspec often uses subject for this purpose: https://relishapp.com/rspec/rspec-core/v/2-0/docs/subject/explicit-subject
comment created time in a month
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
+require 'faraday'++require_relative 'globals'++module Spaceship+ class StatsMiddleware < Faraday::Middleware+ ServiceOption = Struct.new(:name, :url, :auth_type)+ class << self+ def services+ @services ||= [+ ServiceOption.new("App Store Connect API (official)", "api.appstoreconnect.apple.com", "JWT"),+ ServiceOption.new("App Store Connect API (web session)", "appstoreconnect.apple.com/iris/v1", "Web session"),+ ServiceOption.new("App Store Connect API (web session)", "developer.apple.com/services-account/v1/", "Web session"),+ ServiceOption.new("Legacy iTunesConnect Auth", "idmsa.apple.com", "Web session"),+ ServiceOption.new("Legacy iTunesConnect Auth", "appstoreconnect.apple.com/olympus/v1/", "Web session"),+ ServiceOption.new("Legacy iTunesConnect", "appstoreconnect.apple.com/WebObjects/iTunesConnect.woa", "Web session"),+ ServiceOption.new("Legacy iTunesConnect Developer Portal", "developer.apple.com/services-account", "Web session")+ ]++ @services+ end++ def service_stats+ @service_stats ||= Hash.new(0)+ @service_stats+ end
def service_stats
@service_stats ||= Hash.new(0)
end
comment created time in a month
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
++require_relative '../client'+require_relative './response'+require_relative '../client'+require_relative './response'++require_relative '../stats_middleware'++module Spaceship+ class ConnectAPI+ class APIClient < Spaceship::Client+ attr_accessor :token++ #####################################################+ # @!group Client Init+ #####################################################++ # Instantiates a client with cookie session or a JWT token.+ def initialize(cookie: nil, current_team_id: nil, token: nil, another_client: nil)+ if token.nil?+ if another_client.nil?+ super(cookie: cookie, current_team_id: current_team_id, timeout: 1200)+ else+ super(cookie: another_client.instance_variable_get(:@cookie), current_team_id: another_client.team_id)+ end+ else+ options = {+ request: {+ timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i,+ open_timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i+ }+ }+ @token = token+ @current_team_id = current_team_id++ hostname = "https://api.appstoreconnect.apple.com/v1/"++ @client = Faraday.new(hostname, options) do |c|+ c.response(:json, content_type: /\bjson$/)+ c.response(:plist, content_type: /\bplist$/)+ c.use(FaradayMiddleware::RelsMiddleware)+ c.use(Spaceship::StatsMiddleware)+ c.adapter(Faraday.default_adapter)+ c.headers["Authorization"] = "Bearer #{token.text}"++ if ENV['SPACESHIP_DEBUG']+ # for debugging only+ # This enables tracking of networking requests using Charles Web Proxy+ c.proxy = "https://127.0.0.1:8888"+ c.ssl[:verify_mode] = OpenSSL::SSL::VERIFY_NONE+ elsif ENV["SPACESHIP_PROXY"]+ c.proxy = ENV["SPACESHIP_PROXY"]+ c.ssl[:verify_mode] = OpenSSL::SSL::VERIFY_NONE if ENV["SPACESHIP_PROXY_SSL_VERIFY_NONE"]+ end++ if ENV["DEBUG"]+ puts("To run spaceship through a local proxy, use SPACESHIP_DEBUG")+ end+ end+ end+ end++ def self.hostname+ return nil+ end++ #+ # Helpers+ #++ def web_session?+ return @token.nil?+ end++ def build_params(filter: nil, includes: nil, limit: nil, sort: nil, cursor: nil)+ params = {}++ filter = filter.delete_if { |k, v| v.nil? } if filter++ params[:filter] = filter if filter && !filter.empty?+ params[:include] = includes if includes+ params[:limit] = limit if limit+ params[:sort] = sort if sort+ params[:cursor] = cursor if cursor++ return params+ end
nit: Maybe possible to shorten a bit?
def build_params(**params)
supported_params = %i[filter include limit sort cursor]
params[:filter] = params[:filter].delete_if { |k, v| v.nil? } if params[:filter]
params.select { |key, val| supported_params.include?(key) && val }
end
comment created time in a month
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
+require_relative './client'++require_relative './testflight/testflight'++module Spaceship+ class ConnectAPI+ class << self+ # This client stores the global client when using the lazy syntax+ attr_accessor :client++ # Forward class calls to the global client+ extend(Forwardable)+ def_delegators(:client, *Spaceship::ConnectAPI::Provisioning::API.instance_methods(false))+ def_delegators(:client, *Spaceship::ConnectAPI::TestFlight::API.instance_methods(false))+ def_delegators(:client, *Spaceship::ConnectAPI::Tunes::API.instance_methods(false))+ def_delegators(:client, *Spaceship::ConnectAPI::Users::API.instance_methods(false))++ def client+ # Always look for a client set explicitly by the client first+ return @client if @client++ # A client may not always be explicitly set (specially when running tools like match, sigh, pilot, etc)+ # In that case, create a new client based on existing sessions+ # Note: This does not perform logins on the user. It is only reusing the cookies and selected teams+ return nil if Spaceship::Tunes.client.nil? && Spaceship::Portal.client.nil?++ implicit_client = ConnectAPI::Client.new(tunes_client: Spaceship::Tunes.client, portal_client: Spaceship::Portal.client)+ return implicit_client
This seems like it could run quite often, would it make sense to use memoization for the implicit client?
comment created time in a month
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
+require_relative './client'++require_relative './testflight/testflight'++module Spaceship+ class ConnectAPI+ class << self+ # This client stores the global client when using the lazy syntax+ attr_accessor :client++ # Forward class calls to the global client+ extend(Forwardable)+ def_delegators(:client, *Spaceship::ConnectAPI::Provisioning::API.instance_methods(false))+ def_delegators(:client, *Spaceship::ConnectAPI::TestFlight::API.instance_methods(false))+ def_delegators(:client, *Spaceship::ConnectAPI::Tunes::API.instance_methods(false))+ def_delegators(:client, *Spaceship::ConnectAPI::Users::API.instance_methods(false))
This is necessary for backwards compatibility, right?
comment created time in a month
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
module Spaceship class ConnectAPI module Provisioning- #- # bundleIds- #+ module API+ def provisioning_request_client=(provisioning_request_client)+ @provisioning_request_client = provisioning_request_client+ end - def get_bundle_ids(filter: {}, includes: nil, limit: nil, sort: nil)- params = Client.instance.build_params(filter: filter, includes: includes, limit: limit, sort: sort)- Client.instance.get("bundleIds", params)- end+ def provisioning_request_client+ return @provisioning_request_client if @provisioning_request_client+ raise TypeError, "You need to instantiate this module with provisioning_request_client, man!"
😂 Left over from testing, I assume?
comment created time in a month
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
+require 'faraday'++require_relative 'globals'++module Spaceship+ class StatsMiddleware < Faraday::Middleware+ ServiceOption = Struct.new(:name, :url, :auth_type)+ class << self+ def services+ @services ||= [+ ServiceOption.new("App Store Connect API (official)", "api.appstoreconnect.apple.com", "JWT"),+ ServiceOption.new("App Store Connect API (web session)", "appstoreconnect.apple.com/iris/v1", "Web session"),+ ServiceOption.new("App Store Connect API (web session)", "developer.apple.com/services-account/v1/", "Web session"),+ ServiceOption.new("Legacy iTunesConnect Auth", "idmsa.apple.com", "Web session"),+ ServiceOption.new("Legacy iTunesConnect Auth", "appstoreconnect.apple.com/olympus/v1/", "Web session"),+ ServiceOption.new("Legacy iTunesConnect", "appstoreconnect.apple.com/WebObjects/iTunesConnect.woa", "Web session"),+ ServiceOption.new("Legacy iTunesConnect Developer Portal", "developer.apple.com/services-account", "Web session")+ ]++ @services+ end++ def service_stats+ @service_stats ||= Hash.new(0)+ @service_stats+ end+ end++ def initialize(app)+ super(app)+ end++ def call(env)+ log(env)+ @app.call(env)+ end++ def log(env)+ return false unless env && env.url && (uri = URI.parse(env.url))+ service = StatsMiddleware.services.find do |s|+ uri.to_s.include?(s.url)
Why parse the uri and then return it to a string?
comment created time in a month
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
+require 'faraday'++require_relative 'globals'++module Spaceship+ class StatsMiddleware < Faraday::Middleware+ ServiceOption = Struct.new(:name, :url, :auth_type)+ class << self+ def services+ @services ||= [+ ServiceOption.new("App Store Connect API (official)", "api.appstoreconnect.apple.com", "JWT"),+ ServiceOption.new("App Store Connect API (web session)", "appstoreconnect.apple.com/iris/v1", "Web session"),+ ServiceOption.new("App Store Connect API (web session)", "developer.apple.com/services-account/v1/", "Web session"),+ ServiceOption.new("Legacy iTunesConnect Auth", "idmsa.apple.com", "Web session"),+ ServiceOption.new("Legacy iTunesConnect Auth", "appstoreconnect.apple.com/olympus/v1/", "Web session"),+ ServiceOption.new("Legacy iTunesConnect", "appstoreconnect.apple.com/WebObjects/iTunesConnect.woa", "Web session"),+ ServiceOption.new("Legacy iTunesConnect Developer Portal", "developer.apple.com/services-account", "Web session")+ ]++ @services+ end
I don't think these two lines are necessary, the ||= should already return the result of the assignment or the value of the @services variable
def services
@services ||= [
ServiceOption.new("App Store Connect API (official)", "api.appstoreconnect.apple.com", "JWT"),
ServiceOption.new("App Store Connect API (web session)", "appstoreconnect.apple.com/iris/v1", "Web session"),
ServiceOption.new("App Store Connect API (web session)", "developer.apple.com/services-account/v1/", "Web session"),
ServiceOption.new("Legacy iTunesConnect Auth", "idmsa.apple.com", "Web session"),
ServiceOption.new("Legacy iTunesConnect Auth", "appstoreconnect.apple.com/olympus/v1/", "Web session"),
ServiceOption.new("Legacy iTunesConnect", "appstoreconnect.apple.com/WebObjects/iTunesConnect.woa", "Web session"),
ServiceOption.new("Legacy iTunesConnect Developer Portal", "developer.apple.com/services-account", "Web session")
]
end
comment created time in a month
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
describe Spaceship::ConnectAPI::Client do- let(:client) { Spaceship::ConnectAPI::TestFlight::Client.instance }- let(:hostname) { Spaceship::ConnectAPI::Users::Client.hostname }- let(:username) { '[email protected]' }- let(:password) { 'so_secret' }+ context 'create instance' do+ it '#initialize' do+ cookie = double('cookie')+ current_team_id = double('current_team_id')+ token = double('token')+ other_tunes_client = double('tunes_client')+ other_portal_client = double('portal_client') - before do- Spaceship::Tunes.login(username, password)- end+ portal_args = { cookie: cookie, current_team_id: current_team_id, token: token, another_client: other_portal_client }+ tunes_args = { cookie: cookie, current_team_id: current_team_id, token: token, another_client: other_tunes_client } - context 'build_params' do- let(:path) { "betaAppReviewDetails" }- let(:nil_filter) { { build: nil } }- let(:one_filter) { { build: "123" } }- let(:two_filters) { { build: "123", app: "321" } }- let(:includes) { "model.attribute" }- let(:limit) { "30" }- let(:sort) { "asc" }-- it 'builds params with nothing' do- params = client.build_params- expect(params).to eq({})- end+ provisioning_client = double('provisioning_client')+ test_flight_client = double('test_flight_client')+ tunes_client = double('tunes_client')+ users_client = double('users_client') - it 'builds params with nil filter' do- params = client.build_params(filter: nil_filter)- expect(params).to eq({})- end+ # Creates the API clienets for the modules
# Creates the API clients for the modules
comment created time in a month
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
+require 'faraday'++require_relative 'globals'++module Spaceship+ class StatsMiddleware < Faraday::Middleware+ ServiceOption = Struct.new(:name, :url, :auth_type)+ class << self+ def services+ @services ||= [+ ServiceOption.new("App Store Connect API (official)", "api.appstoreconnect.apple.com", "JWT"),+ ServiceOption.new("App Store Connect API (web session)", "appstoreconnect.apple.com/iris/v1", "Web session"),+ ServiceOption.new("App Store Connect API (web session)", "developer.apple.com/services-account/v1/", "Web session"),+ ServiceOption.new("Legacy iTunesConnect Auth", "idmsa.apple.com", "Web session"),+ ServiceOption.new("Legacy iTunesConnect Auth", "appstoreconnect.apple.com/olympus/v1/", "Web session"),+ ServiceOption.new("Legacy iTunesConnect", "appstoreconnect.apple.com/WebObjects/iTunesConnect.woa", "Web session"),+ ServiceOption.new("Legacy iTunesConnect Developer Portal", "developer.apple.com/services-account", "Web session")+ ]++ @services+ end++ def service_stats+ @service_stats ||= Hash.new(0)+ @service_stats+ end+ end++ def initialize(app)+ super(app)+ end++ def call(env)+ log(env)+ @app.call(env)+ end++ def log(env)+ return false unless env && env.url && (uri = URI.parse(env.url))+ service = StatsMiddleware.services.find do |s|+ uri.to_s.include?(s.url)+ end++ service = ServiceOption.new("", uri.host, "") if service.nil?
service = ServiceOption.new("Unknown", uri.host, "Unknown") if service.nil?
comment created time in a month
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
++require_relative '../client'+require_relative './response'+require_relative '../client'+require_relative './response'++require_relative '../stats_middleware'++module Spaceship+ class ConnectAPI+ class APIClient < Spaceship::Client+ attr_accessor :token++ #####################################################+ # @!group Client Init+ #####################################################++ # Instantiates a client with cookie session or a JWT token.+ def initialize(cookie: nil, current_team_id: nil, token: nil, another_client: nil)+ if token.nil?+ if another_client.nil?+ super(cookie: cookie, current_team_id: current_team_id, timeout: 1200)+ else+ super(cookie: another_client.instance_variable_get(:@cookie), current_team_id: another_client.team_id)+ end+ else+ options = {+ request: {+ timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i,+ open_timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i+ }+ }+ @token = token+ @current_team_id = current_team_id++ hostname = "https://api.appstoreconnect.apple.com/v1/"++ @client = Faraday.new(hostname, options) do |c|+ c.response(:json, content_type: /\bjson$/)+ c.response(:plist, content_type: /\bplist$/)+ c.use(FaradayMiddleware::RelsMiddleware)+ c.use(Spaceship::StatsMiddleware)+ c.adapter(Faraday.default_adapter)+ c.headers["Authorization"] = "Bearer #{token.text}"++ if ENV['SPACESHIP_DEBUG']+ # for debugging only+ # This enables tracking of networking requests using Charles Web Proxy+ c.proxy = "https://127.0.0.1:8888"+ c.ssl[:verify_mode] = OpenSSL::SSL::VERIFY_NONE+ elsif ENV["SPACESHIP_PROXY"]+ c.proxy = ENV["SPACESHIP_PROXY"]+ c.ssl[:verify_mode] = OpenSSL::SSL::VERIFY_NONE if ENV["SPACESHIP_PROXY_SSL_VERIFY_NONE"]+ end++ if ENV["DEBUG"]+ puts("To run spaceship through a local proxy, use SPACESHIP_DEBUG")+ end+ end+ end+ end++ def self.hostname+ return nil+ end++ #+ # Helpers+ #++ def web_session?+ return @token.nil?+ end++ def build_params(filter: nil, includes: nil, limit: nil, sort: nil, cursor: nil)+ params = {}++ filter = filter.delete_if { |k, v| v.nil? } if filter++ params[:filter] = filter if filter && !filter.empty?+ params[:include] = includes if includes+ params[:limit] = limit if limit+ params[:sort] = sort if sort+ params[:cursor] = cursor if cursor++ return params+ end++ def get(url_or_path, params = nil)+ response = with_asc_retry do+ request(:get) do |req|+ req.url(url_or_path)+ req.options.params_encoder = Faraday::NestedParamsEncoder+ req.params = params if params+ req.headers['Content-Type'] = 'application/json'+ end+ end+ handle_response(response)+ end++ def post(url_or_path, body, tries: 5)+ response = with_asc_retry(tries) do+ request(:post) do |req|+ req.url(url_or_path)+ req.body = body.to_json+ req.headers['Content-Type'] = 'application/json'+ end+ end+ handle_response(response)+ end++ def patch(url_or_path, body)+ response = with_asc_retry do+ request(:patch) do |req|+ req.url(url_or_path)+ req.body = body.to_json+ req.headers['Content-Type'] = 'application/json'+ end+ end+ handle_response(response)+ end++ def delete(url_or_path, params = nil, body = nil)+ response = with_asc_retry do+ request(:delete) do |req|+ req.url(url_or_path)+ req.options.params_encoder = Faraday::NestedParamsEncoder if params+ req.params = params if params+ req.body = body.to_json if body+ req.headers['Content-Type'] = 'application/json' if body+ end+ end+ handle_response(response)+ end+
nit: lots of duplication here, not sure if it would be worth it to refactor
comment created time in a month
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
++require_relative '../client'+require_relative './response'+require_relative '../client'+require_relative './response'++require_relative '../stats_middleware'++module Spaceship+ class ConnectAPI+ class APIClient < Spaceship::Client+ attr_accessor :token++ #####################################################+ # @!group Client Init+ #####################################################++ # Instantiates a client with cookie session or a JWT token.+ def initialize(cookie: nil, current_team_id: nil, token: nil, another_client: nil)+ if token.nil?+ if another_client.nil?+ super(cookie: cookie, current_team_id: current_team_id, timeout: 1200)+ else+ super(cookie: another_client.instance_variable_get(:@cookie), current_team_id: another_client.team_id)+ end+ else+ options = {+ request: {+ timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i,+ open_timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i+ }+ }+ @token = token+ @current_team_id = current_team_id++ hostname = "https://api.appstoreconnect.apple.com/v1/"++ @client = Faraday.new(hostname, options) do |c|+ c.response(:json, content_type: /\bjson$/)+ c.response(:plist, content_type: /\bplist$/)+ c.use(FaradayMiddleware::RelsMiddleware)+ c.use(Spaceship::StatsMiddleware)+ c.adapter(Faraday.default_adapter)+ c.headers["Authorization"] = "Bearer #{token.text}"++ if ENV['SPACESHIP_DEBUG']+ # for debugging only+ # This enables tracking of networking requests using Charles Web Proxy+ c.proxy = "https://127.0.0.1:8888"+ c.ssl[:verify_mode] = OpenSSL::SSL::VERIFY_NONE+ elsif ENV["SPACESHIP_PROXY"]+ c.proxy = ENV["SPACESHIP_PROXY"]+ c.ssl[:verify_mode] = OpenSSL::SSL::VERIFY_NONE if ENV["SPACESHIP_PROXY_SSL_VERIFY_NONE"]+ end++ if ENV["DEBUG"]+ puts("To run spaceship through a local proxy, use SPACESHIP_DEBUG")+ end+ end+ end+ end++ def self.hostname+ return nil+ end
What's this used for? It looks like it may be used for overriding in the subclasses, but wouldn't it be shadowed by the variable on L36?
comment created time in a month
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
++require_relative '../client'+require_relative './response'+require_relative '../client'+require_relative './response'++require_relative '../stats_middleware'++module Spaceship+ class ConnectAPI+ class APIClient < Spaceship::Client+ attr_accessor :token++ #####################################################+ # @!group Client Init+ #####################################################++ # Instantiates a client with cookie session or a JWT token.+ def initialize(cookie: nil, current_team_id: nil, token: nil, another_client: nil)
What is the failure mode here, e.g. what if all parameters are nil? Maybe explicitly throw at the beginning for combinations that are not supported - if everything is actually optional then that's fine, but maybe add a comment because that's a bit unusual 🙂
comment created time in a month
Pull request review commentfastlane/fastlane
[spaceship] improve multiple sessions and multiple auth types
++require_relative '../client'+require_relative './response'+require_relative '../client'+require_relative './response'++require_relative '../stats_middleware'++module Spaceship+ class ConnectAPI+ class APIClient < Spaceship::Client+ attr_accessor :token++ #####################################################+ # @!group Client Init+ #####################################################++ # Instantiates a client with cookie session or a JWT token.+ def initialize(cookie: nil, current_team_id: nil, token: nil, another_client: nil)+ if token.nil?+ if another_client.nil?+ super(cookie: cookie, current_team_id: current_team_id, timeout: 1200)+ else+ super(cookie: another_client.instance_variable_get(:@cookie), current_team_id: another_client.team_id)+ end+ else
nit: Rightward drift after here, maybe replace else with end and a return before that?
comment created time in a month
push eventmilch/dotfiles
commit sha 32c02ee6677575633ae76372587cd883ee4def59
Always use vim keybindings in fish
commit sha 4a2141e67f4741ce846a43b881291067c9890b01
Switch to my personal fork of the light theme
commit sha 3d12f47c4a0332ceaa9fd7f15c0c5e616e920e65
Update brew install command
push time in 2 months
push eventmilch/papercolor-theme
commit sha b49c7a7a0b84d24004b917ad9324915f87d3d9b3
Add typescript colors
push time in 2 months
:art: Light & Dark Vim color schemes inspired by Google's Material Design
fork in 2 months
push eventmilch/dotfiles
commit sha e2ca0b05996efdb36929db889ffcb866d35445b6
Add iTerm2 preferences
push time in 2 months
push eventmilch/dotfiles
commit sha 61417d2939a20be9c9903e2be811109cbaccbed8
Update Brewfile
commit sha f2b0ccd8ad4124f4bb26cfacdcc8cc37ab130281
Add a couple of frequently used functions
push time in 2 months
push eventmilch/dotfiles
commit sha d344bae22fd496f67c30f4181a8561fed754c24a
Fix issue with dark/light switcher resetting CoC colors
commit sha 6c02977d51225ad70fa20f3c73612a44aad6f1b8
Switch to better diff colors
commit sha 97d97621549dad62f904475fd4c756d5c511e378
Get rid of TERM setting, it's not needed
push time in 2 months