@salte-common/terraflow 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +278 -0
- package/RELEASE_SUMMARY.md +53 -0
- package/STANDARDS_COMPLIANCE.md +85 -0
- package/bin/terraflow.js +3 -0
- package/bin/tf.js +3 -0
- package/dist/commands/apply.d.ts +7 -0
- package/dist/commands/apply.js +12 -0
- package/dist/commands/base.d.ts +7 -0
- package/dist/commands/base.js +12 -0
- package/dist/commands/config.d.ts +25 -0
- package/dist/commands/config.js +354 -0
- package/dist/commands/destroy.d.ts +7 -0
- package/dist/commands/destroy.js +12 -0
- package/dist/commands/init.d.ts +68 -0
- package/dist/commands/init.js +131 -0
- package/dist/commands/plan.d.ts +7 -0
- package/dist/commands/plan.js +12 -0
- package/dist/core/backend-state.d.ts +25 -0
- package/dist/core/backend-state.js +77 -0
- package/dist/core/config.d.ts +83 -0
- package/dist/core/config.js +295 -0
- package/dist/core/context.d.ts +52 -0
- package/dist/core/context.js +192 -0
- package/dist/core/environment.d.ts +62 -0
- package/dist/core/environment.js +205 -0
- package/dist/core/errors.d.ts +22 -0
- package/dist/core/errors.js +36 -0
- package/dist/core/plugin-loader.d.ts +21 -0
- package/dist/core/plugin-loader.js +136 -0
- package/dist/core/terraform.d.ts +45 -0
- package/dist/core/terraform.js +247 -0
- package/dist/core/validator.d.ts +103 -0
- package/dist/core/validator.js +304 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +184 -0
- package/dist/plugins/auth/aws-assume-role.d.ts +10 -0
- package/dist/plugins/auth/aws-assume-role.js +110 -0
- package/dist/plugins/auth/azure-service-principal.d.ts +10 -0
- package/dist/plugins/auth/azure-service-principal.js +99 -0
- package/dist/plugins/auth/gcp-service-account.d.ts +10 -0
- package/dist/plugins/auth/gcp-service-account.js +105 -0
- package/dist/plugins/backends/azurerm.d.ts +10 -0
- package/dist/plugins/backends/azurerm.js +117 -0
- package/dist/plugins/backends/gcs.d.ts +10 -0
- package/dist/plugins/backends/gcs.js +75 -0
- package/dist/plugins/backends/local.d.ts +11 -0
- package/dist/plugins/backends/local.js +37 -0
- package/dist/plugins/backends/s3.d.ts +10 -0
- package/dist/plugins/backends/s3.js +185 -0
- package/dist/plugins/secrets/aws-secrets.d.ts +12 -0
- package/dist/plugins/secrets/aws-secrets.js +125 -0
- package/dist/plugins/secrets/azure-keyvault.d.ts +12 -0
- package/dist/plugins/secrets/azure-keyvault.js +178 -0
- package/dist/plugins/secrets/env.d.ts +24 -0
- package/dist/plugins/secrets/env.js +62 -0
- package/dist/plugins/secrets/gcp-secret-manager.d.ts +12 -0
- package/dist/plugins/secrets/gcp-secret-manager.js +157 -0
- package/dist/templates/application/go/go.mod.template +4 -0
- package/dist/templates/application/go/main.template +8 -0
- package/dist/templates/application/go/test.template +11 -0
- package/dist/templates/application/javascript/main.template +14 -0
- package/dist/templates/application/javascript/test.template +8 -0
- package/dist/templates/application/python/main.template +13 -0
- package/dist/templates/application/python/requirements.txt.template +3 -0
- package/dist/templates/application/python/test.template +8 -0
- package/dist/templates/application/typescript/main.template +14 -0
- package/dist/templates/application/typescript/test.template +8 -0
- package/dist/templates/application/typescript/tsconfig.json.template +20 -0
- package/dist/templates/config/README.md.template +82 -0
- package/dist/templates/config/env.example.template +22 -0
- package/dist/templates/config/gitignore.template +40 -0
- package/dist/templates/config/tfwconfig.yml.template +69 -0
- package/dist/templates/templates/application/go/go.mod.template +4 -0
- package/dist/templates/templates/application/go/main.template +8 -0
- package/dist/templates/templates/application/go/test.template +11 -0
- package/dist/templates/templates/application/javascript/main.template +14 -0
- package/dist/templates/templates/application/javascript/test.template +8 -0
- package/dist/templates/templates/application/python/main.template +13 -0
- package/dist/templates/templates/application/python/requirements.txt.template +3 -0
- package/dist/templates/templates/application/python/test.template +8 -0
- package/dist/templates/templates/application/typescript/main.template +14 -0
- package/dist/templates/templates/application/typescript/test.template +8 -0
- package/dist/templates/templates/application/typescript/tsconfig.json.template +20 -0
- package/dist/templates/templates/config/README.md.template +82 -0
- package/dist/templates/templates/config/env.example.template +22 -0
- package/dist/templates/templates/config/gitignore.template +40 -0
- package/dist/templates/templates/config/tfwconfig.yml.template +69 -0
- package/dist/templates/templates/terraform/aws/_init.tf.template +24 -0
- package/dist/templates/templates/terraform/aws/inputs.tf.template +11 -0
- package/dist/templates/templates/terraform/azure/_init.tf.template +19 -0
- package/dist/templates/templates/terraform/azure/inputs.tf.template +11 -0
- package/dist/templates/templates/terraform/gcp/_init.tf.template +20 -0
- package/dist/templates/templates/terraform/gcp/inputs.tf.template +16 -0
- package/dist/templates/templates/terraform/locals.tf.template +9 -0
- package/dist/templates/templates/terraform/main.tf.template +8 -0
- package/dist/templates/templates/terraform/modules/inputs.tf.template +5 -0
- package/dist/templates/templates/terraform/modules/main.tf.template +2 -0
- package/dist/templates/templates/terraform/modules/outputs.tf.template +2 -0
- package/dist/templates/templates/terraform/outputs.tf.template +6 -0
- package/dist/templates/terraform/aws/_init.tf.template +24 -0
- package/dist/templates/terraform/aws/inputs.tf.template +11 -0
- package/dist/templates/terraform/azure/_init.tf.template +19 -0
- package/dist/templates/terraform/azure/inputs.tf.template +11 -0
- package/dist/templates/terraform/gcp/_init.tf.template +20 -0
- package/dist/templates/terraform/gcp/inputs.tf.template +16 -0
- package/dist/templates/terraform/locals.tf.template +9 -0
- package/dist/templates/terraform/main.tf.template +8 -0
- package/dist/templates/terraform/modules/inputs.tf.template +5 -0
- package/dist/templates/terraform/modules/main.tf.template +2 -0
- package/dist/templates/terraform/modules/outputs.tf.template +2 -0
- package/dist/templates/terraform/outputs.tf.template +6 -0
- package/dist/types/config.d.ts +92 -0
- package/dist/types/config.js +6 -0
- package/dist/types/context.d.ts +59 -0
- package/dist/types/context.js +6 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.js +23 -0
- package/dist/types/plugins.d.ts +77 -0
- package/dist/types/plugins.js +6 -0
- package/dist/utils/cloud.d.ts +43 -0
- package/dist/utils/cloud.js +150 -0
- package/dist/utils/git.d.ts +88 -0
- package/dist/utils/git.js +258 -0
- package/dist/utils/logger.d.ts +67 -0
- package/dist/utils/logger.js +121 -0
- package/dist/utils/scaffolding.d.ts +92 -0
- package/dist/utils/scaffolding.js +338 -0
- package/dist/utils/templates.d.ts +25 -0
- package/dist/utils/templates.js +70 -0
- package/package.json +60 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Backend state management
|
|
4
|
+
* Stores previous backend configuration to detect migrations
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.loadBackendState = loadBackendState;
|
|
8
|
+
exports.saveBackendState = saveBackendState;
|
|
9
|
+
exports.detectBackendMigration = detectBackendMigration;
|
|
10
|
+
const fs_1 = require("fs");
|
|
11
|
+
const path_1 = require("path");
|
|
12
|
+
/**
|
|
13
|
+
* Get the backend state file path
|
|
14
|
+
* @param workingDir - Working directory
|
|
15
|
+
* @returns Path to state file
|
|
16
|
+
*/
|
|
17
|
+
function getStateFilePath(workingDir) {
|
|
18
|
+
const stateDir = (0, path_1.join)(workingDir, '.terraflow');
|
|
19
|
+
if (!(0, fs_1.existsSync)(stateDir)) {
|
|
20
|
+
(0, fs_1.mkdirSync)(stateDir, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
return (0, path_1.join)(stateDir, 'state.json');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Load previous backend state
|
|
26
|
+
* @param workingDir - Working directory
|
|
27
|
+
* @returns Previous backend configuration or null
|
|
28
|
+
*/
|
|
29
|
+
function loadBackendState(workingDir) {
|
|
30
|
+
const statePath = getStateFilePath(workingDir);
|
|
31
|
+
if (!(0, fs_1.existsSync)(statePath)) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const stateContent = (0, fs_1.readFileSync)(statePath, 'utf8');
|
|
36
|
+
const state = JSON.parse(stateContent);
|
|
37
|
+
return state.backend || null;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
// If state file is invalid, treat as no previous state
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Save backend state
|
|
46
|
+
* @param workingDir - Working directory
|
|
47
|
+
* @param backend - Backend configuration to save
|
|
48
|
+
*/
|
|
49
|
+
function saveBackendState(workingDir, backend) {
|
|
50
|
+
const statePath = getStateFilePath(workingDir);
|
|
51
|
+
const state = {
|
|
52
|
+
backend,
|
|
53
|
+
lastUpdated: new Date().toISOString(),
|
|
54
|
+
};
|
|
55
|
+
(0, fs_1.writeFileSync)(statePath, JSON.stringify(state, null, 2), 'utf8');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Detect if backend has changed
|
|
59
|
+
* @param workingDir - Working directory
|
|
60
|
+
* @param currentBackend - Current backend configuration
|
|
61
|
+
* @returns Previous backend type if changed, null otherwise
|
|
62
|
+
*/
|
|
63
|
+
function detectBackendMigration(workingDir, currentBackend) {
|
|
64
|
+
const previousBackend = loadBackendState(workingDir);
|
|
65
|
+
if (!previousBackend) {
|
|
66
|
+
// No previous state, this is first run
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
// Compare backend types
|
|
70
|
+
if (previousBackend.type !== currentBackend.type) {
|
|
71
|
+
return previousBackend.type;
|
|
72
|
+
}
|
|
73
|
+
// Backend types are the same, but config might have changed
|
|
74
|
+
// For now, we only detect type changes
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=backend-state.js.map
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration manager
|
|
3
|
+
* Loads and merges configuration from multiple sources
|
|
4
|
+
* Hierarchy: CLI > Env > Config File > Computed Defaults > Hard-coded Defaults
|
|
5
|
+
*/
|
|
6
|
+
import type { TerraflowConfig } from '../types/config';
|
|
7
|
+
export interface CliOptions {
|
|
8
|
+
config?: string;
|
|
9
|
+
workspace?: string;
|
|
10
|
+
backend?: string;
|
|
11
|
+
secrets?: string;
|
|
12
|
+
skipCommitCheck?: boolean;
|
|
13
|
+
workingDir?: string;
|
|
14
|
+
assumeRole?: string;
|
|
15
|
+
verbose?: boolean;
|
|
16
|
+
debug?: boolean;
|
|
17
|
+
dryRun?: boolean;
|
|
18
|
+
noColor?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Configuration manager for Terraflow
|
|
22
|
+
* Handles loading and merging configuration from multiple sources
|
|
23
|
+
*/
|
|
24
|
+
export declare class ConfigManager {
|
|
25
|
+
/**
|
|
26
|
+
* Load and merge configuration from CLI args, env vars, and config file
|
|
27
|
+
* @param cliOptions - Command line options
|
|
28
|
+
* @param cwd - Current working directory
|
|
29
|
+
* @returns Merged configuration
|
|
30
|
+
*/
|
|
31
|
+
static load(cliOptions?: CliOptions, cwd?: string): Promise<TerraflowConfig>;
|
|
32
|
+
/**
|
|
33
|
+
* Get the config file path
|
|
34
|
+
* @param cliOptions - CLI options
|
|
35
|
+
* @param cwd - Current working directory
|
|
36
|
+
* @returns Path to config file
|
|
37
|
+
*/
|
|
38
|
+
private static getConfigFilePath;
|
|
39
|
+
/**
|
|
40
|
+
* Load configuration from file
|
|
41
|
+
* @param configPath - Path to config file
|
|
42
|
+
* @returns Configuration object or empty object if file doesn't exist
|
|
43
|
+
*/
|
|
44
|
+
private static loadConfigFile;
|
|
45
|
+
/**
|
|
46
|
+
* Load configuration from environment variables
|
|
47
|
+
* @returns Configuration from environment
|
|
48
|
+
*/
|
|
49
|
+
private static loadFromEnvironment;
|
|
50
|
+
/**
|
|
51
|
+
* Convert CLI options to configuration format
|
|
52
|
+
* @param cliOptions - CLI options
|
|
53
|
+
* @returns Configuration object
|
|
54
|
+
*/
|
|
55
|
+
private static cliOptionsToConfig;
|
|
56
|
+
/**
|
|
57
|
+
* Parse boolean from string
|
|
58
|
+
* @param value - String value to parse
|
|
59
|
+
* @returns Boolean value
|
|
60
|
+
*/
|
|
61
|
+
private static parseBoolean;
|
|
62
|
+
/**
|
|
63
|
+
* Deep merge configuration objects
|
|
64
|
+
* Later objects override earlier ones
|
|
65
|
+
* @param configs - Configuration objects to merge (in priority order)
|
|
66
|
+
* @returns Merged configuration
|
|
67
|
+
*/
|
|
68
|
+
private static mergeConfigs;
|
|
69
|
+
/**
|
|
70
|
+
* Get resolved workspace name from configuration
|
|
71
|
+
* @param config - Configuration object
|
|
72
|
+
* @returns Workspace name or undefined
|
|
73
|
+
*/
|
|
74
|
+
static getWorkspace(config: TerraflowConfig): string | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* Get working directory path
|
|
77
|
+
* @param config - Configuration object
|
|
78
|
+
* @param cwd - Current working directory
|
|
79
|
+
* @returns Absolute path to working directory
|
|
80
|
+
*/
|
|
81
|
+
static getWorkingDir(config: TerraflowConfig, cwd?: string): string;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration manager
|
|
4
|
+
* Loads and merges configuration from multiple sources
|
|
5
|
+
* Hierarchy: CLI > Env > Config File > Computed Defaults > Hard-coded Defaults
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.ConfigManager = void 0;
|
|
12
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
15
|
+
const logger_1 = require("../utils/logger");
|
|
16
|
+
/**
|
|
17
|
+
* Configuration manager for Terraflow
|
|
18
|
+
* Handles loading and merging configuration from multiple sources
|
|
19
|
+
*/
|
|
20
|
+
class ConfigManager {
|
|
21
|
+
/**
|
|
22
|
+
* Load and merge configuration from CLI args, env vars, and config file
|
|
23
|
+
* @param cliOptions - Command line options
|
|
24
|
+
* @param cwd - Current working directory
|
|
25
|
+
* @returns Merged configuration
|
|
26
|
+
*/
|
|
27
|
+
static async load(cliOptions = {}, cwd = process.cwd()) {
|
|
28
|
+
// Start with hard-coded defaults (lowest priority)
|
|
29
|
+
const defaults = {
|
|
30
|
+
workspace: undefined,
|
|
31
|
+
'working-dir': './terraform',
|
|
32
|
+
'skip-commit-check': false,
|
|
33
|
+
backend: {
|
|
34
|
+
type: 'local',
|
|
35
|
+
},
|
|
36
|
+
logging: {
|
|
37
|
+
level: 'info',
|
|
38
|
+
terraform_log: false,
|
|
39
|
+
terraform_log_level: 'TRACE',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
// Load config file (higher priority than defaults)
|
|
43
|
+
const configFile = ConfigManager.getConfigFilePath(cliOptions, cwd);
|
|
44
|
+
const fileConfig = ConfigManager.loadConfigFile(configFile);
|
|
45
|
+
// Load environment variables (higher priority than config file)
|
|
46
|
+
const envConfig = ConfigManager.loadFromEnvironment();
|
|
47
|
+
// Merge: defaults < fileConfig < envConfig < cliOptions
|
|
48
|
+
const merged = ConfigManager.mergeConfigs(defaults, fileConfig, envConfig, ConfigManager.cliOptionsToConfig(cliOptions));
|
|
49
|
+
return merged;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get the config file path
|
|
53
|
+
* @param cliOptions - CLI options
|
|
54
|
+
* @param cwd - Current working directory
|
|
55
|
+
* @returns Path to config file
|
|
56
|
+
*/
|
|
57
|
+
static getConfigFilePath(cliOptions, cwd) {
|
|
58
|
+
if (cliOptions.config) {
|
|
59
|
+
return path_1.default.isAbsolute(cliOptions.config)
|
|
60
|
+
? cliOptions.config
|
|
61
|
+
: path_1.default.join(cwd, cliOptions.config);
|
|
62
|
+
}
|
|
63
|
+
const envConfig = process.env.TERRAFLOW_CONFIG;
|
|
64
|
+
if (envConfig) {
|
|
65
|
+
return path_1.default.isAbsolute(envConfig) ? envConfig : path_1.default.join(cwd, envConfig);
|
|
66
|
+
}
|
|
67
|
+
// Default: .tfwconfig.yml in working directory
|
|
68
|
+
return path_1.default.join(cwd, '.tfwconfig.yml');
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Load configuration from file
|
|
72
|
+
* @param configPath - Path to config file
|
|
73
|
+
* @returns Configuration object or empty object if file doesn't exist
|
|
74
|
+
*/
|
|
75
|
+
static loadConfigFile(configPath) {
|
|
76
|
+
if (!fs_1.default.existsSync(configPath)) {
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const content = fs_1.default.readFileSync(configPath, 'utf8');
|
|
81
|
+
const config = js_yaml_1.default.load(content);
|
|
82
|
+
logger_1.Logger.debug(`Loaded configuration from ${configPath}`);
|
|
83
|
+
return config || {};
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
logger_1.Logger.warn(`Failed to load config file ${configPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Load configuration from environment variables
|
|
92
|
+
* @returns Configuration from environment
|
|
93
|
+
*/
|
|
94
|
+
static loadFromEnvironment() {
|
|
95
|
+
const envConfig = {};
|
|
96
|
+
if (process.env.TERRAFLOW_WORKSPACE) {
|
|
97
|
+
envConfig.workspace = process.env.TERRAFLOW_WORKSPACE;
|
|
98
|
+
}
|
|
99
|
+
if (process.env.TERRAFLOW_WORKING_DIR) {
|
|
100
|
+
envConfig['working-dir'] = process.env.TERRAFLOW_WORKING_DIR;
|
|
101
|
+
}
|
|
102
|
+
if (process.env.TERRAFLOW_SKIP_COMMIT_CHECK) {
|
|
103
|
+
envConfig['skip-commit-check'] = ConfigManager.parseBoolean(process.env.TERRAFLOW_SKIP_COMMIT_CHECK);
|
|
104
|
+
}
|
|
105
|
+
if (process.env.TERRAFLOW_BACKEND) {
|
|
106
|
+
envConfig.backend = {
|
|
107
|
+
type: process.env.TERRAFLOW_BACKEND,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (process.env.TERRAFLOW_SECRETS) {
|
|
111
|
+
envConfig.secrets = {
|
|
112
|
+
provider: process.env.TERRAFLOW_SECRETS,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (process.env.TERRAFLOW_ASSUME_ROLE) {
|
|
116
|
+
envConfig.auth = {
|
|
117
|
+
assume_role: {
|
|
118
|
+
role_arn: process.env.TERRAFLOW_ASSUME_ROLE,
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return envConfig;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Convert CLI options to configuration format
|
|
126
|
+
* @param cliOptions - CLI options
|
|
127
|
+
* @returns Configuration object
|
|
128
|
+
*/
|
|
129
|
+
static cliOptionsToConfig(cliOptions) {
|
|
130
|
+
const config = {};
|
|
131
|
+
if (cliOptions.workspace !== undefined) {
|
|
132
|
+
config.workspace = cliOptions.workspace;
|
|
133
|
+
}
|
|
134
|
+
if (cliOptions.workingDir !== undefined) {
|
|
135
|
+
config['working-dir'] = cliOptions.workingDir;
|
|
136
|
+
}
|
|
137
|
+
if (cliOptions.skipCommitCheck !== undefined) {
|
|
138
|
+
config['skip-commit-check'] = cliOptions.skipCommitCheck;
|
|
139
|
+
}
|
|
140
|
+
if (cliOptions.backend !== undefined) {
|
|
141
|
+
config.backend = {
|
|
142
|
+
type: cliOptions.backend,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (cliOptions.secrets !== undefined) {
|
|
146
|
+
config.secrets = {
|
|
147
|
+
provider: cliOptions.secrets,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (cliOptions.assumeRole !== undefined) {
|
|
151
|
+
config.auth = {
|
|
152
|
+
assume_role: {
|
|
153
|
+
role_arn: cliOptions.assumeRole,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (cliOptions.verbose || cliOptions.debug) {
|
|
158
|
+
config.logging = {
|
|
159
|
+
level: cliOptions.debug ? 'debug' : 'info',
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (cliOptions.noColor !== undefined) {
|
|
163
|
+
// no-color is handled by Logger, not config
|
|
164
|
+
}
|
|
165
|
+
return config;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Parse boolean from string
|
|
169
|
+
* @param value - String value to parse
|
|
170
|
+
* @returns Boolean value
|
|
171
|
+
*/
|
|
172
|
+
static parseBoolean(value) {
|
|
173
|
+
const normalized = value.toLowerCase().trim();
|
|
174
|
+
return normalized === 'true' || normalized === '1' || normalized === 'yes';
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Deep merge configuration objects
|
|
178
|
+
* Later objects override earlier ones
|
|
179
|
+
* @param configs - Configuration objects to merge (in priority order)
|
|
180
|
+
* @returns Merged configuration
|
|
181
|
+
*/
|
|
182
|
+
static mergeConfigs(...configs) {
|
|
183
|
+
const result = {};
|
|
184
|
+
for (const config of configs) {
|
|
185
|
+
if (!config || typeof config !== 'object') {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
// Merge workspace
|
|
189
|
+
if (config.workspace !== undefined) {
|
|
190
|
+
result.workspace = config.workspace;
|
|
191
|
+
}
|
|
192
|
+
// Merge working-dir
|
|
193
|
+
if (config['working-dir'] !== undefined) {
|
|
194
|
+
result['working-dir'] = config['working-dir'];
|
|
195
|
+
}
|
|
196
|
+
// Merge skip-commit-check
|
|
197
|
+
if (config['skip-commit-check'] !== undefined) {
|
|
198
|
+
result['skip-commit-check'] = config['skip-commit-check'];
|
|
199
|
+
}
|
|
200
|
+
// Merge backend
|
|
201
|
+
if (config.backend) {
|
|
202
|
+
result.backend = {
|
|
203
|
+
...(result.backend || {}),
|
|
204
|
+
...config.backend,
|
|
205
|
+
config: {
|
|
206
|
+
...(result.backend?.config || {}),
|
|
207
|
+
...(config.backend.config || {}),
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
// Merge secrets
|
|
212
|
+
if (config.secrets) {
|
|
213
|
+
result.secrets = {
|
|
214
|
+
...(result.secrets || {}),
|
|
215
|
+
...config.secrets,
|
|
216
|
+
config: {
|
|
217
|
+
...(result.secrets?.config || {}),
|
|
218
|
+
...(config.secrets.config || {}),
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
// Merge auth
|
|
223
|
+
if (config.auth) {
|
|
224
|
+
result.auth = {
|
|
225
|
+
...(result.auth || {}),
|
|
226
|
+
...config.auth,
|
|
227
|
+
assume_role: config.auth.assume_role
|
|
228
|
+
? {
|
|
229
|
+
...(result.auth?.assume_role || {}),
|
|
230
|
+
...config.auth.assume_role,
|
|
231
|
+
}
|
|
232
|
+
: result.auth?.assume_role,
|
|
233
|
+
service_principal: config.auth.service_principal
|
|
234
|
+
? {
|
|
235
|
+
...(result.auth?.service_principal || {}),
|
|
236
|
+
...config.auth.service_principal,
|
|
237
|
+
}
|
|
238
|
+
: result.auth?.service_principal,
|
|
239
|
+
service_account: config.auth.service_account
|
|
240
|
+
? {
|
|
241
|
+
...(result.auth?.service_account || {}),
|
|
242
|
+
...config.auth.service_account,
|
|
243
|
+
}
|
|
244
|
+
: result.auth?.service_account,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
// Merge variables
|
|
248
|
+
if (config.variables) {
|
|
249
|
+
result.variables = {
|
|
250
|
+
...(result.variables || {}),
|
|
251
|
+
...config.variables,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
// Merge validations
|
|
255
|
+
if (config.validations) {
|
|
256
|
+
result.validations = {
|
|
257
|
+
...(result.validations || {}),
|
|
258
|
+
...config.validations,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
// Merge logging
|
|
262
|
+
if (config.logging) {
|
|
263
|
+
result.logging = {
|
|
264
|
+
...(result.logging || {}),
|
|
265
|
+
...config.logging,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
// Merge workspace_strategy
|
|
269
|
+
if (config.workspace_strategy) {
|
|
270
|
+
result.workspace_strategy = config.workspace_strategy;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Get resolved workspace name from configuration
|
|
277
|
+
* @param config - Configuration object
|
|
278
|
+
* @returns Workspace name or undefined
|
|
279
|
+
*/
|
|
280
|
+
static getWorkspace(config) {
|
|
281
|
+
return config.workspace;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Get working directory path
|
|
285
|
+
* @param config - Configuration object
|
|
286
|
+
* @param cwd - Current working directory
|
|
287
|
+
* @returns Absolute path to working directory
|
|
288
|
+
*/
|
|
289
|
+
static getWorkingDir(config, cwd = process.cwd()) {
|
|
290
|
+
const workingDir = config['working-dir'] || './terraform';
|
|
291
|
+
return path_1.default.isAbsolute(workingDir) ? workingDir : path_1.default.join(cwd, workingDir);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
exports.ConfigManager = ConfigManager;
|
|
295
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution context builder
|
|
3
|
+
* Builds execution context from environment and configuration
|
|
4
|
+
*/
|
|
5
|
+
import type { ExecutionContext } from '../types/context';
|
|
6
|
+
import type { TerraflowConfig } from '../types/config';
|
|
7
|
+
/**
|
|
8
|
+
* Execution context builder for Terraflow
|
|
9
|
+
* Collects runtime state for command execution
|
|
10
|
+
*/
|
|
11
|
+
export declare class ContextBuilder {
|
|
12
|
+
/**
|
|
13
|
+
* Build execution context from configuration and environment
|
|
14
|
+
* @param config - Terraflow configuration
|
|
15
|
+
* @param cwd - Current working directory
|
|
16
|
+
* @returns Execution context
|
|
17
|
+
*/
|
|
18
|
+
static build(config: TerraflowConfig, cwd?: string): Promise<ExecutionContext>;
|
|
19
|
+
/**
|
|
20
|
+
* Derive workspace name following priority strategy:
|
|
21
|
+
* 1. CLI parameter (--workspace)
|
|
22
|
+
* 2. Environment variable (TERRAFLOW_WORKSPACE)
|
|
23
|
+
* 3. Git tag (if on a tag)
|
|
24
|
+
* 4. Git branch (if not ephemeral)
|
|
25
|
+
* 5. Hostname
|
|
26
|
+
* @param config - Terraflow configuration
|
|
27
|
+
* @param cwd - Current working directory
|
|
28
|
+
* @returns Derived workspace name
|
|
29
|
+
*/
|
|
30
|
+
private static deriveWorkspace;
|
|
31
|
+
/**
|
|
32
|
+
* Build cloud provider information
|
|
33
|
+
* @returns Cloud information
|
|
34
|
+
*/
|
|
35
|
+
private static buildCloudInfo;
|
|
36
|
+
/**
|
|
37
|
+
* Build VCS information
|
|
38
|
+
* @param cwd - Current working directory
|
|
39
|
+
* @returns VCS information
|
|
40
|
+
*/
|
|
41
|
+
private static buildVcsInfo;
|
|
42
|
+
/**
|
|
43
|
+
* Build template variables for config resolution
|
|
44
|
+
* @param cloud - Cloud information
|
|
45
|
+
* @param vcs - VCS information
|
|
46
|
+
* @param hostname - Machine hostname
|
|
47
|
+
* @param workspace - Workspace name
|
|
48
|
+
* @returns Template variables
|
|
49
|
+
*/
|
|
50
|
+
private static buildTemplateVars;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Execution context builder
|
|
4
|
+
* Builds execution context from environment and configuration
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.ContextBuilder = void 0;
|
|
11
|
+
const os_1 = __importDefault(require("os"));
|
|
12
|
+
const config_1 = require("./config");
|
|
13
|
+
const git_1 = require("../utils/git");
|
|
14
|
+
/**
|
|
15
|
+
* Execution context builder for Terraflow
|
|
16
|
+
* Collects runtime state for command execution
|
|
17
|
+
*/
|
|
18
|
+
class ContextBuilder {
|
|
19
|
+
/**
|
|
20
|
+
* Build execution context from configuration and environment
|
|
21
|
+
* @param config - Terraflow configuration
|
|
22
|
+
* @param cwd - Current working directory
|
|
23
|
+
* @returns Execution context
|
|
24
|
+
*/
|
|
25
|
+
static async build(config, cwd = process.cwd()) {
|
|
26
|
+
const workspace = await ContextBuilder.deriveWorkspace(config, cwd);
|
|
27
|
+
const workingDir = config_1.ConfigManager.getWorkingDir(config, cwd);
|
|
28
|
+
const cloud = await ContextBuilder.buildCloudInfo();
|
|
29
|
+
const vcs = await ContextBuilder.buildVcsInfo(cwd);
|
|
30
|
+
const hostname = os_1.default.hostname();
|
|
31
|
+
// Build template variables from environment and context
|
|
32
|
+
const templateVars = ContextBuilder.buildTemplateVars(cloud, vcs, hostname, workspace);
|
|
33
|
+
// Build environment variables (sanitized, no secrets)
|
|
34
|
+
const env = {};
|
|
35
|
+
for (const key in process.env) {
|
|
36
|
+
if (Object.prototype.hasOwnProperty.call(process.env, key)) {
|
|
37
|
+
const value = process.env[key];
|
|
38
|
+
if (value !== undefined) {
|
|
39
|
+
env[key] = value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
workspace,
|
|
45
|
+
workingDir,
|
|
46
|
+
cloud,
|
|
47
|
+
vcs,
|
|
48
|
+
hostname,
|
|
49
|
+
env,
|
|
50
|
+
templateVars,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Derive workspace name following priority strategy:
|
|
55
|
+
* 1. CLI parameter (--workspace)
|
|
56
|
+
* 2. Environment variable (TERRAFLOW_WORKSPACE)
|
|
57
|
+
* 3. Git tag (if on a tag)
|
|
58
|
+
* 4. Git branch (if not ephemeral)
|
|
59
|
+
* 5. Hostname
|
|
60
|
+
* @param config - Terraflow configuration
|
|
61
|
+
* @param cwd - Current working directory
|
|
62
|
+
* @returns Derived workspace name
|
|
63
|
+
*/
|
|
64
|
+
static async deriveWorkspace(config, cwd) {
|
|
65
|
+
// 1. CLI parameter (highest priority) - already in config via ConfigManager
|
|
66
|
+
const cliWorkspace = config_1.ConfigManager.getWorkspace(config);
|
|
67
|
+
if (cliWorkspace) {
|
|
68
|
+
return git_1.GitUtils.sanitizeWorkspaceName(cliWorkspace);
|
|
69
|
+
}
|
|
70
|
+
// 2. Environment variable
|
|
71
|
+
const envWorkspace = process.env.TERRAFLOW_WORKSPACE;
|
|
72
|
+
if (envWorkspace) {
|
|
73
|
+
return git_1.GitUtils.sanitizeWorkspaceName(envWorkspace);
|
|
74
|
+
}
|
|
75
|
+
// Check if workspace_strategy is specified in config
|
|
76
|
+
const strategy = config.workspace_strategy || ['cli', 'env', 'tag', 'branch', 'hostname'];
|
|
77
|
+
// 3. Git tag (if on a tag)
|
|
78
|
+
if (strategy.includes('tag')) {
|
|
79
|
+
const tag = await git_1.GitUtils.getTag(cwd);
|
|
80
|
+
if (tag) {
|
|
81
|
+
return git_1.GitUtils.sanitizeWorkspaceName(tag);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// 4. Git branch (if not ephemeral)
|
|
85
|
+
if (strategy.includes('branch')) {
|
|
86
|
+
const branch = await git_1.GitUtils.getBranch(cwd);
|
|
87
|
+
if (branch && !git_1.GitUtils.isEphemeralBranch(branch)) {
|
|
88
|
+
return git_1.GitUtils.sanitizeWorkspaceName(branch);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// 5. Hostname (fallback)
|
|
92
|
+
if (strategy.includes('hostname')) {
|
|
93
|
+
const hostname = os_1.default.hostname();
|
|
94
|
+
return git_1.GitUtils.sanitizeWorkspaceName(hostname);
|
|
95
|
+
}
|
|
96
|
+
// Final fallback
|
|
97
|
+
return 'default';
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Build cloud provider information
|
|
101
|
+
* @returns Cloud information
|
|
102
|
+
*/
|
|
103
|
+
static async buildCloudInfo() {
|
|
104
|
+
// TODO: Implement cloud detection (AWS, Azure, GCP)
|
|
105
|
+
// For now, return default
|
|
106
|
+
return {
|
|
107
|
+
provider: 'none',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Build VCS information
|
|
112
|
+
* @param cwd - Current working directory
|
|
113
|
+
* @returns VCS information
|
|
114
|
+
*/
|
|
115
|
+
static async buildVcsInfo(cwd = process.cwd()) {
|
|
116
|
+
if (!git_1.GitUtils.isGitRepository(cwd)) {
|
|
117
|
+
return {};
|
|
118
|
+
}
|
|
119
|
+
const branch = await git_1.GitUtils.getBranch(cwd);
|
|
120
|
+
const tag = await git_1.GitUtils.getTag(cwd);
|
|
121
|
+
const commitSha = await git_1.GitUtils.getCommitSha(cwd);
|
|
122
|
+
const shortSha = commitSha ? commitSha.substring(0, 7) : await git_1.GitUtils.getShortSha(cwd);
|
|
123
|
+
const isClean = await git_1.GitUtils.isClean(cwd);
|
|
124
|
+
const githubRepository = await git_1.GitUtils.getGithubRepository(cwd);
|
|
125
|
+
const gitlabProjectPath = await git_1.GitUtils.getGitlabProjectPath(cwd);
|
|
126
|
+
return {
|
|
127
|
+
branch,
|
|
128
|
+
tag,
|
|
129
|
+
commitSha,
|
|
130
|
+
shortSha,
|
|
131
|
+
isClean,
|
|
132
|
+
githubRepository,
|
|
133
|
+
gitlabProjectPath,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Build template variables for config resolution
|
|
138
|
+
* @param cloud - Cloud information
|
|
139
|
+
* @param vcs - VCS information
|
|
140
|
+
* @param hostname - Machine hostname
|
|
141
|
+
* @param workspace - Workspace name
|
|
142
|
+
* @returns Template variables
|
|
143
|
+
*/
|
|
144
|
+
static buildTemplateVars(cloud, vcs, hostname, workspace) {
|
|
145
|
+
const vars = {
|
|
146
|
+
HOSTNAME: hostname,
|
|
147
|
+
WORKSPACE: workspace,
|
|
148
|
+
};
|
|
149
|
+
// Add all environment variables
|
|
150
|
+
for (const key in process.env) {
|
|
151
|
+
if (Object.prototype.hasOwnProperty.call(process.env, key)) {
|
|
152
|
+
const value = process.env[key];
|
|
153
|
+
if (value !== undefined) {
|
|
154
|
+
vars[key] = value;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Add cloud-specific variables
|
|
159
|
+
if (cloud.awsAccountId) {
|
|
160
|
+
vars.AWS_ACCOUNT_ID = cloud.awsAccountId;
|
|
161
|
+
}
|
|
162
|
+
if (cloud.awsRegion) {
|
|
163
|
+
vars.AWS_REGION = cloud.awsRegion;
|
|
164
|
+
}
|
|
165
|
+
if (cloud.azureSubscriptionId) {
|
|
166
|
+
vars.AZURE_SUBSCRIPTION_ID = cloud.azureSubscriptionId;
|
|
167
|
+
}
|
|
168
|
+
if (cloud.gcpProjectId) {
|
|
169
|
+
vars.GCP_PROJECT_ID = cloud.gcpProjectId;
|
|
170
|
+
}
|
|
171
|
+
// Add VCS-specific variables
|
|
172
|
+
if (vcs.branch) {
|
|
173
|
+
vars.GIT_BRANCH = vcs.branch;
|
|
174
|
+
}
|
|
175
|
+
if (vcs.tag) {
|
|
176
|
+
vars.GIT_TAG = vcs.tag;
|
|
177
|
+
}
|
|
178
|
+
if (vcs.commitSha) {
|
|
179
|
+
vars.GIT_COMMIT_SHA = vcs.commitSha;
|
|
180
|
+
vars.GIT_SHORT_SHA = vcs.shortSha || vcs.commitSha.substring(0, 7);
|
|
181
|
+
}
|
|
182
|
+
if (vcs.githubRepository) {
|
|
183
|
+
vars.GITHUB_REPOSITORY = vcs.githubRepository;
|
|
184
|
+
}
|
|
185
|
+
if (vcs.gitlabProjectPath) {
|
|
186
|
+
vars.GITLAB_PROJECT_PATH = vcs.gitlabProjectPath;
|
|
187
|
+
}
|
|
188
|
+
return vars;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
exports.ContextBuilder = ContextBuilder;
|
|
192
|
+
//# sourceMappingURL=context.js.map
|