├── .vscode ├── tasks.json └── launch.json ├── .gitignore ├── publish.sh ├── demo.gif ├── run.sh ├── templates ├── icon.png ├── package.json.tmpl ├── README.md └── LICENSE.md ├── tsconfig.json ├── package.json ├── src ├── helpers │ ├── fs-helpers.ts │ ├── commands-helpers.ts │ ├── commands-helpers.js │ └── fs-helpers.js ├── index.ts ├── snippets.ts ├── index.js └── snippets.js └── README.md /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out/* 2 | node_modules 3 | .vscode-test/ 4 | *.vsix -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | ./run.sh 2 | cd out/vs-extension 3 | vsce package --out .. -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/damienaicheh/azure-devops-snippets-generator/HEAD/demo.gif -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | npm install 2 | rm -R out 3 | mkdir out 4 | tsc src/index.ts 5 | node src/index.js --version=1.0.5 -------------------------------------------------------------------------------- /templates/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/damienaicheh/azure-devops-snippets-generator/HEAD/templates/icon.png -------------------------------------------------------------------------------- /templates/package.json.tmpl: -------------------------------------------------------------------------------- 1 | { 2 | "name": "azure-devops-snippets", 3 | "displayName": "Azure DevOps Snippets", 4 | "description": "Snippets for all officials Azure DevOps YAML tasks", 5 | "version": "{{version}}", 6 | "publisher": "damienaicheh", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/damienaicheh/azure-devops-snippets-generator" 10 | }, 11 | "icon": "icon.png", 12 | "engines": { 13 | "vscode": "^1.44.0" 14 | }, 15 | "categories": [ 16 | "Snippets" 17 | ], 18 | "contributes": { 19 | "snippets": [{{{snippets}}}] 20 | } 21 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ] 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /templates/README.md: -------------------------------------------------------------------------------- 1 | # Azure DevOps Snippets 2 | 3 | Generate all Azure DevOps snippets. 4 | 5 | ## Features 6 | 7 | This tool is used to generate all Azure DevOps snippets based on the official [Azure Pipeline Tasks][github-microsoft-link] from Microsoft. 8 | 9 | This extension generate more than 150 snippets. This is useful for creating and editing Azure Pipelines YAML templates inside VS Code. 10 | 11 | ## How to use it? 12 | 13 | All the snippets are prefixed by `ado` this will be available inside a YAML file. 14 | 15 | ## Contributions 16 | 17 | Feel free to contribute, if you want to improve this tool! 18 | 19 | [github-microsoft-link]: https://github.com/microsoft/azure-pipelines-tasks 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | }, 17 | "exclude": [ 18 | "node_modules", 19 | ".vscode-test", 20 | "out" 21 | ] 22 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "azure-devops-snippets-generator", 3 | "displayName": "Azure DevOps Snippets Generator", 4 | "description": "Generate all Azure DevOps snippets", 5 | "version": "0.0.1", 6 | "publisher": "damienaicheh", 7 | "repository": "https://github.com/damienaicheh/azure-devops-snippets-generator", 8 | "engines": { 9 | "vscode": "^1.67.0" 10 | }, 11 | "categories": [ 12 | "Other" 13 | ], 14 | "activationEvents": [], 15 | "main": "./out/extension.js", 16 | "contributes": {}, 17 | "scripts": { 18 | "vscode:prepublish": "npm run compile", 19 | "compile": "tsc -p ./", 20 | "watch": "tsc -watch -p ./" 21 | }, 22 | "devDependencies": { 23 | "@types/node": "^17.0.36", 24 | "@types/vscode": "^1.67.0", 25 | "path-parse": ">=1.0.7", 26 | "tslint": "^5.20.1", 27 | "typescript": "^4.7.2" 28 | }, 29 | "dependencies": { 30 | "child_process": "^1.0.2", 31 | "fs": "0.0.1-security", 32 | "handlebars": "^4.7.7", 33 | "path": "^0.12.7" 34 | } 35 | } -------------------------------------------------------------------------------- /src/helpers/fs-helpers.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | 4 | export function readFile(path: fs.PathLike): Promise { 5 | return new Promise(function (resolve, reject) { 6 | fs.readFile(path, { encoding: 'utf-8', flag: 'r' }, function (error, result) { 7 | if (error) { 8 | reject(error); 9 | } else { 10 | resolve(result); 11 | } 12 | }); 13 | }); 14 | } 15 | 16 | export function createFile(folderPath: string, fileName: string, content: string) { 17 | return new Promise(function (resolve, reject) { 18 | fs.writeFile(path.join(folderPath, fileName), content, err => { 19 | if (err) { 20 | reject(err); 21 | } else { 22 | resolve(); 23 | } 24 | }); 25 | }); 26 | } 27 | 28 | export function readDirectory(path: string): Promise { 29 | return new Promise((resolve, reject) => { 30 | fs.readdir(path, async (err, folders) => { 31 | err ? reject(err) : resolve(folders); 32 | }); 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /templates/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Damien Aicheh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/helpers/commands-helpers.ts: -------------------------------------------------------------------------------- 1 | import { exec } from "child_process"; 2 | 3 | export function execShellCommand(cmd: string): Promise { 4 | return new Promise((resolve, reject) => { 5 | exec(cmd, (error: any, stdout: any, stderr: any) => { 6 | if (error) { 7 | reject(error); 8 | } 9 | resolve(stdout ? stdout : stderr); 10 | }); 11 | }); 12 | } 13 | 14 | export function getArgs(): any { 15 | const args: any = {}; 16 | process.argv 17 | .slice(2, process.argv.length) 18 | .forEach(arg => { 19 | if (arg.slice(0, 2) === '--') { 20 | const longArg = arg.split('='); 21 | const longArgFlag = longArg[0].slice(2, longArg[0].length); 22 | const longArgValue = longArg.length > 1 ? longArg[1] : true; 23 | args[longArgFlag] = longArgValue; 24 | } 25 | else if (arg[0] === '-') { 26 | const flags = arg.slice(1, arg.length).split(''); 27 | flags.forEach(flag => { 28 | args[flag] = true; 29 | }); 30 | } 31 | }); 32 | 33 | return args; 34 | } -------------------------------------------------------------------------------- /src/helpers/commands-helpers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | var child_process_1 = require("child_process"); 4 | function execShellCommand(cmd) { 5 | return new Promise(function (resolve, reject) { 6 | child_process_1.exec(cmd, function (error, stdout, stderr) { 7 | if (error) { 8 | reject(error); 9 | } 10 | resolve(stdout ? stdout : stderr); 11 | }); 12 | }); 13 | } 14 | exports.execShellCommand = execShellCommand; 15 | function getArgs() { 16 | var args = {}; 17 | process.argv 18 | .slice(2, process.argv.length) 19 | .forEach(function (arg) { 20 | if (arg.slice(0, 2) === '--') { 21 | var longArg = arg.split('='); 22 | var longArgFlag = longArg[0].slice(2, longArg[0].length); 23 | var longArgValue = longArg.length > 1 ? longArg[1] : true; 24 | args[longArgFlag] = longArgValue; 25 | } 26 | else if (arg[0] === '-') { 27 | var flags = arg.slice(1, arg.length).split(''); 28 | flags.forEach(function (flag) { 29 | args[flag] = true; 30 | }); 31 | } 32 | }); 33 | return args; 34 | } 35 | exports.getArgs = getArgs; 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Azure DevOps Snippets 2 | 3 | Generate all Azure DevOps snippets. 4 | 5 | ## Features 6 | 7 | This tool is used to generate all Azure DevOps snippets based on the official [Azure Pipeline Tasks][github-microsoft-link] from Microsoft. 8 | 9 | This extension generate more than 150 snippets. This is useful for creating and editing Azure Pipelines YAML templates inside VS Code. 10 | 11 | ## How to use it? 12 | 13 | Just install the extension from the Marketplace available [here][marketplace-link] 14 | 15 | All the snippets are prefixed by `ado` 16 | 17 | ![Demo](demo.gif) 18 | 19 | ## Contributions 20 | 21 | Feel free to contribute, if you want to improve this tool! 22 | 23 | ## Release Notes 24 | 25 | ### 1.0.6 26 | Update the tasks and release notes. 27 | 28 | ### 1.0.5 29 | Update the tasks and release notes. 30 | 31 | ### 1.0.4 32 | Update all packages. 33 | 34 | ### 1.0.3 35 | Update the tasks and release notes. 36 | 37 | ### 1.0.2 38 | Fix run script 39 | 40 | ### 1.0.1 41 | Add Readme.md to the template 42 | 43 | ### 1.0.0 44 | Stable version. 45 | 46 | [github-microsoft-link]: https://github.com/microsoft/azure-pipelines-tasks 47 | [marketplace-link]: https://marketplace.visualstudio.com/items?itemName=DamienAicheh.azure-devops-snippets 48 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import path = require('path'); 2 | import { genereateSnippets } from './snippets'; 3 | import * as Handlebars from 'handlebars'; 4 | import { readFile, createFile } from './helpers/fs-helpers'; 5 | import { execShellCommand, getArgs } from './helpers/commands-helpers'; 6 | 7 | const outputFolder = 'out'; 8 | const projectFolderName = 'vs-extension'; 9 | 10 | async function run() { 11 | console.log("Git clone"); 12 | await execShellCommand(`cd ${outputFolder} && git clone https://github.com/microsoft/azure-pipelines-tasks.git`); 13 | console.log("Git clone done"); 14 | 15 | var projectPath = path.join(outputFolder, projectFolderName); 16 | 17 | const args = getArgs(); 18 | console.log(args); 19 | 20 | console.log("Create project"); 21 | await execShellCommand(`cp -r templates ${projectPath}`); 22 | await execShellCommand(`cd ${projectPath} && mkdir snippets`); 23 | console.log("Create project done"); 24 | 25 | console.log("Generate snippets"); 26 | var filesNames = await genereateSnippets(outputFolder, projectPath); 27 | console.log("Generate snippets done"); 28 | 29 | console.log("Configuration"); 30 | console.log(filesNames); 31 | await setExtensionConfiguration(args.version, filesNames); 32 | console.log("Configuration done"); 33 | } 34 | 35 | async function setExtensionConfiguration(version: string, filesNames: string[]) { 36 | var vscodeExtensionFolder = path.join(__dirname, '..', outputFolder, projectFolderName); 37 | var packageJsonTemplatePath = path.join(vscodeExtensionFolder, 'package.json.tmpl'); 38 | 39 | var source = await readFile(packageJsonTemplatePath); 40 | 41 | var template = Handlebars.compile(source); 42 | var snippets: Object[] = []; 43 | 44 | for (let index = 0; index < filesNames.length; index++) { 45 | if (filesNames[index] != undefined) { 46 | snippets.push(JSON.stringify({ 47 | "language": "yaml", 48 | "path": `./snippets/${filesNames[index]}` 49 | })); 50 | } 51 | } 52 | 53 | await createFile(vscodeExtensionFolder, 'package.json', template({ 54 | 'version': version, 55 | 'snippets': snippets 56 | })); 57 | 58 | await execShellCommand(`rm ${packageJsonTemplatePath}`); 59 | } 60 | 61 | run(); -------------------------------------------------------------------------------- /src/helpers/fs-helpers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __generator = (this && this.__generator) || function (thisArg, body) { 12 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 13 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 14 | function verb(n) { return function (v) { return step([n, v]); }; } 15 | function step(op) { 16 | if (f) throw new TypeError("Generator is already executing."); 17 | while (_) try { 18 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 19 | if (y = 0, t) op = [op[0] & 2, t.value]; 20 | switch (op[0]) { 21 | case 0: case 1: t = op; break; 22 | case 4: _.label++; return { value: op[1], done: false }; 23 | case 5: _.label++; y = op[1]; op = [0]; continue; 24 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 25 | default: 26 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 27 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 28 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 29 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 30 | if (t[2]) _.ops.pop(); 31 | _.trys.pop(); continue; 32 | } 33 | op = body.call(thisArg, _); 34 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 35 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 36 | } 37 | }; 38 | exports.__esModule = true; 39 | var fs = require("fs"); 40 | var path = require("path"); 41 | function readFile(path) { 42 | return new Promise(function (resolve, reject) { 43 | fs.readFile(path, { encoding: 'utf-8', flag: 'r' }, function (error, result) { 44 | if (error) { 45 | reject(error); 46 | } 47 | else { 48 | resolve(result); 49 | } 50 | }); 51 | }); 52 | } 53 | exports.readFile = readFile; 54 | function createFile(folderPath, fileName, content) { 55 | return new Promise(function (resolve, reject) { 56 | fs.writeFile(path.join(folderPath, fileName), content, function (err) { 57 | if (err) { 58 | reject(err); 59 | } 60 | else { 61 | resolve(); 62 | } 63 | }); 64 | }); 65 | } 66 | exports.createFile = createFile; 67 | function readDirectory(path) { 68 | var _this = this; 69 | return new Promise(function (resolve, reject) { 70 | fs.readdir(path, function (err, folders) { return __awaiter(_this, void 0, void 0, function () { 71 | return __generator(this, function (_a) { 72 | err ? reject(err) : resolve(folders); 73 | return [2 /*return*/]; 74 | }); 75 | }); }); 76 | }); 77 | } 78 | exports.readDirectory = readDirectory; 79 | -------------------------------------------------------------------------------- /src/snippets.ts: -------------------------------------------------------------------------------- 1 | import path = require('path'); 2 | import fs = require('fs'); 3 | import { readFile, readDirectory, createFile } from './helpers/fs-helpers'; 4 | 5 | export async function genereateSnippets(outputFolder: string, projectFolderName: string) { 6 | const directoryPath = path.join(__dirname, '..', outputFolder, 'azure-pipelines-tasks/Tasks'); 7 | var filesNames: Promise[] = []; 8 | 9 | var folders: string[] = await readDirectory(directoryPath); 10 | folders.forEach(function (folder) { 11 | filesNames.push(create(path.join(directoryPath, folder, 'task.json'), folder, projectFolderName)); 12 | }); 13 | 14 | return await Promise.all(filesNames); 15 | } 16 | 17 | async function create(filePath: string, taskName: string, snippetsFolder: string): Promise { 18 | return new Promise(async function (resolve, reject) { 19 | if (fs.existsSync(filePath)) { 20 | var taskDefinition = await readFile(filePath); 21 | if (taskDefinition != undefined) { 22 | const snippet = formatSnippet(taskDefinition); 23 | 24 | if (snippet != undefined) { 25 | var outputSnippetsFolder = path.join(__dirname, '..', snippetsFolder, 'snippets'); 26 | var taskFileName = `${taskName}.json`; 27 | await createFile(outputSnippetsFolder, taskFileName, snippet); 28 | resolve(taskFileName); 29 | } 30 | } 31 | } 32 | return resolve(undefined); 33 | }); 34 | } 35 | 36 | function formatSnippet(json: string) { 37 | const jsonData = JSON.parse(json); 38 | 39 | if (jsonData.deprecated != undefined || jsonData.deprecated == true) { 40 | return; 41 | } 42 | 43 | if (jsonData.inputs != undefined) { 44 | var result = `{\n`; 45 | result += `"${jsonData.friendlyName}": {\n`; 46 | result += `"prefix": "ado${jsonData.name}${jsonData.version.Major}",\n`; 47 | result += `"body": [\n`; 48 | result += `"- task: ${jsonData.name}@${jsonData.version.Major}",\n`; 49 | result += `" inputs:",\n`; 50 | 51 | var requiredIndex = 1; 52 | 53 | for (let input of jsonData.inputs) { 54 | result += createLine(input, requiredIndex); 55 | if (input.required) { 56 | requiredIndex++; 57 | } 58 | } 59 | 60 | result += `"$${requiredIndex}"\n`; 61 | result += `],\n`; 62 | var description = escapeAllSpecialCaracters(jsonData.description); 63 | result += `"description": "${description != '' ? description : 'None.'}"\n`; 64 | result += "}\n"; 65 | result += "}\n"; 66 | 67 | return result; 68 | } 69 | } 70 | 71 | function createLine(input: any, index: number): string { 72 | var line = `" ${input.required ? '' : '#'}${input.name}: `; 73 | 74 | if (input.defaultValue != undefined && input.defaultValue != '' && input.required) { 75 | line += `$\{${index}:${escapeAllSpecialCaracters(input.defaultValue)}\} ${displayOptions(input)} # Required `; 76 | } else if (input.required) { 77 | line += `$${index} ${displayOptions(input)} # Required `; 78 | if (input.visibleRule != undefined) { 79 | line += `when ${input.visibleRule} `; 80 | } 81 | } else { 82 | line += `${displayOptions(input)} # Optional `; 83 | } 84 | 85 | if (input.helpMarkDown != undefined && input.helpMarkDown != '') { 86 | line += ` # ${escapeAllSpecialCaracters(input.helpMarkDown)}",\n`; 87 | } else { 88 | line += `",\n`; 89 | } 90 | 91 | return line; 92 | } 93 | 94 | function displayOptions(input: any): string { 95 | if (input.options != undefined) { 96 | var options = '# Options: '; 97 | for (var keys = Object.keys(input.options), i = 0, end = keys.length; i < end; i++) { 98 | options += `'${keys[i]}'`; 99 | if (i < keys.length - 1) { 100 | options += `, `; 101 | } 102 | } 103 | return options; 104 | } 105 | return ''; 106 | } 107 | 108 | function escapeAllSpecialCaracters(value: string): string { 109 | return value != undefined ? value.toString().replace(/\n/g, '').replace(/\\/g, '/\\\/').replace(/"/g, '\\"') : ''; 110 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __generator = (this && this.__generator) || function (thisArg, body) { 12 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 13 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 14 | function verb(n) { return function (v) { return step([n, v]); }; } 15 | function step(op) { 16 | if (f) throw new TypeError("Generator is already executing."); 17 | while (_) try { 18 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 19 | if (y = 0, t) op = [op[0] & 2, t.value]; 20 | switch (op[0]) { 21 | case 0: case 1: t = op; break; 22 | case 4: _.label++; return { value: op[1], done: false }; 23 | case 5: _.label++; y = op[1]; op = [0]; continue; 24 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 25 | default: 26 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 27 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 28 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 29 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 30 | if (t[2]) _.ops.pop(); 31 | _.trys.pop(); continue; 32 | } 33 | op = body.call(thisArg, _); 34 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 35 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 36 | } 37 | }; 38 | exports.__esModule = true; 39 | var path = require("path"); 40 | var snippets_1 = require("./snippets"); 41 | var Handlebars = require("handlebars"); 42 | var fs_helpers_1 = require("./helpers/fs-helpers"); 43 | var commands_helpers_1 = require("./helpers/commands-helpers"); 44 | var outputFolder = 'out'; 45 | var projectFolderName = 'vs-extension'; 46 | function run() { 47 | return __awaiter(this, void 0, void 0, function () { 48 | var projectPath, args, filesNames; 49 | return __generator(this, function (_a) { 50 | switch (_a.label) { 51 | case 0: 52 | console.log("Git clone"); 53 | return [4 /*yield*/, commands_helpers_1.execShellCommand("cd " + outputFolder + " && git clone https://github.com/microsoft/azure-pipelines-tasks.git")]; 54 | case 1: 55 | _a.sent(); 56 | console.log("Git clone done"); 57 | projectPath = path.join(outputFolder, projectFolderName); 58 | args = commands_helpers_1.getArgs(); 59 | console.log(args); 60 | console.log("Create project"); 61 | return [4 /*yield*/, commands_helpers_1.execShellCommand("cp -r templates " + projectPath)]; 62 | case 2: 63 | _a.sent(); 64 | return [4 /*yield*/, commands_helpers_1.execShellCommand("cd " + projectPath + " && mkdir snippets")]; 65 | case 3: 66 | _a.sent(); 67 | console.log("Create project done"); 68 | console.log("Generate snippets"); 69 | return [4 /*yield*/, snippets_1.genereateSnippets(outputFolder, projectPath)]; 70 | case 4: 71 | filesNames = _a.sent(); 72 | console.log("Generate snippets done"); 73 | console.log("Configuration"); 74 | console.log(filesNames); 75 | return [4 /*yield*/, setExtensionConfiguration(args.version, filesNames)]; 76 | case 5: 77 | _a.sent(); 78 | console.log("Configuration done"); 79 | return [2 /*return*/]; 80 | } 81 | }); 82 | }); 83 | } 84 | function setExtensionConfiguration(version, filesNames) { 85 | return __awaiter(this, void 0, void 0, function () { 86 | var vscodeExtensionFolder, packageJsonTemplatePath, source, template, snippets, index; 87 | return __generator(this, function (_a) { 88 | switch (_a.label) { 89 | case 0: 90 | vscodeExtensionFolder = path.join(__dirname, '..', outputFolder, projectFolderName); 91 | packageJsonTemplatePath = path.join(vscodeExtensionFolder, 'package.json.tmpl'); 92 | return [4 /*yield*/, fs_helpers_1.readFile(packageJsonTemplatePath)]; 93 | case 1: 94 | source = _a.sent(); 95 | template = Handlebars.compile(source); 96 | snippets = []; 97 | for (index = 0; index < filesNames.length; index++) { 98 | if (filesNames[index] != undefined) { 99 | snippets.push(JSON.stringify({ 100 | "language": "yaml", 101 | "path": "./snippets/" + filesNames[index] 102 | })); 103 | } 104 | } 105 | return [4 /*yield*/, fs_helpers_1.createFile(vscodeExtensionFolder, 'package.json', template({ 106 | 'version': version, 107 | 'snippets': snippets 108 | }))]; 109 | case 2: 110 | _a.sent(); 111 | return [4 /*yield*/, commands_helpers_1.execShellCommand("rm " + packageJsonTemplatePath)]; 112 | case 3: 113 | _a.sent(); 114 | return [2 /*return*/]; 115 | } 116 | }); 117 | }); 118 | } 119 | run(); 120 | -------------------------------------------------------------------------------- /src/snippets.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __generator = (this && this.__generator) || function (thisArg, body) { 12 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 13 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 14 | function verb(n) { return function (v) { return step([n, v]); }; } 15 | function step(op) { 16 | if (f) throw new TypeError("Generator is already executing."); 17 | while (_) try { 18 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 19 | if (y = 0, t) op = [op[0] & 2, t.value]; 20 | switch (op[0]) { 21 | case 0: case 1: t = op; break; 22 | case 4: _.label++; return { value: op[1], done: false }; 23 | case 5: _.label++; y = op[1]; op = [0]; continue; 24 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 25 | default: 26 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 27 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 28 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 29 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 30 | if (t[2]) _.ops.pop(); 31 | _.trys.pop(); continue; 32 | } 33 | op = body.call(thisArg, _); 34 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 35 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 36 | } 37 | }; 38 | exports.__esModule = true; 39 | var path = require("path"); 40 | var fs = require("fs"); 41 | var fs_helpers_1 = require("./helpers/fs-helpers"); 42 | function genereateSnippets(outputFolder, projectFolderName) { 43 | return __awaiter(this, void 0, void 0, function () { 44 | var directoryPath, filesNames, folders; 45 | return __generator(this, function (_a) { 46 | switch (_a.label) { 47 | case 0: 48 | directoryPath = path.join(__dirname, '..', outputFolder, 'azure-pipelines-tasks/Tasks'); 49 | filesNames = []; 50 | return [4 /*yield*/, fs_helpers_1.readDirectory(directoryPath)]; 51 | case 1: 52 | folders = _a.sent(); 53 | folders.forEach(function (folder) { 54 | filesNames.push(create(path.join(directoryPath, folder, 'task.json'), folder, projectFolderName)); 55 | }); 56 | return [4 /*yield*/, Promise.all(filesNames)]; 57 | case 2: return [2 /*return*/, _a.sent()]; 58 | } 59 | }); 60 | }); 61 | } 62 | exports.genereateSnippets = genereateSnippets; 63 | function create(filePath, taskName, snippetsFolder) { 64 | return __awaiter(this, void 0, void 0, function () { 65 | return __generator(this, function (_a) { 66 | return [2 /*return*/, new Promise(function (resolve, reject) { 67 | return __awaiter(this, void 0, void 0, function () { 68 | var taskDefinition, snippet, outputSnippetsFolder, taskFileName; 69 | return __generator(this, function (_a) { 70 | switch (_a.label) { 71 | case 0: 72 | if (!fs.existsSync(filePath)) return [3 /*break*/, 3]; 73 | return [4 /*yield*/, fs_helpers_1.readFile(filePath)]; 74 | case 1: 75 | taskDefinition = _a.sent(); 76 | if (!(taskDefinition != undefined)) return [3 /*break*/, 3]; 77 | snippet = formatSnippet(taskDefinition); 78 | if (!(snippet != undefined)) return [3 /*break*/, 3]; 79 | outputSnippetsFolder = path.join(__dirname, '..', snippetsFolder, 'snippets'); 80 | taskFileName = taskName + ".json"; 81 | return [4 /*yield*/, fs_helpers_1.createFile(outputSnippetsFolder, taskFileName, snippet)]; 82 | case 2: 83 | _a.sent(); 84 | resolve(taskFileName); 85 | _a.label = 3; 86 | case 3: return [2 /*return*/, resolve(undefined)]; 87 | } 88 | }); 89 | }); 90 | })]; 91 | }); 92 | }); 93 | } 94 | function formatSnippet(json) { 95 | var jsonData = JSON.parse(json); 96 | if (jsonData.deprecated != undefined || jsonData.deprecated == true) { 97 | return; 98 | } 99 | if (jsonData.inputs != undefined) { 100 | var result = "{\n"; 101 | result += "\"" + jsonData.friendlyName + "\": {\n"; 102 | result += "\"prefix\": \"ado" + jsonData.name + jsonData.version.Major + "\",\n"; 103 | result += "\"body\": [\n"; 104 | result += "\"- task: " + jsonData.name + "@" + jsonData.version.Major + "\",\n"; 105 | result += "\" inputs:\",\n"; 106 | var requiredIndex = 1; 107 | for (var _i = 0, _a = jsonData.inputs; _i < _a.length; _i++) { 108 | var input = _a[_i]; 109 | result += createLine(input, requiredIndex); 110 | if (input.required) { 111 | requiredIndex++; 112 | } 113 | } 114 | result += "\"$" + requiredIndex + "\"\n"; 115 | result += "],\n"; 116 | var description = escapeAllSpecialCaracters(jsonData.description); 117 | result += "\"description\": \"" + (description != '' ? description : 'None.') + "\"\n"; 118 | result += "}\n"; 119 | result += "}\n"; 120 | return result; 121 | } 122 | } 123 | function createLine(input, index) { 124 | var line = "\" " + (input.required ? '' : '#') + input.name + ": "; 125 | if (input.defaultValue != undefined && input.defaultValue != '' && input.required) { 126 | line += "${" + index + ":" + escapeAllSpecialCaracters(input.defaultValue) + "} " + displayOptions(input) + " # Required "; 127 | } 128 | else if (input.required) { 129 | line += "$" + index + " " + displayOptions(input) + " # Required "; 130 | if (input.visibleRule != undefined) { 131 | line += "when " + input.visibleRule + " "; 132 | } 133 | } 134 | else { 135 | line += displayOptions(input) + " # Optional "; 136 | } 137 | if (input.helpMarkDown != undefined && input.helpMarkDown != '') { 138 | line += " # " + escapeAllSpecialCaracters(input.helpMarkDown) + "\",\n"; 139 | } 140 | else { 141 | line += "\",\n"; 142 | } 143 | return line; 144 | } 145 | function displayOptions(input) { 146 | if (input.options != undefined) { 147 | var options = '# Options: '; 148 | for (var keys = Object.keys(input.options), i = 0, end = keys.length; i < end; i++) { 149 | options += "'" + keys[i] + "'"; 150 | if (i < keys.length - 1) { 151 | options += ", "; 152 | } 153 | } 154 | return options; 155 | } 156 | return ''; 157 | } 158 | function escapeAllSpecialCaracters(value) { 159 | return value != undefined ? value.toString().replace(/\n/g, '').replace(/\\/g, '/\\\/').replace(/"/g, '\\"') : ''; 160 | } 161 | --------------------------------------------------------------------------------