הגדרת תיוג אוטומטי של גרסאות (SemVer) ב-CI/CD

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

היכולות שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

למה תיוג ידני שובר מהדורות: SemVer בפועל

תיוג ידני של גרסאות נראה בטוח כל עוד המהדורות נדירות. את הגרסה קובע אדם, ו-major, minor ו-patch נבחרים לפי עוצמת השינויים ולא לפי ההרכב שלהם. SemVer הופך להסכמה בעל פה — והוא נשבר ראשון במהדורה דחופה.

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

הבא בתור — תיקונים אבודים. patch מוזג לענף המהדורה, אבל מספר הגרסה לא שונה; בבנייה הבאה הוא לא נכנס לרשימת השינויים, והפגם חוזר. קורה גם ההפך: תיקון נכנס לעבודה בלי שיקוף בגרסה, ואף אחד לא יודע איפה הוא כבר קיים ואיפה לא.

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

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

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

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

זמן הכנת המהדורה מתקצר משעות לדקות

את ההחלטה על major/minor/patch מקבל כלל פירוש הקומיטים, לא אדם. למהנדס נשאר לאשר את המהדורה: המספר חושב, רשימת השינויים נאספה, הענף סומן — המהדורה מפסיקה להיות משימה נפרדת שמתכוננים אליה מראש.

שיעור התגים השגויים יורד כמעט לאפס

כפילויות, תג על הענף הלא נכון, אינקרמנט שנשכח — סיבות אופייניות לטעויות ידניות שמתגלות כבר אחרי הפרסום. הכלל בודק את ההיסטוריה ופוסל את המספר המתנגש בשלב הבנייה: הגרסה השגויה просто לא ממשיכה הלאה. כלים כמו Semantic Release עושים זאת באופן הצהרתי — התצורה נשמרת לצד הקוד ועוברת סקירה כמו קוד.

חזרה לאחור ושחזוריות הבנייה

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

עקיבות שינויים

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

SemVer: השוואה בין תיוג ידני, היברידי ואוטומטי

גרסה ב-SemVer מורכבת מ-major, minor ו-patch בתוספת תווית pre-release: את major מעלים בשינויים שוברים, minor — בפונקציונליות תואמת לאחור, patch — בתיקונים.

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

מצב תיוג מתי מתאים מגבלות
ידני מהדורות נדירות ו-API ציבורי, שבהן שינוי major הוא הסכמה עם הצרכנים אדם שוכח להעלות את המספר, תגים משוכפלים, ההתאמה בין הבנייה לתג הולכת לאיבוד; תגי pre-release חיים בנפרד מהענף הראשי
סכימת גרסאות היברידית מהדורות סדירות, שבהן major ו-minor נשארים החלטה מודעת של המוצר דרוש נוהל: מי ומתי מעלה major ו-minor, אחרת אינקרמנט אוטומטי של הגרסה עבור patch מסווה שינוי שובר
אוטומטי מהדורה רציפה, הרבה מהדורות קצרות וריפוזיטוריז טעות בהודעת קומיט נותנת major שגוי; חובה הגנת ענף, כללי תגי pre-release וחזרה לאחור ברורה

עבור רוב המוצרים הסכימה העובדת היא היברידית: את major ו-minor קובע האחראי על המהדורה, ואת patch ותג ה-pre-release מציבה האוטומציה לפי כללי הענף. אז התג תמיד מצביע בדיוק על הארטיפקט שיצא לאספקה, ובנייות pre-release לא נכנסות לערוץ היציב.

איך אנחנו מטמיעים תיוג אוטומטי: שלבי עבודת הנדסה

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

  1. ביקורת ניהול גרסאות. מעלים את היסטוריית התגים והמהדורות, משווים תוויות לתוכן הבנייות. מחפשים מהדורות שחזרה לאחור מהן בלתי אפשרית: לא ברור מה היה בארטיפקט ומאיזה ענף הוא נבנה.
  2. סכימת ניהול גרסאות. מסכימים מה נחשב שינוי שובר, מה — פונקציונליות חדשה, ומה — תיקון. סכימת ניהול גרסאות סמנטי צריכה להיות קריאה באופן חד-משמעי גם לאדם וגם לצינור.
  3. כללי הודעות שינויים. מגדירים פורמט שלפיו הצינור בעצמו מזהה את סוג התיקון. אחרת יהיה צורך לאשר את שלב התיוג ידנית.
  4. הגדרת הצינור. מוסיפים שלב שקורא את ההיסטוריה, מחשב את המספר הבא ומציב תג מוער על קומיט מסוים. התווית מונפקת פעם אחת ואינה בשימוש חוזר.
  5. בדיקת תגים על היסטוריית המהדורות. מריצים את הכלל על מהדורות קודמות ובודקים אילו תוויות היו מתקבלות. כך תופסים תגים כפולים, גרסאות minor שהוחמצו וקטיעות בשרשרת הגרסאות.
  6. מסירת נוהל. מוסרים מסמך עם הכללים, הגנה על תוויות מפני דריסה והדרכה קצרה לצוות. מכאן והלאה מהנדס המהדורות מציב תג בפקודה אחת, לא מהזיכרון.

ארטיפקטי הטמעה: תצורות, סכימות צינור ונהלים

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

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

מקרה בוחן: איך צמצמנו את שיעור התגים השגויים ואת זמן הכנת המהדורה

מה היה לפני השינויים

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

מה שינו

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

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

התוצאה במספרים

מדד לפני אחרי
שיעור תגים שגויים 11-13% מהמהדורות אפס במשך שני רבעונים, מקרים שנויים במחלוקת נתפסים בבדיקה לפני יצירת התג
זמן מקבלת שינוי ועד התג 40-60 דקות של המתנה למהנדס המהדורות 3-4 דקות של שלב אוטומטי, לא תלוי בעומס על אנשים
פעולות ידניות למהדורה 12-14 שתיים: אישור המהדורה והודעה לצרכנים

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

SemVer ב-monorepo: איך מפרידים בין גרסאות של שירותים?

מונה גרסאות כללי אחד ל-monorepo שובר את המשמעות של SemVer: תיקון בשירות אחד מעלה major אצל עשרים האחרים, והצרכנים רואים «שינוי בלתי תואם» במקום שבו לא השתנה דבר. לכן את המספר מחשבים לא לפי הריפוזיטורי אלא לפי תחום פעולה — הנתיב של השירות המסוים.

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

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

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

נקודות שנויות במחלוקת בניהול גרסאות אוטומטי: שאלות נפוצות

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

בריפוזיטורי כבר יש תגים שלא תואמים ל-SemVer. צריך לכתוב אותם מחדש?

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

ענפים מקבילים — איך להימנע מהתנגשות גרסאות?

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

מה קורה בבנייה חוזרת של אותו קומיט?

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

עבור מהדורות קריטיות אפשר להשאיר אישור ידני?

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

נדון בסכימת ניהול הגרסאות שלכם ונחזור עם תוכנית

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

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

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