תארו לעצמכם: אתם משחררים עדכון לאפליקציית מובייל, אבל NullPointerException שהתחמק מבדיקת הקוד מגיעה לייצור. או שאתם לא שמים לב ללוגיקה כפולה בשני מודולים, וחודש לאחר מכן התיקונים לוקחים פי שניים זמן. בדיקות ידניות ו-linters לא נותנות תמונה אחידה, במיוחד בפרויקטים גדולים עם עשרות מודולים. רגרסיות מצטברות, חוב טכני גדל, ומהירות הפיתוח יורדת. אנו משלבים SonarQube — מנתח סטטי מרכזי שבודק אוטומטית את איכות כל commit ומונע מתקלות להגיע לענף הראשי.
למה פרויקט מובייל צריך SonarQube
SonarQube עובד עם Swift, Kotlin, Java, TypeScript ו-Dart. עבור אפליקציית מובייל זה אומר: מציאת NPE פוטנציאליים לפני הייצור, בקרת כפילויות בין מודולים, מעקב אחר code smells ב-coroutines, ואכיפת סף כיסוי לפני merge. ראינו פרויקטים שבהם לאחר ההטמעה מספר הבאגים ירד ב-40% תוך שישה חודשים — זה לא רק יציבות אלא גם חיסכון: הצוות מבזבז 30% פחות זמן על בדיקות רגרסיה. המהנדסים המוסמכים שלנו מתקינים את SonarQube לפרויקט שלכם תוך 1–3 ימים. אנו מבטיחים שאיכות הקוד תשתפר פי 2–3 בהשוואה לבדיקה ידנית.
למה לשלב את SonarQube ב-CI?
ללא ניתוח אוטומטי, כל שינוי בקוד נושא סיכון. בני אדם מפספסים תקלות קטנות שמצטברות. SonarQube ב-CI תופס אותן מיד: אחרי כל push מתבצע ניתוח, ואם ה-Quality Gate נכשל, ה-build נשבר. זה מחנך את הצוות ומקצר את זמן בדיקת הקוד. לדוגמה, בדיקה טיפוסית לוקחת 30 דקות לכל PR, בעוד SonarQube בודק את כל הפרויקט תוך 2–3 דקות. במשך חודש, צוות של חמישה מפתחים חוסך עד 20 שעות אדם — משאב שניתן להפנות לתכונות חדשות.
איך להגדיר SonarQube ל-Android
התוסף של SonarQube משתלב ב-Gradle:
// build.gradle.kts (project level)
plugins {
id("org.sonarqube") version "4.4.1.3373"
}
sonar {
properties {
property("sonar.projectKey", "myapp-android")
property("sonar.host.url", System.getenv("SONAR_HOST_URL") ?: "http://sonarqube:9000")
property("sonar.token", System.getenv("SONAR_TOKEN") ?: "")
property("sonar.sources", "app/src/main/kotlin")
property("sonar.tests", "app/src/test/kotlin,app/src/androidTest/kotlin")
property("sonar.android.lint.report", "app/build/reports/lint-results-debug.xml")
property("sonar.coverage.jacoco.xmlReportPaths", "app/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml")
property("sonar.kotlin.detekt.reportPaths", "app/build/reports/detekt/detekt.xml")
}
}הרצת ניתוח ב-CI:
./gradlew \ lintDebug \ testDebugUnitTest \ jacocoTestReport \ detekt \ sonar \ --info JaCoCo מוגדר בנפרד ליצירת דוח כיסוי בפורמט XML. עבור Kotlin אנו משתמשים ב-detekt, שתופס code smells הקשורים ל-coroutines ולארכיטקטורה.
איך להגדיר SonarQube ל-iOS
SonarQube מנתח Swift דרך ה-CLI // build.gradle.kts (project level) plugins { id("org.sonarqube") version "4.4.1.3373" } sonar { properties { property("sonar.projectKey", "myapp-android") property("sonar.host.url", System.getenv("SONAR_HOST_URL") ?: "http://sonarqube:9000") property("sonar.token", System.getenv("SONAR_TOKEN") ?: "") property("sonar.sources", "app/src/main/kotlin") property("sonar.tests", "app/src/test/kotlin,app/src/androidTest/kotlin") property("sonar.android.lint.report", "app/build/reports/lint-results-debug.xml") property("sonar.coverage.jacoco.xmlReportPaths", "app/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml") property("sonar.kotlin.detekt.reportPaths", "app/build/reports/detekt/detekt.xml") } } עם התוסף ./gradlew \ lintDebug \ testDebugUnitTest \ jacocoTestReport \ detekt \ sonar \ --info או מנתח ה-Swift המובנה (SonarQube 10+):
# sonar-project.properties
sonar.projectKey=myapp-ios
sonar.sources=MyApp/Sources
sonar.exclusions=**/*.generated.swift,Pods/**/*
sonar.swift.coverage.reportPaths=fastlane/test_output/coverage.xml
sonar.swift.swiftlint.reportPaths=fastlane/swiftlint-report.jsonב-CI:
# Генерация coverage
xcodebuild test \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15' \
-enableCodeCoverage YES
# Конвертация в формат, понятный SonarQube
slather coverage \
--cobertura-xml \
--output-directory fastlane/test_output \
MyApp.xcodeproj
# Анализ
sonar-scanner \
-Dsonar.token=$SONAR_TOKEN \
-Dsonar.host.url=$SONAR_HOST_URLעבור iOS אנו משתמשים ב-sonar-scanner להמרת כיסוי ל-Cobertura XML — הפורמט ש-SonarQube מבין. ו-swiftlint תופס בעיות סגנון ושגיאות פוטנציאליות.
איך להגדיר Quality Gate ב-PR
Quality Gate הוא סט תנאים שאם לא מתקיימים, SonarQube חוסם את ה-merge. ספים אופייניים לפרויקט מובייל:
| מדד | תנאי |
|---|---|
| כיסוי בקוד חדש | >= 70% |
| כפילויות בקוד חדש | <= 5% |
| דירוג תחזוקה | A |
| דירוג אמינות | A |
| דירוג אבטחה | A |
| נקודות חמות אבטחה שנבדקו | 100% |
ב-GitHub Actions, אינטגרציה דרך sonar-swift:
---
- name: SonarQube Quality Gate check
uses: sonarsource/[email protected]
timeout-minutes: 5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
אם ה-Quality Gate נכשל, ה-CI נשבר וה-PR לא ניתן למיזוג. עבור GitLab CI, תצורה דומה דרך # sonar-project.properties sonar.projectKey=myapp-ios sonar.sources=MyApp/Sources sonar.exclusions=**/*.generated.swift,Pods/**/* sonar.swift.coverage.reportPaths=fastlane/test_output/coverage.xml sonar.swift.swiftlint.reportPaths=fastlane/swiftlint-report.json .
SonarCloud או Self-Hosted: מה לבחור?
| קריטריון | SonarCloud | SonarQube עצמאי |
|---|---|---|
| תשתית | לא נדרשת | שרת (מינימום 2GB RAM) |
| מחיר | חינם לקוד פתוח | גרסת Community חינמית, גרסת Developer בתשלום |
| שליטה בנתונים | ענן | מלאה |
| זמן הגדרה | 1–2 שעות | 1–2 ימים |
| ניתוח ענפי תכונה | כן (כל התוכניות) | רק בגרסת Developer |
SonarCloud מהיר יותר ליישום, self-hosted נותן שליטה מלאה. עבור רוב הפרויקטים המסחריים, אנו ממליצים על SonarCloud — זמן ההגדרה מתקצר בחצי. אם אתם צריכים לאחסן קוד בסביבה סגורה, בחרו ב-self-hosted.
מה כלול
- פריסת SonarQube (ענן או self-hosted)
- יצירת פרויקט והגדרת תוספים (Gradle, sonar-swift)
- שילוב כיסוי (JaCoCo, slather) ו-linters (detekt, swiftlint)
- הוספת שלב ניתוח ל-CI
- התאמת Quality Gate לסטack שלכם
- תיעוד והדרכת צוות
- תמיכה טכנית במהלך שלב ההטמעה
המהנדסים שלנו מחזיקים בהסמכות SonarQube ויש להם ניסיון של 5+ שנים בפיתוח מובייל. יישמנו בהצלחה ניתוח ליותר מ-50 פרויקטים, כולל אפליקציות עם מיליוני משתמשים. צרו קשר לייעוץ — נכין תצורה לפרויקט שלכם ונאמן את הצוות. הזמינו הטמעת SonarQube וקבלו איכות קוד יציבה.
לוח זמנים ועלות
ההתקנה אורכת 1–3 ימים בהתאם למורכבות הפרויקט. העלות מחושבת באופן אישי. פנו אלינו — נעריך את הפרויקט שלכם ונציע את הפתרון האופטימלי.







