-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGitHub_Watcher.txt
482 lines (391 loc) · 15.9 KB
/
GitHub_Watcher.txt
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
Script("Name") = "GitHub Watcher"
Script("Author") = "Pyro"
Script("Major") = 1
Script("Minor") = 1
' Command constants
Const GW_COMMAND = "gitwatch" ' Name of the command
Const GW_ACTION = "action" ' first parameter name
Const GW_REPO = "repo" ' second parameter name
' Global variables
Public RepoChecks ' The list of repositories to check (as CommitCheck objects)
Public CheckIndex ' The current position in the repo list
Public DisplayQueue ' List of messages needing short links.
' Settings
Public WatchFile ' The name of the file containing the watch list
Public CheckInterval ' The time between each repository check, in seconds.
Public CheckDelay ' The time to wait after all repositories have been checked, in seconds.
Public MaxCommits ' The maximum number of commits to individually announce before grouping.
Public DisplayMode ' The output method (uses DSP) - 1 = in channel, 2 = emote, 4 = local only
Sub Event_Load()
Call InitCommands
Call LoadSettings
CreateObj "Inet", "gitInet" ' Used for querying the GitHub API
CreateObj "Inet", "gitShortUrl" ' Used to get short URL's for commits.
CreateObj "LongTimer", "gitTime" ' Checks for new commits
gitTime.Interval = CheckInterval
gitTime.Enabled = True
CreateObj "Timer", "gitQueue" ' Display queue timer
gitQueue.Interval = 1000
gitQueue.Enabled = False
Set DisplayQueue = CreateObject("Scripting.Dictionary")
'Loads watch list from the file
Call LoadChecks
CheckIndex = 0
End Sub
Sub Event_Close()
Call SaveSettings
Call SaveChecks
End Sub
Sub Event_Command(Command)
Select Case LCase(Command.Name)
Case GW_COMMAND
If Command.IsValid Then
Select Case LCase(Command.Argument(GW_ACTION))
Case "add" ' <owner>/<repo>/[branch], default branch = master
s = Split(Command.Argument(GW_REPO), "/")
If UBound(s) > 0 Then
owner = s(0)
repo = s(1)
Else
Command.Respond "Invalid repository. Format: <owner>/<repo>/[branch]"
Exit Sub
End If
'Was a branch specified?
If UBound(s) > 1 Then
branch = s(2)
Else
branch = "master"
End If
Set check = MakeCheck(owner, repo, branch)
Call AddCheck(check)
Call SaveChecks
Command.Respond StringFormat("Added repository '{0}/{1}', branch '{2}'", check.RepoOwner, check.RepoName, check.RepoBranch)
Case "remove", "rem" ' <owner>/<repo>/<branch>
repo = Command.Argument(GW_REPO)
If RepoChecks.Exists(repo) Then
RepoChecks.Remove repo
Command.Respond "Repository removed from watch list."
Else
Command.Respond "Repository not found in the watch list."
End If
End Select
Else
Command.Respond StringFormat("Invalid syntax. Format: {0} <action> [repo]", Command.Name)
End If
End Select
End Sub
'Loads the list of watched repositories
Sub LoadChecks()
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set RepoChecks = CreateObject("Scripting.Dictionary")
If oFSO.FileExists(WatchFile) Then
Set oFile = oFSO.OpenTextFile(WatchFile, 1)
Do While Not oFile.AtEndOfStream
checkData = oFile.ReadLine
If Len(checkData) > 0 Then
Set check = New CommitCheck
check.ParseData checkData
Call AddCheck(check)
End If
Loop
oFile.Close
Set oFile = Nothing
End If
Set oFSO = Nothing
AddChat vbYellow, StringFormat("[GW] Loaded {0} repos to watch.", RepoChecks.Count)
End Sub
' Creates a check object
Function MakeCheck(owner, repo, branch)
Set check = New CommitCheck
check.RepoOwner = owner
check.RepoName = repo
check.RepoBranch = branch
Set MakeCheck = check
End Function
' Adds a check object to the list
Sub AddCheck(check)
RepoChecks.Add StringFormat("{0}/{1}/{2}", check.RepoOwner, check.RepoName, check.RepoBranch), check
End Sub
' Saves the check list to the watch file.
Sub SaveChecks()
If RepoChecks.Count = 0 Then Exit Sub
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oFile = oFSO.OpenTextFile(WatchFile, 2, True)
For Each check In RepoChecks.Items
oFile.WriteLine check.GetData
Next
oFile.Close
Set oFile = Nothing
Set oFSO = Nothing
End Sub
' Gets commits from the specified repository
' since is the timestamp (YYYY-MM-DDTHH:mm:ssZ) of the earliest to return commits from
Function GetCommitList(owner, repo, branch, since)
url = "https://api.github.com/repos/" & owner & "/" & repo & "/commits"
params = vbNullString
' Add branch if specified
If LenB(branch) > 0 Then
params = params & "sha=" & branch
End If
' Add since if specified
If LenB(since) > 0 Then
If LenB(params) > 0 Then
params = params & "&"
End If
params = params & "since=" & since
End If
' Attach parameters
If LenB(params) > 0 Then
url = url & "?" & params
End If
'AddChat vbCyan, StringFormat("[GW] Checking repo: {0}/{1} branch {2} ({3})", owner, repo, branch, since)
s = Split(gitInet.OpenURL(CStr(url)), """commit"":{")
' Put each commit into an array
commitCount = 0
ReDim cList(0)
For i = 1 To UBound(s)
ReDim Preserve cList(commitCount)
commitCount = commitCount + 1
cList(commitCount - 1) = s(i)
Next
GetCommitList = cList
End Function
Sub QueueForShortUrl(Message, LongUrl)
Set Request = New ShortUrlRequest
Request.Message = Message
Request.LongUrl = LongUrl
DisplayQueue.Add Message, Request
gitQueue.Enabled = True
End Sub
Sub RequestShortUrl(Request)
gitShortUrl.Tag = Request.Message
gitShortUrl.Execute "https://git.io", "POST", "url=" & Request.LongUrl
If DisplayQueue.Exists(Request.Message) Then
Call DisplayQueue.Remove(Request.Message)
End If
End Sub
Sub gitTime_Timer()
If RepoChecks.Count = 0 Then Exit Sub ' Exit if there are no repositories to check
If gitInet.StillExecuting Then Exit Sub ' Exit if the INET object is busy
' Check the next repository
If CheckIndex < RepoChecks.Count Then
Set check = RepoChecks.Items()(CheckIndex)
check.CheckForCommits
CheckIndex = CheckIndex + 1
End If
' If we are done with the list, wait longer
If CheckIndex >= RepoChecks.Count Then
gitTime.Interval = CheckDelay
CheckIndex = 0
Else
' More to check
If gitTime.Interval <> CheckInterval Then
gitTime.Interval = CheckInterval
End If
End If
End Sub
Sub gitQueue_Timer()
' If there's nothing queued, stop the timer.
If DisplayQueue.Count < 1 Then
gitQueue.Enabled = False
Exit Sub
End If
' Only proceed if the last request has finished.
If gitShortUrl.StillExecuting Then Exit Sub
Set Request = DisplayQueue.Items()(0)
Call RequestShortUrl(Request)
End Sub
Sub gitShortUrl_StateChanged(State)
If State = 12 Then ' icResponseCompleted
Message = gitShortUrl.Tag
Response = Split(gitShortUrl.GetHeader(vbNullString), vbNewLine)(0)
shortUrl = gitShortUrl.GetHeader("Location")
If InStr(Response, "201 Created") > 0 Then
Dsp DisplayMode, StringFormat("{0} - {1}", Message, shortUrl), , vbGreen
End If
End If
End Sub
' Creates all of the commands used in the script, if needed.
Sub InitCommands()
If OpenCommand(GW_COMMAND) Is Nothing Then
Set oCmd = CreateCommand(GW_COMMAND)
With oCmd
.RequiredRank = 60
.Description = "Controls the github watcher."
.Aliases.Add "gitw"
.Aliases.Add "gw"
Set oParam = .NewParameter(GW_ACTION, False, "word")
oParam.Description = "The action to execute."
.Parameters.Add oParam
Set oParam = .NewParameter(GW_REPO, True, "word")
oParam.Description = "The repo to manipulate"
.Parameters.Add oParam
.Save
End With
Set oCmd = Nothing
Set oParam = Nothing
End If
End Sub
' Loads the script's settings
Sub LoadSettings()
WatchFile = ReadSetting("WatchFile", "git_watch.txt")
CheckInterval = Int(ReadSetting("CheckInterval", 60))
CheckDelay = Int(ReadSetting("CheckDelay", 600))
MaxCommits = Int(ReadSetting("MaxCommits", 1))
DisplayMode = Int(ReadSetting("DisplayMode", 1))
End Sub
' Reads a setting and uses the default value if it's not set.
Function ReadSetting(settingName, defaultValue)
s = GetSettingsEntry(settingName)
If LenB(s) > 0 Then
ReadSetting = s
Else
ReadSetting = defaultValue
End If
End Function
' Saves settings
Sub SaveSettings()
WriteSettingsEntry "WatchFile", WatchFile
WriteSettingsEntry "CheckInterval", CheckInterval
WriteSettingsEntry "CheckDelay", CheckDelay
WriteSettingsEntry "MaxCommits", MaxCommits
WriteSettingsEntry "DisplayMode", DisplayMode
End Sub
' Parses and stores information about a specific commit
Class GitCommit
Public RepoOwner
Public RepoName
Public RepoBranch
Public AuthorName
Public CommitterName
Public Message
Public CommitTime
Public HtmlUrl
' Parses a commit from the returned JSON
Public Sub ParseData(data)
' Author
author = Split(data, """author"":{""name"":""")(1)
author = Split(author, """,")(0)
' Committer
cmmter = Split(data, """committer"":{""name"":""")(1)
cTime = Split(cmmter, """date"":""")(1)
cmmter = Split(cmmter, """,")(0)
' Commit Time
cTime = Split(cTime, """")(0)
' Commit Message
msg = Split(data, """message"":""")(1)
msg = Split(msg, """,""")(0)
msg = Split(msg, "\n")(0)
msg = Replace(msg, "\""", """")
' URL
url = Split(data, """html_url"":""")(1)
url = Split(url, """")(0)
AuthorName = author
CommitterName = cmmter
Message = msg
CommitTime = cTime
HtmlUrl = url
End Sub
' Gets a string explaining the commit including the time it was made and a link to it.
Public Function GetInfo()
GetInfo = StringFormat("{0} made a commit to {1}/{2} on {3} UTC: {4} ({5})", _
CommitterName, RepoName, RepoBranch, Replace(Left(CommitTime, Len(CommitTime) - 1), "T", " @ "), Message, HtmlUrl)
End Function
' Gets a string explaining the commit with no time or URL
Public Function GetInfoShort()
GetInfoShort = StringFormat("{0} made a commit to {1}/{2}: {3}", CommitterName, RepoName, RepoBranch, Message)
End Function
End Class
' Stores information about a repository to be checked.
Class CommitCheck
Public LastCommitTime
Public RepoOwner
Public RepoName
Public RepoBranch
' Parses a line from the watch file
' <owner> <repo> <branch> [latest]
Public Sub ParseData(data)
s = Split(data, " ")
If UBound(s) > 1 Then
RepoOwner = s(0)
RepoName = s(1)
RepoBranch = s(2)
LastCommitTime = vbNullString
End If
If UBound(s) > 2 Then
LastCommitTime = s(3)
End If
'AddChat vbWhite, StringFormat("Parsed repo info: {0}/{1} branch {2}", RepoOwner, RepoName, RepoBranch)
End Sub
' Gets the data to be saved to a line in the watch file.
Public Function GetData()
GetData = StringFormat("{0} {1} {2}", RepoOwner, RepoName, RepoBranch)
If LenB(LastCommitTime) > 0 Then
GetData = GetData & Space(1) & LastCommitTime
End If
End Function
' Checks for new commits and outputs them
Public Sub CheckForCommits()
since = LastCommitTime
' If we've already checked this repo, take the time of the latest commit
' and advance it by 1 second. Then use this time to only retreive commits
' made since then.
If LenB(since) > 0 Then
secPart = CStr(Int(Right(Left(since, Len(since) - 1), 2)) + 1)
secPart = Right("00" & secPart, 2)
since = Left(since, Len(since) - 3) & secPart & "Z"
End If
c = GetCommitList(RepoOwner, RepoName, RepoBranch, since)
If InStr(c(0), "{") = 0 And InStr(c(0), "}") = 0 Then Exit Sub
' Create a dictionary to store contributing users.
Set dicComNames = CreateObject("Scripting.Dictionary")
' Figure out how to display them
IsFirstCheck = (LenB(LastCommitTime) = 0)
ShowEach = ((Not IsFirstCheck) And (UBound(c) < MaxCommits))
ShowReport = ((Not IsFirstCheck) And (UBound(c) >= MaxCommits))
LastCommitTime = vbNullString
' Go through each commit
For Each commit in c
Set oC = New GitCommit
oC.RepoOwner = RepoOwner
oC.RepoName = RepoName
oC.RepoBranch = RepoBranch
oC.ParseData commit
' Update the last commit time
If LenB(LastCommitTime) = 0 Then
LastCommitTime = oC.CommitTime
Call SaveChecks
End If
' Count commits by each user
If Not dicComNames.Exists(oC.CommitterName) Then
dicComNames.Add oC.CommitterName, 1
Else
dicComNames.Item(oC.CommitterName) = (dicComNames.Item(oC.CommitterName) + 1)
End If
' Show the commit if desired
If ShowEach Then
Call QueueForShortUrl(oC.GetInfoShort(), oC.HtmlUrl)
End If
Next
' Show a general report of commits
If ShowReport Then
If dicComNames.Count > 2 Then
Call QueueForShortUrl( _
StringFormat("{0} commits were pushed to {1}/{2} by {3} users.", _
UBound(c) + 1, RepoName, RepoBranch, dicComNames.Count), _
StringFormat("https://github.com/{0}/{1}/commits/{2}", RepoOwner, RepoName, RepoBranch))
Else
For Each com In dicComNames.Keys
Call QueueForShortUrl( _
StringFormat("{0} pushed {1} commits to {2}/{3}.", com, dicComNames.Item(com), RepoName, RepoBranch), _
StringFormat("https://github.com/{0}/{1}/commits/{2}", RepoOwner, RepoName, RepoBranch))
Next
End If
End If
End Sub
End Class
Class ShortUrlRequest
Public Message
Public LongUrl
Public ShortUrl
End Class