├── debug ├── rustc │ ├── test.rs │ ├── noOptions.ts │ └── options.ts ├── common │ ├── input.ts │ └── debug.ts ├── cargo │ ├── sample │ │ ├── Cargo.toml │ │ ├── Cargo.lock │ │ └── src │ │ │ └── main.rs │ ├── noOptions.ts │ └── options.ts ├── rustup │ ├── noArgs.ts │ └── args.ts └── install │ ├── default.ts │ └── nigthly.ts ├── icon.png ├── tasks ├── cargo │ ├── icon.png │ ├── package.json │ └── task.json ├── install │ ├── icon.png │ ├── package.json │ └── task.json ├── rustc │ ├── icon.png │ ├── package.json │ └── task.json └── rustup │ ├── icon.png │ ├── package.json │ └── task.json ├── images ├── doc-cargo-task.png ├── doc-other-tasks.png ├── screenshot-cargo.png ├── screenshot-tasks.png ├── screenshot-install.png └── doc-rust-installer-task.png ├── src ├── common │ ├── options.ts │ ├── launch.ts │ ├── path.ts │ └── command.ts ├── rustc.ts ├── rustup.ts ├── cargo.ts └── install.ts ├── tsconfig.json ├── tslint.json ├── .vscode └── launch.json ├── LICENSE ├── .gitignore ├── README.md ├── package.json ├── DETAILS.md ├── gulpfile.js ├── vss-extension.json ├── CODE_OF_CONDUCT.md └── CONTRIBUTING.md /debug/rustc/test.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello world"); 3 | } -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spontoreau/rust-azure-devops/HEAD/icon.png -------------------------------------------------------------------------------- /debug/common/input.ts: -------------------------------------------------------------------------------- 1 | export interface Input { 2 | name: string; 3 | value: string; 4 | } 5 | -------------------------------------------------------------------------------- /tasks/cargo/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spontoreau/rust-azure-devops/HEAD/tasks/cargo/icon.png -------------------------------------------------------------------------------- /tasks/install/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spontoreau/rust-azure-devops/HEAD/tasks/install/icon.png -------------------------------------------------------------------------------- /tasks/rustc/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spontoreau/rust-azure-devops/HEAD/tasks/rustc/icon.png -------------------------------------------------------------------------------- /tasks/rustup/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spontoreau/rust-azure-devops/HEAD/tasks/rustup/icon.png -------------------------------------------------------------------------------- /images/doc-cargo-task.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spontoreau/rust-azure-devops/HEAD/images/doc-cargo-task.png -------------------------------------------------------------------------------- /images/doc-other-tasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spontoreau/rust-azure-devops/HEAD/images/doc-other-tasks.png -------------------------------------------------------------------------------- /images/screenshot-cargo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spontoreau/rust-azure-devops/HEAD/images/screenshot-cargo.png -------------------------------------------------------------------------------- /images/screenshot-tasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spontoreau/rust-azure-devops/HEAD/images/screenshot-tasks.png -------------------------------------------------------------------------------- /images/screenshot-install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spontoreau/rust-azure-devops/HEAD/images/screenshot-install.png -------------------------------------------------------------------------------- /images/doc-rust-installer-task.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spontoreau/rust-azure-devops/HEAD/images/doc-rust-installer-task.png -------------------------------------------------------------------------------- /debug/cargo/sample/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "factorial" 3 | version = "0.1.0" 4 | authors = ["spontoreau "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /debug/cargo/sample/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "factorial" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /debug/cargo/noOptions.ts: -------------------------------------------------------------------------------- 1 | import debug from "../common/debug"; 2 | 3 | const cargoCommandInput = { 4 | name: "cargoCommand", 5 | value: "help" 6 | }; 7 | 8 | debug("cargo.js", cargoCommandInput); 9 | -------------------------------------------------------------------------------- /debug/rustup/noArgs.ts: -------------------------------------------------------------------------------- 1 | import debug from "../common/debug"; 2 | 3 | const rustupCommandInput = { 4 | name: "rustupCommand", 5 | value: "show" 6 | }; 7 | 8 | debug("rustup.js", rustupCommandInput); 9 | -------------------------------------------------------------------------------- /debug/install/default.ts: -------------------------------------------------------------------------------- 1 | import debug from "../common/debug"; 2 | 3 | const installNightlyInput = { 4 | name: "installNightly", 5 | value: "false" 6 | }; 7 | 8 | debug("install.js", installNightlyInput); 9 | -------------------------------------------------------------------------------- /debug/install/nigthly.ts: -------------------------------------------------------------------------------- 1 | import debug from "../common/debug"; 2 | 3 | const installNightlyInput = { 4 | name: "installNightly", 5 | value: "true" 6 | }; 7 | 8 | debug("install.js", installNightlyInput); 9 | -------------------------------------------------------------------------------- /src/common/options.ts: -------------------------------------------------------------------------------- 1 | import { getBoolInput } from "azure-pipelines-task-lib"; 2 | 3 | const getVerboseOption = () => { 4 | return getBoolInput("verbose") ? "--verbose" : ""; 5 | }; 6 | 7 | export { getVerboseOption }; 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true 7 | }, 8 | "exclude": [ 9 | "node_modules" 10 | ] 11 | } -------------------------------------------------------------------------------- /debug/rustc/noOptions.ts: -------------------------------------------------------------------------------- 1 | import debug from "../common/debug"; 2 | import { join } from "path"; 3 | 4 | const rustcInput = { 5 | name: "rustcInput", 6 | value: join(__dirname, "test.rs") 7 | }; 8 | 9 | debug("rustc.js", rustcInput); 10 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended", 5 | "tslint-config-prettier" 6 | ], 7 | "jsRules": {}, 8 | "rules": { 9 | "interface-name": [true, "never-prefix"], 10 | "member-access": [true, "no-public"], 11 | "interface-over-type-literal": false 12 | }, 13 | "rulesDirectory": [] 14 | } -------------------------------------------------------------------------------- /tasks/install/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rust-vsts-install", 3 | "version": "1.0.0", 4 | "description": "Azure DevOps task that allows developers to install Rust.", 5 | "main": "index.js", 6 | "author": "Sylvain Pontoreau", 7 | "license": "MIT", 8 | "dependencies": { 9 | "azure-pipelines-task-lib": "^2.7.7" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tasks/rustc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rust-vsts-rustc", 3 | "version": "1.0.0", 4 | "description": "Azure DevOps task that allows developers to compile a Rust file (.rs).", 5 | "main": "index.js", 6 | "author": "Sylvain Pontoreau", 7 | "license": "MIT", 8 | "dependencies": { 9 | "azure-pipelines-task-lib": "^2.7.7" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/common/launch.ts: -------------------------------------------------------------------------------- 1 | import { setResult, TaskResult } from "azure-pipelines-task-lib"; 2 | 3 | const launch = async (task: (...parameters: any[]) => Promise) => { 4 | try { 5 | const resultMessage = await task(); 6 | setResult(TaskResult.Succeeded, resultMessage); 7 | } catch (e) { 8 | setResult(TaskResult.Failed, e.message); 9 | } 10 | }; 11 | 12 | export { launch }; 13 | -------------------------------------------------------------------------------- /tasks/cargo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rust-vsts-cargo", 3 | "version": "1.0.0", 4 | "description": "Azure DevOps task that allows developers to execute a command with Cargo, the Rust package manager.", 5 | "main": "index.js", 6 | "author": "Sylvain Pontoreau", 7 | "license": "MIT", 8 | "dependencies": { 9 | "azure-pipelines-task-lib": "^2.7.7" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tasks/rustup/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rust-vsts-rustup", 3 | "version": "1.0.0", 4 | "description": "Azure DevOps task that allows developers to execute a command with Rustup, the Rust toolchain installer.", 5 | "main": "index.js", 6 | "author": "Sylvain Pontoreau", 7 | "license": "MIT", 8 | "dependencies": { 9 | "azure-pipelines-task-lib": "^2.7.7" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /debug/cargo/sample/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Factorial of 0: {}", factorial(0)); 3 | println!("Factorial of 1: {}", factorial(1)); 4 | println!("Factorial of 2: {}", factorial(2)); 5 | println!("Factorial of 5: {}", factorial(5)); 6 | println!("Factorial of 9: {}", factorial(9)); 7 | } 8 | 9 | fn factorial(n: u32) -> u32 { 10 | return if n >= 1 { n * factorial(n - 1) } else { 1 }; 11 | } -------------------------------------------------------------------------------- /debug/rustup/args.ts: -------------------------------------------------------------------------------- 1 | import debug from "../common/debug"; 2 | 3 | const rustupCommandInput = { 4 | name: "rustupCommand", 5 | value: "target" 6 | }; 7 | 8 | const rustupCommandArgsInput = { 9 | name: "rustupCommandArguments", 10 | value: "list" 11 | }; 12 | 13 | const verbose = { 14 | name: "verbose", 15 | value: "true" 16 | }; 17 | 18 | debug("rustup.js", rustupCommandInput, rustupCommandArgsInput, verbose); 19 | -------------------------------------------------------------------------------- /debug/common/debug.ts: -------------------------------------------------------------------------------- 1 | import { join } from "path"; 2 | import { TaskMockRunner } from "azure-pipelines-task-lib/mock-run"; 3 | import { Input } from "./input"; 4 | 5 | export default (file: string, ...input: Input[]) => { 6 | const taskPath = join(__dirname, "../../src", file); 7 | const taskMockRunner = new TaskMockRunner(taskPath); 8 | input.forEach(i => taskMockRunner.setInput(i.name, i.value)); 9 | taskMockRunner.run(); 10 | }; 11 | -------------------------------------------------------------------------------- /debug/rustc/options.ts: -------------------------------------------------------------------------------- 1 | import debug from "../common/debug"; 2 | import { join } from "path"; 3 | 4 | const rustcInput = { 5 | name: "rustcInput", 6 | value: join(__dirname, "test.rs") 7 | }; 8 | 9 | const rustcOptions = { 10 | name: "rustcOptions", 11 | value: "-o azure-devops-rustc-debug" 12 | }; 13 | 14 | const verbose = { 15 | name: "verbose", 16 | value: "true" 17 | }; 18 | 19 | debug("rustc.js", rustcOptions, rustcInput, verbose); 20 | -------------------------------------------------------------------------------- /src/rustc.ts: -------------------------------------------------------------------------------- 1 | import { getInput } from "azure-pipelines-task-lib"; 2 | import { createInputCommand, executeCommand } from "./common/command"; 3 | import { launch } from "./common/launch"; 4 | import { getVerboseOption } from "./common/options"; 5 | 6 | const command = createInputCommand( 7 | "rustc", 8 | getInput("rustcInput"), 9 | `${getInput("rustcOptions")} ${getVerboseOption()}` 10 | ); 11 | 12 | launch(async () => await executeCommand(command)); 13 | -------------------------------------------------------------------------------- /src/rustup.ts: -------------------------------------------------------------------------------- 1 | import { getInput } from "azure-pipelines-task-lib"; 2 | import { createCommand, executeCommand } from "./common/command"; 3 | import { launch } from "./common/launch"; 4 | import { getVerboseOption } from "./common/options"; 5 | 6 | const command = createCommand( 7 | "rustup", 8 | `${getVerboseOption()} ${getInput("rustupCommand")}`, 9 | getInput("rustupCommandArguments") 10 | ); 11 | 12 | launch(async () => await executeCommand(command)); 13 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 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 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Debug file", 11 | "program": "${file}", 12 | "outFiles": [ 13 | "${workspaceFolder}/**/*.js" 14 | ] 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /debug/cargo/options.ts: -------------------------------------------------------------------------------- 1 | import debug from "../common/debug"; 2 | import { join } from "path"; 3 | 4 | const cargoCommandInput = { 5 | name: "cargoCommand", 6 | value: "build" 7 | }; 8 | 9 | const cargoCommandOptionsInput = { 10 | name: "cargoCommandOptions", 11 | value: "--release" 12 | }; 13 | 14 | const cargoCommandWorkingDirectory = { 15 | name: "cargoWorkingDir", 16 | value: join(__dirname, "sample") 17 | }; 18 | 19 | const verbose = { 20 | name: "verbose", 21 | value: "true" 22 | }; 23 | 24 | debug( 25 | "cargo.js", 26 | cargoCommandInput, 27 | cargoCommandOptionsInput, 28 | cargoCommandWorkingDirectory, 29 | verbose 30 | ); 31 | -------------------------------------------------------------------------------- /src/cargo.ts: -------------------------------------------------------------------------------- 1 | import { getInput } from "azure-pipelines-task-lib"; 2 | import { join } from "path"; 3 | import { createCommand, executeCommand } from "./common/command"; 4 | import { launch } from "./common/launch"; 5 | import { getVerboseOption } from "./common/options"; 6 | 7 | const workingDir = getInput("cargoWorkingDir"); 8 | const manifestPath = !workingDir 9 | ? "" 10 | : `--manifest-path ${join(workingDir, "Cargo.toml")}`; 11 | 12 | const command = createCommand( 13 | "cargo", 14 | getInput("cargoCommand"), 15 | `${getInput("cargoCommandOptions")} ${manifestPath} ${getVerboseOption()}` 16 | ); 17 | 18 | launch(async () => await executeCommand(command)); 19 | -------------------------------------------------------------------------------- /src/common/path.ts: -------------------------------------------------------------------------------- 1 | import { homedir } from "os"; 2 | import { delimiter, join } from "path"; 3 | import process from "process"; 4 | 5 | const addRustToolToPath = () => { 6 | const toolPath = getToolPath(); 7 | const path = process.env.PATH; 8 | process.env.PATH = !path ? toolPath : combineToPath(path, toolPath); 9 | }; 10 | 11 | const combineToPath = (path: string, toolPath: string) => { 12 | return isInPath(path, toolPath) ? path : `${toolPath}${delimiter}${path}`; 13 | }; 14 | 15 | const isInPath = (path: string, toolPath: string) => { 16 | return !!path && path.indexOf(toolPath) !== -1; 17 | }; 18 | 19 | const getToolPath = () => { 20 | return join(homedir(), ".cargo", "bin"); 21 | }; 22 | 23 | export { addRustToolToPath }; 24 | -------------------------------------------------------------------------------- /tasks/install/task.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "186585e2-87f4-43af-9224-6aa5298a1c5a", 3 | "name": "Rust", 4 | "friendlyName": "Rust Tool Installer", 5 | "description": "Install the latest version of Rust.", 6 | "helpMarkdown": "For more information, take a look at the Rustup [documentation](https://rustup.rs)", 7 | "category": "Tool", 8 | "author": "Sylvain Pontoreau", 9 | "version": { 10 | "Major": 1, 11 | "Minor": 0, 12 | "Patch": 0 13 | }, 14 | "instanceNameFormat": "Rust Tool Installer", 15 | "groups": [ 16 | { 17 | "name": "advanced", 18 | "displayName": "Advanced", 19 | "isExpanded": false 20 | } 21 | ], 22 | "inputs": [ 23 | { 24 | "name": "installNightly", 25 | "type": "boolean", 26 | "label": "Install nightly", 27 | "helpMarkDown": "Access to the nightly compiler and its experimental features.", 28 | "defaultValue": "false", 29 | "required": true, 30 | "groupName": "advanced" 31 | } 32 | ], 33 | "execution": { 34 | "Node": { 35 | "target": "index.js" 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Sylvain PONTOREAU 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. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | #tsc 64 | src/**/*.js 65 | debug/**/*.js 66 | **/*.js.map 67 | 68 | #gulp 69 | tmp/ 70 | 71 | # tfx 72 | dist/ 73 | .taskkey 74 | 75 | # rust 76 | debug/**/target/ 77 | 78 | #macOS 79 | .DS_Store -------------------------------------------------------------------------------- /tasks/rustc/task.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "9a42f43b-1191-4139-a980-32915814b378", 3 | "name": "Rustc", 4 | "friendlyName": "Rustc", 5 | "description": "Compile a Rust file (.rs).", 6 | "helpMarkdown": "For more information about Rust compiler, take a look at the official [documentation](https://www.rust-lang.org)", 7 | "category": "Build", 8 | "author": "Sylvain Pontoreau", 9 | "version": { 10 | "Major": 1, 11 | "Minor": 0, 12 | "Patch": 0 13 | }, 14 | "instanceNameFormat": "Rustc", 15 | "groups": [ 16 | { 17 | "name": "advanced", 18 | "displayName": "Advanced", 19 | "isExpanded": false 20 | } 21 | ], 22 | "inputs": [ 23 | { 24 | "name": "rustcInput", 25 | "type": "filePath", 26 | "label": "File", 27 | "helpMarkDown": "Rust file to compile (.rs).", 28 | "defaultValue": "", 29 | "required": true 30 | }, 31 | { 32 | "name": "rustcOptions", 33 | "type": "string", 34 | "label": "Options", 35 | "helpMarkDown": "Compiler options.", 36 | "defaultValue": "", 37 | "required": false 38 | }, 39 | { 40 | "name": "verbose", 41 | "type": "boolean", 42 | "label": "Verbose logging", 43 | "helpMarkDown": "Select to print more information to the console on run", 44 | "defaultValue": "false", 45 | "required": true, 46 | "groupName": "advanced" 47 | } 48 | ], 49 | "execution": { 50 | "Node": { 51 | "target": "index.js" 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ⚠️ **This project is no longer maintain, use instead Azure pipelines YAML file to setup CI in your Rust projects** ⚠️ 2 | 3 | # Rust extension for Azure DevOps 4 | 5 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) 6 | [![Marketplace](https://img.shields.io/badge/marketplace-public-brightgreen.svg)](https://marketplace.visualstudio.com/items?itemName=spontoreau.rust-vsts) 7 | [![Chat](https://img.shields.io/badge/chat-on%20slack-brightgreen.svg)](https://join.slack.com/t/rust-azure-devops/shared_invite/enQtMzkxNzU4MTgyMDg2LTlkMjJmMzM2MmIyYmJmMjFmNDJkN2IzZmMxZDFhZTgyOGFjYWExNTkwM2YwYTQ3YmI3OWNlYjBhYjcyNGY5OTM) 8 | [![Build Status](https://img.shields.io/vso/build/spontoreau/d5f5ab40-dda9-46c8-8f62-1e8d2e3f7143/5.svg)](https://dev.azure.com/spontoreau/rust-azure-devops/_build?definitionId=5) 9 | 10 | An [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) extension to manage [Rust](https://www.rust-lang.org) projects 🦀. Take a look to this extension on the Visual Studio [marketplace](https://marketplace.visualstudio.com/items?itemName=spontoreau.rust-vsts). 11 | 12 | ## Contribution 13 | 14 | For any contribution (Issue and PR), please follow project [guidelines](CONTRIBUTING.md). 15 | 16 | Add a ⭐️ is also a way to contribute to this repository 😉 17 | 18 | This project has adopted the code of conduct defined by the [Contributor Covenant](https://www.contributor-covenant.org/). Before contributing to this repository, take a look at the [code of conduct](CODE_OF_CONDUCT.md). 19 | 20 | ## Licence 21 | 22 | [MIT](LICENSE) 23 | -------------------------------------------------------------------------------- /tasks/rustup/task.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "e9db5036-d9c9-4a13-bef0-9cf5cff5f6e3", 3 | "name": "Rustup", 4 | "friendlyName": "Rustup", 5 | "description": "Execute a command with Rustup, the Rust toolchain installer.", 6 | "helpMarkdown": "For more information about Rustup, take a look at the official [documentation](https://rustup.rs)", 7 | "category": "Tool", 8 | "author": "Sylvain Pontoreau", 9 | "version": { 10 | "Major": 1, 11 | "Minor": 0, 12 | "Patch": 0 13 | }, 14 | "instanceNameFormat": "Rustup", 15 | "groups": [ 16 | { 17 | "name": "advanced", 18 | "displayName": "Advanced", 19 | "isExpanded": false 20 | } 21 | ], 22 | "inputs": [ 23 | { 24 | "name": "rustupCommand", 25 | "type": "string", 26 | "label": "Command", 27 | "helpMarkDown": "Rustup command to execute (example: update, default, target...)", 28 | "defaultValue": "", 29 | "required": true 30 | }, { 31 | "name": "rustupCommandArguments", 32 | "type": "string", 33 | "label": "Arguments", 34 | "helpMarkDown": "Command arguments.", 35 | "defaultValue": "", 36 | "required": false 37 | }, 38 | { 39 | "name": "verbose", 40 | "type": "boolean", 41 | "label": "Verbose logging", 42 | "helpMarkDown": "Select to print more information to the console on run", 43 | "defaultValue": "false", 44 | "required": true, 45 | "groupName": "advanced" 46 | } 47 | ], 48 | "execution": { 49 | "Node": { 50 | "target": "index.js" 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/install.ts: -------------------------------------------------------------------------------- 1 | import { 2 | debug, 3 | exec, 4 | getBoolInput, 5 | tool, 6 | which 7 | } from "azure-pipelines-task-lib"; 8 | import { createCommand, executeCommand } from "./common/command"; 9 | import { launch } from "./common/launch"; 10 | import { addRustToolToPath } from "./common/path"; 11 | 12 | const nightly = getBoolInput("installNightly"); 13 | 14 | const install = async () => { 15 | debug("Rustup not available."); 16 | return await tool(which("curl")) 17 | .arg("https://sh.rustup.rs") 18 | .arg("-sSf") 19 | .pipeExecOutputToTool( 20 | tool(which("sh")) 21 | .arg("-s") 22 | .arg("--") 23 | .arg("-y") 24 | ) 25 | .exec(); 26 | }; 27 | 28 | const update = async () => { 29 | debug("Rustup available."); 30 | return await exec("rustup", "update"); 31 | }; 32 | 33 | const installNightly = async () => { 34 | const installCommand = createCommand("rustup", "install", "nightly"); 35 | const defaultCommand = createCommand("rustup", "default", "nightly"); 36 | await executeCommand(installCommand); 37 | return await executeCommand(defaultCommand, "Rust nightly installed"); 38 | }; 39 | 40 | const checkUpdateResult = (returnCode: Readonly) => { 41 | debug(`Return code: ${returnCode}`); 42 | if (returnCode !== 0) { 43 | throw new Error("Rustup update failed."); 44 | } 45 | return "Rust updated"; 46 | }; 47 | 48 | launch(async () => { 49 | addRustToolToPath(); 50 | const returnCode = which("rustup") ? await update() : await install(); 51 | const resultMessage = checkUpdateResult(returnCode); 52 | return nightly ? await installNightly() : resultMessage; 53 | }); 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rust-vsts", 3 | "version": "1.0.0", 4 | "description": "Rust extension for Azure DevOps", 5 | "main": "index.js", 6 | "scripts": { 7 | "lint": "tslint -c tslint.json 'src/**/*.ts'", 8 | "compile": "tsc", 9 | "build": "npm run format && gulp", 10 | "package": "gulp pre-package && tfx extension create --root ./tmp --manifest-globs ./vss-extension.json --output-path ./dist", 11 | "deploy": "tfx extension publish", 12 | "format": "prettier --write \"src/**/*.ts\"" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/spontoreau/rust-azure-devops.git" 17 | }, 18 | "keywords": [ 19 | "rust", 20 | "rust language", 21 | "cargo", 22 | "build", 23 | "azure devops", 24 | "ci", 25 | "continious integration" 26 | ], 27 | "author": "Sylvain Pontoreau", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/spontoreau/rust-azure-devops/issues" 31 | }, 32 | "homepage": "https://github.com/spontoreau/rust-azure-devops#readme", 33 | "dependencies": { 34 | "azure-pipelines-task-lib": "^2.7.7" 35 | }, 36 | "devDependencies": { 37 | "@types/node": "^10.12.21", 38 | "@types/q": "^1.5.1", 39 | "del": "^3.0.0", 40 | "gulp": "^3.9.1", 41 | "gulp-json-editor": "^2.5.0", 42 | "gulp-rename": "^1.4.0", 43 | "gulp-run": "^1.7.1", 44 | "gulp-typescript": "^5.0.0", 45 | "moment": "^2.24.0", 46 | "prettier": "^1.16.4", 47 | "run-sequence": "^2.2.1", 48 | "tfx-cli": "^0.6.4", 49 | "tslint": "^5.12.1", 50 | "tslint-config-prettier": "^1.18.0", 51 | "typescript": "^3.3.1", 52 | "yargs": "^12.0.5" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/common/command.ts: -------------------------------------------------------------------------------- 1 | import { exec, getBoolInput, which } from "azure-pipelines-task-lib"; 2 | 3 | import { addRustToolToPath } from "./path"; 4 | 5 | type Command = { 6 | tool: string; 7 | name: string; 8 | args: string[]; 9 | }; 10 | 11 | type InputCommand = { 12 | tool: string; 13 | input: string; 14 | args: string[]; 15 | }; 16 | 17 | const executeCommand = async ( 18 | command: Command | InputCommand, 19 | resultMessage: string = "Task done!" 20 | ): Promise => { 21 | addRustToolToPath(); 22 | const toolArgs = getToolArgs(command); 23 | return which("cargo") 24 | ? (await exec(command.tool, toolArgs)) > 0 25 | ? Promise.reject(new Error("An error has occured.")) 26 | : Promise.resolve(resultMessage) 27 | : Promise.reject(new Error("Rust toolchains are not available.")); 28 | }; 29 | 30 | const getToolArgs = (command: Command | InputCommand): string => { 31 | const fullCommand = isInputCommand(command) 32 | ? [...command.args, command.input] 33 | : [command.name, ...command.args]; 34 | return fullCommand 35 | .filter(p => p !== null && !p.includes("null")) 36 | .reduce((p, n) => `${p} ${n}`) 37 | .trim(); 38 | }; 39 | 40 | const isInputCommand = (command: any): command is InputCommand => { 41 | return command.input !== undefined; 42 | }; 43 | 44 | const createCommand = ( 45 | tool: string, 46 | name: string, 47 | options: string 48 | ): Command => { 49 | return { 50 | args: !!options ? options.split(" ") : [], 51 | name, 52 | tool 53 | }; 54 | }; 55 | 56 | const createInputCommand = ( 57 | tool: string, 58 | input: string, 59 | options: string 60 | ): InputCommand => { 61 | return { 62 | args: !!options ? options.split(" ") : [], 63 | input, 64 | tool 65 | }; 66 | }; 67 | 68 | export { Command, executeCommand, createCommand, createInputCommand }; 69 | -------------------------------------------------------------------------------- /tasks/cargo/task.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "591c95b8-517f-41bd-807e-4de6a95cee24", 3 | "name": "Cargo", 4 | "friendlyName": "Cargo", 5 | "description": "Execute a command with Cargo, the Rust package manager.", 6 | "helpMarkdown": "For more information about Cargo, take a look at the official [documentation](https://doc.rust-lang.org/cargo/)", 7 | "category": "Build", 8 | "author": "Sylvain Pontoreau", 9 | "version": { 10 | "Major": 1, 11 | "Minor": 0, 12 | "Patch": 0 13 | }, 14 | "instanceNameFormat": "Cargo", 15 | "groups": [ 16 | { 17 | "name": "advanced", 18 | "displayName": "Advanced", 19 | "isExpanded": false 20 | } 21 | ], 22 | "inputs": [ 23 | { 24 | "name": "cargoCommand", 25 | "type": "string", 26 | "label": "Command", 27 | "helpMarkDown": "Cargo command to execute (example: build, test, update, install, doc...)", 28 | "defaultValue": "", 29 | "required": true 30 | }, 31 | { 32 | "name": "cargoWorkingDir", 33 | "type": "filePath", 34 | "label": "Working folder that contains Cargo.toml", 35 | "helpMarkDown": "Path to the folder containing the Cargo.toml file.", 36 | "defaultValue": "", 37 | "required": false 38 | }, 39 | { 40 | "name": "cargoCommandOptions", 41 | "type": "string", 42 | "label": "Options", 43 | "helpMarkDown": "Command options.", 44 | "defaultValue": "", 45 | "required": false 46 | }, 47 | { 48 | "name": "verbose", 49 | "type": "boolean", 50 | "label": "Verbose logging", 51 | "helpMarkDown": "Select to print more information to the console on run", 52 | "defaultValue": "false", 53 | "required": true, 54 | "groupName": "advanced" 55 | } 56 | ], 57 | "execution": { 58 | "Node": { 59 | "target": "index.js" 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /DETAILS.md: -------------------------------------------------------------------------------- 1 | Rust 🦀 2 | === 3 | 4 | ⚠️ **This extension is no longer maintain, use instead Azure Pipelines YAML file to setup CI in your Rust projects** ⚠️ 5 | 6 | This extension contains tasks that can be used to manage **Rust** projects. 7 | 8 | **Rust** is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety. For more information on **Rust**, take a look at the official [documentation](https://www.rust-lang.org). 9 | 10 | ## Rust Tool Installer 11 | 12 | The extension adds the **Rust Tool Installer** task inside the **Tool** category. It installs **rustup** and the latest version of the **Rust** toolchain. Always ensure you have run this task first, others need it to run. 13 | 14 | By default, the task will install the latest stable version. You can also install the **nightly** one by changing the advanced settings: 15 | 16 | ![Nightly](images/doc-rust-installer-task.png) 17 | 18 | ## Cargo 19 | 20 | **Cargo** task is available in the **Build** category. 21 | 22 | ![Rustup & Rustc](images/doc-cargo-task.png) 23 | 24 | Parameters: 25 | 26 | - **Command**: Cargo subcommand to execute (example: build, test, update, install, doc...). 27 | - **Working directory**: Working folder that contains Cargo.toml (optional). 28 | - **Options**: Subcommand options (optional). 29 | 30 | ## Other tasks 31 | 32 | The extension also contains: 33 | 34 | ![Rustup & Rustc](images/doc-other-tasks.png) 35 | 36 | Those tasks can be used in the same way as the **Cargo** one. 37 | 38 | ## Features and bugs 39 | 40 | You've got a feature request? You found a bug? 41 | 42 | Don't hesitate to create an issue on [github](https://github.com/spontoreau/rust-azure-devops/issues)! 43 | 44 | ## Like this extension? 45 | 46 | - Don't forget to add a ⭐️ on [Github](https://github.com/spontoreau/rust-azure-devops) 47 | - You can also ✍️ a [review](https://marketplace.visualstudio.com/items?itemName=spontoreau.rust-vsts#review-details)! 48 | - Or share it on Twitter (cc [@spontoreau](https://twitter.com/spontoreau)) 49 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require("gulp"); 2 | const tsc = require("gulp-typescript"); 3 | const del = require("del"); 4 | const runSequence = require("run-sequence"); 5 | const rename = require("gulp-rename"); 6 | const jeditor = require("gulp-json-editor"); 7 | const run = require("gulp-run"); 8 | const argv = require('yargs').argv; 9 | const fs = require("fs"); 10 | const moment = require("moment"); 11 | 12 | const env = argv.release ? "" : "-private"; 13 | const patch = (argv.patch !== null && argv.patch !== undefined) 14 | ? argv.patch 15 | : moment().format("YYDDDHHmm");; 16 | 17 | gulp.task("clean", () => del.sync("tmp")); 18 | 19 | gulp.task("compile", () => { 20 | const tscConfig = tsc.createProject("tsconfig.json", { 21 | target: "es2015", 22 | module: "commonjs", 23 | noResolve: false, 24 | typescript: require("typescript") 25 | }); 26 | 27 | return gulp 28 | .src(["./src/**/*.ts", '!./src/debug/**/*.*']) 29 | .pipe(tscConfig()) 30 | .on("error", () => process.exit(1)) 31 | .pipe(gulp.dest("./tmp/")); 32 | }); 33 | 34 | gulp.task("copy", () => { 35 | const streams = [ 36 | gulp 37 | .src("./tasks/**/*.*") 38 | .pipe(gulp.dest("./tmp/tasks")), 39 | gulp 40 | .src("./vss-extension.json") 41 | .pipe(jeditor((json) => { 42 | json.id = `rust-vsts${env}`; 43 | json.name = `Rust${env}`; 44 | json.public = env ? false : true; 45 | json.version = json.version.replace("{patch}", patch); 46 | return json; 47 | })) 48 | .pipe(gulp.dest("./tmp/")), 49 | gulp 50 | .src(["./DETAILS.md", "./LICENSE", "./icon.png"]) 51 | .pipe(gulp.dest("./tmp/")), 52 | gulp 53 | .src("./images/*.png") 54 | .pipe(gulp.dest("./tmp/images/")) 55 | ]; 56 | 57 | fs.readdirSync("./tmp/").forEach((file) => { 58 | const source = `./tmp/${file}`; 59 | const stat = fs.statSync(source); 60 | 61 | if (stat && stat.isFile()) { 62 | const target = `./tmp/tasks/${file.replace(/\.[^/.]+$/, "")}`; 63 | const stream = gulp 64 | .src(source) 65 | .pipe(rename("index.js")) 66 | .pipe(gulp.dest(target)); 67 | streams.push(stream); 68 | streams.push(del(source)); 69 | streams.push( 70 | gulp 71 | .src("./tmp/common/*.js") 72 | .pipe(gulp.dest(`${ target }/common`)) 73 | ); 74 | } 75 | }); 76 | return streams; 77 | }); 78 | 79 | gulp.task("install", () => { 80 | return ["install", "cargo", "rustup", "rustc"] 81 | .map((task) => run(`npm install azure-pipelines-task-lib --prefix ./tmp/tasks/${task}`).exec()); 82 | }); 83 | 84 | gulp.task("default", (cb) => runSequence("clean", "compile", "copy", "install", cb)); 85 | 86 | gulp.task("pre-package", () => del("./tmp/common")); 87 | -------------------------------------------------------------------------------- /vss-extension.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": 1, 3 | "id": "rust-vsts", 4 | "version": "1.2.{patch}", 5 | "name": "Rust", 6 | "description": "Rust extension for Azure DevOps", 7 | "publisher": "spontoreau", 8 | "public": true, 9 | "targets": [ 10 | { 11 | "id": "Microsoft.VisualStudio.Services.Cloud" 12 | } 13 | ], 14 | "categories": [ 15 | "Azure Pipelines" 16 | ], 17 | "icons": { 18 | "default": "icon.png" 19 | }, 20 | "screenshots": [ 21 | { 22 | "path": "images/screenshot-tasks.png" 23 | }, 24 | { 25 | "path": "images/screenshot-cargo.png" 26 | }, 27 | { 28 | "path": "images/screenshot-install.png" 29 | } 30 | ], 31 | "content": { 32 | "details": { 33 | "path": "DETAILS.md" 34 | }, 35 | "license": { 36 | "path": "LICENSE" 37 | } 38 | }, 39 | "links": { 40 | "support": { 41 | "uri": "https://github.com/spontoreau/rust-azure-devops/issues" 42 | } 43 | }, 44 | "repository": { 45 | "type": "git", 46 | "uri": "https://github.com/spontoreau/rust-azure-devops" 47 | }, 48 | "tags": [ 49 | "rust", 50 | "cargo", 51 | "rustup", 52 | "rustc", 53 | "build" 54 | ], 55 | "files": [ 56 | { 57 | "path": "tasks/cargo" 58 | }, 59 | { 60 | "path": "tasks/install" 61 | }, 62 | { 63 | "path": "tasks/rustup" 64 | }, 65 | { 66 | "path": "tasks/rustc" 67 | }, 68 | { 69 | "path": "images", 70 | "addressable": true 71 | } 72 | ], 73 | "contributions": [ 74 | { 75 | "id": "rust-install", 76 | "type": "ms.vss-distributed-task.task", 77 | "targets": [ 78 | "ms.vss-distributed-task.tasks" 79 | ], 80 | "properties": { 81 | "name": "tasks/install" 82 | } 83 | }, 84 | { 85 | "id": "rust-cargo", 86 | "type": "ms.vss-distributed-task.task", 87 | "targets": [ 88 | "ms.vss-distributed-task.tasks" 89 | ], 90 | "properties": { 91 | "name": "tasks/cargo" 92 | } 93 | }, 94 | { 95 | "id": "rust-rustup", 96 | "type": "ms.vss-distributed-task.task", 97 | "targets": [ 98 | "ms.vss-distributed-task.tasks" 99 | ], 100 | "properties": { 101 | "name": "tasks/rustup" 102 | } 103 | }, 104 | { 105 | "id": "rust-rustc", 106 | "type": "ms.vss-distributed-task.task", 107 | "targets": [ 108 | "ms.vss-distributed-task.tasks" 109 | ], 110 | "properties": { 111 | "name": "tasks/rustc" 112 | } 113 | } 114 | ] 115 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at pontoreau.sylvain@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Congratulations, you are going to contribute to the **rust-azure-devops** repository. 4 | First of all, I want to thank you for spending time to improve this project 🙏! 5 | 6 | ## Table Of Contents 7 | 8 | [Introduction](#introduction) 9 | 10 | [How to contribute](#how-to-contribute) 11 | 12 | * [Bugs](#bugs) 13 | * [Features](#features) 14 | * [Pull Requests](#pull-requests) 15 | 16 | [Debug](#debug) 17 | 18 | [Conventions](#conventions) 19 | 20 | * [Code](#code) 21 | * [Documentation](#documentation) 22 | 23 | ## 🏁 Introduction 24 | 25 | The following guidelines ensure your contributions respect the project philosophy, design, conventions and rules. 26 | 27 | > ℹ️ You can talk about this project on [Slack](https://join.slack.com/t/rust-azure-devops/shared_invite/enQtMzkxNzU4MTgyMDg2LTlkMjJmMzM2MmIyYmJmMjFmNDJkN2IzZmMxZDFhZTgyOGFjYWExNTkwM2YwYTQ3YmI3OWNlYjBhYjcyNGY5OTM) 28 | 29 | ## ❓ How to contribute 30 | 31 | ### 🐛 Bugs 32 | 33 | Bug reports are one of the contributions you can do on **rust-azure-devops** project. 34 | 35 | First, ensure your bug isn't listed in [issues](https://github.com/spontoreau/rust-azure-devops/issues). It is better to contribute to an existing issue instead of creating a new one. It's really important that you respect a specific format for your bug reports. This provides an optimal reading for contributors and ease the implementation of fixes: 36 | 37 | ```markdown 38 | ### Description 39 | [Description of the issue] 40 | 41 | ### Bug scenario 42 | 43 | #### Steps 44 | 1. [First] 45 | 2. [Second] 46 | 3. [and so on...] 47 | 48 | #### Expected 49 | [What you expect to happen] 50 | 51 | #### Actual 52 | [What actually happens] 53 | 54 | ### Additional Information 55 | **Can be reproduced ?**: [Pick one of the following: *Yes*|*No*] 56 | 57 | **Severity**: [Pick one of the following: *Low*|*Medium*|*High*|*Critical*] 58 | 59 | **Version**: [version number] 60 | 61 | **Other**: [Others information] 62 | ``` 63 | 64 | If a bug can be cover with an unit test, you are more than welcome to write it! It's one of the best way to quickly resolve the issue 👍 65 | 66 | ### 💡 Features 67 | 68 | Features can add some new capabilities to the project. 69 | 70 | First, ensure your feature isn't listed in [issues](https://github.com/spontoreau/rust-azure-devops/issues). 71 | 72 | A feature must be created as a proposal for discussion with the community. When an agreement is found, the proposal is added as a feature inside a [project](https://github.com/spontoreau/rust-azure-devops/projects). A feature can be considered too large to be a single card in a project. If so, the team can decide to create the feature as a project and split it into multiples small features (for an easier integration inside the project). 73 | 74 | ### 🎁 Pull Requests 75 | 76 | First, you need to take a look at [Conventions](#conventions) to ensure your code respect project rules. These rules are mandatories to ensure each pull request respects the philosophy of the project. 77 | 78 | #### Authorship 79 | 80 | All commits must be made with your personnal **Github** account and signing commits if possible (Take a look at Github documentation to set your user [name](https://help.github.com/articles/setting-your-username-in-git/), [email](https://help.github.com/articles/setting-your-email-in-git/) & [GPG](https://help.github.com/articles/signing-commits-using-gpg/)). 81 | 82 | #### Build project 83 | 84 | To setup dependencies, execute "_install_" command of **npm**: 85 | 86 | ``` 87 | $ npm install 88 | ``` 89 | 90 | The project can be compile with the "_compile_" **npm** script: 91 | 92 | ``` 93 | $ npm run compile 94 | ``` 95 | 96 | Code analysis need to succeed because of the continious integration. You can run it with: 97 | 98 | ``` 99 | $ npm run lint 100 | ``` 101 | 102 | > ⚠️ Always ensure compile and lint succeeded before commit some code 103 | 104 | To build the VSIX extension file, execute the "_build_" and "_package_" scripts: 105 | 106 | ``` 107 | $ npm run build 108 | $ npm run package 109 | ``` 110 | 111 | By default, the build script generate a _beta_ package and use the current date value to set the patch number. Those information can be change by passing "_--release_" and "_--patch_" arguments to the script: 112 | 113 | ``` 114 | $ npm run build -- --release --patch 1 115 | $ npm run package 116 | ``` 117 | 118 | #### Commit 119 | 120 | Ensure each commit has an understandable message for request reviewers. 121 | 122 | Git command example: 123 | 124 | ``` 125 | $ git add . 126 | $ git commit -m"{message}" 127 | ``` 128 | 129 | #### Rebase 130 | 131 | Each pull request must be synchronized with remote repository. We recommand to use an interactive rebase to synchronize local and remote repositories. 132 | 133 | Git command example: 134 | 135 | ``` 136 | $ git fetch 137 | $ git rebase -i origin/develop 138 | ``` 139 | 140 | External contributors have to synchronize local repository with the forked one (Take a look at the Github documentation [here](https://help.github.com/articles/syncing-a-fork/)). 141 | 142 | #### Push 143 | 144 | Git command example: 145 | 146 | ``` 147 | $ git push {origin} feature/{featureNameOrIssueId} 148 | ``` 149 | 150 | #### Github PR 151 | 152 | If a Pull requests resolve an issue, include it inside the description. When approved by reviewers, pull request are merged into the "_master_" branch. 153 | 154 | > ⚠️ To be reviewed, CI process must succeeded 155 | 156 | ## 🔬 Debug 157 | 158 | Debug can be done by running files inside the debug folder with Node.js. 159 | 160 | VS Code debug configuration allows you to launch the debugger from any of those files. 161 | 162 | ## Conventions 163 | 164 | ### ⌨️ Code 165 | 166 | Please respect TSLint rules. 167 | 168 | > ⚠️ Pull request with TSLint configuration changes whitout valid reasons will be rejected. 169 | 170 | Don't install new dependencies. Remember that the project is an extension and the package weight must be as small as possible. If for any reason a dependency is required for a specific feature, add all the information about it in the pull request. 171 | 172 | Use camelCase convention when naming a file. 173 | 174 | Azure DevOps task library isn't unit tests friendy... That's why there is no unit tests setup in the project... 175 | 176 | ### 📚 Documentation 177 | 178 | * Use [JSDoc](http://usejsdoc.org/) for source code if needed. 179 | * Use [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) for repository documentation. --------------------------------------------------------------------------------