Trải nghiệm CICD di động: một tiêu chuẩn fastlane cho nhiều ứng dụng di động

Trải nghiệm CICD di động: một tiêu chuẩn fastlane cho nhiều ứng dụng di động
Tôi muốn nói về việc tích hợp và phân phối liên tục cho các ứng dụng dành cho thiết bị di động sử dụng fastlane. Cách chúng tôi triển khai CI/CD trên tất cả các ứng dụng di động, cách chúng tôi đạt được điều đó và cuối cùng điều gì đã xảy ra.

Trên mạng đã có đủ tài liệu về công cụ mà chúng tôi rất thiếu khi bắt đầu, vì vậy tôi sẽ cố tình không mô tả chi tiết về công cụ này mà chỉ đề cập đến những gì chúng tôi có khi đó:

Bài viết gồm có hai phần:

  • Bối cảnh cho sự xuất hiện của CI/CD di động trong công ty
  • Giải pháp kỹ thuật triển khai CI/CD cho ứng dụng N

Phần đầu là hoài niệm về ngày xưa nhiều hơn, phần thứ hai là trải nghiệm mà bạn có thể áp dụng cho chính mình.

Đó là cách nó đã xảy ra trong lịch sử

Năm 2015

Chúng tôi mới bắt đầu phát triển các ứng dụng di động, sau đó chúng tôi chưa biết gì về tích hợp liên tục, về DevOps và những thứ thời thượng khác. Mỗi bản cập nhật ứng dụng đều do chính nhà phát triển triển khai từ máy của mình. Và nếu dành cho Android thì khá đơn giản - lắp ráp, ký tên .apk và tải nó lên Google Developer Console, sau đó đối với iOS, công cụ phân phối qua Xcode đã mang lại cho chúng tôi những buổi tối tuyệt vời - những nỗ lực tải xuống kho lưu trữ thường kết thúc bằng lỗi và chúng tôi phải thử lại. Hóa ra nhà phát triển tiên tiến nhất không viết mã vài lần trong tháng mà phát hành ứng dụng.

Năm 2016

Chúng tôi lớn lên, chúng tôi đã có những suy nghĩ về cách giúp các nhà phát triển rảnh rỗi cả ngày để phát hành và một ứng dụng thứ hai cũng xuất hiện, điều này chỉ thúc đẩy chúng tôi hướng tới tự động hóa nhiều hơn. Cùng năm đó, chúng tôi cài đặt Jenkins lần đầu tiên và viết một loạt các đoạn mã đáng sợ, rất giống với những đoạn mã mà fastlane trình bày trong tài liệu của nó.

$ 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"

Thật không may, cho đến nay chỉ có các nhà phát triển của chúng tôi mới biết cách hoạt động của các tập lệnh này và lý do tại sao cần có kho khóa vô tận này và khi có sự cố xảy ra lần nữa, họ đã có được “những buổi tối tuyệt đẹp” để phân tích nhật ký.

Năm 2017

Năm nay chúng tôi đã biết được rằng có một thứ gọi là fastlane. Không có nhiều thông tin như bây giờ - làm thế nào để bắt đầu, làm thế nào để sử dụng nó. Và bản thân công cụ này vẫn còn thô sơ vào thời điểm đó: các lỗi liên tục chỉ khiến chúng tôi thất vọng và thật khó tin vào khả năng tự động hóa kỳ diệu mà họ đã hứa.

Tuy nhiên, các tiện ích chính có trong lõi fastlane là gym и pilot, chúng tôi đã bắt đầu được nó.

Kịch bản của chúng tôi đã được cải thiện một chút.

$ fastlane gym  —-workspace "Example.xcworkspace" 
                --scheme "AppName" 
                —-buildlog_path "/tmp" 
                -—clean

Chúng đã được cải tiến, dù chỉ vì không phải tất cả các thông số cần thiết cho xcodebuild, bạn cần chỉ ra - gym sẽ độc lập hiểu ở đâu và những gì nằm. Và để tinh chỉnh hơn, bạn có thể chỉ định các phím tương tự như trong xcodebuild, chỉ có cách đặt tên của các phím là rõ ràng hơn.

Lần này, nhờ có gym và trình định dạng xcpretty tích hợp sẵn, nhật ký xây dựng đã trở nên dễ đọc hơn nhiều. Điều này bắt đầu tiết kiệm thời gian trong việc sửa chữa các cụm bị hỏng và đôi khi nhóm phát hành có thể tự mình tìm ra cách.

Thật không may, việc đo tốc độ lắp ráp xcodebuild и gym Chúng tôi đã không làm điều đó, nhưng chúng tôi sẽ tin tưởng vào tài liệu - tăng tốc lên tới 30%.

Quy trình duy nhất cho tất cả các ứng dụng

Năm 2018 và hiện tại

Đến năm 2018, quá trình xây dựng và triển khai ứng dụng hoàn toàn chuyển sang Jenkins, các nhà phát triển đã ngừng phát hành từ máy của họ và chỉ có nhóm phát hành mới có quyền phát hành.

Chúng tôi đã muốn cải thiện việc khởi chạy các thử nghiệm và phân tích tĩnh, đồng thời các tập lệnh của chúng tôi ngày càng phát triển. Phát triển và thay đổi cùng với các ứng dụng của chúng tôi. Vào thời điểm đó có khoảng 10 ứng dụng, vì chúng tôi có hai nền tảng nên có khoảng 20 tập lệnh “sống”.

Mỗi lần chúng tôi muốn thêm một bước mới vào tập lệnh, chúng tôi phải sao chép-dán các phần đó vào tất cả các tập lệnh shell. Có lẽ chúng tôi đã có thể làm việc cẩn thận hơn, nhưng những thay đổi như vậy thường kết thúc bằng lỗi chính tả, khiến nhóm phát hành phải mất cả buổi tối để sửa tập lệnh và tìm ra người thông minh nào đã thêm lệnh này và chức năng thực sự của nó. Nói chung, không thể nói rằng các tập lệnh lắp ráp cho một nền tảng ít nhất có phần giống nhau. Mặc dù họ chắc chắn đã làm điều tương tự.

Để bắt đầu quy trình cho một ứng dụng mới, cần phải dành một ngày để chọn phiên bản “mới” của các tập lệnh này, gỡ lỗi nó và nói rằng “vâng, nó hoạt động”.

Vào mùa hè năm 2018, chúng tôi một lần nữa hướng tới đường chạy nhanh vẫn đang phát triển.

Nhiệm vụ số 1: tóm tắt tất cả các bước của tập lệnh và viết lại chúng trong Fastfile

Khi chúng tôi bắt đầu, các tập lệnh của chúng tôi trông giống như một tấm khăn lau chân bao gồm tất cả các bước và chiếc nạng trong một tập lệnh shell ở Jenkins. Chúng tôi vẫn chưa chuyển sang hệ thống đường ống và phân chia theo giai đoạn.

Chúng tôi đã xem xét những gì mình có và xác định 4 bước phù hợp với mô tả CI/CD của chúng tôi:

  • xây dựng - cài đặt các phụ thuộc, tập hợp kho lưu trữ,
  • kiểm tra - chạy thử nghiệm đơn vị dành cho nhà phát triển, tính toán mức độ phù hợp,
  • sonar - khởi chạy tất cả các linters và gửi báo cáo tới SonarQube,
  • triển khai - gửi một tạo phẩm tới alpha (TestFlight).

Và nếu bạn không đi sâu vào chi tiết, bỏ qua các phím được sử dụng trong các hành động, bạn sẽ nhận được Fastfile này:

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

Trên thực tế, Fastfile đầu tiên của chúng tôi hóa ra lại rất quái dị, khi xét đến một số điểm tựa mà chúng tôi vẫn cần và số lượng tham số mà chúng tôi đã thay thế:

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

Trong ví dụ trên, chỉ một phần tham số mà chúng tôi cần chỉ định: đây là các tham số xây dựng - lược đồ, cấu hình, tên Hồ sơ cung cấp, cũng như các tham số phân phối - ID Apple của tài khoản nhà phát triển, mật khẩu, ID ứng dụng, v.v. TRÊN. Trong phép tính gần đúng đầu tiên, chúng tôi đặt tất cả các khóa này vào các tệp đặc biệt - Gymfile, Matchfile и Appfile.

Giờ đây trong Jenkins, bạn có thể gọi các lệnh ngắn không làm mờ chế độ xem và dễ đọc bằng mắt:

# fastlane ios <lane_name>

$ fastlane ios build
$ fastlane ios test
$ fastlane ios run_sonar
$ fastlane ios deploy

Hoan hô, chúng ta tuyệt vời

Bạn đã nhận được gì? Xóa lệnh cho từng bước. Làm sạch các tập lệnh, sắp xếp gọn gàng trong các tệp fastlane. Vui mừng, chúng tôi chạy đến chỗ các nhà phát triển và yêu cầu họ thêm mọi thứ họ cần vào kho lưu trữ của mình.

Nhưng chúng tôi đã kịp thời nhận ra rằng chúng tôi sẽ gặp phải những khó khăn tương tự - chúng tôi vẫn sẽ có 20 tập lệnh lắp ráp bằng cách này hay cách khác sẽ bắt đầu sống cuộc sống của riêng chúng, việc chỉnh sửa chúng sẽ khó khăn hơn vì các tập lệnh sẽ chuyển sang kho lưu trữ, và chúng tôi không có quyền truy cập vào đó. Và nói chung, sẽ không thể giải quyết được nỗi đau của chúng ta theo cách này.

Trải nghiệm CICD di động: một tiêu chuẩn fastlane cho nhiều ứng dụng di động

Nhiệm vụ #2: lấy một Fastfile duy nhất cho N ứng dụng

Bây giờ có vẻ như việc giải quyết vấn đề không quá khó - hãy đặt các biến và bắt đầu. Vâng, trên thực tế, vấn đề đã được giải quyết như vậy. Nhưng tại thời điểm chúng tôi làm hỏng nó, chúng tôi không có kiến ​​thức chuyên môn về fastlane, cũng như về Ruby, loại fastlane được viết trong đó, cũng như các ví dụ hữu ích trên mạng - tất cả những người viết về fastlane khi đó đều bị giới hạn ở một ví dụ cho một ứng dụng cho một nhà phát triển.

Fastlane có thể xử lý các biến môi trường và chúng tôi đã thử điều này bằng cách đặt mật khẩu Chuỗi khóa:

ENV['KEYCHAIN_PASSWORD']

Sau khi xem tập lệnh của mình, chúng tôi đã xác định được các phần chung:

#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

Bây giờ, để bắt đầu sử dụng các khóa này trong các tệp fastlane, chúng tôi phải tìm ra cách đưa chúng đến đó. Fastlane có giải pháp cho việc này: tải biến qua dotenv. Tài liệu nói rằng nếu bạn cần tải khóa cho các mục đích khác nhau, hãy tạo một số tệp cấu hình trong thư mục fastlane .env, .env.default, .env.development.

Và sau đó chúng tôi quyết định sử dụng thư viện này theo cách khác một chút. Hãy đặt trong kho lưu trữ của nhà phát triển không phải các tập lệnh fastlane và thông tin meta của nó mà là các khóa duy nhất của ứng dụng này trong tệp .env.appName.

Bản thân Fastfile, Appfile, Matchfile и Gymfile, chúng tôi đã giấu nó trong một kho lưu trữ riêng. Một tệp bổ sung có khóa mật khẩu từ các dịch vụ khác đã bị ẩn ở đó - .env.
Bạn có thể xem một ví dụ đây.

Trải nghiệm CICD di động: một tiêu chuẩn fastlane cho nhiều ứng dụng di động

Trên CI, cuộc gọi không thay đổi nhiều; khóa cấu hình cho một ứng dụng cụ thể đã được thêm:

# 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

Trước khi chạy các lệnh, chúng tôi tải kho lưu trữ của mình bằng các tập lệnh. Trông không đẹp lắm:

git clone [email protected]/FastlaneCICD.git fastlane_temp

cp ./fastlane_temp/fastlane/* ./fastlane/
cp ./fastlane_temp/fastlane/.env fastlane/.env

Tạm thời để lại giải pháp này, mặc dù Fastlane có giải pháp tải xuống Fastfile qua hoạt động import_from_git, nhưng nó chỉ hoạt động với Fastfile chứ không hoạt động với các tệp khác. Nếu bạn muốn “thực sự đẹp”, bạn có thể tự viết action.

Một bộ tương tự đã được tạo cho các ứng dụng Android và ReactNative, các tệp nằm trong cùng một kho lưu trữ nhưng ở các nhánh khác nhau iOS, android и react_native.

Khi nhóm phát hành muốn thêm một số bước mới, các thay đổi trong tập lệnh được ghi lại thông qua MR trong git, không cần phải tìm thủ phạm của các tập lệnh bị hỏng nữa và nói chung là bây giờ bạn phải cố gắng phá vỡ nó.

Bây giờ chắc chắn là vậy rồi

Trước đây, chúng tôi đã dành thời gian để duy trì tất cả các tập lệnh, cập nhật chúng và khắc phục mọi hậu quả của việc cập nhật. Thật đáng thất vọng khi lý do gây ra lỗi và thời gian ngừng hoạt động trong các bản phát hành là những lỗi đánh máy đơn giản đến mức khó theo dõi trong mớ hỗn độn của các tập lệnh shell. Bây giờ những lỗi như vậy đã giảm đến mức tối thiểu. Các thay đổi được triển khai cho tất cả các ứng dụng cùng một lúc. Và phải mất 15 phút để đưa một ứng dụng mới vào quy trình - thiết lập đường dẫn mẫu trên CI và thêm khóa vào kho lưu trữ của nhà phát triển.

Có vẻ như vấn đề với Fastfile cho Android và chữ ký ứng dụng vẫn chưa được giải thích, nếu bài viết thú vị thì tôi sẽ viết tiếp. Tôi sẽ rất vui khi thấy câu hỏi hoặc đề xuất của bạn “bạn sẽ giải quyết vấn đề này như thế nào” trong phần bình luận hoặc trên Telegram bashkirova.

Nguồn: www.habr.com

Thêm một lời nhận xét