צ'קליסט CI לפרויקט
בכל פעם שאני מתחיל פרויקט חדש, אישי או של העבודה, אני צריך להיזכר מחדש איזה בדיקות וכלים אני נוהג להוסיף, תלוי בשפה של הפרויקט, בצרכים שלו והאם הוא אישי או ארגוני.
אז הנה רשימה של כלים ובדיקות להוסיף לפרויקט חדש.
תשלחו לי כלים שאתם משתמשים בהם ואני אוסיף אותם לרשימה.
Git Hooks
בפרויקטים של JavaScript אני מוסיף את husky שמאפשר לי להגדיר Git hooks (כלומר פקודות שירוצו לפני\אחרי commit/push וכו'), ובעזרתו אני יכול לחסוך למפתח טעויות פשוטות שאחרת הוא יגלה רק כשהוא יפתח PR.
את husky אני משלב עם lint-staged שמאפשר לי למנוע מהמפתח לקבל שגיאות שלא נגרמו על ידו, ולהריץ את הבדיקות רק על הקוד שהוא מבקש להכניס.
בשלב הזה אני מריץ את הכלים הפשוטים שחוסכים לכולנו כאב ראש:
- Linting (ESLint, Stylelint)
- Type Checking (TypeScript)
- Pretty Formatting (Prettier)
וזה נראה כך:
# package.json
"lint-staged": {
"**/*": "prettier --write --ignore-unknown",
"{src,tests}/**/*.js": "eslint --fix"
}
# .husky/pre-commit
#!/bin/sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
Pull Request Validation
כאן לא מדובר בכלים ספציפיים, אלא בפעולות שכדאי להוסיף עוד בשלב הPull Request כדי לחסוך הערות מיותרות בסקירה, וגם כדי לזהות בהקדם בעיות שעלולות לצוץ בענף הראשי:
- Linting (golangci-lint, ESLint, Stylelint,
go mod tidy
) (ולא לשכוח לחפש פורמט של Github, למשלstylelint --formatter=github
או @jamesacarr/eslint-formatter-github-actions) - Type Checking
- Unit Tests
- Build (bundle, compile, Docker)
דוגמא מפרויקט כספיון (TypeScript)
דוגמא מפרויקט 2ms (Go)
_ולא לשכוח להשתמש בmerge_group
lockfile-lint
[JavaScript/TypeScript]
בפרויקטים של JS, החבילות מותקנות על פי מה שכתוב בקובץ lock (package-lock.json
/yarn.lock
), ולכן חשוב לוודא שהקובץ הזה תקין ולא נערך בצורה לא צפויה, מכיוון שתוקף יכול לשנות את הרישום של אחת החבילות בקובץ, ואנחנו לא נשים לב, כי מי מסתכל על הקובץ הזה בכלל?
new-dependencies-advisor
[JavaScript/TypeScript]
כלי שמתריע על תלות חדשה שנוספת לפרויקט בקוד הנוכחי, ומציג את הציון והפידבק של Snyk Advisor על החבילה החדשה.
gosec
[Go]
כלי בדיקת אבטחה לGo.
כלי אבטחה אני מריץ בכמה הזדמנויות. קודם כל בשלב הPull Request כמובן, כדי לוודא שלא מכניסים בעיות אבטחה חדשות. אבל מכיוון שכלי אבטחה חייבים להתעדכן עם הזמן, אני מריץ אותם באופן קבוע (אחת ליום או לשבוע) גם על הענף הראשי, כדי לוודא שלא צצו בעיות אבטחה חדשות.
Kics
Kics הוא מנוע לזיהוי חולשות אבטחה בInfrastructure as Code. כמעט בכל פרויקט יש לפחות קובץ Dockerfile, וKics סורק אותו למציאת בעיות פוטנציאליות.
PR title
אני משתדל להקפיד על Conventional Commits כמו שנראה בהמשך, ולכן אני מוסיף בדיקה שהכותרת של הPR עומדת בקונבנציה. בדרך כלל אני נעזר בcommitlint בשביל לבדוק.
name: Validate Conventional Commit title
on:
pull_request:
types: [opened, edited, synchronize, reopened]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: install commitlint
run: npm install -g @commitlint/cli @commitlint/config-conventional
- name: config commitlint
run: |
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
- name: validate PR title
run: |
echo ${{ github.event.pull_request.title }} | commitlint
את הבדיקה הזאת צריך לתמוך על ידי ההגדרה שהכותרת של הPR תהיה גם ההודעה בcommit:
CI
אז מעבר לפעולות הברורות מאליהן של העלאת חבילה לnpm, עדכון האתר או Dockerhub, יש כמה פעולות נוספות שאני מבצע.
בעקרון רציתי לנצל את ההזדמנות לבדוק את פרויקט allero שעושה ולידציה על הCI, אבל ראיתי שהוא לא מתוחזק אז ויתרתי.
Semantic Release
כדי לשמור על עקרונות semver, אני משתמש בכלי שנקרא semantic-release, ועל פי הפורמט של הקומיטים (שתואר בPR Title למעלה), מעדכן את מספר הגרסה ויוצר גרסה.
מצד אחד מדובר בכלי מדהים, הוא יודע כמעט בלי הגדרות מיוחדות ליצור Github Release, להעלות לnpmjs.org, ליצור changelog ולכתוב בתגובה לIssues/Pull Requests שהם נכללו בגרסה האחרונה.
הבעיה שלי אם הכלי הזה היא שברגע שאני רוצה להתאים אותו לצרכים שלי, אם אני רוצה לשנות את הפורמט של התיאור של הגרסה, או להיעזר בו ליצירת גרסה זמנית שאני מעלה אליה קבצים, אני תמיד מסתבך ומבזבז על זה הרבה זמן.
ניהול פרויקט ואינטגרציות
פינוי משימות וPull Requests שנשכחו
כמנהל פרויקט קוד פתוח, קורה לי הרבה שבאים אנשים ומציעים לי תרומת קוד, ובתהליך הReview הם נשברים או סתם נהיים עסוקים, ולא משלימים את העבודה.
קורה גם לפעמים שיש לי הערות שאולי קשה לי להסביר אבל קל לי מאוד לבצע.
התוצאה של הסיבות הללו היא שבסופו של דבר יש Pull Request שלא קורה איתו כלום שבוע, או שיותר גרוע, אני חסר סבלנות ואני לוקח למישהו Pull Request ומשלים אותו.
בשביל להימנע מהמבוכה הזאת, אני מבצע כמה פעולות.
השמה אוטומטית של Pull Request
ברגע שמישהו פותח PR, אני אוטומטית assign עליו את הPR. זה יעזור לי בהמשך כפי שתראו.
assign-author:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request_target'
steps:
- uses: toshimaru/auto-author-assign@v1.6.2
התראה על Pull Request לא פעיל
יש Github Action רשמי של Github שעוזר לנו לנהל stale issues. אני משתמש בו עם פרמטרים מאוד מסוימים כדי למצוא Issues/PRs שלא פעילים כמה ימים, ואז אני כותב בהם הודעה שקוראת למפתח לעדכן מה הסטטוס, ואני מוסיף תגית מיוחדת.
הורדת משימה ממפתח
בצורה אוטומטית אני עובר על הIssues/PRs שסומנו קודם לכן בתגית המיוחדת, ואם לא התבצעה בהם פעולה בימים האחרונים (מאז ששמתי את התגית), אני מוריד מהם את הassign, ובעצם מסמן שאפשר לקחת אותם ולהמשיך את העבודה שמישהו אחר עשה.
comment-on-possible-stale-issues:
# This job uses the stale action to find inactive assigned issues and pull requests,
# and comments on them to remind the assignee to take action.
# If the assignee does not take action, the another action will unassign them.
name: Comment on possible stable issues
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v8
with:
include-only-assigned: true
exempt-assignees: "baruchiro"
days-before-stale: 7
days-before-close: -1 # Never close an issue/pr
stale-issue-message: "Hey! This task was taken over a few days ago, but nothing has happened since then. Maybe the current contributor can comment on this?"
stale-pr-message: "Hey! This pull request was made a few days ago and still needs changes, but nothing has happened since then. Maybe the current contributor can comment on this?"
stale-issue-label: "Waiting for contributor"
stale-pr-label: "Waiting for contributor"
exempt-issue-labels: "on hold"
exempt-pr-labels: "on hold"
remove-stale-when-updated: true
- uses: boundfoxstudios/action-unassign-contributor-after-days-of-inactivity@1.0.2
with:
last-activity: 7
labels: "Waiting for contributor"
exempt-assignees: "baruchiro"
labels-to-remove: "Waiting for contributor"
message: "Due to a long period of inactivity, this task was unassigned automatically."
Community tag
בפרק 19 של הפודקאסט "קוד פתוח", ליזה כץ אומרת שבמבט לאחור, באלסטיק היו צריכים לסמן איזה קוד הגיע מתורמים חיצוניים, מכיוון שבגיטאהב אין את המידע הזה.
אצלנו באחד הפרויקטים התחלנו מהיום הראשון לסמן PRים שמגיעים מבחוץ:
- name: Mark as Community if PR is from a fork
if: github.event.pull_request.head.repo.full_name != github.repository
uses: actions/github-script@v6
with:
script: |
github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ['Community']
})
Notify Discord
בימים שעוד היה API פתוח לטוויטר, הייתי שולח לשם, אבל בימינו שטוויטר מתחיל להיסגר, ודיסקורד מתחיל לעלות, אני מעוניין לשלוח עדכונים מסוימים לערוצים מסוימים.
למשל, לשלוח הודעות על גרסה חדשה שיוצאת, כמובן. בנוסף, בשביל ערוצי קוד פתוח, אני שולח good first issues חדשים שנפתחים.
בדיסקורד זה מאוד פשוט, יוצרים Webhook ושולחים אליו הודעה.
- name: Notify Discord
if: ${{ steps.semantic_release_info.outputs.git_tag }}
run: |
curl -X POST -H "Content-Type: application/json" -d "{\"content\": \"$msg\"}" ${{ secrets.DISCORD_CHECKMARX_WEBHOOK }}
curl -X POST -H "Content-Type: application/json" -d "{\"content\": \"$msg\"}" ${{ secrets.DISCORD_MAAKAF_WEBHOOK }}
curl -X POST -H "Content-Type: application/json" -d "{\"content\": \"$msg\"}" ${{ secrets.DISCORD_SCAR_WEBHOOK }}
env:
msg: 'Yay! 🎉 \n Version ${{ steps.semantic_release_info.outputs.version }} was released! \n Check it out in: ${{ steps.upload_artifacts.outputs.url }}'
דוגמא מפרויקט Overlay (הודעה על good first issue
)
Badges
עוד אין לי רשימה, זה בטח גם תלוי בכלים שאני משתמש בהם.
תוספות מתגובות לפוסט
ישראל המליץ בטוויטר על cookiecutter, כלי ליצירת Templates לפרויקטים. האמת שנראה טוב ואני מקווה שביום שאני אצור פרויקט לשימוש חוזר אני אשתמש בזה (אם כי אני כבר חושב שאולי זה מוגבל רק לvariables ולא לרמה של איזה קבצים לכלול בפרויקט, אבל לא קראתי את כל התיעוד)
מענדי המליץ בטוויטר על ts-reset
, זאת חבילה שקצת מתקנת Types של TypeScript. אני שומר את זה פה אבל זה כנראה שייך לפוסט מעט דומה על כלים לעבודה על פרויקטים (כאן אנחנו מתמקדים בCI)
מענדי המליץ גם על sync-dotenv
להוספה לpre-commit
Git Hook שתיארתי למעלה. המטרה של הכלי הזה היא לוודא שרשימת משתני הסביבה בקובץ .env.example
תואמת לרשימה שיש לנו ב.env
(שכמובן לא נכנס לGit)