Skip to content
This repository has been archived by the owner on Apr 22, 2022. It is now read-only.

Commit

Permalink
Azure PowerShell - Script Execution (Azure#1)
Browse files Browse the repository at this point in the history
* initial commit

* Create main.yml

* Update main.yml

* added action.yml

* added action.yml

* added action.yml

* Delete main.yml

* removed node_modules

* changes in .gitignore

* changes in PowerShellToolRunner

* Added changes for review comments

* added inputs in action.yml

* changes in package.json

* added review comments

* Update action.yml

* Update action.yml

* fix in ScriptRunner.ts

* changes in URL

* added review comments

* changes for review comments

* added args in PowerShellToolRunner

* changes in PowerShellToolRunner

* fixed action.yml

* removed debug logs

* changes in main
  • Loading branch information
aksm-ms authored Apr 8, 2020
1 parent 15fb06e commit d1a6510
Show file tree
Hide file tree
Showing 20 changed files with 993 additions and 0 deletions.
24 changes: 24 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Azure PowerShell Action
name: 'Azure PowerShell Action'
description: 'Automate your GitHub workflows using Azure PowerShell scripts.'
inputs:
inlineScript:
description: 'Specify the Az PowerShell script here.'
required: true
azPSVersion:
description: 'Azure PS version to be used to execute the script, example: 1.8.0, 2.8.0, 3.4.0. To use the latest version, specify "latest".'
required: true
errorActionPreference:
description: 'Select the value of the ErrorActionPreference variable for executing the script. Options: stop, continue, silentlyContinue. Default is Stop.'
required: false
default: 'Stop'
failOnStandardError:
description: 'If this is true, this task will fail if any errors are written to the error pipeline, or if any data is written to the Standard Error stream.'
required: false
default: 'false'
branding:
icon: 'login.svg'
color: 'blue'
runs:
using: 'node12'
main: 'lib/main.js'
12 changes: 12 additions & 0 deletions lib/Constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class Constants {
}
exports.default = Constants;
Constants.prefix = "az_";
Constants.moduleName = "Az";
Constants.versionPattern = /[0-9]\.[0-9]\.[0-9]/;
Constants.Success = "Success";
Constants.Error = "Error";
Constants.AzVersion = "AzVersion";
Constants.versionExists = "versionExists";
40 changes: 40 additions & 0 deletions lib/InitializeAzure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(require("@actions/core"));
const Utils_1 = __importDefault(require("./Utilities/Utils"));
const Constants_1 = __importDefault(require("./Constants"));
class InitializeAzure {
static importAzModule(azPSVersion) {
return __awaiter(this, void 0, void 0, function* () {
Utils_1.default.setPSModulePath();
if (azPSVersion === "latest") {
azPSVersion = yield Utils_1.default.getLatestModule(Constants_1.default.moduleName);
}
else {
yield Utils_1.default.checkModuleVersion(Constants_1.default.moduleName, azPSVersion);
}
core.debug(`Az Module version used: ${azPSVersion}`);
Utils_1.default.setPSModulePath(`${Constants_1.default.prefix}${azPSVersion}`);
});
}
}
exports.default = InitializeAzure;
70 changes: 70 additions & 0 deletions lib/ScriptRunner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(require("@actions/core"));
const FileUtils_1 = __importDefault(require("./Utilities/FileUtils"));
const PowerShellToolRunner_1 = __importDefault(require("./Utilities/PowerShellToolRunner"));
const ScriptBuilder_1 = __importDefault(require("./Utilities/ScriptBuilder"));
class ScriptRunner {
constructor(inlineScript, errorActionPreference, failOnStandardErr) {
this.inlineScript = inlineScript;
this.errorActionPreference = errorActionPreference;
this.failOnStandardErr = failOnStandardErr;
}
executeFile() {
return __awaiter(this, void 0, void 0, function* () {
const error = [];
const options = {
listeners: {
stderr: (data) => {
if (error.length < 10) {
// Truncate to at most 1000 bytes
if (data.length > 1000) {
error.push(`${data.toString('utf8', 0, 1000)}<truncated>`);
}
else {
error.push(data.toString('utf8'));
}
}
else if (error.length === 10) {
error.push('Additional writes to stderr truncated');
}
}
}
};
const scriptToExecute = new ScriptBuilder_1.default().getInlineScriptFile(this.inlineScript, this.errorActionPreference);
ScriptRunner.filePath = yield FileUtils_1.default.createScriptFile(scriptToExecute);
core.debug(`script file to run: ${ScriptRunner.filePath}`);
yield PowerShellToolRunner_1.default.init();
const exitCode = yield PowerShellToolRunner_1.default.executePowerShellScriptBlock(ScriptRunner.filePath, options);
if (exitCode !== 0) {
core.setOutput(`Azure PowerShell exited with code:`, exitCode.toString());
if (this.failOnStandardErr) {
error.forEach((err) => {
core.error(err);
});
throw new Error(`Standard error stream contains one or more lines`);
}
}
});
}
}
exports.default = ScriptRunner;
50 changes: 50 additions & 0 deletions lib/Utilities/FileUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("fs"));
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const core = __importStar(require("@actions/core"));
const uuid_1 = require("uuid");
class FileUtils {
static createScriptFile(inlineScript) {
return __awaiter(this, void 0, void 0, function* () {
const fileName = FileUtils.getFileName();
const filePath = path.join(FileUtils.tempDirectory, fileName);
fs.writeFileSync(filePath, inlineScript, 'utf-8');
return filePath;
});
}
static getFileName() {
return `${uuid_1.v4()}.ps1`;
}
static deleteFile(filePath) {
return __awaiter(this, void 0, void 0, function* () {
if (fs.existsSync(filePath)) {
try {
fs.unlinkSync(filePath);
}
catch (err) {
core.warning(err.toString());
}
}
});
}
}
exports.default = FileUtils;
FileUtils.tempDirectory = process.env.RUNNER_TEMP || os.tmpdir();
41 changes: 41 additions & 0 deletions lib/Utilities/PowerShellToolRunner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const io = __importStar(require("@actions/io"));
const exec = __importStar(require("@actions/exec"));
class PowerShellToolRunner {
static init() {
return __awaiter(this, void 0, void 0, function* () {
if (!PowerShellToolRunner.psPath) {
PowerShellToolRunner.psPath = yield io.which("pwsh", true);
}
});
}
static executePowerShellCommand(command, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
yield exec.exec(`${PowerShellToolRunner.psPath} -NoLogo -NoProfile -NonInteractive -Command ${command}`, [], options);
});
}
static executePowerShellScriptBlock(scriptBlock, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const exitCode = yield exec.exec(`${PowerShellToolRunner.psPath} -NoLogo -NoProfile -NonInteractive -Command`, [scriptBlock], options);
return exitCode;
});
}
}
exports.default = PowerShellToolRunner;
60 changes: 60 additions & 0 deletions lib/Utilities/ScriptBuilder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const os = __importStar(require("os"));
const core = __importStar(require("@actions/core"));
const Constants_1 = __importDefault(require("../Constants"));
class ScriptBuilder {
constructor() {
this.script = "";
}
getLatestModuleScript(moduleName) {
const command = `Get-Module -Name ${moduleName} -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1`;
this.script += `try {
$ErrorActionPreference = "Stop"
$WarningPreference = "SilentlyContinue"
$output = @{}
$data = ${command}
$output['${Constants_1.default.AzVersion}'] = $data.Version.ToString()
$output['${Constants_1.default.Success}'] = "true"
}
catch {
$output['${Constants_1.default.Error}'] = $_.exception.Message
}
return ConvertTo-Json $output`;
core.debug(`GetLatestModuleScript: ${this.script}`);
return this.script;
}
checkModuleVersionScript(moduleName, version) {
const command = `Get-Module -Name ${moduleName} -ListAvailable | Where-Object Version -match ${version}`;
this.script += `try {
$ErrorActionPreference = "Stop"
$WarningPreference = "SilentlyContinue"
$output = @{}
$data = ${command}
$output['${Constants_1.default.versionExists}'] = [string]::IsNullOrEmpty($data)
$output['${Constants_1.default.Success}'] = "true"
}
catch {
$output['${Constants_1.default.Error}'] = $_.exception.Message
}
return ConvertTo-Json $output`;
core.debug(`CheckModuleVersionScript: ${this.script}`);
return this.script;
}
getInlineScriptFile(inlineScript, errorActionPreference) {
this.script = `$ErrorActionPreference = '${errorActionPreference}'${os.EOL}${inlineScript}`;
core.debug(`InlineScript file to be executed: ${this.script}`);
return this.script;
}
}
exports.default = ScriptBuilder;
Loading

0 comments on commit d1a6510

Please sign in to comment.