protected override async Task <ValidationResult> PopulateSettings(SettingsContainer settings)
        {
            var baseResult = await base.PopulateSettings(settings);

            if (!baseResult.IsSuccess)
            {
                return(baseResult);
            }

            const int defaultMaxPackageUpdates = 1;
            var       fileSettings             = FileSettingsCache.GetSettings();

            var maxUpdates = Concat.FirstValue(
                MaxPackageUpdates,
                fileSettings.MaxPackageUpdates,
                defaultMaxPackageUpdates);

            if (maxUpdates < 1)
            {
                return(ValidationResult.Failure($"Max package updates of {maxUpdates} is not valid"));
            }

            settings.PackageFilters.MaxPackageUpdates = maxUpdates;
            return(ValidationResult.Success);
        }
예제 #2
0
        private SettingsContainer MakeSettings()
        {
            var fileSettings       = FileSettingsCache.GetSettings();
            var allowedChange      = Concat.FirstValue(AllowedChange, fileSettings.Change, VersionChange.Major);
            var usePrerelease      = Concat.FirstValue(UsePrerelease, fileSettings.UsePrerelease, Abstractions.Configuration.UsePrerelease.FromPrerelease);
            var branchNameTemplate = Concat.FirstValue(BranchNameTemplate, fileSettings.BranchNameTemplate);
            var gitpath            = Concat.FirstValue(GitCliPath, fileSettings.GitCliPath);

            var settings = new SettingsContainer
            {
                SourceControlServerSettings = new SourceControlServerSettings(),
                PackageFilters = new FilterSettings(),
                UserSettings   = new UserSettings
                {
                    AllowedChange = allowedChange,
                    UsePrerelease = usePrerelease,
                    NuGetSources  = NuGetSources,
                    GitPath       = gitpath
                },
                BranchSettings = new BranchSettings
                {
                    BranchNameTemplate = branchNameTemplate
                }
            };

            return(settings);
        }
예제 #3
0
        protected override ValidationResult PopulateSettings(SettingsContainer settings)
        {
            var baseResult = base.PopulateSettings(settings);

            if (!baseResult.IsSuccess)
            {
                return(baseResult);
            }

            var regexIncludeReposValid = PopulateIncludeRepos(settings);

            if (!regexIncludeReposValid.IsSuccess)
            {
                return(regexIncludeReposValid);
            }

            var regexExcludeReposValid = PopulateExcludeRepos(settings);

            if (!regexExcludeReposValid.IsSuccess)
            {
                return(regexExcludeReposValid);
            }

            var fileSettings = FileSettingsCache.GetSettings();

            const int defaultMaxReposChanged = 10;

            settings.UserSettings.MaxRepositoriesChanged = Concat.FirstValue(
                AllowedMaxRepositoriesChangedChange, fileSettings.MaxRepo, defaultMaxReposChanged);

            return(ValidationResult.Success);
        }
예제 #4
0
        private ValidationResult PopulateBranchNamePrefix(
            SettingsContainer settings)
        {
            var settingsFromFile = FileSettingsCache.GetSettings();
            var value            = Concat.FirstValue(BranchNamePrefix, settingsFromFile.BranchNamePrefix);

            if (string.IsNullOrWhiteSpace(value))
            {
                settings.BranchSettings.BranchNamePrefix = null;
                return(ValidationResult.Success);
            }

            // Validating git branch names: https://stackoverflow.com/a/12093994/1661209
            // We validate the user defined branch name prefix in combination with a actual branch name that NuKeeper could create.
            // We want to validate the combination since the prefix doesn't need to fully comply with the rules (E.G. 'nukeeper/' is not allowed soley as a branch name).
            var validationValue = $"{value}nukeeper-update-FakeItEasy-to-4.9.2";

            if (!Regex.IsMatch(validationValue, @"^(?!@$|build-|/|.*([/.]\.|//|@\{|\\))[^\000-\037\177 ~^:?*[]+/[^\000-\037\177 ~^:?*[]+(?<!\.lock|[/.])$"))
            {
                return(ValidationResult.Failure(
                           $"Provided branch name prefix '{value}' does not comply with branch naming rules."));
            }

            settings.BranchSettings.BranchNamePrefix = value;
            return(ValidationResult.Success);
        }
예제 #5
0
        private ValidationResult PopulatePackageExcludes(
            SettingsContainer settings)
        {
            var settingsFromFile = FileSettingsCache.Get();
            var value            = Concat.FirstValue(Exclude, settingsFromFile.Exclude);

            if (string.IsNullOrWhiteSpace(value))
            {
                settings.PackageFilters.Excludes = null;
                return(ValidationResult.Success);
            }

            try
            {
                settings.PackageFilters.Excludes = new Regex(value);
            }
            catch (Exception ex)
            {
                {
                    return(ValidationResult.Failure(
                               $"Unable to parse regex '{value}' for Exclude: {ex.Message}"));
                }
            }

            return(ValidationResult.Success);
        }
예제 #6
0
        private string GithubEndpointWithFallback()
        {
            const string defaultGithubApi = "https://api.github.com/";
            var          fileSetting      = FileSettingsCache.Get();

            return(Concat.FirstValue(GithubApiEndpoint, fileSetting.Api, defaultGithubApi));
        }
예제 #7
0
        private ValidationResult PopulateDeleteBranchAfterMerge(
            SettingsContainer settings)
        {
            var fileSettings = FileSettingsCache.GetSettings();

            bool defaultValue;

            // The default value is true, if it is supported for the corresponding platform.
            if (Platform.HasValue && !_platformsSupportingDeleteBranchAfterMerge.Contains(Platform.Value))
            {
                defaultValue = false;
            }
            else
            {
                defaultValue = true;
            }

            settings.BranchSettings.DeleteBranchAfterMerge = Concat.FirstValue(DeleteBranchAfterMerge, fileSettings.DeleteBranchAfterMerge, defaultValue);

            // Ensure that the resulting DeleteBranchAfterMerge value is supported.
            if (settings.BranchSettings.DeleteBranchAfterMerge &&
                Platform.HasValue &&
                !_platformsSupportingDeleteBranchAfterMerge.Contains(Platform.Value))
            {
                return(ValidationResult.Failure("Deletion of source branch after merge is currently only available for Azure DevOps, Gitlab and Bitbucket."));
            }

            return(ValidationResult.Success);
        }
예제 #8
0
        protected override ValidationResult PopulateSettings(SettingsContainer settings)
        {
            var baseResult = base.PopulateSettings(settings);

            if (!baseResult.IsSuccess)
            {
                return(baseResult);
            }

            var fileSettings = FileSettingsCache.GetSettings();

            var endpoint = Concat.FirstValue(ApiEndpoint, fileSettings.Api, settings.SourceControlServerSettings.Repository?.ApiUri.ToString());
            var forkMode = ForkMode ?? fileSettings.ForkMode;
            var platform = Platform ?? fileSettings.Platform;

            if (!Uri.TryCreate(endpoint, UriKind.Absolute, out var baseUri))
            {
                return(ValidationResult.Failure($"Bad Api Base '{endpoint}'"));
            }

            try
            {
                var collaborationResult = CollaborationFactory.Initialise(
                    baseUri, PersonalAccessToken,
                    forkMode, platform);

                if (!collaborationResult.IsSuccess)
                {
                    return(collaborationResult);
                }
            }
#pragma warning disable CA1031
            catch (Exception ex)
#pragma warning restore CA1031
            {
                return(ValidationResult.Failure(ex.Message));
            }

            if (CollaborationFactory.Settings.Token == null)
            {
                return(ValidationResult.Failure("The required access token was not found"));
            }

            settings.UserSettings.ConsolidateUpdatesInSinglePullRequest =
                Concat.FirstValue(Consolidate, fileSettings.Consolidate, false);

            const int defaultMaxPackageUpdates = 3;
            settings.PackageFilters.MaxPackageUpdates =
                Concat.FirstValue(MaxPackageUpdates, fileSettings.MaxPackageUpdates, defaultMaxPackageUpdates);

            var defaultLabels = new List <string> {
                "nukeeper"
            };

            settings.SourceControlServerSettings.Labels =
                Concat.FirstPopulatedList(Label, fileSettings.Label, defaultLabels);

            return(ValidationResult.Success);
        }
예제 #9
0
        private TimeSpan?ReadMinPackageAge()
        {
            const string defaultMinPackageAge = "7d";
            var          settingsFromFile     = FileSettingsCache.Get();
            var          valueWithFallback    = Concat.FirstValue(MinimumPackageAge, settingsFromFile.Age, defaultMinPackageAge);

            return(DurationParser.Parse(valueWithFallback));
        }
예제 #10
0
        private void InitialiseLogging()
        {
            var fileSettings = FileSettingsCache.Get();
            var logLevel     = Concat.FirstValue(Verbosity, fileSettings.Verbosity, LogLevel.Normal);
            var logFile      = Concat.FirstValue(LogFile, fileSettings.LogFile);

            _configureLogger.Initialise(logLevel, logFile);
        }
예제 #11
0
        private ValidationResult PopulateBranchNameTemplate(
            SettingsContainer settings)
        {
            var settingsFromFile = FileSettingsCache.GetSettings();
            var value            = Concat.FirstValue(BranchNameTemplate, settingsFromFile.BranchNameTemplate);

            if (string.IsNullOrWhiteSpace(value))
            {
                settings.BranchSettings.BranchNameTemplate = null;
                return(ValidationResult.Success);
            }

            // Validating git branch names: https://stackoverflow.com/a/12093994/1661209
            // We validate the user defined branch name prefix in combination with a actual branch name that NuKeeper could create.
            // We want to validate the combination since the prefix doesn't need to fully comply with the rules (E.G. 'nukeeper/' is not allowed soley as a branch name).

            var tokenErrors = new StringBuilder();
            var tokenSet    = Regex.Matches(value, @"{(\w+)}").Select(match => match.Groups[1].Value);

            foreach (var token in tokenSet)
            {
                if (!BranchNamer.IsValidTemplateToken(token))
                {
                    tokenErrors.Append($",{token}");
                }
            }

            // Check for valid placeholders
            if (tokenErrors.Length > 0)
            {
                return(ValidationResult.Failure(
                           $"Provided branch template has unknown tokens: '{tokenErrors.ToString().Trim(',')}'."));
            }

            // Test if the generated branchname would be ok.
            // We assume tokens will be generated in valid values, so we use dummy values here
            var tokenValues = new Dictionary <string, string>();

            foreach (var token in BranchNamer.TemplateTokens)
            {
                tokenValues.Add(token, "dummy");
            }

            var validationValue = BranchNamer.MakeName(tokenValues, value);

            if (!Regex.IsMatch(validationValue, @"^(?!@$|build-|/|.*([/.]\.|//|@\{|\\))[^\000-\037\177 ~^:?*[]+/[^\000-\037\177 ~^:?*[]+(?<!\.lock|[/.])$"))
            {
                return(ValidationResult.Failure(
                           $"Provided branch template '{value}' does not comply with branch naming rules."));
            }

            settings.BranchSettings.BranchNameTemplate = value;
            return(ValidationResult.Success);
        }
예제 #12
0
        protected override ValidationResult PopulateSettings(SettingsContainer settings)
        {
            var baseResult = base.PopulateSettings(settings);

            if (!baseResult.IsSuccess)
            {
                return(baseResult);
            }

            var apiBase = GithubEndpointWithFallback();

            if (string.IsNullOrWhiteSpace(apiBase))
            {
                return(ValidationResult.Failure("No GitHub Api base found"));
            }

            if (!Uri.TryCreate(apiBase, UriKind.Absolute, out var githubUri))
            {
                return(ValidationResult.Failure($"Bad GitHub Api base '{GithubApiEndpoint}'"));
            }

            var token = ReadToken();

            if (string.IsNullOrWhiteSpace(token))
            {
                return(ValidationResult.Failure("The required GitHub access token was not found"));
            }

            var githubUrl = GitSettingsReader.EnsureTrailingSlash(githubUri);

            var fileSettings = FileSettingsCache.Get();

            settings.GithubAuthSettings = new GithubAuthSettings(githubUrl, token);

            settings.UserSettings.ConsolidateUpdatesInSinglePullRequest =
                Concat.FirstValue(Consolidate, fileSettings.Consolidate, false);


            const int defaultMaxPullRequests = 3;

            settings.PackageFilters.MaxPackageUpdates =
                Concat.FirstValue(MaxPullRequestsPerRepository, fileSettings.MaxPr, defaultMaxPullRequests);

            settings.UserSettings.ForkMode   = ForkMode;
            settings.UserSettings.ReportMode = ReportMode;

            var defaultLabels = new[] { "nukeeper" };

            settings.SourceControlServerSettings.Labels =
                Concat.FirstPopulatedList(Label, fileSettings.Label, defaultLabels);

            return(ValidationResult.Success);
        }
예제 #13
0
        protected virtual async Task <ValidationResult> PopulateSettings(SettingsContainer settings)
        {
            var minPackageAge = ReadMinPackageAge();

            if (!minPackageAge.HasValue)
            {
                return(await Task.FromResult(ValidationResult.Failure($"Min package age '{MinimumPackageAge}' could not be parsed")));
            }

            settings.PackageFilters.MinimumAge = minPackageAge.Value;

            var regexIncludeValid = PopulatePackageIncludes(settings);

            if (!regexIncludeValid.IsSuccess)
            {
                return(regexIncludeValid);
            }

            var regexExcludeValid = PopulatePackageExcludes(settings);

            if (!regexExcludeValid.IsSuccess)
            {
                return(regexExcludeValid);
            }

            var settingsFromFile = FileSettingsCache.GetSettings();

            var defaultOutputDestination = string.IsNullOrWhiteSpace(OutputFileName)
                ? Abstractions.Output.OutputDestination.Console
                : Abstractions.Output.OutputDestination.File;

            settings.UserSettings.OutputDestination =
                Concat.FirstValue(OutputDestination, settingsFromFile.OutputDestination,
                                  defaultOutputDestination);

            settings.UserSettings.OutputFormat =
                Concat.FirstValue(OutputFormat, settingsFromFile.OutputFormat,
                                  Abstractions.Output.OutputFormat.Text);

            settings.UserSettings.OutputFileName =
                Concat.FirstValue(OutputFileName, settingsFromFile.OutputFileName,
                                  "nukeeper.out");

            var branchNameTemplateValid = PopulateBranchNameTemplate(settings);

            if (!branchNameTemplateValid.IsSuccess)
            {
                return(branchNameTemplateValid);
            }

            return(await Task.FromResult(ValidationResult.Success));
        }
예제 #14
0
        private void InitialiseLogging()
        {
            var settingsFromFile = FileSettingsCache.GetSettings();

            var defaultLogDestination = string.IsNullOrWhiteSpace(LogFile)
                ? Abstractions.Logging.LogDestination.Console
                : Abstractions.Logging.LogDestination.File;

            var logDest = Concat.FirstValue(LogDestination, settingsFromFile.LogDestination,
                                            defaultLogDestination);

            var logLevel = Concat.FirstValue(Verbosity, settingsFromFile.Verbosity, LogLevel.Normal);
            var logFile  = Concat.FirstValue(LogFile, settingsFromFile.LogFile, "nukeeper.log");

            _configureLogger.Initialise(logLevel, logDest, logFile);
        }
예제 #15
0
        protected override async Task <ValidationResult> PopulateSettings(SettingsContainer settings)
        {
            var fileSettings = FileSettingsCache.GetSettings();

            ApiEndpoint = Concat.FirstValue(ApiEndpoint, fileSettings.Api, "https://api.github.com");

            var baseResult = await base.PopulateSettings(settings);

            if (!baseResult.IsSuccess)
            {
                return(baseResult);
            }

            settings.SourceControlServerSettings.Scope            = ServerScope.Organisation;
            settings.SourceControlServerSettings.OrganisationName = GithubOrganisationName;
            return(ValidationResult.Success);
        }
예제 #16
0
        private SettingsContainer MakeSettings()
        {
            var fileSettings  = FileSettingsCache.Get();
            var allowedChange = Concat.FirstValue(AllowedChange, fileSettings.Change, VersionChange.Major);

            var settings = new SettingsContainer
            {
                SourceControlServerSettings = new SourceControlServerSettings(),
                PackageFilters = new FilterSettings(),
                UserSettings   = new UserSettings
                {
                    AllowedChange = allowedChange,
                    NuGetSources  = NuGetSources
                }
            };

            return(settings);
        }
예제 #17
0
        private SettingsContainer MakeSettings()
        {
            var fileSettings  = FileSettingsCache.GetSettings();
            var allowedChange = Concat.FirstValue(AllowedChange, fileSettings.Change, VersionChange.Major);
            var usePrerelease =
                Concat.FirstValue(UsePrerelease, fileSettings.UsePrerelease, Abstractions.Configuration.UsePrerelease.FromPrerelease);

            var settings = new SettingsContainer
            {
                SourceControlServerSettings = new SourceControlServerSettings(),
                PackageFilters = new FilterSettings(),
                UserSettings   = new UserSettings
                {
                    AllowedChange = allowedChange,
                    UsePrerelease = usePrerelease,
                    NuGetSources  = NuGetSources
                }
            };

            return(settings);
        }
예제 #18
0
        private ValidationResult PopulateDeleteBranchAfterMerge(
            SettingsContainer settings)
        {
            var fileSettings = FileSettingsCache.GetSettings();

            if (!Platform.HasValue)
            {
                settings.BranchSettings.DeleteBranchAfterMerge = true;
                return(ValidationResult.Success);
            }

            if (Platform != Abstractions.CollaborationPlatform.Platform.AzureDevOps &&
                Platform != Abstractions.CollaborationPlatform.Platform.GitLab &&
                Platform != Abstractions.CollaborationPlatform.Platform.Bitbucket)
            {
                return(ValidationResult.Failure(
                           $"Deletion of source branch after merge is currently only available for Azure DevOps, Gitlab and Bitbucket."));
            }

            settings.BranchSettings.DeleteBranchAfterMerge = Concat.FirstValue(DeleteBranchAfterMerge, fileSettings.DeleteBranchAfterMerge, true);
            return(ValidationResult.Success);
        }
예제 #19
0
        private ValidationResult PopulateExcludeRepos(SettingsContainer settings)
        {
            var settingsFromFile = FileSettingsCache.GetSettings();
            var value            = Concat.FirstValue(ExcludeRepos, settingsFromFile.ExcludeRepos);

            if (string.IsNullOrWhiteSpace(value))
            {
                settings.SourceControlServerSettings.ExcludeRepos = null;
                return(ValidationResult.Success);
            }

            try
            {
                settings.SourceControlServerSettings.ExcludeRepos = new Regex(value);
            }
            catch (Exception ex)
            {
                return(ValidationResult.Failure($"Unable to parse regex '{value}' for ExcludeRepos: {ex.Message}"));
            }

            return(ValidationResult.Success);
        }