Skip to content

Commit

Permalink
183 StateManagement breaks existing non-interactive build with disabl…
Browse files Browse the repository at this point in the history
…ed secrets (#184)

* Cleanup state handling for different input modes

Ensures that state management works in none interactive mode, and also add the disable state option to the BaseCommand options (doh! - missed that one). Fixes #183

* Save the state file still, as thats where secrets now live. Just dont load all state when --disable-state is true.

If no secrets - dont save state if its disabled

* Skip if secrets null
  • Loading branch information
prom3theu5 authored May 8, 2024
1 parent ddf340a commit dd5688e
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 20 deletions.
1 change: 1 addition & 0 deletions src/Aspirate.Commands/Commands/BaseCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ protected BaseCommand(string name, string description)
{
AddOption(NonInteractiveOption.Instance);
AddOption(DisableSecretsOption.Instance);
AddOption(DisableStateOption.Instance);
Handler = CommandHandler.Create<TOptions, IServiceCollection>(ConstructCommand);
}

Expand Down
74 changes: 54 additions & 20 deletions src/Aspirate.Services/Implementations/StateService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class StateService(IFileSystem fs, IAnsiConsole logger, ISecretProvider s

public async Task SaveState(StateManagementOptions options)
{
if (options.DisableState == true)
if (options.DisableState == true && (options.State.SecretState is null || options.State.SecretState.Secrets.Count == 0))
{
return;
}
Expand All @@ -30,51 +30,85 @@ public async Task RestoreState(StateManagementOptions options)
{
logger.WriteRuler("[purple]Handling Aspirate State[/]");

if (options.DisableState == true)
if (ShouldCancelAsStateFileDoesNotExist(out var stateFile))
{
logger.MarkupLine("State has been [red]disabled[/] for this run.");
return;
}

var stateFile = fs.Path.Combine(fs.Directory.GetCurrentDirectory(), AspirateLiterals.StateFileName);
if (await IsNonInteractiveMode(options, stateFile))
{
return;
}

if (options.NonInteractive == true)
if (options.DisableState == true)
{
await RestoreState(options, stateFile, true);
logger.MarkupLine($"[green]({EmojiLiterals.CheckMark}) Done: [/] State loaded successfully from [blue]{stateFile}[/]");
await OnlyRestoreSecrets(options, stateFile);
return;
}

if (!fs.File.Exists(stateFile))
if (await ShouldUseAllPreviousState(options, stateFile))
{
return;
}

await OnlyRestoreSecrets(options, stateFile);
}

private Task<bool> IsNonInteractiveMode(StateManagementOptions options, string stateFile) =>
options switch
{
{ NonInteractive: true, DisableState: true } => OnlyRestoreSecrets(options, stateFile),
{ NonInteractive: true, DisableState: false or null } => RestoreAllState(options, stateFile),
_ => Task.FromResult(false)
};

private bool ShouldCancelAsStateFileDoesNotExist(out string stateFile)
{
stateFile = fs.Path.Combine(fs.Directory.GetCurrentDirectory(), AspirateLiterals.StateFileName);

return !fs.File.Exists(stateFile);
}

private async Task<bool> ShouldUseAllPreviousState(StateManagementOptions options, string stateFile)
{
logger.MarkupLine($"[bold]Loading state from [blue]{stateFile}[/].[/]");

var shouldUseAllPreviousState = logger.Confirm("Would you like to use all previous state values, and [blue]skip[/] re-prompting where possible ?");

if (shouldUseAllPreviousState)
{
logger.MarkupLine("[bold]Using all previous state values, and skipping re-prompting.[/]");
await RestoreState(options, stateFile, true);
options.State.UseAllPreviousStateValues = true;
}
else
if (!shouldUseAllPreviousState)
{
logger.MarkupLine("[bold]Re-prompting for all state values not specified on command line.[/]");
await RestoreState(options, stateFile, false);
options.State.UseAllPreviousStateValues = false;
return false;
}

logger.MarkupLine($"[green]({EmojiLiterals.CheckMark}) Done: [/] State loaded successfully from [blue]{stateFile}[/]");
await RestoreAllState(options, stateFile);
return true;
}

private async Task<bool> RestoreAllState(StateManagementOptions options, string stateFile)
{
await RestoreState(options, stateFile, true);
LogAllStateReloaded(stateFile);
return true;
}

private async Task<bool> OnlyRestoreSecrets(StateManagementOptions options, string stateFile)
{
await RestoreState(options, stateFile, false);
LogDisabledStateMessage();
return true;
}

private async Task RestoreState(StateManagementOptions options, string stateFile, bool shouldUseAllPreviousStateValues)
{
var stateAsJson = await fs.File.ReadAllTextAsync(stateFile);
var previousState = JsonSerializer.Deserialize<AspirateState>(stateAsJson, _jsonSerializerOptions);

options.State.ReplaceCurrentStateWithPreviousState(previousState, shouldUseAllPreviousStateValues);
options.State.UseAllPreviousStateValues = shouldUseAllPreviousStateValues;
}

private void LogDisabledStateMessage() =>
logger.MarkupLine($"[green]({EmojiLiterals.CheckMark}) Done: [/] State has been disabled for this run. Only secrets will be populated.");

private void LogAllStateReloaded(string stateFile) =>
logger.MarkupLine($"[green]({EmojiLiterals.CheckMark}) Done: [/] State loaded successfully from [blue]{stateFile}[/]. Will run without re-prompting for values.");
}

0 comments on commit dd5688e

Please sign in to comment.