mirror of
https://github.com/hashicorp/setup-terraform.git
synced 2025-12-26 13:03:37 +00:00
add support for fail_on_detected_diff
more logging -- is it working? more logging -- is it working? rerelease fix logging 2 more logging more logging add fail_on_detected_diff add fail_on_detected_diff 2 add fail_on_detected_diff 3 add fail_on_detected_diff 4 fix plan_fail id; two test more debug more debug - try getBooleanInput more debug - try getBooleanInput : add debug to raw js code more debug - try getBooleanInput : add debug stdout to raw js code try using "fail" as trigger instead of boolean
This commit is contained in:
parent
a75f1a3cce
commit
89704370b3
5 changed files with 170 additions and 30 deletions
47
.github/workflows/fail_on_detected_diff.yml
vendored
Normal file
47
.github/workflows/fail_on_detected_diff.yml
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
name: "build-test"
|
||||||
|
|
||||||
|
on: # rebuild any PRs and main branch changes
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- develop
|
||||||
|
- fail_on_detected_diff
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
exitcode:
|
||||||
|
name: 'Terraform Run Local Exitcode'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./.github/workflows/data/local
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup Terraform
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
fail_on_detected_diff: true
|
||||||
|
|
||||||
|
- name: Terraform Init
|
||||||
|
shell: bash
|
||||||
|
run: terraform init
|
||||||
|
|
||||||
|
# - name: Terraform Format
|
||||||
|
# shell: bash
|
||||||
|
# run: terraform fmt -check
|
||||||
|
#
|
||||||
|
- name: Terraform Plan
|
||||||
|
id: plan
|
||||||
|
shell: bash
|
||||||
|
run: terraform plan
|
||||||
|
|
||||||
|
- name: Terraform Plan (fail)
|
||||||
|
id: plan_fail
|
||||||
|
shell: bash
|
||||||
|
run: terraform plan -detailed-exitcode
|
||||||
|
#
|
||||||
|
# - name: Print Terraform Plan
|
||||||
|
# shell: bash
|
||||||
|
# run: echo "${{ steps.plan.outputs.stdout }}"
|
||||||
|
|
@ -17,6 +17,10 @@ inputs:
|
||||||
description: 'Whether or not to install a wrapper to wrap subsequent calls of the `terraform` binary and expose its STDOUT, STDERR, and exit code as outputs named `stdout`, `stderr`, and `exitcode` respectively. Defaults to `true`.'
|
description: 'Whether or not to install a wrapper to wrap subsequent calls of the `terraform` binary and expose its STDOUT, STDERR, and exit code as outputs named `stdout`, `stderr`, and `exitcode` respectively. Defaults to `true`.'
|
||||||
default: 'true'
|
default: 'true'
|
||||||
required: false
|
required: false
|
||||||
|
fail_on_detected_diff:
|
||||||
|
description: 'Using -detailed-exitcode option returns exit code 0 or 2 for a detected change. Normally these are accepted as success. If doing specific handling (failing on drift, for example), this option will fail when exit code 2 is returned. Defaults to `pass`. Accepts `fail` in any case.'
|
||||||
|
default: 'pass'
|
||||||
|
required: false
|
||||||
runs:
|
runs:
|
||||||
using: 'node20'
|
using: 'node20'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
|
|
|
||||||
74
dist/index.js
vendored
74
dist/index.js
vendored
|
|
@ -3424,17 +3424,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||||
};
|
};
|
||||||
var _a;
|
var _a;
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.getCmdPath = exports.tryGetExecutablePath = exports.isRooted = exports.isDirectory = exports.exists = exports.READONLY = exports.UV_FS_O_EXLOCK = exports.IS_WINDOWS = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rm = exports.rename = exports.readlink = exports.readdir = exports.open = exports.mkdir = exports.lstat = exports.copyFile = exports.chmod = void 0;
|
exports.getCmdPath = exports.tryGetExecutablePath = exports.isRooted = exports.isDirectory = exports.exists = exports.IS_WINDOWS = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rename = exports.readlink = exports.readdir = exports.mkdir = exports.lstat = exports.copyFile = exports.chmod = void 0;
|
||||||
const fs = __importStar(__nccwpck_require__(7147));
|
const fs = __importStar(__nccwpck_require__(7147));
|
||||||
const path = __importStar(__nccwpck_require__(1017));
|
const path = __importStar(__nccwpck_require__(1017));
|
||||||
_a = fs.promises
|
_a = fs.promises, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink;
|
||||||
// export const {open} = 'fs'
|
|
||||||
, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.open = _a.open, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rm = _a.rm, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink;
|
|
||||||
// export const {open} = 'fs'
|
|
||||||
exports.IS_WINDOWS = process.platform === 'win32';
|
exports.IS_WINDOWS = process.platform === 'win32';
|
||||||
// See https://github.com/nodejs/node/blob/d0153aee367422d0858105abec186da4dff0a0c5/deps/uv/include/uv/win.h#L691
|
|
||||||
exports.UV_FS_O_EXLOCK = 0x10000000;
|
|
||||||
exports.READONLY = fs.constants.O_RDONLY;
|
|
||||||
function exists(fsPath) {
|
function exists(fsPath) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
|
|
@ -3615,8 +3609,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.findInPath = exports.which = exports.mkdirP = exports.rmRF = exports.mv = exports.cp = void 0;
|
exports.findInPath = exports.which = exports.mkdirP = exports.rmRF = exports.mv = exports.cp = void 0;
|
||||||
const assert_1 = __nccwpck_require__(9491);
|
const assert_1 = __nccwpck_require__(9491);
|
||||||
|
const childProcess = __importStar(__nccwpck_require__(2081));
|
||||||
const path = __importStar(__nccwpck_require__(1017));
|
const path = __importStar(__nccwpck_require__(1017));
|
||||||
|
const util_1 = __nccwpck_require__(3837);
|
||||||
const ioUtil = __importStar(__nccwpck_require__(1962));
|
const ioUtil = __importStar(__nccwpck_require__(1962));
|
||||||
|
const exec = util_1.promisify(childProcess.exec);
|
||||||
|
const execFile = util_1.promisify(childProcess.execFile);
|
||||||
/**
|
/**
|
||||||
* Copies a file or folder.
|
* Copies a file or folder.
|
||||||
* Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js
|
* Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js
|
||||||
|
|
@ -3697,23 +3695,61 @@ exports.mv = mv;
|
||||||
function rmRF(inputPath) {
|
function rmRF(inputPath) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
if (ioUtil.IS_WINDOWS) {
|
if (ioUtil.IS_WINDOWS) {
|
||||||
|
// Node doesn't provide a delete operation, only an unlink function. This means that if the file is being used by another
|
||||||
|
// program (e.g. antivirus), it won't be deleted. To address this, we shell out the work to rd/del.
|
||||||
// Check for invalid characters
|
// Check for invalid characters
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
|
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
|
||||||
if (/[*"<>|]/.test(inputPath)) {
|
if (/[*"<>|]/.test(inputPath)) {
|
||||||
throw new Error('File path must not contain `*`, `"`, `<`, `>` or `|` on Windows');
|
throw new Error('File path must not contain `*`, `"`, `<`, `>` or `|` on Windows');
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
const cmdPath = ioUtil.getCmdPath();
|
||||||
|
if (yield ioUtil.isDirectory(inputPath, true)) {
|
||||||
|
yield exec(`${cmdPath} /s /c "rd /s /q "%inputPath%""`, {
|
||||||
|
env: { inputPath }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
yield exec(`${cmdPath} /s /c "del /f /a "%inputPath%""`, {
|
||||||
|
env: { inputPath }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
// if you try to delete a file that doesn't exist, desired result is achieved
|
||||||
|
// other errors are valid
|
||||||
|
if (err.code !== 'ENOENT')
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
// Shelling out fails to remove a symlink folder with missing source, this unlink catches that
|
||||||
|
try {
|
||||||
|
yield ioUtil.unlink(inputPath);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
// if you try to delete a file that doesn't exist, desired result is achieved
|
||||||
|
// other errors are valid
|
||||||
|
if (err.code !== 'ENOENT')
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try {
|
else {
|
||||||
// note if path does not exist, error is silent
|
let isDir = false;
|
||||||
yield ioUtil.rm(inputPath, {
|
try {
|
||||||
force: true,
|
isDir = yield ioUtil.isDirectory(inputPath);
|
||||||
maxRetries: 3,
|
}
|
||||||
recursive: true,
|
catch (err) {
|
||||||
retryDelay: 300
|
// if you try to delete a file that doesn't exist, desired result is achieved
|
||||||
});
|
// other errors are valid
|
||||||
}
|
if (err.code !== 'ENOENT')
|
||||||
catch (err) {
|
throw err;
|
||||||
throw new Error(`File was unable to be removed ${err}`);
|
return;
|
||||||
|
}
|
||||||
|
if (isDir) {
|
||||||
|
yield execFile(`rm`, [`-rf`, `${inputPath}`]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
yield ioUtil.unlink(inputPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
36
dist/index1.js
vendored
36
dist/index1.js
vendored
|
|
@ -250,6 +250,10 @@ function getBooleanInput(name, options) {
|
||||||
const trueValue = ['true', 'True', 'TRUE'];
|
const trueValue = ['true', 'True', 'TRUE'];
|
||||||
const falseValue = ['false', 'False', 'FALSE'];
|
const falseValue = ['false', 'False', 'FALSE'];
|
||||||
const val = getInput(name, options);
|
const val = getInput(name, options);
|
||||||
|
info(`getBooleanInput: ${name}:${val}:::`)
|
||||||
|
process.stdout.write(`getBooleanInput: ${name}:${val}:::`)
|
||||||
|
process.stdout.write(os.EOL);
|
||||||
|
|
||||||
if (trueValue.includes(val))
|
if (trueValue.includes(val))
|
||||||
return true;
|
return true;
|
||||||
if (falseValue.includes(val))
|
if (falseValue.includes(val))
|
||||||
|
|
@ -27746,24 +27750,44 @@ async function checkTerraform () {
|
||||||
ignoreReturnCode: true,
|
ignoreReturnCode: true,
|
||||||
silent: true // avoid printing command in stdout: https://github.com/actions/toolkit/issues/649
|
silent: true // avoid printing command in stdout: https://github.com/actions/toolkit/issues/649
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: remove
|
||||||
|
core.setCommandEcho(true);
|
||||||
|
|
||||||
const exitCode = await exec(pathToCLI, args, options);
|
const exitCode = await exec(pathToCLI, args, options);
|
||||||
|
|
||||||
// Pass-through stdout/err as `exec` won't due to `silent: true` option
|
// Pass-through stdout/err as `exec` won't due to `silent: true` option
|
||||||
process.stdout.write(stdout.contents);
|
process.stdout.write(stdout.contents);
|
||||||
process.stderr.write(stderr.contents);
|
process.stderr.write(stderr.contents);
|
||||||
|
|
||||||
|
const fail_on_detected_diff2 = core.getInput('fail_on_detected_diff')
|
||||||
|
core.debug(`fail_on_detected_diff2: ${fail_on_detected_diff2}`);
|
||||||
|
|
||||||
// Set outputs, result, exitcode, and stderr
|
// Set outputs, result, exitcode, and stderr
|
||||||
core.setOutput('stdout', stdout.contents);
|
core.setOutput('stdout', stdout.contents);
|
||||||
core.setOutput('stderr', stderr.contents);
|
core.setOutput('stderr', stderr.contents);
|
||||||
core.setOutput('exitcode', exitCode.toString(10));
|
core.setOutput('exitcode', exitCode.toString(10));
|
||||||
|
|
||||||
if (exitCode === 0 || exitCode === 2) {
|
// A exitCode of 0 is considered a success
|
||||||
// A exitCode of 0 is considered a success
|
if (exitCode === 0) {
|
||||||
// An exitCode of 2 may be returned when the '-detailed-exitcode' option
|
core.info('Terraform completed successfully. (0)');
|
||||||
// is passed to plan. This denotes Success with non-empty
|
|
||||||
// diff (changes present).
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// An exitCode of 2 may be returned when the '-detailed-exitcode' option
|
||||||
|
// is passed to plan. This denotes Success with non-empty diff (changes present).
|
||||||
|
// The user may want to capture this and fail the job, so will set `fail_on_detected_diff: true`
|
||||||
|
if (exitCode === 2) {
|
||||||
|
const is_wrapper = core.getInput('terraform_wrapper')
|
||||||
|
const terraform_version = core.getInput('terraform_version');
|
||||||
|
const failOnDetectedDiffString = core.getInput('fail_on_detected_diff');
|
||||||
|
const failOnDetectedDiff = (failOnDetectedDiffString.toLowerCase() === 'true');
|
||||||
|
core.debug(`Terraform detected a difference. (2) failOnDetectedDiffString=${failOnDetectedDiffString} failOnDetectedDiff=${failOnDetectedDiff}`);
|
||||||
|
core.info(`Terraform detected a difference. 4 (2) is_wrapper=${is_wrapper} terraform_version=${terraform_version} failOnDetectedDiffString=${failOnDetectedDiffString} failOnDetectedDiff=${failOnDetectedDiff}`);
|
||||||
|
if (!failOnDetectedDiff) {
|
||||||
|
core.info('Terraform difference ignored.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A non-zero exitCode is considered an error
|
// A non-zero exitCode is considered an error
|
||||||
core.setFailed(`Terraform exited with code ${exitCode}.`);
|
core.setFailed(`Terraform exited with code ${exitCode}.`);
|
||||||
|
|
@ -27773,4 +27797,4 @@ async function checkTerraform () {
|
||||||
|
|
||||||
module.exports = __webpack_exports__;
|
module.exports = __webpack_exports__;
|
||||||
/******/ })()
|
/******/ })()
|
||||||
;
|
;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ const { exec } = require('@actions/exec');
|
||||||
|
|
||||||
const OutputListener = require('./lib/output-listener');
|
const OutputListener = require('./lib/output-listener');
|
||||||
const pathToCLI = require('./lib/terraform-bin');
|
const pathToCLI = require('./lib/terraform-bin');
|
||||||
|
const os = require("os");
|
||||||
|
const releases = require("@hashicorp/js-releases");
|
||||||
|
|
||||||
async function checkTerraform () {
|
async function checkTerraform () {
|
||||||
// Setting check to `true` will cause `which` to throw if terraform isn't found
|
// Setting check to `true` will cause `which` to throw if terraform isn't found
|
||||||
|
|
@ -36,24 +38,51 @@ async function checkTerraform () {
|
||||||
ignoreReturnCode: true,
|
ignoreReturnCode: true,
|
||||||
silent: true // avoid printing command in stdout: https://github.com/actions/toolkit/issues/649
|
silent: true // avoid printing command in stdout: https://github.com/actions/toolkit/issues/649
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: remove
|
||||||
|
core.setCommandEcho(true);
|
||||||
|
|
||||||
const exitCode = await exec(pathToCLI, args, options);
|
const exitCode = await exec(pathToCLI, args, options);
|
||||||
|
|
||||||
// Pass-through stdout/err as `exec` won't due to `silent: true` option
|
// Pass-through stdout/err as `exec` won't due to `silent: true` option
|
||||||
process.stdout.write(stdout.contents);
|
process.stdout.write(stdout.contents);
|
||||||
process.stderr.write(stderr.contents);
|
process.stderr.write(stderr.contents);
|
||||||
|
|
||||||
|
const fail_on_detected_diff2 = core.getInput('fail_on_detected_diff')
|
||||||
|
core.debug(`fail_on_detected_diff2: ${fail_on_detected_diff2}`);
|
||||||
|
|
||||||
|
// Gather GitHub Actions inputs
|
||||||
|
const version = core.getInput('terraform_version');
|
||||||
|
core.debug(`TEST d Terraform version ${version}`);
|
||||||
|
core.info(`TEST i Terraform version ${version}`);
|
||||||
|
|
||||||
// Set outputs, result, exitcode, and stderr
|
// Set outputs, result, exitcode, and stderr
|
||||||
core.setOutput('stdout', stdout.contents);
|
core.setOutput('stdout', stdout.contents);
|
||||||
core.setOutput('stderr', stderr.contents);
|
core.setOutput('stderr', stderr.contents);
|
||||||
core.setOutput('exitcode', exitCode.toString(10));
|
core.setOutput('exitcode', exitCode.toString(10));
|
||||||
|
|
||||||
if (exitCode === 0 || exitCode === 2) {
|
// A exitCode of 0 is considered a success
|
||||||
// A exitCode of 0 is considered a success
|
if (exitCode === 0) {
|
||||||
// An exitCode of 2 may be returned when the '-detailed-exitcode' option
|
core.info('Terraform completed successfully. (0)');
|
||||||
// is passed to plan. This denotes Success with non-empty
|
|
||||||
// diff (changes present).
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// An exitCode of 2 may be returned when the '-detailed-exitcode' option
|
||||||
|
// is passed to plan. This denotes Success with non-empty diff (changes present).
|
||||||
|
// The user may want to capture this and fail the job, so will set `fail_on_detected_diff: true`
|
||||||
|
if (exitCode === 2) {
|
||||||
|
const is_wrapper = core.getInput('terraform_wrapper')
|
||||||
|
const terraform_version = core.getInput('terraform_version');
|
||||||
|
const failOnDetectedDiffString = core.getInput('fail_on_detected_diff');
|
||||||
|
// const failOnDetectedDiff = core.getBooleanInput('fail_on_detected_diff');
|
||||||
|
//# getInput('my-input').toUpper() === 'true'
|
||||||
|
const failOnDetectedDiff = (failOnDetectedDiffString.toLowerCase() === 'fail');
|
||||||
|
core.debug(`Terraform detected a difference. (2) failOnDetectedDiffString=${failOnDetectedDiffString} failOnDetectedDiff=${failOnDetectedDiff}`);
|
||||||
|
core.info(`Terraform detected a difference. 4 (2) is_wrapper=${is_wrapper} terraform_version=${terraform_version} failOnDetectedDiffString=${failOnDetectedDiffString} failOnDetectedDiff=${failOnDetectedDiff}`);
|
||||||
|
if (!failOnDetectedDiff) {
|
||||||
|
core.info('Terraform difference ignored.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A non-zero exitCode is considered an error
|
// A non-zero exitCode is considered an error
|
||||||
core.setFailed(`Terraform exited with code ${exitCode}.`);
|
core.setFailed(`Terraform exited with code ${exitCode}.`);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue