Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WI 2129366][ShellScriptV2] Add explicit error message for OOM error #19557

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
"loc.input.label.failOnStandardError": "Fail on Standard Error",
"loc.input.help.failOnStandardError": "If this is true, this task will fail if any errors are written to the StandardError stream.",
"loc.messages.BashReturnCode": "Bash exited with return code: %d",
"loc.messages.BashFailed": "Bash failed with error: %s"
"loc.messages.BashFailed": "Bash failed with error: %s",
"loc.messages.BashFailedWithCode137": "Bash exited with code 137, which means it ran out of memory. Make sure the agent (container) host has sufficient memory configured."
}
4 changes: 1 addition & 3 deletions Tasks/ShellScriptV2/Tests/L0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ describe('ShellScript L0 Suite', function () {
assert(tr.ran('/usr/local/bin/bash /script.sh arg1 arg2'), 'it should have run ShellScript');
assert(tr.invokedToolCount == 1, 'should have only run ShellScript');

var expectedErr = '/usr/local/bin/bash failed with return code: 1';

assert(tr.stdOutContained(expectedErr), 'should have said: ' + expectedErr);
assert(tr.stdOutContained('loc_mock_BashFailed 1'), 'should have said: loc_mock_BashFailed 1');
// failOnStdErr not set
assert(!tr.stderr, 'should not have written to stderr');
assert(tr.failed, 'task should have failed');
Expand Down
42 changes: 30 additions & 12 deletions Tasks/ShellScriptV2/shellscript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import path = require('path');
import tl = require('azure-pipelines-task-lib/task');
import trm = require('azure-pipelines-task-lib/toolrunner');

async function run() {
try {
async function run() {
try {
tl.setResourcePath(path.join( __dirname, 'task.json'));

var bash: trm.ToolRunner = tl.tool(tl.which('bash', true));
const bash: trm.ToolRunner = tl.tool(tl.which('bash', true));

var scriptPath: string = tl.getPathInput('scriptPath', true, true);
var cwd: string = tl.getPathInput('cwd', true, false);
const scriptPath: string = tl.getPathInput('scriptPath', true, true);
let cwd: string = tl.getPathInput('cwd', true, false);

// if user didn't supply a cwd (advanced), then set cwd to folder script is in.
// All "script" tasks should do this
Expand All @@ -26,15 +26,33 @@ async function run() {

// determines whether output to stderr will fail a task.
// some tools write progress and other warnings to stderr. scripts can also redirect.
var failOnStdErr: boolean = tl.getBoolInput('failOnStandardError', false);
let failOnStdErr: boolean = tl.getBoolInput('failOnStandardError', false);

const options = <trm.IExecOptions>{
failOnStdErr: failOnStdErr,
ignoreReturnCode: true
};

let exitCode: number = await bash.exec(options);

let result = tl.TaskResult.Succeeded;

if (exitCode !== 0)
{
if (exitCode == 137) {
tl.error(tl.loc('BashFailedWithCode137'));
}
else {
tl.error(tl.loc('BashFailed', exitCode));
}
result = tl.TaskResult.Failed;
}

var code: number = await bash.exec(<any>{failOnStdErr: failOnStdErr});
tl.setResult(tl.TaskResult.Succeeded, tl.loc('BashReturnCode', code));
tl.setResult(result, tl.loc('BashReturnCode', exitCode));
}
catch (err: any) {
tl.setResult(tl.TaskResult.Failed, err.message, true);
}
catch(err) {
tl.error(err.message);
tl.setResult(tl.TaskResult.Failed, tl.loc('BashFailed', err.message));
}
}

run();
179 changes: 90 additions & 89 deletions Tasks/ShellScriptV2/task.json
Original file line number Diff line number Diff line change
@@ -1,94 +1,95 @@
{
"id": "6C731C3C-3C68-459A-A5C9-BDE6E6595B5B",
"name": "ShellScript",
"friendlyName": "Shell script",
"description": "Run a shell script using Bash",
"helpUrl": "https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/shell-script",
"helpMarkDown": "[Learn more about this task](https://go.microsoft.com/fwlink/?LinkID=613738)",
"category": "Utility",
"visibility": [
"Build",
"Release"
],
"runsOn": [
"Agent",
"DeploymentGroup"
],
"author": "Microsoft Corporation",
"version": {
"Major": 2,
"Minor": 231,
"Patch": 0
"id": "6C731C3C-3C68-459A-A5C9-BDE6E6595B5B",
"name": "ShellScript",
"friendlyName": "Shell script",
"description": "Run a shell script using Bash",
"helpUrl": "https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/shell-script",
"helpMarkDown": "[Learn more about this task](https://go.microsoft.com/fwlink/?LinkID=613738)",
"category": "Utility",
"visibility": [
"Build",
"Release"
],
"runsOn": [
"Agent",
"DeploymentGroup"
],
"author": "Microsoft Corporation",
"version": {
"Major": 2,
"Minor": 236,
"Patch": 0
},
"demands": [
"sh"
],
"instanceNameFormat": "Shell Script $(scriptPath)",
"groups": [
{
"name": "advanced",
"displayName": "Advanced",
"isExpanded": false
}
],
"inputs": [
{
"name": "scriptPath",
"type": "filePath",
"label": "Script Path",
"defaultValue": "",
"required": true,
"helpMarkDown": "Relative path from repo root of the shell script file to run."
},
{
"name": "args",
"type": "string",
"label": "Arguments",
"defaultValue": "",
"required": false,
"helpMarkDown": "Arguments passed to the shell script"
},
{
"name": "disableAutoCwd",
"type": "boolean",
"label": "Specify Working Directory",
"defaultValue": "false",
"required": false,
"helpMarkDown": "The default behavior is to set the working directory to the script location. This enables you to optionally specify a different working directory.",
"groupName": "advanced"
},
"demands": [
"sh"
],
"instanceNameFormat": "Shell Script $(scriptPath)",
"groups": [
{
"name": "advanced",
"displayName": "Advanced",
"isExpanded": false
}
],
"inputs": [
{
"name": "scriptPath",
"type": "filePath",
"label": "Script Path",
"defaultValue": "",
"required": true,
"helpMarkDown": "Relative path from repo root of the shell script file to run."
},
{
"name": "args",
"type": "string",
"label": "Arguments",
"defaultValue": "",
"required": false,
"helpMarkDown": "Arguments passed to the shell script"
},
{
"name": "disableAutoCwd",
"type": "boolean",
"label": "Specify Working Directory",
"defaultValue": "false",
"required": false,
"helpMarkDown": "The default behavior is to set the working directory to the script location. This enables you to optionally specify a different working directory.",
"groupName": "advanced"
},
{
"name": "cwd",
"type": "filePath",
"label": "Working Directory",
"defaultValue": "",
"required": false,
"visibleRule": "disableAutoCwd = true",
"helpMarkDown": "Current working directory where the script is run. Empty is the root of the repo (build) or artifacts (release), which is $(System.DefaultWorkingDirectory).",
"groupName": "advanced"
},
{
"name": "failOnStandardError",
"type": "boolean",
"label": "Fail on Standard Error",
"defaultValue": "false",
"required": false,
"helpMarkDown": "If this is true, this task will fail if any errors are written to the StandardError stream.",
"groupName": "advanced"
}
],
"execution": {
"Node10": {
"target": "shellscript.js",
"argumentFormat": ""
},
"Node16": {
"target": "shellscript.js",
"argumentFormat": ""
}
{
"name": "cwd",
"type": "filePath",
"label": "Working Directory",
"defaultValue": "",
"required": false,
"visibleRule": "disableAutoCwd = true",
"helpMarkDown": "Current working directory where the script is run. Empty is the root of the repo (build) or artifacts (release), which is $(System.DefaultWorkingDirectory).",
"groupName": "advanced"
},
{
"name": "failOnStandardError",
"type": "boolean",
"label": "Fail on Standard Error",
"defaultValue": "false",
"required": false,
"helpMarkDown": "If this is true, this task will fail if any errors are written to the StandardError stream.",
"groupName": "advanced"
}
],
"execution": {
"Node10": {
"target": "shellscript.js",
"argumentFormat": ""
},
"messages": {
"BashReturnCode": "Bash exited with return code: %d",
"BashFailed": "Bash failed with error: %s"
"Node16": {
"target": "shellscript.js",
"argumentFormat": ""
}
},
"messages": {
"BashReturnCode": "Bash exited with return code: %d",
"BashFailed": "Bash failed with error: %s",
"BashFailedWithCode137": "Bash exited with code 137, which means it ran out of memory. Make sure the agent (container) host has sufficient memory configured."
}
}
5 changes: 3 additions & 2 deletions Tasks/ShellScriptV2/task.loc.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"author": "Microsoft Corporation",
"version": {
"Major": 2,
"Minor": 231,
"Minor": 236,
"Patch": 0
},
"demands": [
Expand Down Expand Up @@ -89,6 +89,7 @@
},
"messages": {
"BashReturnCode": "ms-resource:loc.messages.BashReturnCode",
"BashFailed": "ms-resource:loc.messages.BashFailed"
"BashFailed": "ms-resource:loc.messages.BashFailed",
"BashFailedWithCode137": "ms-resource:loc.messages.BashFailedWithCode137"
}
}
4 changes: 2 additions & 2 deletions _generated/ShellScriptV2.versionmap.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Default|2.231.0
Node20-225|2.231.1
Default|2.236.0
Node20-225|2.236.1
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
"loc.input.label.failOnStandardError": "Fail on Standard Error",
"loc.input.help.failOnStandardError": "If this is true, this task will fail if any errors are written to the StandardError stream.",
"loc.messages.BashReturnCode": "Bash exited with return code: %d",
"loc.messages.BashFailed": "Bash failed with error: %s"
"loc.messages.BashFailed": "Bash failed with error: %s",
"loc.messages.BashFailedWithCode137": "Bash exited with code 137, which means it ran out of memory. Make sure the agent (container) host has sufficient memory configured."
}
4 changes: 1 addition & 3 deletions _generated/ShellScriptV2/Tests/L0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ describe('ShellScript L0 Suite', function () {
assert(tr.ran('/usr/local/bin/bash /script.sh arg1 arg2'), 'it should have run ShellScript');
assert(tr.invokedToolCount == 1, 'should have only run ShellScript');

var expectedErr = '/usr/local/bin/bash failed with return code: 1';

assert(tr.stdOutContained(expectedErr), 'should have said: ' + expectedErr);
assert(tr.stdOutContained('loc_mock_BashFailed 1'), 'should have said: loc_mock_BashFailed 1');
// failOnStdErr not set
assert(!tr.stderr, 'should not have written to stderr');
assert(tr.failed, 'task should have failed');
Expand Down
42 changes: 30 additions & 12 deletions _generated/ShellScriptV2/shellscript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import path = require('path');
import tl = require('azure-pipelines-task-lib/task');
import trm = require('azure-pipelines-task-lib/toolrunner');

async function run() {
try {
async function run() {
try {
tl.setResourcePath(path.join( __dirname, 'task.json'));

var bash: trm.ToolRunner = tl.tool(tl.which('bash', true));
const bash: trm.ToolRunner = tl.tool(tl.which('bash', true));

var scriptPath: string = tl.getPathInput('scriptPath', true, true);
var cwd: string = tl.getPathInput('cwd', true, false);
const scriptPath: string = tl.getPathInput('scriptPath', true, true);
let cwd: string = tl.getPathInput('cwd', true, false);

// if user didn't supply a cwd (advanced), then set cwd to folder script is in.
// All "script" tasks should do this
Expand All @@ -26,15 +26,33 @@ async function run() {

// determines whether output to stderr will fail a task.
// some tools write progress and other warnings to stderr. scripts can also redirect.
var failOnStdErr: boolean = tl.getBoolInput('failOnStandardError', false);
let failOnStdErr: boolean = tl.getBoolInput('failOnStandardError', false);

const options = <trm.IExecOptions>{
failOnStdErr: failOnStdErr,
ignoreReturnCode: true
};

let exitCode: number = await bash.exec(options);

let result = tl.TaskResult.Succeeded;

if (exitCode !== 0)
{
if (exitCode == 137) {
tl.error(tl.loc('BashFailedWithCode137'));
}
else {
tl.error(tl.loc('BashFailed', exitCode));
}
result = tl.TaskResult.Failed;
}

var code: number = await bash.exec(<any>{failOnStdErr: failOnStdErr});
tl.setResult(tl.TaskResult.Succeeded, tl.loc('BashReturnCode', code));
tl.setResult(result, tl.loc('BashReturnCode', exitCode));
}
catch (err: any) {
tl.setResult(tl.TaskResult.Failed, err.message, true);
}
catch(err) {
tl.error(err.message);
tl.setResult(tl.TaskResult.Failed, tl.loc('BashFailed', err.message));
}
}

run();
9 changes: 5 additions & 4 deletions _generated/ShellScriptV2/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"author": "Microsoft Corporation",
"version": {
"Major": 2,
"Minor": 231,
"Minor": 236,
"Patch": 0
},
"demands": [
Expand Down Expand Up @@ -89,10 +89,11 @@
},
"messages": {
"BashReturnCode": "Bash exited with return code: %d",
"BashFailed": "Bash failed with error: %s"
"BashFailed": "Bash failed with error: %s",
"BashFailedWithCode137": "Bash exited with code 137, which means it ran out of memory. Make sure the agent (container) host has sufficient memory configured."
},
"_buildConfigMapping": {
"Default": "2.231.0",
"Node20-225": "2.231.1"
"Default": "2.236.0",
"Node20-225": "2.236.1"
}
}
Loading