3
3
require 'optparse'
4
4
require 'optparse/date'
5
5
6
- SCOPES = [ "read:org" , "read:user" , "repo" , "user:email" ]
7
-
8
- def env_help
9
- output = <<-EOM
10
- Required Environment variables:
11
- OCTOKIT_ACCESS_TOKEN: A valid personal access token with Organzation admin priviliges
12
- OCTOKIT_API_ENDPOINT: A valid GitHub/GitHub Enterprise API endpoint URL (Defaults to https://api.github.com)
13
- EOM
14
- output
6
+
7
+ class InactiveMemberSearch
8
+ attr_accessor :organization , :members , :repositories , :date
9
+
10
+ SCOPES = [ "read:org" , "read:user" , "repo" , "user:email" ]
11
+
12
+ def initialize ( options = { } )
13
+ @client = options [ :client ]
14
+ if options [ :check ]
15
+ check_app
16
+ check_scopes
17
+ exit 0
18
+ end
19
+
20
+ raise ( OptionParser ::MissingArgument ) if (
21
+ options [ :organization ] . nil? or
22
+ options [ :date ] . nil?
23
+ )
24
+
25
+ @date = options [ :date ]
26
+ @organization = options [ :organization ]
27
+
28
+ organization_members
29
+ organization_repositories
30
+ member_activity
31
+ end
32
+
33
+ def check_app
34
+ info "Application client/secret? #{ @client . application_authenticated? } \n "
35
+ info "Authentication Token? #{ @client . token_authenticated? } \n "
36
+ end
37
+
38
+ def check_scopes
39
+ info "Scopes: #{ @client . scopes . join ',' } \n "
40
+ end
41
+
42
+ def env_help
43
+ output = <<-EOM
44
+ Required Environment variables:
45
+ OCTOKIT_ACCESS_TOKEN: A valid personal access token with Organzation admin priviliges
46
+ OCTOKIT_API_ENDPOINT: A valid GitHub/GitHub Enterprise API endpoint URL (Defaults to https://api.github.com)
47
+ EOM
48
+ output
49
+ end
50
+
51
+ # helper to get an auth token for the OAuth application and a user
52
+ def get_auth_token ( login , password , otp )
53
+ temp_client = Octokit ::Client . new ( login : login , password : password )
54
+ res = temp_client . create_authorization (
55
+ {
56
+ :idempotent => true ,
57
+ :scopes => SCOPES ,
58
+ :headers => { 'X-GitHub-OTP' => otp }
59
+ } )
60
+ res [ :token ]
61
+ end
62
+ private
63
+ def debug ( message )
64
+ $stderr. print message
65
+ end
66
+
67
+ def info ( message )
68
+ $stdout. print message
69
+ end
70
+
71
+ def organization_members
72
+ # get all organization members and place into an array of hashes
73
+ @members = @client . organization_members ( @organization ) . collect do |m |
74
+ email = @client . user ( m [ :login ] ) [ :email ]
75
+ {
76
+ login : m [ "login" ] ,
77
+ email : email ,
78
+ active : false
79
+ }
80
+ end
81
+ info "#{ @members . length } members found.\n "
82
+ end
83
+
84
+ def organization_repositories
85
+ # get all repos in the organizaton and place into a hash
86
+ @repositories = @client . organization_repositories ( @organization ) . collect do |repo |
87
+ repo [ "full_name" ]
88
+ end
89
+ info "#{ @repositories . length } repositories found.\n "
90
+ end
91
+
92
+ # method to switch member status to active
93
+ def make_active ( login )
94
+ hsh = @members . find { |member | member [ :login ] == login }
95
+ hsh [ :active ] = true
96
+ end
97
+
98
+ def commit_activity ( repository )
99
+ # get all commits after specified date and iterate
100
+ info "...commits"
101
+ begin
102
+ @client . commits_since ( repo , @date ) . each do |commit |
103
+ # if commmitter is a member of the org and not active, make active
104
+ if t = @members . find { |member | member [ :login ] == commit [ "author" ] [ "login" ] && member [ :active ] == false }
105
+ make_active ( t [ :login ] )
106
+ end
107
+ end
108
+ rescue
109
+ info "...skipping blank repo"
110
+ end
111
+ end
112
+
113
+ def issue_activity ( repo , date = @date )
114
+ # get all issues after specified date and iterate
115
+ info "...issues"
116
+ @client . list_issues ( repo , { :since => date } ) . each do |issue |
117
+ # if creator is a member of the org and not active, make active
118
+ if t = @members . find { |member | member [ :login ] == issue [ "user" ] [ "login" ] && member [ :active ] == false }
119
+ make_active ( t [ :login ] )
120
+ end
121
+ end
122
+ end
123
+
124
+ def issue_comment_activity ( repo , date = @date )
125
+ # get all issue comments after specified date and iterate
126
+ info "...issue comments"
127
+ @client . issues_comments ( repo , { :since => date } ) . each do |comment |
128
+ # if commenter is a member of the org and not active, make active
129
+ if t = @members . find { |member | member [ :login ] == comment [ "user" ] [ "login" ] && member [ :active ] == false }
130
+ make_active ( t [ :login ] )
131
+ end
132
+ end
133
+ end
134
+
135
+ def pr_activity ( repo , date = @date )
136
+ # get all pull request comments comments after specified date and iterate
137
+ info "...pr comments"
138
+ @client . pull_requests_comments ( repo , { :since => date } ) . each do |comment |
139
+ # if commenter is a member of the org and not active, make active
140
+ if t = @members . find { |member | member [ :login ] == comment [ "user" ] [ "login" ] && member [ :active ] == false }
141
+ make_active ( t [ :login ] )
142
+ end
143
+ end
144
+ end
145
+
146
+ def member_activity
147
+ @repos_completed = 0
148
+ # print update to terminal
149
+ info "Analyzing activity for #{ @members . length } members and #{ @repositories . length } repos for #{ @organization } \n "
150
+
151
+ # for each repo
152
+ @repositories . each do |repo |
153
+ info "rate limit remaining: #{ @client . rate_limit . remaining } "
154
+ info "analyzing #{ repo } "
155
+
156
+ commit_activity ( repo )
157
+ issue_activity ( repo )
158
+ issue_comment_activity ( repo )
159
+ pr_activity ( repo )
160
+
161
+ # print update to terminal
162
+ @repos_completed += 1
163
+ info "...#{ @repos_completed } /#{ @repositories . length } repos completed\n "
164
+ end
165
+
166
+ # open a new csv for output
167
+ CSV . open ( "inactive_users.csv" , "wb" ) do |csv |
168
+ # iterate and print inactive members
169
+ @members . each do |member |
170
+ if member [ :active ] == false
171
+ member_detail = "#{ member [ :login ] } <#{ member [ :email ] unless member [ :email ] . nil? } >"
172
+ info "#{ member_detail } is inactive\n "
173
+ csv << [ member_detail ]
174
+ if false # ARGV[2] == "purge"
175
+ info "removing #{ member [ :login ] } \n "
176
+ @client . remove_organization_member ( ORGANIZATION , member [ :login ] )
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
15
182
end
16
183
17
184
options = { }
@@ -58,140 +225,6 @@ def env_help
58
225
kit . middleware = stack if @debug
59
226
end
60
227
61
- @client = Octokit ::Client . new
62
-
63
- def debug ( message )
64
- $stderr. print message
65
- end
66
-
67
- def info ( message )
68
- $stdout. print message
69
- end
70
-
71
- def check_scopes
72
- info "Scopes: #{ @client . scopes . join ',' } \n "
73
- end
74
-
75
- def check_app
76
- info "Application client/secret? #{ Octokit . client . application_authenticated? } \n "
77
- info "Authentication Token? #{ Octokit . client . token_authenticated? } \n "
78
- end
79
-
80
- # helper to get an auth token for the OAuth application and a user
81
- def get_auth_token ( login , password , otp )
82
- temp_client = Octokit ::Client . new ( login : login , password : password )
83
- res = temp_client . create_authorization (
84
- {
85
- :idempotent => true ,
86
- :scopes => SCOPES ,
87
- :headers => { 'X-GitHub-OTP' => otp }
88
- } )
89
- res [ :token ]
90
- end
91
-
92
- if options [ :check ]
93
- check_app
94
- check_scopes
95
- exit 0
96
- end
97
-
98
- raise ( OptionParser ::MissingArgument ) if (
99
- options [ :organization ] . nil? or
100
- options [ :date ] . nil?
101
- )
102
-
103
- # get all organization members and place into an array of hashes
104
- @members = @client . organization_members ( options [ :organization ] ) . collect do |m |
105
- email = @client . user ( m [ :login ] ) [ :email ]
106
- {
107
- login : m [ "login" ] ,
108
- email : email ,
109
- active : false
110
- }
111
- end
112
-
113
- info "#{ @members . length } members found.\n "
114
-
115
- # get all repos in the organizaton and place into a hash
116
- repos = @client . organization_repositories ( options [ :organization ] ) . collect do |repo |
117
- repo [ "full_name" ]
118
- end
119
-
120
- info "#{ repos . length } repositories found.\n "
228
+ options [ :client ] = Octokit ::Client . new
121
229
122
- # method to switch member status to active
123
- def make_active ( login )
124
- hsh = @members . find { |member | member [ :login ] == login }
125
- hsh [ :active ] = true
126
- end
127
-
128
- # print update to terminal
129
- info "Analyzing activity for #{ @members . length } members and #{ repos . length } repos for #{ options [ :organization ] } \n "
130
-
131
- @repos_completed = 0
132
-
133
- # for each repo
134
- repos . each do |repo |
135
- info "rate limit remaining: #{ @client . rate_limit . remaining } "
136
- info "analyzing #{ repo } "
137
-
138
- # get all commits after specified date and iterate
139
- info "...commits"
140
- begin
141
- @client . commits_since ( repo , options [ :date ] ) . each do |commit |
142
- # if commmitter is a member of the org and not active, make active
143
- if t = @members . find { |member | member [ :login ] == commit [ "author" ] [ "login" ] && member [ :active ] == false }
144
- make_active ( t [ :login ] )
145
- end
146
- end
147
- rescue
148
- info "...skipping blank repo"
149
- end
150
-
151
- # get all issues after specified date and iterate
152
- info "...issues"
153
- @client . list_issues ( repo , { :since => options [ :date ] } ) . each do |issue |
154
- # if creator is a member of the org and not active, make active
155
- if t = @members . find { |member | member [ :login ] == issue [ "user" ] [ "login" ] && member [ :active ] == false }
156
- make_active ( t [ :login ] )
157
- end
158
- end
159
-
160
- # get all issue comments after specified date and iterate
161
- info "...comments"
162
- @client . issues_comments ( repo , { :since => options [ :date ] } ) . each do |comment |
163
- # if commenter is a member of the org and not active, make active
164
- if t = @members . find { |member | member [ :login ] == comment [ "user" ] [ "login" ] && member [ :active ] == false }
165
- make_active ( t [ :login ] )
166
- end
167
- end
168
-
169
- # get all pull request comments comments after specified date and iterate
170
- info "...pr comments"
171
- @client . pull_requests_comments ( repo , { :since => options [ :date ] } ) . each do |comment |
172
- # if commenter is a member of the org and not active, make active
173
- if t = @members . find { |member | member [ :login ] == comment [ "user" ] [ "login" ] && member [ :active ] == false }
174
- make_active ( t [ :login ] )
175
- end
176
- end
177
-
178
- # print update to terminal
179
- @repos_completed += 1
180
- info "...#{ @repos_completed } /#{ repos . length } repos completed\n "
181
- end
182
-
183
- # open a new csv for output
184
- CSV . open ( "inactive_users.csv" , "wb" ) do |csv |
185
- # iterate and print inactive members
186
- @members . each do |member |
187
- if member [ :active ] == false
188
- member_detail = "#{ member [ :login ] } <#{ member [ :email ] unless member [ :email ] . nil? } >"
189
- info "#{ member_detail } is inactive\n "
190
- csv << [ member_detail ]
191
- if false # ARGV[2] == "purge"
192
- info "removing #{ member [ :login ] } \n "
193
- @client . remove_organization_member ( ORGANIZATION , member [ :login ] )
194
- end
195
- end
196
- end
197
- end
230
+ InactiveMemberSearch . new ( options )
0 commit comments