-
Notifications
You must be signed in to change notification settings - Fork 366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Full interactive mode (ask for target) #1436
Comments
Note: I digged up some old code which was referenced on some other issues and tried to implement a custom interactive mode similar. But the build log seems to be locked by the current process when I launch the second build. public class InteractiveBuildAttribute : BuildExtensionAttributeBase, IOnBuildInitialized
{
public void OnBuildInitialized(
IReadOnlyCollection<ExecutableTarget> executableTargets,
IReadOnlyCollection<ExecutableTarget> executionPlan)
{
if (!Build.Help && executionPlan.Count == 0 && NukeBuild.Host is Terminal)
{
Log.Information("No target specified, please select the target you want to run:");
foreach (var target in executableTargets.Where(x => x.Listed))
{
Log.Information("{TargetName}", target.Name);
if (!string.IsNullOrWhiteSpace(target.Description))
{
Log.Information(" {Description}", target.Description);
}
}
var defaultTarget = nameof(MySharedNukeBuild.Compile);
Log.Information(
"Type the name of the target you want to execute and hit [ENTER] (default: {DefaultTarget})",
defaultTarget);
Console.Write("> ");
var selectedTarget = Console.ReadLine();
if (string.IsNullOrEmpty(selectedTarget))
{
selectedTarget = defaultTarget;
}
else if (!executableTargets.Any(t => selectedTarget.EqualsOrdinalIgnoreCase(t.Name)))
{
Log.Error("Unknown target '{SelectedTarget}' specified, exiting", selectedTarget);
Environment.Exit(1);
}
Log.Information("Starting target {SelectedTarget}", selectedTarget);
var assembly = Assembly.GetEntryAssembly()!.Location;
var exitCode = 0;
DotNetTasks.DotNet($"{assembly} -- --nologo --target {selectedTarget}",
logInvocation: false,
exitHandler: p => exitCode = p.ExitCode);
Environment.Exit(exitCode);
}
}
}
// HandleHelpRequests has Priority 5, we want to be before it
[InteractiveBuild(Priority = 7)]
public class MySharedNukeBuild;
Even though it would still be great to have this built-in I'd be fine with implementing it myself via |
I would not implement it that way. I would rather extend |
Assuming we'd extend things here. How would you prefer to trigger the interactive flow? If we can agree on some path that also makes you happy, I'd could work on a PR 😉 Here some thoughts and proposals: One idea could be an extension which allows handling this scenario in custom ways and devs implement the logic as they like: var invokedTargets = ParameterService.GetParameter<string[]>(() => build.InvokedTargets);
if (build.IsInteractive || invokedTargets is not { Length: > 0 })
{
var newTargetList = new List<ExecutableTarget>();
build.ExecuteExtension<IOnBuildInteractiveTargets>(x => x.OnSelectTargetsInteractively(build.ExecutableTargets, newTargetList));
if (newTargetList.Count > 0)
{
invokedTargets = newTargetList.Select(t => t.Name).ToArray();
}
}
build.ExecutionPlan = ExecutionPlanner.GetExecutionPlan(
build.ExecutableTargets,
invokedTargets ); The alternative would be to go for a more direct call path to
In code similar to: // BuildManager.cs
var invokedTargets = ParameterService.GetParameter<string[]>(() => build.InvokedTargets);
if (invokedTargets is not { Length: > 0 })
{
invokedTargets = build.OnSelectTargetsInteractively(build.ExecutableTargets)?.Select(t => t.Name).ToArray();
}
build.ExecutionPlan = ExecutionPlanner.GetExecutionPlan(
build.ExecutableTargets,
invokedTargets);
// NukeBuild.cs
protected bool SelectTargetsInteractively { get; set; } // opt-in
protected virtual IReadOnlyCollection<ExecutableTarget>? OnSelectTargetsInteractively(IReadOnlyCollection<ExecutableTarget> executableTargets)
{
if (IsInteractive || SelectTargetsInteractively)
{
return Host.OnSelectTargetsInteractively(executableTargets);
}
else
{
return null;
}
}
// Host.cs
protected virtual IReadOnlyCollection<ExecutableTarget>? OnSelectTargetsInteractively(IReadOnlyCollection<ExecutableTarget> executableTargets)
{
return null;
}
// Terminal.cs
protected override IReadOnlyCollection<ExecutableTarget>? OnSelectTargetsInteractively(IReadOnlyCollection<ExecutableTarget> executableTargets)
{
PrintPrompt(executableTargets);
var userInput = Console.ReadLine().Split(',');
var target = userInput.Select(i => executableTargets.FirstOrDefault(t => i.EqualsOrdinalIgnoreCase(t.Name)).Where(t => t != null).ToReadOnlyCollection();
if (target.Count != userInput.Length)
{
PrintError(userInput);
return null;
}
return target;
} |
In the first iteration, I would keep it simpler and implement it without extension points. Without much research, I think |
Description
Nuke is great and very flexible when it comes to CLI usage and is very flexible in the usage from CI/CD systems. What I am missing a bit, is a modern user experience when developers use the "_build" project locally.
If the project/build is started without any input, and we detect a "Terminal" host, we enter an interactive mode to ask the user what to do. e.g. we have 5 different entry points to our build depending on what you want to do.
Usage Example
When I launch the "_build.exe" (or dotnet run) Nuke should prompt the user:
Then it starts the respective target just as if
nuke --target PrepareEnvironment
is called. The way of asking could be either fully interactive like very modern console apps, or simply asking for the user to type it.Alternative
I thought of making some unlisted target "interactive" the default one. Then I do any console interactivity myself (by loading the targets and stuff myself).
After the user has chosen the target, I would launch the target.
a) I cannot directly trigger another target within the same process. But it would be nice if I can have a dynamic "Triggers" in this target.
b) I trigger the target via
DotNetTasks.DotNetRun(<current assembly, target and parameters>)
Could you help with a pull-request?
Yes
The text was updated successfully, but these errors were encountered: