Slide 1

Slide 1 text

ৄղFastfile iOSDC 2018 @giginet

Slide 2

Slide 2 text

୭ • @giginet • Cookpad Inc. ٕज़෦ϞόΠϧج൫άϧʔϓ • Core contributor of fastlane

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

ର৅ • ͢ͰʹfastlaneΛಋೖ͍ͯ͠Δਓ • ಋೖํ๏ͳͲʹ͍ͭͯ͸͋·Γ৮Ε·ͤΜ • RubyͰͷ։ൃʹ׳Ε͍ͯͳ͍ਓ

Slide 5

Slide 5 text

Agenda • fastlane׆༻ࣄྫ঺հ • ࠷ڧͷFastfileͷॻ͖ํ • ໌೔͔Β࢖͑Δศརػೳ • Ξϯνύλʔϯू • ޮ཰తσόοάख๏ͷ঺հ

Slide 6

Slide 6 text

fastlane׆༻ࣄྫू

Slide 7

Slide 7 text

ίʔυϨϏϡʔ

Slide 8

Slide 8 text

ϦϦʔεϑϩʔ؅ཧ

Slide 9

Slide 9 text

αϒϛοτ • CIͰϦϦʔεϏϧυͯ͠AppStore Connectʹαϒ ϛοτ • ΞϓϦ͝ͱʹҟͳͬͨϦϦʔεϑϩʔ • Slack͔ΒλάΛࢦఆͯ͠δϣϒΛىಈ • ຖिࣗಈతʹϦϦʔε

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

ࣾ಺޲͚Ϗϧυ • masterΛࣗಈͰEnterpriseϥΠηϯεͰϏϧυͯ͠ ഑৴αʔϏεͰࣾ಺഑৴ • ಛఆͷϥϕϧ͕͍ͭͨPR΋ಈ࡞֬ೝ༻ʹ഑৴

Slide 13

Slide 13 text

ࣾ಺޲͚Ϗϧυ

Slide 14

Slide 14 text

ࣾ಺޲͚Ϗϧυ

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

એ఻ • ಈ࡞֬ೝͷͨΊͷࣾ಺ΞϓϦ഑৴αʔϏεΛ৽ͨʹ࡞ͬ ͨ࿩

Slide 17

Slide 17 text

ϝτϦΫεऩू

Slide 18

Slide 18 text

͋Γ͕ͪͳ͜ͱ • ͳΜͰ΋Fastfileʹॻ͖͕ͪ • ͳΜͰ΋Ͱ͖ΔͷͰϩδοΫ૿͕͑ͪ • ஌Βͳ͍͏ͪʹյΕ͍ͯΔ • fastlane͓͡͞Μ͕͍Δ

Slide 19

Slide 19 text

࠷ߴͷFastfileͷॻ͖ํ

Slide 20

Slide 20 text

Fastfileͷॻ͖ํʢجຊฤʣ

Slide 21

Slide 21 text

Fastfile • جຊతʹ͸Ruby • FastlaneͷଞͷΞΫγϣϯ͕؆୯ʹݺ΂Δ • ศརͳಠࣗػೳ͕͍͔ͭ͋͘Δ

Slide 22

Slide 22 text

private_lane • ಺෦తʹ͔࣮͠ߦͰ͖ͳ͍lane • ڞ௨ॲཧͳͲΛ·ͱΊΔͷʹศར • ΄͔ͷlane͔Βݺ΂Δ

Slide 23

Slide 23 text

private_lane :build_for_appstore do |params| scheme = params[:scheme] build_ios_app(scheme: scheme) end lane :release do build_for_appstore(scheme: 'MyApp') end Ҿ਺ ผͷMBOF͔Βݺ΂Δ

Slide 24

Slide 24 text

private_lane VS def • private_lane͸಺෦తʹ͸ProcʹͳΔͷͰॻ͖ํ͕ ҟͳΔ • Rubyͷdef͸ؔ਺ΦϒδΣΫτͰ͸ͳ͍

Slide 25

Slide 25 text

private_lane :build_for_appstore do |params| next unless params[:scheme] build_ios_app end SFUVSOͰ͸ͳ͍

Slide 26

Slide 26 text

import • ڊେͳFastfileΛ෼ׂͰ͖Δ

Slide 27

Slide 27 text

# vim: syntax=ruby lane :release do build_for_appstore end import 'ReleaseFastfile' fastlane/ReleaseFastfile fastlane/Fastfile

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

GitHubͰͷγϯλοΫεϋΠϥΠτ • Fastfile΍ओཁͳ~file͸ࣗಈతʹRubyͱͯ͠ѻΘΕΔ • ϑΝΠϧ໊Λม͑ͨͱ͖ʹਖ਼ৗʹϋΠϥΠτ͞Εͳ͍໰୊ • ϑΝΠϧͷ1ߦ໨ʹϚδοΫίϝϯτΛهड़͢Δ # vim: syntax=ruby

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

Advanced Feature • ެࣜυΩϡϝϯτͷAdvanced͕ৄ͍͠ • https://docs.fastlane.tools/advanced/

Slide 32

Slide 32 text

Fastfile • ͳΜͰ΋ॻ͚͕ͪ • = Ruby • ͳΜͰ΋ॻ͖͕ͪ • ʹFastfile͕ͲΜͲΜංେԽ͍ͯ͘͠

Slide 33

Slide 33 text

ಡΈ΍͍͢Fastfile΁

Slide 34

Slide 34 text

Q. ࠷ߴͷFastfileͱ͸

Slide 35

Slide 35 text

A. ແ

Slide 36

Slide 36 text

ͦ΋ͦ΋FastfileΛॻ͔ͳ͍ • Fastfile͸ίʔυΛॻ͘৔ॴͰ͸ͳ͍ • Fastfile΁ͷهड़ྔΛݮΒ͍ͯ͘͠Ξϓϩʔν

Slide 37

Slide 37 text

ൿಗ஋΍ઃఆ஋͸؀ڥม਺΁ • fastlaneͷଟ͘ͷύϥϝʔλ͸؀ڥม਺͔Β౉ ͢͜ͱ͕Ͱ͖Δ • ϋʔυίʔυΛ͢ΔΑΓ؀ڥม਺Ͱ஫ೖͨ͠ ํ͕σόοάɺϝϯς͠΍͍͢

Slide 38

Slide 38 text

slack(message: 'Building...', slack_url: 'https://hooks.slack.com/ services/XXXXXXXX/YYYYYYY/ZZZZZZZ', channel: '#myapp-dev') slack(message: 'Building...') export SLACK_URL=https://hooks.slack.com/ services/XXXXXXXX/YYYYYYY/ZZZZZZZ export FL_SLACK_CHANNEL=#myapp-dev

Slide 39

Slide 39 text

ઃఆͱϩδοΫ͸෼཭͢Δ • ~fileΛར༻͢Δ • Appfile, Gymfile, Scanfile, Matchfile, Deliverfile etc… • for_laneͰlane͝ͱͷઃఆ஋΋ར༻Մೳ

Slide 40

Slide 40 text

lane :buiid_for_appstore do gym(xcodeproj: 'MyApp.xcodeproj', scheme: 'MyApp', configuration: 'Release', export_method: 'app-store', include_bitcode: true, clean: true) end

Slide 41

Slide 41 text

scheme 'MyApp' include_bitcode false claen true for_lane :build_for_inhouse do configuration 'Beta' export_method 'enterprise' end for_lane :build_for_release do configuration 'Release' export_method 'app-store' include_bitcode true end fastlane/Gymfile σϑΥϧτ஋Λઃఆ MBOF͝ͱʹPWFSSJEF

Slide 42

Slide 42 text

ActionΛ෼཭͢Δ $ bundle exec fastlane new_action

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

module Fastlane module Actions class GetAnswer < Action def self.run(params) 42 end def self.description "Answer to the Ultimate Question of Life, the Universe, and Everything" end end end end get_answer_action.rb ΞΫγϣϯ࣮ߦ࣌ͷ ॲཧ

Slide 45

Slide 45 text

actions_path '../actions/' lane :show_answer do UI.message(get_answer) end Fastfile ࠷্෦Ͱϩʔυ͢Δ

Slide 46

Slide 46 text

Actionͷ෼཭ • ύϥϝʔλͷόϦσʔγϣϯ͕͠΍͍͢(ConfigItem) • ܕνΣοΫɺόϦσʔλɺNullable • ςετ͕ॻ͖΍͍͢(rspec)

Slide 47

Slide 47 text

$ fastlane generate_certificate \ app_identifiers:com.example.myapp,com.example.mya pp.NotificationService \ type:production ΧϯϚ۠੾Γͷจࣈྻ ಛఆͷจࣈྻ͚ͩड͚෇͚͍ͨ

Slide 48

Slide 48 text

lane generate_certificate |params| do # Split app_identifier app_identifiers = params[:app_identifiers] UI.user_error!("app_identifier must be String") unless app_identifier.is_a?(String) app_identifiers = app_identifiers.split(',') # Validate type type = params[:type] UI.user_error!("Type must be development or production") unless %w(development production).include?(type) # Do something... end ܕνΣοΫ͢Δ TQMJU͢Δ UZQF͕ਖ਼͍͔͠ΈΔ

Slide 49

Slide 49 text

def self.available_options [ FastlaneCore::ConfigItem.new( key: :type, description: "Certificate type to generate. (development or production)", optional: false, verify_block: proc do |value| is_valid = %w(development production).include?(value.downcase) UI.user_error!(“type is invalid") unless is_valid end, type: String), FastlaneCore::ConfigItem.new( ɹɹɹɹkey: :app_identifier, ɹɹɹɹshort_option: "-a", ɹɹɹɹdescription: "The bundle identifier(s) of your app (comma- separated)", ɹɹɹɹis_string: false, ɹɹɹɹtype: Array), ] end ΦʔόʔϥΠυ

Slide 50

Slide 50 text

def self.available_options [ FastlaneCore::ConfigItem.new( key: :type, description: "Certificate type to generate. (development or production)", optional: false, verify_block: proc do |value| is_valid = %w(development production).include?(value.downcase) UI.user_error!(“type is invalid") unless is_valid end, type: String), FastlaneCore::ConfigItem.new( ɹɹɹɹkey: :app_identifiers, ɹɹɹɹshort_option: "-a", ɹɹɹɹdescription: "The bundle identifier(s) of your app (comma- separated)", ɹɹɹɹis_string: false, ɹɹɹɹtype: Array), ] end ΦʔόʔϥΠυ

Slide 51

Slide 51 text

ίʔυαΠϯ

Slide 52

Slide 52 text

XcodeͷઃఆΛ׆༻͢Δ • ྫ͑͹഑෍༻ͱࣾ಺Ϗϧυ༻ͳͲͰϏϧυ؀ڥΛෳ਺؅ ཧ͍ͨ͠ #VJME $POpHVSBUJPO %FWFMPQFS 5FBN "QQ*EFOUJpFS $PEF4JHOJOH 4UZMF %FCVH 0SHBOJ[BUJPO DPNDPPLQBEOFX BQQ "VUPNBUJD 3FMFBTF 0SHBOJ[BUJPO DPNDPPLQBEOFX BQQ .BOVBM #FUB &OUFSQSJTF DPNDPPLQBEOF XBQQJOIPVTF .BOVBM

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

XcodeͷઃఆΛ׆༻͢Δ • FastfileͰApp Identifier΍Code Signing StyleΛॻ͖ ׵͑ • update_app_identifier • update_project_team • automatic_code_signing • update_project_provisioning

Slide 55

Slide 55 text

# Provisioning Profileͷऔಘ match(git_branch: "enterprise", type: 'enterprise', readonly: true, app_identifier: 'com.cookpad.myapp-beta') provisioning_profile_specifier = ENV["sigh_com.cookpad.myapp-beta_appstore_profile-name"] provisioning_profile_path = ENV["sigh_com.cookpad.myapp- beta_appstore_profile-path"] team_id = ENV["sigh_com.cookpad.myapp-beta_appstore_team- id"] NBUDIͰ1SPWJTJPOJOH1SPpMFΛऔಘ 1SPWJTJPOJOH1SPpMFͷ1BUI΍໊લΛऔಘ

Slide 56

Slide 56 text

match • Provisioning ProfileΛgitϦϙδτϦͰಉظͰ ͖Δ࢓૊Έ

Slide 57

Slide 57 text

No content

Slide 58

Slide 58 text

No content

Slide 59

Slide 59 text

# Team IDͷߋ৽ update_project_team( teamid: team_id, ) # Automatic Code SigningͷແޮԽ disable_automatic_code_signing( team_id: team_id, profile_name: provisioning_profile_specifier, code_sign_identity: 'iPhone Distribution', targets: %w(MyApp), ) # Provisioning Profileͷઃఆ update_project_provisioning( profile: provisioning_profile_path, target_filter: 'MyApp', )

Slide 60

Slide 60 text

# App Identifierͷߋ৽ update_app_identifier( app_identifier: 'com.cookpad.myapp-inhouse', ) gym(scheme: 'MyApp-Beta', export_method: ‘enterprise')

Slide 61

Slide 61 text

lane :build_for_inhouse # Provisioning Profileͷऔಘ match(git_branch: "enterprise", type: 'enterprise', readonly: true, app_identifier: 'com.cookpad.myapp-beta') provisioning_profile_specifier = ENV["sigh_com.cookpad.myapp-beta_appstore_profile-name"] provisioning_profile_path = ENV["sigh_com.cookpad.myapp-beta_appstore_profile-path"] team_id = ENV["sigh_com.cookpad.myapp-beta_appstore_team-id"] # Team IDͷߋ৽ update_project_team( teamid: team_id, ) # Automatic Code SigningͷແޮԽ disable_automatic_code_signing( team_id: team_id, profile_name: provisioning_profile_specifier, code_sign_identity: 'iPhone Distribution', targets: %w(MyApp), ) # Provisioning Profileͷઃఆ update_project_provisioning( profile: provisioning_profile_path, target_filter: 'MyApp', ) # App Identifierͷߋ৽ update_app_identifier( app_identifier: 'com.cookpad.myapp-beta', ) build_ios_app(scheme: 'MyApp-Beta', export_method: 'enterprise') end

Slide 62

Slide 62 text

lane :build_for_inhouse # Provisioning Profileͷऔಘ match(git_branch: "enterprise", type: 'enterprise', readonly: true, app_identifier: 'com.cookpad.myapp-beta') provisioning_profile_specifier = ENV["sigh_com.cookpad.myapp-beta_appstore_profile-name"] provisioning_profile_path = ENV["sigh_com.cookpad.myapp-beta_appstore_profile-path"] team_id = ENV["sigh_com.cookpad.myapp-beta_appstore_team-id"] # Team IDͷߋ৽ update_project_team( teamid: team_id, ) # Automatic Code SigningͷແޮԽ disable_automatic_code_signing( team_id: team_id, profile_name: provisioning_profile_specifier, code_sign_identity: 'iPhone Distribution', targets: %w(MyApp), ) # Provisioning Profileͷઃఆ update_project_provisioning( profile: provisioning_profile_path, target_filter: 'MyApp', ) # App Identifierͷߋ৽ update_app_identifier( app_identifier: 'com.cookpad.myapp-beta', ) build_ios_app(scheme: 'MyApp-Beta', export_method: 'enterprise') end

Slide 63

Slide 63 text

XcodeͷઃఆΛ׆༻͢Δ • ίʔυͰϏϧυઃఆΛॻ͖׵͑ͳ͍ • XcodeͷBuild ConfigurationΛ׆༻͢Δ

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

No content

Slide 66

Slide 66 text

#VJME $POpHVSBU JPO %FWFMPQF S5FBN 1SPEVDU #VOEMF *EFOUJpFS $PEF 4JHOJOH 4UZMF 1SPEVDU #VOEMF *EFOUJUZ 1SPWJTJPOJOH 1SPpMF %FCVH 0SHBOJ[BUJ PO DPNDPPLQBE OFXBQQ "VUPNBUJD J04 %FWFMPQFS "VUPNBUJD 3FMFBTF 0SHBOJ[BUJ PO DPNDPPLQBE OFXBQQ .BOVBM J04 %JTUSJCVUJPO NBUDI "QQ4UPSF DPNDPPLQBE OFXBQQ #FUB &OUFSQSJTF DPNDPPLQBE OFXBQQ JOIPVTF .BOVBM J04 %JTUSJCVJUJPO NBUDI *O)PVTF DPNDPPLQBE OFXBQQCFUB

Slide 67

Slide 67 text

$PEF4JHO*EFOUJUZ $PEF4JHOJOH4UZMF %FWFMPQFS5FBN 1SPWJTJPOJOH1SPpMF4QFDJpFS

Slide 68

Slide 68 text

lane :build_for_appstore do # Provisioning Profileͷऔಘ(match) app_identifiers = %w(com.cookpad.myapp com.cookpad.myapp.NotificationService) match(type: 'appstore', readonly: true, app_identifier: app_identifiers) # Ϗϧυ gym(scheme: 'MyApp', configuration: 'Release', export_method: 'app-store') end

Slide 69

Slide 69 text

XcodeͷઃఆΛ׆༻͢Δ • ͜Ε͸͜ΕͰಈ͘ • ͕ɺXcode͕ෆ҆ఆʹͳΓ͕ͪͳͷͰίʔυ αΠϯ͸Կ΍ͬͯ΋ਏ͍

Slide 70

Slide 70 text

࠷ߴͷFastfileͷͨΊʹ • ઃఆ஋͸؀ڥม਺Λ࢖͏ • ઃఆͱϩδοΫͷ෼཭ɻ~FileΛ׆༻͢Δ • ڊେͳϩδοΫ͸Actionʹ͢Δ • XcodeͷϏϧυઃఆΛ࢖͏

Slide 71

Slide 71 text

σόοάख๏

Slide 72

Slide 72 text

fastlane͋Δ͋Δ • खݩͰͷಈ࡞֬ೝ͕μϧ͍ • ಈ͔ͳͯ͘CIʹpushΛ܁Γฦ͢

Slide 73

Slide 73 text

σόοάख๏ • جຊతʹRubyͳͷͰσόοΨʔ͕࢖͑Δ • irb, pry, byebug • ൿಗ஋͸؀ڥม਺Λ࢖͏ • envchain • ઃఆ஋΋؀ڥม਺Λ࢖͏ • direnv

Slide 74

Slide 74 text

pry, pry-nav • RubyͷσόοΨ • ϒϨΠΫϙΠϯτΛுͬͯREPL͕ىಈͰ͖Δ • εςοϓ࣮ߦ΋Ͱ͖Δ(pry-byebug) gem 'pry' gem 'pry-byebug'

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

# vim: syntax=ruby require_fastlane 'pry' lane :release do |params| binding.pry scheme = params[:scheme] build_for_appstore end SFRVJSFͱಉ͡ #SFBLQPJOU

Slide 77

Slide 77 text

direnv • σόοά༻ʹൿಗ஋Ͱ͸ͳ͍஋͸ϋʔυίʔ υ͢ΔΑΓ؀ڥม਺Ͱ༩͑ͨํ͕ศར • σΟϨΫτϦ಺ͷ؀ڥม਺Λઃఆͯ͘͠ΕΔ ౕ • .envrcΛಡΜͰ͘ΕΔ

Slide 78

Slide 78 text

export [email protected] export FL_SLACK_CHANNEL=#ios-dev .envrc

Slide 79

Slide 79 text

envchain • ΩʔνΣΠϯʹൿಗ஋Λอଘͯ͠؀ڥม਺͔ ΒಡΊΔ΍ͭ • σόοά༻ʹΑ͘࢖͏஋͸ొ࿥͓ͯ͘͠ͱศ ར

Slide 80

Slide 80 text

envchain

Slide 81

Slide 81 text

·ͱΊ • ࠷ߴͷFastfileͷॻ͖ํ͸FastfileΛॻ͔ͳ͍͜ͱ • σʔλ͸ผʹ؅ཧ͢Δ • XcodeͷػೳΛར༻͢Δ • ϓϥάΠϯɺΞΫγϣϯʹͰ͖Δ΋ͷ͸੾Γग़͢ • ϩδοΫʹ͸specΛॻ͘

Slide 82

Slide 82 text

એ఻

Slide 83

Slide 83 text

એ఻1 • ಈ࡞֬ೝͷͨΊͷࣾ಺ΞϓϦ഑৴αʔϏεΛ৽ͨʹ࡞ͬ ͨ࿩

Slide 84

Slide 84 text

એ఻2 • ୀ۶ͳ͜ͱ͸App Store Connect APIʹ΍ΒͤΑ͏ • 9/20(Tue) iOSDC Reject Conference Day 2

Slide 85

Slide 85 text

એ఻3 •

Slide 86

Slide 86 text

͝ਗ਼ௌ ͋Γ͕ͱ͏͍͟͝·ͨ͠