public Functions(DevOpsServer server, GitHubClient gitHubClient, TriageContext context) { Server = server; GitHubClient = gitHubClient; Context = context; TriageContextUtil = new TriageContextUtil(context); }
public NewTrackingIssueModel(TriageContext triageContext, FunctionQueueUtil functionQueueUtil, IGitHubClientFactory gitHubClientFactory, ILogger <NewTrackingIssueModel> logger) { TriageContext = triageContext; TriageContextUtil = new TriageContextUtil(triageContext); GitHubClientFactory = gitHubClientFactory; FunctionQueueUtil = functionQueueUtil; Logger = logger; }
public Functions(DevOpsServer server, TriageContext context, GitHubClientFactory gitHubClientFactory) { Server = server; Context = context; TriageContextUtil = new TriageContextUtil(context); GitHubClientFactory = gitHubClientFactory; SiteLinkUtil = SiteLinkUtil.Published; HelixServer = new HelixServer(); }
public StandardTestBase(ITestOutputHelper testOutputHelper) { Connection = CreateInMemoryDatabase(); var options = new DbContextOptionsBuilder <TriageContext>() .UseSqlite(Connection) .Options; Context = new TriageContext(options); TriageContextUtil = new TriageContextUtil(Context); TestableHttpMessageHandler = new TestableHttpMessageHandler(); TestableLogger = new TestableLogger(testOutputHelper); TestableGitHubClientFactory = new TestableGitHubClientFactory(); var httpClient = new HttpClient(TestableHttpMessageHandler); Server = new DevOpsServer("random", httpClient: httpClient); HelixServer = new HelixServer(httpClient: httpClient); QueryUtil = new DotNetQueryUtil(Server); Context.Database.EnsureDeleted(); Context.Database.EnsureCreated(); }
public async Task <IActionResult> OnPost() { if (TrackingKind == TrackingKind.Unknown) { ErrorMessage = "Invalid Tracking Kind"; return(Page()); } if (string.IsNullOrEmpty(IssueTitle)) { ErrorMessage = "Need an issue title"; return(Page()); } if (IssueTitle.Length >= ModelTrackingIssue.IssueTitleLengthLimit) { ErrorMessage = $"Please limit issue title to {ModelTrackingIssue.IssueTitleLengthLimit} characters"; return(Page()); } if (string.IsNullOrEmpty(SearchText)) { ErrorMessage = "Must provide search text"; return(Page()); } ModelBuildDefinition?modelBuildDefinition = null; if (!string.IsNullOrEmpty(Definition)) { modelBuildDefinition = await TriageContextUtil.FindModelBuildDefinitionAsync(Definition); if (modelBuildDefinition is null) { ErrorMessage = $"Cannot find build definition with name or ID: {Definition}"; return(Page()); } } switch (TrackingKind) { #pragma warning disable 618 case TrackingKind.HelixConsole: case TrackingKind.HelixRunClient: ErrorMessage = $"'{TrackingKind}' is deprecated. Please use {TrackingKind.HelixLogs}"; return(Page()); case TrackingKind.HelixLogs: { if (TryParseQueryString <SearchHelixLogsRequest>(out var request)) { if (request.HelixLogKinds.Count == 0) { ErrorMessage = "Need to specify at least one log kind to search"; return(Page()); } } else { return(Page()); } } break; case TrackingKind.Test: if (!TryParseQueryString <SearchTestsRequest>(out _)) { return(Page()); } break; case TrackingKind.Timeline: if (!TryParseQueryString <SearchTimelinesRequest>(out _)) { return(Page()); } break; } GitHubIssueKey?issueKey = null; if (!string.IsNullOrEmpty(GitHubIssueUri)) { if (GitHubIssueKey.TryCreateFromUri(GitHubIssueUri, out var key)) { issueKey = key; GitHubOrganization = key.Organization; GitHubRepository = key.Repository; } else { ErrorMessage = $"Invalid GitHub issue link: {GitHubIssueUri}"; return(Page()); } } else if (string.IsNullOrEmpty(GitHubRepository) || string.IsNullOrEmpty(GitHubOrganization)) { ErrorMessage = "Must provide GitHub organization and repository"; return(Page()); } IGitHubClient?gitHubClient = null; try { gitHubClient = await GitHubClientFactory.CreateForAppAsync(GitHubOrganization, GitHubRepository); } catch (Exception ex) { ErrorMessage = $"Cannot create GitHub client for that repository: {ex.Message}"; return(Page()); } var modelTrackingIssue = await CreateTrackingIssue(gitHubClient); return(RedirectToPage( "./Issue", new { id = modelTrackingIssue.Id })); async Task <ModelTrackingIssue> CreateTrackingIssue(IGitHubClient gitHubClient) { var issueKey = await GetOrCreateGitHubIssueAsync(gitHubClient); var modelTrackingIssue = new ModelTrackingIssue() { IsActive = true, IssueTitle = IssueTitle, TrackingKind = TrackingKind, SearchQuery = SearchText, ModelBuildDefinition = modelBuildDefinition, GitHubOrganization = issueKey.Organization, GitHubRepository = issueKey.Repository, GitHubIssueNumber = issueKey.Number, }; TriageContext.ModelTrackingIssues.Add(modelTrackingIssue); await TriageContext.SaveChangesAsync(); await InitialTriageAsync(modelTrackingIssue); return(modelTrackingIssue); } async Task InitialTriageAsync(ModelTrackingIssue modelTrackingIssue) { if (modelBuildDefinition is object) { // The initial triage is only done for tracking issues that have definitions // associated with. Lacking a definition we end up querying all builds and that // can produce a *lot* of data. Hard to find a good formula that is performant // there hence we limit to only builds with definitions. var request = new SearchBuildsRequest() { Definition = modelBuildDefinition?.DefinitionId.ToString() ?? null, Queued = new DateRequestValue(7, RelationalKind.GreaterThan), Result = new BuildResultRequestValue(BuildResult.Succeeded, EqualsKind.NotEquals), }; await FunctionQueueUtil.QueueTriageBuildAttempts(TriageContextUtil, modelTrackingIssue, request); // Issues are bulk updated on a 15 minute cycle. This is a new issue though so want to make sure that // the user sees progress soon. Schedule two manual updates in the near future on this so the issue // gets rolling then it will fall into the 15 minute bulk cycle. await FunctionQueueUtil.QueueUpdateIssueAsync(modelTrackingIssue, TimeSpan.FromSeconds(30)); await FunctionQueueUtil.QueueUpdateIssueAsync(modelTrackingIssue, TimeSpan.FromMinutes(2)); } else { await FunctionQueueUtil.QueueUpdateIssueAsync(modelTrackingIssue, TimeSpan.FromMinutes(0)); } } async Task <GitHubIssueKey> GetOrCreateGitHubIssueAsync(IGitHubClient gitHubClient) { if (issueKey is { } key) { await TrackingGitHubUtil.EnsureGitHubIssueHasMarkers(gitHubClient, key); return(key); } var newIssue = new NewIssue(IssueTitle) { Body = TrackingGitHubUtil.WrapInStartEndMarkers("Runfo Creating Tracking Issue (data being generated)") }; var issue = await gitHubClient.Issue.Create(GitHubOrganization, GitHubRepository, newIssue); return(issue.GetIssueKey()); } bool TryParseQueryString <T>(out T value) where T : ISearchRequest, new() { value = new T(); try { value.ParseQueryString(SearchText ?? ""); return(true); } catch (Exception ex) { ErrorMessage = ex.ToString(); return(false); } } }
public TrackingIndexModel(TriageContext context) { Context = context; }
public BuildsModel(TriageContext triageContext) { TriageContext = triageContext; }
public PullRequestModel(TriageContext triageContext, IGitHubClientFactory gitHubClientFactory) { TriageContext = triageContext; GitHubClientFactory = gitHubClientFactory; }
// internal static async Task<int> Main(string[] args) => await MainCore(args.ToList()); internal static async Task <int> MainCore(TriageContext context, List <string> args) { var azdoToken = Environment.GetEnvironmentVariable("RUNFO_AZURE_TOKEN"); var gitHubToken = Environment.GetEnvironmentVariable("RUNFO_GITHUB_TOKEN"); var cacheDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "runfo", "json"); var server = new CachingDevOpsServer(cacheDirectory, "dnceng", azdoToken); var gitHubClient = new GitHubClient(new ProductHeaderValue("RuntimeStatusPage")); var queryUtil = new DotNetQueryUtil(server); using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); // TODO: should not hard code jaredpar here gitHubClient.Credentials = new Credentials("jaredpar", gitHubToken); string command; if (args.Count == 0) { command = "list"; } else { command = args[0]; args = args.Skip(1).ToList(); } var autoTriageUtil = new AutoTriageUtil(server, gitHubClient, context, loggerFactory.CreateLogger <AutoTriageUtil>()); switch (command) { case "auto": await RunAutoTriage(args); break; case "issues": await RunIssues(); break; case "rebuild": await RunRebuild(); break; case "scratch": await RunScratch(); break; default: Console.WriteLine($"Unrecognized option {command}"); break; } return(ExitSuccess); async Task RunAutoTriage(List <string> args) { autoTriageUtil.EnsureTriageIssues(); await autoTriageUtil.Triage("-d runtime -c 100 -pr"); await autoTriageUtil.Triage("-d runtime-official -c 20 -pr"); await autoTriageUtil.UpdateQueryIssues(); await autoTriageUtil.UpdateStatusIssue(); } async Task RunIssues() { await autoTriageUtil.UpdateQueryIssues(); await autoTriageUtil.UpdateStatusIssue(); } async Task RunRebuild() { autoTriageUtil.EnsureTriageIssues(); await autoTriageUtil.Triage("-d runtime -c 1000 -pr"); await autoTriageUtil.Triage("-d aspnet -c 1000 -pr"); await autoTriageUtil.Triage("-d runtime-official -c 50 -pr"); await autoTriageUtil.Triage("-d aspnet-official -c 50 -pr"); } async Task RunScratch() { // autoTriageUtil.EnsureTriageIssues(); // await autoTriageUtil.Triage("-d runtime -c 500 -pr"); // await autoTriageUtil.Triage("-d runtime-official -c 50 -pr"); // await autoTriageUtil.UpdateQueryIssues(); await autoTriageUtil.UpdateStatusIssue(); } }