fastlane์ ์ฌ์ฉํ๋ ๋ชจ๋ฐ์ผ ์ฑ์ ์ง์์ ์ธ ํตํฉ๊ณผ ์ ๋ฌ์ ๋ํด ์ด์ผ๊ธฐํ๊ณ ์ถ์ต๋๋ค. ๋ชจ๋ ๋ชจ๋ฐ์ผ ์ ํ๋ฆฌ์ผ์ด์
์ CI/CD๋ฅผ ๊ตฌํํ ๋ฐฉ๋ฒ, ๊ทธ ๋ชฉํ์ ๋๋ฌํ ๋ฐฉ๋ฒ ๋ฐ ์ต์ข
๊ฒฐ๊ณผ๋ ๋ฌด์์
๋๊น?
๋๊ตฌ์ ๋คํธ์ํฌ์๋ ์ด๋ฏธ ์ถฉ๋ถํ ์๋ฃ๊ฐ ์์ผ๋ฏ๋ก ์ฒ์์๋ ๋ถ์กฑํ๊ธฐ ๋๋ฌธ์ ์๋์ ์ผ๋ก ๋๊ตฌ์ ๋ํด ์์ธํ ์ค๋ช ํ์ง ์๊ณ ๋น์์ ๊ฐ์ง๊ณ ์๋ ๋ด์ฉ๋ง ์ธ๊ธํ๊ฒ ์ต๋๋ค.
๊ณต์ fastlane ๋ฌธ์ ๋ค๋ฅธ ํ์ฌ์ ์ฌ๋ก Fastlane์ ์ฌ์ฉํ์ฌ iOS ์ ํ๋ฆฌ์ผ์ด์ ์กฐ๋ฆฝ์ ์๋ํํฉ๋๋ค.
์ด ๊ธฐ์ฌ๋ ๋ ๋ถ๋ถ์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
- ์ฌ๋ด ๋ชจ๋ฐ์ผ CI/CD ๋ฑ์ฅ ๋ฐฐ๊ฒฝ
- N ์ ํ๋ฆฌ์ผ์ด์ ์ฉ CI/CD ์ถ์๋ฅผ ์ํ ๊ธฐ์ ์๋ฃจ์
์ฒซ ๋ฒ์งธ ๋ถ๋ถ์ ์๋ ์ ๋ํ ํฅ์๋ฅผ ๋ ๋ง์ด ๋ด๊ณ ์๊ณ , ๋ ๋ฒ์งธ ๋ถ๋ถ์ ์์ ์๊ฒ ์ ์ฉํ ์ ์๋ ๊ฒฝํ์ ๋๋ค.
์ญ์ฌ์ ์ผ๋ก ๊ทธ๋ฌ๋ค.
2015 ์ฐ๋
์ฐ๋ฆฌ๋ ๋ฐฉ๊ธ ๋ชจ๋ฐ์ผ ์ ํ๋ฆฌ์ผ์ด์
๊ฐ๋ฐ์ ์์ํ์ง๋ง ์ง์์ ์ธ ํตํฉ, DevOps ๋ฐ ๊ธฐํ ์ต์ ์ ํ์ ๋ํด ์๋ฌด๊ฒ๋ ๋ชฐ๋์ต๋๋ค. ๊ฐ ์ ํ๋ฆฌ์ผ์ด์
์
๋ฐ์ดํธ๋ ๊ฐ๋ฐ์๊ฐ ์์ ์ ์ปดํจํฐ์์ ์ง์ ์ถ์ํ์ต๋๋ค. Android์ ๊ฒฝ์ฐ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค. ์กฐ๋ฆฝ, ์๋ช
.apk
Google ๊ฐ๋ฐ์ ์ฝ์์ ์
๋ก๋ํ ๋ค์ iOS์ ๊ฒฝ์ฐ Xcode๋ฅผ ํตํ ๋ฐฐํฌ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ฆ๊ฑฐ์ด ์ ๋
์ ๋ณด๋์ต๋๋ค. ์์นด์ด๋ธ๋ฅผ ๋ค์ด๋ก๋ํ๋ ค๋ ์๋๋ ์ข
์ข
์ค๋ฅ๋ก ๋๋์ ๋ค์ ์๋ํด์ผ ํ์ต๋๋ค. ๊ฐ์ฅ ๋ฐ์ ๋ ๊ฐ๋ฐ์๋ ํ ๋ฌ์ ์ฌ๋ฌ ๋ฒ ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฒ์ด ์๋๋ผ ์ ํ๋ฆฌ์ผ์ด์
์ ์ถ์ํ๋ ๊ฒ์ผ๋ก ๋ํ๋ฌ์ต๋๋ค.
2016 ์ฐ๋
์ฐ๋ฆฌ๋ ์ฑ์ฅํ๊ณ , ๋ฆด๋ฆฌ์ค๋ฅผ ์ํด ํ๋ฃจ ์ข ์ผ ๊ฐ๋ฐ์๋ฅผ ํด๋ฐฉ์ํค๋ ๋ฐฉ๋ฒ์ ๋ํด ์ด๋ฏธ ์๊ฐํ๊ณ ์์๊ณ ๋ ๋ฒ์งธ ์ ํ๋ฆฌ์ผ์ด์ ๋ ๋ฑ์ฅํ์ฌ ์ฐ๋ฆฌ๋ฅผ ์๋ํ์ชฝ์ผ๋ก ๋ ๋ฐ์ด ๋ถ์์ต๋๋ค. ๊ฐ์ ํด์ ์ฐ๋ฆฌ๋ ์ฒ์์ผ๋ก Jenkins๋ฅผ ์ค์นํ๊ณ fastlane์ ๋ฌธ์์ ํ์๋ ๊ฒ๊ณผ ๋งค์ฐ ์ ์ฌํ ๋ฌด์์ด ์คํฌ๋ฆฝํธ๋ฅผ ๋ง์ด ์์ฑํ์ต๋๋ค.
$ xcodebuild clean archive -archivePath build/MyApp
-scheme MyApp
$ xcodebuild -exportArchive
-exportFormat ipa
-archivePath "build/MyApp.xcarchive"
-exportPath "build/MyApp.ipa"
-exportProvisioningProfile "ProvisioningProfileName"
$ cd /Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Versions/A/Support/
$ ./altool โupload-app
-f {abs path to your project}/build/{release scheme}.ipa
-u "[email protected]"
-p "PASS_APPLE_ID"
๋ถํํ๊ฒ๋ ์ง๊ธ๊น์ง๋ ์ฐ๋ฆฌ ๊ฐ๋ฐ์๋ค๋ง์ด ์ด๋ฌํ ์คํฌ๋ฆฝํธ๊ฐ ์ด๋ป๊ฒ ์๋ํ๋์ง, ์ ์ด ๋์๋ ํค ์คํ์ด ํ์ํ์ง ์๊ณ ์์์ผ๋ฉฐ, ๋ฌธ์ ๊ฐ ๋ค์ ๋ฐ์ํ๋ฉด ๋ก๊ทธ ๋ถ์์ ์ํด "๋ฉ์ง ์ ๋ "์ ๋ณด๋์ต๋๋ค.
2017 ์ฐ๋
์ฌํด ์ฐ๋ฆฌ๋ fastlane๊ณผ ๊ฐ์ ๊ฒ์ด ์๋ค๋ ๊ฒ์ ๋ฐฐ์ ์ต๋๋ค. ์ง๊ธ๋งํผ ์ ๋ณด๊ฐ ๋ง์ง ์์์ต๋๋ค. ์์ ๋ฐฉ๋ฒ, ์ฌ์ฉ ๋ฐฉ๋ฒ. ๊ทธ๋ฆฌ๊ณ ๊ทธ ๋น์ ๋๊ตฌ ์์ฒด๋ ์ฌ์ ํ ์กฐ์กํ์ต๋๋ค. ๋์์๋ ์ค๋ฅ๋ ์ฐ๋ฆฌ๋ฅผ ์ค๋ง์์ผฐ๊ณ ๊ทธ๋ค์ด ์ฝ์ํ ๋ง๋ฒ ๊ฐ์ ์๋ํ๋ฅผ ๋ฏฟ๊ธฐ ์ด๋ ค์ ์ต๋๋ค.
๊ทธ๋ฌ๋ fastlane ์ฝ์ด์ ํฌํจ๋ ์ฃผ์ ์ ํธ๋ฆฌํฐ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. gym
ะธ pilot
, ์ฐ๋ฆฌ๋ ๊ทธ๊ฒ์ ์์ํ ์์์์ต๋๋ค.
์ฐ๋ฆฌ์ ์คํฌ๋ฆฝํธ๊ฐ ์ฝ๊ฐ ๊ฐ์ ๋์์ต๋๋ค.
$ fastlane gym โ-workspace "Example.xcworkspace"
--scheme "AppName"
โ-buildlog_path "/tmp"
-โclean
ํ์ํ ๋ชจ๋ ๋งค๊ฐ ๋ณ์๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ๊ฐ์ ๋์์ต๋๋ค. xcodebuild
, ๋ค์์ ํ์ํด์ผ ํฉ๋๋ค. gym
์ด๋์ ๋ฌด์์ด ์๋์ง ๋
๋ฆฝ์ ์ผ๋ก ์ดํดํ ๊ฒ์
๋๋ค. ์ข ๋ ์ธ๋ถ์ ์ธ ์กฐ์ ์ ์ํด ๋ค์๊ณผ ๊ฐ์ ํค๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค. xcodebuild
, ํค ์ด๋ฆ๋ง ๋ ๋ช
ํํด์ก์ต๋๋ค.
์ด๋ฒ์๋ gym๊ณผ ๋ด์ฅ๋ xcpretty ํฌ๋งทํฐ ๋๋ถ์ ๋น๋ ๋ก๊ทธ๋ฅผ ํจ์ฌ ๋ ์ฝ๊ธฐ ์ฝ๊ฒ ๋ง๋ค์์ต๋๋ค. ์ด๋ก ์ธํด ๊นจ์ง ์ด์ ๋ธ๋ฆฌ๋ฅผ ์์ ํ๋ ๋ฐ ๋๋ ์๊ฐ์ด ์ ์ฝ๋๊ธฐ ์์ํ์ผ๋ฉฐ ๋๋ก๋ ๋ฆด๋ฆฌ์ค ํ์ด ์ค์ค๋ก ์์๋ผ ์๋ ์์์ต๋๋ค.
๋ถํํ๊ฒ๋ ์กฐ๋ฆฝ ์๋ ์ธก์ xcodebuild
ะธ gym
์ฐ๋ฆฌ๋ ๊ทธ๋ ๊ฒ ํ์ง ์์์ง๋ง ๋ฌธ์๋ฅผ ์ ๋ขฐํ ๊ฒ์
๋๋ค. ์๋๊ฐ ์ต๋ 30% ํฅ์๋ฉ๋๋ค.
๋ชจ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ ๋จ์ผ ํ๋ก์ธ์ค
2018๋ ๊ณผ ํ์ฌ
2018๋ ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๊ณ ์ถ์ํ๋ ํ๋ก์ธ์ค๊ฐ Jenkins๋ก ์์ ํ ์ด์ ๋์๊ณ ๊ฐ๋ฐ์๋ ๋จธ์ ์์ ๋ฆด๋ฆฌ์ค๋ฅผ ์ค๋จํ์ผ๋ฉฐ ๋ฆด๋ฆฌ์ค ํ๋ง์ด ๋ฆด๋ฆฌ์ค ๊ถํ์ ๊ฐ์ก์ต๋๋ค.
์ฐ๋ฆฌ๋ ์ด๋ฏธ ํ ์คํธ ๋ฐ ์ ์ ๋ถ์ ์คํ์ ๊ฐ์ ํ๊ณ ์ถ์๊ณ ์คํฌ๋ฆฝํธ๋ ๊ณ์ํด์ ์ฑ์ฅํ์ต๋๋ค. ์ฐ๋ฆฌ์ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ํจ๊ป ์ฑ์ฅํ๊ณ ๋ณํํ์ต๋๋ค. ๋น์ ์ ํ๋ฆฌ์ผ์ด์ ์ด 10๊ฐ ์ ๋ ์์๋๋ฐ, ํ๋ซํผ์ด 20๊ฐ ์๋ค๋ ์ ์ ๊ณ ๋ คํ๋ฉด '์ด์์๋' ์คํฌ๋ฆฝํธ๊ฐ XNUMX๊ฐ ์ ๋ ๋๋ค.
์คํฌ๋ฆฝํธ์ ์๋ก์ด ๋จ๊ณ๋ฅผ ์ถ๊ฐํ๊ณ ์ถ์ ๋๋ง๋ค ๋ชจ๋ ์ ธ ์คํฌ๋ฆฝํธ์ ํด๋น ๋ถ๋ถ์ ๋ณต์ฌํ์ฌ ๋ถ์ฌ๋ฃ์ด์ผ ํ์ต๋๋ค. ์๋ง๋ ์ฐ๋ฆฌ๋ ์ข ๋ ์ ์คํ๊ฒ ์์ ํ ์ ์์์ง๋ง ๊ทธ๋ฌํ ๋ณ๊ฒฝ ์ฌํญ์ ์ข ์ข ์คํ๋ก ๋๋์ ๋ฆด๋ฆฌ์ค ํ์ด ์คํฌ๋ฆฝํธ๋ฅผ ์์ ํ๊ณ ์ด๋ค ๋๋ํ ์ฌ๋์ด ์ด ๋ช ๋ น์ ์ถ๊ฐํ๋์ง, ์ค์ ๋ก ๋ฌด์์ ํ๋์ง ์์๋ด๋ ๋ฐ ์ ๋ ์๊ฐ์ด ๊ฑธ๋ ธ์ต๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ํ ํ๋ซํผ์ ์ด์ ๋ธ๋ฆฌ ์คํฌ๋ฆฝํธ๊ฐ ์ ์ด๋ ๋ค์ ์ ์ฌํ๋ค๊ณ ๋งํ ์๋ ์์ต๋๋ค. ๊ทธ๋ค์ ํ์คํ ๊ฐ์ ์ผ์ ํ์ง๋ง.
์๋ก์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ํ ํ๋ก์ธ์ค๋ฅผ ์์ํ๋ ค๋ฉด ์ด๋ฌํ ์คํฌ๋ฆฝํธ์ "์" ๋ฒ์ ์ ์ ํํ๊ณ ๋๋ฒ๊น ํ ํ "์, ์๋ํฉ๋๋ค"๋ผ๊ณ ๋งํ๋ ๋ฐ ํ๋ฃจ๊ฐ ์์๋์์ต๋๋ค.
2018๋ ์ฌ๋ฆ, ์ฐ๋ฆฌ๋ ๋ค์ ํ ๋ฒ ์ฌ์ ํ ๋ฐ์ ์ค์ธ fastlane์ ๋ฐ๋ผ๋ณด์์ต๋๋ค.
์์ #1: ๋ชจ๋ ์คํฌ๋ฆฝํธ ๋จ๊ณ๋ฅผ ์์ฝํ๊ณ Fastfile์ ๋ค์ ์์ฑํฉ๋๋ค.
์์ํ์ ๋ ์คํฌ๋ฆฝํธ๋ Jenkins์ ํ๋์ ์ ์คํฌ๋ฆฝํธ์ ์๋ ๋ชจ๋ ๋จ๊ณ์ ๋ชฉ๋ฐ๋ก ๊ตฌ์ฑ๋ ์ ๋ฐ์ฒ๋ผ ๋ณด์์ต๋๋ค. ์์ง ํ์ดํ๋ผ์ธ๊ณผ ๋จ๊ณ๋ณ ๋ถํ ๋ก ์ ํํ์ง ์์์ต๋๋ค.
์ฐ๋ฆฌ๋ ํ์ฌ ๊ฐ์ง๊ณ ์๋ ๊ฒ์ ์ดํด๋ณด๊ณ CI/CD ์ค๋ช ์ ๋ง๋ 4๊ฐ์ง ๋จ๊ณ๋ฅผ ์๋ณํ์ต๋๋ค.
- ๋น๋ - ์ข ์์ฑ ์ค์น, ์์นด์ด๋ธ ์กฐ๋ฆฝ,
- ํ ์คํธ โ ๊ฐ๋ฐ์ ๋จ์ ํ ์คํธ ์คํ, ์ ์ฉ ๋ฒ์ ๊ณ์ฐ,
- sonar - ๋ชจ๋ ๋ฆฐํฐ๋ฅผ ์คํํ๊ณ SonarQube์ ๋ณด๊ณ ์๋ฅผ ๋ณด๋ ๋๋ค.
- ๋ฐฐํฌ โ ์ํฐํฉํธ๋ฅผ ์ํ(TestFlight)๋ก ๋ณด๋ ๋๋ค.
์ธ๋ถ ์ฌํญ์ ๋ค๋ฃจ์ง ์๊ณ ์์ ์ ์ฌ์ฉ๋๋ ํค๋ฅผ ์๋ตํ๋ฉด ๋ค์ Fastfile์ ์ป๊ฒ ๋ฉ๋๋ค.
default_platform(:ios)
platform :ios do
before_all do
unlock
end
desc "Build stage"
lane :build do
match
prepare_build
gym
end
desc "Prepare build stage: carthage and cocoapods"
lane :prepare_build do
pathCartfile = ""
Dir.chdir("..") do
pathCartfile = File.join(Dir.pwd, "/Cartfile")
end
if File.exist?(pathCartfile)
carthage
end
pathPodfile = ""
Dir.chdir("..") do
pathPodfile = File.join(Dir.pwd, "/Podfile")
end
if File.exist?(pathPodfile)
cocoapods
end
end
desc "Test stage"
lane :test do
scan
xcov
end
desc "Sonar stage (after run test!)"
lane :run_sonar do
slather
lizard
swiftlint
sonar
end
desc "Deploy to testflight stage"
lane :deploy do
pilot
end
desc "Unlock keychain"
private_lane :unlock do
pass = ENV['KEYCHAIN_PASSWORD']
unlock_keychain(
password: pass
)
end
end
์ค์ ๋ก ์ฐ๋ฆฌ์ ์ฒซ ๋ฒ์งธ Fastfile์ ์ฌ์ ํ โโํ์ํ ๋ชฉ๋ฐ๊ณผ ๋์ฒดํ ๋งค๊ฐ๋ณ์์ ์๋ฅผ ๊ณ ๋ คํ ๋ ๊ดด๋ฌผ ๊ฐ์ ๊ฒ์ผ๋ก ๋ํ๋ฌ์ต๋๋ค.
lane :build do
carthage(
command: "update",
use_binaries: false,
platform: "ios",
cache_builds: true)
cocoapods(
clean: true,
podfile: "./Podfile",
use_bundle_exec: false)
gym(
workspace: "MyApp.xcworkspace",
configuration: "Release",
scheme: "MyApp",
clean: true,
output_directory: "/build",
output_name: "my-app.ipa")
end
lane :deploy do
pilot(
username: "[email protected]",
app_identifier: "com.example.app",
dev_portal_team_id: "TEAM_ID_NUMBER_DEV",
team_id: "ITS_TEAM_ID")
end
์์ ์์์๋ ๋งค๊ฐ๋ณ์ ์ค ์ผ๋ถ๋ง ์ง์ ํด์ผ ํฉ๋๋ค. ์ด๋ ๋น๋ ๋งค๊ฐ๋ณ์(์คํค๋ง, ๊ตฌ์ฑ, ํ๋ก๋น์ ๋ ํ๋กํ ์ด๋ฆ) ๋ฐ ๋ฐฐํฌ ๋งค๊ฐ๋ณ์(๊ฐ๋ฐ์ ๊ณ์ ์ Apple ID, ๋น๋ฐ๋ฒํธ, ์ ํ๋ฆฌ์ผ์ด์
ID ๋ฑ)์
๋๋ค. ์. ์ฒซ ๋ฒ์งธ ๊ทผ์ฌ์น๋ก ์ฐ๋ฆฌ๋ ์ด๋ฌํ ๋ชจ๋ ํค๋ฅผ ํน์ ํ์ผ์ ๋ฃ์ต๋๋ค. Gymfile
, Matchfile
ะธ Appfile
.
์ด์ Jenkins์์๋ ๋ณด๊ธฐ๋ฅผ ํ๋ฆฌ๊ฒ ํ์ง ์๊ณ ๋์ผ๋ก ์ฝ๊ฒ ์ฝ์ ์ ์๋ ์งง์ ๋ช ๋ น์ ํธ์ถํ ์ ์์ต๋๋ค.
# fastlane ios <lane_name>
$ fastlane ios build
$ fastlane ios test
$ fastlane ios run_sonar
$ fastlane ios deploy
๋ง์ธ, ์ฐ๋ฆฌ๋ ํ๋ฅญํด์
๋ฌด์์ ์ป์๋์? ๋ชจ๋ ๋จ๊ณ์ ๋ํ ๋ช ๋ น์ ์ง์๋๋ค. fastlane ํ์ผ์ ๊น๋ํ๊ฒ ์ ๋ฆฌ๋ ์คํฌ๋ฆฝํธ ์ ๋ฆฌ. ๊ธฐ๋ปํ๋ฉด์ ์ฐ๋ฆฌ๋ ๊ฐ๋ฐ์๋ค์๊ฒ ๋ฌ๋ ค๊ฐ์ ์ ์ฅ์์ ํ์ํ ๋ชจ๋ ๊ฒ์ ์ถ๊ฐํด ๋ฌ๋ผ๊ณ ์์ฒญํ์ต๋๋ค.
๊ทธ๋ฌ๋ ์ฐ๋ฆฌ๋ ๊ฐ์ ์ด๋ ค์์ ์ง๋ฉดํ๊ฒ ๋ ๊ฒ์ด๋ผ๋ ๊ฒ์ ์๊ฐ์ด ์ง๋๋ฉด์ ๊นจ๋ฌ์์ต๋๋ค. ์ด๋ค ์์ผ๋ก๋ ์์ ์ ์ถ์ ์์ํ๋ 20๊ฐ์ ์ด์ ๋ธ๋ฆฌ ์คํฌ๋ฆฝํธ๊ฐ ์ฌ์ ํ ๋จ์ ์์ ๊ฒ์ด๊ณ , ์คํฌ๋ฆฝํธ๊ฐ ๋ฆฌํฌ์งํ ๋ฆฌ๋ก ์ด๋ํ๊ธฐ ๋๋ฌธ์ ํธ์งํ๊ธฐ๊ฐ ๋ ์ด๋ ค์ธ ๊ฒ์ ๋๋ค. ์ฐ๋ฆฌ๋ ๊ฑฐ๊ธฐ์ ์ ๊ทผํ ์ ์์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ผ๋ฐ์ ์ผ๋ก ์ด๋ฐ ์์ผ๋ก ์ฐ๋ฆฌ์ ๊ณ ํต์ ํด๊ฒฐํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํฉ๋๋ค.
์์ #2: N๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ํ ๋จ์ผ Fastfile ๊ฐ์ ธ์ค๊ธฐ
์ด์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ฒ์ด ๊ทธ๋ฆฌ ์ด๋ ต์ง ์์ ๊ฒ ๊ฐ์ต๋๋ค. ๋ณ์๋ฅผ ์ค์ ํ๊ณ ์งํํด ๋ณด๊ฒ ์ต๋๋ค. ๋ค, ์ฌ์ค ๊ทธ๋ ๊ฒ ํด์ ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์ด์. ๊ทธ๋ฌ๋ ์ฐ๋ฆฌ๊ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์๊ฐ ์ฐ๋ฆฌ๋ fastlane ์์ฒด์ ๋ํ ์ ๋ฌธ ์ง์๋, fastlane์ด ์์ฑ๋ Ruby์ ๋ํ ์ ๋ฌธ ์ง์๋, ๋คํธ์ํฌ์ ๋ํ ์ ์ฉํ ์์ ๋ ์์์ต๋๋ค. ๋น์ fastlane์ ๋ํด ์ด ๋ชจ๋ ์ฌ๋์ ํ๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ํ ์์ ๋ก ์ ํ๋์์ต๋๋ค. ๊ฐ๋ฐ์ ํ ๋ช .
Fastlane์ ํ๊ฒฝ ๋ณ์๋ฅผ ์ฒ๋ฆฌํ ์ ์์ผ๋ฉฐ ์ฐ๋ฆฌ๋ ์ด๋ฏธ ํค์ฒด์ธ ๋น๋ฐ๋ฒํธ๋ฅผ ์ค์ ํ์ฌ ์ด๋ฅผ ์๋ํ์ต๋๋ค.
ENV['KEYCHAIN_PASSWORD']
์คํฌ๋ฆฝํธ๋ฅผ ์ดํด๋ณธ ํ ๊ณตํต ๋ถ๋ถ์ ์๋ณํ์ต๋๋ค.
#for build, test and deploy
APPLICATION_SCHEME_NAME=appScheme
APPLICATION_PROJECT_NAME=app.xcodeproj
APPLICATION_WORKSPACE_NAME=app.xcworkspace
APPLICATION_NAME=appName
OUTPUT_IPA_NAME=appName.ipa
#app info
APP_BUNDLE_IDENTIFIER=com.example.appName
[email protected]
TEAM_ID=ABCD1234
FASTLANE_ITC_TEAM_ID=123456789
์ด์ fastlane ํ์ผ์์ ์ด๋ฌํ ํค๋ฅผ ์ฌ์ฉํ๊ธฐ ์์ํ๋ ค๋ฉด ํด๋น ํค๋ฅผ ๊ฑฐ๊ธฐ์ ์ ๋ฌํ๋ ๋ฐฉ๋ฒ์ ์์๋ด์ผ ํ์ต๋๋ค. Fastlane์ ์ด์ ๋ํ ์๋ฃจ์
์ ์ ๊ณตํฉ๋๋ค: .env
, .env.default
, .env.development
.
๊ทธ๋ฆฌ๊ณ ์ฐ๋ฆฌ๋ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์กฐ๊ธ ๋ค๋ฅด๊ฒ ์ฌ์ฉํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค. fastlane ์คํฌ๋ฆฝํธ์ ๋ฉํ ์ ๋ณด๊ฐ ์๋ ํ์ผ์ ์๋ ์ด ์ ํ๋ฆฌ์ผ์ด์
์ ๊ณ ์ ํค๋ฅผ ๊ฐ๋ฐ์ ์ ์ฅ์์ ์ ์ฅํด ๋ณด๊ฒ ์ต๋๋ค. .env.appName
.
๊ทธ๋ค ์์ Fastfile
, Appfile
, Matchfile
ะธ Gymfile
, ๋ณ๋์ ์ ์ฅ์์ ์จ๊ฒผ์ต๋๋ค. ๋ค๋ฅธ ์๋น์ค์ ๋น๋ฐ๋ฒํธ ํค๊ฐ ํฌํจ๋ ์ถ๊ฐ ํ์ผ์ด ์จ๊ฒจ์ ธ ์์ต๋๋ค. .env
.
์๋ฅผ ๋ณผ ์ ์์ต๋๋ค
CI์์๋ ํธ์ถ์ด ํฌ๊ฒ ๋ณ๊ฒฝ๋์ง ์์์ผ๋ฉฐ ํน์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ํ ๊ตฌ์ฑ ํค๊ฐ ์ถ๊ฐ๋์์ต๋๋ค.
# fastlane ios <lane_name> --env appName
$ fastlane ios build --env appName
$ fastlane ios test --env appName
$ fastlane ios run_sonar --env appName
$ fastlane ios deploy --env appName
๋ช ๋ น์ ์คํํ๊ธฐ ์ ์ ์คํฌ๋ฆฝํธ๋ก ์ ์ฅ์๋ฅผ ๋ก๋ํฉ๋๋ค. ๊ทธ๋ค์ง ์ข์ ๋ณด์ด์ง๋ ์์ต๋๋ค.
git clone [email protected]/FastlaneCICD.git fastlane_temp
cp ./fastlane_temp/fastlane/* ./fastlane/
cp ./fastlane_temp/fastlane/.env fastlane/.env
Fastlane์๋ ๋ค์์ ํตํด Fastfile์ ๋ค์ด๋ก๋ํ ์ ์๋ ์๋ฃจ์
์ด ์์ง๋ง ์ง๊ธ์ ์ด ์๋ฃจ์
์ ๊ทธ๋๋ก ๋ก๋๋ค. import_from_git
, ๊ทธ๋ฌ๋ Fastfile์์๋ง ์๋ํ๊ณ ๋ค๋ฅธ ํ์ผ์์๋ ์๋ํ์ง ์์ต๋๋ค. "์ ๋ง ์๋ฆ๋ต์ต๋๋ค"๋ฅผ ์ํ๋ค๋ฉด ์ง์ ์ธ ์ ์์ต๋๋ค action
.
Android ์ ํ๋ฆฌ์ผ์ด์
๋ฐ ReactNative์ ๋ํด ์ ์ฌํ ์ธํธ๊ฐ ๋ง๋ค์ด์ก์ผ๋ฉฐ ํ์ผ์ ๋์ผํ ์ ์ฅ์์ ์์ง๋ง ๋ค๋ฅธ ๋ถ๊ธฐ์ ์์ต๋๋ค. iOS
, android
ะธ react_native
.
๋ฆด๋ฆฌ์ค ํ์ด ์๋ก์ด ๋จ๊ณ๋ฅผ ์ถ๊ฐํ๋ ค๊ณ ํ ๋ ์คํฌ๋ฆฝํธ์ ๋ณ๊ฒฝ ์ฌํญ์ git์ MR์ ํตํด ๊ธฐ๋ก๋๋ฏ๋ก ๋ ์ด์ ์์๋ ์คํฌ๋ฆฝํธ์ ์์ธ์ ์ฐพ์ ํ์๊ฐ ์์ผ๋ฉฐ ์ผ๋ฐ์ ์ผ๋ก ์ด์ ์ด๋ฅผ ๊นจ๋ ค๊ณ ์๋ํด์ผ ํฉ๋๋ค.
์ด์ ๊ทธ๊ฒ ํ์คํด
์ด์ ์๋ ๋ชจ๋ ์คํฌ๋ฆฝํธ๋ฅผ ์ ์ง ๊ด๋ฆฌํ๊ณ , ์ ๋ฐ์ดํธํ๊ณ , ์ ๋ฐ์ดํธ์ ๋ชจ๋ ๊ฒฐ๊ณผ๋ฅผ ์์ ํ๋ ๋ฐ ์๊ฐ์ ๋ณด๋์ต๋๋ค. ๋ฆด๋ฆฌ์ค ์ค๋ฅ์ ๋ค์ดํ์์ ์์ธ์ด ๋ค์ฃฝ๋ฐ์ฃฝ๋ ์ ์คํฌ๋ฆฝํธ์์ ์ถ์ ํ๊ธฐ๊ฐ ๋๋ฌด ์ด๋ ค์ด ๋จ์ํ ์คํ์์ ๋ ๋งค์ฐ ์ค๋ง์ค๋ฌ์ ์ต๋๋ค. ์ด์ ์ด๋ฌํ ์ค๋ฅ๊ฐ ์ต์ํ๋์์ต๋๋ค. ๋ณ๊ฒฝ ์ฌํญ์ ๋ชจ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋์์ ์ ์ฉ๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ๋ก์ธ์ค์ ์ถ๊ฐํ๋ ๋ฐ 15๋ถ์ด ๊ฑธ๋ฆฝ๋๋ค. CI์ ํ ํ๋ฆฟ ํ์ดํ๋ผ์ธ์ ์ค์ ํ๊ณ ๊ฐ๋ฐ์ ์ ์ฅ์์ ํค๋ฅผ ์ถ๊ฐํฉ๋๋ค.
Android์ฉ Fastfile๊ณผ ์ ํ๋ฆฌ์ผ์ด์
์๋ช
์ ๋ํ ์์ ์ ์ฌ์ ํ โโ์ค๋ช
๋์ง ์์ ๊ฒ ๊ฐ์ต๋๋ค. ๊ธฐ์ฌ๊ฐ ํฅ๋ฏธ๋ก์ฐ๋ฉด ๊ณ์ ์์ฑํ๊ฒ ์ต๋๋ค. ๋๊ธ์ด๋ ํ
๋ ๊ทธ๋จ์์ "์ด ๋ฌธ์ ๋ฅผ ์ด๋ป๊ฒ ํด๊ฒฐํ์๊ฒ ์ต๋๊น?"์ ๋ํ ์ง๋ฌธ์ด๋ ์ ์์ ๋ณด๊ณ ๊ธฐ์๊ฒ ์๊ฐํฉ๋๋ค.
์ถ์ฒ : habr.com