Node.js و وب هوک های گیت هاب — راهنمای به روز رسانی پروژه ها از راه دور
زمانی که چند توسعهدهنده مشغول کار روی یک پروژه باشند، در حالتی که یکی از آنها کدی را به یک ریپازیتوری push کند و در همین حال فرد دیگری مشغول ویرایش نسخه قدیمی کد باشد، وضعیت ترسناکی پیش میآید. چنین خطاهایی زمانبر هستند و از این رو شایسته است که اسکریپتی راهاندازی کنیم تا همه ریپازیتوریها همواره بهروز باشند. از این روش میتوان در محیط production نیز برای ارسال hotfixها و یا دیگر تغییرات سریع بهره گرفت.
با این که برای حل این مشکل راهحلهای مختلفی وجود دارد؛ اما نوشتن یک اسکریپت سفارشی، گزینهای انعطافپذیر است که امکان سفارشیسازی در آینده را در اختیار ما قرار میدهد.
گیتهاب امکان پیکربندی وبهوک برای ریپازیتوری را فراهم ساخته است. وبهوکها رویدادهایی هستند که در موارد رخ دادن یک رویداد، درخواستهای خاص HTTP ارسال میکنند. برای مثال میتوانید از یک وبهوک برای اعلان زمان ایجاد درخواست pull یا push کد جدید استفاده کنید.
در این راهنما ما یک سرور Node.js طراحی میکنیم که به اعلانهای وبهوک گیتهاب گوش میدهد تا در مواردی که شما یا فرد دیگر کدی را به گیتهاب push میکند، متوجه شود. این اسکریپت به طور خودکار یک ریپازیتوری روی سرور راه دور را با جدیدترین نسخه از کد، بهروزرسانی کرده و نیاز به گزارشدهی به یک سرور برای pull کردن کامیتهای جدید را رفع میکند.
پیشنیازها
برای اجرای عملی این راهنما به موارد زیر نیاز دارید:
- یک سرور اوبونتو 16.04 که یک کاربر غیر root با دسترسی Sudo داشته و فایروالی روی آن پیکربندی شده باشد.
- میبایست Git روی رایانه محلی شما نصب شده باشد. میتوانید از این آموزش فرادرس برای نصب Git روی رایانه خود استفاده کنید.
- Node.js و npm را با استفاده از PPA رسمی روی سرور راه دور نصب کنید. نصب نسخه پایدار کافی است، زیرا نسخه پیشنهاد شده را بدون هیچ گونه پیکربندی اضافی در اختیار ما قرار میدهد.
- یک ریپازیتوری روی گیتهاب که شامل کد یک پروژه باشد. اگر پروژهای در ذهن ندارید، میتوانید این کد را فورک کنید.
مرحله 1: راهاندازی وبهوک
در ابتدا کار خود را با پیکربندی وبهوک برای ریپازیتوری آغاز میکنیم. این مرحله بسیار مهم است، زیرا بدون وجود چنین وبهوکی، گیتهاب نمیداند که باید چه رویدادی را اطلاعرسانی کند و یا این اعلان را به کجا ارسال کند.
وارد حساب گیتهاب خود شوید و به ریپازیتوری که میخواهید نظارت کنید مراجعه نمایید. بر روی برگه Settings در منوی فوقانی در صفحه ریپازیتوری کلیک کنید و سپس Webhook را در منوی سمت چپ انتخاب کنید. بر روی Add Webhook در منوی راست کلیک کنید و رمز حساب خود را در صورت نیاز وارد نمایید. در این مرحله با صفحهای مانند تصویر زیر مواجه خواهید شد:
- در فیلد Payload URL مقدار http://your_server_ip:8080 را وارد کنید. این همان آدرس و پورت سرور Node.js است که به زودی خواهیم دید.
- مقدار Content type را به صورت application/json تنظیم کنید. اسکریپتی که خواهیم نوشت، انتظار دریافت دادههای جیسون (JSON) را دارد و نوع دادههای دیگر را درک نمیکند.
- در فیلد Secret یک رمز عبور برای این وبهوک وارد نمایید. از این رمز در سرور Node.js برای اعتبارسنجی درخواستها استفاده میشود تا مطمئن شویم که درخواست واقعاً از سوی گیتهاب ارسال شده است.
- در مورد گزینه Which events would you like to trigger this webhook مقدار just the push event را انتخاب کنید. ما تنها به رویداد push نیاز داریم تا هر زمان که فردی کد را بهروزرسانی کرد و کد روی سرور همگامسازی شد، مطلع شویم.
- کادر انتخاب Active را تیک بزنید.
- در انتها فیلدها را یک بار دیگر مرور کرده و برای ایجاد وبهوک بر روی Add Webhook کلیک کنید.
در این مرحله پینگ ناموفق خواهد بود؛ اما مطمئن هستیم که از سمت گیتهاب کار پیکربندی وبهوک به پایان رسیده است. اینک نوبت آن رسیده است که ریپازیتوری خود را روی سرور کلون کنیم.
مرحله 2: کلون کردن ریپازیتوری به سرور
اسکریپت ما میتواند یک ریپازیتوری را بهروزرسانی کند؛ اما نمیتواند آن را در ابتدا راهاندازی نماید. از این رو این کار را در این مرحله به صورت دستی انجام میدهیم. بدین منظور وارد سرور خود شوید:
ssh sammy@your_server_ip
ابتدا اطمینان حاصل کنید که در دایرکتوری home سرور هستید. سپس از دستور Git برای کلون کردن ریپازیتوری استفاده کنید. در این مرحله باید مقدار Sammy را با نام کاربری گیتهاب و مقدار hello_hapi را با نام پروژه خود جایگزین کنید.
cd git clone https://github.com/sammy/hello_hapi.git
دستور فوق یک دایرکتوری جدید ایجاد میکند که حاوی پروژه شما است. از این ریپازیتوری در مرحله بعد استفاده خواهیم کرد. اینک که پروژه کلون شده، میتوانید اسکریپت وبهوک را بنویسید.
مرحله 3: ایجاد اسکریپت وبهوک
در این مرحله از سرور خود میخواهیم که به درخواستهای وبهوک ارسالی از گیتهاب گوش دهد. بدین منظور یک اسکریپت Node.js ایجاد میکنیم که یک وبسرور روی پورت 8080 راه میاندازد. این سرور به درخواستهای ارسالی از سوی وبهوک گوش میدهد، رمز آن را تأیید میکند و آخرین نسخه از کد را از گیتهاب pull میکند. به دایرکتوری home خود مراجعه کنید:
cd ~
یک دایرکتوری جدید برای اسکریپت وبهوک به نام NodeWerbhook ایجاد کنید:
mkdir ~/NodeWebhooks
سپس به دایرکتوری جدید وارد شوید:
cd ~/NodeWebhooks
درون دایرکتوری NodeWebhook یک فایل به نام webjook.js بسازید:
nano webhook.js
این دو خط کد را به اسکریپت اضافه کنید:
var secret = "your_secret_here"; var repo = "/home/sammy/hello_hapi";
در خط نخست یک متغیر ایجاد میکنیم که برای نگهداری رمزی (secret) که در مرحله اول ایجاد کردیم استفاده میشود. این رمز تأیید میکند که درخواستها از سوی گیتهاب ارسال شدهاند. خط دوم یک متغیر تعریف میکند که مسیر کامل ریپازیتوری روی دیسک محلی را که قرار است بهروزرسانی شود، نگهداری میکند. این مسیر باید به ریپازیتوری که در مرحله 2 ایجاد کردید اشاره بکند.
سپس خطوط کد زیر را اضافه میکنیم که کتابخانههای http و crypto را وارد اسکریپت ما میکند. از این کتابخانهها برای ایجاد یک وبسرور و سپس هش کردن رمز استفاده میکنیم و بدین ترتیب میتوانیم آن را با درخواست دریافتی از سوی گیتهاب مقایسه کنیم:
let http = require('http'); let crypto = require('crypto');
سپس کتابخانه child_process را در پروژه خود include میکنیم و بدین ترتیب میتوانیم دستورات پوسته (shell) را از درون اسکریپت اجرا کنیم:
const exec = require('child_process').exec;
در مرحله بعد، کد زیر را به اسکریپت اضافه میکنیم تا یک وبسرور جدید ایجاد کنیم که درخواستهای وبهوک گیتهاب را مدیریت کرده و در صورت وجود یک درخواست معتبر، یک نسخه جدید از کد را از سرور گیتهاب pull میکند.
http.createServer(function (req, res) { req.on('data', function(chunk) { let payload = JSON.parse(chunk.toString()); let sig = "sha1=" + crypto.createHmac('sha1', secret).update(chunk.toString()).digest('hex'); if (req.headers['x-hub-signature'] == sig) { exec('cd ' + repo + ' && git pull'); } }); res.end(); }).listen(8080);
رعایت موارد امنیتی
تابع ()http.createServer یک وبسرور را روی پورت 8080 راهاندازی میکند که به درخواستهای ورودی از گیتهاب گوش میدهد. به دلایل امنیتی بررسی میکنیم که رمز دریافتی همراه با درخواستهای گیتهاب، با رمزی که در مرحله 1 ایجاد کردیم یکسان باشد. این رمز در هدر x-hub-signature به صورت یک رشته با هش SHA1 درافت میشود. بدین ترتیب میتوانیم رمز خود را هش کرده و آن را با رمزی که گیتهاب برای ما ارسال میکند مقایسه کنیم.
اگر درخواست معتبر باشد، یک دستور shell اجرا میکنیم که ریپازیتوری محلی را با استفاده از git pull بهروزرسانی میکند. اسکریپت کامل به صورت زیر خواهد بود:
const secret = "your_secret_here"; const repo = "~/your_repo_path_here/"; const http = require('http'); const crypto = require('crypto'); const exec = require('child_process').exec; http.createServer(function (req, res) { req.on('data', function(chunk) { let payload = JSON.parse(chunk.toString()); let sig = "sha1=" + crypto.createHmac('sha1', secret).update(chunk.toString()).digest('hex'); if (req.headers['x-hub-signature'] == sig) { exec('cd ' + repo + ' && git pull'); } }); res.end(); }).listen(8080);
اگر راهنمای مقدماتی راهاندازی سرور را به درستی طی کرده باشید، میبایست برای ایجاد امکان ارتباط این وبسرور با دنیای بیرون، ترافیک روی پورت 8080 را باز کنید:
sudo ufw allow 8080/tcp
اینک که اسکریپتمان آماده شده است، باید اطمینان حاصل کنیم که به درستی عمل میکند یا نه.
مرحله 4: تست کردن وبهوک
ما میتوانیم وبهوک خود را با استفاده از node برای اجرای آن در خط فرمان تست کنیم. اسکریپت را آغاز کنید و این پروسه را در ترمینال به صورت باز رها کنید:
cd ~/NodeWebhooks nodejs webhook.js
به صفحه پروژه در گیتهاب مراجعه کنید. بر روی برگه Settings در نوار منوی فوقانی در صفحه ریپازیتوری کلیک کنید. سپس بر روی webhooks در منوی سمت چپ کلیک کنید. بر روی دکمه Edit در کنار وبهوک که در مرحله 1 ایجاد کردیم کلیک کنید. به سمت پایین بروید تا بخش Recent Deliveries را که در تصویر زیر نیز نمایش یافته است ببینید:
بر روی منوی سه نقطه (...) در سمت راست کلیک کنید تا دکمه Redeliver نمایش یابد. اینک که سرور Node در حال اجرا است، یک پاسخ موفق را مشاهده خواهید کرد. این مسئله از روی کد پاسخ 200 ok که پس از ارسال مجدد پینگ دریافت میشود، قابل تشخیص است.
اینک میتوانیم به مسیر خود ادامه دهیم و تلاش کنیم تا کاری کنیم که اسکریپت همواره در پسزمینه در حال اجرا باشد و در زمان بوت شدن سرور نیز آغاز شود. با استفاده از دکمه Ctrl+C، سرور وبهوک node متوقف میشود.
مرحله 5: نصب وبهوک به صورت یک سرویس Systemd
Systemd یک نرمافزاری مدیریت وظیفه در اوبونتو است که سرویسها را کنترل میکند. ما سرویسی راهاندازی خواهیم کرد که به ما امکان آغاز اسکریپت وبهوک در زمان بوت شدن رایانه و استفاده از دستورهای system برای مدیریت آن مانند هر سرویس دیگر را میدهد.
در ابتدا یک فایل سرویس جدید به صوت زیر ایجاد کنید:
sudo nano /etc/systemd/system/webhook.service
پیکربندیهای زیر را به فایل سرویس اضافه کنید. این تنظیمات به system میگوید که چگونه اسکریپت را اجرا کند. بدین ترتیب system میداند که کجا میتواند اسکریپت node را پیدا کند و توضیحات سرویس ما چیست. توجه داشته باشید که مقدار Sammy را با نام کاربری خود جایگزین کنید:
[Unit] Description=Github webhook After=network.target [Service] Environment=NODE_PORT=8080 Type=simple User=sammy ExecStart=/usr/bin/nodejs /home/sammy/NodeWebhooks/webhook.js Restart=on-failure [Install] WantedBy=multi-user.target
سرویس جدید را فعال کنید تا وقتی سیستم بوت میشود شروع به کار نماید:
sudo systemctl enable webhook.service
اینک میتوانید این سرویس را آغاز کنید:
sudo systemctl start webhook
برای این که مطمئن شویم سرویس آغاز به کار کرده است:
sudo systemctl status webhook
در خروجی زیر مشخص است که سرویس فعال شده است:
sudo systemctl status webhook
اینک میتوانید کامیتهای جدید خود را به ریپازیتوری گیتهاب push کنید و همزمان تغییرات را در سرور خود ببینید. بر روی رایانه دسکتاپ خود، ریپازیتوری را ببندید:
git clone https://github.com/sammy/hello_hapi.git
بر روی یکی از فایلهای ریپازیتوری تغییری ایجاد کنید. سپس این فایل را کامیت کرده و به گیتهاب push کنید:
git add index.js git commit -m "Update index file" git push origin master
بدین ترتیب وبهوک فعال شده و تغییراتی که در گیتهاب ایجاد شده را روی سرور شما نیز پیادهسازی میکند.
نتیجهگیری
شما در این نوشته موفق شدهاید یک اسکریپت Node.js بسازید که به طور خودکار کامیت های جدید را به یک ریپازیتوری راه دور توزیع میکند. شما میتوانید از این فرایند برای راهاندازی ریپازیتوریهای دیگری که میخواهید مورد نظارت قرار دهید استفاده کنید. حتی میتوانید آن را طوری پیکربندی کنید که در زمان push کردن ریپازیتوری، یک وبسایت یا اپلیکیشن را در محیط production توزیع کند.
اگر این نوشته مورد توجه شما قرار گرفته است، پیشنهاد میکنیم موارد زیر را نیز ملاحظه کنید:
- وب هوک (WebHook) چیست ؟ — به زبان ساده
- گیتهاب و نحوه ایجاد یک پروژه موفق در آن – به زبان ساده
- ابزارها و راهکارهای مدیریت وبسایتها
- آموزش گیت (Git) برای مدیریت نسخه توزیع شده
- ۷ مورد از بهترین جایگزینهای گیتهاب برای میزبانی پروژههای متن-باز
- Node.js و ابزارها و تکنیکها برای ساخت سرورهای قدرتمند و سریع
- مجموعه آموزش های طراحی و برنامه نویسی وب
==