أتمتة ملفك التعريفي على GitHub (README): دليلك لإنشاء محتوى ديناميكي
أحدثت ميزة ملف README التعريفي الجديدة على GitHub ثورة في طريقة عرض المطورين لملفاتهم الشخصية، مانحةً إياها لمسة فريدة وشخصية. فبينما يُعد تنسيق Markdown مثاليًا للمحتوى النصي الثابت، إلا أن المطورين المبدعين يسعون دائمًا لتجاوز هذا الحد لإنشاء ملفات README من مستوى آخر.
يمكنك بالطبع تضمين صور متحركة (GIFs) وصور لإضافة بعض الحيوية والجاذبية (وهي مدعومة بشكل ممتاز في GitHub Flavor Markdown)، ولكننا هنا نتحدث عن شيء أكثر ديناميكية بكثير. نظرًا لموقعه البارز في صفحتك الشخصية على GitHub، يمثل ملف README فرصة ذهبية لتعريف الآخرين بشغفك، اهتماماتك، وإبراز أبرز إنجازاتك ومشروعاتك.
قد ترغب في عرض أحدث مستودعاتك (repositories)، تغريداتك، أو مقالات مدونتك. والأهم من ذلك، أن الحفاظ على تحديث هذا المحتوى لا يجب أن يكون مهمة شاقة، وذلك بفضل أدوات التسليم المستمر (Continuous Delivery) مثل GitHub Actions. في هذا المقال، سنستعرض كيفية بناء ملف README.md ذاتي التحديث باستخدام لغة Go وGitHub Actions، مستلهمين من تجربة فيكتوريا دريك التي تقوم بتحديث ملفها يوميًا بأحدث منشورات مدونتها.
قراءة وكتابة الملفات باستخدام Go: بناء المحتوى الديناميكي
على الرغم من شيوع لغات برمجة مثل Python، إلا أن Go (أو Golang) تبرز كخيار ممتاز للمشروعات السريعة والموجهة نحو الأداء. في هذا الجزء، سنتعلم كيف نجمع بين المحتوى الثابت الموجود في ملف، ونضيف إليه محتوى ديناميكيًا نولده باستخدام Go، ثم ندمج كل ذلك لإنشاء ملف README.md متكامل.
قراءة المحتوى الثابت من ملف
للبدء، سنقوم بقراءة المحتوى الثابت من ملف موجود (مثل static.md) وتحويله إلى سلسلة نصية (string) يمكننا التعامل معها برمجيًا. إليك كيفية قراءة ملف وتخزينه في متغير:
// Unwrap Markdown content
content, err := ioutil.ReadFile("static.md")
if err != nil {
log.Fatalf("cannot read file: %v", err)
return err
}
// Make it a string
stringyContent := string(content)
يشرح هذا الجزء كيفية استخدام دالة ioutil.ReadFile() لقراءة محتويات الملف static.md. في حال وجود أي خطأ أثناء عملية القراءة، سيتم تسجيل الخطأ وإيقاف البرنامج. بعد القراءة بنجاح، يتم تحويل البايتات المقروءة إلى سلسلة نصية باستخدام string(content).
جلب المحتوى الديناميكي: أحدث منشورات المدونة
تتعدد إمكانيات المحتوى الديناميكي الذي يمكنك إضافته، والحد الوحيد هو خيالك! كمثال توضيحي، سنستخدم حزمة github.com/mmcdole/gofeed في Go لقراءة خلاصة RSS لمدونة معينة وجلب أحدث منشور فيها. هذا يتيح لنا عرض أحدث مقالاتك تلقائيًا في ملف README الخاص بك.
fp := gofeed.NewParser()
feed, err := fp.ParseURL("https://victoria.dev/index.xml")
if err != nil {
log.Fatalf("error getting feed: %v", err)
}
// Get the freshest item
rssItem := feed.Items[0]
يقوم الكود أعلاه بإنشاء محلل RSS جديد، ثم يستخدم دالة ParseURL() لجلب وتحليل خلاصة RSS من الرابط المحدد. بعد التحقق من عدم وجود أخطاء، يتم الوصول إلى أحدث عنصر في الخلاصة (المنشور الأخير) عبر feed.Items[0].
دمج المحتوى وكتابة ملف README.md
بعد الحصول على المحتوى الثابت والديناميكي، حان الوقت لدمجهما معًا لإنشاء السلسلة النصية النهائية التي ستمثل ملف README.md. سنستخدم دالة fmt.Sprintf() لتنسيق السلسلة النصية بشكل احترافي:
// Whisk together static and dynamic content until stiff peaks form
blog := "Read my latest blog post: **[" + rssItem.Title + "](" + rssItem.Link + ")**"
data := fmt.Sprintf("%s\n%s\n", stringyContent, blog)
هنا، يتم بناء رابط لأحدث منشور في المدونة، ثم يتم دمج المحتوى الثابت (stringyContent) مع رابط المدونة الديناميكي (blog) باستخدام فواصل أسطر لضمان تنسيق جيد.
أخيرًا، لإنشاء ملف جديد من هذا المزيج، سنستخدم دالة os.Create(). من المهم أيضًا استخدام defer file.Close() لضمان إغلاق الملف بعد الانتهاء من العمليات، وfile.Sync() لضمان كتابة جميع التغييرات إلى القرص.
// Prepare file with a light coating of os
file, err := os.Create("README.md")
if err != nil {
return err
}
defer file.Close()
// Bake at n bytes per second until golden brown
_, err = io.WriteString(file, data)
if err != nil {
return err
}
return file.Sync()
يقوم هذا الجزء بإنشاء ملف README.md، ويكتب البيانات المدمجة فيه، ثم يتأكد من مزامنة التغييرات. يمكنك الاطلاع على الكود الكامل لهذا الجزء في مستودع README الخاص بالمؤلفة.
جدولة تحديث ملف README باستخدام GitHub Actions
بعد أن قمنا ببناء البرنامج الذي يولد ملف README.md الديناميكي، حان الوقت لأتمتة عملية تشغيله. تتيح لنا GitHub Actions إنشاء مسارات عمل (workflows) تُشغل تلقائيًا عند وقوع أحداث معينة، مثل الدفع إلى فرع master أو على جدول زمني محدد.
تعريف مسار العمل (Workflow)
لإنشاء مسار عمل يقوم بتحديث ملف README يوميًا، ستحتاج إلى إنشاء ملف YAML في المسار .github/workflows/update.yaml. إليك جزء من هذا الملف يحدد متى سيتم تشغيل مسار العمل:
on:
push:
branches:
- master
schedule:
- cron: '0 11 * * *'
يحدد هذا التكوين أن مسار العمل سيتم تشغيله في حالتين: الأولى عند كل عملية دفع (push) إلى الفرع master، والثانية على جدول زمني يومي محدد باستخدام تعبير cron. في هذا المثال، '0 11 * * *' يعني التشغيل في تمام الساعة 11:00 صباحًا بالتوقيت العالمي المنسق (UTC) كل يوم.
خطوات تنفيذ البرنامج وتحديث المستودع
يتكون مسار العمل من عدة خطوات (steps) تُنفذ بالتسلسل. إليك الخطوات الأساسية لتشغيل برنامج Go وتحديث الملفات في مستودعك:
1. جلب نسخة العمل (Checkout)
أولاً، نحتاج إلى جلب نسخة من ملفات المستودع لكي يتمكن مسار العمل من الوصول إليها. نستخدم actions/checkout لهذا الغرض:
steps:
- name: ?️ Get working copy
uses: actions/checkout@master
with:
fetch-depth: 1
تقوم هذه الخطوة بجلب المستودع إلى بيئة GitHub Action. استخدام fetch-depth: 1 يضمن جلب أحدث نسخة فقط، مما يوفر الوقت والموارد.
2. تشغيل برنامج Go
الآن، حان وقت تشغيل برنامج Go الذي قمنا ببنائه لتوليد المحتوى الديناميكي وتحديث ملف README.md:
- name: ? Shake & bake README
run: |
cd ${GITHUB_WORKSPACE}/update/
go run main.go
تنتقل هذه الخطوة إلى الدليل الذي يحتوي على برنامج Go (نفترض أنه في update/ داخل مساحة العمل)، ثم تقوم بتشغيل الملف main.go.
3. نشر التغييرات إلى المستودع (Deploy)
بعد تحديث ملف README.md، نحتاج إلى دفع التغييرات مرة أخرى إلى المستودع ليتم عرضها. تتضمن هذه الخطوة إعداد معلومات المستخدم لـ Git، إضافة الملفات المعدلة، الالتزام بالتغييرات (commit)، ثم دفعها (push) إلى المستودع:
- name: ? Deploy
run: |
git config user.name "${GITHUB_ACTOR}"
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
git add .
git commit -am "Update dynamic content"
git push --all -f https://${{ secrets.GITHUB_TOKEN }}@github.com/${GITHUB_REPOSITORY}.git
تستخدم هذه الخطوة متغيرات بيئة GitHub Actions مثل GITHUB_ACTOR وGITHUB_REPOSITORY، بالإضافة إلى secrets.GITHUB_TOKEN للمصادقة الآمنة. يمكنك معرفة المزيد عن المتغيرات والأسرار في مسارات العمل من وثائق GitHub Actions. يمكنك الاطلاع على الكود الكامل لمسار العمل هذا في مستودع README الخاص بالمؤلفة.
الخلاصة التقنية: ملف README يتحدث عنك دائمًا
تهانينا! لقد أصبحت الآن جزءًا من “نادي المطورين الأذكياء” القادرين على بناء ملف README شخصي على GitHub يقوم بالتحديث الذاتي. هذه التقنية لا تقتصر فقط على عرض أحدث منشورات المدونة؛ بل تفتح الأبواب أمام إمكانيات لا حصر لها لإضافة عناصر ديناميكية جذابة إلى صفحتك.
من الناحية التقنية، يمثل هذا النهج دمجًا قويًا بين مرونة Go في معالجة البيانات وسهولة أتمتة المهام عبر GitHub Actions. يتيح لك هذا الحل الحفاظ على ملفك التعريفي حيويًا ومحدثًا باستمرار دون الحاجة إلى تدخل يدوي، مما يعكس احترافيتك ونشاطك كمطور.
يمكنك الآن المضي قدمًا في إضافة جميع أنواع العناصر الديناميكية الرائعة إلى صفحتك، مثل: أحدث المشاريع التي ساهمت فيها، الإحصائيات من حساباتك التقنية الأخرى، أو حتى اقتباسات ملهمة تتغير يوميًا. فقط تذكر، الاعتدال هو المفتاح، خاصة عند استخدام الصور المتحركة (GIFs) لضمان تجربة مستخدم سلسة.
إن القدرة على أتمتة هذه الجوانب تزيد من قيمة ملفك التعريفي، وتجعله أداة تسويقية شخصية فعالة تعرض مهاراتك وإنجازاتك بأسلوب مبتكر وديناميكي.