Skip to content

Files

308 lines (232 loc) · 21.3 KB

5-scripting.asc

File metadata and controls

308 lines (232 loc) · 21.3 KB

Scripting GitHub (اسکریپتنویسی در گیتهاب)

اکنون که تمام ویژگیها و جریانهای کاری اصلی گیتهاب را بررسی کردیم، اما هر گروه یا پروژه بزرگی ممکن است بخواهد سفارشیسازیهایی انجام دهد یا سرویسهای خارجی را به گیتهاب متصل کند.

خوشبختانه، گیتهاب به روشهای زیادی قابل هک و سفارشیسازی است. در این بخش، نحوه استفاده از سیستم hooks و API گیتهاب را بررسی میکنیم تا گیتهاب را مطابق نیاز خودمان تنظیم کنیم.

Services and Hooks (سرویسها و هوکها)

بخش Hooks و Services در مدیریت مخزن گیتهاب سادهترین راه برای تعامل گیتهاب با سیستمهای خارجی است.

Services (سرویس ها)

ابتدا نگاهی به سرویسها میاندازیم. هر دو نوع یکپارچهسازی Hooks و Services در بخش تنظیمات مخزن شما قابل دسترسی هستند، جایی که قبلاً درباره اضافه کردن همکاران و تغییر شاخه پیشفرض پروژه صحبت کردیم. در تب «Webhooks and Services» چیزی شبیه Services and Hooks configuration section. مشاهده خواهید کرد.

Services and hooks
Figure 1. Services and Hooks configuration section.

دهها سرویس مختلف وجود دارد که میتوانید از بین آنها انتخاب کنید، که بیشتر آنها یکپارچهسازی با سیستمهای تجاری و متنباز دیگر هستند. اکثر این سرویسها برای خدمات یکپارچهسازی پیوسته (Continuous Integration)، پیگیری باگ و مسائل (bug and issue trackers)، سیستمهای چت و سیستمهای مستندسازی استفاده میشوند. ما مراحل راهاندازی یک سرویس بسیار ساده را مرور میکنیم: هوک ایمیل (Email hook). اگر از منوی کشویی «Add Service»، گزینه «email» را انتخاب کنید، صفحه تنظیماتی مشابه Email service configuration. برای شما نمایش داده میشود.

Email service
Figure 2. Email service configuration.

در این حالت، اگر روی دکمه «Add service» کلیک کنیم، آدرس ایمیلی که مشخص کردهایم، هر بار که کسی به مخزن push انجام دهد، یک ایمیل دریافت خواهد کرد. سرویسها میتوانند به انواع مختلفی از رویدادها گوش دهند، اما بیشتر آنها فقط به رویدادهای push گوش میدهند و سپس با آن داده کاری انجام میدهند.

اگر از سیستمی استفاده میکنید که میخواهید آن را با گیتهاب یکپارچه کنید، بهتر است ابتدا بررسی کنید که آیا یکپارچهسازی از پیشساختهای (Service Integration) برای آن وجود دارد یا نه. برای مثال، اگر از Jenkins برای اجرای تستهای کد استفاده میکنید، میتوانید سرویس داخلی Jenkins را فعال کنید تا هر بار که کسی به مخزن شما push انجام داد، بهطور خودکار یک اجرای تست شروع شود.

Hooks (هوک ها)

اگر به چیزی خاصتر نیاز دارید یا میخواهید با سرویس یا سایتی یکپارچهسازی انجام دهید که در لیست سرویسهای موجود نیست، میتوانید از سیستم کلیتر هوکها (Hooks) استفاده کنید. هوکهای مخزن گیتهاب بسیار ساده هستند. شما یک آدرس URL مشخص میکنید و گیتهاب در رویدادهایی که انتخاب کردهاید، یک محتوای HTTP (payload) به آن آدرس ارسال میکند.

بهطور کلی، روش کار اینگونه است که یک سرویس وب کوچک راهاندازی میکنید تا به محتوای ارسالشده از گیتهاب گوش دهد و سپس با دادهی دریافتی کاری انجام دهد.

برای فعالسازی یک هوک، روی دکمه «Add webhook» در بخش Services and Hooks configuration section. کلیک کنید. این کار شما را به صفحهای هدایت میکند که شبیه به Web hook configuration. خواهد بود.

Web hook
Figure 3. Web hook configuration.

پیکربندی یک وبهوک (web hook) نسبتاً ساده است. در اغلب موارد، فقط کافی است یک URL و یک کلید امنیتی (secret key) وارد کرده و روی «Add webhook» کلیک کنید. چند گزینه وجود دارد که مشخص میکند گیتهاب برای چه رویدادهایی باید payload ارسال کند — بهصورت پیشفرض، فقط در زمان رخداد push (یعنی زمانی که کسی کدی را به هر شاخهای از مخزن شما push میکند) payload دریافت میشود.

بیایید یک مثال کوچک از یک سرویس وب ببینیم که ممکن است برای مدیریت یک web hook تنظیم کرده باشید. ما از فریمورک Ruby به نام Sinatra استفاده میکنیم چون بسیار مختصر است و بهراحتی میتوانید متوجه شوید که چه کاری انجام میدهد.

فرض کنیم میخواهیم هر زمان که یک شخص خاص، به شاخهای خاص از پروژه کدی push کند که فایل مشخصی را تغییر داده، یک ایمیل دریافت کنیم. میتوانیم این کار را با کدی شبیه به این، نسبتاً راحت انجام دهیم:

require 'sinatra'
require 'json'
require 'mail'

post '/payload' do
  push = JSON.parse(request.body.read) # parse the JSON

  # gather the data we're looking for
  pusher = push["pusher"]["name"]
  branch = push["ref"]

  # get a list of all the files touched
  files = push["commits"].map do |commit|
    commit['added'] + commit['modified'] + commit['removed']
  end
  files = files.flatten.uniq

  # check for our criteria
  if pusher == 'schacon' &&
     branch == 'ref/heads/special-branch' &&
     files.include?('special-file.txt')

    Mail.deliver do
      from     'tchacon@example.com'
      to       'tchacon@example.com'
      subject  'Scott Changed the File'
      body     "ALARM"
    end
  end
end

در اینجا، ما محتوای JSON که گیتهاب برای ما ارسال میکند را میگیریم و بررسی میکنیم که چه کسی push انجام داده، روی کدام شاخه (branch) این کار انجام شده و چه فایلهایی در تمام commitهای ارسالشده تغییر کردهاند. سپس این اطلاعات را با معیارهایی که مشخص کردهایم مقایسه میکنیم و اگر مطابقت داشتند، یک ایمیل ارسال میکنیم.

برای توسعه و تست چنین چیزی، گیتهاب یک کنسول توسعهدهنده مفید در همان صفحهای که هوک را تنظیم کردهاید ارائه میدهد. شما میتوانید آخرین ارسالهایی (delivery) که گیتهاب برای آن وبهوک انجام داده را مشاهده کنید. برای هر هوک، میتوانید جزئیاتی مثل زمان ارسال، موفقیت یا شکست بودن آن، محتوای درخواست (Request) و پاسخ (Response) بههمراه هدرهایشان را ببینید.

این ویژگی باعث میشود تست و اشکالزدایی (debug) هوکهای شما بسیار ساده و سریع انجام شود.

Webhook debug
Figure 4. Web hook debugging information.

ویژگی فوقالعاده دیگر این است که میتوانید هر یک از payloadهایی که قبلاً ارسال شدهاند را مجدداً ارسال (redeliver) کنید تا سرویس خود را بهراحتی تست کنید.

برای اطلاعات بیشتر درباره نحوه نوشتن webhook و انواع مختلف رویدادهایی که میتوانید به آنها گوش دهید، به مستندات توسعهدهندگان گیتهاب در این آدرس مراجعه کنید: https://developer.github.com/webhooks/

The GitHub API (API گیتهاب)

سرویسها و هوکها این امکان را به شما میدهند که نوتیفیکیشنهایی دربارهی رویدادهای رخداده در مخازنتان دریافت کنید؛ اما اگر به اطلاعات بیشتری درباره این رویدادها نیاز داشته باشید چه؟ یا اگر بخواهید کارهایی مثل افزودن همکار (collaborator) یا برچسبگذاری روی issues را بهصورت خودکار انجام دهید چه؟

اینجاست که GitHub API به کارتان میآید. گیتهاب تعداد زیادی API endpoint دارد که تقریباً هر کاری که روی وبسایت میتوانید انجام دهید را، بهشکل خودکار ممکن میسازد.

در این بخش یاد میگیریم چطور به API گیتهاب احراز هویت و اتصال برقرار کنیم، چگونه روی یک issue نظر (comment) بگذاریم و چطور وضعیت یک Pull Request را از طریق API تغییر دهیم.

Basic Usage (استفاده پایه ایی)

پایهایترین کاری که میتوان انجام داد، یک درخواست GET ساده به یک endpoint است که نیازی به احراز هویت ندارد. این میتواند اطلاعات مربوط به یک کاربر یا دادههای فقطخواندنی (read-only) درباره یک پروژه متنباز باشد.

برای مثال، اگر بخواهیم درباره کاربری به نام schacon اطلاعات بیشتری بهدست آوریم، میتوانیم چیزی شبیه به این اجرا کنیم:

$ curl https://api.github.com/users/schacon
{
  "login": "schacon",
  "id": 70,
  "avatar_url": "https://avatars.githubusercontent.com/u/70",
# 
  "name": "Scott Chacon",
  "company": "GitHub",
  "following": 19,
  "created_at": "2008-01-27T17:19:28Z",
  "updated_at": "2014-06-10T02:37:23Z"
}

تعداد زیادی endpoint مانند این وجود دارد که میتوانید از آنها برای دریافت اطلاعات درباره سازمانها، پروژهها، issues، commit ها و تقریباً هر چیزی که بهصورت عمومی در گیتهاب قابل مشاهده است، استفاده کنید. حتی میتوانید با استفاده از API، محتوای Markdown دلخواه را رندر (render) کنید یا یک قالب .gitignore مناسب پیدا کنید.

$ curl https://api.github.com/gitignore/templates/Java
{
  "name": "Java",
  "source": "*.class

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear

# virtual machine crash logs, see https://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
"
}

Commenting on an Issue (نوشتن نظر روی یک Issue)

با این حال، اگر بخواهید کاری در خود وبسایت انجام دهید — مثلاً نوشتن نظر روی یک Issue یا Pull Request — یا اگر بخواهید به محتوای خصوصی (Private) دسترسی داشته باشید یا با آن تعامل کنید، لازم است احراز هویت انجام دهید.

چندین روش برای احراز هویت وجود دارد. میتوانید از احراز هویت پایه فقط با نام کاربری و رمز عبور استفاده کنید، اما معمولاً بهتر است از یک توکن دسترسی شخصی استفاده کنید. میتوانید این توکن را از بخش «Applications» در صفحه تنظیمات خود ایجاد کنید.

Access Token
Figure 5. Generate your access token from the ``Applications'' tab of your settings page.

از شما میپرسد که برای این توکن چه دسترسیهایی (scopes) میخواهید و یک توضیح وارد کنید. حتماً از توضیح خوبی استفاده کنید تا وقتی که دیگر نیازی به اسکریپت یا برنامهتان ندارید، بتوانید با اطمینان توکن را حذف کنید.

گیتهاب تنها یک بار این توکن را به شما نشان میدهد، پس حتماً آن را کپی کنید. حالا میتوانید از این توکن برای احراز هویت در اسکریپت خود استفاده کنید، به جای نام کاربری و رمز عبور. این روش خوب است چون میتوانید محدوده دسترسیها را محدود کنید و توکن قابلیت لغو شدن دارد.

همچنین این روش مزیت دیگری هم دارد: افزایش محدودیت درخواستها. بدون احراز هویت، محدودیت شما ۶۰ درخواست در ساعت است. اما اگر احراز هویت کنید، میتوانید تا ۵۰۰۰ درخواست در ساعت ارسال کنید.

پس بیایید از این توکن استفاده کنیم تا یک نظر روی یکی از مسئله هایمان ثبت کنیم. فرض کنیم میخواهیم یک نظر روی مسئله خاصی، یعنی مسئله شماره ۶، بگذاریم. برای این کار باید یک درخواست HTTP از نوع POST به آدرس repos/<user>/<repo>/issues/<num>/comments ارسال کنیم، که در آن به جای <user>، <repo> و <num> مقادیر مناسب قرار میگیرند، و توکنی که ساختیم را به عنوان هدر Authorization بفرستیم.

$ curl -H "Content-Type: application/json" \
       -H "Authorization: token TOKEN" \
       --data '{"body":"A new comment, :+1:"}' \
       https://api.github.com/repos/schacon/blink/issues/6/comments
{
  "id": 58322100,
  "html_url": "https://github.com/schacon/blink/issues/6#issuecomment-58322100",
  ...
  "user": {
    "login": "tonychacon",
    "id": 7874698,
    "avatar_url": "https://avatars.githubusercontent.com/u/7874698?v=2",
    "type": "User",
  },
  "created_at": "2014-10-08T07:48:19Z",
  "updated_at": "2014-10-08T07:48:19Z",
  "body": "A new comment, :+1:"
}

حالا اگر به آن مسئله مراجعه کنید، میتوانید نظری که همین الان با موفقیت ثبت کردیم را ببینید، مشابه چیزی که در A comment posted from the GitHub API. نشان داده شده است.

API Comment
Figure 6. A comment posted from the GitHub API.

شما میتوانید با استفاده از API تقریباً هر کاری که روی وبسایت انجام میدهید را انجام دهید — از ایجاد و تنظیم مایلستون ها، اختصاص دادن افراد به Issues و Pull Requests، ساخت و تغییر لیبل ها، دسترسی به داده های کامیت، ایجاد کامیت ها و شاخه های جدید، باز و بسته کردن یا ادغام Pull Requests، ایجاد و ویرایش تیمها، نظر دادن روی خطوط کد در یک Pull Request، جستجو در سایت و بسیاری کارهای دیگر. ==== Changing the Status of a Pull Request

یک مثال نهایی داریم که خیلی مفید است اگر با Pull Request ها کار میکنید. هر کامیت میتواند یک یا چند وضعیت (status) مرتبط با خودش داشته باشد و یک API وجود دارد که بتوانید این وضعیتها را اضافه یا بررسی کنید.

بیشتر سرویسهای تست و ادغام پیوسته (Continuous Integration) از این API استفاده میکنند تا پس از هر پوش، کد را تست کنند و نتیجه را گزارش دهند که آیا کامیت تمام تستها را گذرانده یا نه. شما هم میتوانید از این API استفاده کنید تا بررسی کنید آیا پیام کامیت به درستی فرمت شده، ارسالکننده قوانین مشارکت شما را رعایت کرده، امضای کامیت معتبر است یا نه — هر تعداد بررسی دیگر.

فرض کنید یک وبهوک (webhook) روی مخزن خود تنظیم کردهاید که به یک سرویس وب کوچک متصل میشود و در پیام کامیت به دنبال عبارت Signed-off-by میگردد.

require 'httparty'
require 'sinatra'
require 'json'

post '/payload' do
  push = JSON.parse(request.body.read) # parse the JSON
  repo_name = push['repository']['full_name']

  # look through each commit message
  push["commits"].each do |commit|

    # look for a Signed-off-by string
    if /Signed-off-by/.match commit['message']
      state = 'success'
      description = 'Successfully signed off!'
    else
      state = 'failure'
      description = 'No signoff found.'
    end

    # post status to GitHub
    sha = commit["id"]
    status_url = "https://api.github.com/repos/#{repo_name}/statuses/#{sha}"

    status = {
      "state"       => state,
      "description" => description,
      "target_url"  => "http://example.com/how-to-signoff",
      "context"     => "validate/signoff"
    }
    HTTParty.post(status_url,
      :body => status.to_json,
      :headers => {
        'Content-Type'  => 'application/json',
        'User-Agent'    => 'tonychacon/signoff',
        'Authorization' => "token #{ENV['TOKEN']}" }
    )
  end
end

امیدوارم این موضوع تا اینجا نسبتاً ساده و قابل دنبال کردن باشد. در این پردازشگر وبهوک، هر کامیتی که تازه پوش شده را بررسی میکنیم، دنبال عبارت «Signed-off-by» در پیام کامیت میگردیم و در نهایت یک درخواست HTTP از نوع POST به آدرس /repos/<user>/<repo>/statuses/<commit_sha> ارسال میکنیم تا وضعیت مربوطه را ثبت کنیم.

در این درخواست میتوانید یک حالت (state) مثل success (موفق)، failure (شکست) یا error (خطا) بفرستید، همچنین توضیحی درباره آنچه اتفاق افتاده، یک URL مقصد که کاربر بتواند برای اطلاعات بیشتر به آن مراجعه کند و یک context که وقتی چند وضعیت مختلف برای یک کامیت وجود دارد، بتوان آنها را از هم تفکیک کرد. برای مثال، یک سرویس تست ممکن است یک وضعیت ارسال کند و یک سرویس اعتبارسنجی هم وضعیت دیگری ارائه دهد — فیلد «context» به تفکیک آنها کمک میکند.

اگر کسی یک Pull Request جدید روی گیتهاب باز کند و این وبهوک فعال باشد، ممکن است چیزی شبیه Commit status via the API. ببینید.

Commit status
Figure 7. Commit status via the API.

حالا میتوانید یک علامت کوچک تیک سبز کنار کامیتی که در پیامش عبارت «Signed-off-by» وجود دارد ببینید، و یک ضربدر قرمز روی کامیتی که نویسنده فراموش کرده امضا کند. همچنین میبینید که وضعیت Pull Request بر اساس آخرین کامیت روی شاخه تعیین میشود و اگر وضعیت آن شکست باشد، به شما هشدار میدهد. این موضوع خیلی کاربردی است اگر از این API برای نتایج تستها استفاده کنید تا به صورت تصادفی چیزی که آخرین کامیتش تستها را رد کرده، ادغام نشود.

Octokit

با اینکه در این مثالها تقریباً همه چیز را با curl و درخواستهای ساده HTTP انجام دادهایم، چندین کتابخانه متن باز وجود دارد که این API را به روشی طبیعیتر و رایجتر برای زبانهای برنامه نویسی مختلف در دسترس قرار میدهند. در زمان نگارش این متن، زبانهای پشتیبانی شده شامل Go، Objective-C، Ruby و .NET هستند. برای اطلاعات بیشتر میتوانید به https://github.com/octokit مراجعه کنید؛ این کتابخانهها بخش زیادی از کارهای مربوط به HTTP را برای شما مدیریت میکنند.

امیدوارم این ابزارها به شما کمک کنند تا گیتهاب را بهتر و متناسب با جریان کاری خاص خودتان سفارشی و بهینه کنید. برای مستندات کامل API و راهنمایی در انجام کارهای رایج، به https://developer.github.com مراجعه کنید.