تكامل Python لـ Gitlab و Jira و Confluence لأتمتة إصدارات الإصدار

في الآونة الأخيرة ، في حالة الوقوف ، قدم زميل اقتراحًا عقلانيًا : لأتمتة تجميع الإصدارات ، مع الأخذ في الاعتبار الممارسات الجاهزة بالفعل للتفاعل مع Jira ، المكتوبة في Python.

تكون عملية النشر كما يلي: عندما يتراكم عدد كافٍ من المهام التي تم اختبارها ، يتم إطلاق مرشح مرشح (RC) في كل مشروع يتأثر بالمهام ، ثم يتم اختبار المهام كجزء من RC. بعد ذلك ، يتم سكب RC على خادم التدريج ، حيث ، على مقربة شديدة من بيئة القتال ، لا يزال يتم اختباره ويتم تنفيذ الانحدار الكامل. وبعد ذلك ، بعد إجراءات النشر اللازمة ، يتم سكب الإصدار الجديد في الرئيسي.

حتى وقت قريب ، تم تنفيذ عملية التجميع بالكامل يدويًا من قبل أحد المطورين. استغرق الأمر ساعة أو ساعتين أو أكثر ، ويبدو لي أنه ليس مهنة مثيرة للاهتمام. الآن ، عندما يكون كل شيء جاهزًا تقريبًا ، فإن إصدار 20 مهمة ، مما يؤثر على 5 مشاريع ، سيقل إلى أقل من دقيقة. لا يزال هناك ، بالطبع ، حل للنزاعات ، وإجراء اختبارات فائتة ، وأكثر من ذلك ، ولكن حتى مع مراعاة هذا ، فإن وقت المطورين والمختبرين ، الذين يضطرون إلى الانتظار حتى يكون شخص ما هو أول من حرروا أنفسهم ويخلقون RC ، يتم حفظه كثيرًا.

بشكل عام ، بدأت المهمة ، وتبين أنها مثيرة للاهتمام ورائعة للغاية. وماذا هناك غير ذلك من أجل متعة العمل ، إن لم يكن المشاريع المثيرة؟

لقد درست الإرث: اتضح استخدام واجهة برمجة تطبيقات Jira بشكل مباشر ، وقد تمت كتابتها ، وبدا لي ، وليس الأمثل. على سبيل المثال ، تم الحصول على قائمة مهام الإصدار على النحو التالي: تم تنزيل جميع الإصدارات الحالية من Jira ، ثم تمت مقارنة كل منها بالاسم باسم إصدارنا حتى تم العثور على الإصدار المطلوب:

def get_release_info(config):

   try:

       release_input = sys.argv[1]

   except IndexError:

       raise Exception('Enter release name')

   releases_json = requests.get(url=RELEASES_LIST_URL, auth=(login, jira_password).json()

   for release in releases_json:

       if release['name'] == release_input:

                ...


بشكل عام ، يؤدي التفاعل المباشر مع واجهة برمجة التطبيقات إلى رمز غير قابل للقراءة للغاية. ولا أريد اختراع دراجة. قادني بحثي الأول على Github إلى مكتبة JIRA Python Library ، وهي مكتبة بسيطة وقوية إلى حد ما. خططت في البداية لإنشاء طلبات Marge باستخدام مكتبة GitPython ، الموجودة أيضًا على Github. ولكن أدت دراسة أخرى للمسألة على الفور إلى فكرة العثور على شيء لا يتعلق بـ git ، بل على الفور بـ Gitlab. ونتيجة لذلك ، استقرت على الحل الأكثر شهرة: Python GitLab.

لقد بدأت بالحصول على قائمة المهام في الحالة المناسبة للإصدار . قررت عدم تغيير الحل السابق بشدة ، ولكن لجعله أكثر فعالية من خلال طلب واجهة برمجة التطبيقات لمهمة الإصدار المطلوب على الفور:

fix_issues = jira.search_issues(f'fixVersion={release_input}')

fix_id = jira.issue(fix_issues.iterable[0]).fields.fixVersions[0].id

على الرغم من أن الشيء نفسه على الأرجح يحدث تحت غطاء المحرك ، إلا أنه تبين أنه أكثر جمالًا وأفضل ، ولكنه لا يزال غير قابل للقراءة للغاية. علاوة على ذلك ، من المهام المستلمة ، من الضروري جمع الروابط لدمج الطلبات. قررت تخزين طلبات الدمج التي تم العثور عليها في اسم tuple ، فهي رائعة لهذا:

Merge_request = namedtuple('Merge_request', ['url', 'iid', 'project', 'issue'])

تم تلقي طلبات الدمج أيضًا باستخدام واجهة برمجة تطبيقات Jira:

projects = set()

links_json = requests.get(url=REMOTE_LINK.format(issue_number),

                            auth=login,jira_password).json()

for link in links_json:

   url_parts = link['object']['url'].split('/')

   project = f'{url_parts[4]}'

   iid = url_parts[6]

   projects.add(project)   

بعد ذلك ، قررت أين يمكنني استخدام المكتبات الموجودة . ثم ، ربما ، سأعيد صياغة هذه القطع.

بعد ذلك ، تحتاج إلى التحقق ، فجأة توجد فروع RC المناسبة بالفعل ، إذا كانت هناك محاولات بالفعل للبناء ، فيجب حذفها وإنشاء فروع جديدة. لقد فعلت ذلك بالفعل باستخدام مكتبة Python GitLab:

gl = gitlab.Gitlab('https://gitlab...ru/', private_token=GITLAB_PRIVATE_TOKEN)

pr = gl.projects.get(project)

try:

   rc = pr.branches.get(f'{RC_name}')

   rc.delete()

   pr.branches.create({'branch': f'{RC_name}', 'ref': 'master'})

except gitlab.GitlabError:

   pr.branches.create({'branch': f'{RC_name}', 'ref': 'master'})

بعد ذلك ، يمكنك البدء في ملء الجدول في مهمة تجميع Jira . المعلومات الواردة في الجدول موجودة في الأعمدة التالية: لا ، سكب / عدم سكب الطلبات / المهمة ، الأولوية ، طلبات الدمج من المهمة في RC ، حالة طلب الدمج (سواء كانت الاختبارات التي تم تمريرها في Gitlab ، سواء كانت هناك تعارضات أم لا ، أم لا).

في هذه الخطوة ، واجهت خللاً غير سار في Gitlab: إذا تم تجميد التغييرات سابقًا في الفرع الوجهة لطلب الدمج ، فإن واجهة Gitlab API ، عند طلب حالة طلب الدمج ، تقدم إجابة حول وجود تعارضات. من حيث المبدأ ، يمكن فهم ذلك: إذا لم يكن هناك شيء للتدفق ، فلن ينجح ذلك ، ولكن لماذا نقول أنه يوجد صراع في هذا المكان؟ كانت منتديات Gitlab تسأل الناس منذ عدة سنوات ، ولكن لا توجد إجابات حتى الآن.

في حالتي ، يؤدي هذا إلى حالة تعارض كاذبة والتحقق يدويًا من طلب الدمج. لم أتوصل إلى أي شيء حتى الآن.

المنطق عند إنشاء طلبات الدمج هو كما يلي: إذا لم يتم اجتياز الاختبارات ، أو إذا كان هناك تعارض ، يتم إنشاء طلبات الدمج ، ولكنها لا تتدفق إلى RC ، يتم وضع الحالات المقابلة في الجدول.

للتحقق من تنفيذ الاختبارات ، نبحث عن قائمة بخطوط الأنابيب المناسبة. تصدرهم أداة Gitlab مرتبة حسب التاريخ بترتيب تنازلي ، تمامًا كما نحتاج. نأخذ الأول - سيكون هو المطلوب:

pipelines = project.pipelines.list(ref=f'{issue}')

if pipelines:

   pipelines = pipelines[0]

   if pipelines.attributes['status'] != 'success':

       status = '(x)   !, '

ثم قم بإنشاء طلبات الدمج نفسها . نتحقق من فتحها ، في حال لم تكن هذه هي المحاولة الأولى للبناء. في حالة عدم وجود طلب الدمج المطلوب ، قم بإنشاء هذا:

mr = project.mergerequests.list(

 state='opened',

source_branch=source_branch,         target_branch=target_branch)

if mr:

   mr = mr[0]

else:

   mr = project.mergerequests.create(

{'source_branch': source_branch,

           'target_branch': target_branch,

           'title': f"{(MR.issue).replace('-', '_')} -> {RC_name}",

           'target_project_id': PROJECTS_NAMES[MR.project],})

status = mr.attributes['merge_status']

url = mr.attributes['web_url']

return status, url, mr

MR.issue.replace ("-"، "_") - قم بتغيير اسم المهمة للتخلص من تعليقات Gitlaba غير المفيدة حول المهمة في Jira.

بعد ذلك ، ننظر في حالة طلب الدمج المستلم : إذا لم يكن هناك تعارض ، فإننا نسكبه في RC. إذا كان هناك تعارض ، ضع الحالات المناسبة واترك التحقق اليدوي.

علاوة على ذلك ، عن طريق القياس ، نقوم بإنشاء طلبات دمج من RC إلى Staging ومن Staging إلى Master لجميع المشاريع. سيتم سكبها بعد التحقق من بنية الإصدار بالكامل في فروع RC.

تمت إضافة حقلين إلى قالب مهمة Jira: لإجراءات ما قبل النشر وما بعده. لجميع المهام المعنية ، تجمع الخوارزمية قائمة بهذه الإجراءات وتدخل مهمة التجميع حتى لا تنسى أي شيء.

وأخيرًا ، فإن الناتج في Jira هو إنشاء مهمة تجميع :

existing_issue = jira.search_issues(

f'project=PROJ AND summary ~ " {release_name}"')

if existing_issue:

   existing_issue = existing_issue[0]

   existing_issue.update(fields={

       'description': message,

       'customfield_xxx': message_before_deploy,

       'customfield_yyy': message_post_deploy,})

else:

   issue_dict = {

       "fixVersions": [{"name": release_name,}],

       'project': {'key': 'PROJ'},

       'summary': f" {release_name}",

       'description': message,

       'issuetype': {'name': 'RC'},  #      

       'customfield_xxx': message_before_deploy,

       'customfield_yyy': message_post_deploy,}

   new_issue = jira.create_issue(fields=issue_dict)

مزيد من الأفكار كما يلي : تشغيل برنامج نصي على Gitlab بخطاف ويب من Jira. على سبيل المثال ، يمكنك إنشاء بريد إلكتروني لإنشاء مهمة تجميع (إنشاء نوع خاص من المهام لها) ، أو إنشاء مهمة تحتوي على كلمة "تجميع" في العنوان. وسيقوم Gitlab على هذا الخطاف إما بتشغيل برنامج نصي bash يبدأ العملية بأكملها ، أو رفع صورة Docker باستخدام Python وتشغيل برنامج نصي عليه. على الرغم من أن الخيار الثاني معقد بالفعل بالفعل. نعم ، وتحتاج إلى حسابات فنية في Jira و Gitlab. بشكل عام ، لا يوجد قرار نهائي حتى الآن.

بعد إنشاء فروع RC ، يمكنك أيضًا نشر منضدة اختبار على الفروع الضرورية وإجراء اختبارات الانحدار. يمكن لجينكينز التعامل مع هذا. ولكن هذا أيضا في الخطط حتى الآن.

كان هذا كله من أجل تسريع عمل المختبرين وتحرير المطورين من العمل الروتيني. ومع ذلك ، فإن المعنى الاقتصادي هنا محدد أيضًا تمامًا: خذ مطورًا متوسطًا (في فراغ) براتب افتراضي قدره 150،000 روبل لمدة 8 ساعات من وقت العمل في اليوم. لمدة عامين ، كان لدينا حوالي 700 إصدار - هذا عن الإصدار يوميًا. البعض أكثر ، والبعض أقل ، ولكن في المتوسط ​​، على ما أعتقد ، اختفت ساعة على الأقل من وقت المطور لإنشاء الإصدار. أي أن أتمتة هذه العملية توفر على الشركة ما لا يقل عن 150،000 / 8 = 18،750 روبل شهريًا.

على طول الطريق ، صنعت نصًا منفصلاً لنفسي ، تظهر إحصاءات حول الإصدار القادم: كم عدد المهام ، وما هي المشاريع المتأثرة ، وما إلى ذلك. نظرًا لأنه إذا لم يكن لدي حالة مطور في أي من المشاريع في Gitlab ، فسيتم رفض الوصول عند إنشاء طلبات الدمج. أيضًا ، من الملائم أن تعرف مقدمًا حول إجراءات النشر أو اللحاق بمهمة وقعت في هذا الإصدار عن طريق الخطأ. تم حل توزيع إشعارات الإصدار باستخدام وحدتي SMTP والبريد الإلكتروني.

لقد سررت بحل هذه المشكلة: من المثير للاهتمام دائمًا تعلم شيء جديد ووضعه موضع التنفيذ. سيكون من الجيد إذا كانت هذه التجربة مفيدة لشخص ما.

All Articles