33require 'optparse'
44require 'optparse/date'
55
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
15182end
16183
17184options = { }
@@ -58,140 +225,6 @@ def env_help
58225 kit . middleware = stack if @debug
59226end
60227
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
121229
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