Kami memiliki proyek dengan proses CI / CD yang disesuaikan. Ketika pengembang menyelesaikan tugas dan menyuntikkan perubahannya ke dalam pengembangan \, qa secara otomatis diluncurkan, yang menempatkan versi baru aplikasi pada lingkungan pengujian. Dalam dunia yang ideal, tester secara otomatis belajar tentang tugas-tugas yang telah diselesaikan, dan tentang lingkungan apa yang digunakan. Dalam hal ini, alur kerja menjadi kontinu, tidak terputus dan membutuhkan lebih sedikit komunikasi, mengalihkan perhatian dari pekerjaan terkonsentrasi. Dalam praktiknya, semuanya tidak begitu cerah.
Dan suatu pagi, pemimpin tim bertanya kepada saya: "Bisakah Anda membuat hal seperti itu untuk TFS sehingga tag yang terpasang pada build menggantung tag yang ditentukan setelah melewati build ini?"
Saya memutuskan untuk mengimplementasikan tugas build \ release saya untuk tugas tersebut. Selain itu, sumber semua tugas build ada di
github , dan semua informasi tersedia.
Tugas kami menandai warna tugas, yang selesai, tetapi tidak diuji. Berkat ini, pengembang akan segera melihat jika dia lupa memasang tag yang diinginkan, dan QA segera melihat apa yang perlu diperiksa. Ini memvisualisasikan status tugas dan mempercepat pekerjaan di proyek.
Pada artikel ini saya akan berbicara tentang implementasi logika yang diperlukan, pengemasan dalam ekstensi. Jadi, jika Anda tertarik tentang cara membuat plugin semacam itu, selamat datang di cat.
Untuk yang paling tidak sabar:
github dan ekstensi siap di
pasar .

Azure DevOps memiliki kemampuan untuk membuat filter yang memungkinkan Anda untuk mewarnai topeng di papan dengan warna berbeda.

Kami tertarik pada tugas yang:
- selesai
- dituangkan ke lingkungan uji
- belum diverifikasi QA
Untuk item, tag b dan c paling cocok, tetapi secara manual pengaturannya menjijikkan, dan semua orang lupa melakukannya. Jadi kami akan menulis ekstensi, yang setelah penempatan akan secara otomatis menambahkannya.
Jadi, kita perlu langkah custom build \ release untuk mengurangi faktor manusia (pengembang lupa memasang tag) dan untuk membantu QA (Anda dapat segera melihat apa yang perlu diperiksa).
Prasyarat
Untuk mengembangkan ekstensi, kita perlu:
- IDE favorit
- diinstal TypeScript + node.js + npm (sekarang saya telah menginstal versi 3.5.1 \ 12.4 \ 6.9.0)
- tfx-cli - pustaka untuk kemasan extension'a (npm i -g tfx-cli).
Perhatikan keberadaan flag -g
Microsoft memiliki beberapa
dokumentasi yang baik di mana mereka hanya di bagian atas dan memberi tahu cara membuat semacam ekstensi. Selain itu, dengan cara yang sama ada dok untuk membuat tugas build \ release.
Menurut pendapat saya, ada kekurangan dalam kedua artikel dari sudut pandang merinci atau menjelaskan poin-poin tertentu, jadi saya akan mengandalkan mereka, dengan fokus pada poin-poin yang dalam kenyataannya tampak bagi saya tidak begitu jelas.
Secara umum, Anda dapat menulis langkah build \ release dalam sejumlah besar bahasa. Saya akan memberikan contoh pada TypeScript.
Mengapa TypeScript?
Versi pertama build step'a ditulis di PowerShell'e, hanya tim kami dan beberapa orang yang mengetahuinya. Hampir segera, kami dihadapkan dengan fakta bahwa jika Anda mencoba untuk menambahkan tugas ke build yang berjalan pada agen build docker, maka tidak akan ada PowerShell dan tugas itu tidak akan berfungsi. Selain itu, dari waktu ke waktu, berbagai jenis kesalahan lepas landas dari orang-orang, yang dikaitkan dengan PowerShell kooky. Oleh karena itu kesimpulan - solusinya harus lintas platform.
Struktur proyek
|--- README.md |--- images |---extension-icon.png |--- TaskFolder ( build\release step'a) |--- vss-extension.json ( )
Selanjutnya, kita perlu menginstal pustaka untuk implementasi build step'a
- cd TaskFolder
- npm init
- npm instal azure-pipeline-task-lib - save && npm install @ types / node --save-dev && npm install @ types / q --save-dev
- tsc --init
Perpanjangan pengembangan
Pertama-tama, di dalam TaskFolder, kita perlu membuat file task.json - ini adalah file manifes untuk langkah build itu sendiri. Ini berisi informasi layanan (versi, pencipta, deskripsi), lingkungan untuk meluncurkan dan konfigurasi semua input, yang akan kita lihat di masa depan pada formulir.
Saya mengusulkan untuk mempelajari strukturnya secara lebih rinci dalam
dokumentasi .
Dalam kasus kami, akan ada 2 input'a pada formulir - tag yang akan kami tambahkan ke item pekerjaan, dan pilihan jenis pipa (membangun atau melepaskan).
"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" } ]
Berdasarkan nama, dalam kode di bawah ini kita akan merujuk pada nilai dari masing-masing input.
Buat index.ts di TaskFolder dan tulis potongan kode pertama
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();
Perlu dicatat bahwa TFS memiliki dokumentasi yang sangat kaya tentang REST API yang ada, tetapi untuk saat ini, yang perlu kita lakukan adalah mendapatkan item-item pekerjaan yang melekat pada build.
Instal pustaka untuk eksekusi query yang mudah
npm install request --save && npm install request-promise-native --save
Tambahkan ke index.ts
import * as request from "request-promise-native";
Kami mengimplementasikan fungsi, yang dari build saat ini akan mendapatkan item kerja yang dilampirkan
Sedikit tentang otorisasi
Untuk mengakses API REST, kita perlu mendapatkan accessToken
const accessToken = tl.getEndpointAuthorization('SystemVssConnection', true).parameters.AccessToken;
Selanjutnya, setel otorisasi tajuk ke βBearer $ {accessToken}β
Kami kembali menerima item pekerjaan yang terikat pada bangunan.
Server Url Azure DevOps dan nama TeamProject dapat diperoleh dari variabel lingkungan sebagai berikut
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; }
Sebagai tanggapan terhadap permintaan GET dengan URL
${collectionUrl}/${teamProject}/_apis/build/builds/${buildId}/workitems
kita mendapatkan JSON semacam ini
{ "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" } ] }
Untuk setiap url, melalui REST API yang sama, Anda bisa mendapatkan data tentang item pekerjaan.
Saat ini, metode run kami adalah sebagai berikut.
Metode untuk mendapatkan benda kerja dari rilis hampir identik dengan yang sudah dijelaskan.
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); }
Langkah selanjutnya adalah mendapatkan set tag saat ini untuk masing-masing item pekerjaan yang diterima dan menambahkan yang kami tentukan.
Mari kita tambahkan metode run:
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); } }
Mari pertimbangkan untuk menambahkan tag ke item pekerjaan.
Pertama, kita perlu mendapatkan tag yang ditunjukkan pada formulir.
const tagFromInput = tl.getInput('tagToAdd');
Karena 2 langkah ke belakang kami menerima url ke API dari setiap item pekerjaan, lalu dengan bantuan mereka kami dapat dengan mudah meminta daftar tag saat ini:
const uri = workItem.url + "?fields=System.Tags&api-version=2.0"; const getOptions = createGetRequestOptions(uri) const result = await request.get(getOptions);
Sebagai tanggapan, kami mendapatkan JSON ini:
{ "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" }
Kami mengambil semua tag lama dan menambahkan yang baru ke sana:
const currentTags = result.fields['System.Tags']; let newTags = ''; if (currentTags !== undefined) { newTags = currentTags + ";" + tagFromInput; } else { newTags = tagFromInput; }
Kami mengirim permintaan tambalan ke item api:
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 }
Perpanjangan perakitan dan pengemasan
Untuk keindahan segala sesuatu yang terjadi, saya mengusulkan untuk menambahkan tsconfig.json ke compilerOptions
"outDir": "dist"
. Sekarang, jika kita menjalankan perintah
tsc
di dalam TaskFolder, kita mendapatkan folder dist, di dalamnya akan menjadi index.js, yang akan pergi ke paket akhir.
Karena index.js kami terletak di folder dist dan kemudian kami akan menyalinnya ke paket final juga, kami perlu memperbaiki task.json sedikit:
"execution": { "Node": { "target": "dist/index.js" } }
Di vss-extension.json di bagian file, Anda harus secara eksplisit menyatakan apa yang akan disalin ke paket final.
"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" } ]
Langkah terakhir - kita perlu mengemas ekstensi kita.
Untuk melakukan ini, jalankan perintah:
tfx extension create --manifest-globs ./vss-extension.json
Setelah eksekusi, kami mendapatkan file * .vsix, yang akan diinstal lebih lanjut di TFS.
File PS * .vsix pada dasarnya adalah arsip biasa, Anda dapat dengan mudah membukanya melalui 7-zip, misalnya, dan melihat bahwa semua yang Anda butuhkan ada di dalamnya.
Tambahkan sedikit keindahan
Jika Anda ingin memiliki gambar ketika Anda memilih langkah pembangunan Anda sambil menambahkannya ke pipa, file ini harus ditempatkan di sebelah task.json dan bernama icon.png. Anda tidak perlu melakukan perubahan apa pun pada task.json itu sendiri.
Anda dapat menambahkan bagian ke vss-extension.json:
"icons": { "default": "images/logo.png" }
Gambar ini akan ditampilkan di galeri ekstensi lokal.
Pasang ekstensi
- Pergi ke tfs_server_url / _gallery / manage
- Klik Unggah ekstensi
- Tentukan path atau drag'n'drop untuk melempar file * .vsix yang diterima sebelumnya
- Setelah verifikasi berlalu, di menu konteks ekstensi, pilih ekstensi tampilan, pada halaman yang terbuka, pilih koleksi di mana Anda ingin menginstalnya
- Setelah ekstensi ini, Anda dapat mulai menggunakannya.
Menggunakan build step'a
- Buka pipa yang Anda butuhkan
- Pergi untuk menambahkan build step'a
- Kami mencari ekstensi

- Kami menunjukkan semua pengaturan yang diperlukan

- Nikmati hidup :)
Kesimpulan
Pada artikel ini saya menunjukkan cara membuat plug-in untuk Azure DevOps, yang secara otomatis menempatkan tag yang tepat untuk tugas untuk rilis. Kolega membangunnya ke dalam pipeline, yang berjalan di kedua agen windows dan linux build.
Berkat plugin ini, menjadi lebih mudah bagi kami untuk bekerja dengan tugas dan membangun kerja terus menerus pada proyek. Pengembang tidak lagi terganggu oleh hal-hal asing, dan QA dengan cepat belajar tentang tugas pengujian baru.
Sekali lagi, saya ingat
tautan unduhan:
tautanKami menantikan umpan balik dan saran untuk revisi :)
PS
Ada juga ide untuk menambahkan kemampuan untuk menghapus tag yang ditentukan ke dalam plugin. Jika penguji menemukan bug dan Anda harus menggunakan tugas lagi, Anda bisa menyingkirkan tag "Terverifikasi").