public void CloneReleaseEnvironmentWithId_ExistingTargetEnv_ErrorMessage()
        {
            TfsInfo info = new TfsInfo()
            {
                ProjectCollectionUrl  = ProjectCollectionUrl,
                ProjectName           = ProjectName,
                ReleaseDefinitionName = ReleaseDefinitionName
            };

            using (TfsRelease tfsRelease = new TfsRelease(info, pat))
            {
                string result = tfsRelease.CloneReleaseEnvironment("Env1", "Env0", 0);
                Assert.Equal($"**Warning** An Env with name \"Env0\" already exists", result);
            };
        }
        public void GetDeploymentErrors_Data_NoErrors(int value)
        {
            TfsInfo info = new TfsInfo()
            {
                ProjectCollectionUrl  = ProjectCollectionUrl,
                ProjectName           = ProjectName,
                ReleaseDefinitionName = ReleaseDefinitionName
            };

            using (TfsRelease tfsRelease = new TfsRelease(info, pat))
            {
                string result = tfsRelease.GetDeploymentErrors(value);
                Assert.Equal($"**Warning** No errors found", result);
            };
        }
        public void GetTfsReleaseEnvironmentNames_FakeRelease_ErrorMessage()
        {
            TfsInfo info = new TfsInfo()
            {
                ProjectCollectionUrl  = ProjectCollectionUrl,
                ProjectName           = ProjectName,
                ReleaseDefinitionName = "FakeRelease"
            };

            using (TfsRelease tfsRelease = new TfsRelease(info, pat))
            {
                string result = tfsRelease.GetTfsReleaseEnvironmentNames();
                Assert.Equal($"**Warning** Failed to find Release Definition with name \"{info.ReleaseDefinitionName}\"", result);
            };
        }
        public void CloneReleaseEnvironmentWithId_FakeEnv_ErrorMessage()
        {
            TfsInfo info = new TfsInfo()
            {
                ProjectCollectionUrl  = ProjectCollectionUrl,
                ProjectName           = ProjectName,
                ReleaseDefinitionName = ReleaseDefinitionName
            };

            using (TfsRelease tfsRelease = new TfsRelease(info, pat))
            {
                string result = tfsRelease.CloneReleaseEnvironment("FakeEnv", "DoesntMatter1", 0);
                Assert.Equal($"**Warning** Failed to find Env with name \"FakeEnv\"", result);
            };
        }
        public void CloneReleaseEnvironmentWithId_ValidInput_Success()
        {
            TfsInfo info = new TfsInfo()
            {
                ProjectCollectionUrl  = ProjectCollectionUrl,
                ProjectName           = ProjectName,
                ReleaseDefinitionName = ReleaseDefinitionName
            };

            using (TfsRelease tfsRelease = new TfsRelease(info, pat))
            {
                string  result = tfsRelease.CloneReleaseEnvironment("Env1", "Envz_01", 0);
                dynamic obj    = JObject.Parse(result);
                Assert.True((bool)obj.success);
            };
        }
        public void GetTfsReleaseEnvironmentNames_TestRelease_OneItem()
        {
            TfsInfo info = new TfsInfo()
            {
                ProjectCollectionUrl  = ProjectCollectionUrl,
                ProjectName           = ProjectName,
                ReleaseDefinitionName = ReleaseDefinitionNameOneEnv
            };

            using (TfsRelease tfsRelease = new TfsRelease(info, pat))
            {
                string  result = tfsRelease.GetTfsReleaseEnvironmentNames();
                dynamic obj    = JObject.Parse(result);
                Assert.Equal(1, obj.EnvironmentNames.Count);
            };
        }
        public void GetDeploymentErrors_ExistingError_OneError()
        {
            TfsInfo info = new TfsInfo()
            {
                ProjectCollectionUrl  = ProjectCollectionUrl,
                ProjectName           = ProjectName,
                ReleaseDefinitionName = ReleaseDefinitionName
            };

            using (TfsRelease tfsRelease = new TfsRelease(info, pat))
            {
                string  result = tfsRelease.GetDeploymentErrors(1);
                dynamic obj    = JArray.Parse(result);
                Assert.Equal(1, obj.Count);
            };
        }
        public void GetDeploymentErrors_ImpossibleDates_NoErrors()
        {
            TfsInfo info = new TfsInfo()
            {
                ProjectCollectionUrl  = ProjectCollectionUrl,
                ProjectName           = ProjectName,
                ReleaseDefinitionName = ReleaseDefinitionName
            };

            using (TfsRelease tfsRelease = new TfsRelease(info, pat))
            {
                DateTime dtstart = new DateTime(2018, 10, 10);
                DateTime dtend   = new DateTime(2018, 9, 10);
                string   result  = tfsRelease.GetDeploymentErrors(dtstart, dtend);
                Assert.Equal($"**Warning** No errors found", result);
            };
        }
        public void GetDeploymentErrors_ValidDateRangeWithOne_OneError()
        {
            TfsInfo info = new TfsInfo()
            {
                ProjectCollectionUrl  = ProjectCollectionUrl,
                ProjectName           = ProjectName,
                ReleaseDefinitionName = ReleaseDefinitionName
            };

            using (TfsRelease tfsRelease = new TfsRelease(info, pat))
            {
                DateTime dtstart = new DateTime(2018, 10, 31);
                DateTime dtend   = new DateTime(2018, 11, 2);
                string   result  = tfsRelease.GetDeploymentErrors(dtstart, dtend);
                dynamic  obj     = JArray.Parse(result);
                Assert.Equal(1, obj.Count);
            };
        }
        public static string DeleteReleaseEnvironment(TfsInfo info, string pat, string SourceEnvName)
        {
            using (TfsRelease tfsRelease = new TfsRelease(info, pat))
            {
                VssConnection connection = new VssConnection(new Uri(info.ProjectCollectionUrl), new VssBasicCredential(string.Empty, pat));
                var           relclient  = connection.GetClient <ReleaseHttpClient>();
                var           projclient = connection.GetClient <ProjectHttpClient>();

                string result = "";

                var definitions = relclient.GetReleaseDefinitionsAsync(info.ProjectName, info.ReleaseDefinitionName, ReleaseDefinitionExpands.Environments, isExactNameMatch: true).Result;

                if (definitions.Count() > 0)
                {
                    //This call is to get the project GUID
                    var project = projclient.GetProject(info.ProjectName).Result;
                    //This returns everything in a definition including properties such as Owner in an Environment
                    var def = relclient.GetReleaseDefinitionAsync(project.Id, definitions.First().Id).Result;

                    var envcount = def.Environments.Count;

                    var defenvlist = def.Environments.Where(e => e.Name == SourceEnvName);
                    if (defenvlist.Count() > 0)
                    {
                        var source = defenvlist.First();

                        foreach (var env in def.Environments)
                        {
                            if (env.Rank > source.Rank)
                            {
                                env.Rank--;
                            }
                        }

                        def.Environments.Remove(source);

                        var newdef = relclient.UpdateReleaseDefinitionAsync(def, project.Id).Result;

                        var envinfo = new TfsCloneReleaseEnvInfo()
                        {
                            ReleaseName         = newdef.Name,
                            EnvironmentName     = source.Name,
                            RetentionPolicy     = source.RetentionPolicy.ToString(),
                            Rank                = source.Rank,
                            Owner               = source.Owner.DisplayName,
                            PreDeployApprovals  = source.PreDeployApprovals.Approvals.Where(e => e.Approver != null).OrderBy(e => e.Approver.DisplayName).Select(e => e.Approver.DisplayName).ToArray(),
                            PostDeployApprovals = source.PostDeployApprovals.Approvals.Where(e => e.Approver != null).OrderBy(e => e.Approver.DisplayName).Select(e => e.Approver.DisplayName).ToArray(),
                            DeployPhases        = source.DeployPhases.OrderBy(e => e.Name).Select(e => e.Name).ToArray(),
                            success             = (newdef.Environments.Count < envcount) ? true : false //Basic detection if environment was added
                        };

                        result = JsonConvert.SerializeObject(envinfo, Formatting.Indented);
                    }
                    else
                    {
                        result = $"**Warning** Failed to find Env with name \"{SourceEnvName}\"";
                    }
                }
                else
                {
                    result = $"**Warning** Failed to find Release Definition with name \"{info.ReleaseDefinitionName}\"";
                }

                return(result);
            }
        }
示例#11
0
        static void Main(string[] args)
        {
            // Instantiate the command line app
            var app = new CommandLineApplication();

            // Command line info used by help
            app.Name             = "ReleaseUtil";
            app.Description      = "Command line util that utilizes the ReleaseHelper library.";
            app.ExtendedHelpText = "This is a command line util to help streamline the process of getting information and errors about releases."
                                   + Environment.NewLine + "It utilizes the ReleaseHelper library.  The application can be executed by running the ReleaseUtil.exe.";

            // Set the arguments to display the description and help text
            app.HelpOption("-?|-h|--help");

            // This is a helper/shortcut method to display version info
            // The default help text is "Show version Information"
            app.VersionOption("-v|--version", () => {
                return(Assembly.GetEntryAssembly().GetName().Version.ToString());
            });

            // When no commands are specified, this block will execute
            app.OnExecute(() =>
            {
                app.ShowHint();
                return(0);
            });

            // Errors command to show release errors
            app.Command("errors", (command) =>
            {
                command.ExtendedHelpText = "The errors command can be used to return error information experienced by releases.";
                command.Description      = "Errors command used to return Azure Devops/TFS release errors.";
                command.HelpOption("-?|-h|--help");

                // Project collection url options: REQUIRED
                var optionProjectCollectionUrl = command.Option("-p|--project-collection-url",
                                                                "Required - project collection url",
                                                                CommandOptionType.MultipleValue).IsRequired();

                // Project name options: REQUIRED
                var optionProjectName = command.Option("-n|--project-name",
                                                       "Required - project name",
                                                       CommandOptionType.MultipleValue).IsRequired();

                // Release definition name options: REQUIRED
                var optionReleaseDefinitionName = command.Option("-r|--release-definition-name",
                                                                 "Required - release definition name",
                                                                 CommandOptionType.SingleValue).IsRequired();

                /*
                 * // Personal access token options
                 * var optionPersonalAccessToken = command.Option("-pat|--personal-access-token",
                 *  "When provided, will authenticate utilizing a token instead of prompting for user credentials",
                 *  CommandOptionType.SingleValue).IsRequired();
                 */

                // Top count options
                var optionTopCount = command.Option("-t|--top",
                                                    "Top count option to specify how many errors to return",
                                                    CommandOptionType.SingleValue);

                // Date range options
                var optionDateRange = command.Option("-d|--date-range",
                                                     "Ability to filter by providing a date range.  Must provide both a start and end date",
                                                     CommandOptionType.MultipleValue);

                // Release name options
                var optionReleaseName = command.Option("-rn|--release-name",
                                                       "Ability to filter by release name",
                                                       CommandOptionType.SingleValue);

                // Environment name options
                var optionEnvironmentName = command.Option("-e|--environment-name",
                                                           "Ability to filter by environment name",
                                                           CommandOptionType.SingleValue);


                command.OnExecute(() =>
                {
                    //Default top count to 100 and update it if top count option provided
                    int topcount = 100;
                    if (optionTopCount.HasValue())
                    {
                        topcount = Convert.ToInt32(optionTopCount.Value());
                    }

                    // These are all required options for command and we can assume they all
                    // have values as the command would stop if one was not provided
                    string optionProjectCollectionUrlValue  = optionProjectCollectionUrl.Value();
                    string optionProjectNameValue           = optionProjectName.Value();
                    string optionReleaseDefinitionNameValue = optionReleaseDefinitionName.Value();

                    TfsInfo info = new TfsInfo()
                    {
                        ProjectCollectionUrl  = optionProjectCollectionUrlValue,
                        ProjectName           = optionProjectNameValue,
                        ReleaseDefinitionName = optionReleaseDefinitionNameValue
                    };

                    using (TfsRelease tfsRelease = new TfsRelease(info))
                    {
                        string result = "";

                        //Date Range option passed in
                        if (optionDateRange.HasValue())
                        {
                            List <string> optionDateRangeValues = optionDateRange.Values;
                            if (optionDateRangeValues.Count > 1)
                            {
                                DateTime startdate = new DateTime();
                                DateTime enddate   = new DateTime();
                                if (DateTime.TryParse(optionDateRangeValues[0], out startdate))
                                {
                                    if (DateTime.TryParse(optionDateRangeValues[1], out enddate))
                                    {
                                        result = tfsRelease.GetDeploymentErrors(startdate, enddate);

                                        if (!result.StartsWith($"**Warning**"))
                                        {
                                            JArray obj = JArray.Parse(result);
                                            result     = JsonConvert.SerializeObject(obj.Take(topcount), Formatting.Indented);
                                        }
                                    }
                                    else
                                    {
                                        result = $"**Warning** Invalid end date supplied to date range option.";
                                    }
                                }
                                else
                                {
                                    result = $"**Warning** Invalid start date supplied to date range option.";
                                }
                            }
                            else
                            {
                                result = $"**Warning** Must provide two dates when using the date range option.";
                            }
                        }
                        else
                        {
                            result = tfsRelease.GetDeploymentErrors(topcount);
                        }

                        //Check to see if any warnings returned
                        if (!result.StartsWith($"**Warning**"))
                        {
                            //Release Name option passed in
                            if (optionReleaseName.HasValue())
                            {
                                JArray obj = JArray.Parse(result);
                                result     = JsonConvert.SerializeObject(obj.Children().Where(e => e.Value <string>("ReleaseName") == optionReleaseName.Value()).ToList(), Formatting.Indented);
                            }

                            //Environment Name option passed in
                            if (optionEnvironmentName.HasValue())
                            {
                                JArray obj = JArray.Parse(result);
                                result     = JsonConvert.SerializeObject(obj.Children().Where(e => e.Value <string>("EnvironmentName") == optionEnvironmentName.Value()).ToList(), Formatting.Indented);
                            }
                        }

                        Console.WriteLine(result);
                    };

                    return(0); // return 0 on a successful execution
                });
            });

            // Stats command to show deployment stats
            app.Command("stats", (command) =>
            {
                command.ExtendedHelpText = "The stats command can be used to return stats information about release deployments.";
                command.Description      = "Stats command used to return Azure Devops/TFS release stats.";
                command.HelpOption("-?|-h|--help");

                // Project collection url options: REQUIRED
                var optionProjectCollectionUrl = command.Option("-p|--project-collection-url",
                                                                "Required - project collection url",
                                                                CommandOptionType.MultipleValue).IsRequired();

                // Project name options: REQUIRED
                var optionProjectName = command.Option("-n|--project-name",
                                                       "Required - project name",
                                                       CommandOptionType.MultipleValue).IsRequired();

                // Release definition name options: REQUIRED
                var optionReleaseDefinitionName = command.Option("-r|--release-definition-name",
                                                                 "Required - release definition name",
                                                                 CommandOptionType.SingleValue).IsRequired();

                /*
                 * // Personal access token options
                 * var optionPersonalAccessToken = command.Option("-pat|--personal-access-token",
                 *  "When provided, will authenticate utilizing a token instead of prompting for user credentials",
                 *  CommandOptionType.SingleValue).IsRequired();
                 */

                // Top count options
                var optionTopCount = command.Option("-t|--top",
                                                    "Top count option to specify how many errors to return",
                                                    CommandOptionType.SingleValue);

                // Date range options
                var optionDateRange = command.Option("-d|--date-range",
                                                     "Ability to filter by providing a date range.  Must provide both a start and end date",
                                                     CommandOptionType.MultipleValue);

                // Release name options
                var optionReleaseName = command.Option("-rn|--release-name",
                                                       "Ability to filter by release name",
                                                       CommandOptionType.SingleValue);

                // Environment name options
                var optionEnvironmentName = command.Option("-e|--environment-name",
                                                           "Ability to filter by environment name",
                                                           CommandOptionType.SingleValue);


                command.OnExecute(() =>
                {
                    //Default top count to 100 and update it if top count option provided
                    int topcount = 100;
                    if (optionTopCount.HasValue())
                    {
                        topcount = Convert.ToInt32(optionTopCount.Value());
                    }

                    // These are all required options for command and we can assume they all
                    // have values as the command would stop if one was not provided
                    string optionProjectCollectionUrlValue  = optionProjectCollectionUrl.Value();
                    string optionProjectNameValue           = optionProjectName.Value();
                    string optionReleaseDefinitionNameValue = optionReleaseDefinitionName.Value();

                    TfsInfo info = new TfsInfo()
                    {
                        ProjectCollectionUrl  = optionProjectCollectionUrlValue,
                        ProjectName           = optionProjectNameValue,
                        ReleaseDefinitionName = optionReleaseDefinitionNameValue
                    };

                    using (TfsRelease tfsRelease = new TfsRelease(info))
                    {
                        string result = "";

                        //Date Range option passed in
                        if (optionDateRange.HasValue())
                        {
                            List <string> optionDateRangeValues = optionDateRange.Values;
                            if (optionDateRangeValues.Count > 1)
                            {
                                DateTime startdate = new DateTime();
                                DateTime enddate   = new DateTime();
                                if (DateTime.TryParse(optionDateRangeValues[0], out startdate))
                                {
                                    if (DateTime.TryParse(optionDateRangeValues[1], out enddate))
                                    {
                                        result = tfsRelease.GetDeploymentStats(startdate, enddate);

                                        if (!result.StartsWith($"**Warning**"))
                                        {
                                            JArray obj = JArray.Parse(result);
                                            result     = JsonConvert.SerializeObject(obj.Take(topcount), Formatting.Indented);
                                        }
                                    }
                                    else
                                    {
                                        result = $"**Warning** Invalid end date supplied to date range option.";
                                    }
                                }
                                else
                                {
                                    result = $"**Warning** Invalid start date supplied to date range option.";
                                }
                            }
                            else
                            {
                                result = $"**Warning** Must provide two dates when using the date range option.";
                            }
                        }
                        else
                        {
                            result = tfsRelease.GetDeploymentStats(topcount);
                        }

                        //Check to see if any warnings returned
                        if (!result.StartsWith($"**Warning**"))
                        {
                            JArray obj         = JArray.Parse(result);
                            var deploymentlist = obj.ToObject <List <TfsDeploymentInfo> >();

                            //Release Name option passed in
                            if (optionReleaseName.HasValue())
                            {
                                deploymentlist = deploymentlist.Where(e => e.ReleaseName == optionReleaseName.Value()).ToList();
                            }

                            //Environment Name option passed in
                            if (optionEnvironmentName.HasValue())
                            {
                                deploymentlist = deploymentlist.Where(e => e.EnvironmentName == optionEnvironmentName.Value()).ToList();
                            }

                            var deploymentscombined = deploymentlist.GroupBy(e => e.StartedOn.Date).Select(
                                g => new
                            {
                                Date               = (g.Key.Year != 0001 ? g.Key.ToString("MM-dd-yyyy") : "Not started"),
                                Undefined          = g.Count(s => s.Status == DeploymentStatus.Undefined),
                                NotDeployed        = g.Count(s => s.Status == DeploymentStatus.NotDeployed),
                                InProgress         = g.Count(s => s.Status == DeploymentStatus.InProgress),
                                Succeeded          = g.Count(s => s.Status == DeploymentStatus.Succeeded),
                                PartiallySucceeded = g.Count(s => s.Status == DeploymentStatus.PartiallySucceeded),
                                Failed             = g.Count(s => s.Status == DeploymentStatus.Failed),
                                TimeTaken          = new TimeSpan(g.Sum(s => s.TimeTaken.Ticks)).ToString(@"dd\.hh\:mm\:ss")
                            }).OrderBy(e => e.Date);

                            //Concat in totals row
                            var deploymentstats = deploymentscombined.Concat(
                                new[] { new
                                        {
                                            Date               = "Total",
                                            Undefined          = deploymentlist.Count(s => s.Status == DeploymentStatus.Undefined),
                                            NotDeployed        = deploymentlist.Count(s => s.Status == DeploymentStatus.NotDeployed),
                                            InProgress         = deploymentlist.Count(s => s.Status == DeploymentStatus.InProgress),
                                            Succeeded          = deploymentlist.Count(s => s.Status == DeploymentStatus.Succeeded),
                                            PartiallySucceeded = deploymentlist.Count(s => s.Status == DeploymentStatus.PartiallySucceeded),
                                            Failed             = deploymentlist.Count(s => s.Status == DeploymentStatus.Failed),
                                            TimeTaken          = new TimeSpan(deploymentlist.Sum(s => s.TimeTaken.Ticks)).ToString(@"dd\.hh\:mm\:ss")
                                        } });

                            result = JsonConvert.SerializeObject(deploymentstats, Formatting.Indented);
                        }

                        Console.WriteLine(result);
                    };

                    return(0); // return 0 on a successful execution
                });
            });

            try
            {
                // This begins the actual execution of the application
                app.Execute(args);
            }
            catch (CommandParsingException ex)
            {
                // You'll always want to catch this exception, otherwise it will generate a messy and confusing error for the end user.
                // the message will usually be something like:
                // "Unrecognized command or argument '<invalid-command>'"
                Console.WriteLine(ex.Message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Unable to execute application: {0}", ex.Message);
            }
        }