Skip to content

Commit

Permalink
Merge pull request #11 from DeployGate/feature/v0.0.3
Browse files Browse the repository at this point in the history
v0.0.3
  • Loading branch information
henteko committed Oct 29, 2015
2 parents 1b7749c + 3636cb2 commit ebe4695
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 80 deletions.
1 change: 1 addition & 0 deletions deploygate.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ POST_INSTALL_MESSAGE
spec.add_dependency 'xcodeproj', '~> 0.28.2'
spec.add_dependency 'github_issue_request', '~> 0.0.2'
spec.add_dependency 'highline', '~> 1.7.8'
spec.add_dependency 'uuid', '~> 2.3.8'

# ios build
spec.add_dependency 'gym', '~> 1.0.0'
Expand Down
1 change: 1 addition & 0 deletions lib/deploygate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
require "find"
require "github_issue_request"
require "highline"
require "uuid"

# ios build
require "gym"
Expand Down
34 changes: 25 additions & 9 deletions lib/deploygate/builds/ios/analyze.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,38 @@ def initialize(workspaces)

# @return [String]
def target_bundle_identifier
scheme_file = find_xcschemes
xs = Xcodeproj::XCScheme.new(scheme_file)
target_name = xs.profile_action.buildable_product_runnable.buildable_reference.target_name

project = Xcodeproj::Project.open(@xcodeproj)
target = project.native_targets.reject{|target| target.name != target_name}.first
product_name = target.product_name
conf = target.build_configuration_list.build_configurations.reject{|conf| conf.name != BUILD_CONFIGRATION}.first
identifier = conf.build_settings['PRODUCT_BUNDLE_IDENTIFIER']
product_name = target_product_name
identifier = target_build_configration.build_settings['PRODUCT_BUNDLE_IDENTIFIER']
identifier.gsub!(/\$\(PRODUCT_NAME:.+\)/, product_name)

identifier
end

# @return [String]
def target_xcode_setting_provisioning_profile_uuid
uuid = target_build_configration.build_settings['PROVISIONING_PROFILE']
UUID.validate(uuid) ? uuid : nil
end

private

def target_build_configration
target_project_setting.build_configuration_list.build_configurations.reject{|conf| conf.name != BUILD_CONFIGRATION}.first
end

def target_product_name
target_project_setting.product_name
end

def target_project_setting
scheme_file = find_xcschemes
xs = Xcodeproj::XCScheme.new(scheme_file)
target_name = xs.profile_action.buildable_product_runnable.buildable_reference.target_name

project = Xcodeproj::Project.open(@xcodeproj)
project.native_targets.reject{|target| target.name != target_name}.first
end

def find_xcschemes
shared_schemes = Dir[File.join(@xcodeproj, 'xcshareddata', 'xcschemes', '*.xcscheme')].reject do |scheme|
@scheme != File.basename(scheme, '.xcscheme')
Expand Down
103 changes: 55 additions & 48 deletions lib/deploygate/builds/ios/export.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,29 @@ class Export

class << self
# @param [String] bundle_identifier
# @param [String] uuid
# @return [Hash]
def find_local_data(bundle_identifier)
def find_local_data(bundle_identifier, uuid = nil)
result_profiles = {}
teams = {}
profiles.each do |profile_path|
plist = analyze_profile(profile_path)
entities = plist['Entitlements']
profile_paths = load_profile_paths
profiles = profile_paths.map{|p| profile_to_plist(p)}
profiles.reject! {|profile| profile['UUID'] != uuid} unless uuid.nil?

profiles.each do |profile|
entities = profile['Entitlements']
unless entities['get-task-allow']
team = entities['com.apple.developer.team-identifier']
application_id = entities['application-identifier']
application_id.slice!(/^#{team}\./)
application_id = '.' + application_id if application_id == '*'
if bundle_identifier.match(application_id) &&
DateTime.now < plist['ExpirationDate'] &&
installed_certificate?(profile_path)
DateTime.now < profile['ExpirationDate'] &&
installed_certificate?(profile['Path'])

teams[team] = plist['TeamName'] if teams[team].nil?
teams[team] = profile['TeamName'] if teams[team].nil?
result_profiles[team] = [] if result_profiles[team].nil?
result_profiles[team].push(profile_path)
result_profiles[team].push(profile['Path'])
end
end
end
Expand All @@ -41,11 +45,14 @@ def find_local_data(bundle_identifier)
# @param [String] profile_path
# @return [Boolean]
def installed_certificate?(profile_path)
plist = analyze_profile(profile_path)
certificate_str = plist['DeveloperCertificates'].first.read
certificate = OpenSSL::X509::Certificate.new certificate_str
id = OpenSSL::Digest::SHA1.new(certificate.to_der).to_s.upcase!
installed_identies.include?(id)
profile = profile_to_plist(profile_path)
certs = profile['DeveloperCertificates'].map do |cert|
certificate_str = cert.read
certificate = OpenSSL::X509::Certificate.new certificate_str
id = OpenSSL::Digest::SHA1.new(certificate.to_der).to_s.upcase!
installed_identies.include?(id)
end
certs.include?(true)
end

# @return [Array]
Expand All @@ -64,25 +71,39 @@ def installed_identies
ids
end

# @param [Array] profiles
# @param [Array] profile_paths
# @return [String]
def select_profile(profiles)
def select_profile(profile_paths)
select = nil

profiles.each do |profile|
select = profile if adhoc?(profile) && select.nil?
select = profile if inhouse?(profile)
profile_paths.each do |path|
select = path if adhoc?(path) && select.nil?
select = path if inhouse?(path)
end
select
end

# @param [String] profile_path
# @return [String]
def codesigning_identity(profile_path)
plist = analyze_profile(profile_path)
method = method(profile_path)
identity = "iPhone Distribution: #{plist['TeamName']}"
identity += " (#{plist['Entitlements']['com.apple.developer.team-identifier']})" if method == AD_HOC
profile = profile_to_plist(profile_path)
identity = nil

profile['DeveloperCertificates'].each do |cert|
certificate_str = cert.read
certificate = OpenSSL::X509::Certificate.new certificate_str
id = OpenSSL::Digest::SHA1.new(certificate.to_der).to_s.upcase!

available = `security find-identity -v -p codesigning`
available.split("\n").each do |current|
next if current.include? "REVOKED"
begin
search = current.match(/.*\) (.*) \"(.*)\"/)
identity = search[2] if id == search[1]
rescue
end
end
end

identity
end
Expand All @@ -96,46 +117,32 @@ def method(profile_path)
# @param [String] profile_path
# @return [Boolean]
def adhoc?(profile_path)
plist = analyze_profile(profile_path)
!plist['Entitlements']['get-task-allow'] && plist['ProvisionsAllDevices'].nil?
profile = profile_to_plist(profile_path)
!profile['Entitlements']['get-task-allow'] && profile['ProvisionsAllDevices'].nil?
end

# @param [String] profile_path
# @return [Boolean]
def inhouse?(profile_path)
plist = analyze_profile(profile_path)
!plist['Entitlements']['get-task-allow'] && !plist['ProvisionsAllDevices'].nil?
profile = profile_to_plist(profile_path)
!profile['Entitlements']['get-task-allow'] && !profile['ProvisionsAllDevices'].nil?
end

def load_profile_paths
profiles_path = File.expand_path("~") + "/Library/MobileDevice/Provisioning Profiles/*.mobileprovision"
Dir[profiles_path]
end

# @param [String] profile_path
# @return [Hash]
def analyze_profile(profile_path)
plist = nil
def profile_to_plist(profile_path)
File.open(profile_path) do |profile|
asn1 = OpenSSL::ASN1.decode(profile.read)
plist_str = asn1.value[1].value[0].value[2].value[1].value[0].value
plist = Plist.parse_xml plist_str.force_encoding('UTF-8')
plist['Path'] = profile_path
return plist
end
plist
end

# @return [Array]
def profiles
profiles = []
Find.find(profile_dir_path) do |path|
next if path == profile_dir_path
Find.prune if FileTest.directory?(path)
if File.extname(path) == PROFILE_EXTNAME
profiles.push(path)
end
end

profiles
end

# @return [String]
def profile_dir_path
File.join(ENV['HOME'], 'Library/MobileDevice/Provisioning Profiles')
end
end
end
Expand Down
52 changes: 49 additions & 3 deletions lib/deploygate/builds/ios/set_profile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,54 @@ def app_id_create
false
end

# @param [String] uuid
# @return [Array]
def create_provisioning
def create_provisioning(uuid)
FileUtils.mkdir_p(OUTPUT_PATH)

if uuid.nil?
return install_provisioning
else
return select_uuid_provisioning(uuid)
end
end

private

def select_uuid_provisioning(uuid)
adhoc_profiles = Spaceship.provisioning_profile.ad_hoc.all
inhouse_profiles = Spaceship.provisioning_profile.in_house.all

adhoc_profiles.reject!{|p| p.uuid != uuid}
inhouse_profiles.reject!{|p| p.uuid != uuid}
select_profile = nil
method = nil
unless adhoc_profiles.empty?
select_profile = adhoc_profiles.first
method = Export::AD_HOC
end
unless inhouse_profiles.empty?
select_profile = inhouse_profiles.first
method = Export::ENTERPRISE
end
raise 'Not Xcode selected Provisioning Profile' if select_profile.nil?

values = {
:adhoc => method == Export::AD_HOC ? true : false,
:app_identifier => @identifier,
:username => @username,
:output_path => OUTPUT_PATH,
:provisioning_name => select_profile.name,
:team_id => Spaceship.client.team_id
}
v = FastlaneCore::Configuration.create(Sigh::Options.available_options, values)
Sigh.config = v
download_profile_path = Sigh::Manager.start

[download_profile_path]
end

def install_provisioning
if @method == Export::AD_HOC
prod_certs = Spaceship.certificate.production.all
else
Expand All @@ -58,7 +104,6 @@ def create_provisioning
end
raise 'Not local install certificate' if distribution_cert_ids.empty?

FileUtils.mkdir_p(OUTPUT_PATH)
provisionings = []
distribution_cert_ids.each do |cert_id|
values = {
Expand All @@ -71,7 +116,8 @@ def create_provisioning
}
v = FastlaneCore::Configuration.create(Sigh::Options.available_options, values)
Sigh.config = v
provisionings.push(Sigh::Manager.start)
download_profile_path = Sigh::Manager.start
provisionings.push(download_profile_path)
end

provisionings
Expand Down
23 changes: 20 additions & 3 deletions lib/deploygate/command_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def run
begin
Commands::Init.run
rescue => e
error_handling("Commands::Init Error: #{e.class}", e.message, ['bug', 'Init'])
error_handling("Commands::Init Error: #{e.class}", create_error_issue_body(e), ['bug', 'Init'])
raise e
end
end
Expand All @@ -35,7 +35,7 @@ def run
begin
Commands::Deploy.run(args, options)
rescue => e
error_handling("Commands::Deploy Error: #{e.class}", e.message, ['bug', 'Deploy'])
error_handling("Commands::Deploy Error: #{e.class}", create_error_issue_body(e), ['bug', 'Deploy'])
raise e
end
end
Expand All @@ -49,7 +49,7 @@ def run
begin
Commands::Logout.run
rescue => e
error_handling("Commands::Logout Error: #{e.class}", e.message, ['bug', 'Logout'])
error_handling("Commands::Logout Error: #{e.class}", create_error_issue_body(e), ['bug', 'Logout'])
raise e
end
end
Expand All @@ -58,6 +58,23 @@ def run
run!
end

# @param [Exception] error
# @return [String]
def create_error_issue_body(error)
return <<EOF
# Error message
#{error.message}
# Backtrace
```
#{error.backtrace.join("\n")}
```
EOF
end

# @param [String] title
# @param [String] body
# @param [Array] labels
def error_handling(title, body, labels)
options = {
:title => title,
Expand Down
10 changes: 6 additions & 4 deletions lib/deploygate/commands/deploy/build.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ def ios(workspaces, options)
puts 'Example: com.example.ios'
identifier = input_bundle_identifier
end
uuid = analyze.target_xcode_setting_provisioning_profile_uuid

data = DeployGate::Builds::Ios::Export.find_local_data(identifier)
data = DeployGate::Builds::Ios::Export.find_local_data(identifier, uuid)
profiles = data[:profiles]
teams = data[:teams]

target_provisioning_profile = nil
if teams.empty?
target_provisioning_profile = create_provisioning(identifier)
target_provisioning_profile = create_provisioning(identifier, uuid)
elsif teams.count == 1
target_provisioning_profile = DeployGate::Builds::Ios::Export.select_profile(profiles[teams.keys.first])
elsif teams.count >= 2
Expand Down Expand Up @@ -98,8 +99,9 @@ def select_teams(teams, profiles)
end

# @param [String] identifier
# @param [String] uuid
# @return [String]
def create_provisioning(identifier)
def create_provisioning(identifier, uuid)
puts <<EOF
No suitable provisioning profile found to export the app.
Expand Down Expand Up @@ -131,7 +133,7 @@ def create_provisioning(identifier)
end

begin
provisioning_profiles = set_profile.create_provisioning
provisioning_profiles = set_profile.create_provisioning(uuid)
rescue => e
DeployGate::Message::Error.print("Error: Failed to create provisioning profile")
raise e
Expand Down
2 changes: 1 addition & 1 deletion lib/deploygate/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module DeployGate
VERSION = "0.0.2"
VERSION = "0.0.3"
end
Loading

0 comments on commit ebe4695

Please sign in to comment.