Slide 1

Slide 1 text

J04ΞϓϦ։ൃʹ͓͚Δ ࣗಈԽϊ΢ϋ΢ IUUQCJUMZNPTB@BVUPNBUJPO

Slide 2

Slide 2 text

kishikawa katsumi http://kishikawakatsumi.com Twitter @k_katsumi https://github.com/kishikawakatsumi http://kishikawakatsumi.hatenablog.com

Slide 3

Slide 3 text

ࠓ೔࿩͢͜ͱ

Slide 4

Slide 4 text

• ϦϦʔεϓϩηεΛࣗಈԽ͢Δʹ͸ • Ϗϧυ؀ڥΛΫϦʔϯʹอͭ • ख࡞ۀΛͳ͘͢ • ςετͷࣗಈԽ • ܧଓతΠϯςάϨʔγϣϯʢCIʣ • ίʔυΧόϨοδ ࠓ೔࿩͢͜ͱ

Slide 5

Slide 5 text

• ੓࣏తͳ͜ͱ • ؀ڥΛ੔͑Δ࣌ؒΛ֫ಘ͢Δʹ͸ • ͓ۚͷަবͷ࢓ํ • etc… ࠓ೔࿩͞ͳ͍͜ͱ

Slide 6

Slide 6 text

• ࣗಈԽͷϝϦοτ͕Θ͔Δ • අ༻ରޮՌͷόϥϯε͕Θ͔Δ • ࠓ͙͢ʹࣗಈԽΛ࣮ફͰ͖ΔΑ͏ʹͳΔ • Ͱ͖Δ͜ͱ͔Β࢝ΊΒΕΔ • ҰਓͰ΋Ͱ͖Δ ࠓ೔ͷΰʔϧ

Slide 7

Slide 7 text

ෆ҆Λ๊͑ͯ ϦϦʔε͍ͯ͠·ͤΜ͔ʁ

Slide 8

Slide 8 text

มߋ มߋ มߋ มߋ มߋ W ϦϦʔε ख࡞ۀͷʢ͚ͩͲΑ͋͘ΔʣϦϦʔεϓϩηε

Slide 9

Slide 9 text

มߋ มߋ มߋ มߋ มߋ W ϦϦʔε ख࡞ۀͷʢ͚ͩͲΑ͋͘ΔʣϦϦʔεϓϩηε HJUQVMM "MSFBEZVQUPEBUF 2. खݩͷ؀ڥΛ࠷৽ʹߋ৽ͯ͠ 1. ϦϞʔτϦϙδτϦͷߋ৽ΛࢭΊͯ 3. όʔδϣϯ൪߸Λߋ৽ͯ͠

Slide 10

Slide 10 text

ख࡞ۀͷʢ͚ͩͲΑ͋͘ΔʣϦϦʔεϓϩηε 4. XcodeͰϦϦʔεߏ੒ͰϏϧυˍΞʔΧΠϒ

Slide 11

Slide 11 text

ख࡞ۀͷʢ͚ͩͲΑ͋͘ΔʣϦϦʔεϓϩηε 5. ผʹAdHoc൛ΛϏϧυͯؔ͠܎ऀʹ഑෍ˍݕূ 6. iTunes ConnectͰ৽͍͠όʔδϣϯΛ࡞੒ɺߋ৽಺༰ͳͲΛهड़ 7. XcodeͷΦʔΨφΠβʔ͔ΒΞοϓϩʔυ

Slide 12

Slide 12 text

ຊ౰ʹେৎ෉Ͱ͔͢ʁ

Slide 13

Slide 13 text

มߋ มߋ มߋ มߋ มߋ W ਃ੥ ख࡞ۀͷʢ͚ͩͲΑ͋͘ΔʣϦϦʔεϓϩηε HJUQVMM 6QEBUJOHFFCE FSSPS:PVSMPDBMDIBOHFTUPUIFGPMMPXJOHpMFTXPVMECFPWFSXSJUUFOCZNFSHF 6CJSFHJ"QQ%FMFHBUFN 1MFBTF DPNNJUZPVSDIBOHFTPSTUBTIUIFNCFGPSFZPVDBONFSHF "CPSUJOH 2. खݩͷ؀ڥΛ࠷৽ʹߋ৽ͯ͠ 1. ϦϞʔτϦϙδτϦͷߋ৽ΛࢭΊͯ ߋ৽ʹࣦഊͨ͠ͷʹؾ͔ͮͳ͔ͬͨ

Slide 14

Slide 14 text

มߋ มߋ มߋ มߋ มߋ W ਃ੥ ख࡞ۀͷʢ͚ͩͲΑ͋͘ΔʣϦϦʔεϓϩηε HJUGFUDI 2. खݩͷ؀ڥΛ࠷৽ʹߋ৽ͯ͠ 1. ϦϞʔτϦϙδτϦͷߋ৽ΛࢭΊͯ HJUGFUDI͚ͩͯ͠NFSHFΛ๨Εͨ

Slide 15

Slide 15 text

มߋ มߋ มߋ มߋ มߋ W ਃ੥ ख࡞ۀͷʢ͚ͩͲΑ͋͘ΔʣϦϦʔεϓϩηε HJUQVMM "MSFBEZVQUPEBUF 2. खݩͷ؀ڥΛ࠷৽ʹߋ৽ͯ͠ 1. ϦϞʔτϦϙδτϦͷߋ৽ΛࢭΊͯ ࣮͸खݩͷํ͕ϦϞʔτΑΓਐΜͰ͍ͨ

Slide 16

Slide 16 text

ख࡞ۀͷʢ͚ͩͲΑ͋͘ΔʣϦϦʔεϓϩηε 4. XcodeͰϦϦʔεߏ੒ͰϏϧυˍΞʔΧΠϒ Ϗϧυߏ੒Λؒҧ͑ͨ

Slide 17

Slide 17 text

มߋ มߋ มߋ W ਃ੥ ख࡞ۀͷʢ͚ͩͲΑ͋͘ΔʣϦϦʔεϓϩηε 1. ϦϞʔτϦϙδτϦͷߋ৽ΛࢭΊͯ มߋ มߋ ਃ੥ͨ͠ͷ͸ຊ౰ʹ͜ͷϦϏδϣϯʁ ʢ࣮͸୭͔͕1VTI͍͔ͯͨ͠΋͠Εͳ͍ʣ

Slide 18

Slide 18 text

มߋ มߋ มߋ W ਃ੥ ख࡞ۀͷʢ͚ͩͲΑ͋͘ΔʣϦϦʔεϓϩηε 1. ϦϞʔτϦϙδτϦͷߋ৽ΛࢭΊͯ มߋ มߋ ͜ͷ࣌఺ͰϦδΣΫτʹͳͬͨ৔߹Ͳ͏͢Δʁ

Slide 19

Slide 19 text

• खݩͷ؀ڥ͕ϦϞʔτͱҟͳ͍ͬͯͨ • Ϗϧυߏ੒͕ҧ͍ͬͯͨ • Provisioning Profile͕ҧ͏ • όʔδϣϯ൪߸Λ͚ͭؒҧ͑ͨ • ϦδΣΫτ͞Εͨ৔߹ɺͲ͜ʹ໭Δ͔ • etc… ख࡞ۀͷϦϦʔεϓϩηεʹ͓͚Δࣦഊྫ

Slide 20

Slide 20 text

ख࡞ۀͷϦϦʔεϓϩηεͷؒҧ͍͸ݕূ͕ࠔ೉

Slide 21

Slide 21 text

ϦϦʔεϓϩηε͕ ࣗಈԽ͞Ε͍ͯΔ৔߹

Slide 22

Slide 22 text

ࣗಈԽ͞ΕͨϦϦʔεϓϩηε 1. ୭͔͕νϟοτͰʮ@ubibot releaseʯͱൃݴ͢Δ BϦϦʔεϒϥϯν͕࡞ΒΕΔ CϦϦʔεϒϥϯν͔ΒNBTUFS΁ͷ 1VMM3FRVFTU͕࡞ΒΕΔ DϦϦʔεϏϧυ͕࡞ΒΕΔ

Slide 23

Slide 23 text

ࣗಈԽ͞ΕͨϦϦʔεϓϩηε 2. ୭͔͕νϟοτͰʮ@ubibot submitʯͱൃݴ͢Δ EJ5VOFT$POOFDUʹΞοϓϩʔυ͞ΕΔ

Slide 24

Slide 24 text

ࣗಈԽ͞ΕͨϦϦʔεϓϩηε @ubibot release ϦϦʔεϒϥϯν ϓϧϦΫΤετ "E)PD഑෍ ΫϥογϡϨϙʔτ ਃ੥

Slide 25

Slide 25 text

ࣗಈԽʹΑͬͯ΋ͨΒ͞ΕΔ΋ͷ 2. ࡞ۀ͕ՄࢹԽ͞ΕΔ 1. ࡞ۀ͕෼୲Ͱ͖ΔΑ͏ʹͳΔ

Slide 26

Slide 26 text

ࣗಈԽʹΑͬͯ΋ͨΒ͞ΕΔ΋ͷ 3. ͲͷϦϏδϣϯ͕ਃ੥͞Εͨͷ͔ه࿥ʹ࢒Δ

Slide 27

Slide 27 text

มߋ มߋ มߋ W ਃ੥ ࣗಈԽʹΑͬͯ΋ͨΒ͞ΕΔ΋ͷ มߋ มߋ ͜ͷ࣌఺ͰϦδΣΫτʹͳͬͯ΋ɺ

Slide 28

Slide 28 text

มߋ มߋ มߋ W ࠶ਃ੥ ࣗಈԽʹΑͬͯ΋ͨΒ͞ΕΔ΋ͷ มߋ มߋ मਖ਼ΛϦϦʔεϒϥϯνʹੵΜͰ࠶ਃ੥͢Δ͚ͩ

Slide 29

Slide 29 text

• ܁Γฦ͠ͷख࡞ۀ͔Βղ์͞ΕΔ • ຖճಉ͡ߏ੒Ͱ࣮֬ʹϏϧυͰ͖Δ • ΫϦʔϯͳ؀ڥͰϏϧυ͞ΕΔ • ͲͷϦϏδϣϯ͕Ϗϧυ͞Εͨͷ͔ه࿥ʹ࢒Δ • ୭Ͱ΋ͦͷ࡞ۀ͕Ͱ͖ΔΑ͏ʹͳΔ • ࡞ۀ͕෼୲Ͱ͖Δ • ࡞ۀͷه࿥͕࢒Δ • ࡞ۀ͕ՄࢹԽ͞ΕΔ • etc… ࣗಈԽʹΑͬͯ΋ͨΒ͞ΕΔ΋ͷ

Slide 30

Slide 30 text

• ܁Γฦ͠ͷख࡞ۀ͔Βղ์͞ΕΔ • ຖճಉ͡ߏ੒Ͱ࣮֬ʹϏϧυͰ͖Δ • ΫϦʔϯͳ؀ڥͰϏϧυ͞ΕΔ • ͲͷϦϏδϣϯ͕Ϗϧυ͞Εͨͷ͔ه࿥ʹ࢒Δ • ୭Ͱ΋ͦͷ࡞ۀ͕Ͱ͖ΔΑ͏ʹͳΔ • ࡞ۀ͕෼୲Ͱ͖Δ • ࡞ۀͷه࿥͕࢒Δ • ࡞ۀ͕ՄࢹԽ͞ΕΔ • etc… ࣗಈԽʹΑͬͯ΋ͨΒ͞ΕΔ΋ͷ

Slide 31

Slide 31 text

w ʮࣗಈԽͰ͖Δঢ়ଶʯΛอͭ͜ͱ͕ॏཁ w ʮࣗಈԽͰ͖Δঢ়ଶʯͱ͸λεΫ͕γϯϓϧʹ෼ׂ ͞ΕͯػցͰ΋࣮ߦՄೳͰ͋Δͱ͍͏͜ͱ w ػցͰ࣮ߦͰ͖ΔͳΒɺ܁Γฦͨ͠Γɺه࿥΍࿈ܞ ͕༰қͰ͋Δ w ୭͕ݟͯ΋ঢ়ଶ͕೺ѲͰ͖ΔΑ͏ʹͳΔ w ࣗಈԽ͕໨తͰ͸ͳͯ͘ɺࣗಈԽͰ͖͍ͯΔͳΒʮࣗ ಈԽͰ͖Δঢ়ଶʯ͕ҡ࣋Ͱ͖͍ͯΔͱ͍͏͜ͱ w ࣗಈԽʹΑͬͯʮࣗಈԽͰ͖Δঢ়ଶʯ͕ҡ࣋͞Εͯ Δ͜ͱΛอূ͢Δ

Slide 32

Slide 32 text

ϓϩδΣΫτ͔ΒϒϥοΫϘοΫεΛແ͘͢

Slide 33

Slide 33 text

ࣗಈԽ΁ͷऔΓ૊Έ

Slide 34

Slide 34 text

• มߋ؅ཧ • Github • Pull Request • ίʔυϨϏϡʔ • ϥΠϒϥϦ؅ཧ • ࣗಈϏϧυ • ςετ • ςετͷࣗಈԽ • ܧଓతΠϯςάϨʔγϣϯʢCIʣ • ίʔυΧόϨοδ ࣗಈԽ΁ͷऔΓ૊Έ

Slide 35

Slide 35 text

• ϦϦʔεͷࣗಈԽ • ࣗಈϏϧυ • ഑෍ͷࣗಈԽ • ਃ੥ͷࣗಈԽ ࣗಈԽ΁ͷऔΓ૊Έ

Slide 36

Slide 36 text

ࣗಈԽ͢Δલͷ४උ

Slide 37

Slide 37 text

w ϓϩδΣΫτΛμ΢ϯϩʔυͨ͠Βɺ ͦͷ··ϏϧυͰ͖ΔΑ͏ʹ͢Δ w ϓϩδΣΫτಛ༗ͷϧʔϧΛແ͘͢

Slide 38

Slide 38 text

࠷ॳʹ͍͔ͭ͘ͷϑΝΠϧΛੜ੒͢Δඞཁ͕͋Δ $ update-hostname.rb

Slide 39

Slide 39 text

ىಈ࣌ύϥϝʔλͰࢦఆ͢ΔΑ͏ʹมߋ

Slide 40

Slide 40 text

w Ϗϧυߏ੒Λγϯϓϧʹ͢Δ w ϓϩδΣΫτಛ༗ͷϧʔϧΛແ͘͢ w ୅ΘΓʹ୭Ͱ΋஌͍ͬͯΔϝδϟʔ ͳπʔϧΛ࢖͓͏

Slide 41

Slide 41 text

ىಈ࣌ύϥϝʔλͰࢦఆ͢ΔΑ͏ʹมߋ

Slide 42

Slide 42 text

ىಈ࣌ύϥϝʔλͰࢦఆ͢ΔΑ͏ʹมߋ

Slide 43

Slide 43 text

มߋ؅ཧ

Slide 44

Slide 44 text

• ෼ࢄܕόʔδϣϯ؅ཧγεςϜ • Git • Mercurial มߋ؅ཧ

Slide 45

Slide 45 text

• ෼ࢄܕόʔδϣϯ؅ཧγεςϜ • Git → Github, Bitbucket • Mercurial → Bitbucket มߋ؅ཧ Github͔BitbucketΛҰॹʹ࢖͓͏ʂ

Slide 46

Slide 46 text

1VMM3FRVFTU

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

Pull Request Pull Request github-flow masterϒϥϯν͸ৗʹϦϦʔεՄೳͳঢ়ଶʹอͭ master

Slide 50

Slide 50 text

Pull Request Pull Request git-flow masterϒϥϯν͸ৗʹϦϦʔεՄೳͳঢ়ଶʹอͭ develop master

Slide 51

Slide 51 text

• มߋ͕୭ʹͰ΋ݟ͑ΔΑ͏ʹͳΔ • ࡞ۀͷཤྺ͕͢΂ͯه࿥ʹ࢒Δ • ίʔυϨϏϡʔ • ਐḿ͕ՄࢹԽ͞ΕΔ Pull RequestʹΑΔ։ൃελΠϧ

Slide 52

Slide 52 text

[WIP] Work In Progressʢ࡞ۀதʣPull Requestͷ׆༻

Slide 53

Slide 53 text

• ํ਑Λݕ౼͠ͳ͕ΒਐΊΒΕΔ • ͱΓ͋͑ͣಈ͔ͯ͠ࢼͯ͠ΈΔ • ϦϦʔεϒϥϯνʹӨڹΛ༩͑ͳ͍ • etc… [WIP] Work In Progressʢ࡞ۀதʣPull Requestͷ׆༻

Slide 54

Slide 54 text

େ͖ͳมߋ͸ϒϥϯνΛผʹ͢Δ

Slide 55

Slide 55 text

Pull Request Pull Request master 3_0ϒϥϯν

Slide 56

Slide 56 text

֎෦ϥΠϒϥϦͷ؅ཧ

Slide 57

Slide 57 text

ΞϓϦͱϥΠϒϥϦͷίʔυ͕͍ࠞͬͯ͟Δ৔߹

Slide 58

Slide 58 text

• ݱࡏͲͷόʔδϣϯΛ࢖ͬͯΔ͔Θ͔ Βͳ͍ • ΋͔ͨ͠͠ΒԿ͔खΛೖΕͯΔ͔΋͠ Εͳ͍ →্ॻ͖ͨ͠ΒյΕΔ ΞϓϦͱϥΠϒϥϦͷίʔυ͕͍ࠞͬͯ͟Δ৔߹

Slide 59

Slide 59 text

$PDPB1PET

Slide 60

Slide 60 text

source 'https://github.com/CocoaPods/Specs.git' source 'https://[email protected]/ubiregiinc/Specs.git' platform :ios, '7.0' inhibit_all_warnings! pod 'UUIDShortener' pod 'JLRoutes' pod 'NLCoreData' pod 'AFNetworking' pod 'AFNetworkActivityLogger' pod 'SDWebImage' pod 'PEPhotoCropEditor' pod 'UICKeyChainStore' pod 'GCDWebServer', '~> 1.4' pod 'FXImageView' pod 'FastCoding' pod 'SSZipArchive' pod 'Helpshift' pod 'CrittercismSDK' pod 'Aspects' pod 'GoogleAnalytics-iOS-SDK' target :Ubiregi2Tests do pod 'OCMock' pod 'OCHamcrest' pod 'OHHTTPStubs' end

Slide 61

Slide 61 text

PODS: - AFNetworkActivityLogger (2.0.3): - AFNetworking/NSURLConnection (~> 2.0) - AFNetworking/NSURLSession (~> 2.0) - AFNetworking (2.5.0): - AFNetworking/NSURLConnection (= 2.5.0) - AFNetworking/NSURLSession (= 2.5.0) - AFNetworking/Reachability (= 2.5.0) - AFNetworking/Security (= 2.5.0) - AFNetworking/Serialization (= 2.5.0) - AFNetworking/UIKit (= 2.5.0) - Aspects (1.4.1) - CoineyKit-iOS (0.0.7) - CrittercismSDK (5.0.7) - FastCoding (3.2) - FXImageView (1.3.5) - GCDWebServer (1.4) - GoogleAnalytics-iOS-SDK (3.10): - GoogleAnalytics-iOS-SDK/Core (= 3.10) - GoogleAnalytics-iOS-SDK/Core (3.10) - Helpshift (4.9.1) - JLRoutes (1.5.1) - M13BadgeView (1.0.4) - NLCoreData (0.5.3) - OCHamcrest (4.1.1) - OCMock (3.1.2) - OHHTTPStubs (3.1.10): - OHHTTPStubs/Core (= 3.1.10) - OHHTTPStubs/Core (3.1.10) - PEPhotoCropEditor (1.3.1) - SDWebImage (3.7.1): - SDWebImage/Core (= 3.7.1) - SDWebImage/Core (3.7.1) - SEJSONViewController (0.2.0) - SSZipArchive (0.3.2) - UICKeyChainStore (2.0.2) - UUIDShortener (1.0.1) - YLProgressBar (3.5.1)

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

ґଘπʔϧͷ؅ཧ

Slide 64

Slide 64 text

#VOEMFS

Slide 65

Slide 65 text

No content

Slide 66

Slide 66 text

source 'https://rubygems.org' gem 'rake' gem 'cocoapods' gem 'xcpretty' gem 'xcjobs'

Slide 67

Slide 67 text

• CocoaPods • iOS/OS XΞϓϦͷϥΠϒϥϦ؅ཧπʔ ϧ • Bundler • RubygemsʢRubyͷϥΠϒϥϦʣ؅ཧ πʔϧ • ͲͪΒ΋σϑΝΫτελϯμʔυ ֎෦ϥΠϒϥϦͷ؅ཧ

Slide 68

Slide 68 text

• ࣗ෼͕ϝϯςφϯε͍ͯ͠Δίʔυͱɺ ͦ͏Ͱͳ͍ίʔυΛ۠ผ͢Δ ʢϓϩδΣΫτΛγϯϓϧʹอͭʣ • ࠓԿͷͲͷόʔδϣϯΛ࢖͍ͬͯΔͷ ͔Θ͔ΔΑ͏ʹ͢Δ • มߋΛه࿥ʹ࢒͢ ֎෦ϥΠϒϥϦͷ؅ཧ

Slide 69

Slide 69 text

ܧଓతΠϯςάϨʔγϣϯ $POUJOVPVT*OUFHSBUJPO

Slide 70

Slide 70 text

• master (git flowͷ৔߹͸develop) ΛৗʹϦϦʔε Մೳͳঢ়ଶʹอͭ • ࣗಈϏϧυʢςετͳ͠ʣ͚ͩͰ΋ޮՌΞϦ • ഑෍·ͰࣗಈԽ͢ΔͱޮՌେ • ΋ͪΖΜςετ͕͋Δͱ͞Βʹྑ͍ ܧଓతΠϯςάϨʔγϣϯʢCIʣ

Slide 71

Slide 71 text

• WebαʔϏε • Travis CI • Circle CI • Greenhouse CI • ιϑτ΢ΣΞ • Jenkins มߋ؅ཧ

Slide 72

Slide 72 text

• Travis CI • CIαʔϏεͷ࿝ฮ • ϓϥΠϕʔτϦϙδτϦ͸༗ྉ • ೚ҙͷॲཧΛ࣮ߦͰ͖Δ มߋ؅ཧ

Slide 73

Slide 73 text

• Circle CI • ϓϥΠϕʔτϦϙδτϦ΋ແྉ • iOS/OS XͷϏϧυ͸ϕʔλ • ೚ҙͷॲཧΛ࣮ߦͰ͖Δ มߋ؅ཧ

Slide 74

Slide 74 text

• Greenhouse CI • ϓϥΠϕʔτϦϙδτϦ΋ແྉ • ॲཧͷΧελϚΠζ͸Ͱ͖ͳ͍ʢͨͩ ͠ඪ४ͷॲཧ͕ඇৗʹ༏लʣ มߋ؅ཧ

Slide 75

Slide 75 text

Greenhouse CI

Slide 76

Slide 76 text

Greenhouse CI

Slide 77

Slide 77 text

$*αʔϏεͱ࿈ܞ͢Δʹ͸

Slide 78

Slide 78 text

ίϚϯυϥΠϯ

Slide 79

Slide 79 text

xcodebuild test -workspace Ubiregi2.xcworkspace -scheme Ubiregi2-Release -sdk iphonesimulator -configuration Release -derivedDataPath build -destination name=iPad 2,OS=7.1 -destination name=iPad Air,OS=8.1 CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO GCC_SYMBOLS_PRIVATE_EXTERN=NO 1. γϛϡϨʔλ༻ʹϏϧυͯ͠ɺςετΛ࣮ߦ ίϚϯυϥΠϯ • Ϗϧυߏ੒(Debug/Release)͸Ҿ਺Ͱࢦఆ • destinationύϥϝʔλͰ࣮ߦ؀ڥΛࢦఆͰ͖Δ • GCC_SYMBOLS_PRIVATE_EXTERNύϥϝʔλΛҾ਺Ͱ্ॻ͖

Slide 80

Slide 80 text

$ xcodebuild build -workspace Ubiregi2.xcworkspace -scheme Ubiregi2-Release -configuration Release -derivedDataPath "build" CONFIGURATION_TEMP_DIR="build/temp" CODE_SIGN_IDENTITY="iPhone Distribution: Ubiregi Inc. (A1234567XZ)" 2. σόΠε༻ʹϏϧυ͢Δɻ ίϚϯυϥΠϯ • ϓϩϏδϣχϯάϓϩϑΝΠϧ͸Ҿ਺Ͱࢦఆ ʢෳ਺ͷλʔήοτ͕͋Δ৔߹͸.xcodeprojͰࢦఆ͢Δʣ

Slide 81

Slide 81 text

$ xcodebuild archive -workspace Ubiregi2.xcworkspace -scheme Ubiregi2-Release -configuration Release -derivedDataPath "build" CONFIGURATION_TEMP_DIR="build/temp" CODE_SIGN_IDENTITY="iPhone Distribution: Ubiregi Inc. (A1234567XZ)" -archivePath "build/Ubiregi2-Release" 3. ϦϦʔεߏ੒ͰϏϧυͯ͠ɺ.xcarchiveʢਃ੥༻ͷΞʔΧΠϒʣΛ࡞Δ ίϚϯυϥΠϯ • ϓϩϏδϣχϯάϓϩϑΝΠϧ͸Ҿ਺Ͱࢦఆ ʢෳ਺ͷλʔήοτ͕͋Δ৔߹͸.xcodeprojͰࢦఆ͢Δʣ

Slide 82

Slide 82 text

$ xcodebuild -exportArchive -archivePath "build/Ubiregi2-Release.xcarchive" -exportFormat "IPA" -exportPath "build/Ubiregi2-AdHoc.ipa" -exportProvisioningProfile "Ubiregi AdHoc" 4. ਃ੥༻ͷϏϧυ͔ΒɺϓϩϏδϣχϯάϓϩϑΝΠϧ͚ͩม͑ͯ ݕূ༻ͷϕʔλ൛ͷ.ipaΛ࡞੒͢Δ ʢਃ੥ͨ͠΋ͷͱॺ໊Ҏ֎͸શ͘ಉ͡όΠφϦͰݕূͰ͖Δʣ ίϚϯυϥΠϯ

Slide 83

Slide 83 text

$ xcodebuild -exportArchive -archivePath "build/Ubiregi2-Release.xcarchive" -exportFormat "IPA" -exportPath "build/Ubiregi2-Release-AppStore.ipa" -exportProvisioningProfile "Ubiregi App Store" 5. ਃ੥༻ͷϏϧυ͔ΒɺApplication LoaderͰΞοϓϩʔυ͢ΔͨΊʹ.ipaΛ࡞੒͢Δ ίϚϯυϥΠϯ

Slide 84

Slide 84 text

3BLF

Slide 85

Slide 85 text

def build_options(opt = {configuration: "Release"}) options = { sdk: "iphoneos", workspace: "Ubiregi2-Release.xcworkspace", scheme: "Ubiregi2-Release", }.merge opt join_options(options: options, prefix: "-", separator: " ") end def build_settings(configuration: "Release") settings = { CONFIGURATION_BUILD_DIR: "build", CONFIGURATION_TEMP_DIR: "build/temp", CODE_SIGN_IDENTITY: "iPhone Distribution: Ubiregi Inc. (Y7522692LT)", } settings = join_options(options: settings, prefix: "", separator: "=") end def test(configuration: "Release") options = build_options(sdk: "iphonesimulator", configuration: configuration) options << DESTINATIONS.map { |destination| %(-destination "#{destination}") }.join(" ") sh "xcodebuild #{options} test | xcpretty -c" end def build_xcarchive(configuration: "Release") options = build_options(configuration: configuration) settings = build_settings(configuration: configuration) sh "xcodebuild #{options} #{settings} archive -archivePath #{ARCHIVE_FILE} | xcpretty -c" end def export_ipa sh "xcodebuild -exportArchive -exportFormat IPA -archivePath #{ARCHIVE_FILE} -exportPath #{IPA_FILE} | xcpretty -c" end ֤ίϚϯυΛλεΫʹ͢Δ Rake

Slide 86

Slide 86 text

release_date = DateTime.now.strftime("%Y/%m/%d %H:%M:%S") release_notes = "Build: #{InfoPlist.marketing_and_build_version} \nUploaded: #{release_date}" fields = { file: "@#{IPA_FILE}", api_token: API_TOKEN, team_token: TEAM_TOKEN, notes: release_notes, notify: true, distribution_lists: DISTRIBUTION_LISTS } fields = join_option(options: fields, prefix: "-F ", seperator: "=") sh "curl -sL -w \"%{http_code} %{url_effective}\\n\" http:// testflightapp.com/api/builds.json #{fields} -o /dev/null ֤ίϚϯυΛλεΫʹ͢Δ Rake

Slide 87

Slide 87 text

release_date = DateTime.now.strftime("%Y/%m/%d %H:%M:%S") release_notes = "Build: #{InfoPlist.marketing_and_build_version} \nUploaded: #{release_date}" fields = { file: "@#{IPA_FILE}", api_token: API_TOKEN, team_token: TEAM_TOKEN, notes: release_notes, notify: true, distribution_lists: DISTRIBUTION_LISTS } fields = join_option(options: fields, prefix: "-F ", seperator: "=") sh "curl -sL -w \"%{http_code} %{url_effective}\\n\" http:// testflightapp.com/api/builds.json #{fields} -o /dev/null ֤ίϚϯυΛλεΫʹ͢Δ Rake

Slide 88

Slide 88 text

$ rake test $ rake archive $ rake testflight ֤ίϚϯυΛλεΫʹ͢Δ Rake

Slide 89

Slide 89 text

9$+PCT

Slide 90

Slide 90 text

XCJobs::Test.new do |t| t.workspace = 'Ubiregi2' t.scheme = 'Ubiregi2-Release' t.configuration = 'Release' t.build_dir = 'build' t.add_destination('name=iPad 2,OS=7.1') t.add_destination('name=iPad Air,OS=8.1') end xcodebuild test -workspace Ubiregi2.xcworkspace -scheme Ubiregi2-Release -sdk iphonesimulator -configuration Release -derivedDataPath build -destination name=iPad 2,OS=7.1 -destination name=iPad Air,OS=8.1 CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO GCC_SYMBOLS_PRIVATE_EXTERN=NO $ rake test 1. γϛϡϨʔλ༻ʹϏϧυͯ͠ɺςετΛ࣮ߦ

Slide 91

Slide 91 text

XCJobs::Archive.new do |t| t.workspace = APP_NAME t.scheme = SCHEME t.configuration = configuration t.signing_identity = signing_identity t.build_dir = BUILD_DIR t.formatter = 'xcpretty -c' end xcodebuild archive -workspace Ubiregi2.xcworkspace -scheme Ubiregi2-Release -configuration Release -derivedDataPath "build" CONFIGURATION_TEMP_DIR="build/temp" CODE_SIGN_IDENTITY="iPhone Distribution: Ubiregi Inc. (A1234567XZ)" -archivePath "build/Ubiregi2-Release" $ rake build:archive 3. ϦϦʔεߏ੒ͰϏϧυͯ͠ɺ.xcarchiveʢਃ੥༻ͷΞʔΧΠϒʣΛ࡞Δ

Slide 92

Slide 92 text

XCJobs::Export.new do |t| t.archive_path = File.join('build', 'Ubiregi2.xcarchive') t.export_path = File.join('build', 'Ubiregi2.ipa') t.export_provisioning_profile = 'Ubiregi_Ad_Hoc.mobileprovision' t.formatter = 'xcpretty -c' end xcodebuild -exportArchive -archivePath "build/Ubiregi2.xcarchive" -exportFormat "IPA" -exportPath "build/Ubiregi2-AdHoc.ipa" -exportProvisioningProfile "Ubiregi AdHoc" $ rake build:export 4. ਃ੥༻ͷϏϧυ͔ΒɺϓϩϏδϣχϯάϓϩϑΝΠϧ͚ͩม͑ͯ ݕূ༻ͷϕʔλ൛ͷ.ipaΛ࡞੒͢Δ

Slide 93

Slide 93 text

language: objective-c install: - bundle install - bundle exec pod install script: - bundle exec rake test profiles:install certificates:install version:set_build_version build:archive build:export distribute:testflight CIͱ؆୯ʹ࿈ܞͰ͖Δ

Slide 94

Slide 94 text

XCJobs::Test.new do |t| t.workspace = 'UCZProgressView' t.scheme = 'UCZProgressView' t.configuration = 'Release' t.build_dir = 'build' t.coverage = true t.formatter = 'xcpretty -c' end XCJobs::Coverage::Coveralls.new() do |t| t.add_extension('.m') t.add_exclude('Example') end ؆୯ͳϓϩδΣΫτͷ৔߹

Slide 95

Slide 95 text

language: objective-c install: - bundle install script: - bundle exec rake test coverage:coveralls ؆୯ͳϓϩδΣΫτͷ৔߹

Slide 96

Slide 96 text

GBTUMBOF IUUQGBTUMBOFUPPMT

Slide 97

Slide 97 text

No content

Slide 98

Slide 98 text

Ϣχοτςετ

Slide 99

Slide 99 text

• ςετΛϓϩάϥϜͰهड़͢Δ • Կ౓Ͱ΋ࣗಈͰςετͰ͖Δ • มߋʹڧ͘ͳΔ • มߋ͕͠΍͘͢ͳΔ Ϣχοτςετ

Slide 100

Slide 100 text

• ख࡞ۀ͕ܰݮ͢Δ • มߋʹର͢Δ৺ཧతෆ҆ΛऔΓআ͘ Ϣχοτςετ ̎छྨͷҟͳΔϝϦοτ

Slide 101

Slide 101 text

• ࣗಈԽ͢Δͱ඼্࣭͕Δ • ୭Ͱ΋ॻ͚Δ • ςετΛॻ͘εΩϧ • ςετ͠΍͍͢ίʔυΛॻ͘εΩϧ • ݁߹ςετ͕ෆཁʹͳΔ Ϣχοτςετ Α͋͘Δޡղ

Slide 102

Slide 102 text

Ϣχοτςετ 1. ςετλʔήοτΛ௥Ճ͢Δ

Slide 103

Slide 103 text

2. ςετίʔυΛ௥Ճ͢Δ Ϣχοτςετ

Slide 104

Slide 104 text

3. खݩͰ࣮ߦ͢Δ Ϣχοτςετ

Slide 105

Slide 105 text

4. CIͱ࿈ܞ͢Δ Ϣχοτςετ

Slide 106

Slide 106 text

Ϣχοτςετ /* "vat" : 5 "price" : "2000.0", "price_type" : "intax" */ UBCheckoutItem *checkoutItem = nil; for (checkoutItem in self.checkoutItems) { if (checkoutItem.checkoutMenuItem.isTaxIncluded) { break; } } checkoutItem.discount = [NSDecimalNumber decimalNumberWithString:@"500"]; checkoutItem.count = @(1); XCTAssertEqualObjects(checkoutItem.apiSalesNet, [NSDecimalNumber decimalNumberWithString:@"1905"]); XCTAssertEqualObjects(checkoutItem.apiSalesTax, [NSDecimalNumber decimalNumberWithString:@"95"]); XCTAssertEqualObjects(checkoutItem.apiDiscountNet, [NSDecimalNumber decimalNumberWithString:@"476"]); XCTAssertEqualObjects(checkoutItem.apiDiscountTax, [NSDecimalNumber decimalNumberWithString:@"24"]); XCTAssertEqualObjects(checkoutItem.discountRatio, [NSDecimalNumber decimalNumberWithString:@"25"]); checkoutItem.count = @(2); XCTAssertEqualObjects(checkoutItem.apiSalesNet, [NSDecimalNumber decimalNumberWithString:@"3810"]); XCTAssertEqualObjects(checkoutItem.apiSalesTax, [NSDecimalNumber decimalNumberWithString:@"190"]); XCTAssertEqualObjects(checkoutItem.apiDiscountNet, [NSDecimalNumber decimalNumberWithString:@"476"]); XCTAssertEqualObjects(checkoutItem.apiDiscountTax, [NSDecimalNumber decimalNumberWithString:@"24"]); ֹۚͷςετ

Slide 107

Slide 107 text

Ϣχοτςετ NSManagedObjectContext *context = [NSManagedObjectContext mainContext]; NSMutableOrderedSet *checkoutItems = [[NSMutableOrderedSet alloc] init]; UBCheckoutItem *item; item = [UBCheckoutItem checkoutItemWithMenuItem:self.menuItems[@"intaxItem"]]; item.count = @(1); item.discount = [NSDecimalNumber decimalNumberWithString:@"500"]; [checkoutItems addObject:item]; item = [UBCheckoutItem checkoutItemWithMenuItem:self.menuItems[@"outtaxItem"]]; item.count = @(1); item.discount = [NSDecimalNumber decimalNumberWithString:@"190"]; [checkoutItems addObject:item]; item = [UBCheckoutItem checkoutItemWithMenuItem:self.menuItems[@"nosalesItem"]]; item.count = @(1); item.discount = [NSDecimalNumber decimalNumberWithString:@"-500"]; [checkoutItems addObject:item]; item = [UBCheckoutItem checkoutItemWithMenuItem:self.menuItems[@"percentageItem"]]; item.count = @(1); [checkoutItems addObject:item]; UBCheckout *checkout = [UBCheckout insertInContext:context]; checkout.checkoutItems = checkoutItems; XCTAssertEqualObjects(checkout.total, [NSDecimalNumber decimalNumberWithString:@"3737"], ɹɹɹɹɹɹɹɹɹɹɹɹɹ@"Ϣʔβʔʹ੥ٻ͞ΕΔֹۚ"); XCTAssertEqualObjects(checkout.tax, [NSDecimalNumber decimalNumberWithString:@“192"], ɹɹɹɹɹɹɹɹɹɹɹɹɹ @"಺ফඅ੫ֹ"); ֹۚͷςετ

Slide 108

Slide 108 text

Ϣχοτςετ NSDictionary *response = [UBTestUtils JSONObjectWithPath:self.dataPath]; [UBTestUtils stubWithJSONObject:response path:self.endpoint]; NSManagedObjectContext *context = [NSManagedObjectContext mainContext]; UBAccount *account = [UBAccount currentAccountInContext:context]; UBAccountSynchronizer *synchronizer = [[UBAccountSynchronizer alloc] initWithAccountID:account.identifier]; XCTestExpectation *expectation = [self expectationWithDescription:@"finish synchronization"]; synchronizer.completionHandler = ^(NSError *error) { assertThat(error, nilValue()); [expectation fulfill]; }; [synchronizer synchronize]; [self waitForExpectationsWithTimeout:10.0 handler:nil]; [context refreshObject:account mergeChanges:YES]; NSDictionary *result = account.dictionaryRepresentation; NSDictionary *expected = response[@"account"]; XCTAssertEqualObjects(result[@"id"], expected[@"id"]); XCTAssertEqualObjects(result[@"login"], expected[@"login"]); XCTAssertEqualObjects(result[@"name"], expected[@"name"]); XCTAssertEqualObjects(result[@"email"], expected[@"email"]); ௨৴ͷςετ

Slide 109

Slide 109 text

Ϣχοτςετ + (id)stubWithJSONObject:(id)JSONObject statusCode:(int)statusCode path: (NSString *)path { id stub = nil; stub = [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { return [request.URL.path hasPrefix:path]; } withStubResponse:^OHHTTPStubsResponse*(NSURLRequest *request) { return [[OHHTTPStubsResponse responseWithJSONObject:JSONObject statusCode:statusCode headers:nil] requestTime:1.0 responseTime:1.0]; }]; return stub; } ௨৴Λελϒʹ͢Δ

Slide 110

Slide 110 text

• Ϟσϧͷςετ͸ॻ͖΍͍͢ • ௨৴ͷςετ͸ελϒɾϞοΫΛ͏·͘࢖͏ • جຊతʹ֎෦ཁҼͰࣦഊ͢Δςετ͸ϝϯ ςφϯε͕೉͍͠ Ϣχοτςετ

Slide 111

Slide 111 text

• ςετ͸Πϯϑϥ • ؀ڥΛ੔͑Δ͜ͱ͕େࣄ • جຊతʹ໘౗ͳͷͰࣗಈతʹ࣮ߦ͞ΕΔ࢓૊ ΈΛ࡞Δ • ఆظతʹ࣮ߦ͢Δ • ॻ͖΍͍͢ͱ͜Ζ͔Βॻ͘ • େࣄͳͱ͜Ζ͔Βॻ͘ • ॻ͖΍͍͢Α͏ͳઃܭΛ͜͜Ζ͕͚Δ Ϣχοτςετ

Slide 112

Slide 112 text

• ςετΛॻ͘ʹ͸εΩϧ͕ඞཁ • ςετ͕͋Δ͜ͱͰಘΒΕΔ҆৺ײͳͲΛܦ ݧ͢Δ͜ͱ͕େࣄ • ͍ͬͨΜςετ͕ॻ͔Εͩͨ͠Βৗʹςετ ͕ಈ͘؀ڥΛอ࣋͢Δ • ޲͖ෆ޲͖͕͋ΔͷͰίετʹݟۃΊ͸େ੾ • ͕Μ͹Γ͗͢ͳ͍ Ϣχοτςετ

Slide 113

Slide 113 text

• ख๏ʹͱΒΘΕ͗͢ͳ͍ • ςετϑΝʔετ, BDD, etc… • ֤ࣗͷελΠϧʹ೚ͤΔ Ϣχοτςετ

Slide 114

Slide 114 text

• 6ʙ8ׂ͘Β͍ಈ͘Α͏ʹͳͬͨͱ͜ΖͰ͓ ΋ΉΖʹςετΛॻ͖࢝ΊΔ • ਖ਼ৗέʔεΛओମʹ؆୯ͳҎ্έʔεΛ2, 3 ݸ • ॻ͍͍ͯ͘͏ͪʹΘ͔Γʹ͍͘ίʔυɺ૝ఆ ࿙Εͷέʔε͕ग़ͯ͘Δ • ௚͢ɺ܁Γฦ͠ Ϣχοτςετ ͪͳΈʹࢲ͸

Slide 115

Slide 115 text

ίʔυΧόϨοδ

Slide 116

Slide 116 text

XCJobs::Test.new do |t| t.workspace = 'Ubiregi2' t.scheme = ‘Ubiregi2-Release' t.configuration = 'Release' t.build_dir = 'build' t.add_destination('name=iPad 2,OS=7.1') t.add_destination('name=iPad Air,OS=8.1') t.coverage = true t.formatter = 'xcpretty -c' end XCJobs::Coverage::Coveralls.new() do |t| t.service_name = 'travis-pro' t.repo_token = ‘xxx...’ t.add_extension('.m') t.add_exclude('Pods') t.add_exclude('Ubiregi2Tests') t.add_exclude_pattern('.*ViewController\.[hm]') end ίʔυΧόϨοδ XCJobsͰઃఆ͢Δ৔߹

Slide 117

Slide 117 text

No content

Slide 118

Slide 118 text

No content

Slide 119

Slide 119 text

• ΧόϨοδͷ׆༻͸೉͍͠ • ϓϩμΫτίʔυͷ৔߹͍͍ͨͯ͸ը໘ͷΧ όϨοδ͕଍ΛҾͬுΔ • ద౰ʹؒҾ͘ • ݱঢ়ͷ೺Ѳʹ࢖͏ • Ϟνϕʔγϣϯ্͕͕ΔΑ͏ʹίϯτϩʔϧ ͢Δ • ͋·Γؾʹ͗͢͠ͳ͍ ίʔυΧόϨοδ