Skip to content

Commit

Permalink
Merge pull request #8 from Kentico/feat/delete-command
Browse files Browse the repository at this point in the history
Delete command, install only database
  • Loading branch information
kentico-ericd authored Sep 30, 2024
2 parents a427252 + 09ebc94 commit 563f384
Show file tree
Hide file tree
Showing 45 changed files with 836 additions and 264 deletions.
3 changes: 2 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"args": ["i"],
"cwd": "${workspaceFolder}",
"console": "externalTerminal",
"stopAtEntry": false
"stopAtEntry": false,
"brokeredServicePipeName": "undefined",
}
]
}
20 changes: 11 additions & 9 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<Project>
<PropertyGroup>
<Company>Kentico</Company>
<Authors>Eric Dugre</Authors>
<VersionPrefix>4.0.0</VersionPrefix>
<Product>Xperience by Kentico</Product>
<LangVersion>12.0</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<Company>Kentico</Company>
<Authors>Eric Dugre</Authors>
<VersionPrefix>5.0.0</VersionPrefix>
<Product>Xperience by Kentico</Product>
<LangVersion>12.0</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RepositoryUrl>https://github.com/Kentico/xperience-by-kentico-manager</RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup>

<ItemGroup Label="StaticCodeAnalysis">
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.41.0.50478">
Expand All @@ -19,4 +21,4 @@
<PropertyGroup>
<TimestampServerUrl>http://timestamp.digicert.com</TimestampServerUrl>
</PropertyGroup>
</Project>
</Project>
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ The following commands can be executed using the `xman` tool name:
- `?`, `help`
- [`i`, `install`](#installing-a-new-project)
- [`u`, `update`](#updating-a-project-version)
- [`d`, `delete`](#deleting-a-project)
- [`m`, `macros`](#re-signing-macros)
- [`b`, `build`](#building-projects)
- [`g`, `generate`](#generating-code-for-object-types)
Expand Down Expand Up @@ -103,6 +104,8 @@ The installation wizard will automatically generate an administrator password fo
xman install
```

Installing a new project automatically includes a database as well. If you want to _only_ install a database and not the project files, use the __db__ parameter: `xman install db`.

### Updating a project version

1. (optional) Select a profile with the [`profile`](#managing-profiles) command
Expand All @@ -112,6 +115,17 @@ The installation wizard will automatically generate an administrator password fo
xman update
```

### Deleting a project

> :warning: The `delete` command will drop the database and delete the files. Use with caution!

1. (optional) Select a profile with the [`profile`](#managing-profiles) command
1. Run the `delete` command from the directory containing the [configuration file](#configuration-file):

```bash
xman delete
```

### Modifying appsettings.json

This tool can assist with changing the _CMSConnectionString_, supported [configuration keys](https://docs.xperience.io/xp/developers-and-admins/configuration/reference-configuration-keys), and the [headless API](https://docs.xperience.io/xp/developers-and-admins/configuration/headless-channel-management#Headlesschannelmanagement-ConfiguretheheadlessAPI).
Expand Down
Binary file added img/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/Commands/Base/AbstractCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public virtual Task PreExecute(ToolProfile? profile, string? action)


/// <summary>
/// A handler which can be assigned to <see cref="Process.ErrorDataReceived"/> to handler errors.
/// A handler which can be assigned to <see cref="Process.ErrorDataReceived"/> to handle errors.
/// </summary>
protected void ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Expand All @@ -80,7 +80,7 @@ protected void LogError(string message, Process? process = null)
}


protected void PrintCurrentProfile(ToolProfile? profile)
protected static void PrintCurrentProfile(ToolProfile? profile)
{
AnsiConsole.Write(new Rule("Current profile:") { Justification = Justify.Left });
AnsiConsole.MarkupLineInterpolated($"Name: [{Constants.EMPHASIS_COLOR}]{profile?.ProjectName ?? "None"}[/]");
Expand Down
2 changes: 1 addition & 1 deletion src/Commands/BuildCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class BuildCommand : AbstractCommand
public override IEnumerable<string> Keywords => ["b", "build"];


public override IEnumerable<string> Parameters => Enumerable.Empty<string>();
public override IEnumerable<string> Parameters => [];


public override string Description => "Builds a project";
Expand Down
2 changes: 1 addition & 1 deletion src/Commands/CodeGenerateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class CodeGenerateCommand : AbstractCommand
public override IEnumerable<string> Keywords => ["g", "generate"];


public override IEnumerable<string> Parameters => Enumerable.Empty<string>();
public override IEnumerable<string> Parameters => [];


public override string Description => "Generates code files for Xperience objects";
Expand Down
145 changes: 145 additions & 0 deletions src/Commands/DeleteCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
using Spectre.Console;

using Xperience.Manager.Configuration;
using Xperience.Manager.Options;
using Xperience.Manager.Services;

namespace Xperience.Manager.Commands
{
/// <summary>
/// A command which deletes an Xperience by Kentico project.
/// </summary>
public class DeleteCommand : AbstractCommand
{
private bool deleteConfirmed;
private readonly IShellRunner shellRunner;
private readonly IScriptBuilder scriptBuilder;
private readonly IConfigManager configManager;
private readonly IAppSettingsManager appSettingsManager;


public override IEnumerable<string> Keywords => ["d", "delete"];


public override IEnumerable<string> Parameters => [];


public override string Description => "Deletes a project and its database";


public override bool RequiresProfile => true;


/// <summary>
/// Do not use. Workaround for circular dependency in <see cref="HelpCommand"/> when commands are injected
/// into the constuctor.
/// </summary>
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
internal DeleteCommand()
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
{
}


public DeleteCommand(IShellRunner shellRunner, IScriptBuilder scriptBuilder, IConfigManager configManager, IAppSettingsManager appSettingsManager)
{
this.shellRunner = shellRunner;
this.scriptBuilder = scriptBuilder;
this.configManager = configManager;
this.appSettingsManager = appSettingsManager;
}


public override async Task Execute(ToolProfile? profile, string? action)
{
deleteConfirmed = AnsiConsole.Confirm($"This will [{Constants.ERROR_COLOR}]delete[/] the current profile's physical folder and database!\nDo you want to continue?", false);
if (!deleteConfirmed)
{
return;
}

AnsiConsole.WriteLine();
await DropDatabase(profile);
await UninstallFiles(profile);
if (!StopProcessing)
{
await configManager.RemoveProfile(profile);
}
}


public override async Task PostExecute(ToolProfile? profile, string? action)
{
if (!deleteConfirmed)
{
AnsiConsole.MarkupLineInterpolated($"[{Constants.EMPHASIS_COLOR}]Delete cancelled[/]\n");
}
else if (!Errors.Any())
{
AnsiConsole.MarkupLineInterpolated($"[{Constants.SUCCESS_COLOR}]Delete complete![/]\n");
}

await base.PostExecute(profile, action);
}


private async Task DropDatabase(ToolProfile? profile)
{
if (StopProcessing)
{
return;
}

AnsiConsole.MarkupLineInterpolated($"[{Constants.EMPHASIS_COLOR}]Deleting database...[/]");

string? connString = await appSettingsManager.GetConnectionString(profile, "CMSConnectionString");
if (connString is null)
{
LogError("Couldn't load connection string.");
return;
}

// Find "Initial Catalog" in connection string
IEnumerable<string> parts = connString.Split(';').ToList();
string? initialCatalogPart = parts.FirstOrDefault(p => p.ToLower().StartsWith("initial catalog"));
if (initialCatalogPart is null)
{
LogError("Couldn't find database name.");
return;
}

// Remove "Initial Catalog" from connection string, or trying to delete will throw "in use" error
parts = parts.Where(p => !p.Equals(initialCatalogPart, StringComparison.OrdinalIgnoreCase));
connString = string.Join(';', parts);
string databaseName = initialCatalogPart.Split('=')[1].Trim();

var options = new RunSqlOptions()
{
SqlQuery = $"DROP DATABASE {databaseName}",
ConnString = connString
};
string dbScript = scriptBuilder.SetScript(ScriptType.ExecuteSql).WithPlaceholders(options).Build();
await shellRunner.Execute(new(dbScript)
{
ErrorHandler = ErrorDataReceived
}).WaitForExitAsync();
}


private async Task UninstallFiles(ToolProfile? profile)
{
if (StopProcessing)
{
return;
}

AnsiConsole.MarkupLineInterpolated($"[{Constants.EMPHASIS_COLOR}]Deleting local files...[/]");

string uninstallScript = scriptBuilder.SetScript(ScriptType.DeleteDirectory).WithPlaceholders(profile).Build();
await shellRunner.Execute(new(uninstallScript)
{
ErrorHandler = ErrorDataReceived
}).WaitForExitAsync();
}
}
}
5 changes: 3 additions & 2 deletions src/Commands/HelpCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class HelpCommand : AbstractCommand
[
new ProfileCommand(),
new InstallCommand(),
new DeleteCommand(),
new UpdateCommand(),
new ContinuousIntegrationCommand(),
new ContinuousDeploymentCommand(),
Expand All @@ -32,7 +33,7 @@ public class HelpCommand : AbstractCommand
public override IEnumerable<string> Keywords => ["?", "help"];


public override IEnumerable<string> Parameters => Enumerable.Empty<string>();
public override IEnumerable<string> Parameters => [];


public override string Description => "Displays the help menu (this screen)";
Expand All @@ -51,7 +52,7 @@ public override async Task Execute(ToolProfile? profile, string? action)
AnsiConsole.WriteLine($" v{v.Major}.{v.Minor}.{v.Build}");
}

AnsiConsole.MarkupInterpolated($" [{Constants.EMPHASIS_COLOR}]https://github.com/kentico/xperience-manager[/]\n");
AnsiConsole.MarkupInterpolated($" [{Constants.EMPHASIS_COLOR}]https://github.com/Kentico/xperience-by-kentico-manager[/]\n");

var table = new Table()
.AddColumn("Command")
Expand Down
Loading

0 comments on commit 563f384

Please sign in to comment.