<commit_before>﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using Kudu.Contracts.Jobs;
using Kudu.Contracts.Settings;
using Kudu.Core.Tracing;

namespace Kudu.Core.Jobs
{
    public class TriggeredJobsManager : JobsManagerBase<TriggeredJob>, ITriggeredJobsManager
    {
        private readonly ConcurrentDictionary<string, TriggeredJobRunner> _triggeredJobRunners =
            new ConcurrentDictionary<string, TriggeredJobRunner>(StringComparer.OrdinalIgnoreCase);

        private string _extraInfoUrlPrefix;

        public TriggeredJobsManager(ITraceFactory traceFactory, IEnvironment environment, IFileSystem fileSystem, IDeploymentSettingsManager settings, IAnalytics analytics)
            : base(traceFactory, environment, fileSystem, settings, analytics, Constants.TriggeredPath)
        {
        }

        public override IEnumerable<TriggeredJob> ListJobs()
        {
            return ListJobsInternal();
        }

        public override TriggeredJob GetJob(string jobName)
        {
            return GetJobInternal(jobName);
        }

        public TriggeredJobHistory GetJobHistory(string jobName)
        {
            var triggeredJobRuns = new List<TriggeredJobRun>();
            var triggeredJobHistory = new TriggeredJobHistory()
            {
                TriggeredJobRuns = triggeredJobRuns
            };

            DirectoryInfoBase[] jobRunsDirectories = GetJobRunsDirectories(jobName);
            if (jobRunsDirectories == null)
            {
                return triggeredJobHistory;
            }

            foreach (DirectoryInfoBase jobRunDirectory in jobRunsDirectories)
            {
                TriggeredJobRun triggeredJobRun = BuildJobRun(jobRunDirectory, jobName);
                if (triggeredJobRun != null)
                {
                    triggeredJobRuns.Add(triggeredJobRun);
                }
            }

            return triggeredJobHistory;
        }

        public TriggeredJobRun GetJobRun(string jobName, string runId)
        {
            string triggeredJobRunPath = Path.Combine(JobsDataPath, jobName, runId);
            DirectoryInfoBase triggeredJobRunDirectory = FileSystem.DirectoryInfo.FromDirectoryName(triggeredJobRunPath);

            return BuildJobRun(triggeredJobRunDirectory, jobName);
        }

        protected override void UpdateJob(TriggeredJob job)
        {
            job.HistoryUrl = BuildJobsUrl(job.Name + "/history");
            job.LatestRun = BuildLatestJobRun(job.Name);
        }

        protected override Uri BuildDefaultExtraInfoUrl(string jobName)
        {
            if (_extraInfoUrlPrefix == null)
            {
                if (AppBaseUrlPrefix == null)
                {
                    return null;
                }

                _extraInfoUrlPrefix = AppBaseUrlPrefix + "/JobRuns/history.html";
            }

            return new Uri(_extraInfoUrlPrefix + "?jobName=" + jobName);
        }

        private TriggeredJobRun BuildLatestJobRun(string jobName)
        {
            DirectoryInfoBase[] jobRunsDirectories = GetJobRunsDirectories(jobName);
            if (jobRunsDirectories == null)
            {
                return null;
            }

            DirectoryInfoBase latestJobRunDirectory = jobRunsDirectories.OrderByDescending(j => j.Name).First();

            return BuildJobRun(latestJobRunDirectory, jobName);
        }

        private DirectoryInfoBase[] GetJobRunsDirectories(string jobName)
        {
            string jobHistoryPath = Path.Combine(JobsDataPath, jobName);
            DirectoryInfoBase jobHistoryDirectory = FileSystem.DirectoryInfo.FromDirectoryName(jobHistoryPath);
            if (!jobHistoryDirectory.Exists)
            {
                return null;
            }

            return jobHistoryDirectory.GetDirectories("*", SearchOption.TopDirectoryOnly);<commit_msg>Fix issue in triggered job run when the history path is not empty yet doesn't have any runs.<commit_after>﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using Kudu.Contracts.Jobs;
using Kudu.Contracts.Settings;
using Kudu.Core.Tracing;

namespace Kudu.Core.Jobs
{
    public class TriggeredJobsManager : JobsManagerBase<TriggeredJob>, ITriggeredJobsManager
    {
        private readonly ConcurrentDictionary<string, TriggeredJobRunner> _triggeredJobRunners =
            new ConcurrentDictionary<string, TriggeredJobRunner>(StringComparer.OrdinalIgnoreCase);

        private string _extraInfoUrlPrefix;

        public TriggeredJobsManager(ITraceFactory traceFactory, IEnvironment environment, IFileSystem fileSystem, IDeploymentSettingsManager settings, IAnalytics analytics)
            : base(traceFactory, environment, fileSystem, settings, analytics, Constants.TriggeredPath)
        {
        }

        public override IEnumerable<TriggeredJob> ListJobs()
        {
            return ListJobsInternal();
        }

        public override TriggeredJob GetJob(string jobName)
        {
            return GetJobInternal(jobName);
        }

        public TriggeredJobHistory GetJobHistory(string jobName)
        {
            var triggeredJobRuns = new List<TriggeredJobRun>();
            var triggeredJobHistory = new TriggeredJobHistory()
            {
                TriggeredJobRuns = triggeredJobRuns
            };

            DirectoryInfoBase[] jobRunsDirectories = GetJobRunsDirectories(jobName);
            if (jobRunsDirectories == null)
            {
                return triggeredJobHistory;
            }

            foreach (DirectoryInfoBase jobRunDirectory in jobRunsDirectories)
            {
                TriggeredJobRun triggeredJobRun = BuildJobRun(jobRunDirectory, jobName);
                if (triggeredJobRun != null)
                {
                    triggeredJobRuns.Add(triggeredJobRun);
                }
            }

            return triggeredJobHistory;
        }

        public TriggeredJobRun GetJobRun(string jobName, string runId)
        {
            string triggeredJobRunPath = Path.Combine(JobsDataPath, jobName, runId);
            DirectoryInfoBase triggeredJobRunDirectory = FileSystem.DirectoryInfo.FromDirectoryName(triggeredJobRunPath);

            return BuildJobRun(triggeredJobRunDirectory, jobName);
        }

        protected override void UpdateJob(TriggeredJob job)
        {
            job.HistoryUrl = BuildJobsUrl(job.Name + "/history");
            job.LatestRun = BuildLatestJobRun(job.Name);
        }

        protected override Uri BuildDefaultExtraInfoUrl(string jobName)
        {
            if (_extraInfoUrlPrefix == null)
            {
                if (AppBaseUrlPrefix == null)
                {
                    return null;
                }

                _extraInfoUrlPrefix = AppBaseUrlPrefix + "/JobRuns/history.html";
            }

            return new Uri(_extraInfoUrlPrefix + "?jobName=" + jobName);
        }

        private TriggeredJobRun BuildLatestJobRun(string jobName)
        {
            DirectoryInfoBase[] jobRunsDirectories = GetJobRunsDirectories(jobName);
            if (jobRunsDirectories == null || jobRunsDirectories.Length == 0)
            {
                return null;
            }

            DirectoryInfoBase latestJobRunDirectory = jobRunsDirectories.OrderByDescending(j => j.Name).First();

            return BuildJobRun(latestJobRunDirectory, jobName);
        }

        private DirectoryInfoBase[] GetJobRunsDirectories(string jobName)
        {
            string jobHistoryPath = Path.Combine(JobsDataPath, jobName);
            DirectoryInfoBase jobHistoryDirectory = FileSystem.DirectoryInfo.FromDirectoryName(jobHistoryPath);
            if (!jobHistoryDirectory.Exists)
            {
                return null;
            }

            return jobHistoryDirectory.GetDirectories("*", SearchOption.TopDirectoryOnly);
{'fraction_non_alphanumeric': 0.06812259585556521, 'fraction_numerical': 0.00012408487405385284, 'mean_word_length': 2.281758957654723, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4808101', 'n_tokens_mistral': 2077, 'n_tokens_neox': 2004, 'n_words': 394}