-
Notifications
You must be signed in to change notification settings - Fork 220
Allow forced creation when release plans already exist #12516
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
cbf8cc0
02167e3
f689b35
d377e4e
d99704c
6204f78
b3b4d42
68d0296
3bbde3c
2165b3d
46b3aaa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -88,6 +88,7 @@ public interface IDevOpsService | |
| public Task<ReleasePlanDetails> GetReleasePlanAsync(int releasePlanId); | ||
| public Task<ReleasePlanDetails> GetReleasePlanForWorkItemAsync(int workItemId); | ||
| public Task<ReleasePlanDetails> GetReleasePlanAsync(string pullRequestUrl); | ||
| public Task<List<ReleasePlanDetails>> GetReleasePlansForProductAsync(string productTreeId, string specApiVersion); | ||
| public Task<WorkItem> CreateReleasePlanWorkItemAsync(ReleasePlanDetails releasePlan); | ||
| public Task<Build> RunSDKGenerationPipelineAsync(string apiSpecBranchRef, string typespecProjectRoot, string apiVersion, string sdkReleaseType, string language, int workItemId, string sdkRepoBranch = ""); | ||
| public Task<Build> GetPipelineRunAsync(int buildId); | ||
|
|
@@ -136,6 +137,38 @@ public async Task<ReleasePlanDetails> GetReleasePlanAsync(int releasePlanId) | |
| return await MapWorkItemToReleasePlanAsync(releasePlanWorkItems[0]); | ||
| } | ||
|
|
||
| public async Task<List<ReleasePlanDetails>> GetReleasePlansForProductAsync(string productTreeId, string specApiVersion) | ||
| { | ||
| try | ||
| { | ||
| var query = $"SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = '{Constants.AZURE_SDK_DEVOPS_RELEASE_PROJECT}' AND [Custom.ProductServiceTreeID] = '{productTreeId}' AND [System.WorkItemType] = 'Release Plan' AND [System.State] IN ('New','Not Started','In Progress')"; | ||
smw-ms marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| var releasePlanWorkItems = await FetchWorkItemsAsync(query); | ||
| if (releasePlanWorkItems.Count == 0) | ||
| { | ||
| logger.LogInformation($"Release plan does not exist for the given product id {productTreeId}"); | ||
| return null; | ||
smw-ms marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| var releasePlans = new List<ReleasePlanDetails>(); | ||
|
|
||
| foreach (var workItem in releasePlanWorkItems) | ||
| { | ||
| var releasePlan = await MapWorkItemToReleasePlanAsync(workItem); | ||
| if (releasePlan.SpecAPIVersion == specApiVersion) | ||
| { | ||
| releasePlans.Add(releasePlan); | ||
| } | ||
| } | ||
|
|
||
| return releasePlans; | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| logger.LogError($"Failed to get release plans for product id {productTreeId}. Error: {ex.Message}"); | ||
smw-ms marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| throw new Exception($"Failed to get release plans for product id {productTreeId}. Error: {ex.Message}"); | ||
| } | ||
| } | ||
|
|
||
| private async Task<ReleasePlanDetails> MapWorkItemToReleasePlanAsync(WorkItem workItem) | ||
| { | ||
| var releasePlan = new ReleasePlanDetails() | ||
|
|
@@ -178,7 +211,7 @@ private async Task<ReleasePlanDetails> MapWorkItemToReleasePlanAsync(WorkItem wo | |
| { | ||
| Language = MapLanguageIdToName(lang), | ||
| GenerationPipelineUrl = sdkGenPipelineUrl, | ||
| SdkPullRequestUrl = sdkPullRequestUrl, | ||
| SdkPullRequestUrl = sdkPullRequestUrl, | ||
| ReleaseStatus = releaseStatus, | ||
| PackageName = packageName, | ||
| ReleaseExclusionStatus = exclusionStatus | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,6 +47,7 @@ IEnvironmentHelper environmentHelper | |
| private readonly Option<bool> isTestReleasePlanOpt = new(["--test-release"], () => false, "Create release plan in test environment") { IsRequired = false }; | ||
| private readonly Option<string> userEmailOpt = new(["--user-email"], "User email for release plan creation") { IsRequired = false }; | ||
| private readonly Option<string> namespaceApprovalIssueOpt = new Option<string>(["--namespace-approval-issue"], "Namespace approval issue URL") { IsRequired = true }; | ||
| private readonly Option<bool> forceCreateReleasePlanOpt = new(["--force-create-release"], () => false, "Force creation of release plan even if one already exists") { IsRequired = false }; | ||
|
|
||
| //Namespace approval repo details | ||
| private const string namespaceApprovalRepoName = "azure-sdk"; | ||
|
|
@@ -73,7 +74,7 @@ IEnvironmentHelper environmentHelper | |
| protected override List<Command> GetCommands() => | ||
| [ | ||
| new(getReleasePlanDetailsCommandName, "Get release plan details") {workItemIdOpt, releasePlanNumberOpt}, | ||
| new(createReleasePlanCommandName, "Create a release plan") { typeSpecProjectPathOpt, targetReleaseOpt, serviceTreeIdOpt, productTreeIdOpt, apiVersionOpt, pullRequestOpt, sdkReleaseTypeOpt, userEmailOpt, isTestReleasePlanOpt }, | ||
| new(createReleasePlanCommandName, "Create a release plan") { typeSpecProjectPathOpt, targetReleaseOpt, serviceTreeIdOpt, productTreeIdOpt, apiVersionOpt, pullRequestOpt, sdkReleaseTypeOpt, userEmailOpt, isTestReleasePlanOpt, forceCreateReleasePlanOpt }, | ||
| new(linkNamespaceApprovalIssueCommandName, "Link namespace approval issue to release plan") { workItemIdOpt, namespaceApprovalIssueOpt } | ||
| ]; | ||
|
|
||
|
|
@@ -98,7 +99,8 @@ public override async Task<CommandResponse> HandleCommand(InvocationContext ctx, | |
| var sdkReleaseType = commandParser.GetValueForOption(sdkReleaseTypeOpt); | ||
| var isTestReleasePlan = commandParser.GetValueForOption(isTestReleasePlanOpt); | ||
| var userEmail = commandParser.GetValueForOption(userEmailOpt); | ||
| return await CreateReleasePlan(typeSpecProjectPath, targetReleaseMonthYear, serviceTreeId, productTreeId, specApiVersion, specPullRequestUrl, sdkReleaseType, userEmail: userEmail, isTestReleasePlan: isTestReleasePlan); | ||
| var forceCreateReleasePlan = commandParser.GetValueForOption(forceCreateReleasePlanOpt); | ||
| return await CreateReleasePlan(typeSpecProjectPath, targetReleaseMonthYear, serviceTreeId, productTreeId, specApiVersion, specPullRequestUrl, sdkReleaseType, userEmail: userEmail, isTestReleasePlan: isTestReleasePlan, forceCreateReleasePlan); | ||
|
|
||
| case linkNamespaceApprovalIssueCommandName: | ||
| return await LinkNamespaceApprovalIssue(commandParser.GetValueForOption(workItemIdOpt), commandParser.GetValueForOption(namespaceApprovalIssueOpt)); | ||
|
|
@@ -221,7 +223,7 @@ Please create a pull request in the public Azure/azure-rest-api-specs repository | |
| } | ||
|
|
||
| [McpServerTool(Name = "azsdk_create_release_plan"), Description("Create Release Plan")] | ||
| public async Task<ObjectCommandResponse> CreateReleasePlan(string typeSpecProjectPath, string targetReleaseMonthYear, string serviceTreeId, string productTreeId, string specApiVersion, string specPullRequestUrl, string sdkReleaseType, string userEmail = "", bool isTestReleasePlan = false) | ||
| public async Task<ObjectCommandResponse> CreateReleasePlan(string typeSpecProjectPath, string targetReleaseMonthYear, string serviceTreeId, string productTreeId, string specApiVersion, string specPullRequestUrl, string sdkReleaseType, string userEmail = "", bool isTestReleasePlan = false, bool forceCreateReleasePlan = false) | ||
| { | ||
| try | ||
| { | ||
|
|
@@ -235,21 +237,37 @@ public async Task<ObjectCommandResponse> CreateReleasePlan(string typeSpecProjec | |
| { | ||
| sdkReleaseType = mappedType; | ||
| } | ||
|
|
||
| ValidateCreateReleasePlanInputAsync(typeSpecProjectPath, serviceTreeId, productTreeId, specPullRequestUrl, sdkReleaseType, specApiVersion); | ||
|
|
||
| // Check for existing release plan for the given pull request URL. | ||
| logger.LogInformation("Checking for existing release plan for pull request URL: {specPullRequestUrl}", specPullRequestUrl); | ||
| var existingReleasePlan = await devOpsService.GetReleasePlanAsync(specPullRequestUrl); | ||
| if (existingReleasePlan != null && existingReleasePlan.WorkItemId > 0) | ||
| ValidateCreateReleasePlanInputAsync(typeSpecProjectPath, serviceTreeId, productTreeId, specPullRequestUrl, sdkReleaseType, specApiVersion); | ||
|
|
||
| if (!forceCreateReleasePlan) | ||
| { | ||
| return new ObjectCommandResponse | ||
| // Check for existing release plan for the given pull request URL. | ||
| logger.LogInformation("Checking for existing release plan for pull request URL: {specPullRequestUrl}", specPullRequestUrl); | ||
| var existingReleasePlan = await devOpsService.GetReleasePlanAsync(specPullRequestUrl); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if there are multiples Release plans with the same API spec PR, wouldn't this return a list of release plans?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think service method fetches only latest release plan. @smw-ms can you please check and confirm this?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. only one release plan is returned. looking at the code there is no sorting happening, it just returns the first linked release plan it comes across, so there is no guarantee that it is the latest release plan |
||
| if (existingReleasePlan != null && existingReleasePlan.WorkItemId > 0) | ||
| { | ||
| Message = $"Release plan already exists for the pull request: {specPullRequestUrl}. Release plan link: {existingReleasePlan.ReleasePlanLink}", | ||
| Result = existingReleasePlan | ||
| }; | ||
| } | ||
| return new ObjectCommandResponse | ||
| { | ||
| Message = $"Release plan not created. Release plan already exists for the pull request: {specPullRequestUrl}. Release plan link: {existingReleasePlan.ReleasePlanLink}", | ||
smw-ms marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Result = existingReleasePlan | ||
| }; | ||
| } | ||
|
|
||
| logger.LogInformation("Checking for existing release plans for product: {productTreeId}", productTreeId); | ||
| var existingReleasePlans = await devOpsService.GetReleasePlansForProductAsync(productTreeId, specApiVersion); | ||
| existingReleasePlans = existingReleasePlans.Where(releasePlan => releasePlan.WorkItemId > 0).ToList(); | ||
smw-ms marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (existingReleasePlans.Any()) | ||
| { | ||
| return new ObjectCommandResponse | ||
| { | ||
| Message = $" Release plan not created. Release plan(s) already exist for the product: {productTreeId}." | ||
smw-ms marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| + $"Release plan link(s): {string.Join("\n ", existingReleasePlans.Select(p => p.ReleasePlanLink))}", | ||
| Result = existingReleasePlans | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| // Check environment variable to determine if this should be a test release plan | ||
| var isAgentTesting = environmentHelper.GetBooleanVariable("AZSDKTOOLS_AGENT_TESTING", false); | ||
| if (isAgentTesting) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.