/// <summary>
        /// Compares IInternalCache objects
        /// </summary>
        internal IEnumerable <UserEvents.MergeRequestEvent> CheckForUpdates(
            IInternalCache oldDetails, IInternalCache newDetails)
        {
            TwoListDifference <MergeRequestWithProject> diff = getMergeRequestDiff(oldDetails, newDetails);

            return(getMergeRequestUpdates(diff, oldDetails, newDetails));
        }
        /// <summary>
        /// Calculate difference between two IInternalCache objects
        /// </summary>
        private TwoListDifference <MergeRequestWithProject> getMergeRequestDiff(
            IInternalCache oldDetails, IInternalCache newDetails)
        {
            TwoListDifference <MergeRequestWithProject> diff = new TwoListDifference <MergeRequestWithProject>
                                                               (
                new List <MergeRequestWithProject>(),
                new List <MergeRequestWithProject>(),
                new List <Tuple <MergeRequestWithProject, MergeRequestWithProject> >()
                                                               );

            HashSet <ProjectKey> projectKeys = oldDetails.GetProjects().Concat(newDetails.GetProjects()).ToHashSet();

            foreach (ProjectKey projectKey in projectKeys)
            {
                MergeRequest[] previouslyCachedMergeRequests = oldDetails.GetMergeRequests(projectKey).ToArray();
                MergeRequest[] newCachedMergeRequests        = newDetails.GetMergeRequests(projectKey).ToArray();

                Array.Sort(previouslyCachedMergeRequests, (x, y) => x.Id.CompareTo(y.Id));
                Array.Sort(newCachedMergeRequests, (x, y) => x.Id.CompareTo(y.Id));

                int iPrevMR = 0, iNewMR = 0;
                while (iPrevMR < previouslyCachedMergeRequests.Count() && iNewMR < newCachedMergeRequests.Count())
                {
                    if (previouslyCachedMergeRequests[iPrevMR].Id < newCachedMergeRequests[iNewMR].Id)
                    {
                        diff.FirstOnly.Add(new MergeRequestWithProject(previouslyCachedMergeRequests[iPrevMR], projectKey));
                        ++iPrevMR;
                    }
                    else if (previouslyCachedMergeRequests[iPrevMR].Id == newCachedMergeRequests[iNewMR].Id)
                    {
                        diff.Common.Add(new Tuple <MergeRequestWithProject, MergeRequestWithProject>(
                                            new MergeRequestWithProject(previouslyCachedMergeRequests[iPrevMR], projectKey),
                                            new MergeRequestWithProject(newCachedMergeRequests[iNewMR], projectKey)));
                        ++iPrevMR;
                        ++iNewMR;
                    }
                    else
                    {
                        diff.SecondOnly.Add(new MergeRequestWithProject(newCachedMergeRequests[iNewMR], projectKey));
                        ++iNewMR;
                    }
                }

                while (iPrevMR < previouslyCachedMergeRequests.Count())
                {
                    diff.FirstOnly.Add(new MergeRequestWithProject(previouslyCachedMergeRequests[iPrevMR], projectKey));
                    ++iPrevMR;
                }

                while (iNewMR < newCachedMergeRequests.Count())
                {
                    diff.SecondOnly.Add(new MergeRequestWithProject(newCachedMergeRequests[iNewMR], projectKey));
                    ++iNewMR;
                }
            }

            return(diff);
        }
Пример #3
0
        public CacheUpdater(Dictionary <TKey, TObject> data, Func <TObject, TKey> keySelector = null)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            _cache       = new InternalCache <TObject, TKey>(data);
            _keySelector = keySelector;
        }
        /// <summary>
        /// Convert a difference between two states into a list of merge request updates splitted in new/updated/closed
        /// </summary>
        private IEnumerable <UserEvents.MergeRequestEvent> getMergeRequestUpdates(
            TwoListDifference <MergeRequestWithProject> diff, IInternalCache oldDetails, IInternalCache newDetails)
        {
            List <UserEvents.MergeRequestEvent> updates = new List <UserEvents.MergeRequestEvent>();

            foreach (MergeRequestWithProject mergeRequest in diff.SecondOnly)
            {
                FullMergeRequestKey fmk = new FullMergeRequestKey(mergeRequest.Project, mergeRequest.MergeRequest);

                updates.Add(new UserEvents.MergeRequestEvent(
                                fmk, UserEvents.MergeRequestEvent.Type.AddedMergeRequest, null));
            }

            foreach (MergeRequestWithProject mergeRequest in diff.FirstOnly)
            {
                FullMergeRequestKey fmk = new FullMergeRequestKey(mergeRequest.Project, mergeRequest.MergeRequest);

                updates.Add(new UserEvents.MergeRequestEvent(
                                fmk, UserEvents.MergeRequestEvent.Type.RemovedMergeRequest, null));
            }

            foreach (Tuple <MergeRequestWithProject, MergeRequestWithProject> mrPair in diff.Common)
            {
                MergeRequest mergeRequest1 = mrPair.Item1.MergeRequest;
                MergeRequest mergeRequest2 = mrPair.Item2.MergeRequest;
                Debug.Assert(mergeRequest1.Id == mergeRequest2.Id);

                MergeRequestKey mergeRequestKey = new MergeRequestKey(mrPair.Item2.Project, mergeRequest2.IId);

                IEnumerable <Version> oldVersions = oldDetails.GetVersions(mergeRequestKey);
                IEnumerable <Version> newVersions = newDetails.GetVersions(mergeRequestKey);

                bool labelsUpdated  = !Enumerable.SequenceEqual(mergeRequest1.Labels, mergeRequest2.Labels);
                bool commitsUpdated = newVersions.Count() > oldVersions.Count();

                MergeRequestApprovalConfiguration oldApprovals = oldDetails.GetApprovals(mergeRequestKey);
                MergeRequestApprovalConfiguration newApprovals = newDetails.GetApprovals(mergeRequestKey);
                bool detailsUpdated = areMergeRequestsDifferentInDetails(mergeRequest1, mergeRequest2) ||
                                      areApprovalsDifferent(oldApprovals, newApprovals);

                if (labelsUpdated || commitsUpdated || detailsUpdated)
                {
                    FullMergeRequestKey fmk = new FullMergeRequestKey(
                        mergeRequestKey.ProjectKey, mergeRequest2);

                    updates.Add(new UserEvents.MergeRequestEvent(
                                    fmk, UserEvents.MergeRequestEvent.Type.UpdatedMergeRequest,
                                    new UserEvents.MergeRequestEvent.UpdateScope(commitsUpdated, labelsUpdated, detailsUpdated)));
                }
            }

            return(updates);
        }
Пример #5
0
        async private Task <IEnumerable <UserEvents.MergeRequestEvent> > updateOneOnTimer(MergeRequestKey mrk)
        {
            if (_updating)
            {
                traceDetailed(String.Format("Cannot update !{0} in {1}", mrk.IId, mrk.ProjectKey.ProjectName));
                await TaskUtils.WhileAsync(() => _updating);

                traceDetailed(String.Format("Skipped update for !{0} in {1}", mrk.IId, mrk.ProjectKey.ProjectName));
                return(null);
            }

            IInternalCache oldDetails = _cache.Clone();

            traceDetailed(String.Format("Ready to update !{0} in {1}", mrk.IId, mrk.ProjectKey.ProjectName));
            try
            {
                _updating = true;
                if (_mergeRequestLoader != null)
                {
                    await _mergeRequestLoader.LoadMergeRequest(mrk);
                }
                MergeRequestRefreshed?.Invoke(mrk);
            }
            catch (BaseLoaderException ex)
            {
                ExceptionHandlers.Handle("Cannot perform a one-shot update", ex);
                return(null);
            }
            finally
            {
                _updating = false;
                traceDetailed(String.Format("Updated !{0} in {1}", mrk.IId, mrk.ProjectKey.ProjectName));
            }

            IEnumerable <UserEvents.MergeRequestEvent> updates = _checker.CheckForUpdates(oldDetails, _cache);

            int legalUpdates = updates.Count(x => x.Labels);

            Debug.Assert(legalUpdates == 0 || legalUpdates == 1);

            if (legalUpdates > 0)
            {
                traceInformation(
                    String.Format(
                        "Updated Labels: {0}. MRK: HostName={1}, ProjectName={2}, IId={3}",
                        legalUpdates, mrk.ProjectKey.HostName, mrk.ProjectKey.ProjectName, mrk.IId));
            }

            return(updates);
        }
Пример #6
0
        async private Task <IEnumerable <UserEvents.MergeRequestEvent> > updateAllOnTimer()
        {
            if (_updating)
            {
                await TaskUtils.WhileAsync(() => _updating);

                return(null);
            }

            IInternalCache oldDetails = _cache.Clone();

            try
            {
                _updating = true;
                await _mergeRequestListLoader.Load();
            }
            catch (BaseLoaderException ex)
            {
                ExceptionHandlers.Handle("Cannot update merge requests on timer", ex);
            }
            finally
            {
                _updating = false;
            }

            IEnumerable <UserEvents.MergeRequestEvent> updates = _checker.CheckForUpdates(oldDetails, _cache);

            Trace.TraceInformation(
                String.Format(
                    "[UpdateManager] Merge Request Updates: " +
                    "New {0}, Updated commits {1}, Updated labels {2}, Updated details {3}, Closed {4}",
                    updates.Count(x => x.New),
                    updates.Count(x => x.Commits),
                    updates.Count(x => x.Labels),
                    updates.Count(x => x.Details),
                    updates.Count(x => x.Closed)));

            return(updates);
        }
Пример #7
0
        async private Task <IEnumerable <UserEvents.MergeRequestEvent> > updateAllOnTimer()
        {
            if (_updating)
            {
                traceDetailed("Cannot update the list");
                await TaskUtils.WhileAsync(() => _updating);

                traceDetailed("List update has been skipped");
                return(null);
            }

            IInternalCache oldDetails = _cache.Clone();

            traceDetailed("Ready to update the list");
            try
            {
                _updating = true;
                if (_mergeRequestListLoader != null)
                {
                    await _mergeRequestListLoader.Load();
                }
                MergeRequestListRefreshed?.Invoke();
            }
            catch (BaseLoaderException ex)
            {
                ExceptionHandlers.Handle("Cannot update merge requests on timer", ex);
                return(null);
            }
            finally
            {
                _updating = false;
                traceDetailed("Updated the list");
            }

            IEnumerable <UserEvents.MergeRequestEvent> updates = _checker.CheckForUpdates(oldDetails, _cache);

            int newMergeRequestsCount = updates.Count(x => x.AddedToCache);
            int mergeRequestsWithUpdatedCommitsCount = updates.Count(x => x.Commits);
            int mergeRequestsWithUpdatedLabelsCount  = updates.Count(x => x.Labels);
            int mergeRequestsWithUpdatedDetailsCount = updates.Count(x => x.Details);
            int closedMergeRequestsCount             = updates.Count(x => x.RemovedFromCache);

            if (newMergeRequestsCount > 0 ||
                mergeRequestsWithUpdatedCommitsCount > 0 ||
                mergeRequestsWithUpdatedLabelsCount > 0 ||
                mergeRequestsWithUpdatedDetailsCount > 0 ||
                closedMergeRequestsCount > 0)
            {
                traceInformation(
                    String.Format(
                        "Merge Request Updates: " +
                        "New {0}, Updated commits {1}, Updated labels {2}, Updated details {3}, Closed {4}",
                        newMergeRequestsCount,
                        mergeRequestsWithUpdatedCommitsCount,
                        mergeRequestsWithUpdatedLabelsCount,
                        mergeRequestsWithUpdatedDetailsCount,
                        closedMergeRequestsCount));
            }

            return(updates);
        }
Пример #8
0
 internal ImmutableGroup(TGroupKey key, IInternalCache <TObject, TKey> cache)
 {
     Key    = key;
     _cache = new InternalCache <TObject, TKey>(cache.Count);
     cache.KeyValues.ForEach(kvp => _cache.AddOrUpdate(kvp.Value, kvp.Key));
 }
Пример #9
0
 public CacheUpdater(IInternalCache <TObject, TKey> cache, Func <TObject, TKey> keySelector = null)
 {
     _cache       = cache ?? throw new ArgumentNullException(nameof(cache));
     _keySelector = keySelector;
 }
Пример #10
0
 private static IGrouping <TObject, TKey, TGroupKey> GetGroupState(TGroupKey key, IInternalCache <TObject, TKey> cache)
 {
     return(new ImmutableGroup <TObject, TKey, TGroupKey>(key, cache));
 }