ประสบการณ์ CICD บนมือถือ: มาตรฐาน fastlane หนึ่งเดียวสำหรับแอปพลิเคชันมือถือจำนวนมาก

ประสบการณ์ CICD บนมือถือ: มาตรฐาน fastlane หนึ่งเดียวสำหรับแอปพลิเคชันมือถือจำนวนมาก
ฉันต้องการพูดคุยเกี่ยวกับการบูรณาการอย่างต่อเนื่องและการส่งมอบแอปมือถือที่ใช้ fastlane วิธีที่เราใช้ CI/CD บนแอปพลิเคชันบนมือถือทั้งหมด เราไปถึงจุดนั้นได้อย่างไร และเกิดอะไรขึ้นในท้ายที่สุด

มีเนื้อหาเพียงพอบนเครือข่ายของเครื่องมือซึ่งเราขาดไปตั้งแต่เริ่มต้น ดังนั้นฉันจะไม่อธิบายเครื่องมืออย่างละเอียดโดยเจตนา แต่จะอ้างถึงสิ่งที่เรามีในขณะนั้นเท่านั้น:

บทความนี้ประกอบด้วยสองส่วน:

  • ความเป็นมาของการเกิดขึ้นของ 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 สคริปต์ที่จะเริ่มต้นใช้ชีวิตของตัวเองไม่ทางใดก็ทางหนึ่ง มันจะยากกว่าที่จะแก้ไขเนื่องจากสคริปต์จะย้ายไปยังที่เก็บ และเราไม่สามารถเข้าไปที่นั่นได้ และโดยทั่วไปแล้ว จะไม่สามารถแก้ไขความเจ็บปวดของเราด้วยวิธีนี้ได้

ประสบการณ์ CICD บนมือถือ: มาตรฐาน fastlane หนึ่งเดียวสำหรับแอปพลิเคชันมือถือจำนวนมาก

งาน #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 มีวิธีแก้ปัญหาสำหรับสิ่งนี้: กำลังโหลดตัวแปรผ่าน dotenv. เอกสารระบุว่าหากคุณจำเป็นต้องโหลดคีย์เพื่อวัตถุประสงค์ที่แตกต่างกัน ให้สร้างไฟล์การกำหนดค่าหลายไฟล์ในไดเร็กทอรี fastlane .env, .env.default, .env.development.

จากนั้นเราก็ตัดสินใจใช้ห้องสมุดนี้แตกต่างออกไปเล็กน้อย เรามาวางในที่เก็บของนักพัฒนา ไม่ใช่สคริปต์ fastlane และข้อมูลเมตาของมัน แต่เป็นคีย์เฉพาะของแอปพลิเคชันนี้ในไฟล์ .env.appName.

ตัวเอง Fastfile, Appfile, Matchfile и Gymfileเราซ่อนมันไว้ในที่เก็บแยกต่างหาก ไฟล์เพิ่มเติมพร้อมรหัสรหัสผ่านจากบริการอื่นถูกซ่อนอยู่ที่นั่น - .env.
คุณสามารถดูตัวอย่างได้ ที่นี่.

ประสบการณ์ CICD บนมือถือ: มาตรฐาน fastlane หนึ่งเดียวสำหรับแอปพลิเคชันมือถือจำนวนมาก

บน 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

เพิ่มความคิดเห็น