Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ choco install wingetcreate
| [Settings](doc/settings.md) | Command for editing the settings file configurations |
| [Cache](doc/cache.md) | Command for managing downloaded installers stored in cache
| [Info](doc/info.md) | Displays information about the client |
| [Dsc](doc/dsc.md) | DSC v3 resource commands |
| [-?](doc/help.md) | Displays command line help |

Click on the individual commands to learn more.
Expand Down
25 changes: 25 additions & 0 deletions doc/dsc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# dsc command (Winget-Create)

The **dsc** command is the entry point for using DSC (Desired State Coonfiguration) with Winget-Create.

## Usage

`wingetcreate.exe dsc <resource> [<options>]`

## Resources
| Resource | Type | Description | <div style="white-space: nowrap;">--get</div> | <div style="white-space: nowrap;">--set</div> | <div style="white-space: nowrap;">--test</div> | <div style="white-space: nowrap;">--export</div> | <div style="white-space: nowrap;">--schema</div> | Link |
| ---- | ------ | ------------| ----- | ----- | ----- | ----- | ----- | ----- |
| `settings` | `Microsoft.WinGetCreate/Settings` | Manage the settings for Winget-Create | ✅ | ✅ | ✅ | ✅ | ✅ | [Details](dsc/settings.md) |

## Arguments

The following arguments are available:

| <div style="width:100px">Argument</div> | Description |
| --------------------------------------- | ------------|
| **-g, --get** | Get the resource state
| **-s, --set** | Set the resource state |
| **-t, --test** | Test the resource state |
| **-e, --export** | Get all state instances |
| **--schema** | Execute the Schema command |
| **-?, --help** | Gets additional help on this command. |
49 changes: 49 additions & 0 deletions doc/dsc/settings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Settings resource
Manage the settings for Winget-Create

## 📄 Get
```shell
PS C:\> wingetcreate dsc settings --get
{"settings":{"$schema":"https://aka.ms/wingetcreate-settings.schema.0.1.json","Telemetry":{"disable":true},"CleanUp":{"intervalInDays":7,"disable":false},"WindowsPackageManagerRepository":{"owner":"microsoft","name":"winget-pkgs"},"Manifest":{"format":"yaml"},"Visual":{"anonymizePaths":true}}}
```

## 🖨️ Export
ℹ️ Settings resource Get and Export operation output states are identical.
```shell
PS C:\> wingetcreate dsc settings --export
{"settings":{"$schema":"https://aka.ms/wingetcreate-settings.schema.0.1.json","Telemetry":{"disable":true},"CleanUp":{"intervalInDays":7,"disable":false},"WindowsPackageManagerRepository":{"owner":"microsoft","name":"winget-pkgs"},"Manifest":{"format":"yaml"},"Visual":{"anonymizePaths":true}}}
```

## 📝 Set
- Action `Full`: When action is set to Full, the specified settings will be update accordingly and the remaining settings will be set to their default values.
- Action `Partial`: When action is set to Partial, only the specified settings will be updated, and the remaining settings will remain unchanged.
### 🌕 Full
```shell
PS C:\> wingetcreate dsc settings --set '{"settings": { "Telemetry": { "disable": false }}, "action": "Full"}'
Comment thread
AmelBawa-msft marked this conversation as resolved.
{"settings":{"$schema":"https://aka.ms/wingetcreate-settings.schema.0.1.json","Telemetry":{"disable":false},"CleanUp":{"intervalInDays":7,"disable":false},"WindowsPackageManagerRepository":{"owner":"microsoft","name":"winget-pkgs"},"Manifest":{"format":"yaml"},"Visual":{"anonymizePaths":true}},"action":"Full"}
["settings"]
```

### 🌗 Partial
```shell
PS C:\> wingetcreate dsc settings --set '{"settings": { "Telemetry": { "disable": true }}, "action": "Partial"}'
{"settings":{"$schema":"https://aka.ms/wingetcreate-settings.schema.0.1.json","Telemetry":{"disable":true},"CleanUp":{"intervalInDays":7,"disable":false},"WindowsPackageManagerRepository":{"owner":"microsoft","name":"winget-pkgs"},"Manifest":{"format":"yaml"},"Visual":{"anonymizePaths":true}},"action":"Partial"}
["settings"]
```

## 🧪 Test
- Action `Full`: When action is set to Full, the specified settings will be tested accordingly, and the remaining settings will be tested against their default values.
- Action `Partial`: When action is set to Partial, only the specified settings will be tested, and the remaining settings will be omitted from the test.
### 🌕 Full
```shell
PS C:\> wingetcreate dsc settings --test '{"settings": { "Telemetry": { "disable": false }}, "action": "Full"}'
{"settings":{"$schema":"https://aka.ms/wingetcreate-settings.schema.0.1.json","Telemetry":{"disable":true},"CleanUp":{"intervalInDays":7,"disable":false},"WindowsPackageManagerRepository":{"owner":"microsoft","name":"winget-pkgs"},"Manifest":{"format":"yaml"},"Visual":{"anonymizePaths":true}},"action":"Full","_inDesiredState":false}
["settings"]
```

### 🌗 Partial
```shell
PS C:\> wingetcreate dsc settings --test '{"settings": { "Telemetry": { "disable": false }}, "action": "Partial"}'
{"settings":{"$schema":"https://aka.ms/wingetcreate-settings.schema.0.1.json","Telemetry":{"disable":true},"CleanUp":{"intervalInDays":7,"disable":false},"WindowsPackageManagerRepository":{"owner":"microsoft","name":"winget-pkgs"},"Manifest":{"format":"yaml"},"Visual":{"anonymizePaths":true}},"action":"Partial","_inDesiredState":false}
["settings"]
```
5 changes: 5 additions & 0 deletions src/WingetCreateCLI/Commands/BaseCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ public abstract class BaseCommand
/// </summary>
public static string Extension => Serialization.ManifestSerializer.AssociatedFileExtension;

/// <summary>
/// Gets a value indicating whether or not the command accepts a GitHub token.
/// </summary>
public virtual bool AcceptsGitHubToken { get; } = true;

/// <summary>
/// Gets or sets the GitHub token used to submit a pull request on behalf of the user.
/// </summary>
Expand Down
3 changes: 3 additions & 0 deletions src/WingetCreateCLI/Commands/CacheCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public class CacheCommand : BaseCommand
/// </summary>
[Option('o', "open", Required = true, SetName = nameof(Open), HelpText = "Open_HelpText", ResourceType = typeof(Resources))]
public bool Open { get; set; }

/// <inheritdoc/>
public override bool AcceptsGitHubToken => false;

/// <summary>
/// Executes the cache command flow.
Expand Down
118 changes: 118 additions & 0 deletions src/WingetCreateCLI/Commands/DscCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.

namespace Microsoft.WingetCreateCLI.Commands;
Comment thread
AmelBawa-msft marked this conversation as resolved.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using CommandLine;
using Microsoft.WingetCreateCLI.Commands.DscCommands;
using Microsoft.WingetCreateCLI.Logging;
using Microsoft.WingetCreateCLI.Properties;
using Newtonsoft.Json.Linq;

/// <summary>
/// Command for managing the application using dsc v3.
/// </summary>
[Verb("dsc", HelpText = "DscCommand_HelpText", ResourceType = typeof(Resources))]
public class DscCommand : BaseCommand
{
/// <inheritdoc/>
public override bool AcceptsGitHubToken => false;

/// <summary>
/// Gets or sets the name of the resource to be managed by the dsc command.
/// </summary>
[Value(0, MetaName = "ResourceName", Required = true, HelpText = "DscResourceName_HelpText", ResourceType = typeof(Resources))]
public string ResourceName { get; set; }

/// <summary>
/// Gets or sets the input for the dsc command.
/// </summary>
[Value(1, MetaName = "Input", Required = false, HelpText = "DscInput_HelpText", ResourceType = typeof(Resources))]
public string Input { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to execute the dsc Get operation.
/// </summary>
[Option('g', "get", SetName = "GetMethod", HelpText = "DscGet_HelpText", ResourceType = typeof(Resources))]
public bool Get { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to execute the dsc Set operation.
/// </summary>
[Option('s', "set", SetName = "SetMethod", HelpText = "DscSet_HelpText", ResourceType = typeof(Resources))]
public bool Set { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to execute the dsc Test operation.
/// </summary>
[Option('t', "test", SetName = "TestMethod", HelpText = "DscTest_HelpText", ResourceType = typeof(Resources))]
public bool Test { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to execute the dsc Export operation.
/// </summary>
[Option('e', "export", SetName = "ExportMethod", HelpText = "DscExport_HelpText", ResourceType = typeof(Resources))]
public bool Export { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to execute the schema command.
/// </summary>
[Option("schema", SetName = "SchemaMethod", HelpText = "DscSchema_HelpText", ResourceType = typeof(Resources))]
public bool Schema { get; set; }

/// <summary>
/// Executes the dsc command flow.
/// </summary>
/// <returns>Boolean representing success or fail of the command.</returns>
public override async Task<bool> Execute()
{
await Task.CompletedTask;
Comment thread
AmelBawa-msft marked this conversation as resolved.

if (!BaseDscCommand.TryCreateInstance(this.ResourceName, out var dscCommand))
{
var availableResources = string.Join(", ", BaseDscCommand.GetAvailableCommands());
Logger.ErrorLocalized(nameof(Resources.DscResourceNameNotFound_Message), this.ResourceName, availableResources);
return false;
}

try
{
var input = string.IsNullOrWhiteSpace(this.Input) ? null : JToken.Parse(this.Input);
var operations = new (bool, Func<bool>)[]
{
(this.Get, () => dscCommand.Get(input)),
(this.Set, () => dscCommand.Set(input)),
(this.Test, () => dscCommand.Test(input)),
(this.Export, () => dscCommand.Export(input)),
(this.Schema, () => dscCommand.Schema()),
};

foreach (var (methodFlag, methodAction) in operations)
{
if (methodFlag)
{
if (!methodAction())
{
Logger.ErrorLocalized(nameof(Resources.DscResourceOperationFailed_Message));
return false;
}

return true;
}
}

Logger.ErrorLocalized(nameof(Resources.DscResourceOperationNotSpecified_Message));
return false;
}
catch (Exception ex)
{
Logger.Error(ex.Message);
return false;
}
}
}
116 changes: 116 additions & 0 deletions src/WingetCreateCLI/Commands/DscCommands/BaseDscCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.

namespace Microsoft.WingetCreateCLI.Commands.DscCommands;

using System;
using System.Collections.Generic;
using Microsoft.WingetCreateCLI.Models.DscModels;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

/// <summary>
/// Base class for DSC commands.
/// </summary>
public abstract class BaseDscCommand
{
/// <summary>
/// Tries to create an instance of a DSC command based on the command name.
/// </summary>
/// <param name="commandName">The name of the command to create an instance for.</param>
/// <param name="commandInstance">The created command instance if successful; otherwise, null.</param>
/// <returns>True if the command instance was created successfully; otherwise, false.</returns>
public static bool TryCreateInstance(string commandName, out BaseDscCommand commandInstance)
{
var formattedCommandName = commandName?.ToLowerInvariant() ?? string.Empty;
switch (formattedCommandName)
{
case DscSettingsCommand.CommandName:
commandInstance = new DscSettingsCommand();
return true;

// Add more cases here for other DSC commands as needed.

// Return false if no matching command is found.
default:
commandInstance = null;
return false;
}
}

/// <summary>
/// Gets the list of available command names for DSC commands.
/// </summary>
/// <returns>The list of available command names.</returns>
public static List<string> GetAvailableCommands()
{
return [
DscSettingsCommand.CommandName,

// Add more command names here as needed.
];
}

/// <summary>
/// DSC Get command.
/// </summary>
/// <param name="input">Input for the Get command.</param>
/// <returns>True if the command was successful; otherwise, false.</returns>
public abstract bool Get(JToken input);

/// <summary>
/// DSC Set command.
/// </summary>
/// <param name="input">Input for the Set command.</param>
/// <returns>True if the command was successful; otherwise, false.</returns>
public abstract bool Set(JToken input);

/// <summary>
/// DSC Test command.
/// </summary>
/// <param name="input">Input for the Test command.</param>
/// <returns>True if the command was successful; otherwise, false.</returns>
public abstract bool Test(JToken input);

/// <summary>
/// DSC Export command.
/// </summary>
/// <param name="input">Input for the Export command.</param>
/// <returns>True if the command was successful; otherwise, false.</returns>
public abstract bool Export(JToken input);

/// <summary>
/// DSC Schema command.
/// </summary>
/// <returns>True if the command was successful; otherwise, false.</returns>
public abstract bool Schema();

/// <summary>
/// Creates a Json schema for a DSC resource object.
/// </summary>
/// <typeparam name="T">The type of the resource object.</typeparam>
/// <returns>A Json object representing the schema.</returns>
protected JObject CreateSchema<T>(string commandName)
where T : BaseResourceObject, new()
{
var resourceObject = new T();
return new JObject
{
["$schema"] = "http://json-schema.org/draft-07/schema#",
["title"] = commandName,
["type"] = "object",
["properties"] = resourceObject.GetProperties(),
["required"] = resourceObject.GetRequiredProperties(),
["additionalProperties"] = false,
};
Comment thread
AmelBawa-msft marked this conversation as resolved.
}

/// <summary>
/// Writes a JSON output line to the console.
/// </summary>
/// <param name="token">The JSON token to be written.</param>
protected void WriteJsonOutputLine(JToken token)
{
Console.WriteLine(token.ToString(Formatting.None));
}
}
Loading