דלגו לתוכן

אכלוס פרויקט ממאגר GitHub

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

הדף הזה הוא הלולאה הזו מקצה לקצה. לשלב האכלוס יש שני מסלולים: GitHub-to-EAT, כלי הייבוא בקוד פתוח של East Agile, עושה זאת בפקודה אחת (שלב 3); ה-API של הייבוא עושה את אותה עבודה קריאה אחר קריאה (שלבים 4 ו-5), וזה מה שסוכן מפעיל כשהוא רוצה את ידית העבודה. כל מה שבא אחר כך רץ על ה-API, כי הנקודה היא שסוכן יכול לעשות את השאר ללא השגחה.

זהו אינו “ייבוא AI” נפרד. שלב האכלוס הוא אותו כלי ייבוא GitHub שאתם יכולים להריץ ידנית מ-Project Settings → Import / Export, המתואר בהוראות הפעלה → ייבוא מכלים אחרים. הסוכן קורא לאותו endpoint שאתם הייתם קוראים לו. מה שהדף הזה מוסיף הוא כל מה שסביבו: מי מחזיק את המפתח, איך לבדוק את הייבוא לפני שהוא כותב, ומה הסוכן עושה עם הלוח ברגע שהוא קיים.

המקור GitHub בלשונית Import / Export: הבעלים והמאגר מולאו, האסימון ריק, בקשות משיכה ואבני דרך מסומנות

  • פרויקט — ומפתח session או ea_user_… כדי ליצור אותו.
  • מפתח סוכן — מפתח ea_agent_… המוגבל לאותו פרויקט. איזה תפקיד הוא צריך תלוי בכמה מהלולאה אתם רוצים שהסוכן יריץ; ראו שלב 2. ראו גם מדריך API → שני סוגי מפתחות.
  • GitHub personal access token — עם הרשאת קריאה ל-issues של המאגר. כל ייבוא עובר אימות, כי השליפה רצה על ה-GraphQL API של GitHub ו-GraphQL דוחה בקשה שאינה נושאת אסימון. תוכלו להשמיט אותו רק כשה-Tracker שולף בשמכם: מאגר ציבורי, בפריסה שיש בה אסימון גיבוי משותף (השירות המתארח eastagiletracker.com מחזיק אחד; להתקנה עצמאית אין אף אחד עד שמפעילה מגדיר GITHUB_IMPORT_PAT), ולא עם --engine direct של GitHub-to-EAT. ראו אסימונים ומגבלות קצב.
  • Node.js 22+ — רק עבור מסלול GitHub-to-EAT בשלב 3. מסלול ה-API אינו צריך דבר מלבד curl.

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

Terminal window
curl -X POST https://eastagiletracker.com/api/v1/projects \
-H "X-TrackerToken: $TRACKER_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "hello-world", "iteration_length_weeks": 1}'

התשובה נושאת את ה-project_id שכל קריאה למטה זקוקה לו.

בעל פרויקט יוצר מפתחות סוכן ב-Project Settings → Agents. התפקיד שתבחרו קובע כמה מהדף הזה הסוכן יכול לעשות בכוחות עצמו, ויש שתי תשובות הגיוניות:

  • owner — מפתח אחד מריץ את כל הלולאה, כולל הייבוא. ייבוא הוא לבעלים בלבד, כי ייבוא כותב מחדש את צורת הפרויקט כולה. הנפקת סוכן בתפקיד owner מחייבת שאתם עצמכם תהיו בעלי הפרויקט: תפקידו של סוכן לעולם אינו יכול לעלות על זה של יוצרו.
  • member — הרשאה מזערית. הסוכן תופס סיפורים, מזיז אותם, מגיב ומקשר pull requests, אך אינו יכול לייבא. אתם מריצים את הייבוא בעצמכם (שלב 5) עם המפתח שלכם, ואז מוסרים את הלוח לסוכן.

כך או כך, אל תשאירו את ברירת המחדל. מפתח סוכן חדש הוא viewer אלא אם תאמרו אחרת, ו-viewer יכול לקרוא את הלוח אך לא לתפוס או להזיז סיפור — וזה רוב הלולאה הזו.

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

Terminal window
export TRACKER_TOKEN="ea_agent_xxxxx"

בקשו מהסוכן לקרוא את /meta לפני כל דבר אחר:

Terminal window
curl https://eastagiletracker.com/api/v1/meta \
-H "X-TrackerToken: $TRACKER_TOKEN"

זה עונה על שתי השאלות שסוכן היה אחרת מנחש: לאיזה פרויקט המפתח קשור (auth.project_id), ואילו מעברי מצב חוקיים לכל סוג סיפור (transitions). Feature רץ unstarted → started → finished → delivered → accepted; Chore הוא רק unstarted → started → accepted. קריאת המפה עדיפה על קיבועה בקוד.

GitHub-to-EAT הוא כלי הייבוא בקוד פתוח של East Agile עצמה: כלי שורת פקודה ברישיון MIT שעושה את כל שלב האכלוס — שלבים 4 ו-5 למטה — בפקודה אחת. הושיטו אליו יד כשאדם יושב מול טרמינל. הושיטו יד ל-API שמתחתיו כשסוכן מפעיל ללא השגחה ורוצה את ידית העבודה כדי לתשאל אותה.

הוא צריך Node.js 22+ ואין לו תלויות ריצה משלו. הוא עדיין אינו מפורסם ב-npm, אז התקינו אותו מהמאגר:

Terminal window
git clone git@github.com:EastAgile/GitHub-to-EAT.git
cd GitHub-to-EAT
npm install --global .

אחר כך הפנו אותו למפתח שהנפקתם בשלב 2 ולפרויקט שיצרתם בשלב 1:

Terminal window
export EAT_AGENT_KEY="ea_agent_xxxxx"
github-to-eat --project $PROJECT_ID --repo octocat/hello-world

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

דגלמה הוא עושה
--dry-runבדיקה מקדימה, ואז הדפסת התוכנית שהיה מבצע — כמה סיפורים היה מייבא, כמה היה מדלג ככבר קיימים — וללא כתיבה. אינו צריך --yes.
--includeאילו סוגים לייבא, מופרדים בפסיקים: issues,prs,milestones,releases,deps. ברירת המחדל היא issues, וכל בחירה חייבת להכיל אותו. אלו אותן הצטרפויות כמו בטבלה בשלב 6.
--tokenה-GitHub personal access token שלכם (GITHUB_TOKEN בסביבה או ב-.env נחשב גם הוא). הוא צריך repo, או הרשאה מפורטת Issues: Read, על אותו מאגר. נדרש עבור מאגר פרטי, עבור שרת ללא אסימון גיבוי משותף, ותמיד עבור --engine direct. השמיטו אותו במנוע ברירת המחדל של השירות המתארח וה-Tracker יוציא מהתקציב המשותף שלו — ראו אסימונים ומגבלות קצב.
--engineserver, ברירת המחדל, שולח קריאת /import/json אחת ומניח ל-Tracker לשלוף, למפות ולכתוב. direct מריץ את אותו צינור על המכונה שלכם וכותב דרך ה-API הציבורי במקום — ולכן הוא קורא את GitHub בעצמו ותמיד צריך אסימון, ויוצא עם 2 בלעדיו.
--states, --milestones, --story-type, --no-comments, --no-tasksצמצום או דריסה של המיפוי להרצה אחת; דבר אינו נשמר. כל אחד מהם גורר --engine direct.

הגדירו EAT_API_BASE ו-EAT_APP_BASE כדי להפנות אותו ל-Tracker באחסון עצמי או מקומי; שניהם מוגדרים כברירת מחדל לשירות המתארח. ה-README נושא את מלוא רשימת הדגלים, קודי היציאה ופתרון תקלות.

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

ייבוא הוא לבעלים בלבד — השתמשו במפתח סוכן בתפקיד owner, או במפתח שלכם אם השארתם את הסוכן כ-member. הריצו אותו עם dry_run תחילה, לפני שאתם נותנים לו לכתוב דבר:

Terminal window
curl -X POST https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/import/json \
-H "X-TrackerToken: $TRACKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source": "github",
"owner": "octocat",
"repo": "hello-world",
"include_pull_requests": true,
"include_milestones": true,
"dry_run": true
}'

הרצת dry run שולפת מ-GitHub, פותרת ומסירה כפילויות בדיוק כמו הדבר האמיתי, מדווחת על אותן ספירות — imported, skipped, errors, unmatched — ואז מגלגלת את כל הטרנזקציה לאחור. דבר אינו נשמר ואף אירוע ייבוא-הושלם אינו מגיע ליומן הביקורת שלכם. זו הדרך הזולה ביותר לגלות שהתכוונתם לצרף milestones, או שמאגר גדול ממה שחשבתם, בזמן שזה עדיין אינו עולה לכם דבר.

כל קריאה ל-/import/json היא אסינכרונית, כולל הרצת dry run: ה-endpoint מחזיר 202 עם ידית עבודה, לא תוצאה, והספירות מגיעות על העבודה כשאתם מתשאלים אותה (שלב 5). עבודה של dry run מגיעה ל-done בדיוק כמו עבודה אמיתית; ההבדל הוא ששום דבר לא נכתב.

הסירו את dry_run ושלחו שוב. כמו קודם, ה-endpoint מחזיר 202 עם ידית עבודה:

{ "import_id": "…", "status": "pending" }

תשאלו את העבודה עד שהיא מגיעה למצב סופי:

Terminal window
curl https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/imports/$IMPORT_ID \
-H "X-TrackerToken: $TRACKER_TOKEN"

המצב רץ pending → fetching → writing → done | failed. רק שני האחרונים סופיים: done נושא את ספירות התוצאה, failed נושא הודעת שגיאה וקוד מכונה יציב שאפשר להסתעף עליו. בזמן שהשליפה מדפדפת, progress_current ו-progress_total אומרים לכם באיזה עמוד היא נמצאת — שווה להציג אם אדם צופה.

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

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

Issues מיובאים כברירת מחדל. כל השאר בהצטרפות, דגל אחד לכל אחד:

מ-GitHubהופך לדגל
Issueסיפור. פתוח → unstarted ב-Backlog. סגור → accepted, או rejected כש-GitHub אומר שה-issue נסגר כ-not_planned או duplicate (הסיפור נושא אז תווית תואמת).ברירת מחדל
רשימת משימות בגוף ה-issueמשימות — כל שורת - [ ] / - [x] הופכת למשימה אחת לפי סדר הגוף, כש-[x] מגיעה כמושלמת. הרשימה גם נשארת בתיאור.ברירת מחדל
תוויותתוויות, מועברות כמות שהן.ברירת מחדל
Pull requestסיפור בתווית pull-request. פתוח → started, ממוזג → accepted, סגור ללא מיזוג → rejected.include_pull_requests
MilestoneEpic, שכותרתו על שם ה-milestone, ללא כפילויות לפי כותרת — שני issues החולקים milestone נוחתים ב-Epic אחד. כשהדגל כבוי הוא נוסע כתווית milestone:<title> במקום.include_milestones
Releaseסיפור Release. פורסם → accepted, טיוטה → unstarted.include_releases
תלות בין issuesblocker על הסיפור. issues בלבד, לעולם לא pull requests.include_dependencies

סוג הסיפור נגזר כשה-issue אינו אומר. תווית המכילה bug, fix או defect — או כותרת המתחילה ב-fix או bug — הופכת אותו ל-Bug; chore, maintenance, devops או infra הופכים אותו ל-Chore; כל השאר הוא Feature. שווה לדעת זאת לפני שאתם מייבאים, כי ב-East Agile Tracker רק Features נושאים נקודות ורק Features מזינים מהירות. ראו מבוא → סיפורים.

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

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

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

Terminal window
curl "https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/stories?state=unstarted" \
-H "X-TrackerToken: $TRACKER_TOKEN"

import_source=github מצמצם זאת למה שהייבוא הביא. אם הסוכן מצא עבודה שהמאגר מעולם לא תיעד, הוא יוצר את הסיפור במקום — ראו מדריך API → יצירת סיפור.

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

Terminal window
curl -X POST https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/stories/$STORY_ID/owners \
-H "X-TrackerToken: $TRACKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'

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

התחילו אותו.

Terminal window
curl -X POST https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/stories/$STORY_ID/transitions \
-H "X-TrackerToken: $TRACKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"to": "started"}'

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

צרפו את ה-pull request.

Terminal window
curl -X POST https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/stories/$STORY_ID/links \
-H "X-TrackerToken: $TRACKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://github.com/octocat/hello-world/pull/42"}'

כתובת URL של pull request ב-GitHub מזוהה ככזו — אינכם צריכים לומר זאת. הסיפור והקוד שסוגר אותו נמצאים עכשיו במרחק קליק אחד זה מזה בשני הכיוונים.

סיימו אותו. העבירו ל-finished ועצרו שם. ל-Feature עדיין נותרו delivered ו-accepted לפניו, ואלו שערי הביקורת: מישהו שאינו הסוכן מחליט שהעבודה נכונה. ל-Chore אין שער כזה — started → accepted הוא כל המסלול שנותר לו.

issue סגור שיובא, שהמקטע CODE שלו מקשר לבקשת המשיכה שתיקנה אותו, ולצדו תגובות מ-GitHub

כל ייבוא עובר אימות. שליפת ה-issues, התגובות וה-pull requests רצה על ה-API של GraphQL ב-GitHub, ו-GraphQL דוחה בקשה שאינה נושאת אסימון — אין שכבה אנונימית, לא במאגר ציבורי ולא בפרטי. השאלה לעולם אינה האם אסימון מגיע ל-GitHub, אלא של מי.

העבירו token בקריאת הייבוא, או --token ל-GitHub-to-EAT. personal access token מפורט עם הרשאת קריאה ל-issues של המאגר מספיק. הוא מפעיל את קריאות GitHub במעלה הזרם ותו לא: לעולם אינו נרשם ביומן, לעולם אינו נרשם ביומן הביקורת, לעולם אינו נשמר, ולעולם אינו מוחזר בתשובה או בשגיאה.

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

--engine direct אינו משאיר לכם ברירה. המנוע הזה קורא את GitHub מהמכונה שלכם ולא דרך ה-Tracker, ולכן האסימון של השרת מחוץ להישג יד; הרצה ללא אסימון יוצאת עם 2 ושגיאת שימוש לפני שהיא שולפת או כותבת דבר. GITHUB_TOKEN בסביבה שלכם או ב-.env נחשב, בדיוק כמו --token.

מה שמחייב את האסימון הוא מעבר ה-issues, לא המנוע כולו. direct קורא issues, תגובות ו-pull requests דרך GraphQL, שאין בו מצב אנונימי; הוא נוגע ב-REST רק עבור רשימת ה-releases והבדיקה החינמית /rate_limit. הכלי עדיין נושא שולף REST אנונימי ישן יותר שהריץ ייבוא של מאגר ציבורי בתוך תקציב 60 לשעה, אך שום נתיב ב-CLI אינו מגיע אליו עוד והוא מיועד למחיקה — לכן התייחסו ל---token כנדרש עבור direct.

האסימון המשותף של הפריסה

Section titled “האסימון המשותף של הפריסה”

אל תשלחו token והשרת ישתמש באסימון הפלטפורמה שמפעילה הגדיר (GITHUB_IMPORT_PAT). שלוש מגבלות נוסעות איתו:

  • זו הגדרה אופציונלית. השירות המתארח eastagiletracker.com מספק אחד, ולכן ייבוא של מאגר ציבורי ללא אסימון עובד שם. להתקנה עצמאית — הקובץ הבינארי שהורדתם — אין אף אחד עד שמפעילה מגדיר GITHUB_IMPORT_PAT בסביבה, ועד אז היא דוחה כל ייבוא ללא אסימון עם 400 import_github_no_token.
  • הוא קורא מאגרים ציבוריים בלבד. השירות המתארח מנפיק אותו לקריאה בלבד על מאגרים ציבוריים, ולכן מאגר פרטי תמיד צריך אסימון משלכם.
  • כל הקוראים בפריסה חולקים תקציב אחד. לפני שייבוא ללא אסימון רץ, השרת קורא את נקודות ה-GraphQL שנותרו לאסימון המשותף ודוחה עם 400 import_github_shared_quota_low מתחת ל-500. תקציב שנגמר באמצע הייבוא מכשיל את העבודה עם import_github_rate_limited_platform. שתי ההודעות נוקבות באותו פתרון: ספקו אסימון משלכם.

GitHub מודד את שני ה-APIs שלו בנפרד, ותקרת הלא-מאומת נמוכה בשני סדרי גודל.

API של GitHubמשמש לעם אסימוןבלעדיו
GraphQLissues, תגובות, pull requests, תת-issues, תלויות5,000 נקודות לשעה, נספרות לפי הצמתים שהשאילתה מחזירהנדחה — ל-GraphQL אין שכבה לא-מאומתת
RESTReleases (include_releases), והבדיקה המקדימה /rate_limit5,000 בקשות לשעה60 בקשות לשעה, נספרות לכל כתובת IP ומשותפות עם כל מי שמאחוריה

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

קראו את התקציב שנותר לכם בכל עת; GET /rate_limit פטור משתי המגבלות, ולכן הבדיקה אינה עולה דבר:

Terminal window
curl -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/rate_limit

נקודות GraphQL אינן בקשות. GitHub נותן ניקוד לשאילתה לפי הצמתים שהיא מחזירה, ולכן עמוד אחד של 100 issues עם התגובות והמשויכים שלהם עולה נקודות רבות, ומאגר גדול מוציא את התקציב השעתי בהרבה פחות קריאות ממה שמספרי עידן ה-REST מרמזים. --dry-run (שלב 3) ו-dry_run (שלב 4) עולים כל אחד את אותן נקודות כמו השליפה האמיתית — וזה מה שהופך את הספירות שלהם לאמינות — אז תכננו תקציב לשני מעברים כשאתם בודקים ייבוא גדול מראש.

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