diff --git a/CloneDevOpsTemplate/Controllers/ProjectController.cs b/CloneDevOpsTemplate/Controllers/ProjectController.cs index 330e04a..85ff366 100644 --- a/CloneDevOpsTemplate/Controllers/ProjectController.cs +++ b/CloneDevOpsTemplate/Controllers/ProjectController.cs @@ -78,6 +78,8 @@ await Task.WhenAll( _cloneManager.CloneRepositoriesAsync(templateProjectId, cloneProjectResult.Project.Id) ); + await _cloneManager.CloneGitPullRequestsAsync(templateProjectId, cloneProjectResult.Project.Id); + return RedirectToAction("Project", new { projectId = cloneProjectResult.Project.Id }); } diff --git a/CloneDevOpsTemplate/Controllers/RepositoryController.cs b/CloneDevOpsTemplate/Controllers/RepositoryController.cs index eff4fe0..9438710 100644 --- a/CloneDevOpsTemplate/Controllers/RepositoryController.cs +++ b/CloneDevOpsTemplate/Controllers/RepositoryController.cs @@ -48,7 +48,7 @@ public async Task PullRequests(Guid projectId) return View(pullRequests.Value); } - pullRequests = await _repositoryService.GetGitPullRequest(projectId) ?? new(); + pullRequests = await _repositoryService.GetGitPullRequestAsync(projectId) ?? new(); return View(pullRequests.Value); } @@ -72,4 +72,24 @@ public async Task CloneRepository(Guid templateProjectId, Guid pr return await CloneRepository(); } + + [HttpGet] + public async Task ClonePullRequests() + { + return await CloneRepository(); + } + + [HttpPost] + public async Task ClonePullRequests(Guid templateProjectId, Guid projectId) + { + if (!ModelState.IsValid) + { + return await ClonePullRequests(); + } + + await _cloneManager.CloneGitPullRequestsAsync(templateProjectId, projectId); + ViewBag.SuccessMessage = "Success"; + + return await ClonePullRequests(); + } } \ No newline at end of file diff --git a/CloneDevOpsTemplate/IServices/IRepositoryService.cs b/CloneDevOpsTemplate/IServices/IRepositoryService.cs index 8586a43..1989060 100644 --- a/CloneDevOpsTemplate/IServices/IRepositoryService.cs +++ b/CloneDevOpsTemplate/IServices/IRepositoryService.cs @@ -10,5 +10,6 @@ public interface IRepositoryService Task DeleteRepositoryAsync(Guid projectId, Guid repositoryId); Task CreateImportRequestAsync(Guid projectId, Guid repositoryId, string sourceRepositoryRemoteUrl, Guid serviceEndpointId); Task GetImportRequestAsync(Guid projectId, Guid repositoryId, int importRequestId); - Task GetGitPullRequest(Guid projectId); + Task GetGitPullRequestAsync(Guid projectId); + Task CreateGitPullRequestAsync(Guid projectId, Guid repositoryId, GitPullRequestBase pullRequest); } diff --git a/CloneDevOpsTemplate/Managers/CloneManager.cs b/CloneDevOpsTemplate/Managers/CloneManager.cs index 551e17e..ac83b9f 100644 --- a/CloneDevOpsTemplate/Managers/CloneManager.cs +++ b/CloneDevOpsTemplate/Managers/CloneManager.cs @@ -216,4 +216,33 @@ public async Task CloneTeamIterationsAsync(Guid templateProjectId, Guid projectI } } } + + public async Task CloneGitPullRequestsAsync(Guid templateProjectId, Guid projectId) + { + var templatePullRequests = await _repositoryService.GetGitPullRequestAsync(templateProjectId) ?? new(); + var mappedRespositories = await MapRepositories(templateProjectId, projectId); + foreach (var templatePullRequest in templatePullRequests.Value) + { + var repository = mappedRespositories.GetValueOrDefault(templatePullRequest.Repository.Id); + await _repositoryService.CreateGitPullRequestAsync(projectId, repository, templatePullRequest); + } + } + + public async Task> MapRepositories(Guid templateProjectId, Guid projectId) + { + var mappedRespositories = new Dictionary(); + var repositories = await _repositoryService.GetRepositoriesAsync(projectId) ?? new(); + var templateRepositories = await _repositoryService.GetRepositoriesAsync(templateProjectId) ?? new(); + + foreach (var templateRepository in templateRepositories.Value) + { + var mappedRespository = repositories.Value.FirstOrDefault(r => r.Name == templateRepository.Name); + if (mappedRespository is not null) + { + mappedRespositories.Add(templateRepository.Id, mappedRespository.Id); + } + } + + return mappedRespositories; + } } \ No newline at end of file diff --git a/CloneDevOpsTemplate/Managers/ICloneManager.cs b/CloneDevOpsTemplate/Managers/ICloneManager.cs index 811e5f0..d00eb7c 100644 --- a/CloneDevOpsTemplate/Managers/ICloneManager.cs +++ b/CloneDevOpsTemplate/Managers/ICloneManager.cs @@ -15,4 +15,5 @@ public interface ICloneManager Task CloneTeamsAndSettingsAndBoardsAsync(Project templateProject, Project project); Task CloneTeamSettingsAsync(Guid templateProjectId, Guid projectId, Guid templateTeamId, Guid projectTeamId); Task CloneTeamIterationsAsync(Guid templateProjectId, Guid projectId, Guid templateTeamId, Guid projectTeamId); + Task CloneGitPullRequestsAsync(Guid templateProjectId, Guid projectId); } diff --git a/CloneDevOpsTemplate/Models/Identity.cs b/CloneDevOpsTemplate/Models/Identity.cs new file mode 100644 index 0000000..933d116 --- /dev/null +++ b/CloneDevOpsTemplate/Models/Identity.cs @@ -0,0 +1,11 @@ +namespace CloneDevOpsTemplate.Models; + +public class IdentityRef +{ + public string DisplayName { get; set; } = string.Empty; + public string Url { get; set; } = string.Empty; + public string Descriptor { get; set; } = string.Empty; + public string DirectoryAlias { get; set; } = string.Empty; + public string Id { get; set; } = string.Empty; + public bool IsDeletedInOrigin { get; set; } +} diff --git a/CloneDevOpsTemplate/Models/PullRequests.cs b/CloneDevOpsTemplate/Models/PullRequests.cs index 740e272..7cbf065 100644 --- a/CloneDevOpsTemplate/Models/PullRequests.cs +++ b/CloneDevOpsTemplate/Models/PullRequests.cs @@ -8,25 +8,29 @@ public class GitPullRequests public GitPullRequest[] Value { get; set; } = []; } -public class GitPullRequest +public class GitPullRequestBase +{ + public string Title { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string SourceRefName { get; set; } = string.Empty; + public string TargetRefName { get; set; } = string.Empty; + public IdentityRef CreatedBy { get; set; } = new(); + public bool IsDraft { get; set; } + public IdentityRef[] Reviewers { get; set; } = []; +} + +public class GitPullRequest : GitPullRequestBase { public Repository Repository { get; set; } = new(); public int PullRequestId { get; set; } public int CodeReviewId { get; set; } public PullRequestStatus Status { get; set; } - public User CreatedBy { get; set; } = new(); public DateTime CreationDate { get; set; } - public string Title { get; set; } = string.Empty; - public string Description { get; set; } = string.Empty; - public string SourceRefName { get; set; } = string.Empty; - public string TargetRefName { get; set; } = string.Empty; public PullRequestAsyncStatus MergeStatus { get; set; } - public bool IsDraft { get; set; } public Guid MergeId { get; set; } public GitCommitRef LastMergeSourceCommit { get; set; } = new(); public GitCommitRef LastMergeTargetCommit { get; set; } = new(); public GitCommitRef LastMergeCommit { get; set; } = new(); - public User[] Reviewers { get; set; } = []; public bool SupportsIterations { get; set; } } diff --git a/CloneDevOpsTemplate/Models/Services.cs b/CloneDevOpsTemplate/Models/Services.cs index 8447266..6b0c823 100644 --- a/CloneDevOpsTemplate/Models/Services.cs +++ b/CloneDevOpsTemplate/Models/Services.cs @@ -19,19 +19,13 @@ public class ServiceModelBase public class ServiceModel : ServiceModelBase { public Guid Id { get; set; } - public User CreatedBy { get; set; } = new(); + public IdentityRef CreatedBy { get; set; } = new(); public string Description { get; set; } = string.Empty; public bool IsShared { get; set; } public bool IsOutdated { get; set; } public DateTime CreationDate { get; set; } } -public class User -{ - public string DisplayName { get; set; } = string.Empty; - public string Url { get; set; } = string.Empty; -} - public class ServiceAuthorization { public string Scheme { get; set; } = string.Empty; diff --git a/CloneDevOpsTemplate/Services/RepositoryService.cs b/CloneDevOpsTemplate/Services/RepositoryService.cs index 75f4c67..fdc4a39 100644 --- a/CloneDevOpsTemplate/Services/RepositoryService.cs +++ b/CloneDevOpsTemplate/Services/RepositoryService.cs @@ -49,8 +49,13 @@ public Task DeleteRepositoryAsync(Guid projectId, Guid repo return _client.GetFromJsonAsync($"{projectId}/_apis/git/repositories/{repositoryId}/importRequests/{importRequestId}"); } - public Task GetGitPullRequest(Guid projectId) + public Task GetGitPullRequestAsync(Guid projectId) { return _client.GetFromJsonAsync($"{projectId}/_apis/git/pullrequests"); } + + public Task CreateGitPullRequestAsync(Guid projectId, Guid repositoryId, GitPullRequestBase pullRequest) + { + return _client.PostAsJsonAsync($"{projectId}/_apis/git/repositories/{repositoryId}/pullrequests?api-version=7.1", pullRequest); + } } \ No newline at end of file diff --git a/CloneDevOpsTemplate/Views/Repository/ClonePullRequests.cshtml b/CloneDevOpsTemplate/Views/Repository/ClonePullRequests.cshtml new file mode 100644 index 0000000..e7aa999 --- /dev/null +++ b/CloneDevOpsTemplate/Views/Repository/ClonePullRequests.cshtml @@ -0,0 +1,10 @@ +@model ProjectBase[] +@{ + ViewData["Title"] = "Clone pull requests"; +} + +

Clone pull requests

+ +@{ + await Html.RenderPartialAsync("_CloneByProject", Tuple.Create(Model, "Repository", "ClonePullRequests")); +} diff --git a/CloneDevOpsTemplate/Views/Shared/_Header.cshtml b/CloneDevOpsTemplate/Views/Shared/_Header.cshtml index 880daf2..1b45ded 100644 --- a/CloneDevOpsTemplate/Views/Shared/_Header.cshtml +++ b/CloneDevOpsTemplate/Views/Shared/_Header.cshtml @@ -62,6 +62,10 @@ Repository +
  • + Pull + requests +