Earlier, when we didn’t have our corporate blog, I wrote about how we use Microsoft TFS (Visual Studio Team Services on Premises) to manage the software development life cycle and to automate testing. In particular, we have collected a large set of autotests for different systems in one package, which we run every day. I talked more about this at the DevOpsDaysMoscow conference ( presentation , video of the speech ) During the implementation, we encountered several problems:
Assemblies from Jenkins do not publish test results in VSTS
All these problems were successfully solved with the help of the own VSTS extensions:
Completion of the standard Jenkins job start task
Learn more about the problems and how we looked for solutions - in my last article . And today I want to talk about how to do these extensions and how we can help the developers of extensions.
Practically from the very beginning we understood that the easiest way to solve our problems is our own tasks (tasks) or assembly steps in TFS. Tasks can be written either in powershell or in typescript. We chose typescript, and for some reason, this is actually javascript, but with support for typing. On the benefits of typescript and its use, there are many articles, including those in Habré. For us, the main advantages were the following:
To work with TFS, Microsoft created and published 2 npm modules, which again eliminated the need to reinvent the wheel.
Also of great help was the fact that many tasks from Microsoft are written and typescript and published under an open source license. Besides the fact that it allows using them as examples, it gave the opportunity to make a fork of this repository and make your own bootstrap kit for quickly creating tasks and automating the assembly and packaging of extensions.
What is the challenge for VSTS? This is a set of required components:
task icon
Task definition contains several blocks.
{ "id": "b5525419-bae1-44de-a479-d6de6a3ccb2f", "name": "TestTask", "friendlyName": "TestTask", "description": "TestTask", "helpMarkDown": "", "category": "Build", "author": "authorName", "version": { "Major": 1, "Minor": 0, "Patch": 0 }, "instanceNameFormat": "TestTask $(testparam)" }
This block describes the unique id of the task, its name, category and version. When creating a task, you must specify all these fields. The instanceNameFormat field defines how the task name in the default VSTS assembly will look. It can contain parameters from the parameter block in the form of $ (parameter name)
The parameter block contains the input parameters of the task, their names, descriptions, and types. Parameters can be grouped for ease of presentation on the task settings page. Below the block is the AutoDefects task parameter:
{ "groups": [ { "name": "authentication", "displayName": "Authentication", "isExpanded": false } ], "inputs": [ { "name": "Assignees", "type": "filePath", "label": "Assignees list file", "defaultValue": "assignees.json", "required": false, "helpMarkDown": "Bug assignees list in json format. Format: {\"testrunname\":\"username\"}" }, { "name": "authtype", "type": "pickList", "label": "Authentication type", "defaultValue": "oauth", "required": false, "helpMarkDown": "Authentication type to access the tfs rest api", "options": { "oauth": "OAuth", "NTLM": "NTLM", "Basic": "Basic" }, "groupName" : "authentication" }, { "name": "Username", "type": "string", "label": "Username", "defaultValue": "", "required": false, "helpMarkDown": "Username to access tfs rest api (NTLM and Basic types)", "groupName" : "authentication", "visibilityRule" : "authtype != OAuth" }, { "name": "Password", "type": "string", "label": "Password", "defaultValue": "", "required": false, "helpMarkDown": "Password to access tfs rest api (NTLM and Basic types)", "groupName" : "authentication", "visibilityRule" : "authtype != OAuth" } ] }
The parameters defining the authentication scheme are placed in a separate group, which is minimized by default.
As the types of parameters are most often used:
contains a link to the main task executable file
{ "execution": { "Node": { "target": "testtask.ts" } } }
{ "messages": { "taskSucceeded": "All done", "taskFailed": "Task Failed" } }
contains a set of localized strings for logging the task in the assembly log file. Used less frequently than blocks above. Messages for the current local settings can be obtained by calling task.loc ("messagename");
The main executable file is a script that executes VSTS at the start of a task. At a minimum, it should contain code for importing the necessary modules for the task to work and error handling. For example:
import tl = require('vsts-task-lib/task'); import trm = require('vsts-task-lib/toolrunner'); import path = require('path'); import fs = require('fs'); import Q = require("q"); import * as vm from 'vso-node-api'; import * as bi from 'vso-node-api/interfaces/BuildInterfaces'; import * as ci from 'vso-node-api/interfaces/CoreInterfaces'; import * as ti from 'vso-node-api/interfaces/TestInterfaces'; import * as wi from 'vso-node-api/interfaces/WorkItemTrackingInterfaces'; async function run() { tl.setResourcePath(path.join(__dirname, 'task.json')); let projId = tl.getVariable("System.TeamProjectId"); try { } catch(err) { console.log(err); console.log(err.stack); throw err; } } run() .then(r => tl.setResult(tl.TaskResult.Succeeded,tl.loc("taskSucceeded"))) .catch(r => tl.setResult(tl.TaskResult.Failed,tl.loc("taskFailed")))
As you can see, a task is a set of standard components that vary little from task to task. Therefore, when I created the third task, an idea appeared to automate the creation of tasks. This is how our “bootstrap” appeared, which makes life easier for the development of VSTS extensions.
What do you need to do when you create a task for VSTS, except for actually writing the code of the task itself? The steps are usually the same:
All these steps can be automated to speed development and eliminate unnecessary manual labor. To automate these steps and you can use our "bootstrap". The work scheme of our collector is similar to the task collector from Microsoft - the tasks for the assembly are listed in the file make-options.json in the project root:
{ "tasks": [ "AutoDefects", "ChainBuildsAwaiter", "ChainBuildsStarter", "TestTask" ], ... }
To create extensions you need the following software:
npm install -g typescript
npm install -g gulp
npm install -g tfx-cli
TaskName is created with the command:gulp generate –-name TaskName
As a result of running the command, the following happens:
Skeleton files contain the minimum required set of data and code.
Assembling the project’s tasks is done by the command gulp
For all the tasks listed in make-options.json , the following happens:
Packing tasks is done with the gulp mkext [--all] [--exts ext1,ext2]
command gulp mkext [--all] [--exts ext1,ext2]
By default, each task is packaged in a separate vsix file, if the --all parameter is specified, then all tasks are collected into one large vsix file.
By default, all tasks listed in make-options.json are packaged; if the option --exts is specified, then only the extensions listed in the option are packaged.
Bootstrap published on GitHub - forks, feature requests, pull requests are welcome.
I really hope that this article will arouse interest in Miscosoft VSTS, which in my opinion is an excellent tool for group work, not only for large companies, but also for small flexible teams.
Konstantin Neradovsky,
Head of Test Automation,
Bank opening"
Source: https://habr.com/ru/post/330078/
All Articles