ฉันต้องการพูดคุยเกี่ยวกับการบูรณาการอย่างต่อเนื่องและการส่งมอบแอปมือถือที่ใช้ fastlane วิธีที่เราใช้ CI/CD บนแอปพลิเคชันบนมือถือทั้งหมด เราไปถึงจุดนั้นได้อย่างไร และเกิดอะไรขึ้นในท้ายที่สุด
มีเนื้อหาเพียงพอบนเครือข่ายของเครื่องมือซึ่งเราขาดไปตั้งแต่เริ่มต้น ดังนั้นฉันจะไม่อธิบายเครื่องมืออย่างละเอียดโดยเจตนา แต่จะอ้างถึงสิ่งที่เรามีในขณะนั้นเท่านั้น:
เอกสาร fastlane อย่างเป็นทางการ ตัวอย่างของบริษัทอื่นๆ เราทำให้การประกอบแอปพลิเคชัน iOS เป็นแบบอัตโนมัติโดยใช้ Fastlane
บทความนี้ประกอบด้วยสองส่วน:
- ความเป็นมาของการเกิดขึ้นของ CI/CD แบบเคลื่อนที่ในบริษัท
- โซลูชันทางเทคนิคสำหรับการเปิดตัว CI/CD สำหรับแอปพลิเคชัน N
ส่วนแรกเป็นการหวนคิดถึงวันเก่าๆ มากขึ้น และส่วนที่สองคือประสบการณ์ที่คุณสามารถนำไปใช้กับตัวเองได้
นี่คือสิ่งที่เกิดขึ้นในอดีต
ปีที่ 2015
เราเพิ่งเริ่มพัฒนาแอปพลิเคชันบนมือถือ จากนั้นเราไม่รู้อะไรเลยเกี่ยวกับการบูรณาการอย่างต่อเนื่อง เกี่ยวกับ DevOps และสิ่งที่ทันสมัยอื่นๆ การอัปเดตแอปพลิเคชันแต่ละครั้งดำเนินการโดยนักพัฒนาเองจากเครื่องของเขา และถ้าสำหรับ Android มันค่อนข้างง่าย - ประกอบและลงนาม .apk
และอัปโหลดไปยัง Google Developer Console จากนั้นสำหรับ 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 ได้แก่ gym
и pilot
เราก็สามารถเริ่มต้นมันได้
สคริปต์ของเราได้รับการปรับปรุงเล็กน้อย
$ fastlane gym —-workspace "Example.xcworkspace"
--scheme "AppName"
—-buildlog_path "/tmp"
-—clean
ได้รับการปรับปรุงให้ดีขึ้นหากเพียงเพราะไม่ใช่พารามิเตอร์ทั้งหมดที่จำเป็นสำหรับ xcodebuild
คุณต้องระบุ - gym
จะเข้าใจอย่างเป็นอิสระว่าอยู่ที่ไหนและอะไรอยู่ และเพื่อการปรับแต่งที่ละเอียดยิ่งขึ้น คุณสามารถระบุคีย์เดียวกับในได้ xcodebuild
มีเพียงการตั้งชื่อคีย์เท่านั้นที่ชัดเจนยิ่งขึ้น
ครั้งนี้ ต้องขอบคุณยิมและฟอร์แมตเตอร์ xcpretty ในตัว บันทึกการสร้างจึงอ่านได้ง่ายขึ้นมาก ซึ่งเริ่มช่วยประหยัดเวลาในการซ่อมแซมส่วนประกอบที่เสียหาย และบางครั้งทีมปล่อยอาจแก้ไขปัญหาได้ด้วยตนเอง
น่าเสียดายที่การวัดความเร็วการประกอบ xcodebuild
и gym
เราไม่ได้ทำ แต่เราจะเชื่อถือเอกสารประกอบ - เร่งความเร็วได้ถึง 30%
กระบวนการเดียวสำหรับทุกแอปพลิเคชัน
ปี 2018 และปัจจุบัน
ภายในปี 2018 กระบวนการสร้างและเปิดตัวแอปพลิเคชันได้ย้ายไปยัง Jenkins โดยสมบูรณ์ นักพัฒนาหยุดการเผยแพร่จากเครื่องของตน และมีเพียงทีมเผยแพร่เท่านั้นที่มีสิทธิ์เผยแพร่
เราต้องการปรับปรุงการเปิดตัวการทดสอบและการวิเคราะห์แบบคงที่อยู่แล้ว และสคริปต์ของเราก็เติบโตขึ้นเรื่อยๆ เติบโตและเปลี่ยนแปลงไปพร้อมกับแอปพลิเคชันของเรา ในเวลานั้นมีแอปพลิเคชันประมาณ 10 แอปพลิเคชัน เมื่อพิจารณาว่าเรามีสองแพลตฟอร์ม นั่นคือสคริปต์ “ที่ใช้งานอยู่” ประมาณ 20 สคริปต์
ทุกครั้งที่เราต้องการเพิ่มขั้นตอนใหม่ให้กับสคริปต์ เราต้องคัดลอกและวางส่วนต่างๆ ลงในเชลล์สคริปต์ทั้งหมด บางทีเราอาจทำงานอย่างระมัดระวังมากขึ้น แต่บ่อยครั้งที่การเปลี่ยนแปลงดังกล่าวจบลงด้วยการพิมพ์ผิด ซึ่งกลายเป็นช่วงเย็นที่ทีมเผยแพร่ต้องแก้ไขสคริปต์และค้นหาว่าคนฉลาดคนไหนที่เพิ่มคำสั่งนี้และทำหน้าที่อะไรจริงๆ โดยทั่วไปไม่สามารถพูดได้ว่าสคริปต์สำหรับการประกอบสำหรับแพลตฟอร์มเดียวอย่างน้อยก็ค่อนข้างคล้ายกัน แม้ว่าพวกเขาจะทำสิ่งเดียวกันอย่างแน่นอน
ในการเริ่มกระบวนการสำหรับแอปพลิเคชันใหม่ ต้องใช้เวลาหนึ่งวันในการเลือกเวอร์ชัน "ใหม่" ของสคริปต์เหล่านี้ แก้ไขข้อบกพร่อง และบอกว่า "ใช่ ใช้งานได้"
ในฤดูร้อนปี 2018 เราได้มองไปยังช่องทางด่วนที่ยังคงพัฒนาอยู่อีกครั้ง
งาน #1: สรุปขั้นตอนสคริปต์ทั้งหมดและเขียนใหม่ใน Fastfile
เมื่อเราเริ่มต้น สคริปต์ของเราดูเหมือนผ้าเช็ดเท้าที่ประกอบด้วยขั้นตอนและไม้ค้ำยันทั้งหมดในเชลล์สคริปต์ใน Jenkins เรายังไม่ได้เปลี่ยนมาใช้ไปป์ไลน์และแบ่งตามขั้นตอน
เราพิจารณาสิ่งที่เรามีและระบุ 4 ขั้นตอนที่เหมาะสมกับคำอธิบายของ CI/CD ของเรา:
- สร้าง - การติดตั้งการพึ่งพา, การประกอบไฟล์เก็บถาวร,
- ทดสอบ — รันการทดสอบหน่วยของนักพัฒนา คำนวณความครอบคลุม
- โซนาร์ - เปิดตัว linters ทั้งหมดและส่งรายงานไปยัง 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 ของบัญชีนักพัฒนา รหัสผ่าน รหัสแอปพลิเคชัน และอื่นๆ บน. ในการประมาณครั้งแรก เราใส่คีย์เหล่านี้ทั้งหมดไว้ในไฟล์พิเศษ - Gymfile
, Matchfile
и Appfile
.
ขณะนี้ใน Jenkins คุณสามารถเรียกใช้คำสั่งสั้นๆ ที่ไม่เบลอมุมมองและอ่านได้ด้วยตาเปล่า:
# fastlane ios <lane_name>
$ fastlane ios build
$ fastlane ios test
$ fastlane ios run_sonar
$ fastlane ios deploy
ไชโย เราเก่งนะ
คุณได้อะไร? เคลียร์คำสั่งทุกขั้นตอน ทำความสะอาดสคริปต์ จัดเรียงอย่างเรียบร้อยในไฟล์ช่องทางด่วน เราดีใจมากที่รีบไปหานักพัฒนาเพื่อขอให้พวกเขาเพิ่มทุกสิ่งที่จำเป็นลงในคลังของพวกเขา
แต่ทันเวลาเราก็ตระหนักได้ว่าเราจะเผชิญกับความยากลำบากแบบเดียวกัน - เราจะยังคงมีสคริปต์แอสเซมบลี 20 สคริปต์ที่จะเริ่มต้นใช้ชีวิตของตัวเองไม่ทางใดก็ทางหนึ่ง มันจะยากกว่าที่จะแก้ไขเนื่องจากสคริปต์จะย้ายไปยังที่เก็บ และเราไม่สามารถเข้าไปที่นั่นได้ และโดยทั่วไปแล้ว จะไม่สามารถแก้ไขความเจ็บปวดของเราด้วยวิธีนี้ได้
งาน #2: รับ Fastfile เพียงไฟล์เดียวสำหรับแอปพลิเคชัน N
ตอนนี้ดูเหมือนว่าการแก้ปัญหาไม่ใช่เรื่องยาก - ตั้งค่าตัวแปรแล้วไปกันเลย ใช่ ที่จริงแล้ว นั่นคือวิธีแก้ปัญหา แต่ในขณะที่เราทำพัง เราไม่มีความเชี่ยวชาญใน fastlane เองหรือใน Ruby ซึ่งเขียน fastlane หรือตัวอย่างที่เป็นประโยชน์บนเครือข่าย - ทุกคนที่เขียนเกี่ยวกับ 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
.
เมื่อทีมเผยแพร่ต้องการเพิ่มขั้นตอนใหม่ การเปลี่ยนแปลงในสคริปต์จะถูกบันทึกผ่าน MR ใน git ไม่จำเป็นต้องค้นหาสาเหตุของสคริปต์ที่เสียหายอีกต่อไป และโดยทั่วไป ตอนนี้คุณต้องพยายามทำลายมัน
ตอนนี้มันแน่นอนแล้ว
ก่อนหน้านี้ เราใช้เวลาดูแลรักษาสคริปต์ทั้งหมด อัปเดตและแก้ไขผลที่ตามมาทั้งหมดของการอัปเดต เป็นเรื่องที่น่าผิดหวังมากเมื่อสาเหตุของข้อผิดพลาดและการหยุดทำงานในการเผยแพร่นั้นเกิดจากการพิมพ์ผิดธรรมดาๆ ซึ่งยากต่อการติดตามในเชลล์สคริปต์ที่สับสนวุ่นวาย ตอนนี้ข้อผิดพลาดดังกล่าวลดลงเหลือน้อยที่สุด การเปลี่ยนแปลงจะมีผลกับแอปพลิเคชันทั้งหมดในคราวเดียว และจะใช้เวลา 15 นาทีในการนำแอปพลิเคชันใหม่เข้าสู่กระบวนการ - ตั้งค่าไปป์ไลน์เทมเพลตบน CI และเพิ่มคีย์ไปยังพื้นที่เก็บข้อมูลของนักพัฒนา
ดูเหมือนว่าจุดที่มี Fastfile สำหรับ Android และลายเซ็นของแอปพลิเคชันยังคงไม่สามารถอธิบายได้ หากบทความน่าสนใจ ฉันจะเขียนต่อ ฉันยินดีที่จะเห็นคำถามหรือข้อเสนอแนะของคุณ "คุณจะแก้ไขปัญหานี้อย่างไร" ในความคิดเห็นหรือทางโทรเลข
ที่มา: will.com