public async void Should_Output_ReleaseNote()
    {
        // Given
        var options = new ReleaseOptions {
            MileStone = "v1.0.0", Owner = "root", Repository = "test"
        };
        var dbContext = EnsureDbCreated(options);
        var service   = new ReleaseService(dbContext, FakeConsole);

        // When
        var result = await service.Execute(options, new Mock <IGitHubClient>().Object);

        // Then
        Assert.Equal(0, result);
        Assert.Single(FakeConsole.Messages);
        Assert.Equal(
            @"As part of this release we had 3 issues closed.
The highest priority among them is ""high"".

### Bug
* Found a bug! #1
* Another bug #2

### Enhancement
* Some improvement on build #3

",
            FakeConsole.Messages[0],
            ignoreLineEndingDifferences: true);

        Assert.Empty(FakeConsole.WarnMessages);
        Assert.Empty(FakeConsole.ErrorMessages);
    }
    public async void PullRequest_Already_Exists()
    {
        // Given
        var options = new ReleaseOptions {
            CreatePullRequest = true, MileStone = "v1.0.0", Owner = "root", Repository = "test"
        };
        var dbContext       = EnsureDbCreated(options);
        var service         = new ReleaseService(dbContext, FakeConsole);
        var gitbucketClient = new Mock <IGitHubClient>();

        gitbucketClient
        .Setup(g => g.PullRequest.GetAllForRepository(It.IsAny <string>(), It.IsAny <string>()))
        .ReturnsAsync(new ReadOnlyCollection <Octokit.PullRequest>(new List <Octokit.PullRequest>
        {
            new FakePullRequest(new FakeGitReference("develop"), new FakeGitReference("master"))
        }));

        // When
        var result = await service.Execute(options, gitbucketClient.Object);

        // Then
        Assert.Equal(1, result);
        Assert.Empty(FakeConsole.Messages);
        Assert.Single(FakeConsole.WarnMessages);
        Assert.Equal("A pull request already exists for root:develop.", FakeConsole.WarnMessages[0]);
        Assert.Empty(FakeConsole.ErrorMessages);
    }
예제 #3
0
    private async Task <int> CreatePullRequest(
        ReleaseOptions options,
        List <Core.Models.Issue> issues,
        List <Core.Models.IssueLabel> issueLabels,
        string pullRequestSource,
        List <Core.Models.Label> labels,
        IGitHubClient gitBucketClient)
    {
        // Check if specified pull request already exists
        var pullRequests = await gitBucketClient.PullRequest.GetAllForRepository(options.Owner, options.Repository);

        if (pullRequests.Any(p => p.Head.Ref == options.Head && p.Base.Ref == options.Base))
        {
            _console.WriteWarnLine($"A pull request already exists for {options.Owner}:{options.Head}.");
            return(await Task.FromResult(1));
        }

        var releaseNote = CreateReleaseNote(issues, issueLabels, pullRequestSource, labels);

        try
        {
            // Create new pull request
            await gitBucketClient.PullRequest.Create(
                options.Owner,
                options.Repository,
                new NewPullRequest(
                    title : options.Title ?? options.MileStone,
                    head : options.Head,
                    baseRef : options.Base)
            {
                Body  = releaseNote,
                Draft = options.Draft,
            });
        }
        catch (InvalidCastException)
        {
            // Ignore InvalidCastException because of escaped response.
            // https://github.com/gitbucket/gitbucket/issues/2306
        }

        var allPRs = await gitBucketClient.PullRequest.GetAllForRepository(options.Owner, options.Repository);

        var latest = allPRs.OrderByDescending(p => p.Number).First();

        // Add all labels which corresponding issues have.
        // If there is not the same name label, GitBucket creates one automatically.
        await gitBucketClient.Issue.Labels.AddToIssue(
            options.Owner,
            options.Repository,
            latest.Number,
            labels.Select(l => l.LabelName).ToArray());

        _console.WriteLine($"A new pull request has been successfully created!");
        return(await Task.FromResult(0));
    }
예제 #4
0
    private async Task <List <GitBucket.Core.Models.IssueLabel> > FindIssueLabels(
        ReleaseOptions options,
        IEnumerable <GitBucket.Core.Models.Issue> issues)
    {
#pragma warning disable CA1304 // Specify CultureInfo
        // "String.Equals(String, StringComparison)" causes client side evaluation.
        // https://github.com/aspnet/EntityFrameworkCore/issues/1222
        return(await _context.Set <GitBucket.Core.Models.IssueLabel>()
               .Where(l => l.UserName.ToLower() == options.Owner.ToLower())
               .Where(l => l.RepositoryName.ToLower() == options.Repository.ToLower())
               .Where(l => issues.Select(i => i.IssueId).Contains(l.IssueId))
               .AsNoTracking()
               .ToListAsync());
    }
예제 #5
0
    private List <Core.Models.Label> FindLabels(ReleaseOptions options, List <IssueLabel> issueLabels)
    {
#pragma warning disable CA1304 // Specify CultureInfo

        return(_context.Set <Core.Models.Label>()
               .Where(l =>
                      l.UserName.ToLower() == options.Owner.ToLower() &&
                      l.RepositoryName.ToLower() == options.Repository.ToLower() &&
                      issueLabels.Select(i => i.LabelId).Contains(l.LabelId))
               .OrderBy(i => i.LabelId)
               .AsNoTracking()
               .ToList());

#pragma warning restore CA1304 // Specify CultureInfo
    }
예제 #6
0
    public async Task <int> Execute(ReleaseOptions options, IGitHubClient gitBucketClient)
    {
        ArgumentNullException.ThrowIfNull(options);
        ArgumentNullException.ThrowIfNull(gitBucketClient);

        var pullRequestSource = options.FromPullRequest ? "pull requests" : "issues";
        var issues            = await FindIssuesRelatedToMileStone(options);

        if (!issues.Any())
        {
            _console.WriteWarnLine($"There are no {pullRequestSource} related to \"{options.MileStone}\".");
            return(await Task.FromResult(1));
        }

        if (!options.Force && issues.Any(i => !i.Closed))
        {
            _console.WriteWarnLine($"There are unclosed {pullRequestSource} in \"{options.MileStone}\".");
            _console.WriteWarn("Do you want to continue?([Y]es/[N]o): ");
            var yesOrNo = _console.ReadLine();

            if (!string.Equals(yesOrNo, "y", StringComparison.OrdinalIgnoreCase) &&
                !string.Equals(yesOrNo, "yes", StringComparison.OrdinalIgnoreCase))
            {
                return(await Task.FromResult(1));
            }

            _console.WriteLine("");
        }

        var issueLabels = await FindIssueLabels(options, issues);

        if (issues.Any(i => !issueLabels.Select(l => l.IssueId).Contains(i.IssueId)))
        {
            _console.WriteWarnLine($"There are issues which have no labels in \"{options.MileStone}\".");
            return(await Task.FromResult(1));
        }

        var labels = FindLabels(options, issueLabels);

        if (options.CreatePullRequest)
        {
            return(await CreatePullRequest(options, issues, issueLabels, pullRequestSource, labels, gitBucketClient));
        }
        else
        {
            return(await OutputReleaseNote(issues, issueLabels, pullRequestSource, labels));
        }
    }
    public async void Milestone_Has_Issue_Without_Labels()
    {
        // Given
        var options = new ReleaseOptions {
            MileStone = "v1.0.0", Owner = "root", Repository = "test"
        };
        var dbContextOptions = new DbContextOptionsBuilder <GitBucketDbContext>()
                               .UseInMemoryDatabase(databaseName: "Milestone_Has_Issue_Without_Labels")
                               .Options;

        var dbContext = new GitBucketDbContext(dbContextOptions);

        dbContext.Issues.Add(new Core.Models.Issue
        {
            Milestone = new Core.Models.Milestone
            {
                RepositoryName = options.Repository,
                Title          = options.MileStone,
                UserName       = options.Owner,
            },
            RepositoryName = options.Repository,
            UserName       = options.Owner,
            OpenedUserName = "******",
            Title          = "Implement xxx feature",
        });

        dbContext.SaveChanges();

        var service = new ReleaseService(dbContext, FakeConsole);

        // When
        var result = await service.Execute(options, new Mock <IGitHubClient>().Object);

        // Then
        Assert.Equal(1, result);
        Assert.Single(FakeConsole.Messages);
        Assert.Equal("", FakeConsole.Messages[0]);

        Assert.Equal(3, FakeConsole.WarnMessages.Count);
        Assert.Equal("There are unclosed issues in \"v1.0.0\".", FakeConsole.WarnMessages[0]);
        Assert.Equal("Do you want to continue?([Y]es/[N]o): yes", FakeConsole.WarnMessages[1]);
        Assert.Equal("There are issues which have no labels in \"v1.0.0\".", FakeConsole.WarnMessages[2]);

        Assert.Empty(FakeConsole.ErrorMessages);
    }
예제 #8
0
        private void ReleaseAllConfigurations(ICheckNotifier notifier, params ExtractionConfiguration[] extractionConfigurations)
        {
            var releasePipeline = _repos.CatalogueRepository.GetAllObjects <Pipeline>().FirstOrDefault(p => p?.Destination?.Class == typeof(BasicDataReleaseDestination).FullName);

            try
            {
                //cleanup any old releases
                var project = extractionConfigurations.Select(ec => ec.Project).Distinct().Single();

                var folderProvider = new ReleaseFolderProvider();
                var dir            = folderProvider.GetFromProjectFolder(project);
                if (dir.Exists)
                {
                    dir.Delete(true);
                }
            }
            catch (Exception ex)
            {
                notifier.OnCheckPerformed(new CheckEventArgs("Could not detect/delete release folder for extractions", CheckResult.Warning, ex));
                return;
            }


            if (releasePipeline != null)
            {
                try
                {
                    var optsRelease = new ReleaseOptions()
                    {
                        Configurations = extractionConfigurations.Select(ec => ec.ID).Distinct().ToArray(),
                        Pipeline       = releasePipeline.ID
                    };

                    var runnerRelease = new ReleaseRunner(optsRelease);
                    runnerRelease.Run(_repos, new ThrowImmediatelyDataLoadEventListener(), notifier, new GracefulCancellationToken());
                }
                catch (Exception ex)
                {
                    notifier.OnCheckPerformed(new CheckEventArgs("Could not Release ExtractionConfiguration (nevermind)", CheckResult.Warning, ex));
                }
            }
        }
예제 #9
0
        public NewProfileVM(ConfigurationVM config, Action <ProfileVM> postRun)
        {
            ReleaseOptions.AddRange(EnumExt.GetValues <GameRelease>());

            this.WhenAnyValue(x => x.SelectedGame)
            .Subscribe(game =>
            {
                if (game == null)
                {
                    return;
                }
                var profile = new ProfileVM(config, game.Value)
                {
                    Nickname = Nickname
                };
                config.Profiles.AddOrUpdate(profile);
                postRun(profile);
            })
            .DisposeWith(this);
        }
예제 #10
0
    public async void Milestone_Has_No_PullRequest()
    {
        // Given
        var dbContextOptions = new DbContextOptionsBuilder <GitBucketDbContext>()
                               .UseInMemoryDatabase(databaseName: "Milestone_Has_No_PullRequest")
                               .Options;

        var dbContext = new GitBucketDbContext(dbContextOptions);
        var options   = new ReleaseOptions {
            FromPullRequest = true, MileStone = "v1.0.0", Owner = "root", Repository = "test"
        };
        var service = new ReleaseService(dbContext, FakeConsole);

        // When
        var result = await service.Execute(options, new Mock <IGitHubClient>().Object);

        // Then
        Assert.Equal(1, result);
        Assert.Empty(FakeConsole.Messages);
        Assert.Single(FakeConsole.WarnMessages);
        Assert.Empty(FakeConsole.ErrorMessages);
        Assert.Equal("There are no pull requests related to \"v1.0.0\".", FakeConsole.WarnMessages[0]);
    }
예제 #11
0
    private static GitBucketDbContext EnsureDbCreated(ReleaseOptions options)
    {
        var dbContextOptions = new DbContextOptionsBuilder <GitBucketDbContext>()
                               .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
                               .Options;

        var dbContext = new GitBucketDbContext(dbContextOptions);

        var milestone = new Core.Models.Milestone
        {
            RepositoryName = options.Repository,
            Title          = options.MileStone,
            UserName       = options.Owner,
        };

        var highPriority = new Core.Models.Priority
        {
            Ordering       = 0,
            PriorityName   = "high",
            RepositoryName = options.Repository,
            UserName       = options.Owner,
            Color          = "red",
        };

        var defaultPriority = new Core.Models.Priority
        {
            Ordering       = 1,
            PriorityName   = "default",
            RepositoryName = options.Repository,
            UserName       = options.Owner,
            Color          = "red",
        };

        dbContext.Issues.AddRange(new List <Core.Models.Issue>
        {
            new Core.Models.Issue
            {
                Closed         = true,
                IssueId        = 1,
                Milestone      = milestone,
                Priority       = highPriority,
                RepositoryName = options.Repository,
                Title          = "Found a bug!",
                UserName       = options.Owner,
                OpenedUserName = "******",
            },
            new Core.Models.Issue
            {
                Closed         = true,
                IssueId        = 2,
                Milestone      = milestone,
                Priority       = defaultPriority,
                RepositoryName = options.Repository,
                Title          = "Another bug",
                UserName       = options.Owner,
                OpenedUserName = "******",
            },
            new Core.Models.Issue
            {
                Closed         = true,
                IssueId        = 3,
                Milestone      = milestone,
                Priority       = defaultPriority,
                RepositoryName = options.Repository,
                Title          = "Some improvement on build",
                UserName       = options.Owner,
                OpenedUserName = "******",
            },
            new Core.Models.Issue
            {
                Closed         = true,
                IssueId        = 4,
                Milestone      = milestone,
                Priority       = defaultPriority,
                PullRequest    = true,
                RepositoryName = options.Repository,
                Title          = "Fix a bug",
                UserName       = options.Owner,
                OpenedUserName = "******",
            }
        });

        dbContext.IssueLabels.AddRange(new List <Core.Models.IssueLabel>
        {
            new Core.Models.IssueLabel
            {
                IssueId        = 1,
                LabelId        = 10,
                RepositoryName = options.Repository,
                UserName       = options.Owner,
            },
            new Core.Models.IssueLabel
            {
                IssueId        = 2,
                LabelId        = 10,
                RepositoryName = options.Repository,
                UserName       = options.Owner,
            },
            new Core.Models.IssueLabel
            {
                IssueId        = 3,
                LabelId        = 30,
                RepositoryName = options.Repository,
                UserName       = options.Owner,
            },
            new Core.Models.IssueLabel
            {
                IssueId        = 4,
                LabelId        = 10,
                RepositoryName = options.Repository,
                UserName       = options.Owner,
            }
        });

        dbContext.Labels.AddRange(new List <Core.Models.Label>
        {
            new Core.Models.Label
            {
                LabelId        = 10,
                LabelName      = "Bug",
                RepositoryName = options.Repository,
                UserName       = options.Owner,
                Color          = "red",
            },
            new Core.Models.Label
            {
                LabelId        = 30,
                LabelName      = "Enhancement",
                RepositoryName = options.Repository,
                UserName       = options.Owner,
                Color          = "red",
            }
        });

        dbContext.SaveChanges();
        return(dbContext);
    }
예제 #12
0
    public async void Should_Create_PullRequest_With_Different_Options()
    {
        // Given
        var options = new ReleaseOptions
        {
            Base = "release/v1.0.0",
            CreatePullRequest = true,
            FromPullRequest   = true,
            Head       = "master2",
            MileStone  = "v1.0.0",
            Owner      = "root",
            Repository = "test",
            Title      = "Amazing PR",
        };

        var dbContext       = EnsureDbCreated(options);
        var service         = new ReleaseService(dbContext, FakeConsole);
        var gitbucketClient = new Mock <IGitHubClient>();

        gitbucketClient
        .SetupSequence(g => g.PullRequest.GetAllForRepository(It.IsAny <string>(), It.IsAny <string>()))
        .ReturnsAsync(new ReadOnlyCollection <Octokit.PullRequest>(new List <Octokit.PullRequest>
        {
            new FakePullRequest(new FakeGitReference("improve-performance"), new FakeGitReference("master"))
        }))
        .ReturnsAsync(new ReadOnlyCollection <Octokit.PullRequest>(new List <Octokit.PullRequest>
        {
            new FakePullRequest(new FakeGitReference("improve-performance"), new FakeGitReference("master")),
            new FakePullRequest(new FakeGitReference("release/v1.0.0"), new FakeGitReference("master"), 2)
        }));

        var body = string.Empty;

        gitbucketClient
        .Setup(g => g.PullRequest.Create(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <NewPullRequest>()))
        .Callback((string owner, string name, NewPullRequest newPullRequest) => body = newPullRequest.Body)
        .ThrowsAsync(new InvalidCastException("Ignore InvalidCastException because of escaped response."));

        gitbucketClient.Setup(g => g.Issue.Labels.AddToIssue(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <int>(), It.IsAny <string[]>()));

        // When
        var result = await service.Execute(options, gitbucketClient.Object);

        // Then
        Assert.Equal(0, result);

        gitbucketClient
        .Verify(g => g.PullRequest.Create(
                    It.Is <string>(o => o == "root"),
                    It.Is <string>(r => r == "test"),
                    It.Is <NewPullRequest>(p =>
                                           p.Title == "Amazing PR" &&
                                           p.Head == "master2" &&
                                           p.Base == "release/v1.0.0")));

        Assert.Equal(@"As part of this release we had 1 pull requests closed.
The highest priority among them is ""default"".

### Bug
* Fix a bug #4

",
                     body,
                     ignoreLineEndingDifferences: true);

        Assert.Single(FakeConsole.Messages);
        Assert.Equal("A new pull request has been successfully created!", FakeConsole.Messages[0]);
        Assert.Empty(FakeConsole.WarnMessages);
        Assert.Empty(FakeConsole.ErrorMessages);
    }
예제 #13
0
    public async void Should_Create_Draft_PullRequest()
    {
        // Given
        var options = new ReleaseOptions {
            Draft = true, CreatePullRequest = true, MileStone = "v1.0.0", Owner = "root", Repository = "test"
        };
        var dbContext = EnsureDbCreated(options);

        dbContext.PullRequests.AddRange(new List <Core.Models.PullRequest>
        {
            new Core.Models.PullRequest {
                UserName = "******", RepositoryName = "test", RequestBranch = "develop", Branch = "master", IssueId = 1, CommitIdFrom = "test", CommitIdTo = "test", RequestRepositoryName = "test", RequestUserName = "******"
            },
            new Core.Models.PullRequest {
                UserName = "******", RepositoryName = "test", RequestBranch = "develop", Branch = "master", IssueId = 2, CommitIdFrom = "test", CommitIdTo = "test", RequestRepositoryName = "test", RequestUserName = "******"
            },
        });
        dbContext.SaveChanges();

        var service         = new ReleaseService(dbContext, FakeConsole);
        var gitbucketClient = new Mock <IGitHubClient>();

        gitbucketClient
        .SetupSequence(g => g.PullRequest.GetAllForRepository(It.IsAny <string>(), It.IsAny <string>()))
        .ReturnsAsync(new ReadOnlyCollection <Octokit.PullRequest>(new List <Octokit.PullRequest>()))
        .ReturnsAsync(new ReadOnlyCollection <Octokit.PullRequest>(new List <Octokit.PullRequest>
        {
            new FakePullRequest(new FakeGitReference("develop"), new FakeGitReference("master"), 2)
        }));

        var  body    = string.Empty;
        bool?isDraft = null;

        gitbucketClient
        .Setup(g => g.PullRequest.Create(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <NewPullRequest>()))
        .Callback((string owner, string name, NewPullRequest newPullRequest) =>
        {
            body    = newPullRequest.Body;
            isDraft = newPullRequest.Draft;
        })
        .ThrowsAsync(new InvalidCastException("Ignore InvalidCastException because of escaped response."));

        gitbucketClient.Setup(g => g.Issue.Labels.AddToIssue(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <int>(), It.IsAny <string[]>()));

        // When
        var result = await service.Execute(options, gitbucketClient.Object);

        // Then
        Assert.Equal(0, result);

        gitbucketClient
        .Verify(g => g.PullRequest.Create(
                    It.Is <string>(o => o == "root"),
                    It.Is <string>(r => r == "test"),
                    It.Is <NewPullRequest>(p =>
                                           p.Title == "v1.0.0" &&
                                           p.Head == "develop" &&
                                           p.Base == "master")));

        Assert.Equal(@"As part of this release we had 3 issues closed.
The highest priority among them is ""high"".

### Bug
* Found a bug! #1
* Another bug #2

### Enhancement
* Some improvement on build #3

",
                     body,
                     ignoreLineEndingDifferences: true);

        Assert.Single(FakeConsole.Messages);
        Assert.Equal("A new pull request has been successfully created!", FakeConsole.Messages[0]);
        Assert.Empty(FakeConsole.WarnMessages);
        Assert.Empty(FakeConsole.ErrorMessages);
        Assert.True(isDraft);
    }
예제 #14
0
 public ReleaseRunner(ReleaseOptions options) : base(options)
 {
     _options = options;
 }
예제 #15
0
    private async Task <List <GitBucket.Core.Models.Issue> > FindIssuesRelatedToMileStone(ReleaseOptions options)
    {
        // "String.Equals(String, StringComparison)" causes client side evaluation.
        // https://github.com/aspnet/EntityFrameworkCore/issues/1222
        return(await _context.Set <GitBucket.Core.Models.Issue>()
               .Where(i => i.UserName.ToLower() == options.Owner.ToLower())
               .Where(i => i.RepositoryName.ToLower() == options.Repository.ToLower())
               .Where(i => i.Milestone !.Title.ToLower() == options.MileStone.ToLower())
               .Where(i => i.PullRequest == options.FromPullRequest)
               .Include(i => i.Milestone)
               .Include(i => i.Priority)
               .AsNoTracking()
               .ToListAsync());

#pragma warning restore CA1304 // Specify CultureInfo
    }