public AzurePipelinesController( IGitHubApplicationClientFactory gitHubApplicationClientFactory, IAzureDevOpsClientFactory azureDevOpsClientFactory, IOptions <BuildMonitorOptions> options, ILogger <AzurePipelinesController> logger) { _gitHubApplicationClientFactory = gitHubApplicationClientFactory; _azureDevOpsClientFactory = azureDevOpsClientFactory; _options = options; _logger = logger; _clientLazy = new Lazy <IAzureDevOpsClient>(BuildAzureDevOpsClient); _projectMapping = new Lazy <Task <Dictionary <string, string> > >(GetProjectMappingInternal); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure( IApplicationBuilder app, IMergePolicyRunnerFactory runnerFactory, IAzureDevOpsClientFactory azDoClientFactory, ILogger <Startup> logger) { app.UseSerilogRequestLogging(); app.Use(ExceptionHandler); app.UseRouting(); app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapGet("/", Home); endpoints.MapPost("/jwt", JwtRoute); endpoints.MapPost("/webhook", Webhook).RequireAuthorization(); endpoints.MapDelete("/policies", ClearPolicies); }); async Task Home(HttpContext context) { await context.Response.WriteAsync("Merge-a-Bot"); } async Task JwtRoute(HttpContext context) { using var sr = new StreamReader(context.Request.Body); var pat = await sr.ReadToEndAsync(); if (string.IsNullOrEmpty(pat)) { context.Response.StatusCode = StatusCodes.Status400BadRequest; await context.Response.WriteAsync("Body did not contain Personal Access Token"); return; } var claims = new List <Claim> { new Claim(JwtRegisteredClaimNames.Sub, pat), }; var token = new JwtSecurityToken( issuer: JwtIssuer, audience: null, claims: claims, expires: DateTime.UtcNow.Date.AddYears(1), signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtSigningKey)), SecurityAlgorithms.HmacSha256) ); var tokenValue = new JwtSecurityTokenHandler().WriteToken(token); await context.Response.WriteAsync(tokenValue); } async Task Webhook(HttpContext context) { var request = context.Request; if (!HttpMethods.IsPost(request.Method)) { return; } if (request.ContentType == null || !request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) { return; } var payload = await WebhookDeserializer.DeserializeAsync(request.Body); var pat = context.User.FindFirstValue(ClaimTypes.NameIdentifier); if (payload != null) { var azDoClient = azDoClientFactory.Create(pat); var organization = payload.Resource.Repository.GetOrganization(); var baseUrl = payload.Resource.Repository.GetBaseUrl(); var factoryContext = new MergePolicyRunnerFactoryContext(azDoClient, payload.Resource.Repository.Id, organization, baseUrl); var runner = await runnerFactory.CreateAsync(factoryContext); await runner.RunAsync(azDoClient, payload); } } async Task ExceptionHandler(HttpContext context, Func <Task> next) { try { await next(); } catch (Exception ex) { logger.LogError(new EventId(1, "UnhandledError"), ex, "Unhandled error"); context.Response.StatusCode = 200; } } Task ClearPolicies(HttpContext context) { var org = context.Request.Query["organization"]; var repoId = context.Request.Query["repositoryId"]; if (string.IsNullOrEmpty(org) || string.IsNullOrEmpty(repoId)) { context.Response.StatusCode = (int)HttpStatusCode.BadRequest; return(Task.CompletedTask); } runnerFactory.Clear(new MergePolicyRunnerFactoryContext(repoId, org)); return(Task.CompletedTask); } }