diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBot.sln b/tools/CreateRuleFabricBot/CreateRuleFabricBot.sln deleted file mode 100644 index 0207d915c3f..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBot.sln +++ /dev/null @@ -1,42 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.33103.201 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CreateRuleFabricBot", "CreateRuleFabricBot\CreateRuleFabricBot.csproj", "{6D171EBE-B5D6-4709-9CC4-D408DBB67943}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CreateRuleFabricBotTests", "CreateRuleFabricBotTests\CreateRuleFabricBotTests.csproj", "{7A9CB777-6429-4E5C-831B-666880169CC5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Sdk.Tools.CodeOwnersParser", "..\code-owners-parser\CodeOwnersParser\Azure.Sdk.Tools.CodeOwnersParser.csproj", "{0B7CF835-6B93-42A6-8833-75771B923DB6}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0A6BCF82-8E13-49CF-B951-945DC742C291}" - ProjectSection(SolutionItems) = preProject - ci.yml = ci.yml - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6D171EBE-B5D6-4709-9CC4-D408DBB67943}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6D171EBE-B5D6-4709-9CC4-D408DBB67943}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6D171EBE-B5D6-4709-9CC4-D408DBB67943}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6D171EBE-B5D6-4709-9CC4-D408DBB67943}.Release|Any CPU.Build.0 = Release|Any CPU - {7A9CB777-6429-4E5C-831B-666880169CC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7A9CB777-6429-4E5C-831B-666880169CC5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7A9CB777-6429-4E5C-831B-666880169CC5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7A9CB777-6429-4E5C-831B-666880169CC5}.Release|Any CPU.Build.0 = Release|Any CPU - {0B7CF835-6B93-42A6-8833-75771B923DB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0B7CF835-6B93-42A6-8833-75771B923DB6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0B7CF835-6B93-42A6-8833-75771B923DB6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0B7CF835-6B93-42A6-8833-75771B923DB6}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {67E39242-0381-4B87-BD82-483C04F901BF} - EndGlobalSection -EndGlobal diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBot/CommandLine/ActionToTake.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBot/CommandLine/ActionToTake.cs deleted file mode 100644 index 934c05d9c2d..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBot/CommandLine/ActionToTake.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace CreateRuleFabricBot.CommandLine -{ - public enum ActionToTake - { - create, - update, - delete, - deleteall, - listTaskIds - } -} diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBot/CommandLine/ActionType.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBot/CommandLine/ActionType.cs deleted file mode 100644 index 66a300245de..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBot/CommandLine/ActionType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace CreateRuleFabricBot.CommandLine -{ - public enum TaskType - { - IssueRouting, - PullRequestLabel - } -} diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBot/CommandLine/Options.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBot/CommandLine/Options.cs deleted file mode 100644 index bee07ad7437..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBot/CommandLine/Options.cs +++ /dev/null @@ -1,41 +0,0 @@ -using CommandLine.Attributes; -using CommandLine.Attributes.Advanced; - -namespace CreateRuleFabricBot.CommandLine -{ - public class CommandLineArgs - { - [ActionArgument] - public ActionToTake Action { get; set; } - - [CommonArgument] - [RequiredArgument(0, "org", "The org the repo is in")] - public string Owner { get; set; } - - [CommonArgument] - [RequiredArgument(1, "repo", "The name of the repo")] - public string Repo { get; set; } - - [ArgumentGroup(nameof(ActionToTake.create))] - [ArgumentGroup(nameof(ActionToTake.update))] - [RequiredArgument(2, "taskType", "The type of the task that you want to create/update.")] - public TaskType TaskType{ get; set; } - - [ArgumentGroup(nameof(ActionToTake.create))] - [ArgumentGroup(nameof(ActionToTake.update))] - [OptionalArgument(null, "additionalData", "File with additional data. For IssueRouting: Structure for the table Labels: Column1, Handles: Column3. For PullRequestLabel: CODEOWNERS file")] - public string InputDataFile { get; set; } - - [ArgumentGroup(nameof(ActionToTake.delete))] - [RequiredArgument(2, "task", "The task id to delete.")] - public string TaskId { get; set; } - - [CommonArgument] - [OptionalArgument(null, "token", "The cookie token for authentication")] - public string CookieToken { get; set; } - - [CommonArgument] - [OptionalArgument(true, "prompt", "Don't prompt for validation")] - public bool Prompt { get; set; } - } -} diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBot/CreateRuleFabricBot.csproj b/tools/CreateRuleFabricBot/CreateRuleFabricBot/CreateRuleFabricBot.csproj deleted file mode 100644 index ed35c975596..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBot/CreateRuleFabricBot.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - Exe - net6.0 - $(NoWarn);CS8002;NU5105 - - true - dotnet-createRuleFabricBot - 1.0.0 - - - - - - - - - - - - - diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Markdown/MarkdownTable.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBot/Markdown/MarkdownTable.cs deleted file mode 100644 index 20d50681639..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Markdown/MarkdownTable.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Azure.Sdk.Tools.CodeOwnersParser; -using System; -using System.Collections.Generic; -using System.IO; - -namespace CreateRuleFabricBot.Markdown -{ - public class MarkdownTable - { - public string[] Headers { get; set; } - public List Rows { get; set; } = new List(); - - public static MarkdownTable Parse(string filePath) - { - MarkdownTable mt = new MarkdownTable(); - string line; - - using (StringReader sr = new StringReader(FileHelpers.GetFileContents(filePath))) - { - while ((line = sr.ReadLine()) != null) - { - line = line.Trim(); - - if (!line.StartsWith('|')) - { // We don't have a line that starts with | - break; - } - - string[] items = line.Split('|', StringSplitOptions.RemoveEmptyEntries); - for (int i = 0; i < items.Length; i++) - { - items[i] = items[i].Trim(); - } - - if (mt.Headers == null) - { - mt.Headers = items; - } - else - { - if (!IsOnlySeparator(items[0])) - { - mt.Rows.Add(items); - } - } - } - } - return mt; - } - - private static bool IsOnlySeparator(string s) - { - for (int i = 0; i < s.Length; i++) - { - if (s[i] != '-') - { - return false; - } - } - return true; - } - } -} diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Program.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBot/Program.cs deleted file mode 100644 index e3c6d972501..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Program.cs +++ /dev/null @@ -1,110 +0,0 @@ -using CommandLine; -using CreateRuleFabricBot.CommandLine; -using CreateRuleFabricBot.Markdown; -using CreateRuleFabricBot.Rules; -using CreateRuleFabricBot.Rules.IssueRouting; -using CreateRuleFabricBot.Rules.PullRequestLabel; -using CreateRuleFabricBot.Service; -using OutputColorizer; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace CreateRuleFabricBot -{ - internal class Program - { - private const string ParserPrefix = "officebot_"; - private static CommandLineArgs s_options; - - private static void Main(string[] args) - { - if (!Parser.TryParse(args, out s_options, new ParserOptions() { VariableNamePrefix = ParserPrefix })) - { - return; - } - - if (s_options.CookieToken == null) - { - Colorizer.WriteLine($"[Red!Error]: Please specify authentication token as an argument or in the environment variable [Yellow!{ParserPrefix}_token]"); - return; - } - - FabricBotClient rs = new FabricBotClient(s_options.Owner, s_options.Repo, s_options.CookieToken); - - string payload = string.Empty; - string taskId = string.Empty; - - // for Create and update, construct the payload and taskId - if (s_options.Action == ActionToTake.create || s_options.Action == ActionToTake.update) - { - // Instantiate the object based on the TaskType - BaseCapability capability = CreateCapabilityObject(s_options); - payload = capability.GetPayload(); - taskId = capability.GetTaskId(); - } - - if (s_options.Prompt) - { - Colorizer.Write("Proceed with [Cyan!{0}] for repo [Yellow!{1}\\{2}] (y/n)? ", s_options.Action, s_options.Owner, s_options.Repo); - var key = Console.ReadKey(); - - if (key.Key != ConsoleKey.Y) - { - Colorizer.WriteLine("No action taken."); - return; - } - Colorizer.WriteLine(""); - } - - try - { - switch (s_options.Action) - { - case ActionToTake.create: - rs.CreateTask(payload); - break; - case ActionToTake.update: - rs.UpdateTask(taskId, payload); - break; - case ActionToTake.delete: - rs.DeleteTask(s_options.TaskId); - break; - case ActionToTake.deleteall: - rs.DeleteAll(); - break; - case ActionToTake.listTaskIds: - var taskIds = rs.GetTaskIds(); - foreach (string item in taskIds) - { - Colorizer.WriteLine("Found task with id: [Yellow!{0}]", item); - } - break; - default: - Colorizer.WriteLine($"[Red!Error]: Command [Yellow!{s_options.Action}] unknown."); - return; - } - Colorizer.WriteLine("[Green!Done]."); - } - catch (Exception e) - { - Colorizer.WriteLine("[Red!Error]: {0}", e.Message); - } - } - - private static BaseCapability CreateCapabilityObject(CommandLineArgs s_options) - { - switch (s_options.TaskType) - { - case TaskType.IssueRouting: - return new IssueRoutingCapability(s_options.Owner, s_options.Repo, s_options.InputDataFile); - case TaskType.PullRequestLabel: - return new PullRequestLabelFolderCapability(s_options.Owner, s_options.Repo, s_options.InputDataFile); - } - - throw new InvalidOperationException("Unknown task type " + s_options.TaskType); - } - } -} diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/BaseCapability.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/BaseCapability.cs deleted file mode 100644 index f2e8a1384ac..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/BaseCapability.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace CreateRuleFabricBot.Rules -{ - public abstract class BaseCapability - { - protected readonly string _repo; - protected readonly string _owner; - private readonly string _configurationFile; - - public BaseCapability(string org, string repo, string configurationFile) - { - _repo = repo; - _owner = org; - _configurationFile = configurationFile; - - if (!string.IsNullOrEmpty(configurationFile)) - { - ReadConfigurationFromFile(configurationFile); - } - } - - internal abstract void ReadConfigurationFromFile(string configurationFile); - public abstract string GetPayload(); - public abstract string GetTaskId(); - } -} diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/IssueRouting/IssueRoutingCapability.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/IssueRouting/IssueRoutingCapability.cs deleted file mode 100644 index ff2789f4a17..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/IssueRouting/IssueRoutingCapability.cs +++ /dev/null @@ -1,78 +0,0 @@ -using Azure.Sdk.Tools.CodeOwnersParser; -using Newtonsoft.Json.Linq; -using OutputColorizer; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace CreateRuleFabricBot.Rules.IssueRouting -{ - public class IssueRoutingCapability : BaseCapability - { - private readonly List _triageConfig = new List(); - - private int RouteCount { get { return _triageConfig.Count; } } - - public IssueRoutingCapability(string org, string repo, string configurationFile) - : base(org, repo, configurationFile) - { - } - - public void AddRoute(IEnumerable labels, IEnumerable mentionees) - { - TriageConfig tc = new TriageConfig(); - tc.Labels.AddRange(labels); - tc.Mentionee.AddRange(mentionees); - _triageConfig.Add(tc); - } - - public override string GetPayload() - { - Colorizer.WriteLine("Found [Yellow!{0}] service routes.", RouteCount); - foreach (TriageConfig triage in _triageConfig) - { - Colorizer.WriteLine("Labels:[Yellow!{0}], Owners:[Yellow!{1}]", string.Join(',', triage.Labels), string.Join(',', triage.Mentionee)); - } - - // create the payload - JObject payload = new JObject( - new JProperty("taskType", "scheduledAndTrigger"), - new JProperty("capabilityId", "IssueRouting"), - new JProperty("version", "1.0"), - new JProperty("subCapability", "@Mention"), - new JProperty("config", - new JObject( - new JProperty("labelsAndMentions", new JArray(_triageConfig.Select(tc => tc.GetJsonPayload()))), - new JProperty("replyTemplate", "Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc ${mentionees}."), - new JProperty("taskName", "Triage issues to the service team") - ) - ), - new JProperty("id", new JValue(GetTaskId()))); - - return payload.ToString(); - } - - public override string GetTaskId() - { - return $"AzureSDKTriage_{_owner}_{_repo}"; - } - - internal override void ReadConfigurationFromFile(string configurationFile) - { - List entries = CodeOwnersFile.ParseFile(configurationFile); - - foreach (CodeOwnerEntry entry in entries) - { - // If we have labels for the specific codeowners entry, add that to the triage list - if (entry.ServiceLabels.Any()) - { - // Remove the '@' from the owners handle - IEnumerable mentionees = entry.Owners.Select(x => x.Replace("@", "").Trim()); - - //add the service - AddRoute(entry.ServiceLabels, mentionees); - } - } - } - } -} diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/IssueRouting/TriageConfig.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/IssueRouting/TriageConfig.cs deleted file mode 100644 index 31013afe064..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/IssueRouting/TriageConfig.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Newtonsoft.Json.Linq; -using System.Collections.Generic; -using System.Linq; - -namespace CreateRuleFabricBot.Rules.IssueRouting -{ - public class TriageConfig - { - public List Labels { get; } = new List(); - public List Mentionee { get; } = new List(); - - public override string ToString() - { - var array = Labels.Select(label => new JValue(label)).ToArray(); - var arr = new JArray(array); - - return GetJsonPayload().ToString(); - } - - public JObject GetJsonPayload() - { - return new JObject( - new JProperty("labels", - new JArray(Labels.Select(label => new JValue(label)).ToArray())), - new JProperty("mentionees", - new JArray(Mentionee.Select(ment => new JValue(ment)).ToArray()))); - } - } -} diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/PullRequestLabel/PathConfig.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/PullRequestLabel/PathConfig.cs deleted file mode 100644 index 30708bdf826..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/PullRequestLabel/PathConfig.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Newtonsoft.Json.Linq; -using System.Collections.Generic; -using System.IO; -using System.Text.Json; - -namespace CreateRuleFabricBot.Rules.PullRequestLabel -{ - public class PathConfig - { - public PathConfig(string pathExpression, string label) - { - // at this point we should remove the leading '/' if any - if (pathExpression.StartsWith("/")) - { - pathExpression = pathExpression.Substring(1); - } - - Path = pathExpression; - Label = label; - } - - public string Label { get; set; } = ""; - public string Path { get; set; } = ""; - - public override string ToString() - { - return GetJsonPayload().ToString(); - } - - public JObject GetJsonPayload() - { - return new JObject( - new JProperty("label", new JValue(Label)), - new JProperty("pathFilter", new JArray(new JValue(Path))), - new JProperty("exclude", new JArray(new JValue("")))); - // Note: By using an empty string in the exclude property above, - // the rule we create will allow multiple labels (from different folders) to be applied to the same PR. - } - } -} diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/PullRequestLabel/PullRequestLabelFolderCapability.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/PullRequestLabel/PullRequestLabelFolderCapability.cs deleted file mode 100644 index 4b0d912943a..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Rules/PullRequestLabel/PullRequestLabelFolderCapability.cs +++ /dev/null @@ -1,106 +0,0 @@ -using Azure.Sdk.Tools.CodeOwnersParser; -using Newtonsoft.Json.Linq; -using OutputColorizer; -using System; -using System.Collections.Generic; -using System.Data; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Text; -using System.Text.Encodings.Web; - -namespace CreateRuleFabricBot.Rules.PullRequestLabel -{ - public class PullRequestLabelFolderCapability : BaseCapability - { - private List _entriesToCreate = new List(); - - public PullRequestLabelFolderCapability(string org, string name, string configurationFile) - : base(org, name, configurationFile) - { - } - - public override string GetPayload() - { - // Display the payload on the screen - foreach (var entry in _entriesToCreate) - { - Colorizer.WriteLine("[Cyan!{0}] => [Magenta!{1}]", entry.Path, entry.Label); - } - - // create the payload from the template - JObject payload = new JObject( - new JProperty("taskType", "trigger"), - new JProperty("capabilityId", "PrAutoLabel"), - new JProperty("subCapability", "Path"), - new JProperty("version", "1.0"), - new JProperty("id", new JValue(GetTaskId())), - new JProperty("config", - new JObject( - new JProperty("configs",new JArray(_entriesToCreate.Select(tc => tc.GetJsonPayload()))), - new JProperty("taskName", "Auto PR based on folder paths ") - ) - )); - - return payload.ToString(); - } - - /// - /// Add an entry for a folder with a specified label - /// - public void AddEntry(string pathExpression, string label) - { - _entriesToCreate.Add(new PathConfig(pathExpression, label)); - } - - internal override void ReadConfigurationFromFile(string configurationFile) - { - List entries = CodeOwnersFile.ParseFile(configurationFile); - - // Filter our the list of entries that we want to create. - for (int i = 0; i < entries.Count; i++) - { - // Entries with wildcards are not yet supported - if (entries[i].ContainsWildcard) - { - // log a warning there - - if (entries[i].PRLabels.Any()) - { - Colorizer.WriteLine("[Yellow!Warning]: The path '[Cyan!{0}]' contains a wildcard and a label '[Magenta!{1}]' which is not supported!", entries[i].PathExpression, string.Join(',', entries[i].PRLabels)); - } - - continue; //TODO: regex expressions are not yet supported - } - - if (entries[i].PathExpression.IndexOf(CodeOwnerEntry.MissingFolder, StringComparison.OrdinalIgnoreCase) != -1) - { - Colorizer.WriteLine("[Yellow!Warning]: The path '[Cyan!{0}]' is marked with the non-existing path marker.", entries[i].PathExpression); - - continue; - } - - // Entries with more than one label are not yet supported. - if (entries[i].PRLabels.Count > 1) - { - Colorizer.WriteLine("[Yellow!Warning]: Multiple labels for the same path '[Cyan!{0}]' are not yet supported", entries[i].PathExpression); - continue; - } - - if (entries[i].PRLabels.Count == 0) - { - Colorizer.WriteLine("[Yellow!Warning]: The path '[Cyan!{0}]' does not contain a label.", entries[i].PathExpression, string.Join(',', entries[i].PRLabels)); - continue; - } - - AddEntry(entries[i].PathExpression, entries[i].PRLabels.First()); - } - } - - public override string GetTaskId() - { - return $"AzureSDKPullRequestLabelFolder_{_repo}_{_owner}"; - } - } -} diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Service/RequestSender.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBot/Service/RequestSender.cs deleted file mode 100644 index c8512f7c9eb..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBot/Service/RequestSender.cs +++ /dev/null @@ -1,153 +0,0 @@ -using OutputColorizer; -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -namespace CreateRuleFabricBot.Service -{ - public class FabricBotClient - { - private readonly string _authHeaderValue; - private readonly string _owner; - private readonly string _repo; - - public FabricBotClient(string owner, string repo, string authToken) - { - _owner = owner; - _repo = repo; - _authHeaderValue = authToken; - } - - public void CreateTask(string jsonPayload) - { - string requestUri = $"https://portal.fabricbot.ms/api/bot/task/{_owner}/{_repo}"; - var response = SendRequestAsync(HttpMethod.Post, requestUri, CreateContent(jsonPayload)).GetAwaiter().GetResult(); - } - - public void UpdateTask(string taskId, string jsonPayload) - { - string requestUri = $"https://portal.fabricbot.ms/api/bot/task/{_owner}/{_repo}/{taskId}"; - - var response = SendRequestAsync(new HttpMethod("PATCH"), requestUri, CreateContent(jsonPayload)).GetAwaiter().GetResult(); - } - - public void DeleteAll() - { - Colorizer.Write("Retrieving list of taskIds for [Yellow!{0}]...", $"{_owner}\\{_repo}"); - List taskIds = GetTaskIds(); - Colorizer.WriteLine("[Green!done]."); - - //start deleting - foreach (string taskId in taskIds) - { - int retryCount = 0; - retry: - Colorizer.WriteLine("Deleting task [Yellow!{0}]...", taskId); - try - { - DeleteTask(taskId); - Colorizer.WriteLine("[Green!done]."); - } - catch - { - retryCount++; - Colorizer.WriteLine("[Red!failed]. Retrying..."); - Thread.Sleep(2000); // wait 2 seconds for the server - if (retryCount > 3) - { - Colorizer.WriteLine("[DarkYellow!Skipping task] [Yellow!{0}]", taskId); - } - else - { - goto retry; - } - } - } - } - - public void DeleteTask(string taskId) - { - string requestUri = $"https://portal.fabricbot.ms/api/bot/task/{_owner}/{_repo}/{taskId}"; - - var response = SendRequestAsync(HttpMethod.Delete, requestUri).GetAwaiter().GetResult(); - response.EnsureSuccessStatusCode(); - } - - public List GetTaskIds() - { - string requestUri = $"https://portal.fabricbot.ms/api/bot/getBotConfig?githubKey={_owner}/{_repo}"; - List elements = new List(); - var response = SendRequestAsync(HttpMethod.Get, requestUri).GetAwaiter().GetResult(); - - // retrieve the information from the response. - var configJson = JsonDocument.Parse(response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult()); - // get the config - var configArray = configJson.RootElement.GetProperty("config"); - foreach (JsonElement item in configArray.EnumerateArray()) - { - JsonElement property = item.GetProperty("id"); - elements.Add(property.GetString()); - } - - return elements; - } - - private HttpContent CreateContent(string jsonPayload) - { - StringContent sc = new StringContent(jsonPayload, Encoding.UTF8, "application/json"); - return sc; - } - - private async Task SendRequestAsync(HttpMethod method, string uri, HttpContent content = null) - { - Cookie authCookie = new Cookie("AppServiceAuthSession", _authHeaderValue, "/", "portal.fabricbot.ms") - { - HttpOnly = true, - Secure = true - }; - - HttpResponseMessage response = null; - CookieContainer cookies = new CookieContainer(); - using (HttpClientHandler handler = new HttpClientHandler() { CookieContainer = cookies }) - using (HttpClient client = new HttpClient(handler)) - { - cookies.Add(authCookie); - - switch (method.Method.ToUpperInvariant()) - { - case "DELETE": - response = await client.DeleteAsync(uri); - break; - case "POST": - response = await client.PostAsync(uri, content); - break; - case "PATCH": - response = await client.SendAsync(new HttpRequestMessage - { - Method = new HttpMethod("PATCH"), - RequestUri = new Uri(uri), - Content = content - }); - break; - case "GET": - response = await client.GetAsync(uri); - break; - default: - throw new NotSupportedException($"{method.Method} not supported"); - } - - if (response != null) - { - response.EnsureSuccessStatusCode(); - } - } - return response; - } - } -} - diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/CodeOwnerTests.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/CodeOwnerTests.cs deleted file mode 100644 index c658fa216e3..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/CodeOwnerTests.cs +++ /dev/null @@ -1,140 +0,0 @@ -using Azure.Sdk.Tools.CodeOwnersParser; -using CreateRuleFabricBot; -using CreateRuleFabricBot.Rules.PullRequestLabel; -using CreateRuleFabricBotTests; -using NUnit.Framework; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; - -namespace Tests -{ - public class CodeOwnerTests - { - [DatapointSource] - public TestAndExpected[] Expectations = new TestAndExpected[] - { - new TestAndExpected("/test @author", "# PRLabel: %label", "/test", new []{ "author"}, new[]{"label" }), - new TestAndExpected("/test @author1 @author2", "# PRLabel: %label", "/test", new []{ "author1", "author2"}, new[]{"label" }), - new TestAndExpected("/test @author", "# PRLabel: %label1 %label2", "/test", new []{ "author"}, new[]{"label1", "label2" }), - // no labels - new TestAndExpected("/test @author", "", "/test", new []{ "author"}, new string[]{ }), - - // Different casing for PRLabel marker - new TestAndExpected("/test @author1 @author2", "# prlabeL : %label", "/test", new []{ "author1", "author2"}, new[]{"label" }), - - // >>>> malformed lines <<<< - // no colon after PRLabel - new TestAndExpected("/test @author", "# PRLabel %label1 %label2", "/test", new []{ "author"}, new string[]{ }), - // no PRLabel marker - new TestAndExpected("/test @author", "# : %label1 %label2", "/test", new []{ "author"}, new string[]{ }), - // Empty label name - new TestAndExpected("/test @author", "#PRLabel : % %label1 %label2", "/test", new []{ "author"}, new string[]{ "label1", "label2" }), - // Empty author name - new TestAndExpected("/test @ @author", "#PRLabel : % %label1 %label2", "/test", new []{ "author"}, new string[]{ "label1", "label2" }) - }; - - - [Theory] - public void ValidateOwnersLines(TestAndExpected entry) - { - // create the content - string content = $"{entry.LabelsLine}\r\n{entry.PathAndOwners}"; - - CodeOwnerEntry coe = CodeOwnersFile.ParseContent(content).First(); - Assert.AreEqual(entry.ExpectedLabels, coe.PRLabels); - Assert.AreEqual(entry.ExpectedOwners, coe.Owners); - Assert.AreEqual(entry.ExpectedPath, coe.PathExpression); - } - - [Test] - public void ParseInvalidEntry() - { - // no path and owners - var entry = new TestAndExpected("", "# PRLabel: %label1 %label2", string.Empty, new string[] { }, new string[] { "label1", "label2" }); - - // create the content - string content = $"{entry.LabelsLine}\r\n{entry.PathAndOwners}"; - - CodeOwnerEntry coe = CodeOwnersFile.ParseContent(content).FirstOrDefault(); - - Assert.IsNull(coe); - } - - [Test] - public void ValidateCodeOwnersContent() - { - string content = @"#Comment - - -# ServiceLabel: %F1 %Service Attention -# PRLabel: %F1 -/folder1/ @user1 - -# ServiceLabel: %F2 %Service Attention -# PRLabel: %F2 -/folder2/ @user2 - -# ServiceLabel: %Service Attention %F3 -/folder3/ @user3 @user1 - -# PRLabel: %F4 %Service Attention -/folder4/ @user4 - -/folder5/ @user5 - -# ServiceLabel: %MyService -#// @user6 - - -# ServiceLabel: %MyService -# CommentedLine @user7 - - -/folder6 @user7 - - -# ServiceLabel: %MyService -/folder8 @user6 #This has comment at the end -"; - - List entries = CodeOwnersFile.ParseContent(content); - Assert.AreEqual(8, entries.Count); - - - Assert.AreEqual("F1", entries[0].PRLabels[0]); - Assert.AreEqual("F1", entries[0].ServiceLabels[0]); - Assert.AreEqual("Service Attention", entries[0].ServiceLabels[1]); - - Assert.AreEqual("F2", entries[1].PRLabels[0]); - Assert.AreEqual("F2", entries[1].ServiceLabels[0]); - Assert.AreEqual("Service Attention", entries[1].ServiceLabels[1]); - Assert.AreEqual("/folder2/", entries[1].PathExpression); - - Assert.AreEqual("Service Attention", entries[2].ServiceLabels[0]); - Assert.AreEqual(0, entries[2].PRLabels.Count); - Assert.AreEqual("F3", entries[2].ServiceLabels[1]); - - Assert.AreEqual("F4", entries[3].PRLabels[0]); - Assert.AreEqual(0, entries[3].ServiceLabels.Count); - Assert.AreEqual("Service Attention", entries[3].PRLabels[1]); - - Assert.AreEqual(0, entries[4].ServiceLabels.Count); - Assert.AreEqual(0, entries[4].PRLabels.Count); - Assert.AreEqual("/folder5/", entries[4].PathExpression); - - Assert.AreEqual(1, entries[5].ServiceLabels.Count); - Assert.AreEqual(0, entries[5].PRLabels.Count); - Assert.AreEqual("#//", entries[5].PathExpression); - - Assert.AreEqual(1, entries[6].ServiceLabels.Count); - Assert.AreEqual(0, entries[6].PRLabels.Count); - Assert.AreEqual("/folder6", entries[6].PathExpression); - - Assert.AreEqual(1, entries[7].ServiceLabels.Count); - Assert.AreEqual(0, entries[7].PRLabels.Count); - Assert.AreEqual("/folder8", entries[7].PathExpression); - Assert.AreEqual("user6", entries[7].Owners[0]); - } - } -} \ No newline at end of file diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/CreateRuleFabricBotTests.csproj b/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/CreateRuleFabricBotTests.csproj deleted file mode 100644 index 38cc813e2c2..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/CreateRuleFabricBotTests.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - net6.0 - false - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/LiveTests.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/LiveTests.cs deleted file mode 100644 index f957336f7ec..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/LiveTests.cs +++ /dev/null @@ -1,59 +0,0 @@ -using CreateRuleFabricBot.Rules.IssueRouting; -using CreateRuleFabricBot.Service; -using NUnit.Framework; -using System; -using System.Linq; -using System.Threading; - -namespace Tests -{ - public class Tests - { - private string _org = ""; - private string _repo = ""; - private FabricBotClient _requestSender; - - //[OneTimeSetUp] - public void OneTimeSetup() - { - string token = Environment.GetEnvironmentVariable("officebot_token"); - if (token == null) - { - throw new InvalidOperationException("Authentication token not found."); - } - _requestSender = new FabricBotClient(_org, _repo, token); - } - - [Test] - [Ignore("Can't run test without officebot_token")] - public void CreateUpdateDeleteRule() - { - IssueRoutingCapability irc = new IssueRoutingCapability(_org, _repo, ""); - - _requestSender.CreateTask(irc.GetPayload()); - // delay for the service to react - Thread.Sleep(3000); - - var ids = _requestSender.GetTaskIds(); - Assert.Contains(irc.GetTaskId(), ids); - // delay for the service to react - Thread.Sleep(3000); - - _requestSender.UpdateTask(irc.GetTaskId(), irc.GetPayload()); - // delay for the service to react - Thread.Sleep(3000); - - ids = _requestSender.GetTaskIds(); - Assert.Contains(irc.GetTaskId(), ids); - // delay for the service to react - Thread.Sleep(3000); - - _requestSender.DeleteTask(irc.GetTaskId()); - // delay for the service to react - Thread.Sleep(3000); - - ids = _requestSender.GetTaskIds(); - Assert.False(ids.Any(x => x == irc.GetTaskId())); - } - } -} \ No newline at end of file diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/PayloadTests.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/PayloadTests.cs deleted file mode 100644 index fc59f415e05..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/PayloadTests.cs +++ /dev/null @@ -1,108 +0,0 @@ -using CreateRuleFabricBot; -using CreateRuleFabricBot.Rules.IssueRouting; -using CreateRuleFabricBot.Rules.PullRequestLabel; -using CreateRuleFabricBot.Service; -using CreateRuleFabricBotTests; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using NUnit.Framework; -using NUnit.Framework.Constraints; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.Json; -using System.Threading; - -namespace Tests -{ - public class PayloadTests - { - [Test] - public void ValidateIssueRouting() - { - IssueRoutingCapability irc = new IssueRoutingCapability("test", "repo", null); - irc.AddRoute(new string[] { "label1", "label2" }, new string[] { "user1", "user2" }); - - string expectedPayload = @" -{ - ""taskType"" : ""scheduledAndTrigger"", - ""capabilityId"" : ""IssueRouting"", - ""version"" : ""1.0"", - ""subCapability"": ""@Mention"", - ""config"": { - ""labelsAndMentions"": [ - { ""labels"": [ ""label1"",""label2"" ], ""mentionees"": [ ""user1"",""user2"" ] } - ], - ""replyTemplate"": ""Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc ${mentionees}."", - ""taskName"" :""Triage issues to the service team"" - }, - ""id"": ""AzureSDKTriage_test_repo"" -}"; - - AreJsonEquivalent(expectedPayload, irc.GetPayload()); - } - - - [Test] - public void ValidatePullRequestRouting() - { - PullRequestLabelFolderCapability plfc = new PullRequestLabelFolderCapability("test", "repo", null); - plfc.AddEntry("/test", "Label1"); - - string expectedPayload = @" -{ - ""taskType"": ""trigger"", - ""capabilityId"": ""PrAutoLabel"", - ""subCapability"": ""Path"", - ""version"": ""1.0"", - ""id"": ""AzureSDKPullRequestLabelFolder_repo_test"", - ""config"": { - ""configs"": [ - { ""label"": ""Label1"", ""pathFilter"": [""test""], ""exclude"": [ """" ] } - ], - ""taskName"" :""Auto PR based on folder paths "" - } - } -"; - - AreJsonEquivalent(expectedPayload, plfc.GetPayload()); - } - - [Test] - public void ValidatePathConfigPayload() - { - PathConfig pc = new PathConfig("folder", "path"); - - string expectedPayload = @"{ - ""label"": ""path"", - ""pathFilter"": [ ""folder"" ], ""exclude"": [ """" ] -}"; - - AreJsonEquivalent(expectedPayload, pc.ToString()); - } - - [Test] - public void ValidateTriageConfigPayload() - { - TriageConfig tc = new TriageConfig(); - tc.Labels.Add("Label1"); - tc.Labels.Add("Label2"); - tc.Mentionee.Add("User1"); - tc.Mentionee.Add("User2"); - - string expectedPayload = @"{ - ""labels"": [ ""Label1"",""Label2"" ], - ""mentionees"": [ ""User1"",""User2"" ]}"; - - AreJsonEquivalent(expectedPayload, tc.ToString()); - } - - private void AreJsonEquivalent(string expected, string actual) - { - expected = JObject.Parse(expected).ToString(Formatting.Indented); - actual = JObject.Parse(actual).ToString(Formatting.Indented); - - Assert.AreEqual(expected, actual); - } - } -} \ No newline at end of file diff --git a/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/TestAndExpected.cs b/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/TestAndExpected.cs deleted file mode 100644 index 2dd8c151503..00000000000 --- a/tools/CreateRuleFabricBot/CreateRuleFabricBotTests/TestAndExpected.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace CreateRuleFabricBotTests -{ - public class TestAndExpected - { - public TestAndExpected(string pathAndOwnersLine, string labelsLine, string expectedPath, string[] expectedOwners, string[] expectedLabels) - { - PathAndOwners = pathAndOwnersLine; - LabelsLine = labelsLine; - - ExpectedLabels = expectedLabels; - ExpectedOwners = expectedOwners; - ExpectedPath = expectedPath; - } - - public string LabelsLine { get; set; } - - public string PathAndOwners { get; set; } - - public string[] ExpectedLabels { get; set; } - - public string[] ExpectedOwners { get; set; } - - public string ExpectedPath { get; set; } - } -} diff --git a/tools/CreateRuleFabricBot/README.md b/tools/CreateRuleFabricBot/README.md deleted file mode 100644 index 3b5e4cdb07b..00000000000 --- a/tools/CreateRuleFabricBot/README.md +++ /dev/null @@ -1,39 +0,0 @@ -This tool allows the creation and management of the fabric bot tool. - -### How to use - - Usage: - CreateRuleFabricBot.exe create org repo taskType [-additionalData value] [-token value] [-prompt value] - - org : The org the repo is in (string, required) - - repo : The name of the repo (string, required) - - taskType : The type of the task that you want to create/update. (one of IssueRouting,PullRequestLabel, required) - - additionalData : File with additional data. For IssueRouting: Structure for the table Labels: Column1, Handles: Column3. For PullRequestLabel: CODEOWNERS file (string, default=) - - token : The cookie token for authentication (string, default=) - - prompt : Don't prompt for validation (true or false, default=True) - - CreateRuleFabricBot.exe update org repo taskType [-additionalData value] [-token value] [-prompt value] - - org : The org the repo is in (string, required) - - repo : The name of the repo (string, required) - - taskType : The type of the task that you want to create/update. (one of IssueRouting,PullRequestLabel, required) - - additionalData : File with additional data. For IssueRouting: Structure for the table Labels: Column1, Handles: Column3. For PullRequestLabel: CODEOWNERS file (string, default=) - - token : The cookie token for authentication (string, default=) - - prompt : Don't prompt for validation (true or false, default=True) - - CreateRuleFabricBot.exe delete org repo task [-token value] [-prompt value] - - org : The org the repo is in (string, required) - - repo : The name of the repo (string, required) - - task : The task id to delete. (string, required) - - token : The cookie token for authentication (string, default=) - - prompt : Don't prompt for validation (true or false, default=True) - - CreateRuleFabricBot.exe deleteall org repo [-token value] [-prompt value] - - org : The org the repo is in (string, required) - - repo : The name of the repo (string, required) - - token : The cookie token for authentication (string, default=) - - prompt : Don't prompt for validation (true or false, default=True) - - CreateRuleFabricBot.exe listTaskIds org repo [-token value] [-prompt value] - - org : The org the repo is in (string, required) - - repo : The name of the repo (string, required) - - token : The cookie token for authentication (string, default=) - - prompt : Don't prompt for validation (true or false, default=True) diff --git a/tools/CreateRuleFabricBot/ci.yml b/tools/CreateRuleFabricBot/ci.yml deleted file mode 100644 index cfdb3f9dbea..00000000000 --- a/tools/CreateRuleFabricBot/ci.yml +++ /dev/null @@ -1,27 +0,0 @@ -# NOTE: Please refer to https://aka.ms/azsdk/engsys/ci-yaml before editing this file. -trigger: - branches: - include: - - main - - feature/* - - release/* - - hotfix/* - paths: - include: - - tools/CreateRuleFabricBot - -pr: - branches: - include: - - main - - feature/* - - release/* - - hotfix/* - paths: - include: - - tools/CreateRuleFabricBot - -extends: - template: /eng/pipelines/templates/stages/archetype-sdk-tool-dotnet.yml - parameters: - ToolDirectory: tools/CreateRuleFabricBot