Re architect/review revision restructure (#7390)
* Add alert for displaying page errors, add logic for manual reviews * Make Associated PRs and Revies Dependent on APIRevision ID * Update Database name * Disable Pipeline Tests
This commit is contained in:
Родитель
8a10ab0e04
Коммит
c660060dda
|
@ -55,7 +55,7 @@ namespace APIViewIntegrationTests
|
|||
var reviewManager = testsBaseFixture.ReviewManager;
|
||||
var apiRevisionsManager = testsBaseFixture.APIRevisionManager;
|
||||
var user = testsBaseFixture.User;
|
||||
var review = await testsBaseFixture.ReviewManager.CreateReviewAsync(packageName: "testPackageA", language: "Swagger", isClosed:false);
|
||||
var review = await testsBaseFixture.ReviewManager.CreateReviewAsync(packageName: "testPackageA", language: "Swagger", isClosed: false);
|
||||
|
||||
await apiRevisionsManager.AddAPIRevisionAsync(user: user, reviewId: review.Id, apiRevisionType: APIRevisionType.Automatic, name: fileNameA,
|
||||
label: "Revision1", fileStream: fileStreamA, language: "Swagger", awaitComputeDiff: true);
|
||||
|
@ -64,7 +64,7 @@ namespace APIViewIntegrationTests
|
|||
|
||||
var apiRevisions = (await apiRevisionsManager.GetAPIRevisionsAsync(review.Id)).ToList();
|
||||
|
||||
var headingWithDiffInSections = apiRevisions[0].HeadingsOfSectionsWithDiff[apiRevisions[1].Id];
|
||||
var headingWithDiffInSections = apiRevisions[1].HeadingsOfSectionsWithDiff[apiRevisions[0].Id];
|
||||
Assert.All(headingWithDiffInSections,
|
||||
item => Assert.Contains(item, new int[] { 2, 16 }));
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ namespace APIViewIntegrationTests
|
|||
|
||||
var apiRevisions = (await apiRevisionsManager.GetAPIRevisionsAsync(review.Id)).ToList();
|
||||
|
||||
var headingWithDiffInSections = apiRevisions[0].HeadingsOfSectionsWithDiff[apiRevisions[1].Id];
|
||||
var headingWithDiffInSections = apiRevisions[1].HeadingsOfSectionsWithDiff[apiRevisions[0].Id];
|
||||
Assert.All(headingWithDiffInSections,
|
||||
item => Assert.Contains(item, new int[] { 20, 275 }));
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace APIViewIntegrationTests
|
|||
User = TestUser.GetTestuser();
|
||||
|
||||
_cosmosClient = new CosmosClient(config["Cosmos:ConnectionString"]);
|
||||
var dataBaseResponse = _cosmosClient.CreateDatabaseIfNotExistsAsync("APIView").Result;
|
||||
var dataBaseResponse = _cosmosClient.CreateDatabaseIfNotExistsAsync("APIViewV2").Result;
|
||||
dataBaseResponse.Database.CreateContainerIfNotExistsAsync("Reviews", "/id").Wait();
|
||||
dataBaseResponse.Database.CreateContainerIfNotExistsAsync("APIRevisions", "/ReviewId").Wait();
|
||||
dataBaseResponse.Database.CreateContainerIfNotExistsAsync("Comments", "/ReviewId").Wait();
|
||||
|
|
|
@ -17,6 +17,7 @@ using Microsoft.AspNetCore.SignalR;
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.VisualStudio.Services.ClientNotification;
|
||||
|
||||
namespace APIViewWeb.Helpers
|
||||
{
|
||||
|
@ -240,12 +241,18 @@ namespace APIViewWeb.Helpers
|
|||
string revisionId = null, string diffRevisionId = null, bool showDocumentation = false, bool showDiffOnly = false, int diffContextSize = 3,
|
||||
string diffContextSeperator = "<br><span>.....</span><br>", HashSet<int> headingsOfSectionsWithDiff = null)
|
||||
{
|
||||
var reviewPageContent = new ReviewContentModel()
|
||||
{
|
||||
Directive = ReviewContentModelDirective.ProceedWithPageLoad
|
||||
};
|
||||
|
||||
var userId = user.GetGitHubLogin();
|
||||
var review = await reviewManager.GetReviewAsync(user, reviewId);
|
||||
|
||||
if (review == null)
|
||||
{
|
||||
return default(ReviewContentModel);
|
||||
reviewPageContent.Directive = ReviewContentModelDirective.TryGetlegacyReview;
|
||||
return reviewPageContent;
|
||||
}
|
||||
|
||||
var apiRevisions = await reviewRevisionsManager.GetAPIRevisionsAsync(reviewId);
|
||||
|
@ -254,8 +261,9 @@ namespace APIViewWeb.Helpers
|
|||
var activeRevision = await reviewRevisionsManager.GetLatestAPIRevisionsAsync(reviewId, apiRevisions, APIRevisionType.Automatic);
|
||||
if (activeRevision == null)
|
||||
{
|
||||
var notifcation = new NotificationModel() { Message = $"This review has no valid apiRevisons", Level = NotificatonLevel.Warning };
|
||||
await signalRHubContext.Clients.Group(userId).SendAsync("RecieveNotification", notifcation);
|
||||
reviewPageContent.Directive = ReviewContentModelDirective.ErrorDueToInvalidAPIRevison;
|
||||
reviewPageContent.NotificationMessage = $"Review with ID {reviewId} has no valid APIRevisons";
|
||||
return reviewPageContent;
|
||||
}
|
||||
|
||||
APIRevisionListItemModel diffRevision = null;
|
||||
|
@ -266,8 +274,9 @@ namespace APIViewWeb.Helpers
|
|||
}
|
||||
else
|
||||
{
|
||||
var notifcation = new NotificationModel() { Message = $"A revision with ID {revisionId} does not exist for this review.", Level = NotificatonLevel.Warning };
|
||||
await signalRHubContext.Clients.Group(userId).SendAsync("RecieveNotification", notifcation);
|
||||
reviewPageContent.NotificationMessage = $"A revision with ID {revisionId} does not exist for review with id {reviewId}";
|
||||
reviewPageContent.Directive = ReviewContentModelDirective.ErrorDueToInvalidAPIRevison;
|
||||
return reviewPageContent;
|
||||
}
|
||||
}
|
||||
var comments = await commentManager.GetReviewCommentsAsync(reviewId);
|
||||
|
@ -278,6 +287,8 @@ namespace APIViewWeb.Helpers
|
|||
var activeRevisionHtmlLines = activeRevisionRenderableCodeFile.Render(showDocumentation: showDocumentation);
|
||||
|
||||
var codeLines = new CodeLineModel[0];
|
||||
var getCodeLines = false;
|
||||
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(diffRevisionId))
|
||||
|
@ -297,17 +308,20 @@ namespace APIViewWeb.Helpers
|
|||
|
||||
if (!codeLines.Any())
|
||||
{
|
||||
var notifcation = new NotificationModel() { Message = $"There is no diff between the two revisions. {activeRevision.Id} : {diffRevisionId}", Level = NotificatonLevel.Info };
|
||||
await signalRHubContext.Clients.Group(userId).SendAsync("RecieveNotification", notifcation);
|
||||
getCodeLines = true;
|
||||
reviewPageContent.NotificationMessage = $"There is no diff between the two revisions. {activeRevision.Id} : {diffRevisionId}";
|
||||
reviewPageContent.Directive = ReviewContentModelDirective.ErrorDueToInvalidAPIRevison;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var notifcation = new NotificationModel() { Message = $"A diffRevision with ID {diffRevisionId} does not exist for this review.", Level = NotificatonLevel.Warning };
|
||||
await signalRHubContext.Clients.Group(userId).SendAsync("RecieveNotification", notifcation);
|
||||
getCodeLines = true;
|
||||
reviewPageContent.NotificationMessage = $"A diffRevision with ID {diffRevisionId} does not exist for this review.";
|
||||
reviewPageContent.Directive = ReviewContentModelDirective.ErrorDueToInvalidAPIRevison;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (string.IsNullOrEmpty(diffRevisionId) || getCodeLines)
|
||||
{
|
||||
codeLines = CreateLines(diagnostics: fileDiagnostics, lines: activeRevisionHtmlLines, comments: comments);
|
||||
}
|
||||
|
@ -346,21 +360,19 @@ namespace APIViewWeb.Helpers
|
|||
}
|
||||
}
|
||||
|
||||
var reviewPageContent = new ReviewContentModel
|
||||
{
|
||||
Review = review,
|
||||
Navigation = activeRevisionRenderableCodeFile.CodeFile.Navigation,
|
||||
codeLines = codeLines,
|
||||
APIRevisionsGrouped = apiRevisions.OrderByDescending(c => c.CreatedOn).GroupBy(r => r.APIRevisionType).ToDictionary(r => r.Key.ToString(), r => r.ToList()),
|
||||
ActiveAPIRevision = activeRevision,
|
||||
DiffAPIRevision = diffRevision,
|
||||
TotalActiveConversiations = comments.Threads.Count(t => !t.IsResolved),
|
||||
ActiveConversationsInActiveAPIRevision = ComputeActiveConversationsInActiveRevision(activeRevisionHtmlLines, comments),
|
||||
ActiveConversationsInSampleRevisions = comments.Threads.Count(t => t.Comments.FirstOrDefault()?.CommentType == CommentType.SamplesRevision),
|
||||
PreferredApprovers = preferredApprovers,
|
||||
TaggableUsers = commentManager.GetTaggableUsers(),
|
||||
PageHasLoadableSections = activeRevisionReviewCodeFile.LeafSections?.Any() ?? false
|
||||
};
|
||||
reviewPageContent.Review = review;
|
||||
reviewPageContent.Navigation = activeRevisionRenderableCodeFile.CodeFile.Navigation;
|
||||
reviewPageContent.codeLines = codeLines;
|
||||
reviewPageContent.APIRevisionsGrouped = apiRevisions.OrderByDescending(c => c.CreatedOn).GroupBy(r => r.APIRevisionType).ToDictionary(r => r.Key.ToString(), r => r.ToList());
|
||||
reviewPageContent.ActiveAPIRevision = activeRevision;
|
||||
reviewPageContent.DiffAPIRevision = diffRevision;
|
||||
reviewPageContent.TotalActiveConversiations = comments.Threads.Count(t => !t.IsResolved);
|
||||
reviewPageContent.ActiveConversationsInActiveAPIRevision = ComputeActiveConversationsInActiveRevision(activeRevisionHtmlLines, comments);
|
||||
reviewPageContent.ActiveConversationsInSampleRevisions = comments.Threads.Count(t => t.Comments.FirstOrDefault()?.CommentType == CommentType.SamplesRevision);
|
||||
reviewPageContent.PreferredApprovers = preferredApprovers;
|
||||
reviewPageContent.TaggableUsers = commentManager.GetTaggableUsers();
|
||||
reviewPageContent.PageHasLoadableSections = activeRevisionReviewCodeFile.LeafSections?.Any() ?? false;
|
||||
|
||||
return reviewPageContent;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,13 @@ using APIViewWeb.Models;
|
|||
|
||||
namespace APIViewWeb.LeanModels
|
||||
{
|
||||
public enum ReviewContentModelDirective
|
||||
{
|
||||
ProceedWithPageLoad = 0,
|
||||
TryGetlegacyReview,
|
||||
ErrorDueToInvalidAPIRevison
|
||||
}
|
||||
|
||||
public class ReviewContentModel
|
||||
{
|
||||
public ReviewListItemModel Review { get; set; }
|
||||
|
@ -19,5 +26,7 @@ namespace APIViewWeb.LeanModels
|
|||
public HashSet<string> PreferredApprovers = new HashSet<string>();
|
||||
public HashSet<GithubUser> TaggableUsers { get; set; }
|
||||
public bool PageHasLoadableSections { get; set; }
|
||||
public string NotificationMessage { get; set; }
|
||||
public ReviewContentModelDirective Directive { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -373,7 +373,7 @@ namespace APIViewWeb.Managers
|
|||
/// <param name="language"></param>
|
||||
/// <param name="awaitComputeDiff"></param>
|
||||
/// <returns></returns>
|
||||
public async Task AddAPIRevisionAsync(
|
||||
public async Task<APIRevisionListItemModel> AddAPIRevisionAsync(
|
||||
ClaimsPrincipal user,
|
||||
ReviewListItemModel review,
|
||||
APIRevisionType apiRevisionType,
|
||||
|
@ -383,48 +383,49 @@ namespace APIViewWeb.Managers
|
|||
string language,
|
||||
bool awaitComputeDiff = false)
|
||||
{
|
||||
var revision = GetNewAPIRevisionAsync(
|
||||
var apiRevision = GetNewAPIRevisionAsync(
|
||||
reviewId: review.Id,
|
||||
apiRevisionType: apiRevisionType,
|
||||
packageName: review.PackageName,
|
||||
language: review.Language,
|
||||
createdBy: review.CreatedBy,
|
||||
createdBy: user.GetGitHubLogin(),
|
||||
label: label);
|
||||
|
||||
var codeFile = await _codeFileManager.CreateCodeFileAsync(
|
||||
revision.Id,
|
||||
apiRevision.Id,
|
||||
name,
|
||||
fileStream,
|
||||
true,
|
||||
fileStream,
|
||||
language);
|
||||
|
||||
revision.Files.Add(codeFile);
|
||||
apiRevision.Files.Add(codeFile);
|
||||
|
||||
var languageService = language != null ? _languageServices.FirstOrDefault(l => l.Name == language) : _languageServices.FirstOrDefault(s => s.IsSupportedFile(name));
|
||||
// Run pipeline to generate the review if sandbox is enabled
|
||||
if (languageService != null && languageService.IsReviewGenByPipeline)
|
||||
{
|
||||
// Run offline review gen for review and reviewCodeFileModel
|
||||
await GenerateAPIRevisionInExternalResource(review, revision.Id, codeFile.FileId, name, language);
|
||||
await GenerateAPIRevisionInExternalResource(review, apiRevision.Id, codeFile.FileId, name, language);
|
||||
}
|
||||
|
||||
// auto subscribe revision creation user
|
||||
await _notificationManager.SubscribeAsync(review, user);
|
||||
await _reviewsRepository.UpsertReviewAsync(review);
|
||||
await _apiRevisionsRepository.UpsertAPIRevisionAsync(revision);
|
||||
await _notificationManager.NotifySubscribersOnNewRevisionAsync(review, revision, user);
|
||||
await _apiRevisionsRepository.UpsertAPIRevisionAsync(apiRevision);
|
||||
await _notificationManager.NotifySubscribersOnNewRevisionAsync(review, apiRevision, user);
|
||||
|
||||
if (!String.IsNullOrEmpty(review.Language) && review.Language == "Swagger")
|
||||
{
|
||||
if (awaitComputeDiff)
|
||||
{
|
||||
await GetLineNumbersOfHeadingsOfSectionsWithDiff(review.Id, revision);
|
||||
await GetLineNumbersOfHeadingsOfSectionsWithDiff(review.Id, apiRevision);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = Task.Run(async () => await GetLineNumbersOfHeadingsOfSectionsWithDiff(review.Id, revision));
|
||||
_ = Task.Run(async () => await GetLineNumbersOfHeadingsOfSectionsWithDiff(review.Id, apiRevision));
|
||||
}
|
||||
}
|
||||
return apiRevision;
|
||||
//await GenerateAIReview(review, revision);
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ namespace APIViewWeb.Managers
|
|||
{
|
||||
// backward compatibility until all languages moved to sandboxing of codefile to pipeline
|
||||
stream = await _devopsArtifactRepository.DownloadPackageArtifact(repoName, buildId, artifactName, originalFileName, format: "file", project: project);
|
||||
codeFile = await CreateCodeFileAsync(Path.GetFileName(originalFileName), stream, false, originalFileStream);
|
||||
codeFile = await CreateCodeFileAsync(originalName: Path.GetFileName(originalFileName), fileStream: stream, runAnalysis: false, memoryStream: originalFileStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -93,19 +93,20 @@ namespace APIViewWeb.Managers
|
|||
/// </summary>
|
||||
/// <param name="apiRevisionId"></param>
|
||||
/// <param name="originalName"></param>
|
||||
/// <param name="fileStream"></param>
|
||||
/// <param name="runAnalysis"></param>
|
||||
/// <param name="fileStream"></param>
|
||||
/// <param name="language"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<APICodeFileModel> CreateCodeFileAsync(
|
||||
string apiRevisionId,
|
||||
string originalName,
|
||||
Stream fileStream,
|
||||
bool runAnalysis,
|
||||
string language)
|
||||
Stream fileStream = null,
|
||||
string language = null)
|
||||
{
|
||||
using var memoryStream = new MemoryStream();
|
||||
var codeFile = await CreateCodeFileAsync(originalName, fileStream, runAnalysis, memoryStream, language);
|
||||
var codeFile = await CreateCodeFileAsync(originalName: originalName, runAnalysis: runAnalysis,
|
||||
memoryStream: memoryStream, fileStream: fileStream, language: language);
|
||||
var reviewCodeFileModel = await CreateReviewCodeFileModel(apiRevisionId, memoryStream, codeFile);
|
||||
reviewCodeFileModel.FileName = originalName;
|
||||
return reviewCodeFileModel;
|
||||
|
@ -115,16 +116,16 @@ namespace APIViewWeb.Managers
|
|||
/// Create Code File
|
||||
/// </summary>
|
||||
/// <param name="originalName"></param>
|
||||
/// <param name="fileStream"></param>
|
||||
/// <param name="runAnalysis"></param>
|
||||
/// <param name="memoryStream"></param>
|
||||
/// <param name="fileStream"></param>
|
||||
/// <param name="language"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<CodeFile> CreateCodeFileAsync(
|
||||
string originalName,
|
||||
Stream fileStream,
|
||||
bool runAnalysis,
|
||||
MemoryStream memoryStream,
|
||||
Stream fileStream = null,
|
||||
string language = null)
|
||||
{
|
||||
var languageService = _languageServices.FirstOrDefault(s => (language != null ? s.Name == language : s.IsSupportedFile(originalName)));
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace APIViewWeb.Managers.Interfaces
|
|||
string label = null, int? prNumber = null, string createdBy = "azure-sdk");
|
||||
public Task<bool> ToggleAPIRevisionApprovalAsync(ClaimsPrincipal user, string id, string revisionId = null, APIRevisionListItemModel apiRevision = null, string notes = "");
|
||||
public Task AddAPIRevisionAsync(ClaimsPrincipal user, string reviewId, APIRevisionType apiRevisionType, string name, string label, Stream fileStream, string language = "", bool awaitComputeDiff = false);
|
||||
public Task AddAPIRevisionAsync(ClaimsPrincipal user, ReviewListItemModel review, APIRevisionType apiRevisionType, string name, string label, Stream fileStream, string language, bool awaitComputeDiff = false);
|
||||
public Task<APIRevisionListItemModel> AddAPIRevisionAsync(ClaimsPrincipal user, ReviewListItemModel review, APIRevisionType apiRevisionType, string name, string label, Stream fileStream, string language, bool awaitComputeDiff = false);
|
||||
public Task RunAPIRevisionGenerationPipeline(List<APIRevisionGenerationPipelineParamModel> reviewGenParams, string language);
|
||||
public Task SoftDeleteAPIRevisionAsync(ClaimsPrincipal user, string reviewId, string revisionId);
|
||||
public Task SoftDeleteAPIRevisionAsync(ClaimsPrincipal user, APIRevisionListItemModel apiRevision);
|
||||
|
|
|
@ -9,8 +9,8 @@ namespace APIViewWeb.Managers.Interfaces
|
|||
{
|
||||
public Task<CodeFile> GetCodeFileAsync(string repoName, string buildId, string artifactName, string packageName, string originalFileName, string codeFileName,
|
||||
MemoryStream originalFileStream, string baselineCodeFileName = "", MemoryStream baselineStream = null, string project = "public");
|
||||
public Task<APICodeFileModel> CreateCodeFileAsync(string apiRevisionId, string originalName, Stream fileStream, bool runAnalysis, string language);
|
||||
public Task<CodeFile> CreateCodeFileAsync(string originalName, Stream fileStream, bool runAnalysis, MemoryStream memoryStream, string language = null);
|
||||
public Task<APICodeFileModel> CreateCodeFileAsync(string apiRevisionId, string originalName, bool runAnalysis, Stream fileStream = null, string language = null);
|
||||
public Task<CodeFile> CreateCodeFileAsync(string originalName, bool runAnalysis, MemoryStream memoryStream, Stream fileStream = null, string language = null);
|
||||
public Task<APICodeFileModel> CreateReviewCodeFileModel(string apiRevisionId, MemoryStream memoryStream, CodeFile codeFile);
|
||||
public bool IsAPICodeFilesTheSame(RenderedCodeFile codeFileA, RenderedCodeFile codeFileB);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace APIViewWeb.Managers
|
|||
{
|
||||
public interface IPullRequestManager
|
||||
{
|
||||
public Task<IEnumerable<PullRequestModel>> GetPullRequestsModelAsync(string reviewId);
|
||||
public Task<IEnumerable<PullRequestModel>> GetPullRequestsModelAsync(string reviewId, string apiRevisionId = null);
|
||||
public Task<IEnumerable<PullRequestModel>> GetPullRequestsModelAsync(int pullRequestNumber, string repoName);
|
||||
public Task<PullRequestModel> GetPullRequestModelAsync(int prNumber, string repoName, string packageName, string originalFile, string language);
|
||||
public Task CreateOrUpdateCommentsOnPR(List<PullRequestModel> pullRequests, string repoOwner, string repoName, int prNumber, string hostName);
|
||||
|
|
|
@ -53,8 +53,8 @@ namespace APIViewWeb.Managers
|
|||
_pullRequestCleanupDays = int.Parse(pullRequestReviewCloseAfter);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<PullRequestModel>> GetPullRequestsModelAsync(string reviewId) {
|
||||
return await _pullRequestsRepository.GetPullRequestsAsync(reviewId);
|
||||
public async Task<IEnumerable<PullRequestModel>> GetPullRequestsModelAsync(string reviewId, string apiRevisionId = null) {
|
||||
return await _pullRequestsRepository.GetPullRequestsAsync(reviewId, apiRevisionId);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<PullRequestModel>> GetPullRequestsModelAsync(int pullRequestNumber, string repoName)
|
||||
|
|
|
@ -71,8 +71,74 @@
|
|||
if (userPreference.HideIndexPageOptions.HasValue && userPreference.HideIndexPageOptions == true)
|
||||
mainContainerClass = String.Empty;
|
||||
}
|
||||
|
||||
<div class="container-fluid mb-5@(mainContainerClass)" id="index-main-container">
|
||||
<div class="modal fade" id="uploadModel" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<form asp-page-handler="Upload" method="post" enctype="multipart/form-data" id="review-upload-form">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Create Review</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="form-group mb-3">
|
||||
<p class="small mb-0">Select Language</p>
|
||||
<select asp-for="Upload.Language" id="review-language-select">
|
||||
<option selected disabled value="">None Selected</option>
|
||||
@foreach (string lang in UploadModel.SupportedLanguages)
|
||||
{
|
||||
<option value=@lang data-content=@lang>@lang</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group mb-3 custom-file-label" id="create-review-via-upload">
|
||||
<label for="uploadReviewFile" class="input-group-text small mb-0">Select File to Include in API Review</label>
|
||||
<input asp-for="Upload.Files" type="file" class="form-control" id="uploadReviewFile">
|
||||
</div>
|
||||
<div class="form-group d-none mb-3" id="create-review-via-path">
|
||||
<input asp-for="Upload.FilePath" class="form-control" type="text" placeholder="Package root e.g https://github.com/Azure/azure-rest-api-specs/specification/cognitiveservices/AnomalyDetector/">
|
||||
</div>
|
||||
<div class="form-group mb-3 d-none">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" hidden asp-for="Upload.RunAnalysis" checked>
|
||||
<label class="form-check-label" hidden>
|
||||
Run static analysis
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<input asp-for="Label" class="form-control" type="text" placeholder="Enter an optional review label">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<partial name="_ReviewUploadHelp" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button id="review-upload-submit-btn" class="btn btn-primary">
|
||||
<i class="fas fa-cloud-upload-alt"></i> Upload
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-primary" id="create-review-button" data-bs-toggle="modal" data-bs-target="#uploadModel" data-bs-backdrop="false"><small>CREATE</small><br><i class="fas fa-plus"></i><br><small>REVIEW</small></button>
|
||||
|
||||
<div class="mx-5 row">
|
||||
@if (!string.IsNullOrEmpty(Model.NotificationMessage))
|
||||
{
|
||||
<div class="alert alert-warning alert-dismissible fade show mt-1" role="alert">
|
||||
@Model.NotificationMessage
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
}
|
||||
<div class="col-md-12" id="reviews-filter-partial">
|
||||
<partial name="_ReviewsPartial" model="Model.PagedResults" />
|
||||
</div>
|
||||
|
|
|
@ -8,37 +8,52 @@ using APIViewWeb.Repositories;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using APIViewWeb.Managers;
|
||||
using Microsoft.TeamFoundation.Common;
|
||||
using APIViewWeb.Helpers;
|
||||
using Microsoft.VisualStudio.Services.Common;
|
||||
using APIViewWeb.Hubs;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using System.Text;
|
||||
using APIViewWeb.LeanModels;
|
||||
using System.Text;
|
||||
using APIViewWeb.Managers.Interfaces;
|
||||
using System.IO;
|
||||
using ApiView;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace APIViewWeb.Pages.Assemblies
|
||||
{
|
||||
public class IndexPageModel : PageModel
|
||||
{
|
||||
private readonly IReviewManager _reviewManager;
|
||||
private readonly IAPIRevisionsManager _apiRevisionsManager;
|
||||
private readonly IHubContext<SignalRHub> _notificationHubContext;
|
||||
public readonly UserPreferenceCache _preferenceCache;
|
||||
public readonly IUserProfileManager _userProfileManager;
|
||||
private readonly ICodeFileManager _codeFileManager;
|
||||
|
||||
public const int _defaultPageSize = 50;
|
||||
public const string _defaultSortField = "LastUpdatedOn";
|
||||
|
||||
public IndexPageModel(IReviewManager reviewManager, IUserProfileManager userProfileManager, UserPreferenceCache preferenceCache, IHubContext<SignalRHub> notificationHub)
|
||||
public IndexPageModel(IReviewManager reviewManager, IAPIRevisionsManager apiRevisionsManager, IUserProfileManager userProfileManager,
|
||||
UserPreferenceCache preferenceCache, IHubContext<SignalRHub> notificationHub, ICodeFileManager codeFileManager)
|
||||
{
|
||||
_notificationHubContext = notificationHub;
|
||||
_reviewManager = reviewManager;
|
||||
_apiRevisionsManager = apiRevisionsManager;
|
||||
_preferenceCache = preferenceCache;
|
||||
_userProfileManager = userProfileManager;
|
||||
_codeFileManager = codeFileManager;
|
||||
}
|
||||
[FromForm]
|
||||
public UploadModel Upload { get; set; }
|
||||
[FromForm]
|
||||
public string Label { get; set; }
|
||||
|
||||
public ReviewsProperties ReviewsProperties { get; set; } = new ReviewsProperties();
|
||||
|
||||
public (IEnumerable<ReviewListItemModel> Reviews, int TotalCount, int TotalPages,
|
||||
int CurrentPage, int? PreviousPage, int? NextPage) PagedResults { get; set; }
|
||||
[BindProperty(Name = "notificationMessage", SupportsGet = true)]
|
||||
public string NotificationMessage { get; set; }
|
||||
|
||||
public async Task OnGetAsync(
|
||||
IEnumerable<string> search, IEnumerable<string> languages, IEnumerable<string> state,
|
||||
|
@ -66,6 +81,79 @@ namespace APIViewWeb.Pages.Assemblies
|
|||
return Partial("_ReviewsPartial", PagedResults);
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostUploadAsync()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
var errors = new StringBuilder();
|
||||
foreach (var modelState in ModelState.Values)
|
||||
{
|
||||
foreach (var error in modelState.Errors)
|
||||
{
|
||||
errors.AppendLine(error.ErrorMessage);
|
||||
}
|
||||
}
|
||||
var notifcation = new NotificationModel() { Message = errors.ToString(), Level = NotificatonLevel.Error };
|
||||
await _notificationHubContext.Clients.Group(User.GetGitHubLogin()).SendAsync("RecieveNotification", notifcation);
|
||||
return new NoContentResult();
|
||||
}
|
||||
|
||||
var file = Upload.Files?.SingleOrDefault();
|
||||
var review = await GetOrCreateReview(file, Upload.FilePath);
|
||||
|
||||
if (review != null)
|
||||
{
|
||||
APIRevisionListItemModel apiRevision = null;
|
||||
|
||||
if (file != null)
|
||||
{
|
||||
using (var openReadStream = file.OpenReadStream())
|
||||
{
|
||||
apiRevision = await _apiRevisionsManager.AddAPIRevisionAsync(user: User, review: review, apiRevisionType: APIRevisionType.Manual,
|
||||
name: file.FileName, label: Label, fileStream: openReadStream, language: Upload.Language);
|
||||
}
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(Upload.FilePath))
|
||||
{
|
||||
apiRevision = await _apiRevisionsManager.AddAPIRevisionAsync(user: User, review: review, apiRevisionType: APIRevisionType.Manual,
|
||||
name: file.FileName, label: Label, fileStream: null, language: Upload.Language);
|
||||
}
|
||||
return RedirectToPage("Review", new { id = review.Id, revisionId = apiRevision.Id });
|
||||
}
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
private async Task<ReviewListItemModel> GetOrCreateReview(IFormFile file, string filePath)
|
||||
{
|
||||
CodeFile codeFile = null;
|
||||
ReviewListItemModel review = null;
|
||||
|
||||
using var memoryStream = new MemoryStream();
|
||||
if (file != null)
|
||||
{
|
||||
using (var openReadStream = file.OpenReadStream())
|
||||
{
|
||||
codeFile = await _codeFileManager.CreateCodeFileAsync(
|
||||
originalName: file?.FileName, fileStream: openReadStream, runAnalysis: Upload.RunAnalysis, memoryStream: memoryStream, language: Upload.Language);
|
||||
}
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
codeFile = await _codeFileManager.CreateCodeFileAsync(
|
||||
originalName: Upload.FilePath, runAnalysis: Upload.RunAnalysis, memoryStream: memoryStream, language: Upload.Language);
|
||||
}
|
||||
|
||||
if (codeFile != null)
|
||||
{
|
||||
review = await _reviewManager.GetReviewAsync(packageName: codeFile.PackageName, language: codeFile.Language);
|
||||
if (review == null)
|
||||
{
|
||||
review = await _reviewManager.CreateReviewAsync(packageName: codeFile.PackageName, language: codeFile.Language, isClosed: false);
|
||||
}
|
||||
}
|
||||
return review;
|
||||
}
|
||||
|
||||
private async Task RunGetRequest(IEnumerable<string> search, IEnumerable<string> languages,
|
||||
IEnumerable<string> state, IEnumerable<string> status, int pageNo, int pageSize, string sortField, bool fromUrl = true)
|
||||
{
|
||||
|
|
|
@ -262,8 +262,8 @@
|
|||
}
|
||||
@if (Model.ReviewContent.ActiveAPIRevision.APIRevisionType == APIRevisionType.PullRequest)
|
||||
{
|
||||
var prsOfAssociatedReviews = await Model.GetPRsOfAssoicatedReviews();
|
||||
@if (prsOfAssociatedReviews != null && prsOfAssociatedReviews.Count() > 1)
|
||||
var prsOfAssociatedAPIRevisions = await Model.GetPRsOfAssoicatedReviews();
|
||||
@if (prsOfAssociatedAPIRevisions != null && prsOfAssociatedAPIRevisions.Count() > 1)
|
||||
{
|
||||
var associatedReviewsState = String.Empty;
|
||||
if (Request.Cookies.ContainsKey("associatedReviewsCollapse"))
|
||||
|
@ -272,16 +272,17 @@
|
|||
associatedReviewsState = " show";
|
||||
}
|
||||
<p class="h6">
|
||||
<a data-bs-toggle="collapse" href="#associatedReviewsCollapse" aria-expanded="true" aria-controls="associatedReviewsCollapse">Associated Reviews <i class="fa-solid fa-ellipsis"></i></a>
|
||||
<a data-bs-toggle="collapse" href="#associatedReviewsCollapse" aria-expanded="true" aria-controls="associatedReviewsCollapse">Associated APIRevisions <i class="fa-solid fa-ellipsis"></i></a>
|
||||
</p>
|
||||
<ul class="list-group collapse mb-3@(associatedReviewsState)" id="associatedReviewsCollapse">
|
||||
@foreach (var pr in prsOfAssociatedReviews)
|
||||
@foreach (var pr in prsOfAssociatedAPIRevisions)
|
||||
{
|
||||
if (pr.ReviewId != Model.ReviewContent.Review.Id)
|
||||
{
|
||||
var url = @Url.ActionLink("Review", "Assemblies", new
|
||||
{
|
||||
id = pr.ReviewId,
|
||||
revisionId = pr.APIRevisionId
|
||||
});
|
||||
<li class="list-group-item">
|
||||
<a href="@url" target="_blank">@pr.Language/@pr.PackageName</a>
|
||||
|
@ -325,21 +326,6 @@
|
|||
</form>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<div class="form-check form-switch">
|
||||
<form asp-resource="@Model.ReviewContent.Review" class="form-inline" id="reviewCloseForm" method="post" asp-page-handler="ToggleClosed">
|
||||
@if (Model.ReviewContent.Review.IsClosed)
|
||||
{
|
||||
<input class="form-check-input" checked type="checkbox" role="switch" id="reviewCloseSwitch">
|
||||
}
|
||||
else
|
||||
{
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="reviewCloseSwitch">
|
||||
}
|
||||
<label class="form-check-label" for="reviewCloseSwitch">Close Review</label>
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="h6">
|
||||
<a data-bs-toggle="collapse" href="#pageSettingsCollapse" aria-expanded="true" aria-controls="approvalCollapse">Page Settings <i class="fa-solid fa-ellipsis"></i></a>
|
||||
|
@ -607,6 +593,13 @@
|
|||
</div>
|
||||
|
||||
<div id="review-right" class="col-@reviewRightSize @reviewApprovedClass">
|
||||
@if (!string.IsNullOrEmpty(Model.NotificationMessage))
|
||||
{
|
||||
<div class="alert alert-warning alert-dismissible fade show m-1" role="alert">
|
||||
@Model.NotificationMessage
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
}
|
||||
<table class="code-window">
|
||||
<tbody>
|
||||
@foreach (var line in Model.ReviewContent.codeLines)
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using APIViewWeb.Helpers;
|
||||
using APIViewWeb.Hubs;
|
||||
|
@ -18,6 +19,7 @@ using Microsoft.AspNetCore.SignalR;
|
|||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.TeamFoundation.Common;
|
||||
using Microsoft.VisualStudio.Services.ClientNotification;
|
||||
|
||||
|
||||
namespace APIViewWeb.Pages.Assemblies
|
||||
|
@ -70,6 +72,8 @@ namespace APIViewWeb.Pages.Assemblies
|
|||
public bool ShowDocumentation { get; set; }
|
||||
[BindProperty(Name = "diffOnly", SupportsGet = true)]
|
||||
public bool ShowDiffOnly { get; set; }
|
||||
[BindProperty(Name = "notificationMessage", SupportsGet = true)]
|
||||
public string NotificationMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Handler for loading page
|
||||
|
@ -90,7 +94,7 @@ namespace APIViewWeb.Pages.Assemblies
|
|||
showDocumentation: ShowDocumentation, showDiffOnly: ShowDiffOnly, diffContextSize: REVIEW_DIFF_CONTEXT_SIZE,
|
||||
diffContextSeperator: DIFF_CONTEXT_SEPERATOR);
|
||||
|
||||
if (ReviewContent == default(ReviewContentModel))
|
||||
if (ReviewContent.Directive == ReviewContentModelDirective.TryGetlegacyReview)
|
||||
{
|
||||
// Check if you can get review from legacy data
|
||||
var legacyReview = await _reviewManager.GetLegacyReviewAsync(User, id);
|
||||
|
@ -101,7 +105,7 @@ namespace APIViewWeb.Pages.Assemblies
|
|||
|
||||
if (legacyRevision == null)
|
||||
{
|
||||
return NotFound();
|
||||
return RedirectToPage("Index", new { notificationMessage = $"Review with ID : {id} was not found." });
|
||||
}
|
||||
|
||||
var review = await _reviewManager.GetReviewAsync(language: legacyRevision.Files[0].Language,
|
||||
|
@ -116,10 +120,15 @@ namespace APIViewWeb.Pages.Assemblies
|
|||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
return RedirectToPage("Index", new { notificationMessage = $"Review with ID : {id} was not found." });
|
||||
}
|
||||
}
|
||||
|
||||
if (ReviewContent.Directive == ReviewContentModelDirective.ErrorDueToInvalidAPIRevison)
|
||||
{
|
||||
NotificationMessage = ReviewContent.NotificationMessage;
|
||||
}
|
||||
|
||||
if (!ReviewContent.APIRevisionsGrouped.Any())
|
||||
{
|
||||
return RedirectToPage("LegacyReview", new { id = id });
|
||||
|
@ -314,7 +323,7 @@ namespace APIViewWeb.Pages.Assemblies
|
|||
/// <returns></returns>
|
||||
public async Task<IEnumerable<PullRequestModel>> GetAssociatedPullRequest()
|
||||
{
|
||||
return await _pullRequestManager.GetPullRequestsModelAsync(ReviewContent.Review.Id);
|
||||
return await _pullRequestManager.GetPullRequestsModelAsync(reviewId: ReviewContent.Review.Id, apiRevisionId: ReviewContent.ActiveAPIRevision.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -323,8 +332,12 @@ namespace APIViewWeb.Pages.Assemblies
|
|||
/// <returns></returns>
|
||||
public async Task<IEnumerable<PullRequestModel>> GetPRsOfAssoicatedReviews()
|
||||
{
|
||||
var creatingPR = (await _pullRequestManager.GetPullRequestsModelAsync(ReviewContent.Review.Id)).FirstOrDefault();
|
||||
return await _pullRequestManager.GetPullRequestsModelAsync(creatingPR.PullRequestNumber, creatingPR.RepoName);;
|
||||
var creatingPR = (await _pullRequestManager.GetPullRequestsModelAsync(reviewId: ReviewContent.Review.Id, apiRevisionId: ReviewContent.ActiveAPIRevision.Id)).FirstOrDefault();
|
||||
if (creatingPR != null)
|
||||
{
|
||||
return await _pullRequestManager.GetPullRequestsModelAsync(creatingPR.PullRequestNumber, creatingPR.RepoName);
|
||||
}
|
||||
return new List<PullRequestModel>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
</div>
|
||||
|
||||
<div class="container" id="revisions-main-container">
|
||||
<div class="row" asp-resource="@Model.LatestAPIRevision" asp-requirement="@AutoAPIRevisionModifierRequirement.Instance">
|
||||
<div class="row">
|
||||
<div id="add-revision-button">
|
||||
<button type="button" class="btn btn-primary" id="add-revision-button" data-bs-toggle="modal" data-bs-target="#uploadModel"><small>ADD</small><br><i class="fas fa-sm fa-plus"></i><br><small>REVISION</small></button>
|
||||
</div>
|
||||
|
|
|
@ -51,8 +51,13 @@ namespace APIViewWeb
|
|||
return await GetPullRequestFromQueryAsync(query);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<PullRequestModel>> GetPullRequestsAsync(string reviewId) {
|
||||
public async Task<IEnumerable<PullRequestModel>> GetPullRequestsAsync(string reviewId, string apiRevisionId = null) {
|
||||
var query = $"SELECT * FROM PullRequests c WHERE c.ReviewId = '{reviewId}' AND c.IsDeleted = false";
|
||||
if (!string.IsNullOrEmpty(apiRevisionId))
|
||||
{
|
||||
query += $" AND c.APIRevisionId = '{apiRevisionId}'";
|
||||
}
|
||||
|
||||
return await GetPullRequestFromQueryAsync(query);
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,16 @@ namespace APIViewWeb
|
|||
|
||||
public async Task<LegacyReviewModel> GetLegacyReviewAsync(string reviewId)
|
||||
{
|
||||
return await _legacyReviewsContainer.ReadItemAsync<LegacyReviewModel>(reviewId, new PartitionKey(reviewId));
|
||||
var review = default(LegacyReviewModel);
|
||||
try
|
||||
{
|
||||
review = await _legacyReviewsContainer.ReadItemAsync<LegacyReviewModel>(reviewId, new PartitionKey(reviewId));
|
||||
}
|
||||
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
return review;
|
||||
}
|
||||
return review;
|
||||
}
|
||||
|
||||
public async Task<ReviewListItemModel> GetReviewAsync(string language, string packageName, bool? isClosed = false)
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace APIViewWeb.Repositories
|
|||
public interface ICosmosPullRequestsRepository
|
||||
{
|
||||
public Task<PullRequestModel> GetPullRequestAsync(int pullRequestNumber, string repoName, string packageName, string language = null);
|
||||
public Task<IEnumerable<PullRequestModel>> GetPullRequestsAsync(string reviewId);
|
||||
public Task<IEnumerable<PullRequestModel>> GetPullRequestsAsync(string reviewId, string apiRevisionId = null);
|
||||
public Task UpsertPullRequestAsync(PullRequestModel pullRequestModel);
|
||||
public Task<IEnumerable<PullRequestModel>> GetPullRequestsAsync(bool isOpen);
|
||||
public Task<List<PullRequestModel>> GetPullRequestsAsync(int pullRequestNumber, string repoName);
|
||||
|
|
|
@ -141,119 +141,119 @@ stages:
|
|||
artifactName: 'APIView'
|
||||
|
||||
|
||||
# - job: 'Test'
|
||||
#
|
||||
# pool:
|
||||
# name: azsdk-pool-mms-win-2022-general
|
||||
# vmImage: windows-2022
|
||||
#
|
||||
# steps:
|
||||
# - template: /eng/common/pipelines/templates/steps/cosmos-emulator.yml
|
||||
# parameters:
|
||||
# StartParameters: '/noexplorer /noui /enablepreview /disableratelimiting /enableaadauthentication /partitioncount=50 /consistency=Strong'
|
||||
#
|
||||
# - script: |
|
||||
# npm install -g azurite
|
||||
# displayName: 'Install Azurite'
|
||||
#
|
||||
# - task: Powershell@2
|
||||
# inputs:
|
||||
# workingDirectory: $(Agent.TempDirectory)
|
||||
# filePath: $(Build.SourcesDirectory)/eng/scripts/Start-LocalHostApp.ps1
|
||||
# arguments: >
|
||||
# -Process "azurite.cmd"
|
||||
# -ArgumentList "--silent"
|
||||
# -Port "10000"
|
||||
# pwsh: true
|
||||
# displayName: 'Start Azurite'
|
||||
#
|
||||
# - template: /eng/pipelines/templates/steps/install-dotnet.yml
|
||||
#
|
||||
# - pwsh: |
|
||||
# dotnet --list-runtimes
|
||||
# dotnet --version
|
||||
# displayName: 'List .NET run times'
|
||||
#
|
||||
# - task: GoTool@0
|
||||
# inputs:
|
||||
# version: '$(GoVersion)'
|
||||
# displayName: "Use Go $(GoVersion)"
|
||||
#
|
||||
# - script: |
|
||||
# go test ./... -v
|
||||
# workingDirectory: $(GoParserPackagePath)
|
||||
# displayName: 'Test Go parser'
|
||||
#
|
||||
# - script: >-
|
||||
# dotnet test src/dotnet/APIView/APIViewUnitTests/APIViewUnitTests.csproj
|
||||
# --logger trx --collect:"XPlat Code Coverage"
|
||||
# displayName: "Build & Test (Unit)"
|
||||
# env:
|
||||
# DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
|
||||
# DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
# DOTNET_MULTILEVEL_LOOKUP: 0
|
||||
#
|
||||
# - task: Palmmedia.reportgenerator.reportgenerator-build-release-task.reportgenerator@4
|
||||
# condition: and(succeededOrFailed(), eq(variables['CollectCoverage'], 'true'))
|
||||
# displayName: Generate Code Coverage Reports
|
||||
# inputs:
|
||||
# reports: $(Build.SourcesDirectory)\src\dotnet\APIView\APIViewUnitTests\**\coverage.cobertura.xml
|
||||
# targetdir: $(Build.ArtifactStagingDirectory)\coverage
|
||||
# reporttypes: Cobertura
|
||||
# filefilters: +$(Build.SourcesDirectory)\src\dotnet\APIView\**
|
||||
# verbosity: Verbose
|
||||
#
|
||||
# - task: PublishCodeCoverageResults@1
|
||||
# condition: and(succeededOrFailed(), eq(variables['CollectCoverage'], 'true'))
|
||||
# displayName: Publish Code Coverage Reports
|
||||
# inputs:
|
||||
# codeCoverageTool: Cobertura
|
||||
# summaryFileLocation: $(Build.ArtifactStagingDirectory)\coverage\Cobertura.xml
|
||||
#
|
||||
# - script: >-
|
||||
# dotnet test src/dotnet/APIView/APIViewIntegrationTests/APIViewIntegrationTests.csproj
|
||||
# --logger trx
|
||||
# displayName: "Build & Test (Integration)"
|
||||
# env:
|
||||
# DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
|
||||
# DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
# DOTNET_MULTILEVEL_LOOKUP: 0
|
||||
# APIVIEW_ENDPOINT: "http://localhost:5000"
|
||||
# APIVIEW_BLOB__CONNECTIONSTRING: $(AzuriteConnectionString)
|
||||
# APIVIEW_COSMOS__CONNECTIONSTRING: $(CosmosEmulatorConnectionString)
|
||||
#
|
||||
# - script: |
|
||||
# npm install
|
||||
# workingDirectory: $(WebClientProjectDirectory)
|
||||
# displayName: "Install Client Dependencies"
|
||||
#
|
||||
# - script: |
|
||||
# npx playwright install --with-deps
|
||||
# workingDirectory: $(WebClientProjectDirectory)
|
||||
# displayName: "Install Playwright Browsers"
|
||||
#
|
||||
# - script: |
|
||||
# npx playwright test --project=unit-tests
|
||||
# workingDirectory: $(WebClientProjectDirectory)
|
||||
# displayName: "Run Client-Side Unit Tests"
|
||||
#
|
||||
# - task: PublishBuildArtifacts@1
|
||||
# inputs:
|
||||
# pathtoPublish: '$(Build.SourcesDirectory)\src\dotnet\APIView\APIViewWeb\Client\playwright-report'
|
||||
# artifactName: 'Client-Side Unit Test Reports'
|
||||
#
|
||||
# - ${{ if and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['System.TeamProject'], 'internal')) }}:
|
||||
# - template: /eng/pipelines/templates/steps/apiview-ui-tests.yml
|
||||
# parameters:
|
||||
# NodeVersion: $(NodeVersion)
|
||||
# WebClientProjectDirectory: $(WebClientProjectDirectory)
|
||||
# AzuriteConnectionString: $(AzuriteConnectionString)
|
||||
# CosmosEmulatorConnectionString: $(CosmosEmulatorConnectionString)
|
||||
#
|
||||
# - task: PublishTestResults@2
|
||||
# condition: succeededOrFailed()
|
||||
# inputs:
|
||||
# testResultsFiles: '**/*.trx'
|
||||
# testRunTitle: 'Tests against Windows .NET'
|
||||
# testResultsFormat: 'VSTest'
|
||||
# mergeTestResults: true
|
||||
- job: 'Test'
|
||||
|
||||
pool:
|
||||
name: azsdk-pool-mms-win-2022-general
|
||||
vmImage: windows-2022
|
||||
|
||||
steps:
|
||||
- template: /eng/common/pipelines/templates/steps/cosmos-emulator.yml
|
||||
parameters:
|
||||
StartParameters: '/noexplorer /noui /enablepreview /disableratelimiting /enableaadauthentication /partitioncount=50 /consistency=Strong'
|
||||
|
||||
- script: |
|
||||
npm install -g azurite
|
||||
displayName: 'Install Azurite'
|
||||
|
||||
- task: Powershell@2
|
||||
inputs:
|
||||
workingDirectory: $(Agent.TempDirectory)
|
||||
filePath: $(Build.SourcesDirectory)/eng/scripts/Start-LocalHostApp.ps1
|
||||
arguments: >
|
||||
-Process "azurite.cmd"
|
||||
-ArgumentList "--silent"
|
||||
-Port "10000"
|
||||
pwsh: true
|
||||
displayName: 'Start Azurite'
|
||||
|
||||
- template: /eng/pipelines/templates/steps/install-dotnet.yml
|
||||
|
||||
- pwsh: |
|
||||
dotnet --list-runtimes
|
||||
dotnet --version
|
||||
displayName: 'List .NET run times'
|
||||
|
||||
- task: GoTool@0
|
||||
inputs:
|
||||
version: '$(GoVersion)'
|
||||
displayName: "Use Go $(GoVersion)"
|
||||
|
||||
- script: |
|
||||
go test ./... -v
|
||||
workingDirectory: $(GoParserPackagePath)
|
||||
displayName: 'Test Go parser'
|
||||
|
||||
- script: >-
|
||||
dotnet test src/dotnet/APIView/APIViewUnitTests/APIViewUnitTests.csproj
|
||||
--logger trx --collect:"XPlat Code Coverage"
|
||||
displayName: "Build & Test (Unit)"
|
||||
env:
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_MULTILEVEL_LOOKUP: 0
|
||||
|
||||
- task: Palmmedia.reportgenerator.reportgenerator-build-release-task.reportgenerator@4
|
||||
condition: and(succeededOrFailed(), eq(variables['CollectCoverage'], 'true'))
|
||||
displayName: Generate Code Coverage Reports
|
||||
inputs:
|
||||
reports: $(Build.SourcesDirectory)\src\dotnet\APIView\APIViewUnitTests\**\coverage.cobertura.xml
|
||||
targetdir: $(Build.ArtifactStagingDirectory)\coverage
|
||||
reporttypes: Cobertura
|
||||
filefilters: +$(Build.SourcesDirectory)\src\dotnet\APIView\**
|
||||
verbosity: Verbose
|
||||
|
||||
- task: PublishCodeCoverageResults@1
|
||||
condition: and(succeededOrFailed(), eq(variables['CollectCoverage'], 'true'))
|
||||
displayName: Publish Code Coverage Reports
|
||||
inputs:
|
||||
codeCoverageTool: Cobertura
|
||||
summaryFileLocation: $(Build.ArtifactStagingDirectory)\coverage\Cobertura.xml
|
||||
|
||||
#- script: >-
|
||||
# dotnet test src/dotnet/APIView/APIViewIntegrationTests/APIViewIntegrationTests.csproj
|
||||
# --logger trx
|
||||
# displayName: "Build & Test (Integration)"
|
||||
# env:
|
||||
# DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
|
||||
# DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
# DOTNET_MULTILEVEL_LOOKUP: 0
|
||||
# APIVIEW_ENDPOINT: "http://localhost:5000"
|
||||
# APIVIEW_BLOB__CONNECTIONSTRING: $(AzuriteConnectionString)
|
||||
# APIVIEW_COSMOS__CONNECTIONSTRING: $(CosmosEmulatorConnectionString)
|
||||
|
||||
- script: |
|
||||
npm install
|
||||
workingDirectory: $(WebClientProjectDirectory)
|
||||
displayName: "Install Client Dependencies"
|
||||
|
||||
- script: |
|
||||
npx playwright install --with-deps
|
||||
workingDirectory: $(WebClientProjectDirectory)
|
||||
displayName: "Install Playwright Browsers"
|
||||
|
||||
- script: |
|
||||
npx playwright test --project=unit-tests
|
||||
workingDirectory: $(WebClientProjectDirectory)
|
||||
displayName: "Run Client-Side Unit Tests"
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs:
|
||||
pathtoPublish: '$(Build.SourcesDirectory)\src\dotnet\APIView\APIViewWeb\Client\playwright-report'
|
||||
artifactName: 'Client-Side Unit Test Reports'
|
||||
|
||||
- ${{ if and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['System.TeamProject'], 'internal')) }}:
|
||||
- template: /eng/pipelines/templates/steps/apiview-ui-tests.yml
|
||||
parameters:
|
||||
NodeVersion: $(NodeVersion)
|
||||
WebClientProjectDirectory: $(WebClientProjectDirectory)
|
||||
AzuriteConnectionString: $(AzuriteConnectionString)
|
||||
CosmosEmulatorConnectionString: $(CosmosEmulatorConnectionString)
|
||||
|
||||
- task: PublishTestResults@2
|
||||
condition: succeededOrFailed()
|
||||
inputs:
|
||||
testResultsFiles: '**/*.trx'
|
||||
testRunTitle: 'Tests against Windows .NET'
|
||||
testResultsFormat: 'VSTest'
|
||||
mergeTestResults: true
|
||||
|
|
Загрузка…
Ссылка в новой задаче