Skip to content

Commit

Permalink
Improved documentation with badges (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
svrooij authored May 1, 2024
1 parent d2bce51 commit fa54cb6
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 43 deletions.
52 changes: 24 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# WinTuner

[![Documentation badge](https://img.shields.io/badge/Show_Documentation-darkblue?style=for-the-badge)](https://wintuner.app/)
[![PowerShell gallery version][badge_powershell]][link_powershell]
[![Nuget version][badge_nuget]][link_nuget]
[![License][badge_license]][link_license]
[![GitHub issues](https://img.shields.io/github/issues/svrooij/wingetintune?style=for-the-badge)](https://github.com/svrooij/WingetIntune/issues)
[![Github sponsors](https://img.shields.io/github/sponsors/svrooij?style=for-the-badge&logo=github&logoColor=white)](https://github.com/sponsors/svrooij)

[Documentation](https://wintuner.app/)
[![WinTuner Mascot](https://wintuner.app/img/wintuner-mascotte-two_100.png)](https://wintuner.app/)

Take any app from WinGet and upload it to Intune in minutes. This app is available as [PowerShell module](#wintuner-powershell-module) and as a [CLI](#wintuner-cli), both run mostly thee same code.

Expand All @@ -19,6 +23,9 @@ Take any app from WinGet and upload it to Intune in minutes. This app is availab

## WinTuner PowerShell Module

[![PowerShell gallery version][badge_powershell]][link_powershell]
[![PowerShell gallery downloads][badge_powershell_downloads]][link_powershell]

This is the PowerShell version of the WinTuner application, requiring PowerShell `7.4` (net8.0). Available in the [PowerShell Gallery](https://www.powershellgallery.com/packages/WinTuner/). Documentation can be found [here](https://wintuner.app/docs/category/wintuner-powershell).

```PowerShell
Expand All @@ -29,48 +36,27 @@ As of April 2024, the main development focus will be on the PowerShell module, s

## WinTuner CLI

This application ~~is Windows only and~~ requires **Dotnet 8** to be installed on your computer. It's a [beta application](#beta-application), so please report any issues you find.
[![Nuget version][badge_nuget]][link_nuget]
[![Nuget downloads][badge_nuget_downloads]][link_nuget]

This application requires **Dotnet 8** to be installed on your computer. It's a [beta application](#beta-application), so please report any issues you find.
Some commands run the `winget` in the background and are thus Windows-only, make sure you have the [App Installer](https://www.microsoft.com/p/app-installer/9nblggh4nns1) installed on your computer if you want to use these commands.

The `package` and `publish` commands are cross-platform, and should work on any platform that supports dotnet 8. These commands no longer use the WinGet executable, which also means any other sources than `winget` are no longer supported.
The `msi` command is still windows only, as it uses the `Microsoft.Deployment.WindowsInstaller` package.

Check out the [documentation](https://wintuner.app/docs/category/wintuner-cli) for more information.

### Installing

This package can be downloaded as a dotnet tool. Make sure you have Dotnet 8 installed on your computer.
I'm working to get a code signing certificate, but for now you might have to configure an exception on your computer to run unsigned code.

```Shell
# Install dotnet 8 sdk (or the way specific for your platform)
winget install --id Microsoft.DotNet.SDK.8 --source winget

# Add the nuget feed, if that is not already done
dotnet nuget add source https://api.nuget.org/v3/index.json --name nuget.org

# This command will install the tool
dotnet tool install --global Svrooij.Winget-Intune.Cli

# or to update to the latest version
dotnet tool update --global SvRooij.Winget-Intune.Cli

```

## Beta application

This is a beta application, it's not yet ready for production use. I'm still working on it, and I'm looking for feedback.
If you found a bug please create an [issue](https://github.com/svrooij/WingetIntune/issues/new/choose), if you have questions or want to share your feedback, check out the [discussions](https://github.com/svrooij/WingetIntune/discussions) page.

## Library (soon)

I'm planning to release the actual intune specific code as a separate library, so you can use it in your own projects. This will be released as a separate package.

## Contributing

If you want to contribute to this project, please check out the [contributing](https://github.com/svrooij/WingetIntune/blob/main/CONTRIBUTING.md) page and the [Code of Conduct](https://github.com/svrooij/WingetIntune/blob/main/CODE_OF_CONDUCT.md).

## Usefull information
## Useful information

- [WinTuner website](https://wintuner.app/)
- [Blog articles on Intune](https://svrooij.io/tags/intune/)
Expand All @@ -84,4 +70,14 @@ If you want to contribute to this project, please check out the [contributing](h
[link_blog]: https://svrooij.io/
[link_linkedin]: https://www.linkedin.com/in/stephanvanrooij
[link_mastodon]: https://dotnet.social/@svrooij
[link_twitter]: https://twitter.com/svrooij
[link_twitter]: https://twitter.com/svrooij

[badge_license]: https://img.shields.io/github/license/svrooij/WingetIntune?style=for-the-badge
[link_license]: https://github.com/svrooij/WingetIntune/blob/main/LICENSE.txt
[badge_powershell]: https://img.shields.io/powershellgallery/v/WinTuner?style=for-the-badge&logo=powershell&logoColor=white
[badge_powershell_downloads]: https://img.shields.io/powershellgallery/dt/WinTuner?style=for-the-badge&logo=powershell&logoColor=white
[link_powershell]: https://www.powershellgallery.com/packages/WinTuner/

[badge_nuget]: https://img.shields.io/nuget/v/Svrooij.Winget-Intune.Cli?style=for-the-badge&logo=nuget&logoColor=white
[badge_nuget_downloads]: https://img.shields.io/nuget/dt/Svrooij.Winget-Intune.Cli?style=for-the-badge&logo=nuget&logoColor=white
[link_nuget]: https://www.nuget.org/packages/Svrooij.Winget-Intune.Cli/
19 changes: 11 additions & 8 deletions src/Svrooij.WinTuner.CmdLets/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# WinTuner PowerShell module

## Refresh documentation
[![Documentation badge](https://img.shields.io/badge/Show_Documentation-darkblue?style=for-the-badge)](https://wintuner.app/)
[![PowerShell gallery version][badge_powershell]][link_powershell]
[![PowerShell gallery downloads][badge_powershell_downloads]][link_powershell]
[![License][badge_license]][link_license]

```PowerShell
New-MarkdownHelp -Module "Svrooij.WinTuner.CmdLets" -OutputFolder "..\..\..\docs" -WithModulePage -Force
```
Source of WinTuner PowerShell module, available in the [PowerShell Gallery][link_powershell].

## Create a package and deploy to Intune
Documentation can be found [here](https://wintuner.app/docs/category/wintuner-powershell).

```PowerShell
New-WtWingetPackage -PackageId Jandedobbeleer.ohmyposh -PackageFolder C:\tools\packages\ | Deploy-WtWin32App -Username [email protected]
```
[badge_license]: https://img.shields.io/github/license/svrooij/WingetIntune?style=for-the-badge
[link_license]: https://github.com/svrooij/WingetIntune/blob/main/LICENSE.txt
[badge_powershell]: https://img.shields.io/powershellgallery/v/WinTuner?style=for-the-badge&logo=powershell&logoColor=white
[badge_powershell_downloads]: https://img.shields.io/powershellgallery/dt/WinTuner?style=for-the-badge&logo=powershell&logoColor=white
[link_powershell]: https://www.powershellgallery.com/packages/WinTuner/
108 changes: 101 additions & 7 deletions src/WingetIntune.Cli/Commands/GenerateIndexCommand.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Hosting;
using System.CommandLine.Invocation;
using System.CommandLine.NamingConventionBinder;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using WingetIntune.Cli.Configuration;

namespace WingetIntune.Commands;
Expand All @@ -20,9 +16,19 @@ internal class GenerateIndexCommand : Command
public GenerateIndexCommand() : base(name, description)
{
IsHidden = true;
AddOption(new Option<string>(new string[] { "--output-path", "-o" }, "The path to the output file") { IsRequired = true });
AddOption(new Option<Uri>(new string[] { "--source-uri", "-s" }, () => new Uri(Winget.CommunityRepository.WingetRepository.DefaultIndexUri), "The source URI to use for the index.json file"));
AddOption(new Option<int>(new string[] { "--timeout", "-t" }, () => 600000, "The timeout for the operation in milliseconds"));
AddOption(new Option<string>(["--output-path", "-o"], "The path to the output file") { IsRequired = true });
AddOption(new Option<Uri>(["--source-uri", "-s"], () => new Uri(Winget.CommunityRepository.WingetRepository.DefaultIndexUri), "The source URI to use for the index.json file"));
AddOption(new Option<int>(["--timeout", "-t"], () => 600000, "The timeout for the operation in milliseconds"));
AddOption(new Option<string>(["--update-json"], "Create JSON file with only the updates") { IsHidden = true });
AddOption(new Option<string>(["--update-csv"], "Create CSV file with only the updates") { IsHidden = true });
AddOption(new Option<bool>(["--update-github"], "Create GitHub Action step summary") { IsHidden = true });
AddOption(new Option<Uri?>(["--update-uri"], () =>
{
var uri = Environment.GetEnvironmentVariable("UPDATE_URI");
return string.IsNullOrEmpty(uri) ? null : new Uri(uri);
}, "Post updates to this url")
{ IsHidden = true });

this.Handler = CommandHandler.Create<GenerateIndexCommandOptions, InvocationContext>(HandleCommand);
}

Expand All @@ -39,16 +45,104 @@ private async Task<int> HandleCommand(GenerateIndexCommandOptions options, Invoc
var repo = host.Services.GetRequiredService<Winget.CommunityRepository.WingetRepository>();
repo.UseRespository = true;
var packages = await repo.RefreshPackages(false, combinedCancellation.Token);
if (File.Exists(options.OutputPath) && options.DetectChanges)
{
await HandleChanges(logger, options, packages, combinedCancellation.Token);
}
var json = JsonSerializer.Serialize(packages);
await File.WriteAllTextAsync(Path.GetFullPath(options.OutputPath), json, combinedCancellation.Token);
logger.LogInformation("Generated index.json file at {outputPath}", options.OutputPath);
return 0;
}

private static async Task HandleChanges(ILogger logger, GenerateIndexCommandOptions options, IEnumerable<Winget.CommunityRepository.Models.WingetEntry> packages, CancellationToken cancellationToken)
{
logger.LogInformation("Detecting changes from existing index.json file at {outputPath}", options.OutputPath);
var existingJson = await File.ReadAllTextAsync(Path.GetFullPath(options.OutputPath), cancellationToken);
var existingPackages = JsonSerializer.Deserialize<IEnumerable<Winget.CommunityRepository.Models.WingetEntry>>(existingJson);
if (existingPackages is not null)
{
var updates = packages
.Where(p => !existingPackages.Any(ep => ep.PackageId == p.PackageId && ep.Version == p.Version))
.OrderBy(p => p.PackageId);
if (updates.Any())
{
var lastWriteTime = File.GetLastWriteTimeUtc(Path.GetFullPath(options.OutputPath));
logger.LogInformation("Detected {count} updates since {lastWriteTime:yyyy-MM-dd HH:mm} UTC", updates.Count(), lastWriteTime);
if (!string.IsNullOrEmpty(options.UpdateJson))
{
var updatesJson = JsonSerializer.Serialize(updates);
await File.WriteAllTextAsync(Path.GetFullPath(options.UpdateJson), updatesJson, cancellationToken);
logger.LogInformation("Generated updates.json file at {outputPath}", options.UpdateJson);
}

if (!string.IsNullOrEmpty(options.UpdateCsv))
{
var csv = new StringBuilder();
csv.AppendLine("\"PackageId\",\"Version\"");
foreach (var update in updates)
{
csv.AppendLine($"\"{update.PackageId}\",\"{update.Version}\"");
}
await File.WriteAllTextAsync(Path.GetFullPath(options.UpdateCsv), csv.ToString(), cancellationToken);
logger.LogInformation("Generated updates.csv file at {outputPath}", options.UpdateCsv);
}

if (options.UpdateGithub == true)
{
// Write markdown table with update summary to environment variable GITHUB_STEP_SUMMARY
// get last file write date from the existing file

var markdown = new StringBuilder();
markdown.AppendLine($"Detected **{updates.Count()}** updates since `{lastWriteTime:yyyy-MM-dd HH:mm:ss} UTC`");
markdown.AppendLine("");
markdown.AppendLine("| PackageId | Version |");
markdown.AppendLine("| --- | --- |");
foreach (var update in updates)
{
markdown.AppendLine($"| {update.PackageId} | {update.Version} |");
}
Environment.SetEnvironmentVariable("GITHUB_STEP_SUMMARY", markdown.ToString(), EnvironmentVariableTarget.Process);
logger.LogInformation("Generated GitHub Action step summary");
}

if (options.UpdateUri is not null && options.UpdateUri.IsAbsoluteUri)
{
await PostUpdatesToUri(logger, options.UpdateUri, updates, cancellationToken);
}
}
else
{
logger.LogInformation("No updates detected");
}
}
}

private static async Task PostUpdatesToUri(ILogger logger, Uri uri, IEnumerable<Winget.CommunityRepository.Models.WingetEntry> updates, CancellationToken cancellationToken)
{
try
{
var json = JsonSerializer.Serialize(updates);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var client = new HttpClient();
await client.PostAsync(uri, content, cancellationToken);
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to post updates to {host}", uri.Host);
}
}

internal class GenerateIndexCommandOptions
{
public int Timeout { get; set; }
public string OutputPath { get; set; }
public Uri? SourceUri { get; set; }
public string? UpdateCsv { get; set; }
public string? UpdateJson { get; set; }
public bool? UpdateGithub { get; set; }
public Uri? UpdateUri { get; set; }

internal bool DetectChanges => !string.IsNullOrEmpty(UpdateJson) || !string.IsNullOrEmpty(UpdateCsv) || UpdateUri?.IsAbsoluteUri == true || UpdateGithub == true;
}
}
Binary file added static/img/wintuner-mascotte-two_100.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit fa54cb6

Please sign in to comment.