/// <summary>
 /// Initializes a new instance of the <see cref="ConsoleManager"/> class.
 /// </summary>
 /// <param name="os">The os.</param>
 /// <param name="consoleName">Name of the console.</param>
 /// <param name="helpInfo">The help info.</param>
 private ConsoleManager(RequiredValuesOptionSet os, string consoleName, HelpInfo helpInfo)
 {
     ConsoleName = consoleName;
     _optionSet = os;
     Requirements = new List<Requirement>();
     _helpInfo = helpInfo;
 }
        static void Main(string[] args)
        {

            var optionSet = new RequiredValuesOptionSet();
            var pathToProjectFile = optionSet.AddRequiredVariable<string>("p", "Path to project file");
            var pathToFiles = optionSet.AddRequiredVariable<string>("i", "path for files, must end in trailing slash");
            var searchPattern = optionSet.AddRequiredVariable<string>("sp", "search pattern to use");
            var buildType = optionSet.AddVariable<string>("bt", "buildtype to use.  Values are EmbeddedResource, Content, Compile, and None");
            //var structureInVS = optionSet.AddVariable<string>("s", "structure inside of VS.  Must end with a backslash. eg: REPORTS\\");
            string structureInVS = "";

            var helper = new ConsoleManager(optionSet, "Include Files As Links");

            var canProceed = helper.PerformCanProceed(Console.Out, args);

            if (canProceed)
            {
                Console.WriteLine("Loading project file at {0}", pathToProjectFile.Value);
                var modifier = new ProjectModifierFacade(new Project(pathToProjectFile.Value));

                BuildAction compileAction;

                switch (buildType.Value.ToUpper())
                {
                    case "EMBEDDEDRESOURCE":
                        compileAction = BuildAction.EmbeddedResource;
                        break;
                    case "CONTENT":
                        compileAction = BuildAction.Content;
                        break;
                    case "NONE":
                        compileAction = BuildAction.None;
                        break;
                    case "COMPILE":
                        compileAction = BuildAction.Compile;
                        break;
                    default:
                        throw new NotImplementedException(String.Format("{0} is not supported.", buildType.Value));
                }


                Console.WriteLine("Searching for files");
                var myParams = EstablishLinkParams.BuildParamsForMatchingFiles(compileAction, pathToFiles.Value, searchPattern.Value, structureInVS).ToList();

                Console.WriteLine("{0} files found to link", myParams.Count);
                myParams.ForEach(modifier.EstablishLinkToFile);
                Console.WriteLine("Saving project file");
                modifier.Project.Save(pathToProjectFile.Value);
                Console.WriteLine("Complete");
            }
        }
        public void Should_Detect_Required_VariableLists()
        {
            var optionSet = new RequiredValuesOptionSet();
            var n = optionSet.AddRequiredVariableList<string>("n", "");
            var a = optionSet.AddRequiredVariableList<int>("a", "");
            var m = optionSet.AddRequiredVariableList<string>("m", "");

            //TODO: Screaming for an NUnit-test-case-coverage.
            var args = "-n FindThisString -n:Findit2 -n:Findit3 -a2 -a3 -a5565 -a:23".Split(' ');

            optionSet.Parse(args);

            Action<IEnumerable<string>> verifyN = x =>
            {
                // ReSharper disable PossibleMultipleEnumeration
                Assert.AreEqual(3, x.Count());
                Assert.IsTrue(x.Contains("FindThisString"));
                Assert.IsTrue(x.Contains("Findit2"));
                Assert.IsTrue(x.Contains("Findit3"));
                // ReSharper restore PossibleMultipleEnumeration
            };

            Action<IEnumerable<int>> verifyA = x =>
            {
                // ReSharper disable PossibleMultipleEnumeration
                Assert.AreEqual(4, x.Count());
                Assert.IsTrue(x.Contains(2));
                Assert.IsTrue(x.Contains(3));
                Assert.IsTrue(x.Contains(5565));
                Assert.IsTrue(x.Contains(23));
                // ReSharper restore PossibleMultipleEnumeration
            };

            Action<IEnumerable<string>> verifyM = x =>
            {
                // ReSharper disable PossibleMultipleEnumeration
                Assert.AreEqual(0, x.Count());
                Assert.AreEqual(1, optionSet.GetMissingVariables().Count());
                // ReSharper restore PossibleMultipleEnumeration
            };

            verifyA(a);
            verifyA(a.Values);

            verifyN(n);
            verifyN(n.Values);

            verifyM(m);
            verifyM(m.Values);
        }
        public void ShouldGoIntoHelpMode()
        {
            var p = new RequiredValuesOptionSet();
            var name = p.AddRequiredVariable<string>("n", "");

            var m = new ConsoleManager(p, "Test", "?", new string[] { "TESTMODE" });
            var sb = new StringBuilder();
            var stringWriter = new StringWriter(sb);
            var canProceed = m.PerformCanProceed(stringWriter, new string[] { "/?" });

            Assert.IsFalse(canProceed);

            var content = sb.ToString();
            Assert.IsTrue(content.Contains("TESTMODE"));
        }
        public void Should_detect_require_variables()
        {
            var p = new RequiredValuesOptionSet();
            var name = p.AddRequiredVariable<string>("n", "");
            var age = p.AddRequiredVariable<int>("a", "");
            var age2 = p.AddRequiredVariable<int>("b", "");
            var age3 = p.AddRequiredVariable<int>("c", "");

            var myArgs = "-n FindThisString".Split(' ');
            p.Parse(myArgs);

            Assert.AreEqual(3, p.GetMissingVariables().Count());

            Assert.AreEqual("FindThisString", name);
        }
        public void TestMethod1()
        {
            var p = new RequiredValuesOptionSet();
            var name = p.AddRequiredVariable<string>("n", "");
            var age = p.AddRequiredVariable<int>("a", "");
            var age2 = p.AddRequiredVariable<int>("b", "");
            var age3 = p.AddRequiredVariable<int>("c", "");

            var myArgs = "-n FindThisString".Split(' ');

            p.Parse(myArgs);

            var m = new ConsoleManager(p, "Test");
            var canproceed = m.PerformCanProceed(new StringWriter(), new string[] { });
            Assert.IsFalse(canproceed);
        }
        public void Should_Detect_Required_Variables()
        {
            var optionSet = new RequiredValuesOptionSet();
            var name = optionSet.AddRequiredVariable<string>("n", "");
            var age = optionSet.AddRequiredVariable<int>("a", "");
            var age2 = optionSet.AddRequiredVariable<int>("b", "");
            var age3 = optionSet.AddRequiredVariable<int>("c", "");

            //TODO: Screaming for NUnit-test-case-coverage.
            var args = "-n FindThisString".Split(' ');
            optionSet.Parse(args);

            /* TODO: Might could (should) also verify that each of the missing ones,
             * as well as found ones, are either there are not there. */
            Assert.AreEqual(3, optionSet.GetMissingVariables().Count());

            Assert.AreEqual("FindThisString", name);
        }
        public void ShouldSupportVisualStudioErrors()
        {
            var p = new RequiredValuesOptionSet();
            var name = p.AddRequiredVariable<string>("n", "");
            var age = p.AddRequiredVariable<int>("a", "");
            var age2 = p.AddRequiredVariable<int>("b", "");
            var age3 = p.AddRequiredVariable<int>("c", "");
                     
            var m = new ConsoleManager(p, "TestConsoleApp");

            var myArgs = "-n FindThisString".Split(' ');

            m.MakeOptionExceptionsVisualStudioAware();

            var writer = new StringWriter();
            var canproceed = m.PerformCanProceed(writer, myArgs);
            Assert.IsFalse(canproceed);

            // Test contains Visual Studio error message
            Assert.IsTrue(writer.ToString().Contains("TestConsoleApp : error"));
        }
        public void Should_Respond_To_Help_Arg()
        {
            var optionSet = new RequiredValuesOptionSet();

            //Add a non-required variable because we want to verify the help-arg.
            var name = optionSet.AddVariable<string>("n", "");

            const string HelpPrototype = "?";
            const string Description = "TESTMODE";

            var cm = new ConsoleManager("Test", optionSet, HelpPrototype, Description);

            using (var writer = new StringWriter())
            {
                var parsed = cm.TryParseOrShowHelp(writer, new[] {HelpPrototype,});

                Assert.IsFalse(parsed);

                Assert.IsTrue(writer.ToString().Contains(Description));
            }
        }
        public void Should_Respond_To_Missing_Required_VariableLists_With_Show_Help()
        {
            var optionSet = new RequiredValuesOptionSet();

            //Populate the OptionSet with some nominal options.
            var n = optionSet.AddRequiredVariableList<string>("n", "");
            var a = optionSet.AddRequiredVariableList<int>("a", "");
            var m = optionSet.AddRequiredVariableList<string>("m", "");

            const string ConsoleName = "Test";

            var cm = new ConsoleManager(ConsoleName, optionSet);

            using (var writer = new StringWriter())
            {
                var parsed = cm.TryParseOrShowHelp(writer, new string[] { });

                Assert.IsFalse(parsed);

                Assert.IsTrue(writer.ToString().Contains(ConsoleName + ": error parsing arguments:"));
            }
        }
        public void Show_Show_Help_For_Remaining_Args()
        {
            var optionSet = new RequiredValuesOptionSet();

            //This one can be a required-variable, no problem, but that's it.
            var name = optionSet.AddRequiredVariable<string>("n");

            const string ConsoleName = "Test";

            var cm = new ConsoleManager(ConsoleName, optionSet);

            //Then we should have some remaining args.
            var args = "-n ThisIsName UnknownOptionCausesErrorShowHelp".Split(' ');

            using (var writer = new StringWriter())
            {
                var parsed = cm.TryParseOrShowHelp(writer, args);

                Assert.IsFalse(parsed);

                // Test contains Visual Studio error message
                Assert.IsTrue(writer.ToString().Contains(ConsoleName + ": error parsing arguments:"));
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ConsoleManager"/> class using a specified value for help flag and text
 /// </summary>
 /// <param name="os">The os.</param>
 /// <param name="consoleName">Name of the console.</param>
 /// <param name="helpFlag">The help flag.</param>
 /// <param name="text">The text.</param>
 public ConsoleManager(RequiredValuesOptionSet os, string consoleName, string helpFlag, string[] text)
     : this(os, consoleName, null)
 {
     var help = os.AddFlag(helpFlag, "help");
     _helpInfo = new HelpInfo("-" + helpFlag, () => help, text);
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="ConsoleManager"/> class.
 /// </summary>
 /// <param name="optionSet">An OptionSet.</param>
 /// <param name="consoleName">Name of the console.</param>
 /// <param name="helpInfo">The help info.</param>
 private ConsoleManager(RequiredValuesOptionSet optionSet, string consoleName, HelpInfo helpInfo)
 {
     ConsoleName = consoleName;
     _optionSet = optionSet;
     _helpInfo = helpInfo;
 }
        /// <summary>
        ///     Processes the arguments, utilising NDesk.Options.
        /// </summary>
        /// <param name="args">The arguments.</param>
        /// <returns>True if the command line was successfully processed</returns>
        private static bool ProcessArguments(string[] args)
        {
            try
            {
                bool retVal;

                // Create a commandline option set for processing command line options
                RequiredValuesOptionSet options = new RequiredValuesOptionSet();

                commandLine.SettingsFile        = options.AddRequiredVariable <string>("f|File", "Settings file to encrypt/decrypt");
                commandLine.Decrypt             = options.AddSwitch("d|Decrypt", "Indicates that settings are to be decrypted - default is to encrypt");
                commandLine.AffectedSettingsCsv =
                    options.AddVariable <string>("s|Settings", "Comma seperated list of individual settings to encrypt/decrypt");
                commandLine.AffectedSettingsFile = options.AddVariable <string>("sf|SettingsFile",
                                                                                "Filepath to the file containing line seperated settings to encrypt/decrypt");

                // Process the command line arguments
                ConsoleManager consoleOptionsManager = new ConsoleManager("Settings Encryptor", options);
                retVal = consoleOptionsManager.TryParseOrShowHelp(Console.Out, args);

                if (retVal)
                {
                    if (commandLine.AffectedSettingsCsv.Value != null)
                    {
                        settingsToEncrypt.AddRange(commandLine.AffectedSettingsCsv.Value.Split(','));
                    }
                    else if (commandLine.AffectedSettingsFile.Value == null)
                    {
                        throw new EncryptAppException(EncryptAppExceptionReason.NoSettingsSpecified);
                    }
                    else
                    {
                        if (!File.Exists(commandLine.AffectedSettingsFile))
                        {
                            throw new EncryptAppException(EncryptAppExceptionReason.SettingsInputFileNotFound,
                                                          commandLine.AffectedSettingsFile.Value);
                        }

                        // Read the list of settings from the settings file
                        string[] readSettings = File.ReadAllLines(commandLine.AffectedSettingsFile);

                        foreach (string readSetting in readSettings)
                        {
                            // Be quite forgiving about how the settings are listed.
                            settingsToEncrypt.AddRange(readSetting.Trim(' ', '"', '\'', ',').Split(','));
                        }
                    }
                }

                return(retVal);
            }
            catch (EncryptAppException)
            {
                throw;
            }
            catch (OptionException excep)
            {
                throw new EncryptAppException(EncryptAppExceptionReason.CommandLineOptionException, excep.Message);
            }
            catch (Exception excep)
            {
                throw new EncryptAppException(EncryptAppExceptionReason.UnknownException, nameof(ProcessArguments), excep.Message);
            }
        }
        public static void Main(string[] args)
        {
            SetupNLog();

            var options = new RequiredValuesOptionSet();

            // Required
            var templateBaseFolderArg = options.AddRequiredVariable<string>("tbase", "{TemplateBaseFolder} which contains .cshtml Razor templates");
            var razorFilenameArg = options.AddRequiredVariable<string>("f", "{RazorFile} to parse & execute");
            var outputFilenameArg = options.AddRequiredVariable<string>("o", "{OutputFilename}");

            // Optional
            var modelKeyValuePairArgs = options.AddVariableMatrix<object>("m", "{Model} key/value pairs");
            var namespaceArgs = options.AddVariableList<string>("n", "{Namespaces} to automatically include");
            var outputBaseFolderArg = options.AddVariable<string>("obase", "{OutputBaseFolder}");
            var assemblyFileArgs = options.AddVariableList<string>("assemblyFile", "{Assembly} path to load");
            var assemblyFolderArgs = options.AddVariableList<string>("assemblyFolder", "{AssemblyFolder} to load assemblies from");
            var assemblyFolderIgnorePatternArgs = options.AddVariableList<string>("ignoreAssemblyPattern", "{RegexIgnorePattern} to ignore certain assemblies within Assembly Folders. Helpful to prevent an assembly from attempting to load multiple times.");
            var suspendRootOutput = options.AddVariable<bool>("suspendRootOutput", "Silence primary root template's output. Child templates are still outputed.");
            var rootExistingFileBehavior = options.AddVariable<int>("rootOverwriteBehavior", "ExistingFileBehavior of primary root template. 0 = ThrowException, 1 = NeverOverwrite, 3 = AlwaysOverwrite");

            var consoleManager = new ConsoleManager(options, "gcRazorConsole", "?", new string[] {
                "",
                "gcRazorConsole: 'Console-Based Razor Template Execution'",
                "",
                "Specify the Razor file to parse & execute, as well as key/value pairs to be used for @Model calls. For instance: Console parameter m:Name=Greg would transform razor @Model.Name into Greg",
                "Please find out more information at http://www.geniuscode.net", 
                ""});

            // VisualStudio-Aware Exceptions (for cast exceptions)
            consoleManager.MakeOptionExceptionsVisualStudioAware();

            var argErrors = new StringWriter();

            // Apply Arguments

            bool canProceed = consoleManager.PerformCanProceed(argErrors, args);

            if (canProceed)
            {
                logger.Info(string.Format("templateBaseFolder = {0}", templateBaseFolderArg.Value));
                logger.Info(string.Format("razorFilename = {0}", razorFilenameArg.Value));
                logger.Info(string.Format("outputFilename = {0}", outputFilenameArg.Value));
                logger.Info(string.Format("outputBaseFolder = {0}", outputBaseFolderArg.Value));
                logger.Info(string.Format("assemblyFiles = {0}", assemblyFileArgs.Values.Select(file => file + "; ")));
                logger.Info(string.Format("assemblyFolders = {0}", assemblyFolderArgs.Values.Select(folder => folder + "; ")));
                logger.Info(string.Format("assemblyFolderIgnorePatterns = {0}", assemblyFolderIgnorePatternArgs.Values.Select(pattern => pattern + "; ")));

                // Remove quotes from folder paths
                var templateBaseFolder = RemoveSurroundingQuotes(templateBaseFolderArg.Value);
                var razorFilename = RemoveSurroundingQuotes(razorFilenameArg.Value);
                var outputFilename = RemoveSurroundingQuotes(outputFilenameArg.Value);
                var outputBaseFolder = RemoveSurroundingQuotes(outputBaseFolderArg.Value);

                var assemblyFiles = assemblyFileArgs.Values.Select(file => RemoveSurroundingQuotes(file));
                var assemblyFolders = assemblyFolderArgs.Values.Select(folder => RemoveSurroundingQuotes(folder));
                var assemblyFolderIgnorePatterns = assemblyFolderIgnorePatternArgs.Values.Select(pattern => new Regex(pattern));

                // Template & Output Base Folders
                var razorArgs = new RazorExecuteArgs(templateBaseFolder, outputBaseFolder);

                // Additional Namespaces
                razorArgs.namespaces.AddRange(namespaceArgs.Values);

                // Additional Assemblies
                RazorExtensions.ApplyAssembliesToRazorArgs(razorArgs, assemblyFiles, assemblyFolders, assemblyFolderIgnorePatterns);

                // Additional Options
                razorArgs.SuspendRootOutput = suspendRootOutput.Value;
                razorArgs.RootExistingFileBehavior = (ExistingFileBehavior)rootExistingFileBehavior.Value;

                // Execute Razor
                RazorExtensions.ExecuteRazorDynamicModel(razorArgs, razorFilename, modelKeyValuePairArgs.Matrix, outputFilename);
            }
            else
            {
                // Arguments Failed
                // Build VisualStudio-Aware Exception
                var errorString = ConsoleHelper.CreateVisualStudioErrorString("gcRazorConsole", "-100", string.Format("Invalid command-line arguments. {0}",argErrors.ToString()));

                logger.Error(errorString);

                Console.Write(errorString);
            }

        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ConsoleManager"/>
 /// class using a specified value for HelpInfo prototype and description.
 /// </summary>
 /// <param name="consoleName">Name of the console.</param>
 /// <param name="optionSet">An OptionSet.</param>
 /// <param name="helpPrototype">The Help prototype. Informs a Switch with its Prototype.</param>
 /// <param name="helpDescription">The help description.</param>
 public ConsoleManager(string consoleName, RequiredValuesOptionSet optionSet, string helpPrototype = "?", string helpDescription = "Show the help")
     : this(optionSet, consoleName, new HelpInfo(optionSet, helpPrototype, helpDescription))
 {
 }
Beispiel #17
0
    private static void Main(string[] args)
    {
      // TODO this code is prone to invalid inputs... idc :bikini:

      var requiredValuesOptionSet = new RequiredValuesOptionSet();
      var repository = requiredValuesOptionSet.AddRequiredVariable<string>("repository",
                                                                           "Specifies the URI to the SVN repository");
      var trunk = requiredValuesOptionSet.AddRequiredVariable<string>("trunk",
                                                                      "Specifies the relative path to the trunk, which is diffed against the <branch> parameter (usually trunk)");
      var branch = requiredValuesOptionSet.AddRequiredVariable<string>("branch",
                                                                       "Specifies the relative path to the branch, whose initial revision is used as the offset for the change log");
      var redmineHost = requiredValuesOptionSet.AddRequiredVariable<string>("redmineHost",
                                                                            "Specifies the host, which serves the Redmine instance");
      var redmineApiKey = requiredValuesOptionSet.AddRequiredVariable<string>("redmineApiKey",
                                                                              "Specifies the api key that is used for communication with the Redmine instance");
      var ignoreBranchIssues = requiredValuesOptionSet.AddVariable<bool>("ignoreBranchIssues",
                                                                         "Specifies whether issues, comitted to the branch, should be ignored or not. Default is false");
      var consoleManager = new ConsoleManager("ChangeLog Generator",
                                              requiredValuesOptionSet);
      if (!consoleManager.TryParseOrShowHelp(Console.Out,
                                             args))
      {
        return;
      }

      Console.WriteLine("Getting the initial revision of {0}",
                        branch.Value);
      var initialLogItem = Program.GetInitialLogItem(repository,
                                                     branch);
      if (initialLogItem == null)
      {
        Console.WriteLine("Could not get the initial revision of {0}",
                          branch.Value);
        return;
      }

      long[] branchIssueIds;
      if (ignoreBranchIssues)
      {
        Console.WriteLine("Getting log for {0} since {1} ({2})",
                          branch.Value,
                          initialLogItem.Revision,
                          initialLogItem.Time);
        var branchLogItems = Program.GetLogSince(repository,
                                                 branch,
                                                 initialLogItem.Revision);
        branchIssueIds = branchLogItems.SelectMany(arg => arg.GetIssueIds())
                                       .Distinct()
                                       .ToArray();
      }
      else
      {
        branchIssueIds = new long[0];
      }

      var revision = initialLogItem.ChangedPaths.Max(arg => arg.CopyFromRevision);
      Console.WriteLine("Getting log for {0} since {1}",
                        trunk.Value,
                        revision);
      var logItems = Program.GetLogSince(repository,
                                         trunk,
                                         revision);

      var complexIssueIds = logItems.SelectMany(arg => arg.GetIssueIds()
                                                          .Except(branchIssueIds)
                                                          .Select(issueId => new
                                                                             {
                                                                               LogItem = arg,
                                                                               IssueId = issueId
                                                                             }))
                                    .OrderBy(arg => arg.IssueId)
                                    .GroupBy(arg => arg.IssueId)
                                    .ToDictionary(arg => arg.Key);

      Console.WriteLine("Getting the issues for {0} since {1} ({3}) from {2}",
                        trunk.Value,
                        revision,
                        redmineHost.Value,
                        initialLogItem.Time);
      var issues = Program.GetIssues(redmineHost,
                                     redmineApiKey,
                                     complexIssueIds.Keys);

      issues.ForEach(issue =>
                     {
                       Console.WriteLine("#{0}: {1} (assigned to: {2}, commits by: {3})",
                                         issue.Id,
                                         issue.Subject,
                                         issue.AssignedTo?.Name ?? "none",
                                         string.Join(", ",
                                                     complexIssueIds[issue.Id].Select(arg => arg.LogItem)
                                                                              .Select(arg => arg.Author)
                                                                              .Distinct()));
                     });
    }
Beispiel #18
0
        private static void Main(string[] args)
        {
            // TODO this code is prone to invalid inputs... idc :bikini:

            var requiredValuesOptionSet = new RequiredValuesOptionSet();
            var repository = requiredValuesOptionSet.AddRequiredVariable <string>("repository",
                                                                                  "Specifies the URI to the SVN repository");
            var trunk = requiredValuesOptionSet.AddRequiredVariable <string>("trunk",
                                                                             "Specifies the relative path to the trunk, which is diffed against the <branch> parameter (usually trunk)");
            var branch = requiredValuesOptionSet.AddRequiredVariable <string>("branch",
                                                                              "Specifies the relative path to the branch, whose initial revision is used as the offset for the change log");
            var redmineHost = requiredValuesOptionSet.AddRequiredVariable <string>("redmineHost",
                                                                                   "Specifies the host, which serves the Redmine instance");
            var redmineApiKey = requiredValuesOptionSet.AddRequiredVariable <string>("redmineApiKey",
                                                                                     "Specifies the api key that is used for communication with the Redmine instance");
            var ignoreBranchIssues = requiredValuesOptionSet.AddVariable <bool>("ignoreBranchIssues",
                                                                                "Specifies whether issues, comitted to the branch, should be ignored or not. Default is false");
            var consoleManager = new ConsoleManager("ChangeLog Generator",
                                                    requiredValuesOptionSet);

            if (!consoleManager.TryParseOrShowHelp(Console.Out,
                                                   args))
            {
                return;
            }

            Console.WriteLine("Getting the initial revision of {0}",
                              branch.Value);
            var initialLogItem = Program.GetInitialLogItem(repository,
                                                           branch);

            if (initialLogItem == null)
            {
                Console.WriteLine("Could not get the initial revision of {0}",
                                  branch.Value);
                return;
            }

            long[] branchIssueIds;
            if (ignoreBranchIssues)
            {
                Console.WriteLine("Getting log for {0} since {1} ({2})",
                                  branch.Value,
                                  initialLogItem.Revision,
                                  initialLogItem.Time);
                var branchLogItems = Program.GetLogSince(repository,
                                                         branch,
                                                         initialLogItem.Revision);
                branchIssueIds = branchLogItems.SelectMany(arg => arg.GetIssueIds())
                                 .Distinct()
                                 .ToArray();
            }
            else
            {
                branchIssueIds = new long[0];
            }

            var revision = initialLogItem.ChangedPaths.Max(arg => arg.CopyFromRevision);

            Console.WriteLine("Getting log for {0} since {1}",
                              trunk.Value,
                              revision);
            var logItems = Program.GetLogSince(repository,
                                               trunk,
                                               revision);

            var complexIssueIds = logItems.SelectMany(arg => arg.GetIssueIds()
                                                      .Except(branchIssueIds)
                                                      .Select(issueId => new
            {
                LogItem = arg,
                IssueId = issueId
            }))
                                  .OrderBy(arg => arg.IssueId)
                                  .GroupBy(arg => arg.IssueId)
                                  .ToDictionary(arg => arg.Key);

            Console.WriteLine("Getting the issues for {0} since {1} ({3}) from {2}",
                              trunk.Value,
                              revision,
                              redmineHost.Value,
                              initialLogItem.Time);
            var issues = Program.GetIssues(redmineHost,
                                           redmineApiKey,
                                           complexIssueIds.Keys);

            issues.ForEach(issue =>
            {
                Console.WriteLine("#{0}: {1} (assigned to: {2}, commits by: {3})",
                                  issue.Id,
                                  issue.Subject,
                                  issue.AssignedTo?.Name ?? "none",
                                  string.Join(", ",
                                              complexIssueIds[issue.Id].Select(arg => arg.LogItem)
                                              .Select(arg => arg.Author)
                                              .Distinct()));
            });
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ConsoleManager"/> class using -? as the help flag
 /// </summary>
 /// <param name="os">The os.</param>
 /// <param name="consoleName">Name of the console.</param>
 public ConsoleManager(RequiredValuesOptionSet os, string consoleName)
     : this(os, consoleName, "?", new string[] { })
 {
 }