Ejemplo n.º 1
0
 public Functions(DevOpsServer server, GitHubClient gitHubClient, TriageContext context)
 {
     Server            = server;
     GitHubClient      = gitHubClient;
     Context           = context;
     TriageContextUtil = new TriageContextUtil(context);
 }
Ejemplo n.º 2
0
 public NewTrackingIssueModel(TriageContext triageContext, FunctionQueueUtil functionQueueUtil, IGitHubClientFactory gitHubClientFactory, ILogger <NewTrackingIssueModel> logger)
 {
     TriageContext       = triageContext;
     TriageContextUtil   = new TriageContextUtil(triageContext);
     GitHubClientFactory = gitHubClientFactory;
     FunctionQueueUtil   = functionQueueUtil;
     Logger = logger;
 }
Ejemplo n.º 3
0
 public Functions(DevOpsServer server, TriageContext context, GitHubClientFactory gitHubClientFactory)
 {
     Server              = server;
     Context             = context;
     TriageContextUtil   = new TriageContextUtil(context);
     GitHubClientFactory = gitHubClientFactory;
     SiteLinkUtil        = SiteLinkUtil.Published;
     HelixServer         = new HelixServer();
 }
Ejemplo n.º 4
0
        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();
        }
Ejemplo n.º 5
0
        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);
                }
            }
        }
Ejemplo n.º 6
0
 public TrackingIndexModel(TriageContext context)
 {
     Context = context;
 }
Ejemplo n.º 7
0
 public BuildsModel(TriageContext triageContext)
 {
     TriageContext = triageContext;
 }
Ejemplo n.º 8
0
 public PullRequestModel(TriageContext triageContext, IGitHubClientFactory gitHubClientFactory)
 {
     TriageContext       = triageContext;
     GitHubClientFactory = gitHubClientFactory;
 }
Ejemplo n.º 9
0
    // 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();
        }
    }