إنشاء امتداد Azure DevOps

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

وفي صباح أحد الأيام ، سألني قائد الفريق: "هل يمكنك عمل شيء مثل TFS بحيث تعلق العلامات المرتبطة بالبناء العلامة المحددة بعد المرور عبر هذه البنية؟"

قررت تنفيذ مهمة build / release الخاصة بي للمهمة. علاوة على ذلك ، فإن مصادر جميع مهام البناء على جيثب ، وجميع المعلومات المتاحة.

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

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

لمعظم الصبر: جيثب وتمديد جاهز في السوق .



لدى Azure DevOps القدرة على إنشاء عوامل تصفية تسمح لك بتلوين الأقنعة على اللوحة بألوان مختلفة.




نحن مهتمون بالمهام التالية:

  • الانتهاء
  • سكب في بيئة الاختبار
  • لم يتم التحقق بعد

بالنسبة للعناصر ، تعد العلامات b و c أكثر ملاءمة ، لكن إعدادها يدويًا أمر مثير للاشمئزاز ، وينسى الجميع القيام بذلك. لذلك ، سنكتب امتدادًا ، والذي بعد النشر سيتم تثبيته تلقائيًا.

وبالتالي ، نحتاج إلى خطوة build / release المخصصة لتقليل العامل البشري (نسي المطور وضع العلامة) ولمساعدة QA (يمكنك على الفور معرفة ما يلزم التحقق منه).

المتطلبات الأساسية


لتطوير الامتداد ، نحتاج إلى:

  1. IDE المفضل
  2. تثبيت TypeScript + node.js + npm (الآن قمت بتثبيت الإصدارات 3.5.1 \ 12.4 \ 6.9.0)
  3. tfx-cli - مكتبة لتمديد التغليف (npm i -g tfx-cli).

لاحظ وجود العلم -g

لدى Microsoft بعض الوثائق الجيدة التي تكون في المقدمة وتحدث عن كيفية إنشاء بعض الامتدادات. بالإضافة إلى ذلك ، بنفس الطريقة ، يوجد رصيف لإنشاء مهمة build \ release.

في رأيي ، هناك عيوب في كلا المقالين من وجهة نظر تفصيلية أو شرح بعض النقاط ، لذلك سأعتمد عليها ، مع التركيز على تلك النقاط التي بدا لي في الواقع غير واضحة تمامًا.

بشكل عام ، يمكنك كتابة خطوة build \ release بعدد كبير من اللغات. سأقدم مثالا على TypeScript.

لماذا TypeScript؟


تمت كتابة الإصدار الأول من build step'a في PowerShell'e ، وفريقنا واثنين فقط من الأشخاص يعرفون ذلك. على الفور تقريبًا ، واجهنا حقيقة أنه إذا حاولت إضافة مهمة إلى البنية التي تعمل على عامل بناء عامل ميناء ، فلن يكون هناك PowerShell ولن تعمل المهمة ببساطة. بالإضافة إلى ذلك ، من وقت لآخر ، خلعت أنواع مختلفة من الأخطاء من الناس ، والتي نسبت إلى PowerShell kooky. ومن هنا الاستنتاج - يجب أن يكون الحل عبر منصة.

هيكل المشروع


|--- README.md |--- images |---extension-icon.png |--- TaskFolder (     build\release step'a) |--- vss-extension.json ( ) 

بعد ذلك ، نحتاج إلى تثبيت المكتبة لتنفيذ build'a

  1. TaskFolder مؤتمر نزع السلاح
  2. npm init
  3. npm install azure-pipelines-task-lib - حفظ & npm install @ types / node --save-dev && npm install @ types / q --save-dev
  4. tsc -

تمديد التنمية


بادئ ذي بدء ، داخل TaskFolder ، نحتاج إلى إنشاء ملف task.json - هذا هو ملف البيان لخطوة الإنشاء نفسها. أنه يحتوي على معلومات الخدمة (الإصدار ، المنشئ ، الوصف) ، بيئة لإطلاق وتكوين جميع المدخلات ، والتي سنرىها في المستقبل في النموذج.

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

 "inputs": [ { "name": "pipelineType", "type": "pickList", "label": "Specify type of pipeline", "helpMarkDown": "Specify whether task is used for build or release", "required": true, "defaultValue": "Build", "options":{ "Build": "Build", "Release": "Release" } }, { "name": "tagToAdd", "type": "string", "label": "Tag to add to work items", "defaultValue": "", "required": true, "helpMarkDown": "Specify a tag that will be added to work items" } ] 

بالاسم ، في الكود أدناه سنشير إلى قيمة كل من المدخلات.
إنشاء index.ts في TaskFolder وكتابة أول قطعة من التعليمات البرمجية

 import * as tl from 'azure-pipelines-task-lib/task'; async function run() { try { const pipelineType = tl.getInput('pipelineType'); } catch (err) { tl.setResult(tl.TaskResult.Failed, err.message); } } run(); 

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

تثبيت مكتبة لتنفيذ الاستعلام سهل

 npm install request --save && npm install request-promise-native --save 

إضافته إلى index.ts

 import * as request from "request-promise-native"; 

ننفذ الوظيفة ، والتي من البنية الحالية ستحصل على عناصر العمل المرفقة

قليلا عن الترخيص


للوصول إلى REST API ، نحتاج إلى الوصول إلى accessToken

 const accessToken = tl.getEndpointAuthorization('SystemVssConnection', true).parameters.AccessToken; 

بعد ذلك ، قم بتعيين تفويض الرأس على "Bearer $ {accessToken}"

نعود إلى تلقي عناصر العمل المرتبطة بالبناء.

يمكن الحصول على خادم Url Azure DevOps واسم TeamProject من متغيرات البيئة كما يلي

 const collectionUrl = process.env["SYSTEM_TEAMFOUNDATIONCOLLECTIONURI"]; const teamProject = process.env["SYSTEM_TEAMPROJECT"]; 

 async function getWorkItemsFromBuild() { const buildId = process.env["BUILD_BUILDID"]; const uri = `${collectionUrl}/${teamProject}/_apis/build/builds/${buildId}/workitems`; const options = createGetRequestOptions(uri); const result = await request.get(options); return result.value; } 

 function createGetRequestOptions(uri: string): any { let options = { uri: uri, headers: { "authorization": `Bearer ${accessToken}`, "content-type": "application/json" }, json: true }; return options; } 

كرد على طلب GET بواسطة URL

 ${collectionUrl}/${teamProject}/_apis/build/builds/${buildId}/workitems 

نحصل على هذا النوع من JSON

 { "count": 3, "value": [ { "id": "55402", "url": "https://.../_apis/wit/workItems/55402" }, { "id": "59777", "url": "https://.../_apis/wit/workItems/59777" }, { "id": "60199", "url": "https://.../_apis/wit/workItems/60199" } ] } 

لكل عنوان url ، من خلال نفس واجهة برمجة تطبيقات REST ، يمكنك الحصول على بيانات حول عنصر العمل.

في الوقت الحالي ، طريقة التشغيل لدينا هي كما يلي.

طريقة الحصول على عناصر العمل من الإصدار مماثلة تقريبا لتلك الموصوفة بالفعل.

 async function run() { try { const pipelineType = tl.getInput('pipelineType'); const workItemsData = pipelineType === "Build" ? await getWorkItemsFromBuild() : await getWorkItemsFromRelease(); catch (err) { tl.setResult(tl.TaskResult.Failed, err.message); } 

الخطوة التالية هي الحصول على مجموعة العلامات الحالية لكل عنصر من عناصر العمل المستلمة وإضافة العنصر الذي حددناه.

دعنا نضيف طريقة التشغيل:

 async function run() { try { const pipelineType = tl.getInput('pipelineType'); const workItemsData = pipelineType === "Build" ? await getWorkItemsFromBuild() : await getWorkItemsFromRelease(); workItemsData.forEach(async (workItem: any) => { await addTagToWorkItem(workItem); }); } catch (err) { tl.setResult(tl.TaskResult.Failed, err.message); } } 

دعنا نفكر في إضافة علامة إلى عناصر العمل.

أولاً ، نحتاج إلى الحصول على العلامة التي أشرنا إليها في النموذج.

 const tagFromInput = tl.getInput('tagToAdd'); 

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

 const uri = workItem.url + "?fields=System.Tags&api-version=2.0"; const getOptions = createGetRequestOptions(uri) const result = await request.get(getOptions); 

استجابة لذلك ، حصلنا على هذا JSON:

 { "id": 55402, "rev": 85, "fields": { "System.Tags": "added-to-prod-package; test-tag" }, "_links": { "self": { "href": "https://.../_apis/wit/workItems/55402" }, "workItemUpdates": { "href": "https://.../_apis/wit/workItems/55402/updates" }, "workItemRevisions": { "href": "https://.../_apis/wit/workItems/55402/revisions" }, "workItemHistory": { "href": "https://.../_apis/wit/workItems/55402/history" }, "html": { "href": "https://..../web/wi.aspx?pcguid=e3c978d9-6ea1-406f-987d-5b03e24973a1&id=55402" }, "workItemType": { "href": "https://.../602fd27d-4e0d-4aec-82a0-dcf55c8eef73/_apis/wit/workItemTypes" }, "fields": { "href": "https://.../_apis/wit/fields" } }, "url": "https://.../_apis/wit/workItems/55402" } 

نأخذ جميع العلامات القديمة ونضيف واحدة جديدة لهم:

 const currentTags = result.fields['System.Tags']; let newTags = ''; if (currentTags !== undefined) { newTags = currentTags + ";" + tagFromInput; } else { newTags = tagFromInput; } 

نرسل طلب تصحيح للعمل api item:

 const patchOptions = getPatchRequestOptions(uri, newTags); await request.patch(patchOptions) function getPatchRequestOptions(uri: string, newTags: string): any { const options = { uri: uri, headers: { "authorization": `Bearer ${accessToken}`, "content-type": "application/json-patch+json" }, body: [{ "op": "add", "path": "/fields/System.Tags", "value": newTags }], json: true }; return options } 

الجمعية والتعبئة والتغليف extension'a


من أجل جمال كل ما يحدث ، أقترح إضافة tsconfig.json إلى compilerOptions
 "outDir": "dist" 
. الآن ، إذا قمنا بتنفيذ الأمر tsc داخل TaskFolder ، فسنحصل على مجلد dist ، والذي سيكون index.js بداخله ، والذي سينتقل إلى الحزمة النهائية.

لأن يوجد index.js الخاص بنا في مجلد dist ومن ثم سنقوم بنسخه إلى الحزمة النهائية أيضًا ، نحتاج إلى إصلاح task.json قليلاً:

 "execution": { "Node": { "target": "dist/index.js" } } 

في vss-extension.json في قسم الملفات ، يجب أن تعلن بوضوح ما سيتم نسخه إلى الحزمة النهائية.

 "files": [ { "path": "TaskFolder/dist", "packagePath": "TaskFolder/dist" }, { "path": "TaskFolder/node_modules", "packagePath": "TaskFolder/node_modules" }, { "path": "TaskFolder/icon.png", "packagePath": "TaskFolder/icon.png" }, { "path": "TaskFolder/task.json", "packagePath": "TaskFolder/task.json" } ] 

الخطوة الأخيرة - نحن بحاجة إلى حزمة ملحق لدينا.

للقيام بذلك ، قم بتشغيل الأمر:

  tfx extension create --manifest-globs ./vss-extension.json 

بعد التنفيذ ، نحصل على ملف * .vsix ، والذي سيتم تثبيته مرة أخرى في TFS.

يعد ملف PS * .vsix أرشيفًا أساسيًا ، يمكنك فتحه بسهولة من خلال 7-zip ، على سبيل المثال ، ومعرفة أن كل ما تحتاجه موجود بالفعل.

أضف بعض الجمال


إذا كنت ترغب في الحصول على صورة عند تحديد خطوة الإنشاء الخاصة بك أثناء إضافتها إلى خط الأنابيب ، فيجب وضع هذا الملف بجوار task.json وتسميته icon.png. لا تحتاج إلى إجراء أي تغييرات على task.json نفسها.

يمكنك إضافة قسم إلى vss-extension.json:

 "icons": { "default": "images/logo.png" } 

سيتم عرض هذه الصورة في معرض الإضافات المحلية.

تثبيت التمديد


  1. انتقل إلى tfs_server_url / _gallery / management
  2. انقر فوق تحميل الإضافة
  3. حدد المسار أو اسحب لإلقاء ملف * .vsix الذي تم استلامه مسبقًا
  4. بعد مرور عملية التحقق ، في قائمة السياق بالملحق ، حدد امتداد العرض ، على الصفحة التي تفتح ، حدد المجموعة التي تريد تثبيتها بها
  5. بعد هذا التمديد ، يمكنك البدء في استخدامه.

باستخدام بناء step'a


  1. افتح خط الأنابيب الذي تحتاجه
  2. انتقل لإضافة بناء step'a
  3. نحن نبحث عن التمديد


  4. نشير إلى جميع الإعدادات اللازمة

  5. استمتع بالحياة :)

استنتاج


لقد أوضحت في هذه المقالة كيفية إنشاء مكون إضافي لـ Azure DevOps ، والذي يضع العلامة الصحيحة تلقائيًا في مهام الإصدار. قام الزملاء ببنائه في خط الأنابيب ، والذي يعمل على كل من الويندوز ووكلاء بناء لينكس.

بفضل هذا البرنامج المساعد ، أصبح من الأسهل بالنسبة لنا العمل مع المهام وبناء عمل مستمر في المشروع. لم يعد المطورون يصرف انتباههم عن أشياء غريبة ، وسرعان ما تتعرف ضمان الجودة على مهام اختبار جديدة.

مرة أخرى ، أذكر رابط التنزيل: link

ونحن نتطلع إلى ردود الفعل والاقتراحات للمراجعة :)

PS

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

Source: https://habr.com/ru/post/ar461389/


All Articles