mirror of
https://github.com/zoriya/octokit.net.git
synced 2026-06-06 03:55:55 +00:00
Implement Review API for Pull Requests (#1648)
* First Iteration Need to finish tests and docs * Mostly Complete * Fixing tests and adding review comments * Added tests for reactive client * Moved Reviews inside fo the Pull request client for better organization and began initial intigration testing * Fixing bad recursive function breaking tests * test fixes * Add paging support to review comments call * Fixing recursive function * Addressing comments from PR * fixing CI break * Typo build break * Fixing Convention Tests * Adding correct nameof() usage in Ensure * Small consitancy changes * Trigger build * Address PR Comments * Fixup test naming * Fix sub client ordering and incorrect URL * Tidy up comments and remove StringEnum wrapper from Request models as it is only for Response models * Rename GetReview to Get * tweak debugger display * Rework integration tests - implement the easy Get/GetAll ones first... * Implement integration tests for Create method. Move helpers to create PR/review into SetupHelper class Fixed up review status enum to contain correct values Tests for Approve/RequestChanges currently failing as a user cant approve/request changes on their own PR * Implement secondary account settings for integration tests and a new [DualAccountTest] attribute for discovery when configured Change integration test to create PR from the 2nd account, so the main test account is able to perform review actions on the PR * Add integration tests for Delete, Dismiss and Submit methods Fixed up API client implementation for delete (was looking for incorrect 201 http status) Removed unnecessary await/async calls from client implementations that dont need to do anything with the result * Attempting to add comments as part of a review revealed that we cant use the existing PullRequestReviewCommentCreate class as the API throws a validation error due to the CommitId field These newer review APIs need a DraftPullRequestReviewComment (that doesnt have a commitId) instead * add second test account user/password to configure-integration-tests script
This commit is contained in:
committed by
Ryan Gribble
parent
7c170213fd
commit
ff9521ce3d
@@ -44,9 +44,9 @@ public class PullRequestReviewRequestsClientTests
|
||||
[IntegrationTest]
|
||||
public async Task GetsNoRequestsWhenNoneExist()
|
||||
{
|
||||
var pullRequestId = await CreateTheWorld(_github, _context, createReviewRequests: false);
|
||||
var number = await CreateTheWorld(_github, _context, createReviewRequests: false);
|
||||
|
||||
var reviewRequests = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, pullRequestId);
|
||||
var reviewRequests = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, number);
|
||||
|
||||
Assert.NotNull(reviewRequests);
|
||||
Assert.Empty(reviewRequests);
|
||||
@@ -55,9 +55,9 @@ public class PullRequestReviewRequestsClientTests
|
||||
[IntegrationTest]
|
||||
public async Task GetsNoRequestsWhenNoneExistWithRepositoryId()
|
||||
{
|
||||
var pullRequestId = await CreateTheWorld(_github, _context, createReviewRequests: false);
|
||||
var number = await CreateTheWorld(_github, _context, createReviewRequests: false);
|
||||
|
||||
var reviewRequests = await _client.GetAll(_context.RepositoryId, pullRequestId);
|
||||
var reviewRequests = await _client.GetAll(_context.RepositoryId, number);
|
||||
|
||||
Assert.NotNull(reviewRequests);
|
||||
Assert.Empty(reviewRequests);
|
||||
@@ -66,9 +66,9 @@ public class PullRequestReviewRequestsClientTests
|
||||
[IntegrationTest]
|
||||
public async Task GetsRequests()
|
||||
{
|
||||
var pullRequestId = await CreateTheWorld(_github, _context);
|
||||
var number = await CreateTheWorld(_github, _context);
|
||||
|
||||
var reviewRequests = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, pullRequestId);
|
||||
var reviewRequests = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, number);
|
||||
|
||||
Assert.Equal(_collaboratorLogins, reviewRequests.Select(rr => rr.Login));
|
||||
}
|
||||
@@ -76,9 +76,9 @@ public class PullRequestReviewRequestsClientTests
|
||||
[IntegrationTest]
|
||||
public async Task GetsRequestsWithRepositoryId()
|
||||
{
|
||||
var pullRequestId = await CreateTheWorld(_github, _context);
|
||||
var number = await CreateTheWorld(_github, _context);
|
||||
|
||||
var reviewRequests = await _client.GetAll(_context.RepositoryId, pullRequestId);
|
||||
var reviewRequests = await _client.GetAll(_context.RepositoryId, number);
|
||||
|
||||
Assert.Equal(_collaboratorLogins, reviewRequests.Select(rr => rr.Login));
|
||||
}
|
||||
@@ -86,7 +86,7 @@ public class PullRequestReviewRequestsClientTests
|
||||
[IntegrationTest]
|
||||
public async Task ReturnsCorrectCountOfReviewRequestsWithStart()
|
||||
{
|
||||
var pullRequestId = await CreateTheWorld(_github, _context);
|
||||
var number = await CreateTheWorld(_github, _context);
|
||||
|
||||
var options = new ApiOptions
|
||||
{
|
||||
@@ -94,7 +94,7 @@ public class PullRequestReviewRequestsClientTests
|
||||
PageCount = 1,
|
||||
StartPage = 2
|
||||
};
|
||||
var reviewRequests = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, pullRequestId, options);
|
||||
var reviewRequests = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, number, options);
|
||||
|
||||
Assert.Equal(1, reviewRequests.Count);
|
||||
}
|
||||
@@ -102,7 +102,7 @@ public class PullRequestReviewRequestsClientTests
|
||||
[IntegrationTest]
|
||||
public async Task ReturnsCorrectCountOfReviewRequestsWithStartWithRepositoryId()
|
||||
{
|
||||
var pullRequestId = await CreateTheWorld(_github, _context);
|
||||
var number = await CreateTheWorld(_github, _context);
|
||||
|
||||
var options = new ApiOptions
|
||||
{
|
||||
@@ -110,7 +110,7 @@ public class PullRequestReviewRequestsClientTests
|
||||
PageCount = 2,
|
||||
StartPage = 2
|
||||
};
|
||||
var reviewRequests = await _client.GetAll(_context.RepositoryId, pullRequestId, options);
|
||||
var reviewRequests = await _client.GetAll(_context.RepositoryId, number, options);
|
||||
|
||||
Assert.Equal(1, reviewRequests.Count);
|
||||
}
|
||||
@@ -118,14 +118,14 @@ public class PullRequestReviewRequestsClientTests
|
||||
[IntegrationTest]
|
||||
public async Task ReturnsDistinctResultsBasedOnStartPage()
|
||||
{
|
||||
var pullRequestId = await CreateTheWorld(_github, _context);
|
||||
var number = await CreateTheWorld(_github, _context);
|
||||
|
||||
var startOptions = new ApiOptions
|
||||
{
|
||||
PageSize = 1,
|
||||
PageCount = 1
|
||||
};
|
||||
var firstPage = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, pullRequestId, startOptions);
|
||||
var firstPage = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, number, startOptions);
|
||||
|
||||
var skipStartOptions = new ApiOptions
|
||||
{
|
||||
@@ -133,7 +133,7 @@ public class PullRequestReviewRequestsClientTests
|
||||
PageCount = 1,
|
||||
StartPage = 2
|
||||
};
|
||||
var secondPage = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, pullRequestId, skipStartOptions);
|
||||
var secondPage = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, number, skipStartOptions);
|
||||
|
||||
Assert.Equal(1, firstPage.Count);
|
||||
Assert.Equal(1, secondPage.Count);
|
||||
@@ -143,14 +143,14 @@ public class PullRequestReviewRequestsClientTests
|
||||
[IntegrationTest]
|
||||
public async Task ReturnsDistinctResultsBasedOnStartPageWithRepositoryId()
|
||||
{
|
||||
var pullRequestId = await CreateTheWorld(_github, _context);
|
||||
var number = await CreateTheWorld(_github, _context);
|
||||
|
||||
var startOptions = new ApiOptions
|
||||
{
|
||||
PageSize = 1,
|
||||
PageCount = 1
|
||||
};
|
||||
var firstPage = await _client.GetAll(_context.RepositoryId, pullRequestId, startOptions);
|
||||
var firstPage = await _client.GetAll(_context.RepositoryId, number, startOptions);
|
||||
|
||||
var skipStartOptions = new ApiOptions
|
||||
{
|
||||
@@ -158,7 +158,7 @@ public class PullRequestReviewRequestsClientTests
|
||||
PageCount = 1,
|
||||
StartPage = 2
|
||||
};
|
||||
var secondPage = await _client.GetAll(_context.RepositoryId, pullRequestId, skipStartOptions);
|
||||
var secondPage = await _client.GetAll(_context.RepositoryId, number, skipStartOptions);
|
||||
|
||||
Assert.Equal(1, firstPage.Count);
|
||||
Assert.Equal(1, secondPage.Count);
|
||||
@@ -171,12 +171,12 @@ public class PullRequestReviewRequestsClientTests
|
||||
[IntegrationTest]
|
||||
public async Task DeletesRequests()
|
||||
{
|
||||
var pullRequestId = await CreateTheWorld(_github, _context);
|
||||
var number = await CreateTheWorld(_github, _context);
|
||||
|
||||
var reviewRequestsBeforeDelete = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, pullRequestId);
|
||||
var reviewRequestsBeforeDelete = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, number);
|
||||
var reviewRequestToCreate = new PullRequestReviewRequest(_collaboratorLogins);
|
||||
await _client.Delete(_context.RepositoryOwner, _context.RepositoryName, pullRequestId, reviewRequestToCreate);
|
||||
var reviewRequestsAfterDelete = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, pullRequestId);
|
||||
await _client.Delete(_context.RepositoryOwner, _context.RepositoryName, number, reviewRequestToCreate);
|
||||
var reviewRequestsAfterDelete = await _client.GetAll(_context.RepositoryOwner, _context.RepositoryName, number);
|
||||
|
||||
Assert.NotEmpty(reviewRequestsBeforeDelete);
|
||||
Assert.Empty(reviewRequestsAfterDelete);
|
||||
@@ -185,12 +185,12 @@ public class PullRequestReviewRequestsClientTests
|
||||
[IntegrationTest]
|
||||
public async Task DeletesRequestsWithRepositoryId()
|
||||
{
|
||||
var pullRequestId = await CreateTheWorld(_github, _context);
|
||||
var number = await CreateTheWorld(_github, _context);
|
||||
|
||||
var reviewRequestsBeforeDelete = await _client.GetAll(_context.RepositoryId, pullRequestId);
|
||||
var reviewRequestsBeforeDelete = await _client.GetAll(_context.RepositoryId, number);
|
||||
var reviewRequestToCreate = new PullRequestReviewRequest(_collaboratorLogins);
|
||||
await _client.Delete(_context.RepositoryId, pullRequestId, reviewRequestToCreate);
|
||||
var reviewRequestsAfterDelete = await _client.GetAll(_context.RepositoryId, pullRequestId);
|
||||
await _client.Delete(_context.RepositoryId, number, reviewRequestToCreate);
|
||||
var reviewRequestsAfterDelete = await _client.GetAll(_context.RepositoryId, number);
|
||||
|
||||
Assert.NotEmpty(reviewRequestsBeforeDelete);
|
||||
Assert.Empty(reviewRequestsAfterDelete);
|
||||
@@ -202,10 +202,10 @@ public class PullRequestReviewRequestsClientTests
|
||||
[IntegrationTest]
|
||||
public async Task CreatesRequests()
|
||||
{
|
||||
var pullRequestId = await CreateTheWorld(_github, _context, createReviewRequests: false);
|
||||
var number = await CreateTheWorld(_github, _context, createReviewRequests: false);
|
||||
var reviewRequestToCreate = new PullRequestReviewRequest(_collaboratorLogins);
|
||||
|
||||
var pr = await _client.Create(_context.RepositoryOwner, _context.RepositoryName, pullRequestId, reviewRequestToCreate);
|
||||
var pr = await _client.Create(_context.RepositoryOwner, _context.RepositoryName, number, reviewRequestToCreate);
|
||||
|
||||
Assert.Equal(_collaboratorLogins.ToList(), pr.RequestedReviewers.Select(rr => rr.Login));
|
||||
}
|
||||
@@ -213,10 +213,10 @@ public class PullRequestReviewRequestsClientTests
|
||||
[IntegrationTest]
|
||||
public async Task CreatesRequestsWithRepositoryId()
|
||||
{
|
||||
var pullRequestId = await CreateTheWorld(_github, _context, createReviewRequests: false);
|
||||
var number = await CreateTheWorld(_github, _context, createReviewRequests: false);
|
||||
var reviewRequestToCreate = new PullRequestReviewRequest(_collaboratorLogins);
|
||||
|
||||
var pr = await _client.Create(_context.RepositoryId, pullRequestId, reviewRequestToCreate);
|
||||
var pr = await _client.Create(_context.RepositoryId, number, reviewRequestToCreate);
|
||||
|
||||
Assert.Equal(_collaboratorLogins.ToList(), pr.RequestedReviewers.Select(rr => rr.Login));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,691 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Octokit;
|
||||
using Octokit.Tests.Integration;
|
||||
using Octokit.Tests.Integration.Helpers;
|
||||
using Xunit;
|
||||
|
||||
public class PullRequestReviewsClientTests
|
||||
{
|
||||
public class TheGetAllMethod
|
||||
{
|
||||
private readonly IGitHubClient _github;
|
||||
|
||||
public TheGetAllMethod()
|
||||
{
|
||||
_github = Helper.GetAuthenticatedClient();
|
||||
}
|
||||
|
||||
[IntegrationTest]
|
||||
public async Task GetsAllReviews()
|
||||
{
|
||||
var reviews = await _github.PullRequest.Review.GetAll("octokit", "octokit.net", 1648);
|
||||
|
||||
Assert.NotNull(reviews);
|
||||
Assert.NotEmpty(reviews);
|
||||
Assert.True(reviews.Count > 1);
|
||||
Assert.False(string.IsNullOrEmpty(reviews[0].Body));
|
||||
Assert.False(string.IsNullOrEmpty(reviews[0].CommitId));
|
||||
Assert.False(string.IsNullOrEmpty(reviews[0].User.Login));
|
||||
}
|
||||
|
||||
[IntegrationTest]
|
||||
public async Task ReturnsCorrectCountOfReviewsWithoutStart()
|
||||
{
|
||||
var options = new ApiOptions
|
||||
{
|
||||
PageCount = 1,
|
||||
PageSize = 1
|
||||
};
|
||||
|
||||
var reviews = await _github.PullRequest.Review.GetAll("octokit", "octokit.net", 1648, options);
|
||||
|
||||
Assert.Equal(1, reviews.Count);
|
||||
}
|
||||
|
||||
[IntegrationTest]
|
||||
public async Task ReturnsCorrectCountOfReviewsWithStart()
|
||||
{
|
||||
var options = new ApiOptions
|
||||
{
|
||||
PageCount = 1,
|
||||
PageSize = 1,
|
||||
StartPage = 1
|
||||
};
|
||||
|
||||
var reviews = await _github.PullRequest.Review.GetAll("octokit", "octokit.net", 1648, options);
|
||||
|
||||
Assert.Equal(1, reviews.Count);
|
||||
}
|
||||
|
||||
[IntegrationTest]
|
||||
public async Task ReturnsDistinctReviewsBasedOnStartPage()
|
||||
{
|
||||
var startOptions = new ApiOptions
|
||||
{
|
||||
PageCount = 1,
|
||||
PageSize = 1,
|
||||
StartPage = 1
|
||||
};
|
||||
|
||||
var firstPage = await _github.PullRequest.Review.GetAll("octokit", "octokit.net", 1648, startOptions);
|
||||
|
||||
var skipStartOptions = new ApiOptions
|
||||
{
|
||||
PageSize = 1,
|
||||
PageCount = 1,
|
||||
StartPage = 2
|
||||
};
|
||||
|
||||
var secondPage = await _github.PullRequest.Review.GetAll("octokit", "octokit.net", 1648, skipStartOptions);
|
||||
|
||||
Assert.Equal(1, firstPage.Count);
|
||||
Assert.Equal(1, secondPage.Count);
|
||||
Assert.NotEqual(firstPage.First().Id, secondPage.First().Id);
|
||||
}
|
||||
}
|
||||
|
||||
public class TheGetMethod
|
||||
{
|
||||
private readonly IGitHubClient _github;
|
||||
|
||||
public TheGetMethod()
|
||||
{
|
||||
_github = Helper.GetAuthenticatedClient();
|
||||
}
|
||||
|
||||
[IntegrationTest]
|
||||
public async Task GetsReview()
|
||||
{
|
||||
var review = await _github.PullRequest.Review.Get("octokit", "octokit.net", 1648, 54646850);
|
||||
|
||||
Assert.NotNull(review);
|
||||
Assert.False(string.IsNullOrEmpty(review.Body));
|
||||
Assert.False(string.IsNullOrEmpty(review.CommitId));
|
||||
Assert.False(string.IsNullOrEmpty(review.User.Login));
|
||||
}
|
||||
}
|
||||
|
||||
public class TheCreateMethod
|
||||
{
|
||||
private readonly IGitHubClient _github;
|
||||
private readonly IPullRequestReviewsClient _client;
|
||||
|
||||
private readonly IGitHubClient _github2;
|
||||
|
||||
public TheCreateMethod()
|
||||
{
|
||||
_github = Helper.GetAuthenticatedClient();
|
||||
_client = _github.PullRequest.Review;
|
||||
|
||||
_github2 = Helper.GetAuthenticatedClient(true);
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanCreatePendingReview()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
|
||||
var body = "A review comment message";
|
||||
|
||||
var review = new PullRequestReviewCreate()
|
||||
{
|
||||
CommitId = pullRequest.Head.Sha,
|
||||
Body = body,
|
||||
Comments = new List<DraftPullRequestReviewComment>
|
||||
{
|
||||
new DraftPullRequestReviewComment("comment 1", "README.md", 1),
|
||||
new DraftPullRequestReviewComment("comment 2", "README.md", 2)
|
||||
}
|
||||
};
|
||||
|
||||
var createdReview = await _client.Create(context.RepositoryOwner, context.RepositoryName, pullRequest.Number, review);
|
||||
|
||||
Assert.NotNull(createdReview);
|
||||
Assert.Equal(body, createdReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.Pending, createdReview.State);
|
||||
Assert.Equal(pullRequest.Head.Sha, createdReview.CommitId);
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanCreatePendingReviewWithRepositoryId()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
|
||||
const string body = "A review comment message";
|
||||
|
||||
var review = new PullRequestReviewCreate()
|
||||
{
|
||||
CommitId = pullRequest.Head.Sha,
|
||||
Body = body,
|
||||
Comments = new List<DraftPullRequestReviewComment>
|
||||
{
|
||||
new DraftPullRequestReviewComment("comment 1", "README.md", 1),
|
||||
new DraftPullRequestReviewComment("comment 2", "README.md", 2)
|
||||
}
|
||||
};
|
||||
|
||||
var createdReview = await _client.Create(context.RepositoryId, pullRequest.Number, review);
|
||||
|
||||
Assert.NotNull(createdReview);
|
||||
Assert.Equal(body, createdReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.Pending, createdReview.State);
|
||||
Assert.Equal(pullRequest.Head.Sha, createdReview.CommitId);
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanCreateCommentedReview()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
|
||||
var body = "A review comment message";
|
||||
|
||||
var review = new PullRequestReviewCreate()
|
||||
{
|
||||
CommitId = pullRequest.Head.Sha,
|
||||
Body = body,
|
||||
Event = PullRequestReviewEvent.Comment,
|
||||
Comments = new List<DraftPullRequestReviewComment>
|
||||
{
|
||||
new DraftPullRequestReviewComment("comment 1", "README.md", 1),
|
||||
new DraftPullRequestReviewComment("comment 2", "README.md", 2)
|
||||
}
|
||||
};
|
||||
|
||||
var createdReview = await _client.Create(context.RepositoryOwner, context.RepositoryName, pullRequest.Number, review);
|
||||
|
||||
Assert.NotNull(createdReview);
|
||||
Assert.Equal(body, createdReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.Commented, createdReview.State);
|
||||
Assert.Equal(pullRequest.Head.Sha, createdReview.CommitId);
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanCreateCommentedReviewWithRepositoryId()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
|
||||
const string body = "A review comment message";
|
||||
|
||||
var review = new PullRequestReviewCreate()
|
||||
{
|
||||
CommitId = pullRequest.Head.Sha,
|
||||
Body = body,
|
||||
Event = PullRequestReviewEvent.Comment,
|
||||
Comments = new List<DraftPullRequestReviewComment>
|
||||
{
|
||||
new DraftPullRequestReviewComment("comment 1", "README.md", 1),
|
||||
new DraftPullRequestReviewComment("comment 2", "README.md", 2)
|
||||
}
|
||||
};
|
||||
|
||||
var createdReview = await _client.Create(context.RepositoryId, pullRequest.Number, review);
|
||||
|
||||
Assert.NotNull(createdReview);
|
||||
Assert.Equal(body, createdReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.Commented, createdReview.State);
|
||||
Assert.Equal(pullRequest.Head.Sha, createdReview.CommitId);
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanCreateChangesRequestedReview()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
|
||||
var body = "A review comment message";
|
||||
|
||||
var review = new PullRequestReviewCreate()
|
||||
{
|
||||
CommitId = pullRequest.Head.Sha,
|
||||
Body = body,
|
||||
Event = PullRequestReviewEvent.RequestChanges,
|
||||
Comments = new List<DraftPullRequestReviewComment>
|
||||
{
|
||||
new DraftPullRequestReviewComment("comment 1", "README.md", 1),
|
||||
new DraftPullRequestReviewComment("comment 2", "README.md", 2)
|
||||
}
|
||||
};
|
||||
|
||||
var createdReview = await _client.Create(context.RepositoryOwner, context.RepositoryName, pullRequest.Number, review);
|
||||
|
||||
Assert.NotNull(createdReview);
|
||||
Assert.Equal(body, createdReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.ChangesRequested, createdReview.State);
|
||||
Assert.Equal(pullRequest.Head.Sha, createdReview.CommitId);
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanCreateChangesRequestedReviewWithRepositoryId()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
|
||||
const string body = "A review comment message";
|
||||
|
||||
var review = new PullRequestReviewCreate()
|
||||
{
|
||||
CommitId = pullRequest.Head.Sha,
|
||||
Body = body,
|
||||
Event = PullRequestReviewEvent.RequestChanges,
|
||||
Comments = new List<DraftPullRequestReviewComment>
|
||||
{
|
||||
new DraftPullRequestReviewComment("comment 1", "README.md", 1),
|
||||
new DraftPullRequestReviewComment("comment 2", "README.md", 2)
|
||||
}
|
||||
};
|
||||
|
||||
var createdReview = await _client.Create(context.RepositoryId, pullRequest.Number, review);
|
||||
|
||||
Assert.NotNull(createdReview);
|
||||
Assert.Equal(body, createdReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.ChangesRequested, createdReview.State);
|
||||
Assert.Equal(pullRequest.Head.Sha, createdReview.CommitId);
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanCreateApprovedReview()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
|
||||
var body = "A review comment message";
|
||||
|
||||
var review = new PullRequestReviewCreate()
|
||||
{
|
||||
CommitId = pullRequest.Head.Sha,
|
||||
Body = body,
|
||||
Event = PullRequestReviewEvent.Approve,
|
||||
Comments = new List<DraftPullRequestReviewComment>
|
||||
{
|
||||
new DraftPullRequestReviewComment("comment 1", "README.md", 1),
|
||||
new DraftPullRequestReviewComment("comment 2", "README.md", 2)
|
||||
}
|
||||
};
|
||||
|
||||
var createdReview = await _client.Create(context.RepositoryOwner, context.RepositoryName, pullRequest.Number, review);
|
||||
|
||||
Assert.NotNull(createdReview);
|
||||
Assert.Equal(body, createdReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.Approved, createdReview.State);
|
||||
Assert.Equal(pullRequest.Head.Sha, createdReview.CommitId);
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanCreateApprovedReviewWithRepositoryId()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
|
||||
const string body = "A review comment message";
|
||||
|
||||
var review = new PullRequestReviewCreate()
|
||||
{
|
||||
CommitId = pullRequest.Head.Sha,
|
||||
Body = body,
|
||||
Event = PullRequestReviewEvent.Approve,
|
||||
Comments = new List<DraftPullRequestReviewComment>
|
||||
{
|
||||
new DraftPullRequestReviewComment("comment 1", "README.md", 1),
|
||||
new DraftPullRequestReviewComment("comment 2", "README.md", 2)
|
||||
}
|
||||
};
|
||||
|
||||
var createdReview = await _client.Create(context.RepositoryId, pullRequest.Number, review);
|
||||
|
||||
Assert.NotNull(createdReview);
|
||||
Assert.Equal(body, createdReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.Approved, createdReview.State);
|
||||
Assert.Equal(pullRequest.Head.Sha, createdReview.CommitId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TheDeleteMethod
|
||||
{
|
||||
private readonly IGitHubClient _github;
|
||||
private readonly IPullRequestReviewsClient _client;
|
||||
|
||||
private readonly IGitHubClient _github2;
|
||||
|
||||
public TheDeleteMethod()
|
||||
{
|
||||
_github = Helper.GetAuthenticatedClient();
|
||||
_client = _github.PullRequest.Review;
|
||||
|
||||
_github2 = Helper.GetAuthenticatedClient(true);
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanDeleteReview()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
var createdReview = await _github.CreatePullRequestReview(context.Repository, pullRequest.Number, "A pending review");
|
||||
|
||||
await _client.Delete(context.RepositoryOwner, context.RepositoryName, pullRequest.Number, createdReview.Id);
|
||||
|
||||
var retrievedReviews = await _client.GetAll(context.RepositoryOwner, context.RepositoryName, pullRequest.Number);
|
||||
|
||||
Assert.False(retrievedReviews.Any(x => x.Id == createdReview.Id));
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanDeleteReviewWithRepositoryId()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
var createdReview = await _github.CreatePullRequestReview(context.Repository, pullRequest.Number, "A pending review");
|
||||
|
||||
await _client.Delete(context.RepositoryId, pullRequest.Number, createdReview.Id);
|
||||
|
||||
var retrievedReviews = await _client.GetAll(context.RepositoryId, pullRequest.Number);
|
||||
|
||||
Assert.False(retrievedReviews.Any(x => x.Id == createdReview.Id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TheDismissMethod
|
||||
{
|
||||
private readonly IGitHubClient _github;
|
||||
private readonly IPullRequestReviewsClient _client;
|
||||
|
||||
private readonly IGitHubClient _github2;
|
||||
|
||||
public TheDismissMethod()
|
||||
{
|
||||
_github = Helper.GetAuthenticatedClient();
|
||||
_client = _github.PullRequest.Review;
|
||||
|
||||
_github2 = Helper.GetAuthenticatedClient(true);
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanDismissReview()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
var createdReview = await _github.CreatePullRequestReview(context.Repository, pullRequest.Number, "A pending review", PullRequestReviewEvent.RequestChanges);
|
||||
|
||||
var dismissedReview = await _client.Dismiss(context.RepositoryOwner, context.RepositoryName, pullRequest.Number, createdReview.Id, new PullRequestReviewDismiss { Message = "No soup for you!" });
|
||||
|
||||
Assert.Equal(PullRequestReviewState.Dismissed, dismissedReview.State);
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanDismissReviewWithRepositoryId()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
var createdReview = await _github.CreatePullRequestReview(context.Repository, pullRequest.Number, "A pending review", PullRequestReviewEvent.RequestChanges);
|
||||
|
||||
var dismissedReview = await _client.Dismiss(context.RepositoryId, pullRequest.Number, createdReview.Id, new PullRequestReviewDismiss { Message = "No soup for you!" });
|
||||
|
||||
Assert.Equal(PullRequestReviewState.Dismissed, dismissedReview.State);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TheGetAllCommentsMethod
|
||||
{
|
||||
private readonly IGitHubClient _github;
|
||||
|
||||
public TheGetAllCommentsMethod()
|
||||
{
|
||||
_github = Helper.GetAuthenticatedClient();
|
||||
}
|
||||
|
||||
[IntegrationTest]
|
||||
public async Task GetsAllComments()
|
||||
{
|
||||
var comments = await _github.PullRequest.Review.GetAllComments("octokit", "octokit.net", 1648, 54646850);
|
||||
|
||||
Assert.NotNull(comments);
|
||||
Assert.NotEmpty(comments);
|
||||
Assert.True(comments.Count > 1);
|
||||
foreach (var comment in comments)
|
||||
{
|
||||
Assert.False(string.IsNullOrEmpty(comment.Body));
|
||||
Assert.False(string.IsNullOrEmpty(comment.CommitId));
|
||||
Assert.False(string.IsNullOrEmpty(comment.User.Login));
|
||||
}
|
||||
}
|
||||
|
||||
[IntegrationTest]
|
||||
public async Task ReturnsCorrectCountOfCommentsWithoutStart()
|
||||
{
|
||||
var options = new ApiOptions
|
||||
{
|
||||
PageCount = 1,
|
||||
PageSize = 1
|
||||
};
|
||||
|
||||
var comments = await _github.PullRequest.Review.GetAllComments("octokit", "octokit.net", 1648, 54646850, options);
|
||||
|
||||
Assert.Equal(1, comments.Count);
|
||||
}
|
||||
|
||||
[IntegrationTest]
|
||||
public async Task ReturnsCorrectCountOfCommentsWithStart()
|
||||
{
|
||||
var options = new ApiOptions
|
||||
{
|
||||
PageCount = 1,
|
||||
PageSize = 1,
|
||||
StartPage = 1
|
||||
};
|
||||
|
||||
var comments = await _github.PullRequest.Review.GetAllComments("octokit", "octokit.net", 1648, 54646850, options);
|
||||
|
||||
Assert.Equal(1, comments.Count);
|
||||
}
|
||||
|
||||
[IntegrationTest]
|
||||
public async Task ReturnsDistinctCommentsBasedOnStartPage()
|
||||
{
|
||||
var startOptions = new ApiOptions
|
||||
{
|
||||
PageCount = 1,
|
||||
PageSize = 1,
|
||||
StartPage = 1
|
||||
};
|
||||
|
||||
var firstPage = await _github.PullRequest.Review.GetAllComments("octokit", "octokit.net", 1648, 54646850, startOptions);
|
||||
|
||||
var skipStartOptions = new ApiOptions
|
||||
{
|
||||
PageSize = 1,
|
||||
PageCount = 1,
|
||||
StartPage = 2
|
||||
};
|
||||
|
||||
var secondPage = await _github.PullRequest.Review.GetAllComments("octokit", "octokit.net", 1648, 54646850, skipStartOptions);
|
||||
|
||||
Assert.Equal(1, firstPage.Count);
|
||||
Assert.Equal(1, secondPage.Count);
|
||||
Assert.NotEqual(firstPage.First().Id, secondPage.First().Id);
|
||||
}
|
||||
}
|
||||
|
||||
public class TheSubmitMethod
|
||||
{
|
||||
private readonly IGitHubClient _github;
|
||||
private readonly IPullRequestReviewsClient _client;
|
||||
|
||||
private readonly IGitHubClient _github2;
|
||||
|
||||
public TheSubmitMethod()
|
||||
{
|
||||
_github = Helper.GetAuthenticatedClient();
|
||||
_client = _github.PullRequest.Review;
|
||||
|
||||
_github2 = Helper.GetAuthenticatedClient(true);
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanSubmitCommentedReview()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
var createdReview = await _github.CreatePullRequestReview(context.Repository, pullRequest.Number, "A pending review");
|
||||
|
||||
var submitMessage = new PullRequestReviewSubmit
|
||||
{
|
||||
Body = "Roger roger!",
|
||||
Event = PullRequestReviewEvent.Comment
|
||||
};
|
||||
var submittedReview = await _client.Submit(context.RepositoryOwner, context.RepositoryName, pullRequest.Number, createdReview.Id, submitMessage);
|
||||
|
||||
Assert.Equal("Roger roger!", submittedReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.Commented, submittedReview.State);
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanSubmitCommentedReviewWithRepositoryId()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
var createdReview = await _github.CreatePullRequestReview(context.Repository, pullRequest.Number, "A pending review");
|
||||
|
||||
var submitMessage = new PullRequestReviewSubmit
|
||||
{
|
||||
Body = "Roger roger!",
|
||||
Event = PullRequestReviewEvent.Comment
|
||||
};
|
||||
var submittedReview = await _client.Submit(context.RepositoryId, pullRequest.Number, createdReview.Id, submitMessage);
|
||||
|
||||
Assert.Equal("Roger roger!", submittedReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.Commented, submittedReview.State);
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanSubmitChangesRequestedReview()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
var createdReview = await _github.CreatePullRequestReview(context.Repository, pullRequest.Number, "A pending review");
|
||||
|
||||
var submitMessage = new PullRequestReviewSubmit
|
||||
{
|
||||
Body = "Roger roger!",
|
||||
Event = PullRequestReviewEvent.RequestChanges
|
||||
};
|
||||
var submittedReview = await _client.Submit(context.RepositoryOwner, context.RepositoryName, pullRequest.Number, createdReview.Id, submitMessage);
|
||||
|
||||
Assert.Equal("Roger roger!", submittedReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.ChangesRequested, submittedReview.State);
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanSubmitChangesRequestedReviewWithRepositoryId()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
var createdReview = await _github.CreatePullRequestReview(context.Repository, pullRequest.Number, "A pending review");
|
||||
|
||||
var submitMessage = new PullRequestReviewSubmit
|
||||
{
|
||||
Body = "Roger roger!",
|
||||
Event = PullRequestReviewEvent.RequestChanges
|
||||
};
|
||||
var submittedReview = await _client.Submit(context.RepositoryId, pullRequest.Number, createdReview.Id, submitMessage);
|
||||
|
||||
Assert.Equal("Roger roger!", submittedReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.ChangesRequested, submittedReview.State);
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanSubmitApprovedReview()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
var createdReview = await _github.CreatePullRequestReview(context.Repository, pullRequest.Number, "A pending review");
|
||||
|
||||
var submitMessage = new PullRequestReviewSubmit
|
||||
{
|
||||
Body = "Roger roger!",
|
||||
Event = PullRequestReviewEvent.Approve
|
||||
};
|
||||
var submittedReview = await _client.Submit(context.RepositoryOwner, context.RepositoryName, pullRequest.Number, createdReview.Id, submitMessage);
|
||||
|
||||
Assert.Equal("Roger roger!", submittedReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.Approved, submittedReview.State);
|
||||
}
|
||||
}
|
||||
|
||||
[DualAccountTest]
|
||||
public async Task CanSubmitApprovedReviewWithRepositoryId()
|
||||
{
|
||||
using (var context = await _github.CreateRepositoryContext("test-repo"))
|
||||
{
|
||||
await _github.CreateTheWorld(context.Repository);
|
||||
var pullRequest = await _github2.CreatePullRequest(context.Repository);
|
||||
var createdReview = await _github.CreatePullRequestReview(context.Repository, pullRequest.Number, "A pending review");
|
||||
|
||||
var submitMessage = new PullRequestReviewSubmit
|
||||
{
|
||||
Body = "Roger roger!",
|
||||
Event = PullRequestReviewEvent.Approve
|
||||
};
|
||||
var submittedReview = await _client.Submit(context.RepositoryId, pullRequest.Number, createdReview.Id, submitMessage);
|
||||
|
||||
Assert.Equal("Roger roger!", submittedReview.Body);
|
||||
Assert.Equal(PullRequestReviewState.Approved, submittedReview.State);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,18 @@ namespace Octokit.Tests.Integration
|
||||
return new Credentials(githubUsername, githubPassword);
|
||||
});
|
||||
|
||||
static readonly Lazy<Credentials> _credentialsSecondUserThunk = new Lazy<Credentials>(() =>
|
||||
{
|
||||
var githubUsername = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBUSERNAME_2");
|
||||
|
||||
var githubPassword = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBPASSWORD_2");
|
||||
|
||||
if (githubUsername == null || githubPassword == null)
|
||||
return null;
|
||||
|
||||
return new Credentials(githubUsername, githubPassword);
|
||||
});
|
||||
|
||||
static readonly Lazy<Credentials> _oauthApplicationCredentials = new Lazy<Credentials>(() =>
|
||||
{
|
||||
var applicationClientId = ClientId;
|
||||
@@ -78,6 +90,8 @@ namespace Octokit.Tests.Integration
|
||||
/// </summary>
|
||||
public static Credentials Credentials { get { return _credentialsThunk.Value; } }
|
||||
|
||||
public static Credentials CredentialsSecondUser { get { return _credentialsSecondUserThunk.Value; } }
|
||||
|
||||
public static Credentials ApplicationCredentials { get { return _oauthApplicationCredentials.Value; } }
|
||||
|
||||
public static Credentials BasicAuthCredentials { get { return _basicAuthCredentials.Value; } }
|
||||
@@ -193,11 +207,11 @@ namespace Octokit.Tests.Integration
|
||||
return stream;
|
||||
}
|
||||
|
||||
public static IGitHubClient GetAuthenticatedClient()
|
||||
public static IGitHubClient GetAuthenticatedClient(bool useSecondUser = false)
|
||||
{
|
||||
return new GitHubClient(new ProductHeaderValue("OctokitTests"), TargetUrl)
|
||||
{
|
||||
Credentials = Credentials
|
||||
Credentials = useSecondUser ? CredentialsSecondUser : Credentials
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace Octokit.Tests.Integration
|
||||
{
|
||||
public class DualAccountTestDiscoverer : IXunitTestCaseDiscoverer
|
||||
{
|
||||
readonly IMessageSink diagnosticMessageSink;
|
||||
|
||||
public DualAccountTestDiscoverer(IMessageSink diagnosticMessageSink)
|
||||
{
|
||||
this.diagnosticMessageSink = diagnosticMessageSink;
|
||||
}
|
||||
|
||||
public IEnumerable<IXunitTestCase> Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute)
|
||||
{
|
||||
if (Helper.CredentialsSecondUser == null)
|
||||
{
|
||||
return Enumerable.Empty<IXunitTestCase>();
|
||||
}
|
||||
|
||||
return new[] { new XunitTestCase(diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod) };
|
||||
}
|
||||
}
|
||||
|
||||
[XunitTestCaseDiscoverer("Octokit.Tests.Integration.DualAccountTestDiscoverer", "Octokit.Tests.Integration")]
|
||||
public class DualAccountTestAttribute : FactAttribute
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -54,11 +54,34 @@ namespace Octokit.Tests.Integration.Helpers
|
||||
await client.Git.Reference.Update(repository.Owner.Login, repository.Name, "heads/master", new ReferenceUpdate(newMaster.Sha));
|
||||
|
||||
// create new commit for feature branch
|
||||
var featureBranchTree = await client.CreateTree(repository, new Dictionary<string, string> { { "README.md", "I am overwriting this blob with something new" } });
|
||||
var featureBranchTree = await client.CreateTree(repository, new Dictionary<string, string> { { "README.md", "I am overwriting this blob with something new\nand a second line too" } });
|
||||
var featureBranchCommit = await client.CreateCommit(repository, "this is the commit to merge into the pull request", featureBranchTree.Sha, newMaster.Sha);
|
||||
|
||||
// create branch
|
||||
return await client.Git.Reference.Create(repository.Owner.Login, repository.Name, new NewReference("refs/heads/my-branch", featureBranchCommit.Sha));
|
||||
}
|
||||
|
||||
public static async Task<PullRequest> CreatePullRequest(this IGitHubClient client, Repository repository, string branch = "my-branch")
|
||||
{
|
||||
var pullRequest = new NewPullRequest("Nice title for the pull request", branch, "master");
|
||||
var createdPullRequest = await client.PullRequest.Create(repository.Owner.Login, repository.Name, pullRequest);
|
||||
|
||||
return createdPullRequest;
|
||||
}
|
||||
|
||||
public static async Task<PullRequestReview> CreatePullRequestReview(this IGitHubClient client, Repository repository, int number, string body, PullRequestReviewEvent? @event = null, string commitId = null, List<DraftPullRequestReviewComment> comments = null)
|
||||
{
|
||||
var review = new PullRequestReviewCreate()
|
||||
{
|
||||
CommitId = commitId,
|
||||
Body = body,
|
||||
Event = @event,
|
||||
Comments = comments
|
||||
};
|
||||
|
||||
var createdReview = await client.PullRequest.Review.Create(repository.Owner.Login, repository.Name, number, review);
|
||||
|
||||
return createdReview;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user