-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
847 additions
and
17 deletions.
There are no files selected for viewing
22 changes: 22 additions & 0 deletions
22
Tasks/PythonScriptV0/Strings/resources.resjson/en-US/resources.resjson
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"loc.friendlyName": "Python Script", | ||
"loc.helpMarkDown": "", | ||
"loc.description": "Run a Python script.", | ||
"loc.instanceNameFormat": "Run Python script", | ||
"loc.group.displayName.advanced": "Advanced", | ||
"loc.input.label.scriptSource": "Script source", | ||
"loc.input.help.scriptSource": "Whether the script is a file in the source tree or is written inline in this task.", | ||
"loc.input.label.scriptPath": "Script path", | ||
"loc.input.help.scriptPath": "Path of the script to execute. Must be a fully qualified path or relative to $(System.DefaultWorkingDirectory).", | ||
"loc.input.label.script": "Script", | ||
"loc.input.help.script": "The Python script to run", | ||
"loc.input.label.arguments": "Arguments", | ||
"loc.input.help.arguments": "Arguments passed to the script execution, available through `sys.argv`.", | ||
"loc.input.label.pythonInterpreter": "Python interpreter", | ||
"loc.input.help.pythonInterpreter": "Absolute path to the Python interpreter to use. If not specified, the task will use the interpreter in PATH.<br /> Run the [Use Python Version](https://go.microsoft.com/fwlink/?linkid=871498) task to add a version of Python to PATH.", | ||
"loc.input.label.workingDirectory": "Working directory", | ||
"loc.input.label.failOnStderr": "Fail on standard error", | ||
"loc.input.help.failOnStderr": "If this is true, this task will fail if any text is written to the stderr stream.", | ||
"loc.messages.NotAFile": "The given path was not to a file: '%s'.", | ||
"loc.messages.ParameterRequired": "The `%s` parameter is required" | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import * as path from 'path'; | ||
import * as task from 'vsts-task-lib/task'; | ||
import { pythonScript } from './pythonscript'; | ||
|
||
(async () => { | ||
try { | ||
task.setResourcePath(path.join(__dirname, 'task.json')); | ||
await pythonScript({ | ||
scriptSource: task.getInput('scriptSource'), | ||
scriptPath: task.getPathInput('scriptPath'), | ||
script: task.getInput('script'), | ||
arguments: task.getInput('arguments'), | ||
pythonInterpreter: task.getInput('pythonInterpreter'), // string instead of path: a path will default to the agent's sources directory | ||
workingDirectory: task.getPathInput('workingDirectory'), | ||
failOnStderr: task.getBoolInput('failOnStderr') | ||
}); | ||
task.setResult(task.TaskResult.Succeeded, ""); | ||
} catch (error) { | ||
task.error(error.message); | ||
task.setResult(task.TaskResult.Failed, error.message); | ||
} | ||
})(); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"name": "python-script", | ||
"version": "1.0.0", | ||
"description": "Create and activate a Conda environment.", | ||
"main": "pythonscript.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/microsoft/vsts-tasks.git" | ||
}, | ||
"author": "Microsoft Corporation", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/microsoft/vsts-tasks/issues" | ||
}, | ||
"homepage": "https://github.com/microsoft/vsts-tasks#readme", | ||
"dependencies": { | ||
"@types/node": "^6.0.101", | ||
"@types/q": "^1.5.0", | ||
"@types/uuid": "^3.4.3", | ||
"vsts-task-lib": "^2.4.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import * as fs from 'fs'; | ||
import * as path from 'path'; | ||
|
||
import * as task from 'vsts-task-lib/task'; | ||
import * as toolRunner from 'vsts-task-lib/toolrunner'; | ||
|
||
import * as uuidV4 from 'uuid/v4'; | ||
|
||
interface TaskParameters { | ||
scriptSource: string, | ||
scriptPath?: string, | ||
script?: string, | ||
arguments?: string, | ||
pythonInterpreter?: string, | ||
workingDirectory?: string, | ||
failOnStderr?: boolean | ||
} | ||
|
||
/** | ||
* Check for a parameter at runtime. | ||
* Useful for conditionally-visible, required parameters. | ||
*/ | ||
function assertParameter<T>(value: T | undefined, propertyName: string): T { | ||
if (!value) { | ||
throw new Error(task.loc('ParameterRequired', propertyName)); | ||
} | ||
|
||
return value!; | ||
} | ||
|
||
// TODO Enable with TypeScript 2.8 (ensures correct property name in the error message) | ||
// function assertParameter<T extends keyof TaskParameters>(parameters: TaskParameters, propertyName: T): NonNullable<TaskParameters[T]> { | ||
// const param = parameters[propertyName]; | ||
// if (!param) { | ||
// throw new Error(task.loc('ParameterRequired', propertyName)); | ||
// } | ||
|
||
// return param!; | ||
// } | ||
|
||
export async function pythonScript(parameters: Readonly<TaskParameters>): Promise<void> { | ||
// Get the script to run | ||
const scriptPath = await (async () => { | ||
if (parameters.scriptSource.toLowerCase() === 'filepath') { // Run script file | ||
const scriptPath = assertParameter(parameters.scriptPath, 'scriptPath'); | ||
|
||
if (!fs.statSync(scriptPath).isFile()) { | ||
throw new Error(task.loc('NotAFile', scriptPath)); | ||
} | ||
return scriptPath; | ||
} else { // Run inline script | ||
const script = assertParameter(parameters.script, 'script'); | ||
|
||
// Write the script to disk | ||
task.assertAgent('2.115.0'); | ||
const tempDirectory = task.getVariable('agent.tempDirectory'); | ||
task.checkPath(tempDirectory, `${tempDirectory} (agent.tempDirectory)`); | ||
const scriptPath = path.join(tempDirectory, `${uuidV4()}.py`); | ||
await fs.writeFileSync( | ||
scriptPath, | ||
script, | ||
{ encoding: 'utf8' }); | ||
|
||
return scriptPath; | ||
} | ||
})(); | ||
|
||
// Create the tool runner | ||
const pythonPath = parameters.pythonInterpreter || task.which('python'); | ||
const python = task.tool(pythonPath).arg(scriptPath); | ||
|
||
// Calling `line` with a falsy argument returns `undefined`, so can't chain this call | ||
if (parameters.arguments) { | ||
python.line(parameters.arguments); | ||
} | ||
|
||
// Run the script | ||
// Use `any` to work around what I suspect are bugs with `IExecOptions`'s type annotations: | ||
// - optional fields need to be typed as optional | ||
// - `errStream` and `outStream` should be `NodeJs.WritableStream`, not `NodeJS.Writable` | ||
await python.exec(<any>{ | ||
cwd: parameters.workingDirectory, | ||
failOnStdErr: parameters.failOnStderr, | ||
// Direct all output to stdout, otherwise the output may appear out-of-order since Node buffers its own stdout but not stderr | ||
errStream: process.stdout, | ||
outStream: process.stdout, | ||
ignoreReturnCode: false | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
{ | ||
"id": "6392F95F-7E76-4A18-B3C7-7F078D2F7700", | ||
"name": "PythonScript", | ||
"friendlyName": "Python Script", | ||
"description": "Run a Python script.", | ||
"helpMarkDown": "", | ||
"category": "Utility", | ||
"visibility": [ | ||
"Build", | ||
"Release" | ||
], | ||
"runsOn": [ | ||
"Agent", | ||
"DeploymentGroup" | ||
], | ||
"author": "Microsoft Corporation", | ||
"version": { | ||
"Major": 0, | ||
"Minor": 135, | ||
"Patch": 0 | ||
}, | ||
"preview": true, | ||
"demands": [], | ||
"instanceNameFormat": "Run Python script", | ||
"groups": [ | ||
{ | ||
"name": "advanced", | ||
"displayName": "Advanced", | ||
"isExpanded": false | ||
} | ||
], | ||
"inputs": [ | ||
{ | ||
"name": "scriptSource", | ||
"type": "radio", | ||
"label": "Script source", | ||
"required": true, | ||
"defaultValue": "filePath", | ||
"helpMarkDown": "Whether the script is a file in the source tree or is written inline in this task.", | ||
"options": { | ||
"filePath": "File path", | ||
"inline": "Inline" | ||
} | ||
}, | ||
{ | ||
"name": "scriptPath", | ||
"type": "filePath", | ||
"label": "Script path", | ||
"visibleRule": "scriptSource = filePath", | ||
"required": true, | ||
"defaultValue": "", | ||
"helpMarkDown": "Path of the script to execute. Must be a fully qualified path or relative to $(System.DefaultWorkingDirectory)." | ||
}, | ||
{ | ||
"name": "script", | ||
"type": "multiLine", | ||
"label": "Script", | ||
"visibleRule": "scriptSource = inline", | ||
"required": true, | ||
"defaultValue": "", | ||
"properties": { | ||
"resizable": "true", | ||
"rows": "10", | ||
"maxLength": "5000" | ||
}, | ||
"helpMarkDown": "The Python script to run" | ||
}, | ||
{ | ||
"name": "arguments", | ||
"type": "string", | ||
"label": "Arguments", | ||
"required": false, | ||
"defaultValue": "", | ||
"helpMarkDown": "Arguments passed to the script execution, available through `sys.argv`." | ||
}, | ||
{ | ||
"name": "pythonInterpreter", | ||
"type": "string", | ||
"label": "Python interpreter", | ||
"defaultValue": "", | ||
"required": false, | ||
"helpMarkDown": "Absolute path to the Python interpreter to use. If not specified, the task will use the interpreter in PATH.<br /> Run the [Use Python Version](https://go.microsoft.com/fwlink/?linkid=871498) task to add a version of Python to PATH.", | ||
"groupName": "advanced" | ||
}, | ||
{ | ||
"name": "workingDirectory", | ||
"type": "filePath", | ||
"label": "Working directory", | ||
"defaultValue": "", | ||
"required": false, | ||
"groupName": "advanced" | ||
}, | ||
{ | ||
"name": "failOnStderr", | ||
"type": "boolean", | ||
"label": "Fail on standard error", | ||
"defaultValue": "false", | ||
"required": false, | ||
"helpMarkDown": "If this is true, this task will fail if any text is written to the stderr stream.", | ||
"groupName": "advanced" | ||
} | ||
], | ||
"execution": { | ||
"Node": { | ||
"target": "main.js", | ||
"argumentFormat": "" | ||
} | ||
}, | ||
"messages": { | ||
"NotAFile": "The given path was not to a file: '%s'.", | ||
"ParameterRequired": "The `%s` parameter is required" | ||
} | ||
} |
Oops, something went wrong.