-
Notifications
You must be signed in to change notification settings - Fork 0
/
github.php
157 lines (145 loc) · 4.58 KB
/
github.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
<?php
require_once 'curl.php';
/**
* 久々に実行する際はアクセストークンを再生成して入れ替え
* 実行時は検索対象のmerged_atを指定する。
* この期間が長ければ長い程実行時間は長くなるので注意。
*/
class Github
{
const ACCESS_TOKEN = "";
const URL = "https://api.github.com/graphql";
const USER = "";
// @var Curl
private $curl_client;
// @var string 検索対象のユーザー
private $user;
/**
* Githubクライアントのコンストラクタ
*
* @param string $url エンドポイント
* @param string $access_token アクセストークン
* @param string $user 検索対象のユーザー
* @return void
*/
public function __construct(
string $url = self::URL,
string $access_token = self::ACCESS_TOKEN,
string $user = self::USER
) {
$this->curl_client = new Curl($url, $access_token);
$this->user = $user;
}
/**
* 実行関数
*
* @param string $merged_at 検索対象のmerged_at
* @return bool 成功したらtrue
*/
public function exec(string $merged_at): bool
{
$next_cursor = null;
$has_next_page = true;
// ネクストページがある分ループで取得する
while ($has_next_page) {
if ($next_cursor === null) {
$after = '';
} else {
$after = 'after: \"' . $next_cursor . '\",';
}
$query = $this->_get_query($after, $merged_at);
$output = $this->curl_client->exec($query);
if ($output === false) {
echo "curl実行失敗\n";
return false;
}
$result = json_decode($output);
// レスポンスからendCursorとhasNextPageを抜き出す
$pull_requests = $result->data->search->nodes;
$next_cursor = $result->data->search->pageInfo->endCursor;
$has_next_page = $result->data->search->pageInfo->hasNextPage;
$this->_output_csv($pull_requests);
}
return true;
}
/**
* GraphQLのクエリを取得する
*
* @param string $after 次のページのカーソル
* @param string $merged_at 検索対象のmerged_at
* @return string graphqlのクエリ
*/
private function _get_query(string $after, string $merged_at): string
{
$query = <<<END
{
"query": "query {
search(first: 100, {$after} query: \"user:{$this->user} is:pr is:merged merged:{$merged_at} base:master base:main\", type: ISSUE) {
nodes {
... on PullRequest {
title
permalink
repository{name}
author{login}
baseRefName
mergedAt
updatedAt
commits(first: 1){nodes{commit{committedDate}}}
}
}
pageInfo{endCursor hasNextPage}
}
}"
}
END;
// MEMO: 改行を含んでいるとうまくいかなかったので削除
$one_line_query = str_replace("\n", '', $query);
return $one_line_query;
}
/**
* 結果をCSVに出力する
*
* @param array[object] $pull_requests プルリクエストの配列
* @return void
*/
private function _output_csv(array $pull_requests)
{
// ループで呼び出す都合で追記形式とする。
// 再実行時はファイルを削除してください。
$fp = fopen('data.csv', 'a');
/**
* 出力形式
* author,プルリクタイトル,プルリクURL,repository,base_branch,mergedAt,updatedAt,first_commit
*/
foreach ($pull_requests as $pull_request) {
$author = $pull_request->author->login ?? '削除済みユーザー';
$title = '"' . $pull_request->title . '"';
$permalink = $pull_request->permalink;
$repository_name = $pull_request->repository->name;
$baseRefName = $pull_request->baseRefName;
$mergedAt = $this->_format_date($pull_request->mergedAt);
$updatedAt = $this->_format_date($pull_request->updatedAt);
$firstCommittedDate = $this->_format_date($pull_request->commits->nodes[0]->commit->committedDate);
$line = [$author, $title, $permalink, $repository_name, $baseRefName, $mergedAt, $updatedAt, $firstCommittedDate];
fwrite($fp, implode(',', $line) . "\n");
}
fclose($fp);
}
/**
* スプレッドシートで扱いやすい形に変換する
*
* 例
* 2023-08-16T04:33:02Z
* ↓
* 2023-08-16 13:33:02
*
* @param string $string_date 日付の文字列
* @return string フォーマットした日付の文字列
*/
private function _format_date(string $string_date): string
{
$datetime = new DateTime($string_date);
$datetime->setTimeZone(new DateTimeZone('Asia/Tokyo'));
return $datetime->format('Y-m-d H:i:s');
}
}