A Pull Request Scanner that is extendable, allowing you to add pull request providers, or plugins, that do something with the pull request data. If you write the implementation for a new provider, or a new plugin, feel free to open a pull request to add it into the repository.
Currently the out-of-the-box providers are Azure DevOps and GitHub, with a plugin that can publish cards to a Microsoft Teams Webhook, notifying your team of any open pull requests and their current state.
Install via Nuget
Install-Package TomLonghurst.PullRequestScanner
Install-Package TomLonghurst.PullRequestScanner.AzureDevOps
Install-Package TomLonghurst.PullRequestScanner.GitHub
Install-Package TomLonghurst.PullRequestScanner.Plugins.MicrosoftTeams.WebHook
Requires .NET 6
In your startup, call:
services
.AddPullRequestScanner();
And either use any of the already built providers and plugins, or build your own and plug them in. That could either look like:
builder.Services
.AddPullRequestScanner()
.AddGithub(new GithubOrganizationTeamOptions
{
PersonalAccessToken = myGithubPat,
OrganizationSlug = myOrganisation,
TeamSlug = myGithubTeamSlug
})
.AddAzureDevOps(new AzureDevOpsOptions
{
OrganizationSlug = myOrganisation,
ProjectSlug = myAzureDevOpsProjectSlug,
PersonalAccessToken = myAzureDevopsPat
})
.AddMicrosoftTeamsWebHookPublisher(new MicrosoftTeamsOptions
{
WebHookUri = new Uri(myMicrosoftTeamsWebhookUri)
},
microsoftTeamsWebHookPublisherBuilder =>
{
microsoftTeamsWebHookPublisherBuilder.AddLeaderboardCardPublisher();
microsoftTeamsWebHookPublisherBuilder.AddOverviewCardPublisher();
microsoftTeamsWebHookPublisherBuilder.AddStatusCardsPublisher();
}
);
or
builder.Services
.AddPullRequestScanner()
.AddPullRequestProvider(serviceProvider => serviceProvider.GetRequiredService<MyCustomPullRequestProvider1>())
.AddPullRequestProvider(serviceProvider => serviceProvider.GetRequiredService<MyCustomPullRequestProvider2>())
.AddPullRequestProvider(serviceProvider => serviceProvider.GetRequiredService<MyCustomPullRequestProvider3>())
.AddPlugin(serviceProvider => serviceProvider.GetRequiredService<MyCustomPlugin1>())
.AddPlugin(serviceProvider => serviceProvider.GetRequiredService<MyCustomPlugin2>());
Then wherever you want to use it, just inject IPullRequestScanner
into your class. With this you can:
- Get Pull Request Data
- Execute All Plugins
- Execute All Plugins that meet a condition
- Get a particular plugin and invoke it with more granular control
You need to tag/label your pull request with prscanner-ignore
- In Azure DevOps, add as a tag to your pull request
- In GitHub, add as a label to your pull request
A simple Timed Azure Function to notify your team every morning can look as simple as this:
[assembly: WebJobsStartup(typeof(Startup))]
namespace MyNamespace;
public class MorningTrigger
{
private readonly IPullRequestScanner _pullRequestScanner;
public MorningTrigger(IPullRequestScanner pullRequestScanner)
{
_pullRequestScanner = pullRequestScanner;
}
[FunctionName("MorningTrigger")]
public async Task RunAsync([TimerTrigger("0 0 8 * * 1-5")] TimerInfo myTimer, ILogger log)
{
await _pullRequestScanner.ExecutePluginsAsync();
}
}
If I want more control over my plugins or pull request data, I could do this:
public class MorningTrigger
{
private readonly IPullRequestScanner _pullRequestScanner;
private readonly PullRequestOverviewMicrosoftTeamsWebHookPublisher _overviewCardPublisher;
private readonly PullRequestStatusMicrosoftTeamsWebHookPublisher _statusCardPublisher;
public MorningTrigger(IPullRequestScanner pullRequestScanner)
{
_pullRequestScanner = pullRequestScanner;
_overviewCardPublisher = _pullRequestScanner.GetPlugin<PullRequestOverviewMicrosoftTeamsWebHookPublisher>();
_statusCardPublisher = _pullRequestScanner.GetPlugin<PullRequestStatusMicrosoftTeamsWebHookPublisher>();
}
[FunctionName("MorningTrigger")]
public async Task RunAsync([TimerTrigger("0 0 8 * * 1-5")] TimerInfo myTimer, ILogger log)
{
var pullRequests = await _pullRequestScanner.GetPullRequests();
await _overviewCardPublisher.ExecuteAsync(pullRequests);
foreach (var pullRequestStatus in new[] { PullRequestStatus.MergeConflicts, PullRequestStatus.ReadyToMerge })
{
await _statusCardPublisher.ExecuteAsync(pullRequests, pullRequestStatus);
}
}
}