core/public/Invoke-JaxEnvInit.ps1
|
function Invoke-JaxEnvInit { [CmdletBinding()] param ( [string] $RepoRoot = (Get-JaxRepoRoot), [string] $EnvRoot, [string] $Client, [string] $Env, [string] $DefaultFlow, [string[]] $AdditionalFlows, [switch] $IncludeJaxfile, [switch] $IncludeBobfile, [switch] $EnableVault, [switch] $EnableDotenv, [switch] $IncludeState, [System.Collections.Queue] $InputQueue ) $commonParams = Get-JaxCommonParameters -BoundParameters $PSBoundParameters Write-Debug "FUNC: $($MyInvocation.MyCommand.Name) Args: $($PSBoundParameters | ConvertTo-Json -Depth 1 -Compress -WarningAction SilentlyContinue)" $config = Get-JaxConfig -RepoRoot $RepoRoot -SkipUserConfig @commonParams if ([string]::IsNullOrWhiteSpace($EnvRoot)) { $EnvRoot = $config.envRoot } if ([string]::IsNullOrWhiteSpace($EnvRoot)) { $EnvRoot = 'env' } if ([string]::IsNullOrWhiteSpace($Client)) { $Client = Read-JaxPromptString -Prompt 'client name' -Default 'sample' -InputQueue $InputQueue } if ([string]::IsNullOrWhiteSpace($Client)) { throw 'Client name is required.' } if ([string]::IsNullOrWhiteSpace($Env)) { $Env = Read-JaxPromptString -Prompt 'env name' -Default 'dev' -InputQueue $InputQueue } if ([string]::IsNullOrWhiteSpace($Env)) { throw 'Env name is required.' } if ([string]::IsNullOrWhiteSpace($DefaultFlow)) { $DefaultFlow = Read-JaxPromptString -Prompt 'default flow name' -Default 'build' -InputQueue $InputQueue } if ([string]::IsNullOrWhiteSpace($DefaultFlow)) { throw 'Default flow name is required.' } $extraFlows = @() if ($null -ne $AdditionalFlows -and $AdditionalFlows.Count -gt 0) { $extraFlows = @($AdditionalFlows) } elseif (-not $PSBoundParameters.ContainsKey('AdditionalFlows')) { $extraFlows = Read-JaxPromptList -Prompt 'additional flows (comma-separated)' -Default @() -InputQueue $InputQueue } $flowNames = New-Object 'System.Collections.Generic.List[string]' foreach ($flow in @($DefaultFlow) + @($extraFlows)) { if ($null -eq $flow) { continue } $candidate = $flow.ToString().Trim() if ([string]::IsNullOrWhiteSpace($candidate)) { continue } if (-not $flowNames.Contains($candidate)) { $flowNames.Add($candidate) | Out-Null } } $flowDirName = $config.flowDirNames | Select-Object -First 1 if ([string]::IsNullOrWhiteSpace($flowDirName)) { $flowDirName = 'flows' } $scriptsDirName = $config.scripts.dirNames | Select-Object -First 1 if ([string]::IsNullOrWhiteSpace($scriptsDirName)) { $scriptsDirName = 'scripts' } $commonDirName = $config.commonDirName if ([string]::IsNullOrWhiteSpace($commonDirName)) { $commonDirName = 'common' } $scenarioLibDirName = $config.scenarioLibDirName if ([string]::IsNullOrWhiteSpace($scenarioLibDirName)) { $scenarioLibDirName = 'scenarios-lib' } $envRootPath = Join-Path $RepoRoot $EnvRoot $commonDir = Join-Path $envRootPath $commonDirName $clientDir = Join-Path $envRootPath $Client $clientCommonDir = Join-Path $clientDir $commonDirName $envDir = Join-Path $clientDir $Env $hierarchy = @($commonDir, $clientCommonDir, $envDir) foreach ($dir in $hierarchy) { if (-not (Test-Path -Path $dir -PathType Container)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } foreach ($sub in @($flowDirName, $scriptsDirName, $scenarioLibDirName)) { $subPath = Join-Path $dir $sub if (-not (Test-Path -Path $subPath -PathType Container)) { New-Item -ItemType Directory -Path $subPath -Force | Out-Null } $anchorPath = Join-Path $subPath '.gitkeep' if (-not (Test-Path -Path $anchorPath -PathType Leaf)) { [System.IO.File]::WriteAllText($anchorPath, '') } } } $flowDir = Join-Path $envDir $flowDirName $flowTaskMap = @{ 'build' = @('Build', 'Test') 'publish' = @('PublishZip', 'PublishNuget') 'k8s' = @('BuildImage', 'PushImage', 'DeployK8s') } $taskNames = New-Object 'System.Collections.Generic.List[string]' foreach ($flowName in $flowNames) { $fileName = "{0}.yml" -f $flowName $flowPath = Join-Path $flowDir $fileName if (-not (Test-Path -Path $flowPath -PathType Leaf)) { $lower = $flowName.ToLowerInvariant() $flowTasks = @() if ($flowTaskMap.ContainsKey($lower)) { $flowTasks = $flowTaskMap[$lower] } else { $safe = ($flowName -replace '[^\w]', '') if ([string]::IsNullOrWhiteSpace($safe)) { $safe = 'Example' } $flowTasks = @("{0}Task" -f $safe) } $flowContent = @() $flowContent += 'suite:' $flowContent += ' scenarios:' $flowContent += ' default:' foreach ($task in $flowTasks) { $flowContent += " - $task" } $flowContent -join "`n" | Set-Content -Path $flowPath -Encoding ascii } if ($flowTaskMap.ContainsKey($flowName.ToLowerInvariant())) { foreach ($task in $flowTaskMap[$flowName.ToLowerInvariant()]) { if (-not $taskNames.Contains($task)) { $taskNames.Add($task) | Out-Null } } } else { $safe = ($flowName -replace '[^\w]', '') if ([string]::IsNullOrWhiteSpace($safe)) { $safe = 'Example' } $task = "{0}Task" -f $safe if (-not $taskNames.Contains($task)) { $taskNames.Add($task) | Out-Null } } } if ($taskNames.Count -eq 0) { $taskNames.Add('ExampleTask') | Out-Null } $psakeContent = @() $psakeContent += ("Task Default -Depends {0}" -f $taskNames[0]) foreach ($task in $taskNames) { $psakeContent += '' $psakeContent += ("Task {0} {{" -f $task) $psakeContent += (" Write-Host ""{0} task""" -f $task) $psakeContent += '}' } $psakePayload = $psakeContent -join "`n" foreach ($dir in $hierarchy) { $psakePath = Join-Path $dir 'psakefile.ps1' if (-not (Test-Path -Path $psakePath -PathType Leaf)) { $psakePayload | Set-Content -Path $psakePath -Encoding ascii } } $sampleLibPath = Join-Path (Join-Path $commonDir $scenarioLibDirName) 'sample.yml' if (-not (Test-Path -Path $sampleLibPath -PathType Leaf)) { @' sample_task: runner: psake tasks: - Build '@ | Set-Content -Path $sampleLibPath -Encoding ascii } if ($IncludeJaxfile) { $jaxfilePath = Join-Path $envDir 'jaxfile.yml' if (-not (Test-Path -Path $jaxfilePath -PathType Leaf)) { @' module: tasks: ExampleTask: exampleParam: "value" '@ | Set-Content -Path $jaxfilePath -Encoding ascii } } if ($IncludeBobfile) { $bobfilePath = Join-Path $envDir 'bobfile.yml' if (-not (Test-Path -Path $bobfilePath -PathType Leaf)) { @' module: tasks: ExampleTask: exampleParam: "value" '@ | Set-Content -Path $bobfilePath -Encoding ascii } } $enableVault = $EnableVault if (-not $PSBoundParameters.ContainsKey('EnableVault')) { $enableVault = Read-JaxPromptBool -Prompt 'Enable vault plugin scaffold?' -Default $false -InputQueue $InputQueue } $enableDotenv = $EnableDotenv if (-not $PSBoundParameters.ContainsKey('EnableDotenv')) { $enableDotenv = Read-JaxPromptBool -Prompt 'Enable dotenv plugin scaffold?' -Default $false -InputQueue $InputQueue } if ($enableVault -or $enableDotenv) { $repoConfigPath = Get-JaxRepoConfigPath -RepoRoot $RepoRoot $repoConfig = $null if (Test-Path -Path $repoConfigPath -PathType Leaf) { $repoConfig = Resolve-JaxConfigSection -Config (Read-JaxYaml -Path $repoConfigPath) } if ($null -eq $repoConfig) { $repoConfig = @{} } if (-not ($repoConfig.Contains('plugins') -and $repoConfig['plugins'] -is [System.Collections.IDictionary])) { $repoConfig['plugins'] = @{} } $plugins = $repoConfig['plugins'] $effectivePlugins = $config['plugins'] $plugins['enabled'] = if ($plugins.Contains('enabled')) { @($plugins['enabled']) } else { @($effectivePlugins['enabled']) } $plugins['disabled'] = if ($plugins.Contains('disabled')) { @($plugins['disabled']) } else { @($effectivePlugins['disabled']) } if (-not ($plugins.Contains('config') -and $plugins['config'] -is [System.Collections.IDictionary])) { $plugins['config'] = @{} } $pluginConfig = $plugins['config'] if ($enableVault) { if (-not ($plugins['enabled'] -contains 'vault')) { $plugins['enabled'] = @($plugins['enabled']) + @('vault') } $plugins['disabled'] = @($plugins['disabled'] | Where-Object { $_ -ne 'vault' }) if (-not ($pluginConfig.Contains('vault') -and $pluginConfig['vault'] -is [System.Collections.IDictionary])) { $pluginConfig['vault'] = @{} } $pluginConfig['vault']['enabled'] = $true $vaultSampleDir = Join-Path $RepoRoot 'configs/jax' if (-not (Test-Path -Path $vaultSampleDir -PathType Container)) { New-Item -ItemType Directory -Path $vaultSampleDir -Force | Out-Null } $vaultSamplePath = Join-Path $vaultSampleDir 'vault.sample.yml' if (-not (Test-Path -Path $vaultSamplePath -PathType Leaf)) { @' vault: address: "https://vault.example.com" auth: method: "approle" roleId: "replace-me" secretId: "replace-me" '@ | Set-Content -Path $vaultSamplePath -Encoding ascii } } if ($enableDotenv) { if (-not ($plugins['enabled'] -contains 'dotenv')) { $plugins['enabled'] = @($plugins['enabled']) + @('dotenv') } $plugins['disabled'] = @($plugins['disabled'] | Where-Object { $_ -ne 'dotenv' }) if (-not ($pluginConfig.Contains('dotenv') -and $pluginConfig['dotenv'] -is [System.Collections.IDictionary])) { $pluginConfig['dotenv'] = @{} } $pluginConfig['dotenv']['enabled'] = $true if (-not $pluginConfig['dotenv'].Contains('files')) { $pluginConfig['dotenv']['files'] = @('.env') } $envPath = Join-Path $RepoRoot '.env' if (-not (Test-Path -Path $envPath -PathType Leaf)) { @' # Example local env variables (do not commit this file) EXAMPLE_FLAG=true '@ | Set-Content -Path $envPath -Encoding ascii } $gitIgnorePath = Join-Path $RepoRoot '.gitignore' if (Test-Path -Path $gitIgnorePath -PathType Leaf) { $ignoreContent = Get-Content -Path $gitIgnorePath if ($ignoreContent -notcontains '.env') { Add-Content -Path $gitIgnorePath -Value '.env' } } } # Persist the repository overrides plus the explicit plugin choice. # Do not expand the rest of the effective defaults into repo config. $payload = [ordered]@{ jax = $repoConfig } Write-JaxYaml -Path $repoConfigPath -InputObject $payload @commonParams $jaxDir = Join-Path $RepoRoot '.jax' if (-not (Test-Path -Path $jaxDir -PathType Container)) { New-Item -ItemType Directory -Path $jaxDir -Force | Out-Null } $jaxGitIgnore = Join-Path $jaxDir '.gitignore' if (-not (Test-Path -Path $jaxGitIgnore -PathType Leaf)) { @' state.yml logs/ '@ | Set-Content -Path $jaxGitIgnore -Encoding ascii } } $jaxDir = Join-Path $RepoRoot '.jax' if (-not (Test-Path -Path $jaxDir -PathType Container)) { New-Item -ItemType Directory -Path $jaxDir -Force | Out-Null } $jaxGitIgnore = Join-Path $jaxDir '.gitignore' if (-not (Test-Path -Path $jaxGitIgnore -PathType Leaf)) { @' state.yml logs/ '@ | Set-Content -Path $jaxGitIgnore -Encoding ascii } $createState = $IncludeState if (-not $PSBoundParameters.ContainsKey('IncludeState')) { $createState = Read-JaxPromptBool -Prompt 'Create .jax/state.yml with defaults?' -Default $false -InputQueue $InputQueue } if ($createState) { Update-JaxState -RepoRoot $RepoRoot -Updates @{} | Out-Null } return @{ EnvDir = $envDir FlowDir = $flowDir Flows = @($flowNames) } } |