חווית CICD ניידת: תקן מהיר אחד עבור יישומים ניידים רבים

חווית CICD ניידת: תקן מהיר אחד עבור יישומים ניידים רבים
ברצוני לדבר על אינטגרציה ואספקה ​​מתמשכת עבור אפליקציות לנייד המשתמשות ב-fastlane. איך אנחנו מיישמים CI/CD בכל האפליקציות לנייד, איך הגענו לשם ומה קרה בסופו של דבר.

יש כבר מספיק חומר ברשת על הכלי, שכל כך היה חסר לנו בהתחלה, אז אני בכוונה לא אתאר את הכלי בפירוט, אלא אתייחס רק למה שהיה לנו אז:

המאמר מורכב משני חלקים:

  • רקע להופעתו של CI/CD נייד בחברה
  • פתרון טכני להפצת CI/CD עבור אפליקציות N

החלק הראשון הוא יותר נוסטלגיה לימים עברו, והשני הוא חוויה שתוכלו ליישם על עצמכם.

כך זה קרה היסטורית

שנה 2015

רק התחלנו לפתח אפליקציות מובייל, ואז לא ידענו כלום על אינטגרציה מתמשכת, על DevOps ודברים אופנתיים אחרים. כל עדכון אפליקציה הושק על ידי המפתח עצמו מהמחשב שלו. ואם לאנדרואיד זה די פשוט - מורכב, חתום .apk והעלה אותו ל-Google Developer Console, ואז עבור iOS כלי ההפצה דאז דרך Xcode השאיר לנו ערבים נהדרים - ניסיונות להוריד את הארכיון הסתיימו לעתים קרובות בשגיאות והיינו צריכים לנסות שוב. התברר שהמפתח המתקדם ביותר אינו כותב קוד מספר פעמים בחודש, אלא משחרר את האפליקציה.

שנה 2016

גדלנו, כבר היו לנו מחשבות איך לשחרר מפתחים מיום שלם לשחרור, והופיעה גם אפליקציה שנייה שרק דחפה אותנו יותר לאוטומציה. באותה שנה, התקנו את ג'נקינס בפעם הראשונה וכתבנו חבורה של סקריפטים מפחידים, דומים מאוד לאלו ש-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, תהליך הבנייה וההפצה של יישומים עבר לחלוטין לג'נקינס, מפתחים הפסיקו לשחרר מהמכונות שלהם, ורק לצוות ההפצה הייתה הזכות לשחרר.

כבר רצינו לשפר את ההשקה של בדיקות וניתוח סטטי, והתסריטים שלנו גדלו וגדלו. גדל והשתנה יחד עם האפליקציות שלנו. באותה תקופה היו בערך 10 יישומים. בהתחשב בכך שיש לנו שתי פלטפורמות, זה בערך 20 סקריפטים "חיים".

בכל פעם שרצינו להוסיף שלב חדש לתסריט, היינו צריכים להעתיק-הדבק את הקטעים לתוך כל התסריטים של המעטפת. אולי יכולנו לעבוד ביתר זהירות, אבל לעתים קרובות שינויים כאלה הסתיימו בשגיאות הקלדה, שהפכו לערב עבור צוות השחרור כדי לתקן סקריפטים ולגלות איזה בחור חכם הוסיף את הפקודה הזו ומה היא בעצם עושה. באופן כללי, לא ניתן לומר שהתסריטים להרכבה עבור פלטפורמה אחת היו דומים לפחות במקצת. למרות שהם בהחלט עשו את אותו הדבר.

על מנת להתחיל תהליך עבור אפליקציה חדשה, היה צורך להקדיש יום לבחירת גרסה "טרייה" של הסקריפטים הללו, לנפות באגים ולהגיד ש"כן, זה עובד".

בקיץ 2018, שוב הסתכלנו לעבר המסלול המהיר שעדיין מתפתח.

משימה מס' 1: סכם את כל שלבי הסקריפט וכתוב אותם מחדש ב-Fastfile

כשהתחלנו, התסריטים שלנו נראו כמו בד רגליים המורכב מכל הצעדים והקביים בתסריט קליפה אחת בג'נקינס. עוד לא עברנו לצנרת ולחלוקה לפי שלב.

הסתכלנו על מה שיש לנו וזיהינו 4 שלבים שמתאימים לתיאור של ה-CI/CD שלנו:

  • build - התקנת תלות, הרכבת הארכיון,
  • בדיקה - הפעלת בדיקות יחידות מפתח, חישוב כיסוי,
  • sonar - משיק את כל הלינטרים ושולח דוחות ל- SonarQube,
  • deploy - שליחת חפץ לאלפא (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

בדוגמה שלמעלה, רק חלק מהפרמטרים שעלינו לציין: אלו הם פרמטרי ה-build - סכימה, תצורה, שמות פרופילי אספקה, וכן פרמטרי הפצה - Apple ID של חשבון המפתח, סיסמה, מזהה אפליקציה וכדומה עַל. כקירוב ראשון, שמנו את כל המפתחות האלה בקבצים מיוחדים - Gymfile, Matchfile и Appfile.

עכשיו בג'נקינס אתה יכול לקרוא לפקודות קצרות שאינן מטשטשות את התצוגה והן ניתנות לקריאה בקלות בעין:

# fastlane ios <lane_name>

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

היי, אנחנו מעולים

מה קיבלת? פקודות ברורות לכל שלב. סקריפטים נקיים, מסודרים בקפידה בקבצי Fastlane. בשמחה, רצנו אל המפתחים וביקשנו מהם להוסיף את כל מה שהם צריכים למאגרים שלהם.

אבל הבנו עם הזמן שניתקל באותם קשיים - עדיין יהיו לנו 20 סקריפטים אסמבליים שיתחילו כך או אחרת לחיות את חייהם, יהיה קשה יותר לערוך אותם, היות והתסריטים יעברו למאגרים, ולא הייתה לנו גישה לשם. ובכלל, לא ניתן יהיה לפתור את הכאב שלנו כך.

חווית CICD ניידת: תקן מהיר אחד עבור יישומים ניידים רבים

משימה מס' 2: קבל Fastfile יחיד עבור N יישומים

כעת נראה שפתרון הבעיה לא כל כך קשה – הגדירו את המשתנים, ויאללה. כן, למעשה, כך נפתרה הבעיה. אבל ברגע שבו פישלנו את זה, לא הייתה לנו מומחיות ב-fastlane עצמו, ולא ברובי, שבה כתוב 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 ניידת: תקן מהיר אחד עבור יישומים ניידים רבים

ב-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.

ערכה דומה נוצרה עבור אפליקציות אנדרואיד ו-ReactNative, הקבצים נמצאים באותו מאגר, אך בסניפים שונים iOS, android и react_native.

כאשר צוות השחרור רוצה להוסיף איזשהו שלב חדש, שינויים בסקריפט מוקלטים דרך MR ב-git, כבר אין צורך לחפש את האשמים של סקריפטים שבורים, ובכלל, עכשיו צריך לנסות לשבור אותו.

עכשיו זה זה בטוח

בעבר, השקענו זמן בתחזוקה של כל התסריטים, בעדכון שלהם ובתיקון כל ההשלכות של עדכונים. זה היה מאוד מאכזב כשהסיבות לשגיאות וזמני השבתה במהדורות היו שגיאות הקלדה פשוטות שהיה כל כך קשה לעקוב אחרין בערבוביה של תסריטי מעטפת. עכשיו שגיאות כאלה מצטמצמות למינימום. השינויים מופעלים לכל היישומים בבת אחת. וזה לוקח 15 דקות להכניס אפליקציה חדשה לתהליך - הגדר צינור תבנית ב-CI והוסף את המפתחות למאגר של המפתח.

נראה שהנקודה עם Fastfile לאנדרואיד וחתימת אפליקציות נותרה בלתי מוסברת; אם המאמר מעניין, אכתוב המשך. אני אשמח לראות את השאלות או ההצעות שלך "איך היית פותר את הבעיה הזו" בתגובות או בטלגרם בשקירובה.

מקור: www.habr.com

הוספת תגובה