Skip to content

Commit c07b90a

Browse files
Adds support for showing in-product announcements (#895)
1 parent 7910f51 commit c07b90a

File tree

2 files changed

+149
-116
lines changed

2 files changed

+149
-116
lines changed

dev-proxy/Announcement.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
namespace Microsoft.DevProxy;
5+
6+
static class Announcement
7+
{
8+
private static readonly string announcementUrl = "https://aka.ms/devproxy/announcement";
9+
10+
public static async Task ShowAsync()
11+
{
12+
var announcement = await GetAsync();
13+
if (!string.IsNullOrEmpty(announcement))
14+
{
15+
await Console.Error.WriteLineAsync(announcement);
16+
}
17+
}
18+
19+
public static async Task<string?> GetAsync()
20+
{
21+
try
22+
{
23+
using var client = new HttpClient();
24+
return await client.GetStringAsync(announcementUrl);
25+
}
26+
catch
27+
{
28+
return null;
29+
}
30+
}
31+
}

dev-proxy/Program.cs

Lines changed: 118 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,118 @@
1-
// Copyright (c) Microsoft Corporation.
2-
// Licensed under the MIT License.
3-
4-
using Microsoft.DevProxy;
5-
using Microsoft.DevProxy.Abstractions;
6-
using Microsoft.DevProxy.Abstractions.LanguageModel;
7-
using Microsoft.DevProxy.CommandHandlers;
8-
using Microsoft.DevProxy.Logging;
9-
using Microsoft.Extensions.Logging.Console;
10-
using System.CommandLine;
11-
12-
PluginEvents pluginEvents = new();
13-
14-
ILogger BuildLogger()
15-
{
16-
var loggerFactory = LoggerFactory.Create(builder =>
17-
{
18-
builder
19-
.AddConsole(options =>
20-
{
21-
options.FormatterName = "devproxy";
22-
options.LogToStandardErrorThreshold = LogLevel.Warning;
23-
})
24-
.AddConsoleFormatter<ProxyConsoleFormatter, ConsoleFormatterOptions>(options => {
25-
options.IncludeScopes = true;
26-
})
27-
.AddRequestLogger(pluginEvents)
28-
.SetMinimumLevel(ProxyHost.LogLevel ?? ProxyCommandHandler.Configuration.LogLevel);
29-
});
30-
return loggerFactory.CreateLogger("devproxy");
31-
}
32-
33-
var logger = BuildLogger();
34-
35-
var lmClient = new OllamaLanguageModelClient(ProxyCommandHandler.Configuration.LanguageModel, logger);
36-
IProxyContext context = new ProxyContext(ProxyCommandHandler.Configuration, ProxyEngine.Certificate, lmClient);
37-
ProxyHost proxyHost = new();
38-
39-
// this is where the root command is created which contains all commands and subcommands
40-
RootCommand rootCommand = proxyHost.GetRootCommand(logger);
41-
42-
// store the global options that are created automatically for us
43-
// rootCommand doesn't return the global options, so we have to store them manually
44-
string[] globalOptions = ["--version", "--help", "-h", "/h", "-?", "/?"];
45-
46-
// check if any of the global options are present
47-
var hasGlobalOption = args.Any(arg => globalOptions.Contains(arg));
48-
49-
// get the list of available subcommands
50-
var subCommands = rootCommand.Children.OfType<Command>().Select(c => c.Name).ToArray();
51-
52-
// check if any of the subcommands are present
53-
var hasSubCommand = args.Any(arg => subCommands.Contains(arg));
54-
55-
if (hasGlobalOption || hasSubCommand)
56-
{
57-
// we don't need to load plugins if the user is using a global option or using a subcommand, so we can exit early
58-
await rootCommand.InvokeAsync(args);
59-
return;
60-
}
61-
62-
var pluginLoader = new PluginLoader(logger);
63-
PluginLoaderResult loaderResults = await pluginLoader.LoadPluginsAsync(pluginEvents, context);
64-
// have all the plugins init
65-
pluginEvents.RaiseInit(new InitArgs());
66-
67-
var options = loaderResults.ProxyPlugins
68-
.SelectMany(p => p.GetOptions())
69-
// remove duplicates by comparing the option names
70-
.GroupBy(o => o.Name)
71-
.Select(g => g.First())
72-
.ToList();
73-
options.ForEach(rootCommand.AddOption);
74-
// register all plugin commands
75-
loaderResults.ProxyPlugins
76-
.SelectMany(p => p.GetCommands())
77-
.ToList()
78-
.ForEach(rootCommand.AddCommand);
79-
80-
rootCommand.Handler = proxyHost.GetCommandHandler(pluginEvents, [.. options], loaderResults.UrlsToWatch, logger);
81-
82-
// filter args to retrieve options
83-
var incomingOptions = args.Where(arg => arg.StartsWith('-')).ToArray();
84-
85-
// remove the global options from the incoming options
86-
incomingOptions = incomingOptions.Except(globalOptions).ToArray();
87-
88-
// compare the incoming options against the root command options
89-
foreach (var option in rootCommand.Options)
90-
{
91-
// get the option aliases
92-
var aliases = option.Aliases.ToArray();
93-
94-
// iterate over aliases
95-
foreach (string alias in aliases)
96-
{
97-
// if the alias is present
98-
if (incomingOptions.Contains(alias))
99-
{
100-
// remove the option from the incoming options
101-
incomingOptions = incomingOptions.Where(val => val != alias).ToArray();
102-
}
103-
}
104-
}
105-
106-
// list the remaining incoming options as unknown in the output
107-
if (incomingOptions.Length > 0)
108-
{
109-
logger.LogError("Unknown option(s): {unknownOptions}", string.Join(" ", incomingOptions));
110-
logger.LogInformation("TIP: Use --help view available options");
111-
logger.LogInformation("TIP: Are you missing a plugin? See: https://aka.ms/devproxy/plugins");
112-
}
113-
else
114-
{
115-
await rootCommand.InvokeAsync(args);
116-
}
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.DevProxy;
5+
using Microsoft.DevProxy.Abstractions;
6+
using Microsoft.DevProxy.Abstractions.LanguageModel;
7+
using Microsoft.DevProxy.CommandHandlers;
8+
using Microsoft.DevProxy.Logging;
9+
using Microsoft.Extensions.Logging.Console;
10+
using System.CommandLine;
11+
12+
_ = Announcement.ShowAsync();
13+
14+
PluginEvents pluginEvents = new();
15+
16+
ILogger BuildLogger()
17+
{
18+
var loggerFactory = LoggerFactory.Create(builder =>
19+
{
20+
builder
21+
.AddConsole(options =>
22+
{
23+
options.FormatterName = "devproxy";
24+
options.LogToStandardErrorThreshold = LogLevel.Warning;
25+
})
26+
.AddConsoleFormatter<ProxyConsoleFormatter, ConsoleFormatterOptions>(options => {
27+
options.IncludeScopes = true;
28+
})
29+
.AddRequestLogger(pluginEvents)
30+
.SetMinimumLevel(ProxyHost.LogLevel ?? ProxyCommandHandler.Configuration.LogLevel);
31+
});
32+
return loggerFactory.CreateLogger("devproxy");
33+
}
34+
35+
var logger = BuildLogger();
36+
37+
var lmClient = new OllamaLanguageModelClient(ProxyCommandHandler.Configuration.LanguageModel, logger);
38+
IProxyContext context = new ProxyContext(ProxyCommandHandler.Configuration, ProxyEngine.Certificate, lmClient);
39+
ProxyHost proxyHost = new();
40+
41+
// this is where the root command is created which contains all commands and subcommands
42+
RootCommand rootCommand = proxyHost.GetRootCommand(logger);
43+
44+
// store the global options that are created automatically for us
45+
// rootCommand doesn't return the global options, so we have to store them manually
46+
string[] globalOptions = ["--version", "--help", "-h", "/h", "-?", "/?"];
47+
48+
// check if any of the global options are present
49+
var hasGlobalOption = args.Any(arg => globalOptions.Contains(arg));
50+
51+
// get the list of available subcommands
52+
var subCommands = rootCommand.Children.OfType<Command>().Select(c => c.Name).ToArray();
53+
54+
// check if any of the subcommands are present
55+
var hasSubCommand = args.Any(arg => subCommands.Contains(arg));
56+
57+
if (hasGlobalOption || hasSubCommand)
58+
{
59+
// we don't need to load plugins if the user is using a global option or using a subcommand, so we can exit early
60+
await rootCommand.InvokeAsync(args);
61+
return;
62+
}
63+
64+
var pluginLoader = new PluginLoader(logger);
65+
PluginLoaderResult loaderResults = await pluginLoader.LoadPluginsAsync(pluginEvents, context);
66+
// have all the plugins init
67+
pluginEvents.RaiseInit(new InitArgs());
68+
69+
var options = loaderResults.ProxyPlugins
70+
.SelectMany(p => p.GetOptions())
71+
// remove duplicates by comparing the option names
72+
.GroupBy(o => o.Name)
73+
.Select(g => g.First())
74+
.ToList();
75+
options.ForEach(rootCommand.AddOption);
76+
// register all plugin commands
77+
loaderResults.ProxyPlugins
78+
.SelectMany(p => p.GetCommands())
79+
.ToList()
80+
.ForEach(rootCommand.AddCommand);
81+
82+
rootCommand.Handler = proxyHost.GetCommandHandler(pluginEvents, [.. options], loaderResults.UrlsToWatch, logger);
83+
84+
// filter args to retrieve options
85+
var incomingOptions = args.Where(arg => arg.StartsWith('-')).ToArray();
86+
87+
// remove the global options from the incoming options
88+
incomingOptions = incomingOptions.Except(globalOptions).ToArray();
89+
90+
// compare the incoming options against the root command options
91+
foreach (var option in rootCommand.Options)
92+
{
93+
// get the option aliases
94+
var aliases = option.Aliases.ToArray();
95+
96+
// iterate over aliases
97+
foreach (string alias in aliases)
98+
{
99+
// if the alias is present
100+
if (incomingOptions.Contains(alias))
101+
{
102+
// remove the option from the incoming options
103+
incomingOptions = incomingOptions.Where(val => val != alias).ToArray();
104+
}
105+
}
106+
}
107+
108+
// list the remaining incoming options as unknown in the output
109+
if (incomingOptions.Length > 0)
110+
{
111+
logger.LogError("Unknown option(s): {unknownOptions}", string.Join(" ", incomingOptions));
112+
logger.LogInformation("TIP: Use --help view available options");
113+
logger.LogInformation("TIP: Are you missing a plugin? See: https://aka.ms/devproxy/plugins");
114+
}
115+
else
116+
{
117+
await rootCommand.InvokeAsync(args);
118+
}

0 commit comments

Comments
 (0)