Skip to content

Commit b02ff4b

Browse files
author
Calin Lupas
authored
Merge pull request #48 from DevExcelerate/feature/updates
Feature/updates - Auto PR approval + fixes issues
2 parents e5d3b86 + fd05618 commit b02ff4b

16 files changed

Lines changed: 139 additions & 110 deletions

README.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,3 @@ GitHub DevExcelerate - Platform Engineering. Improve the Developer Experience an
33
---
44

55
Please view our documentation at [docs/main.md](./docs/main.md) for more information.
6-
7-
## Contributing
8-
9-
Lorem ipsum
10-
11-
## Trademarks
12-
13-
Lorem ipsum

docs/main.md

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ This application is built using .NET Core. It supports multiple data stores, inc
2727
| `GitHub:RepoOnboarding` | String | Repository for onboarding. |
2828
| `GitHub:RepoInventory` | String | Repository for inventory. |
2929
| `GitHub:RepoPolicy` | String | Repository for policy. |
30-
| `GitHub:IssueAutoApprove` | String | Automatically approve issues, "true" or "false". |
31-
| `GitHub:UseInventoryWithPullRequest` | String | Use inventory with pull requests, "true" or "false". |
32-
| `GitHub:RepoRulesetsCustomPropertyName` | String | Custom property name for repository rulesets. |
3330
| `Azure:KeyVaultName` | String | Name of the Azure Key Vault. |
3431
| `Azure:KeyName` | String | Name of the key in Azure Key Vault. |
3532
| `Azure:AzureMonitor:EnableTelemetry` | String | Whether to enable telemetry or not. |
@@ -41,28 +38,6 @@ This application is built using .NET Core. It supports multiple data stores, inc
4138
| `DataStore:CosmosDb:GitHubWebhooksContainer` | String | Container for GitHub webhooks in Cosmos DB. |
4239
| `DataStore:SqlServer:ConnectionString` | String | Connection string for SQL Server. |
4340

44-
### Feature flags
45-
46-
Follows the .NET FeatureManagement [schema](https://learn.microsoft.com/en-us/azure/azure-app-configuration/feature-management-dotnet-reference#net-feature-management-schema)
47-
48-
```json
49-
"feature_management": {
50-
"feature_flags": [
51-
{
52-
"id": "IssueAutoApprove",
53-
"display_name": "Auto Approve Issues",
54-
"description": "Whether to auto approve issues or let someone approve them",
55-
"enabled": true
56-
},
57-
{
58-
"id": "UseInventoryWithPullRequest",
59-
"display_name": "Use Pull Request for Inventory Metadata",
60-
"description": "Determines whether to use a pull request to populate the inventory metadata or not",
61-
"enabled": true
62-
}
63-
]
64-
}
65-
```
6641

6742
### Example
6843

@@ -85,9 +60,6 @@ Follows the .NET FeatureManagement [schema](https://learn.microsoft.com/en-us/az
8560
"RepoOnboarding": "",
8661
"RepoInventory": "",
8762
"RepoPolicy": "",
88-
"IssueAutoApprove": "true",
89-
"UseInventoryWithPullRequest": "true",
90-
"RepoRulesetsCustomPropertyName": ""
9163
},
9264
"Azure": {
9365
"KeyVaultName": "",

src/DevExcelerateApi/Core/Extensions/GitHubClientExtensions.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,59 @@ public static async Task<PullRequest> CreatePullRequestAsync(this IGitHubClient
192192
return await gitHubClient.PullRequest.Create(owner, repo, newPullRequest);
193193
}
194194

195+
public static async Task<PullRequestMerge> MergePullRequestAsync(this IGitHubClient gitHubClient, string owner, string repo, int pullRequestNumber, string? commitTitle = null, string? commitMessage = null)
196+
{
197+
if (gitHubClient == null)
198+
{
199+
throw new InvalidOperationException("GitHub client is not configured.");
200+
}
201+
202+
try
203+
{
204+
// First, check if the pull request exists and is mergeable
205+
var pullRequest = await gitHubClient.PullRequest.Get(owner, repo, pullRequestNumber);
206+
207+
if (pullRequest.State == ItemState.Closed)
208+
{
209+
throw new InvalidOperationException($"Pull request #{pullRequestNumber} is already closed.");
210+
}
211+
212+
if (pullRequest.Merged == true)
213+
{
214+
throw new InvalidOperationException($"Pull request #{pullRequestNumber} is already merged.");
215+
}
216+
217+
if (pullRequest.Mergeable == false)
218+
{
219+
throw new InvalidOperationException($"Pull request #{pullRequestNumber} has conflicts and cannot be merged.");
220+
}
221+
222+
// Create the merge request
223+
var mergePullRequest = new MergePullRequest
224+
{
225+
CommitTitle = commitTitle ?? pullRequest.Title,
226+
CommitMessage = commitMessage ?? pullRequest.Body
227+
};
228+
229+
// Perform the merge
230+
var mergeResult = await gitHubClient.PullRequest.Merge(owner, repo, pullRequestNumber, mergePullRequest);
231+
232+
return mergeResult;
233+
}
234+
catch (NotFoundException)
235+
{
236+
throw new InvalidOperationException($"Pull request #{pullRequestNumber} not found in repository '{owner}/{repo}'.");
237+
}
238+
catch (ApiException ex) when (ex.StatusCode == System.Net.HttpStatusCode.MethodNotAllowed)
239+
{
240+
throw new InvalidOperationException($"Pull request #{pullRequestNumber} cannot be merged. It may have conflicts, required status checks may be failing, or branch protection rules may be preventing the merge.");
241+
}
242+
catch (Exception ex)
243+
{
244+
throw new InvalidOperationException($"Failed to merge pull request #{pullRequestNumber} in repository '{owner}/{repo}': {ex.Message}", ex);
245+
}
246+
}
247+
195248
public static async Task<IReadOnlyList<GitHubCommitFile>> GetCommitFilesAsync(this IGitHubClient gitHubClient, string owner, string repo, string commitSha)
196249
{
197250
if (gitHubClient == null)

src/DevExcelerateApi/Core/Options/GitHubOptions.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,6 @@ public class GitHubOptions
4646
[Required]
4747
public required string RepoPolicy { get; set; }
4848

49-
/// <summary>
50-
/// The custom property name for the repository rulesets.
51-
/// </summary>
52-
[Required]
53-
public required string RepoRulesetsCustomPropertyName { get; set; }
54-
5549
/// <summary>
5650
/// Gets or sets the local path to the RSA private key used for the signing credentials.
5751
/// </summary>

src/DevExcelerateApi/DevExcelerateApi.csproj

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@
1111
<PackageReference Include="Azure.Identity" Version="1.14.0" />
1212
<PackageReference Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.3.0" />
1313
<PackageReference Include="Azure.Security.KeyVault.Keys" Version="4.7.0" />
14-
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.51.0" />
15-
<PackageReference Include="Microsoft.FeatureManagement" Version="4.0.0" />
16-
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.10.0" />
14+
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.52.0" />
15+
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.12.1" />
1716
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
1817
<PackageReference Include="Octokit" Version="14.0.0" />
1918
<PackageReference Include="Octokit.Webhooks.AspNetCore" Version="2.4.1" />
20-
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.10.0" />
19+
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.12.1" />
2120
<PackageReference Include="YamlDotNet" Version="16.3.0" />
2221
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.2" />
2322
<PackageReference Include="Dapper" Version="2.1.66" />

src/DevExcelerateApi/Models/DevExOrganizationPolicies.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,30 @@ public class DevExOrganizationPolicies
2727
[YamlMember(Alias = "team_naming_convention", Order = 5)]
2828
public string? TeamNamingConvention { get; set; }
2929

30+
/// <summary>
31+
/// Whether to auto approve issues or let someone approve them
32+
/// </summary>
33+
[YamlMember(Alias = "issue_auto_approve", Order = 6)]
34+
public bool? IssueAutoApprove { get; set; } = true;
35+
36+
/// <summary>
37+
/// Whether to auto approve pull requests or let someone approve them
38+
/// </summary>
39+
[YamlMember(Alias = "pull_request_auto_approve", Order = 7)]
40+
public bool? PullRequestAutoApprove { get; set; } = true;
41+
42+
/// <summary>
43+
/// Determines whether to use a pull request to populate the inventory metadata or not
44+
/// </summary>
45+
[YamlMember(Alias = "use_inventory_with_pull_request", Order = 8)]
46+
public bool? UseInventoryWithPullRequest { get; set; } = true;
47+
48+
/// <summary>
49+
/// The custom property name for the repository rulesets.
50+
/// </summary>
51+
[YamlMember(Alias = "repo_rulesets_custom_property_name", Order = 9)]
52+
public string? RepoRulesetsCustomPropertyName { get; set; } = "DevExcelerate-Rulesets";
53+
3054
public static DevExOrganizationPolicies DeserializeFromYaml(string yamlContent)
3155
{
3256
ArgumentNullException.ThrowIfNull(yamlContent);

src/DevExcelerateApi/Models/RepositoryRequestModel.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ public class RepositoryRequestModel : DevExIssueRequestModel
1818
[YamlMember(Alias = "visibility", Order = 12)]
1919
public string? RepositoryVisibility { get; set; }
2020

21-
[YamlMember(Alias = "classification", Order = 13)]
22-
public string? RepositoryClassification { get; set; }
23-
2421
[YamlMember(Alias = "repository_description", Order = 14)]
2522
public string? RepositoryDescription { get; set; }
2623

@@ -93,7 +90,6 @@ public class RepositoryRequestModel : DevExIssueRequestModel
9390
RepositoryName = repositoryName?.ToString()?.SanitizeResourceName(),
9491
NewRepositoryName = newRepositoryName?.ToString()?.SanitizeResourceName(),
9592
RepositoryVisibility = repositoryVisibility?.ToString(),
96-
RepositoryClassification = repositoryClassification?.ToString(),
9793
RepositoryDescription = repositoryDescription?.ToString(),
9894
RepositoryMaintainers = repositoryMaintainers?.ToString(),
9995
MaintainerList = repositoryMaintainers?.ToString().ConvertCsvToList(),
@@ -116,7 +112,6 @@ public bool IsValidCreate()
116112
return RequestType == RequestType.CREATE_REPOSITORY &&
117113
!string.IsNullOrEmpty(RepositoryName) &&
118114
!string.IsNullOrEmpty(RepositoryVisibility) &&
119-
!string.IsNullOrEmpty(RepositoryClassification) &&
120115
!string.IsNullOrEmpty(RepositoryDescription) &&
121116
ContributorList?.Count > 0 &&
122117
RulesetList?.Count > 0;
@@ -131,7 +126,6 @@ public bool IsValidUpdate()
131126
!string.IsNullOrEmpty(NewRepositoryName) ||
132127
!string.IsNullOrEmpty(RepositoryDescription) ||
133128
!string.IsNullOrEmpty(RepositoryVisibility) ||
134-
!string.IsNullOrEmpty(RepositoryClassification) ||
135129
!string.IsNullOrEmpty(RepositoryMaintainers) ||
136130
!string.IsNullOrEmpty(RepositoryReaders) ||
137131
!string.IsNullOrEmpty(RepositoryContributors) ||
@@ -155,8 +149,7 @@ public void Update(RepositoryRequestModel model)
155149
{
156150
if (string.IsNullOrEmpty(RepositoryDescription)) RepositoryDescription = model.RepositoryDescription;
157151
if (string.IsNullOrEmpty(RepositoryVisibility)) RepositoryVisibility = model.RepositoryVisibility;
158-
if (string.IsNullOrEmpty(RepositoryClassification)) RepositoryClassification = model.RepositoryClassification;
159-
152+
160153
if (MaintainerList == null || MaintainerList.Count == 0)
161154
{
162155
MaintainerList = model.MaintainerList ?? [];

src/DevExcelerateApi/Models/TeamRequestModel.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,7 @@ public bool IsValidCreate()
102102
{
103103
return RequestType == RequestType.CREATE_TEAM &&
104104
!string.IsNullOrEmpty(TeamName) &&
105-
!string.IsNullOrEmpty(TeamDescription) &&
106-
!string.IsNullOrEmpty(TeamVisibility);
105+
!string.IsNullOrEmpty(TeamDescription);
107106
}
108107

109108
public bool IsValidUpdate()

src/DevExcelerateApi/Program.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using System.Text.Json;
99
using Azure.Core;
1010
using Azure.Identity;
11-
using Microsoft.FeatureManagement;
1211

1312
// see https://learn.microsoft.com/en-us/aspnet/core/fundamentals/localization/provide-resources?view=aspnetcore-9.0#culture-fallback-behavior
1413
[assembly: NeutralResourcesLanguage("en")]
@@ -71,8 +70,6 @@ public static async Task Main(string[] args)
7170
});
7271
}
7372

74-
builder.Services.AddFeatureManagement();
75-
7673
// Application Build & Run
7774

7875
// Configure middleware and endpoints

src/DevExcelerateApi/Resources/Services.LocalizationService.fr.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@
268268
<value>description_du_dépôt</value>
269269
</data>
270270
<data name="repository_maintainers" xml:space="preserve">
271-
<value>mainteneurs_du_dépôt</value>
271+
<value>responsables_du_dépôt</value>
272272
</data>
273273
<data name="repository_readers" xml:space="preserve">
274274
<value>lecteurs_du_dépôt</value>

0 commit comments

Comments
 (0)