-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrecurring-issue-generator.php
188 lines (178 loc) · 6.11 KB
/
recurring-issue-generator.php
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
<?php
const TRIM_CHARS = " \n\r\t\v\x00\"";
$github_token = trim((string)getenv('GITHUB_TOKEN'), TRIM_CHARS);
$title = trim((string)getenv('ISSUE_TITLE'), TRIM_CHARS);
$body = trim((string)getenv('ISSUE_BODY'), TRIM_CHARS);
$label = trim((string)getenv('ISSUE_LABEL'), TRIM_CHARS) ?: 'maintenance';
/**
* Retrieves the project configurations from the environment variables.
*
* This function iterates over the environment variables and extracts the project configurations
* that start with the prefix 'PROJECT_'. It splits the value of each variable into parts using
* the '|' delimiter and creates an array of configuration arrays. Each configuration array contains
* the following keys:
* - 'name': The name of the project, extracted from the environment variable name.
* - 'frequency': The frequency of the project, extracted from the first part of the value.
* - 'user': The user associated with the project, extracted from the second part of the value.
* - 'repo': The repository associated with the project, extracted from the third part of the value.
* - 'manager': The GitHub handle of the project manager, extracted from the fourth part of the value.
*
* @return array
* An array of project configurations.
*/
function get_project_configs(): array {
$configs = [];
foreach (getenv() as $key => $value) {
if (strpos($key, 'PROJECT_') === 0) {
$parts = explode('|', $value);
$configs[] = [
'name' => trim(substr($key, 8)),
'frequency' => trim($parts[0], TRIM_CHARS),
'user' => trim($parts[1]),
'repo' => trim($parts[2], TRIM_CHARS),
'manager' => isset($parts[3]) ? trim($parts[3], TRIM_CHARS) : NULL,
];
}
}
return $configs;
}
/**
* Calls the GitHub API using the specified HTTP method and URL.
*
* @param string $method
* The HTTP method to use (e.g., GET, POST).
* @param string $url
* The URL of the API endpoint.
* @param string $github_token
* The GitHub token for authentication.
* @param array<string, mixed> $data
* The data to send with the request (for POST requests).
*
* @return mixed
* The response from the API as a decoded JSON object.
* @throws Exception
* If there is an error with the cURL request.
*/
function call_github_api(string $method, string $url, string $github_token, array $data = []) {
$ch = curl_init($url);
if ($ch === FALSE) {
throw new Exception('CURL initialization failed.');
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: token ' . $github_token,
'User-Agent: RecurringIssueGenerator 0.1',
'Content-Type: application/json'
]);
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
$response = curl_exec($ch);
if ($response === FALSE) {
throw new Exception('CURL error: ' . curl_error($ch));
}
curl_close($ch);
return json_decode((string)$response, TRUE);
}
/**
* Creates a GitHub issue.
*
* @param string $repo
* The repository name.
* @param string $user
* The username of the assignee.
* @param string $github_token
* The GitHub token for authentication.
* @param string $title
* The title of the issue.
* @param string $body
* The body of the issue.
* @param string $label
* The label for the issue.
* @param string|null $manager
* The GitHub handle of the project manager.
*
* @return mixed
* The response from the GitHub API as a decoded JSON object.
* @throws \Exception If there is an error with the GitHub API request.
*/
function create_github_issue(string $repo, string $user, string $github_token, string $title, string $body, string $label, string $manager = NULL) {
$data = [
'title' => $title,
'body' => $body,
'assignees' => explode(',', $user),
'labels' => [$label]
];
if ($manager) {
$data['body'] .= "\n\n//cc @" . $manager;
}
$issue = call_github_api('POST', "https://api.github.com/repos/$repo/issues", $github_token, $data);
if (!is_array($issue) || !isset($issue['id'])) {
throw new Exception('Issue creation failed.');
}
return $issue;
}
/**
* Checks if the last issue with the given title in the specified repository
* meets the recurrence frequency.
*
* @param string $repo
* The name of the repository.
* @param string $frequency
* The frequency of the recurrence. Can be 'Daily', 'Weekly', 'Monthly', or
* 'Quarterly'.
* @param string $github_token
* The GitHub token for authentication.
* @param string $title
* The title of the issue.
*
* @return bool
* Returns true if the last issue meets the recurrence frequency, false
* otherwise.
*
* @throws \Exception
*/
function check_last_issue(string $repo, string $frequency, string $github_token, string $title): bool {
$issues = call_github_api('GET', "https://api.github.com/repos/$repo/issues?state=all&per_page=100", $github_token);
if (!is_array($issues)) {
throw new Exception('Failed to fetch issues.');
}
foreach ($issues as $issue) {
if (is_array($issue) && isset($issue['title']) && $issue['title'] === $title) {
$last_issue_date = new DateTime($issue['created_at']);
$current_date = new DateTime();
$interval = $current_date->diff($last_issue_date)->days;
switch ($frequency) {
case 'Daily':
return $interval >= 1;
case 'Weekly':
return $interval >= 7;
case 'Monthly':
return $interval >= 30;
case 'Quarterly':
return $interval >= 90;
default:
return FALSE;
}
}
}
return TRUE;
}
try {
$projects = get_project_configs();
foreach ($projects as $project) {
if (!check_last_issue($project['repo'], $project['frequency'], $github_token, $title)) {
echo "Skipping {$project['name']}, not yet time to notify.\n";
continue;
}
echo "Creating an issue for {$project['name']}\n";
create_github_issue($project['repo'], $project['user'], $github_token, $title, $body, $label, $project['manager']);
// Making sure we do not hit API limits.
sleep(2);
}
}
catch (\Exception $e) {
echo "Error: {$e->getMessage()}\n";
exit(1);
}