-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathPushHandler.cs
More file actions
115 lines (98 loc) · 3.65 KB
/
Copy pathPushHandler.cs
File metadata and controls
115 lines (98 loc) · 3.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Copyright (c) Martin Costello, 2022. All rights reserved.
// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.
using Octokit;
using Octokit.Webhooks;
using Octokit.Webhooks.Events;
namespace MartinCostello.Costellobot.Handlers;
public sealed partial class PushHandler : IHandler
{
private const string DefaultBranch = "refs/heads/main";
private const string DispatchDestination = "martincostello/github-automation";
private readonly IGitHubClient _client;
private readonly ILogger _logger;
public PushHandler(
IGitHubClientForInstallation client,
ILogger<PushHandler> logger)
{
_client = client;
_logger = logger;
}
public async Task HandleAsync(WebhookEvent message)
{
if (message is not PushEvent push ||
push.Repository is not { Fork: false } repo ||
push.Commits is not { } commits ||
push.Created ||
push.Deleted ||
!string.Equals(push.Ref, DefaultBranch, StringComparison.Ordinal))
{
return;
}
var filesChanged = new HashSet<string>();
foreach (var commit in commits)
{
foreach (var file in commit.Added)
{
filesChanged.Add(file);
}
foreach (var file in commit.Modified)
{
filesChanged.Add(file);
}
}
if (DependencyFileChanged(filesChanged))
{
Log.CreatedRepositoryDispatchForPush(_logger, repo.Owner.Login, repo.Name, push.Ref);
await CreateDispatchAsync(repo.FullName);
}
}
private static bool DependencyFileChanged(HashSet<string> filesChanged)
{
return filesChanged.Any(IsDependencyFile);
static bool IsDependencyFile(string path)
{
return Path.GetExtension(path) switch
{
".csproj" => true,
_ => Path.GetFileName(path) switch
{
"Directory.Packages.props" => IsFileInRepositoryRoot(path),
"global.json" => IsFileInRepositoryRoot(path),
"package.json" => true,
"package-lock.json" => true,
_ => false,
},
};
static bool IsFileInRepositoryRoot(string path)
=> Path.GetDirectoryName(path) is "";
}
}
private async Task CreateDispatchAsync(string repository)
{
// See https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#create-a-repository-dispatch-event
var dispatch = new
{
event_type = "dotnet_dependencies_updated",
client_payload = new { repository },
};
var uri = new Uri($"repos/{DispatchDestination}/dispatches", UriKind.Relative);
var status = await _client.Connection.Post(uri, dispatch, "application/vnd.github+json");
if (status is not System.Net.HttpStatusCode.NoContent)
{
throw new ApiException($"Failed to create repository dispatch event for push to {repository}.", status);
}
}
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
private static partial class Log
{
[LoggerMessage(
EventId = 1,
Level = LogLevel.Information,
Message = "Creating repository dispatch for push to {Owner}/{Repository} for ref {Reference}.")]
public static partial void CreatedRepositoryDispatchForPush(
ILogger logger,
string? owner,
string? repository,
string? reference);
}
}