5 | #
6 | # These environment variables must be set:
7 | # - GITHUB_TOKEN: A valid personal access token with Organzation admin priviliges
8 | # - GITHUB_API_ENDPOINT: A valid GitHub/GitHub Enterprise API endpoint URL
9 | # (use https://api.github.com for GitHub.com auditing)
10 | #
11 | # Requires the Octokit Rubygem: https://github.com/octokit/octokit.rb
12 |
13 | require 'octokit.rb'
14 |
15 | begin
16 | ACCESS_TOKEN = ENV.fetch("GITHUB_TOKEN")
17 | API_ENDPOINT = ENV.fetch("GITHUB_API_ENDPOINT")
18 | rescue KeyError
19 | $stderr.puts "To run this script, please set the following environment variables:"
20 | $stderr.puts "- GITHUB_TOKEN: A valid personal access token with Organzation admin priviliges"
21 | $stderr.puts "- GITHUB_API_ENDPOINT: A valid GitHub/GitHub Enterprise API endpoint URL"
22 | $stderr.puts " (use https://api.github.com for GitHub.com auditing)"
23 | exit 1
24 | end
25 |
26 | Octokit.configure do |kit|
27 | kit.api_endpoint = API_ENDPOINT
28 | kit.access_token = ACCESS_TOKEN
29 | kit.auto_paginate = true
30 | end
31 |
32 | if ARGV.length != 1
33 | $stderr.puts "Pass a valid Organization name to audit."
34 | exit 1
35 | end
36 |
37 | ORG = ARGV[0].to_s
38 |
39 | client = Octokit::Client.new
40 |
41 | users = client.organization_members(ORG, {:filter => "2fa_disabled"})
42 |
43 | puts "The following #{users.count} users do not have 2FA enabled:\n\n"
44 | users.each do |user|
45 | puts "#{user[:login]}"
46 | end
47 |
--------------------------------------------------------------------------------
/api/ruby/basics-of-authentication/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "rest-client", "~> 1.8.0"
4 | gem "sinatra", "~> 2.2.3"
5 |
--------------------------------------------------------------------------------
/api/ruby/basics-of-authentication/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | domain_name (0.5.20190701)
5 | unf (>= 0.0.5, < 1.0.0)
6 | http-cookie (1.0.3)
7 | domain_name (~> 0.5)
8 | mime-types (2.99.3)
9 | mustermann (2.0.2)
10 | ruby2_keywords (~> 0.0.1)
11 | netrc (0.11.0)
12 | rack (2.2.8.1)
13 | rack-protection (2.2.3)
14 | rack
15 | rest-client (1.8.0)
16 | http-cookie (>= 1.0.2, < 2.0)
17 | mime-types (>= 1.16, < 3.0)
18 | netrc (~> 0.7)
19 | ruby2_keywords (0.0.5)
20 | sinatra (2.2.3)
21 | mustermann (~> 2.0)
22 | rack (~> 2.2)
23 | rack-protection (= 2.2.3)
24 | tilt (~> 2.0)
25 | tilt (2.0.11)
26 | unf (0.1.4)
27 | unf_ext
28 | unf_ext (0.0.7.6)
29 |
30 | PLATFORMS
31 | ruby
32 |
33 | DEPENDENCIES
34 | rest-client (~> 1.8.0)
35 | sinatra (~> 2.2.3)
36 |
37 | BUNDLED WITH
38 | 1.17.2
39 |
--------------------------------------------------------------------------------
/api/ruby/basics-of-authentication/README.md:
--------------------------------------------------------------------------------
1 | # basics-of-authentication
2 |
3 | This is the sample project built by following the "[Basics of Authentication][basics of auth]"
4 | guide on developer.github.com.
5 |
6 | It consists of two different servers: one built correctly, and one built less optimally.
7 |
8 | ## Install and Run project
9 |
10 | To run these projects, make sure you have [Bundler][bundler] installed; then type
11 | `bundle install` on the command line.
12 |
13 | For the "less optimal" server, type `ruby server.rb` on the command line.
14 |
15 | For the correct server, enter `ruby advanced_server.rb` on the command line.
16 |
17 | Both commands will run the server at `localhost:4567`.
18 |
19 | [basics of auth]: http://developer.github.com/guides/basics-of-authentication/
20 | [bundler]: http://gembundler.com/
21 |
--------------------------------------------------------------------------------
/api/ruby/basics-of-authentication/server.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra'
2 | require 'rest-client'
3 | require 'json'
4 |
5 | # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
6 | # Instead, set and test environment variables, like below
7 | # if ENV['GITHUB_CLIENT_ID'] && ENV['GITHUB_CLIENT_SECRET']
8 | # CLIENT_ID = ENV['GITHUB_CLIENT_ID']
9 | # CLIENT_SECRET = ENV['GITHUB_CLIENT_SECRET']
10 | # end
11 |
12 | CLIENT_ID = ENV['GH_BASIC_CLIENT_ID']
13 | CLIENT_SECRET = ENV['GH_BASIC_SECRET_ID']
14 |
15 | get '/' do
16 | erb :index, :locals => {:client_id => CLIENT_ID}
17 | end
18 |
19 | get '/callback' do
20 | # get temporary GitHub code...
21 | session_code = request.env['rack.request.query_hash']['code']
22 |
23 | # ... and POST it back to GitHub
24 | result = RestClient.post('https://github.com/login/oauth/access_token',
25 | {:client_id => CLIENT_ID,
26 | :client_secret => CLIENT_SECRET,
27 | :code => session_code},
28 | :accept => :json)
29 |
30 | # extract token and granted scopes
31 | access_token = JSON.parse(result)['access_token']
32 | scopes = JSON.parse(result)['scope'].split(',')
33 |
34 | # check if we were granted user:email scope
35 | has_user_email_scope = scopes.include? 'user:email'
36 |
37 | # fetch user information
38 | auth_result = JSON.parse(RestClient.get('https://api.github.com/user',
39 | {:params => {:access_token => access_token},
40 | :accept => :json}))
41 |
42 | # if the user authorized it, fetch private emails
43 | if has_user_email_scope
44 | auth_result['private_emails'] =
45 | JSON.parse(RestClient.get('https://api.github.com/user/emails',
46 | {:params => {:access_token => access_token},
47 | :accept => :json}))
48 | end
49 |
50 | erb :basic, :locals => auth_result
51 | end
52 |
--------------------------------------------------------------------------------
/api/ruby/basics-of-authentication/views/advanced.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Well, well, well, <%= login %>!
9 |
10 | <% if !email.nil? && !email.empty? %> It looks like your public email address is <%= email %>.
11 | <% else %> It looks like you don't have a public email. That's cool.
12 | <% end %>
13 |
14 |
15 | <% if defined? private_emails %>
16 | With your permission, we were also able to dig up your private email addresses:
17 | <%= private_emails.map{ |private_email_address| private_email_address["email"] }.join(', ') %>
18 | <% else %>
19 | Also, you're a bit secretive about your private email addresses.
20 | <% end %>
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/api/ruby/basics-of-authentication/views/basic.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Hello, <%= login %>!
9 |
10 | <% if !email.nil? && !email.empty? %> It looks like your public email address is <%= email %>.
11 | <% else %> It looks like you don't have a public email. That's cool.
12 | <% end %>
13 |
14 |
15 | <% if defined? private_emails %>
16 | With your permission, we were also able to dig up your private email addresses:
17 | <%= private_emails.map{ |private_email_address| private_email_address["email"] }.join(', ') %>
18 | <% else %>
19 | Also, you're a bit secretive about your private email addresses.
20 | <% end %>
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/api/ruby/basics-of-authentication/views/index.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Well, hello there!
9 | We're going to now talk to the GitHub API. Ready? Click here to begin!
10 | If that link doesn't work, remember to provide your own Client ID!
11 |
12 |
13 |
--------------------------------------------------------------------------------
/api/ruby/building-a-ci-server/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "json", "~> 2.3"
4 | gem "octokit", "~> 3.0"
5 | gem "shotgun"
6 | gem "sinatra", "~> 4.0.0"
7 |
--------------------------------------------------------------------------------
/api/ruby/building-a-ci-server/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | addressable (2.3.6)
5 | base64 (0.2.0)
6 | faraday (0.9.0)
7 | multipart-post (>= 1.2, < 3)
8 | json (2.3.0)
9 | multipart-post (2.0.0)
10 | mustermann (3.0.3)
11 | ruby2_keywords (~> 0.0.1)
12 | octokit (3.0.0)
13 | sawyer (~> 0.5.3)
14 | rack (3.1.7)
15 | rack-protection (4.0.0)
16 | base64 (>= 0.1.0)
17 | rack (>= 3.0.0, < 4)
18 | rack-session (2.0.0)
19 | rack (>= 3.0.0)
20 | ruby2_keywords (0.0.5)
21 | sawyer (0.5.4)
22 | addressable (~> 2.3.5)
23 | faraday (~> 0.8, < 0.10)
24 | shotgun (0.9)
25 | rack (>= 1.0)
26 | sinatra (4.0.0)
27 | mustermann (~> 3.0)
28 | rack (>= 3.0.0, < 4)
29 | rack-protection (= 4.0.0)
30 | rack-session (>= 2.0.0, < 3)
31 | tilt (~> 2.0)
32 | tilt (2.4.0)
33 |
34 | PLATFORMS
35 | ruby
36 |
37 | DEPENDENCIES
38 | json (~> 2.3)
39 | octokit (~> 3.0)
40 | shotgun
41 | sinatra (~> 4.0.0)
42 |
43 | BUNDLED WITH
44 | 1.11.2
45 |
--------------------------------------------------------------------------------
/api/ruby/building-a-ci-server/config.ru:
--------------------------------------------------------------------------------
1 | require "./server"
2 | run CITutorial
3 |
--------------------------------------------------------------------------------
/api/ruby/building-a-ci-server/server.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | require 'json'
3 | require 'octokit'
4 |
5 | class CITutorial < Sinatra::Base
6 |
7 | # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
8 | # Instead, set and test environment variables, like below
9 | ACCESS_TOKEN = ENV['MY_PERSONAL_TOKEN']
10 |
11 | before do
12 | @client ||= Octokit::Client.new(:access_token => ACCESS_TOKEN)
13 | end
14 |
15 | post '/event_handler' do
16 | @payload = JSON.parse(params[:payload])
17 |
18 | case request.env['HTTP_X_GITHUB_EVENT']
19 | when "pull_request"
20 | if @payload["action"] == "opened"
21 | process_pull_request(@payload["pull_request"])
22 | end
23 | end
24 | end
25 |
26 | helpers do
27 | def process_pull_request(pull_request)
28 | puts "Processing pull request..."
29 | @client.create_status(pull_request['base']['repo']['full_name'], pull_request['head']['sha'], 'pending')
30 | sleep 2 # do busy work...
31 | @client.create_status(pull_request['base']['repo']['full_name'], pull_request['head']['sha'], 'success')
32 | puts "Pull request processed!"
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/api/ruby/building-your-first-github-app/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "jwt", "~> 2.1"
4 | gem "octokit", "~> 4.0"
5 | gem "sinatra", "~> 2.2"
6 |
--------------------------------------------------------------------------------
/api/ruby/building-your-first-github-app/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | addressable (2.8.1)
5 | public_suffix (>= 2.0.2, < 6.0)
6 | faraday (1.10.3)
7 | faraday-em_http (~> 1.0)
8 | faraday-em_synchrony (~> 1.0)
9 | faraday-excon (~> 1.1)
10 | faraday-httpclient (~> 1.0)
11 | faraday-multipart (~> 1.0)
12 | faraday-net_http (~> 1.0)
13 | faraday-net_http_persistent (~> 1.0)
14 | faraday-patron (~> 1.0)
15 | faraday-rack (~> 1.0)
16 | faraday-retry (~> 1.0)
17 | ruby2_keywords (>= 0.0.4)
18 | faraday-em_http (1.0.0)
19 | faraday-em_synchrony (1.0.0)
20 | faraday-excon (1.1.0)
21 | faraday-httpclient (1.0.1)
22 | faraday-multipart (1.0.4)
23 | multipart-post (~> 2)
24 | faraday-net_http (1.0.1)
25 | faraday-net_http_persistent (1.2.0)
26 | faraday-patron (1.0.0)
27 | faraday-rack (1.0.0)
28 | faraday-retry (1.0.3)
29 | jwt (2.1.0)
30 | multipart-post (2.3.0)
31 | mustermann (2.0.2)
32 | ruby2_keywords (~> 0.0.1)
33 | octokit (4.9.0)
34 | sawyer (~> 0.8.0, >= 0.5.3)
35 | public_suffix (5.0.1)
36 | rack (2.2.8.1)
37 | rack-protection (2.2.3)
38 | rack
39 | ruby2_keywords (0.0.5)
40 | sawyer (0.8.2)
41 | addressable (>= 2.3.5)
42 | faraday (> 0.8, < 2.0)
43 | sinatra (2.2.3)
44 | mustermann (~> 2.0)
45 | rack (~> 2.2)
46 | rack-protection (= 2.2.3)
47 | tilt (~> 2.0)
48 | tilt (2.1.0)
49 |
50 | PLATFORMS
51 | ruby
52 |
53 | DEPENDENCIES
54 | jwt (~> 2.1)
55 | octokit (~> 4.0)
56 | sinatra (~> 2.2)
57 |
58 | BUNDLED WITH
59 | 1.14.6
60 |
--------------------------------------------------------------------------------
/api/ruby/building-your-first-github-app/README.md:
--------------------------------------------------------------------------------
1 | This is the sample project built by following the "[Building Your First GitHub App](https://developer.github.com/apps/building-your-first-github-app)" Quickstart guide on developer.github.com.
2 |
3 | It consists of two different servers: `server.rb` (boilerplate) and `advanced_server.rb` (completed project).
4 |
5 | ## Install and run
6 |
7 | To run the code, make sure you have [Bundler](http://gembundler.com/) installed; then enter `bundle install` on the command line.
8 |
9 | * For the boilerplate project, enter `ruby server.rb` on the command line.
10 |
11 | * For the completed project, enter `ruby advanced_server.rb` on the command line.
12 |
13 | Both commands will run the server at `localhost:3000`.
14 |
--------------------------------------------------------------------------------
/api/ruby/building-your-first-github-app/config.ru:
--------------------------------------------------------------------------------
1 | require "./server"
2 | run GHAapp
3 |
--------------------------------------------------------------------------------
/api/ruby/delivering-deployments/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "json", "~> 2.3"
4 | gem "octokit", "~> 3.0"
5 | gem "shotgun"
6 | gem "sinatra", "~> 4.0.0"
7 |
--------------------------------------------------------------------------------
/api/ruby/delivering-deployments/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | addressable (2.3.6)
5 | base64 (0.2.0)
6 | faraday (0.9.0)
7 | multipart-post (>= 1.2, < 3)
8 | json (2.3.0)
9 | multipart-post (2.0.0)
10 | mustermann (3.0.3)
11 | ruby2_keywords (~> 0.0.1)
12 | octokit (3.0.0)
13 | sawyer (~> 0.5.3)
14 | rack (3.1.7)
15 | rack-protection (4.0.0)
16 | base64 (>= 0.1.0)
17 | rack (>= 3.0.0, < 4)
18 | rack-session (2.0.0)
19 | rack (>= 3.0.0)
20 | ruby2_keywords (0.0.5)
21 | sawyer (0.5.4)
22 | addressable (~> 2.3.5)
23 | faraday (~> 0.8, < 0.10)
24 | shotgun (0.9)
25 | rack (>= 1.0)
26 | sinatra (4.0.0)
27 | mustermann (~> 3.0)
28 | rack (>= 3.0.0, < 4)
29 | rack-protection (= 4.0.0)
30 | rack-session (>= 2.0.0, < 3)
31 | tilt (~> 2.0)
32 | tilt (2.4.0)
33 |
34 | PLATFORMS
35 | ruby
36 |
37 | DEPENDENCIES
38 | json (~> 2.3)
39 | octokit (~> 3.0)
40 | shotgun
41 | sinatra (~> 4.0.0)
42 |
43 | BUNDLED WITH
44 | 1.11.2
45 |
--------------------------------------------------------------------------------
/api/ruby/delivering-deployments/config.ru:
--------------------------------------------------------------------------------
1 | require "./server"
2 | run DeploymentTutorial
3 |
--------------------------------------------------------------------------------
/api/ruby/delivering-deployments/server.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | require 'json'
3 | require 'octokit'
4 |
5 | class DeploymentTutorial < Sinatra::Base
6 |
7 | # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
8 | # Instead, set and test environment variables, like below
9 | ACCESS_TOKEN = ENV['MY_PERSONAL_TOKEN']
10 |
11 | before do
12 | @client ||= Octokit::Client.new(:access_token => ACCESS_TOKEN)
13 | end
14 |
15 | post '/event_handler' do
16 | @payload = JSON.parse(params[:payload])
17 |
18 | case request.env['HTTP_X_GITHUB_EVENT']
19 | when "pull_request"
20 | if @payload["action"] == "closed" && @payload["pull_request"]["merged"]
21 | start_deployment(@payload["pull_request"])
22 | end
23 | when "deployment"
24 | process_deployment
25 | when "deployment_status"
26 | update_deployment_status
27 | end
28 | end
29 |
30 | helpers do
31 | def start_deployment(pull_request)
32 | user = pull_request['user']['login']
33 | payload = JSON.generate(:environment => 'production', :deploy_user => user)
34 | @client.create_deployment(pull_request['head']['repo']['full_name'], pull_request['head']['sha'], {:payload => payload, :description => "Deploying my sweet branch"})
35 | end
36 |
37 | def process_deployment
38 | payload = JSON.parse(@payload['payload'])
39 | # you can send this information to your chat room, monitor, pager, e.t.c.
40 | puts "Processing '#{@payload['description']}' for #{payload['deploy_user']} to #{payload['environment']}"
41 | sleep 2 # simulate work
42 | @client.create_deployment_status("repos/#{@payload['repository']['full_name']}/deployments/#{@payload['id']}", 'pending')
43 | sleep 2 # simulate work
44 | @client.create_deployment_status("repos/#{@payload['repository']['full_name']}/deployments/#{@payload['id']}", 'success')
45 | end
46 |
47 | def update_deployment_status
48 | puts "Deployment status for #{@payload['id']} is #{@payload['state']}"
49 | end
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/api/ruby/discovering-resources-for-a-user/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "octokit", "~> 3.0"
4 |
--------------------------------------------------------------------------------
/api/ruby/discovering-resources-for-a-user/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: http://rubygems.org/
3 | specs:
4 | addressable (2.3.6)
5 | faraday (0.9.0)
6 | multipart-post (>= 1.2, < 3)
7 | multipart-post (2.0.0)
8 | octokit (3.7.0)
9 | sawyer (~> 0.6.0, >= 0.5.3)
10 | sawyer (0.6.0)
11 | addressable (~> 2.3.5)
12 | faraday (~> 0.8, < 0.10)
13 |
14 | PLATFORMS
15 | ruby
16 |
17 | DEPENDENCIES
18 | octokit (~> 3.0)
19 |
--------------------------------------------------------------------------------
/api/ruby/discovering-resources-for-a-user/discovering_organizations.rb:
--------------------------------------------------------------------------------
1 | require 'octokit'
2 |
3 | Octokit.auto_paginate = true
4 |
5 | # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
6 | # Instead, set and test environment variables, like below.
7 | client = Octokit::Client.new :access_token => ENV["OAUTH_ACCESS_TOKEN"]
8 |
9 | client.organizations.each do |organization|
10 | puts "User belongs to the #{organization[:login]} organization."
11 | end
12 |
--------------------------------------------------------------------------------
/api/ruby/discovering-resources-for-a-user/discovering_repositories.rb:
--------------------------------------------------------------------------------
1 | require 'octokit'
2 |
3 | Octokit.auto_paginate = true
4 |
5 | # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
6 | # Instead, set and test environment variables, like below.
7 | client = Octokit::Client.new :access_token => ENV["OAUTH_ACCESS_TOKEN"]
8 |
9 | client.repositories.each do |repository|
10 | full_name = repository[:full_name]
11 | has_push_access = repository[:permissions][:push]
12 |
13 | access_type = if has_push_access
14 | "write"
15 | else
16 | "read-only"
17 | end
18 |
19 | puts "User has #{access_type} access to #{full_name}."
20 | end
21 |
--------------------------------------------------------------------------------
/api/ruby/enterprise/list_all_ssh_keys.rb:
--------------------------------------------------------------------------------
1 | require 'octokit'
2 |
3 | # Check for environment variables
4 | begin
5 | access_token = ENV.fetch("GITHUB_TOKEN")
6 | hostname = ENV.fetch("GITHUB_HOSTNAME")
7 | rescue KeyError
8 | puts
9 | puts "To run this script, please set the following environment variables:"
10 | puts "- GITHUB_TOKEN: A valid access token"
11 | puts "- GITHUB_HOSTNAME: A valid GitHub Enterprise hostname"
12 | exit 1
13 | end
14 |
15 | # Set up Octokit
16 | Octokit.configure do |kit|
17 | kit.api_endpoint = "#{hostname}/api/v3"
18 | kit.access_token = access_token
19 | kit.auto_paginate = true
20 | end
21 |
22 | # Get a list of all users
23 | begin
24 | users = Octokit.all_users
25 | rescue
26 | puts "\nAn error occurred."
27 | puts "\nPlease check your hostname ('#{hostname}') and access token ('#{access_token}')."
28 | exit 1
29 | end
30 |
31 | total = users.length
32 | puts "Found #{total} users."
33 | puts
34 |
35 | count = 1
36 |
37 | # Print each user's public SSH keys
38 | users.each do |user|
39 | # Skip organization accounts, which are included in the list of users
40 | # but don't have any public SSH keys
41 | if user.type == 'Organization'
42 | puts "No keys for #{user.login} (user ##{count} of #{total})."
43 | count += 1
44 | next
45 | end
46 |
47 | keys = Octokit.user_keys(user.login)
48 |
49 | if keys.empty?
50 | puts "No keys for #{user.login} (user ##{count} of #{total})."
51 | else
52 | puts
53 | puts "=================================================="
54 | puts "Keys for #{user.login} (user ##{count} of #{total}):"
55 | keys.each do |key|
56 | puts
57 | puts key.key
58 | end
59 | puts "=================================================="
60 | puts
61 | end
62 |
63 | count += 1
64 | end
65 |
--------------------------------------------------------------------------------
/api/ruby/fork_checker.rb:
--------------------------------------------------------------------------------
1 | require 'octokit.rb'
2 |
3 | if ARGV.length != 1
4 | $stderr.puts "Pass in the name of the repository you're interested in checking as an argument, as /."
5 | exit 1
6 | end
7 |
8 | # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
9 | # Instead, set and test environment variables, like below
10 | client = Octokit::Client.new(:access_token => ENV['MY_PERSONAL_TOKEN'])
11 |
12 | REPO = ARGV[0].to_s
13 | owner = REPO.split("/")[0]
14 |
15 | client.forks REPO
16 | forks = client.last_response.data
17 | loop do
18 | last_response = client.last_response
19 | break if last_response.rels[:next].nil?
20 | forks.concat last_response.rels[:next].get.data
21 | end
22 |
23 | forks.map{ |f| f[:owner][:login] }.each do |user|
24 | unless client.organization_member?(owner, user)
25 | puts "#{user} forked #{REPO}, but is not a member of #{owner}!"
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/api/ruby/instance-auditing/.gitignore:
--------------------------------------------------------------------------------
1 | *.xlsx
2 |
--------------------------------------------------------------------------------
/api/ruby/instance-auditing/README.md:
--------------------------------------------------------------------------------
1 | # Instance auditor
2 |
3 | This script creates an spreadsheet file that will allow you to audit the access of each team and user with all of the organizations across your GitHub Enterprise instance.
4 |
5 | ## Getting started
6 |
7 | The user who is going to run the script must be on the "Owners" team of every organization you wish to audit. You can promote all users with Site Admin access to owners of every organization by running [`ghe-org-admin-promote`](https://help.github.com/enterprise/admin/articles/command-line-utilities/#ghe-org-admin-promote).
8 |
9 | You will also need to [generate a Personal Access Token](https://help.github.com/enterprise/user/articles/creating-an-access-token-for-command-line-use/) for that user with the `admin:org` permission.
10 |
11 | ## Output
12 |
13 | This utility will create a file in the same directory called `audit.xlsx` containing the audit data.
14 |
--------------------------------------------------------------------------------
/api/ruby/instance-auditing/instance_auditor.rb:
--------------------------------------------------------------------------------
1 |
2 | # GitHub & GitHub Enterprise Instance auditor
3 | # =======================================
4 | #
5 | # Usage: ruby instance_audit.rb
6 | #
7 | # These environment variables must be set:
8 | # - GITHUB_TOKEN: A valid personal access token with Organzation admin priviliges
9 | # - GITHUB_API_ENDPOINT: A valid GitHub/GitHub Enterprise API endpoint URL
10 | # (use https://api.github.com for GitHub.com auditing)
11 | #
12 | # Requires the Octokit Rubygem: https://github.com/octokit/octokit.rb
13 | # Requires the axlsx Rubygem: https://github.com/randym/axlsx
14 |
15 | require 'octokit.rb'
16 | require 'axlsx'
17 |
18 | begin
19 | ACCESS_TOKEN = ENV.fetch("GITHUB_TOKEN")
20 | API_ENDPOINT = ENV.fetch("GITHUB_API_ENDPOINT")
21 | rescue KeyError
22 | $stderr.puts "To run this script, please set the following environment variables:"
23 | $stderr.puts "- GITHUB_TOKEN: A valid personal access token with Organzation admin priviliges"
24 | $stderr.puts "- GITHUB_API_ENDPOINT: A valid GitHub/GitHub Enterprise API endpoint URL"
25 | $stderr.puts " (use https://api.github.com for GitHub.com auditing)"
26 | exit 1
27 | end
28 |
29 | Octokit.configure do |kit|
30 | kit.api_endpoint = API_ENDPOINT
31 | kit.access_token = ACCESS_TOKEN
32 | kit.auto_paginate = true
33 | end
34 |
35 | client = Octokit::Client.new
36 |
37 | Axlsx::Package.new do |p|
38 | client.organizations.each do |org|
39 | p.workbook.add_worksheet(:name => org[:login]) do |sheet|
40 | sheet.add_row %w{Organization Team Repo User Access}
41 | client.organization_teams(org[:login]).each do |team|
42 | client.team_repos(team[:id]).each do |repo|
43 | client.team_members(team[:id]).each do |user|
44 | sheet.add_row [org[:login], team[:name], repo[:name], user[:login], team[:permission]]
45 | end
46 | end
47 | end
48 | end
49 | end
50 | p.use_shared_strings = true
51 | p.serialize("#{Time.now.strftime "%Y-%m-%d"}-audit.xlsx")
52 | end
53 |
--------------------------------------------------------------------------------
/api/ruby/rendering-data-as-graphs/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "json", "~>2.3.0"
4 | gem "octokit", "~>4.7.0"
5 | gem "sinatra", "~>1.4.8"
6 | gem "sinatra_auth_github", "~>1.2.0"
7 |
--------------------------------------------------------------------------------
/api/ruby/rendering-data-as-graphs/README.md:
--------------------------------------------------------------------------------
1 | rendering-data-as-graphs
2 | ================
3 |
4 | This is the sample project built by following the "[Rendering Data as Graphs][rendering data]"
5 | guide on developer.github.com.
6 |
7 | To run these projects, make sure you have [Bundler][bundler] installed; then type
8 | `bundle install` on the command line.
9 |
10 | Then, enter `bundle exec rackup -p 4567` on the command line.
11 |
12 | [rendering data]: http://developer.github.com/guides/rendering-data-as-graphs/
13 | [bundler]: http://gembundler.com/
14 |
--------------------------------------------------------------------------------
/api/ruby/rendering-data-as-graphs/config.ru:
--------------------------------------------------------------------------------
1 | ENV['RACK_ENV'] ||= 'development'
2 | require "rubygems"
3 | require "bundler/setup"
4 |
5 | require File.expand_path(File.join(File.dirname(__FILE__), 'server'))
6 |
7 | run Example::MyGraphApp
--------------------------------------------------------------------------------
/api/ruby/traversing-with-pagination/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "octokit", "~> 2.0"
4 |
--------------------------------------------------------------------------------
/api/ruby/traversing-with-pagination/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: http://rubygems.org/
3 | specs:
4 | faraday (0.8.8)
5 | multipart-post (~> 1.2.0)
6 | multipart-post (1.2.0)
7 | octokit (2.1.1)
8 | sawyer (~> 0.3.0)
9 | sawyer (0.3.0)
10 | faraday (~> 0.8, < 0.10)
11 | uri_template (~> 0.5.0)
12 | uri_template (0.5.3)
13 |
14 | PLATFORMS
15 | ruby
16 |
17 | DEPENDENCIES
18 | octokit (~> 2.0)
19 |
--------------------------------------------------------------------------------
/api/ruby/traversing-with-pagination/changing_number_of_items.rb:
--------------------------------------------------------------------------------
1 | require 'octokit'
2 |
3 | # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
4 | # Instead, set and test environment variables, like below
5 | client = Octokit::Client.new :access_token => ENV['MY_PERSONAL_TOKEN']
6 |
7 | results = client.search_code('addClass user:mozilla', :per_page => 100)
8 | total_count = results.total_count
9 |
10 | last_response = client.last_response
11 | number_of_pages = last_response.rels[:last].href.match(/page=(\d+).*$/)[1]
12 |
13 | puts last_response.rels[:last].href
14 | puts "There are #{total_count} results, on #{number_of_pages} pages!"
15 |
16 | puts "And here's the first path for every set"
17 |
18 | puts last_response.data.items.first.path
19 | until last_response.rels[:next].nil?
20 | last_response = last_response.rels[:next].get
21 | sleep 4 # back off from the API rate limiting; don't do this in Real Life
22 | break if last_response.rels[:next].nil?
23 | puts last_response.data.items.first.path
24 | end
25 |
--------------------------------------------------------------------------------
/api/ruby/traversing-with-pagination/constructing_results.rb:
--------------------------------------------------------------------------------
1 | require 'octokit'
2 |
3 | # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
4 | # Instead, set and test environment variables, like below
5 | client = Octokit::Client.new :access_token => ENV['MY_PERSONAL_TOKEN']
6 |
7 | results = client.search_code('addClass user:mozilla')
8 | total_count = results.total_count
9 |
10 | last_response = client.last_response
11 | number_of_pages = last_response.rels[:last].href.match(/page=(\d+).*$/)[1]
12 |
13 | puts last_response.rels[:last].href
14 | puts "There are #{total_count} results, on #{number_of_pages} pages!"
15 |
16 | ascii_numbers = ""
17 | for i in 1..number_of_pages.to_i
18 | ascii_numbers << "[#{i}] "
19 | end
20 | puts ascii_numbers
21 |
22 | random_page = Random.new
23 | random_page = random_page.rand(1..number_of_pages.to_i)
24 |
25 | puts "A User appeared, and clicked number #{random_page}!"
26 |
27 | clicked_results = client.search_code('addClass user:mozilla', :page => random_page)
28 |
29 | prev_page_href = client.last_response.rels[:prev] ? client.last_response.rels[:prev].href : "(none)"
30 | next_page_href = client.last_response.rels[:next] ? client.last_response.rels[:next].href : "(none)"
31 |
32 | puts "The prev page link is #{prev_page_href}"
33 | puts "The next page link is #{next_page_href}"
34 |
--------------------------------------------------------------------------------
/api/ruby/traversing-with-pagination/navigating_results.rb:
--------------------------------------------------------------------------------
1 | require 'octokit'
2 |
3 | # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
4 | # Instead, set and test environment variables, like below
5 | client = Octokit::Client.new :access_token => ENV['MY_PERSONAL_TOKEN']
6 |
7 | results = client.search_code('addClass user:mozilla')
8 | total_count = results.total_count
9 |
10 | last_response = client.last_response
11 | number_of_pages = last_response.rels[:last].href.match(/page=(\d+).*$/)[1]
12 |
13 | puts "There are #{total_count} results, on #{number_of_pages} pages!"
14 |
15 | puts "And here's the first path for every set"
16 |
17 | puts last_response.data.items.first.path
18 | until last_response.rels[:next].nil?
19 | last_response = last_response.rels[:next].get
20 | sleep 4 # back off from the API rate limiting; don't do this in Real Life
21 | break if last_response.rels[:next].nil?
22 | puts last_response.data.items.first.path
23 | end
24 |
25 |
--------------------------------------------------------------------------------
/api/ruby/user-auditing/README.md:
--------------------------------------------------------------------------------
1 | # Suspended User Audit
2 |
3 | Lists total number of active, suspended, and recently suspended users. Gives the option to unsuspend all recently suspended users. This is mostly useful when a configuration change may have caused a large number of users to become suspended.
4 |
5 | ## Installation
6 |
7 |
8 | ### Clone this repository
9 |
10 | ```shell
11 | git clone git@github.com:github/platform-samples.git
12 | cd api/ruby/user-auditing
13 | ```
14 |
15 |
16 | ### Install dependencies
17 |
18 | ```shell
19 | gem install octokit
20 | ```
21 |
22 |
23 | ## Usage
24 |
25 | ### Configure Octokit
26 |
27 | ```shell
28 | export OCTOKIT_API_ENDPOINT="https://github.example.com/api/v3" # Default: "https://api.github.com"
29 | export OCTOKIT_ACCESS_TOKEN=00000000000000000000000
30 | ```
31 |
32 | ### Execute
33 |
34 | ```shell
35 | ruby suspended_user_audit.rb
36 | ```
37 |
--------------------------------------------------------------------------------
/api/ruby/user-auditing/suspended_user_audit.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # Suspended User Audit - Generated with Octokitchen https://github.com/kylemacey/octokitchen
4 |
5 | # Dependencies
6 | require "octokit"
7 |
8 | Octokit.configure do |kit|
9 | kit.auto_paginate = true
10 | end
11 |
12 | client = Octokit::Client.new
13 | users = client.all_users
14 | n = 1
15 | puts "Aggregating users..."
16 | full_users = users.map { |u|
17 | print "\r#{n}/#{users.count}"
18 | n += 1
19 | client.user(u.login) rescue nil;
20 | }
21 |
22 | suspended = full_users.select do |u|
23 | next unless u
24 | !u.suspended_at.nil? rescue false;
25 | end
26 |
27 | active = full_users.select do |u|
28 | next unless u
29 | u.suspended_at.nil? rescue false;
30 | end
31 |
32 | seconds_in_two_days = 60 * # seconds in an minute
33 | 60 * # minutes in an hour
34 | 48 # hours in 2 days
35 |
36 | recent = suspended.select do |u|
37 | u[:suspended_at] > (Time.now - seconds_in_two_days)
38 | end
39 |
40 | puts ""
41 | puts ""
42 | puts "Suspended: #{suspended.count}"
43 | puts "Recently Suspended: #{recent.count}"
44 | puts "Active: #{active.count}"
45 |
46 | puts ""
47 |
48 | print "Unsuspend recently suspended users? (y/N) "
49 |
50 | if gets.rstrip == "y"
51 | ent = Octokit::EnterpriseAdminClient.new
52 |
53 | recent.each do |u|
54 | ent.unsuspend u[:login]
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/api/ruby/working-with-comments/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "octokit", "~> 2.0"
4 |
--------------------------------------------------------------------------------
/api/ruby/working-with-comments/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: http://rubygems.org/
3 | specs:
4 | faraday (0.8.8)
5 | multipart-post (~> 1.2.0)
6 | multipart-post (1.2.0)
7 | octokit (2.1.1)
8 | sawyer (~> 0.3.0)
9 | sawyer (0.3.0)
10 | faraday (~> 0.8, < 0.10)
11 | uri_template (~> 0.5.0)
12 | uri_template (0.5.3)
13 |
14 | PLATFORMS
15 | ruby
16 |
17 | DEPENDENCIES
18 | octokit (~> 2.0)
19 |
--------------------------------------------------------------------------------
/api/ruby/working-with-comments/comments_on_a_commit.rb:
--------------------------------------------------------------------------------
1 | require 'octokit'
2 |
3 | # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
4 | # Instead, set and test environment variables, like below
5 | client = Octokit::Client.new :access_token => ENV['MY_PERSONAL_TOKEN']
6 |
7 | client.commit_comments("octocat/Spoon-Knife", "cbc28e7c8caee26febc8c013b0adfb97a4edd96e").each do |comment|
8 | username = comment[:user][:login]
9 | post_date = comment[:created_at]
10 | content = comment[:body]
11 |
12 | puts "#{username} made a comment on #{post_date}. It says:\n'#{content}'\n"
13 | end
14 |
--------------------------------------------------------------------------------
/api/ruby/working-with-comments/comments_on_an_entire_diff.rb:
--------------------------------------------------------------------------------
1 | require 'octokit'
2 |
3 | # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
4 | # Instead, set and test environment variables, like below
5 | client = Octokit::Client.new :access_token => ENV['MY_PERSONAL_TOKEN']
6 |
7 | client.pull_request_comments("octocat/Spoon-Knife", 1176).each do |comment|
8 | username = comment[:user][:login]
9 | post_date = comment[:created_at]
10 | content = comment[:body]
11 |
12 | puts "#{username} made a comment on #{post_date}. It says:\n'#{content}'\n"
13 | end
14 |
--------------------------------------------------------------------------------
/api/ruby/working-with-comments/pull_request_comment.rb:
--------------------------------------------------------------------------------
1 | require 'octokit'
2 |
3 | # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
4 | # Instead, set and test environment variables, like below
5 | client = Octokit::Client.new :access_token => ENV['MY_PERSONAL_TOKEN']
6 |
7 | client.issue_comments("octocat/Spoon-Knife", 1176).each do |comment|
8 | username = comment[:user][:login]
9 | post_date = comment[:created_at]
10 | content = comment[:body]
11 |
12 | puts "#{username} made a comment on #{post_date}. It says:\n'#{content}'\n"
13 | end
14 |
--------------------------------------------------------------------------------
/api/scala.with.sbt/octocat-samples/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/*
2 | project/*
3 | target/*
4 |
--------------------------------------------------------------------------------
/api/scala.with.sbt/octocat-samples/build.sbt:
--------------------------------------------------------------------------------
1 | name := "octocat-samples"
2 | version := "1.0"
3 | scalaVersion := "2.12.0"
4 | libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.4"
5 |
--------------------------------------------------------------------------------
/api/scala.with.sbt/octocat-samples/src/main/scala/DemoOrganizations.scala:
--------------------------------------------------------------------------------
1 | import github.features.{Organizations, Repositories}
2 |
3 | /**
4 | * Create an organization and then a repository
5 | */
6 | object DemoOrganizations extends App {
7 |
8 | val gitHubCli = new github.Client(
9 | "http://github.at.home/api/v3",
10 | sys.env("TOKEN_GITHUB_ENTERPRISE")
11 | ) with Organizations
12 | with Repositories
13 |
14 | gitHubCli.createOrganization(
15 | login = "PlanetEarth",
16 | admin = "k33g",
17 | profile_name = "PlanetEarth Organization"
18 | ).fold(
19 | {errorMessage => println(s"Organization Error: $errorMessage")},
20 | {
21 | case Some(organizationData) =>
22 | val organization = organizationData.asInstanceOf[Map[String, Any]]
23 | println(organization)
24 | println(organization.getOrElse("login","???"))
25 |
26 | gitHubCli.createOrganizationRepository(
27 | name = "my-little-tools",
28 | description = "foo...",
29 | organization = organization.getOrElse("login","???").toString,
30 | isPrivate = false,
31 | hasIssues = true
32 | ).fold(
33 | {errorMessage => println(s"Repository Error: $errorMessage")},
34 | {repositoryInformation:Option[Any] =>
35 | println(
36 | repositoryInformation
37 | .map(repo => repo.asInstanceOf[Map[String, Any]])
38 | .getOrElse("Huston? We've got a problem!")
39 | )
40 | }
41 | )
42 | case None =>
43 | println("Huston? We've got a problem!")
44 | }
45 |
46 | )
47 | }
48 |
--------------------------------------------------------------------------------
/api/scala.with.sbt/octocat-samples/src/main/scala/DemoRepositories.scala:
--------------------------------------------------------------------------------
1 | import github.features.Repositories
2 |
3 | /**
4 | * Create a repository
5 | */
6 | object DemoRepositories extends App {
7 |
8 | val gitHubCli = new github.Client(
9 | "https://api.github.com",
10 | sys.env("TOKEN_GITHUB_DOT_COM")
11 | ) with Repositories
12 |
13 | gitHubCli.createRepository(
14 | name = "hello_earth_africa",
15 | description = "Hello world :heart:",
16 | isPrivate = false,
17 | hasIssues = true
18 | ).fold(
19 | {errorMessage => println(s"Error: $errorMessage")},
20 | {repositoryInformation:Option[Any] =>
21 | println(
22 | repositoryInformation
23 | .map(repo => repo.asInstanceOf[Map[String, Any]])
24 | .getOrElse("ouch!")
25 | )
26 | }
27 | )
28 | }
--------------------------------------------------------------------------------
/api/scala.with.sbt/octocat-samples/src/main/scala/DemoUser.scala:
--------------------------------------------------------------------------------
1 | import github.features.Users
2 |
3 | /**
4 | * Display user informations on GitHub
5 | */
6 | object DemoUser extends App {
7 |
8 | val gitHubCli = new github.Client(
9 | "https://api.github.com",
10 | sys.env("TOKEN_GITHUB_DOT_COM")
11 | ) with Users
12 |
13 |
14 | gitHubCli.fetchUser("k33g").fold(
15 | {errorMessage => println(errorMessage)},
16 | {userInformation:Option[Any] =>
17 | println(
18 | userInformation
19 | .map(user => user.asInstanceOf[Map[String, Any]])
20 | .getOrElse("Huston? We've got a problem!")
21 | )
22 | }
23 | )
24 |
25 | }
--------------------------------------------------------------------------------
/api/scala.with.sbt/octocat-samples/src/main/scala/DemoZen.scala:
--------------------------------------------------------------------------------
1 | import github.features.Zen
2 |
3 | object DemoZen extends App {
4 | /**
5 | * Display Zen of GitHub
6 | */
7 | val gitHubCli = new github.Client(
8 | "https://api.github.com"
9 | , sys.env("TOKEN_GITHUB_DOT_COM")
10 | ) with Zen
11 |
12 | gitHubCli.octocatMessage().fold(
13 | {errorMessage => println(s"Error: $errorMessage")},
14 | {data => println(data)}
15 | )
16 |
17 | }
--------------------------------------------------------------------------------
/api/scala.with.sbt/octocat-samples/src/main/scala/github/Client.scala:
--------------------------------------------------------------------------------
1 | package github
2 |
3 | import github.features.RESTMethods
4 |
5 | /** =Simple GitHub client=
6 | *
7 | * ==Setup==
8 | * {{{
9 | * val gitHubCli = new github.Client(
10 | * "https://api.github.com",
11 | * sys.env("TOKEN_GITHUB_DOT_COM")
12 | * ) with trait1 with trait2
13 | * // trait1, trait2 are features provided in the `features` package
14 | * }}}
15 | */
16 | class Client(gitHubUrl:String, gitHubToken:String) extends RESTMethods {
17 | override var baseUri: String = gitHubUrl
18 | override var token: String = gitHubToken
19 | }
20 |
--------------------------------------------------------------------------------
/api/scala.with.sbt/octocat-samples/src/main/scala/github/features/Users.scala:
--------------------------------------------------------------------------------
1 | package github.features
2 |
3 |
4 | import http.Response
5 |
6 | import scala.util.{Failure, Success}
7 | import scala.util.parsing.json.JSON
8 |
9 | /** =Users features=
10 | *
11 | * ==Setup==
12 | *
13 | * instantiate the `github.Client` with `Users` trait:
14 | *
15 | * {{{
16 | * val gitHubCli = new github.Client(
17 | * "http://github.at.home/api/v3",
18 | * sys.env("TOKEN_GITHUB_ENTERPRISE")
19 | * ) with Users
20 | *
21 | * }}}
22 | */
23 | trait Users extends RESTMethods {
24 | /** Get the details of a User on GitHub
25 | *
26 | * @param user user handle(login)
27 | * @return
28 | */
29 | def fetchUser(user:String):Either[String, Option[Any]] = {
30 | getData(s"/users/$user", generateHeaders.::(new http.Header("Content-Type", "application/json"))) match {
31 | case Success(resp:Response) =>
32 | if (http.isOk(resp.code)) Right(JSON.parseFull(resp.data)) else Left(resp.message)
33 | case Failure(err) => Left(err.getMessage)
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/api/scala.with.sbt/octocat-samples/src/main/scala/github/features/Zen.scala:
--------------------------------------------------------------------------------
1 | package github.features
2 |
3 | import http.Response
4 |
5 | import scala.util.{Failure, Success}
6 |
7 | /** =Zen features=
8 | *
9 | * ==Setup==
10 | *
11 | * instantiate the `github.Client` with `Zen` trait:
12 | *
13 | * {{{
14 | * val gitHubCli = new github.Client(
15 | * "http://github.at.home/api/v3",
16 | * sys.env("TOKEN_GITHUB_ENTERPRISE")
17 | * ) with Zen
18 | *
19 | * }}}
20 | */
21 | trait Zen extends RESTMethods {
22 | /** Get zen of Octocat
23 | *
24 | * @return
25 | */
26 | def octocatMessage():Either[String, String] = {
27 | getData("/octocat", generateHeaders.::(new http.Header("Content-Type", "plain/text"))) match {
28 | case Success(resp:Response) => if (http.isOk(resp.code)) Right(resp.data) else Left(resp.message)
29 | case Failure(err) => Left(err.getMessage)
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/api/scala.with.sbt/octocat-samples/src/main/scala/http/Header.scala:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | /**
4 | *
5 | * @param property name of the header
6 | * @param value value of the header
7 | */
8 | class Header(val property:String, val value:String) {}
9 |
--------------------------------------------------------------------------------
/api/scala.with.sbt/octocat-samples/src/main/scala/http/Response.scala:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | /**
4 | *
5 | * @param code http response code
6 | * @param message message of the response
7 | * @param data data of the response
8 | */
9 | class Response(val code:Int, val message:String, val data:String) {}
10 |
--------------------------------------------------------------------------------
/app/ruby/app-issue-creator/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "activesupport", "~> 6.1"
4 | gem "json", "~> 2.3"
5 | gem "jwt"
6 | gem "octokit"
7 | gem "sinatra", "~> 2.2.3"
8 |
--------------------------------------------------------------------------------
/app/ruby/app-issue-creator/README.md:
--------------------------------------------------------------------------------
1 | # app-issue-creator
2 |
3 | This is the sample project that walks through creating a GitHub App and configuring a server to listen to [`installation` events](https://developer.github.com/v3/activity/events/types/#installationevent). When an App is added to an account, it will create an issue in each repository with a message, "added new app!".
4 |
5 | ## Requirements
6 |
7 | * Ruby installed
8 | * [Bundler](http://bundler.io/) installed
9 | * [ngrok](https://ngrok.com/) or [localtunnel](https://localtunnel.github.io/www/) exposing port `4567` to allow GitHub to access your server
10 |
11 | ## Set up a GitHub App
12 |
13 | * [Set up and register GitHub App](https://developer.github.com/apps/building-integrations/setting-up-and-registering-github-apps/)
14 | * [Enable `issue` write permissions](https://developer.github.com/v3/apps/permissions/#permission-on-issues)
15 | * If not running on a public-facing IP, use ngrok to generate a URL as [documented here](https://developer.github.com/v3/guides/building-a-ci-server/#writing-your-server)
16 |
17 | ## Install and Run project
18 |
19 | Install the required Ruby Gems by entering `bundle install` on the command line.
20 |
21 | Set environment variables `GITHUB_APP_ID` and `GITHUB_APP_PRIVATE_KEY`. For example, run the following to store the private key to an environment variable: `export GITHUB_APP_PRIVATE_KEY="$(less private-key.pem)"`
22 |
23 | To start the server, type `ruby server.rb` on the command line.
24 |
25 | The [sinatra server](http://www.sinatrarb.com/) will be running at `localhost:4567`.
26 |
27 | [basics of auth]: http://developer.github.com/guides/basics-of-authentication/
28 |
--------------------------------------------------------------------------------
/graphql/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 | package-lock.json
4 |
--------------------------------------------------------------------------------
/graphql/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "httparty"
4 |
--------------------------------------------------------------------------------
/graphql/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | httparty (0.21.0)
5 | mini_mime (>= 1.0.0)
6 | multi_xml (>= 0.5.2)
7 | mini_mime (1.1.2)
8 | multi_xml (0.6.0)
9 |
10 | PLATFORMS
11 | ruby
12 |
13 | DEPENDENCIES
14 | httparty
15 |
16 | BUNDLED WITH
17 | 1.11.2
18 |
--------------------------------------------------------------------------------
/graphql/README.md:
--------------------------------------------------------------------------------
1 | # GitHub GraphQL API: Query Samples
2 |
3 | This repository holds query samples for the GitHub GraphQL API. It's an easy way to get started using the GraphQL API for common workflows. You can copy and paste these queries into [GraphQL Explorer](https://developer.github.com/early-access/graphql/explorer) or you can use the included script.
4 |
5 | ### How to use the included script
6 |
7 | 1. Generate a [personal access token](https://help.github.com/articles/creating-an-access-token-for-command-line-use/) for use with these queries.
8 | 1. Run `npm install`
9 | 1. Pick the name of one of the included queries in the `/queries` directory, such as `viewer.graphql`.
10 | 1. Run `bin/run-query `
11 |
12 | To change variable values, modify the variables in the `.graphql` file.
13 |
--------------------------------------------------------------------------------
/graphql/enterprise/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/graphql/enterprise/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github/platform-samples/4fe2f31287f0a6f005479c36e3de367fc2730cc2/graphql/enterprise/.nojekyll
--------------------------------------------------------------------------------
/graphql/enterprise/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "graphiql-pages",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "graphiql": "^1.4.7",
7 | "primer-css": "^6.0.0",
8 | "react": "^15.5.4",
9 | "react-dom": "^16.0.1"
10 | },
11 | "scripts": {
12 | "build": "node scripts/build.js"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/graphql/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "graphql",
3 | "version": "1.0.0",
4 | "description": "Simple command line utility for running GraphQL queries",
5 | "main": "index.js",
6 | "bin": {
7 | "run-query": "./index.js"
8 | },
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "author": "bryancross@github.com",
13 | "license": "ISC",
14 | "dependencies": {
15 | "commander": "^2.12.2"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/graphql/queries/emu-list-enterprise-member-email-addresses.graphql:
--------------------------------------------------------------------------------
1 | # This GraphQL query will print a list of all EMU (Enterprise Managed User) member email addresses, usernames, and display names in an enterprise.
2 | # This query will not work properly for enterprises that do not use EMUs, as non-EMU enterprises contain personal user accounts and therefore email addresses may be private depending on the user profile configuration.
3 |
4 | query {
5 | enterprise(slug: "ENT_SLUG") {
6 | members(first: 100) {
7 | nodes {
8 | ... on EnterpriseUserAccount {
9 | login
10 | name
11 | user {
12 | email
13 | }
14 | organizations(first: 10) {
15 | nodes {
16 | login
17 | }
18 | }
19 | }
20 | }
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/graphql/queries/emu-scim-list-scim-identities.graphql:
--------------------------------------------------------------------------------
1 | # For GitHub Enterprise Cloud enterprises that are using Enterprise Managed Users (EMUs) and SAML authentication, this GraphQL query will print a list (first 100 in this example) of the SCIM identities (specifically, the SCIM `username` attribute) and the linked GitHub usernames.
2 | # This query will not work for enterprises that do not use EMUs, as SCIM provisioning cannot be enabled at the enterprise level for enterprises that do not use EMUs.j
3 | # Modifying this query to also show member SAML identities will not work for EMU enterprises, since SAML identities are not currently stored for enterprises that use EMUs.
4 | # This query will also not work for EMU enterprises that are using Azure AD OIDC for authentication.
5 | # If there are a large number of identities/users (greater than 100), pagination will need to be used. See https://graphql.org/learn/pagination/ for details on pagination. There is an example of pagination in simple-pagination-example.graphql.
6 |
7 | query {
8 | enterprise(slug: "ENT_SLUG") {
9 | ownerInfo {
10 | samlIdentityProvider {
11 | externalIdentities(first: 100) {
12 | pageInfo {
13 | hasNextPage
14 | endCursor
15 | }
16 | edges{
17 | node{
18 | scimIdentity {
19 | username
20 | }
21 | user {
22 | login
23 | name
24 | }
25 | }
26 | }
27 | }
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/graphql/queries/emu-scim-oidc-list-scim-identities.graphql:
--------------------------------------------------------------------------------
1 | # For GitHub Enterprise Cloud enterprises that are using Enterprise Managed Users (EMUs) and have Azure AD OIDC setup in the enterprise authentication settings, this query will print a list of the first 100 SCIM identities and their GitHub usernames.
2 | # The SCIM identity attributes displayed in the query results will include the SCIM `username`, the first (`givenName`) and last (familyName`) name, and the `emails` attribute value.
3 | # The SCIM identity attributes that are stored in a GitHub EMU enterprise are based on the attributes that the external Identity Provider has previously sent for each user via the SCIM integration which leverages the GitHub EMU SCIM API.
4 | # The query will not work for EMU enterprises that are using SAML as the enterprise authentication method.
5 |
6 | query {
7 | enterprise(slug: "ENT_SLUG") {
8 | ownerInfo {
9 | oidcProvider {
10 | id
11 | providerType
12 | tenantId
13 | externalIdentities(first: 100) {
14 | totalCount
15 | edges {
16 | node {
17 | scimIdentity {
18 | username
19 | givenName
20 | familyName
21 | emails {
22 | primary
23 | type
24 | value
25 | }
26 | }
27 | user {
28 | login
29 | name
30 | }
31 | }
32 | }
33 | }
34 | }
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/graphql/queries/enterprise-audit-log.graphql:
--------------------------------------------------------------------------------
1 | # This graphql queries for audit logs at the enterprise level
2 |
3 | # Make sure that you set the request to `POST` with URL `https://api.github.com/graphql`
4 | # Set `Headers` where `Content-Type` is `application/json` and `Accept` is `application/vnd.github.audit-log-preview+json`
5 |
6 | query {
7 | enterprise(slug: "ENT_SLUG") {
8 | organizations(first: 100){
9 | nodes {
10 | auditLog(last: 5) {
11 | edges {
12 | node {
13 | ... on AuditEntry {
14 | # Get Audit Log Entry by 'Action'
15 | action
16 | actorLogin
17 | createdAt
18 | # User 'Action' was performed on
19 | user{
20 | name
21 | email
22 | }
23 | }
24 | }
25 | }
26 | }
27 | }
28 | }
29 | }
30 | }
31 |
32 | # If you'd like to use environment variables, this is what it would look like:
33 |
34 | query getAuditLog($entSlug: String!, $numEntries: Int!, $cursor: String){
35 | enterprise(slug: $slug) {
36 | organizations(first: 100){
37 | nodes {
38 | auditLog(last: $numEntries, before: $cursor) {
39 | edges {
40 | node {
41 | ... on AuditEntry { # Get Audit Log Entry by 'Action'
42 | action
43 | actorLogin
44 | createdAt
45 | user { # User 'Action' was performed on
46 | name
47 | email
48 | }
49 | }
50 | }
51 | cursor
52 | }
53 | pageInfo {
54 | endCursor
55 | hasNextPage
56 | }
57 | totalCount
58 | }
59 | }
60 | }
61 | }
62 | }
63 |
64 | # Envrionment variables:
65 | {
66 | "entSlug": "",
67 | "numEntries": 5,
68 | "cursor": null
69 | }
--------------------------------------------------------------------------------
/graphql/queries/enterprise-get-ip-allow-list.graphql:
--------------------------------------------------------------------------------
1 | # Grab current IP allow list settings for an enterprise.
2 | # This includes:
3 | # - The IP allow list entries
4 | # - The IP allow list enabled setting
5 | # - The IP allow list for GitHub Apps enabled setting
6 |
7 | query GetEnterpriseIPAllowList {
8 | enterprise(slug: "ENTERPRISE_SLUG") {
9 | owner_id: id
10 | enterprise_slug: slug
11 | enterprise_owner_info: ownerInfo {
12 | is_ip_allow_list_enabled: ipAllowListEnabledSetting
13 | is_ip_allow_list_for_github_apps_enabled: ipAllowListForInstalledAppsEnabledSetting
14 | ipAllowListEntries(first: 100) {
15 | nodes {
16 | ip_allow_list_entry_id: id
17 | ip_allow_list_entry_name: name
18 | ip_allow_list_entry_value: allowListValue
19 | ip_allow_list_entry_created: createdAt
20 | is_ip_allow_list_entry_active: isActive
21 | }
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/graphql/queries/enterprise-members-2fa-disabled.graphql:
--------------------------------------------------------------------------------
1 | # This GraphQL query will list any enterprise members who have yet to enable 2FA on their personal GitHub account.
2 | # This does not list any outside collaborators, and will not work with Enterprise Managed Users other than the setup user.
3 |
4 | query GetEnterpriseMembersWith2faDisabled {
5 | enterprise(slug: "ENTERPRISE_SLUG") {
6 | enterprise_id: id
7 | enterprise_slug: slug
8 | members_with_no_2fa: members(
9 | first: 100
10 | twoFactorMethodSecurity: DISABLED
11 | ) {
12 | num_of_members: totalCount
13 | edges {
14 | node {
15 | ... on EnterpriseUserAccount {
16 | login
17 | }
18 | }
19 | }
20 | pageInfo {
21 | endCursor
22 | startCursor
23 | hasNextPage
24 | hasPreviousPage
25 | }
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/graphql/queries/enterprise-members-2fa-insecure.graphql:
--------------------------------------------------------------------------------
1 | # This GraphQL query will list any enterprise members who have enabled 2FA on their GitHub account, but amongst their 2FA methods is SMS (which is deemed insecure).
2 | # This does not list any outside collaborators, and will not work with Enterprise Managed Users other than the setup user.
3 |
4 | query GetEnterpriseMembersWithInsecure2fa {
5 | enterprise(slug: "ENTERPRISE_SLUG") {
6 | enterprise_id: id
7 | enterprise_slug: slug
8 | members_with_insecure_2fa: members(
9 | first: 100
10 | twoFactorMethodSecurity: INSECURE
11 | ) {
12 | num_of_members: totalCount
13 | edges {
14 | node {
15 | ... on EnterpriseUserAccount {
16 | login
17 | }
18 | }
19 | }
20 | pageInfo {
21 | endCursor
22 | startCursor
23 | hasNextPage
24 | hasPreviousPage
25 | }
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/graphql/queries/enterprise-members-2fa-secure.graphql:
--------------------------------------------------------------------------------
1 | # This GraphQL query will list any enterprise members who have enabled 2FA on their GitHub account with a secure (non-SMS) method.
2 | # This does not list any outside collaborators, and will not work with Enterprise Managed Users other than the setup user.
3 |
4 | query GetEnterpriseMembersWithSecure2fa {
5 | enterprise(slug: "ENTERPRISE_SLUG") {
6 | enterprise_id: id
7 | enterprise_slug: slug
8 | members_with_secure_2fa: members(
9 | first: 100
10 | twoFactorMethodSecurity: SECURE
11 | ) {
12 | num_of_members: totalCount
13 | edges {
14 | node {
15 | ... on EnterpriseUserAccount {
16 | login
17 | }
18 | }
19 | }
20 | pageInfo {
21 | endCursor
22 | startCursor
23 | hasNextPage
24 | hasPreviousPage
25 | }
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/graphql/queries/enterprise-outside-collaborators-2fa-disabled.graphql:
--------------------------------------------------------------------------------
1 | # This GraphQL query will list any outside collaborators in an enterprise who have yet to enable 2FA on their GitHub account.
2 |
3 | query GetEnterpriseollaboratorsWith2faDisabled {
4 | enterprise(slug: "ENTERPRISE_SLUG") {
5 | enterprise_id: id
6 | enterprise_slug: slug
7 | enterprise_owner_info: ownerInfo {
8 | collaborators_with_no_2fa: outsideCollaborators(
9 | twoFactorMethodSecurity: DISABLED
10 | first: 100
11 | ) {
12 | num_of_collaborators: totalCount
13 | nodes {
14 | login
15 | }
16 | pageInfo {
17 | endCursor
18 | startCursor
19 | hasNextPage
20 | hasPreviousPage
21 | }
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/graphql/queries/enterprise-outside-collaborators-2fa-insecure.graphql:
--------------------------------------------------------------------------------
1 | # This GraphQL query will list any outside collaborators in an enterprise who have enabled 2FA on their GitHub account, but amongst the 2FA methods is SMS (which is deemed insecure).
2 |
3 | query GetEnterpriseCollaboratorsWithInsecure2fa {
4 | enterprise(slug: "ENTERPRISE_SLUG") {
5 | enterprise_id: id
6 | enterprise_slug: slug
7 | enterprise_owner_info: ownerInfo {
8 | collaborators_with_insecure_2fa: outsideCollaborators(
9 | twoFactorMethodSecurity: INSECURE
10 | first: 100
11 | ) {
12 | num_of_collaborators: totalCount
13 | nodes {
14 | login
15 | }
16 | pageInfo {
17 | endCursor
18 | startCursor
19 | hasNextPage
20 | hasPreviousPage
21 | }
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/graphql/queries/enterprise-outside-collaborators-2fa-secure.graphql:
--------------------------------------------------------------------------------
1 | # This GraphQL query will list any outside collaborators in an enterprise who have enabled 2FA on their GitHub account with a secure (non-SMS) method.
2 |
3 | query GetEnterpriseCollaboratorsWithSecure2fa {
4 | enterprise(slug: "ENTERPRISE_SLUG") {
5 | enterprise_id: id
6 | enterprise_slug: slug
7 | enterprise_owner_info: ownerInfo {
8 | collaborators_with_secure_2fa: outsideCollaborators(
9 | twoFactorMethodSecurity: SECURE
10 | first: 100
11 | ) {
12 | num_of_collaborators: totalCount
13 | nodes {
14 | login
15 | }
16 | pageInfo {
17 | endCursor
18 | startCursor
19 | hasNextPage
20 | hasPreviousPage
21 | }
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/graphql/queries/enterprise-saml-identities.graphql:
--------------------------------------------------------------------------------
1 | # For GitHub Enterprise Cloud enterprises that have SAML configured at the enterprise level, this query will print a list of the first 100 SAML identities (specifically the `nameId` attribute value) in the enterprise and the linked GitHub username (if the SAML identity is linked).
2 | # An email address often gets used for the SAML `nameId` value, but this is not always the case.
3 | # If the Identity Provider has sent an `emails` attribute/value in a previous SAML response for enterprise member(s), it also possible to add the `emails` attribute in the `samlIdentity` section right below `nameID` and query for this SAML identity attribute value as well.
4 | # If there are a large number of identities/users (greater than 100), pagination will need to be used. See https://graphql.org/learn/pagination/ for details on pagination. There is an example of pagination in simple-pagination-example.graphql.
5 |
6 | query listSSOUserIdentities {
7 | enterprise(slug: "ENTERPRISE_SLUG") {
8 | ownerInfo {
9 | samlIdentityProvider {
10 | externalIdentities(first: 100) {
11 | totalCount
12 | edges {
13 | node {
14 | guid
15 | samlIdentity {
16 | nameId
17 | }
18 | user {
19 | login
20 | }
21 | }
22 | }
23 | pageInfo {
24 | hasNextPage
25 | endCursor
26 | }
27 | }
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/graphql/queries/enterprise-scim-identities-all-orgs.graphql:
--------------------------------------------------------------------------------
1 | # For GitHub Enterprise Cloud organizations that are in an enterprise and have SAML and SCIM configured at the organization level, this query will print out a list of the first 100 SCIM identities (specifically the `username` attribute value in these SCIM identities) in the first 100 organizations in the enterprise.
2 | # The query will also print out the linked GitHub username, if the SCIM identity is linked to a user. A SCIM identity can be unlinked if a user has not logged in with their GitHub.com user account, accepted the invitation and authenticated via SAML to link their SAML/SCIM identity.
3 | # This query will not print out a SCIM identity (`username` attribute) for members if an organization is not using SCIM provisioning, or if a user does not have a linked SCIM identity.
4 | # This query will not work for GitHub Enterprise Cloud enterprises that are using Enterprise Managed Users (EMUs).
5 |
6 | query ($entSlug: String!) {
7 | enterprise(slug: $entSlug) {
8 | organizations(first: 100) {
9 | nodes {
10 | samlIdentityProvider {
11 | ssoUrl
12 | externalIdentities(first: 100) {
13 | edges {
14 | node {
15 | user {
16 | login
17 | email
18 | }
19 | scimIdentity {
20 | username
21 | }
22 | }
23 | }
24 | }
25 | }
26 | }
27 | }
28 | }
29 | }
30 |
31 | variables {
32 | "entSlug": "ENT_SLUG"
33 | }
--------------------------------------------------------------------------------
/graphql/queries/introspection_query.graphql:
--------------------------------------------------------------------------------
1 | query IntrospectionQuery {
2 | __schema {
3 | queryType { name }
4 | mutationType { name }
5 | types {
6 | ...FullType
7 | }
8 | directives {
9 | name
10 | description
11 | args {
12 | ...InputValue
13 | }
14 | onOperation
15 | onFragment
16 | onField
17 | }
18 | }
19 | }
20 |
21 | fragment FullType on __Type {
22 | kind
23 | name
24 | description
25 | fields {
26 | name
27 | description
28 | args {
29 | ...InputValue
30 | }
31 | type {
32 | ...TypeRef
33 | }
34 | isDeprecated
35 | deprecationReason
36 | }
37 | inputFields {
38 | ...InputValue
39 | }
40 | interfaces {
41 | ...TypeRef
42 | }
43 | enumValues {
44 | name
45 | description
46 | isDeprecated
47 | deprecationReason
48 | }
49 | possibleTypes {
50 | ...TypeRef
51 | }
52 | }
53 |
54 | fragment InputValue on __InputValue {
55 | name
56 | description
57 | type { ...TypeRef }
58 | defaultValue
59 | }
60 |
61 | fragment TypeRef on __Type {
62 | kind
63 | name
64 | ofType {
65 | kind
66 | name
67 | ofType {
68 | kind
69 | name
70 | ofType {
71 | kind
72 | name
73 | }
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/graphql/queries/ip-allow-list-add-ip.graphql:
--------------------------------------------------------------------------------
1 | # This query is used to add an IP address to the IP allow list.
2 | # This can be used on both organizations and enterprise accounts.
3 | #
4 | # The `OWNER_ID` is the ID of the organization or enterprise account. You can
5 | # get the ID of an organization or enterprise account by executing either of
6 | # the following queries and referring to the value from `owner_id` field:
7 | #
8 | # - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql
9 | # - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql
10 |
11 | mutation AddIPAddressToIPAllowList {
12 | createIpAllowListEntry(
13 | input: {
14 | ownerId: "OWNER_ID"
15 | name: "DESCRIPTION_OF_IP_ADDRESS"
16 | allowListValue: "IP_ADDRESS"
17 | isActive: true
18 | }
19 | ) {
20 | ipAllowListEntry {
21 | ip_allow_list_entry_id: id
22 | ip_allow_list_entry_name: name
23 | ip_allow_list_entry_ip_address: allowListValue
24 | ip_allow_list_entry_created: createdAt
25 | ip_allow_list_entry_updated: updatedAt
26 | is_ip_allow_list_entry_active: isActive
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/graphql/queries/ip-allow-list-disable-github-apps-only.graphql:
--------------------------------------------------------------------------------
1 | # This query is used to disable the IP allow list feature. This will apply to GitHub Apps only.
2 | # This can be used on both organizations and enterprise accounts.
3 | #
4 | # The `OWNER_ID` is the ID of the organization or enterprise account. You can
5 | # get the ID of an organization or enterprise account by executing either of
6 | # the following queries and referring to the value from `owner_id` field:
7 | #
8 | # - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql
9 | # - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql
10 |
11 | mutation DisableIPAllowListForGitHubAppsOnly {
12 | updateIpAllowListForInstalledAppsEnabledSetting(
13 | input: { ownerId: "OWNER_ID", settingValue: DISABLED }
14 | ) {
15 | clientMutationId
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/graphql/queries/ip-allow-list-disable-ip-address-only.graphql:
--------------------------------------------------------------------------------
1 | # This query is used to disable the IP allow list feature. This will apply to IP addresses only.
2 | # This can be used on both organizations and enterprise accounts.
3 | #
4 | # The `OWNER_ID` is the ID of the organization or enterprise account. You can
5 | # get the ID of an organization or enterprise account by executing either of
6 | # the following queries and referring to the value from `owner_id` field:
7 | #
8 | # - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql
9 | # - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql
10 |
11 | mutation DisableAllowListForIpsOnly {
12 | updateIpAllowListEnabledSetting(
13 | input: { ownerId: "OWNER_ID", settingValue: DISABLED }
14 | ) {
15 | clientMutationId
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/graphql/queries/ip-allow-list-disable.graphql:
--------------------------------------------------------------------------------
1 | # This query is used to disable the IP allow list feature. This will apply to both IP addresses and GitHub Apps.
2 | # This can be used on both organizations and enterprise accounts.
3 | #
4 | # The `OWNER_ID` is the ID of the organization or enterprise account. You can
5 | # get the ID of an organization or enterprise account by executing either of
6 | # the following queries and referring to the value from `owner_id` field:
7 | #
8 | # - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql
9 | # - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql
10 |
11 | mutation DisableIPAllowList {
12 | updateIpAllowListEnabledSetting(
13 | input: { ownerId: "OWNER_ID", settingValue: DISABLED }
14 | ) {
15 | clientMutationId
16 | }
17 | updateIpAllowListForInstalledAppsEnabledSetting(
18 | input: { ownerId: "OWNER_ID", settingValue: DISABLED }
19 | ) {
20 | clientMutationId
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/graphql/queries/ip-allow-list-enable-github-apps-only.graphql:
--------------------------------------------------------------------------------
1 | # This query is used to enable the IP allow list feature. This will apply to GitHub Apps only.
2 | # This can be used on both organizations and enterprise accounts.
3 | #
4 | # The `OWNER_ID` is the ID of the organization or enterprise account. You can
5 | # get the ID of an organization or enterprise account by executing either of
6 | # the following queries and referring to the value from `owner_id` field:
7 | #
8 | # - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql
9 | # - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql
10 |
11 | mutation EnableIPAllowListForGitHubAppsOnly {
12 | updateIpAllowListForInstalledAppsEnabledSetting(
13 | input: { ownerId: "OWNER_ID", settingValue: ENABLED }
14 | ) {
15 | clientMutationId
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/graphql/queries/ip-allow-list-enable-ip-address-only.graphql:
--------------------------------------------------------------------------------
1 | # This query is used to enable the IP allow list feature. This will apply to IP addresses only.
2 | # This can be used on both organizations and enterprise accounts.
3 | #
4 | # The `OWNER_ID` is the ID of the organization or enterprise account. You can
5 | # get the ID of an organization or enterprise account by executing either of
6 | # the following queries and referring to the value from `owner_id` field:
7 | #
8 | # - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql
9 | # - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql
10 |
11 | mutation EnableAllowListForIpsOnly {
12 | updateIpAllowListEnabledSetting(
13 | input: { ownerId: "OWNER_ID", settingValue: ENABLED }
14 | ) {
15 | clientMutationId
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/graphql/queries/ip-allow-list-enable.graphql:
--------------------------------------------------------------------------------
1 | # This query is used to enable the IP allow list feature. This will apply to both IP addresses and GitHub Apps.
2 | # This can be used on both organizations and enterprise accounts.
3 | #
4 | # The `OWNER_ID` is the ID of the organization or enterprise account. You can
5 | # get the ID of an organization or enterprise account by executing either of
6 | # the following queries and referring to the value from `owner_id` field:
7 | #
8 | # - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql
9 | # - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql
10 |
11 | mutation EnableIPAllowList {
12 | updateIpAllowListEnabledSetting(
13 | input: { ownerId: "OWNER_ID", settingValue: ENABLED }
14 | ) {
15 | clientMutationId
16 | }
17 | updateIpAllowListForInstalledAppsEnabledSetting(
18 | input: { ownerId: "OWNER_ID", settingValue: ENABLED }
19 | ) {
20 | clientMutationId
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/graphql/queries/ip-allow-list-remove-ip-entry.graphql:
--------------------------------------------------------------------------------
1 | # This query is used to remove an IP allow list entry from the IP allow list.
2 | # This can be used on both organizations and enterprise accounts.
3 | #
4 | # The `IP_ENTRY_ID` is the ID of the IP allow list entry. You can
5 | # get the ID for this by executing either of the following queries
6 | # and referring to the value from `ip_allow_list_entry_id` field:
7 | #
8 | # - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql
9 | # - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql
10 |
11 | mutation DeleteIPAddressFromIPAllowList {
12 | deleteIpAllowListEntry(input: { ipAllowListEntryId: "IP_ENTRY_ID" }) {
13 | clientMutationId
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/graphql/queries/issue-add-comment.graphql:
--------------------------------------------------------------------------------
1 | # Get ISSUE_ID from graphql/queries/repos-get-last-issue-comment.graphql
2 |
3 | mutation {
4 | addComment (
5 | input: {
6 | body: "Added by GraphQL",
7 | subjectId:"ISSUE_ID"
8 | })
9 |
10 | {
11 | clientMutationId
12 | }
13 | }
--------------------------------------------------------------------------------
/graphql/queries/issue-search-for-issue-or-bug-requests.graphql:
--------------------------------------------------------------------------------
1 | # This query accepts a variable containing the search syntax that can be learned at:
2 | # https://docs.github.com/en/github/searching-for-information-on-github/understanding-the-search-syntax
3 | #
4 | # Then will return any Issues & any associated PRs or Issues that reference the parent issue
5 | # Useful for finding a 'paper trail' of any particular feature requests or bug fixes
6 | #
7 |
8 | query findFeedbackTrail($searchCriteria: String!) {
9 | search(first: 20, type: ISSUE, query: $searchCriteria) {
10 | edges {
11 | node {
12 | __typename
13 | ... on Issue {
14 | number
15 | title
16 | repository {
17 | name
18 | }
19 | timelineItems(first: 50, itemTypes: CROSS_REFERENCED_EVENT) {
20 | nodes {
21 | ... on CrossReferencedEvent {
22 | source {
23 | __typename
24 | # Show any PRs associated with the Issue
25 | ... on PullRequest {
26 | title
27 | number
28 | files(first: 100) {
29 | nodes {
30 | path
31 | }
32 | }
33 | }
34 | # Show any Issues referencing the returned Issue
35 | ... on Issue {
36 | title
37 | number
38 | url
39 | }
40 | }
41 | }
42 | }
43 | }
44 | }
45 | }
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/graphql/queries/org-audit-log-api-example.graphql:
--------------------------------------------------------------------------------
1 | # In order for this to work, you need to add a Header: "Accept" : "application/vnd.github.audit-log-preview+json"
2 | # When querying an enterprise instance via GraphQL, the endpoint will follow the syntax: “https:///api/graphql" - ex;"GRAPHQL_ENDPOINT": “https://34.208.232.154/api/graphql"
3 |
4 | query {
5 | organization(login: "ORG_NAME") {
6 | auditLog(first: 50) {
7 | edges {
8 | node {
9 | ... on RepositoryAuditEntryData {
10 | repository {
11 | name
12 | }
13 | }
14 | ... on OrganizationAuditEntryData {
15 | organization {
16 | name
17 | }
18 | }
19 |
20 | ... on TeamAuditEntryData {
21 | teamName
22 | }
23 |
24 | ... on EnterpriseAuditEntryData {
25 | enterpriseUrl
26 | }
27 |
28 | ... on OauthApplicationAuditEntryData {
29 | oauthApplicationName
30 | }
31 |
32 | ... on AuditEntry {
33 | actorResourcePath
34 | action
35 | actorIp
36 | actorLogin
37 | createdAt
38 | actorLocation {
39 | countryCode
40 | country
41 | regionCode
42 | region
43 | city
44 | }
45 | }
46 | }
47 | cursor
48 | }
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/graphql/queries/org-branches-and-commits-by-repository.graphql:
--------------------------------------------------------------------------------
1 | query getCommitsByBranchByRepo {
2 | organization(login: "ORG_NAME") {
3 | name
4 | repository(name: "REPO_NAME") {
5 | name
6 | refs(refPrefix: "refs/heads/", first: 10) {
7 | nodes {
8 | id
9 | name
10 | target {
11 | ... on Commit {
12 | history(first: 100) {
13 | nodes {
14 | messageHeadline
15 | committedDate
16 | author {
17 | name
18 | email
19 | }
20 | }
21 | pageInfo {
22 | hasNextPage
23 | endCursor
24 | }
25 | }
26 | }
27 | }
28 | }
29 | pageInfo {
30 | hasNextPage
31 | endCursor
32 | }
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/graphql/queries/org-get-ip-allow-list.graphql:
--------------------------------------------------------------------------------
1 | # Grab current IP allow list settings for an organization.
2 | # This includes:
3 | # - The IP allow list entries
4 | # - The IP allow list enabled setting
5 | # - The IP allow list for GitHub Apps enabled setting
6 |
7 | query GetOrganizationIPAllowList {
8 | organization(login: "ORG_NAME") {
9 | owner_id: id
10 | organization_slug: login
11 | is_ip_allow_list_enabled: ipAllowListEnabledSetting
12 | is_ip_allow_list_for_github_apps_enabled: ipAllowListForInstalledAppsEnabledSetting
13 | ipAllowListEntries(first: 100) {
14 | totalCount
15 | nodes {
16 | ip_allow_list_entry_id: id
17 | ip_allow_list_entry_name: name
18 | ip_allow_list_entry_ip_address: allowListValue
19 | ip_allow_list_entry_created: createdAt
20 | is_ip_allow_list_entry_active: isActive
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/graphql/queries/org-list-outside-collaborators-by-repo.graphql:
--------------------------------------------------------------------------------
1 | query( $cursor: String) {
2 | organization(login: "ORG_NAME") {
3 | url
4 | login
5 | repositories(first: 100, after: $cursor) {
6 | pageInfo {
7 | endCursor
8 | hasNextPage
9 | }
10 | nodes {
11 | name
12 | collaborators(affiliation: OUTSIDE, first: 100) {
13 |
14 | nodes {
15 | url
16 | login
17 | }
18 | edges {
19 | permission
20 | }
21 | }
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/graphql/queries/org-members-by-team.graphql:
--------------------------------------------------------------------------------
1 | query getMembersByTeam {
2 | organization(login: "ORG_NAME") {
3 | id
4 | name
5 | teams(first: 1, query: "TEAM_NAME") {
6 | edges {
7 | node {
8 | id
9 | name
10 | members(first: 100) {
11 | edges {
12 | node {
13 | id: databaseId
14 | name
15 | }
16 | }
17 | pageInfo {
18 | endCursor #use this value to paginate through teams with more than 100 members
19 | }
20 | }
21 | }
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/graphql/queries/org-members-commit-msgs.graphql:
--------------------------------------------------------------------------------
1 | query {
2 | organization(login: "ORG_NAME") {
3 | login
4 | name
5 | members(first: 100) {
6 | edges {
7 | node {
8 | login
9 | location
10 | }
11 | }
12 | edges {
13 | node {
14 | commitComments(first: 3) {
15 | edges {
16 | node {
17 | id
18 | body
19 | }
20 | }
21 | }
22 | }
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/graphql/queries/org-members-with-role.graphql:
--------------------------------------------------------------------------------
1 | query {
2 | organization(login: "ORG_NAME") {
3 | login
4 | name
5 | membersWithRole(first: 100) {
6 | edges {
7 | node {
8 | login
9 | location
10 | }
11 | }
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/graphql/queries/org-members.graphql:
--------------------------------------------------------------------------------
1 | query {
2 | organization(login: "ORG_NAME") {
3 | login
4 | name
5 | members(first: 100) {
6 | edges {
7 | node {
8 | login
9 | location
10 | }
11 | }
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/graphql/queries/org-pr-merged-info-by-repository.graphql:
--------------------------------------------------------------------------------
1 | query getRepoMergedPRDetails {
2 | repository(owner: "ORG_NAME, name: "REPO_NAME") {
3 | pullRequests(first: 100, states: MERGED) {
4 | pageInfo {
5 | endCursor #use this value in the pullRequests argument list
6 | #to paginate to the next page using the `after:` argument.
7 | #Use the `before:` argument with this value to specify the previous page
8 | }
9 | edges {
10 | node {
11 | mergedFrom: headRefName
12 | mergedTo: baseRefName
13 | labels(first: 10) {
14 | nodes {
15 | name
16 | }
17 | }
18 | mergeCommit {
19 | message
20 | author {
21 | name
22 | email
23 | }
24 | additions
25 | deletions
26 | }
27 | }
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/graphql/queries/org-repos-fragment-2.graphql:
--------------------------------------------------------------------------------
1 | query {
2 | organization(login: "ORG_NAME") {
3 | ...orgFrag
4 | repositories {
5 | ...repoFrag
6 | }
7 | }
8 | }
9 |
10 | fragment repoFrag on RepositoryConnection {
11 | totalCount
12 | totalDiskUsage
13 | }
14 |
15 | fragment orgFrag on Organization{
16 | login
17 | name
18 | }
--------------------------------------------------------------------------------
/graphql/queries/org-repos-fragment-directive-2.graphql:
--------------------------------------------------------------------------------
1 | query orgInfo($showRepoInfo: Boolean!) {
2 | organization(login: "ORG_NAME") {
3 | ...orgFrag
4 | }
5 | }
6 |
7 |
8 | fragment orgFrag on Organization {
9 | login
10 | name
11 | repositories @include(if: $showRepoInfo) {
12 | totalCount
13 | totalDiskUsage
14 | }
15 | }
16 |
17 | variables {
18 | "showRepoInfo": true
19 | }
--------------------------------------------------------------------------------
/graphql/queries/org-repos-fragment-directive.graphql:
--------------------------------------------------------------------------------
1 | query orgInfo($showRepoInfo: Boolean!) {
2 | organization(login: "ORG_NAME") {
3 | login
4 | name
5 | repositories @include(if: $showRepoInfo) {
6 | ...repoFrag
7 | }
8 | }
9 | }
10 |
11 | fragment repoFrag on RepositoryConnection {
12 | totalCount
13 | totalDiskUsage
14 | }
15 |
16 | variables {
17 | "showRepoInfo": true
18 | }
--------------------------------------------------------------------------------
/graphql/queries/org-repos-fragment.graphql:
--------------------------------------------------------------------------------
1 | query {
2 | organization(login: "ORG_NAME") {
3 | repositories {
4 | ...repoFrag
5 | }
6 | }
7 | }
8 |
9 | fragment repoFrag on RepositoryConnection {
10 | totalCount
11 | totalDiskUsage
12 | }
13 |
--------------------------------------------------------------------------------
/graphql/queries/org-saml-identities-filtered-by-nameid-username.graphql:
--------------------------------------------------------------------------------
1 | # You will need to replace and with the actual GitHub organization name and the SAML `NameID` value that you're searching stored external identities for in the GitHub organization.
2 | # For GitHub Enterprise Cloud organizations that have SAML configured at the organization level, this will query the stored SAML `nameId` and SCIM `userName` external identity values in the GitHub organization, and if one is found that matches the value specified for ``, it will print out the SAML `nameId` and GitHub username for that stored external identity.
3 |
4 | # Note that the query below will not tell you if the GitHub username/account associated with this linked identity is still a member of the organization. Organization owners can navigate to the Organization > People > Members UI and search for the user to determine this.
5 |
6 | # This query will not print out a user username (`login`) value if there is not a GitHub user account linked to this SAML identity.
7 | # Pagination shouldn't be needed since there shouldn't be multiple entries in the organization that have the same SAML `NameID` or SCIM `userName`. However, for more information on pagination. There is also an example of pagination in simple-pagination-example.graphql.
8 |
9 | query OrganizationIdentitiesBySAMLNameID {
10 | organization(login: "") {
11 | samlIdentityProvider {
12 | externalIdentities(userName:"", first: 25) {
13 | edges {
14 | node {
15 | samlIdentity {
16 | nameId
17 | }
18 | user {
19 | login
20 | }
21 | }
22 | }
23 | pageInfo {
24 | endCursor
25 | }
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/graphql/queries/org-saml-identities.graphql:
--------------------------------------------------------------------------------
1 | # For GitHub Enterprise Cloud organizations that have SAML configured at the organization level, this query will print out a list of the first 100 SAML identities (specifically the `nameid` attribute value in these SAML identities) in the organization and the GitHub username linked to them.
2 | # This query can be used to see which users in a GitHub Enterprise Cloud organization have a linked SAML identity.
3 | # This query will not print out a user username (`login`) value if there is not a GitHub user account linked to this SAML identity.
4 | # If there are a large number of identities/users (greater than 100), pagination will need to be used. See https://graphql.org/learn/pagination/ for details on pagination. There is an example of pagination in simple-pagination-example.graphql.
5 |
6 |
7 | query OrgSAMLidentities {
8 | organization(login: "ORG_NAME") {
9 | samlIdentityProvider {
10 | externalIdentities(first: 100) {
11 | edges {
12 | node {
13 | samlIdentity {
14 | nameId
15 | }
16 | user {
17 | login
18 | }
19 | }
20 | }
21 | pageInfo {
22 | endCursor
23 | }
24 | }
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/graphql/queries/org-scim-identities.graphql:
--------------------------------------------------------------------------------
1 | # For GitHub Enterprise Cloud organizations that have SAML and SCIM provisioning configured at the organization level, this query will print out a list of the first 100 SCIM identities (specifically the `username` attribute value in these SCIM identities) in the organization.
2 | # The query will also print out the linked GitHub username, if the SCIM identity is linked to a user. A SCIM identity can be unlinked if a user has not logged in with their GitHub.com user account, accepted the invitation and authenticated via SAML to link their SAML/SCIM identity.
3 | # This query will not print out a SCIM identity (`username` attribute) for members if an organization is not using SCIM provisioning, or if a user does not have a linked SCIM identity.
4 |
5 |
6 | query ($orgName: String!) {
7 | organization(login: $orgName) {
8 | samlIdentityProvider {
9 | ssoUrl
10 | externalIdentities(first: 100) {
11 | edges {
12 | node {
13 | user {
14 | login
15 | }
16 | scimIdentity {
17 | username
18 | }
19 | }
20 | }
21 | }
22 | }
23 | }
24 | }
25 |
26 | variables {
27 | "orgName": "ORG_NAME"
28 | }
--------------------------------------------------------------------------------
/graphql/queries/org-with-alias.graphql:
--------------------------------------------------------------------------------
1 | {
2 | orgGithub: organization(login: "github") {
3 | ...orgFrag
4 | members(first: 1) {
5 | edges {
6 | node {
7 | login
8 | location
9 | }
10 | }
11 | }
12 | }
13 | orgBidness: organization(login: "microsoft") {
14 | ...orgFrag
15 | members(first: 1) {
16 | ...memFrag
17 | }
18 | }
19 | }
20 |
21 | fragment memFrag on UserConnection {
22 | edges {
23 | node {
24 | login
25 | location
26 |
27 | }
28 | }
29 | }
30 |
31 | fragment orgFrag on Organization
32 | {
33 | login
34 | name
35 | }
36 |
37 |
38 |
--------------------------------------------------------------------------------
/graphql/queries/org-with-variables.graphql:
--------------------------------------------------------------------------------
1 | query getOrg($orgName:String!) {
2 | organization(login: $orgName) {
3 | login
4 | name
5 | membersWithRole(first: 100) {
6 | edges {
7 | node {
8 | login
9 | location
10 | }
11 | }
12 | }
13 | }
14 | }
15 |
16 | variables {
17 | "orgName": "ORG_NAME"
18 | }
19 |
--------------------------------------------------------------------------------
/graphql/queries/repo-get-all-branches.graphql:
--------------------------------------------------------------------------------
1 | query getExistingRepoBranches {
2 | organization(login: "ORG_NAME") {
3 | repository(name: "REPO_NAME") {
4 | id
5 | name
6 | refs(refPrefix: "refs/heads/", first: 10) {
7 | edges {
8 | node {
9 | branchName:name
10 | }
11 | }
12 | pageInfo {
13 | endCursor #use this value to paginate through repos with more than 100 branches
14 | }
15 | }
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/graphql/queries/repos-get-last-issue-comment.graphql:
--------------------------------------------------------------------------------
1 | query getRepoIssue {
2 | repository(owner: "ORG_NAME", name: "REPO_NAME") {
3 | issues(last: 1) {
4 | edges {
5 | node {
6 | number
7 | id
8 | body
9 | }
10 | }
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/graphql/queries/repositories_with_stargazers.graphql:
--------------------------------------------------------------------------------
1 | query {
2 | viewer {
3 | repositories(last: 30) {
4 | edges {
5 | node {
6 | owner {
7 | login
8 | }
9 | name
10 | stargazers(first: 5) {
11 | totalCount
12 | edges {
13 | node {
14 | login
15 | }
16 | }
17 | }
18 | }
19 | }
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/graphql/queries/repository_overview.graphql:
--------------------------------------------------------------------------------
1 | query {
2 | repositoryOwner(login: "OWNER_LOGIN") {
3 | repository(name: "REPO_NAME") {
4 | description
5 | hasWikiEnabled
6 | issues(states: OPEN) {
7 | totalCount
8 | }
9 | pullRequests(states: OPEN) {
10 | totalCount
11 | }
12 | stargazers {
13 | totalCount
14 | }
15 | forks {
16 | totalCount
17 | }
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/graphql/queries/simple-pagination-example.graphql:
--------------------------------------------------------------------------------
1 | # Here is a simple query that can be easily paginated with the gh clientMutationId
2 |
3 | query($orgName: String!, $endCursor: String) {
4 | organization(login: $orgName) {
5 | repositories(first: 10, after: $endCursor) {
6 | nodes {
7 | name
8 | databaseId
9 | id
10 | owner {
11 | login
12 | }
13 | }
14 | pageInfo {
15 | endCursor
16 | hasNextPage
17 | }
18 | }
19 | }
20 | }
21 |
22 | # To run it with pagination, use the following gh cli command and pass in your organization as orgName
23 | # Note that we do not need to specify the endCursor variable
24 | # For paginating through multiple objects, custom logic is required to pass in each endCursor into the query
25 |
26 | gh api graphql --paginate -F owner="orgName" -f query='
27 | query($orgName: String!, $endCursor: String) {
28 | organization(login: $orgName) {
29 | repositories(first: 50, after: $endCursor) {
30 | nodes {
31 | name
32 | databaseId
33 | id
34 | owner {
35 | login
36 | }
37 | }
38 | pageInfo {
39 | endCursor
40 | hasNextPage
41 | }
42 | }
43 | }
44 | }
45 | '
--------------------------------------------------------------------------------
/graphql/queries/viewer.graphql:
--------------------------------------------------------------------------------
1 | query {
2 | viewer {
3 | login
4 | }
5 | }
--------------------------------------------------------------------------------
/hooks/jenkins/jira-issue-validator/jira-issue-validator.Jenkinsfile:
--------------------------------------------------------------------------------
1 | node {
2 | properties([
3 | [$class: 'BuildDiscarderProperty',
4 | strategy: [$class: 'LogRotator',
5 | artifactDaysToKeepStr: '',
6 | artifactNumToKeepStr: '',
7 | daysToKeepStr: '',
8 | numToKeepStr: '5']
9 | ]
10 | ])
11 | stage('Validate JIRA Issue') {
12 | //echo sh(returnStdout: true, script: 'env')
13 | // Get the issue number from the PR Title
14 | def prTitleJira = sh(
15 | script: "echo \${GITHUB_PR_TITLE}|awk {'print \$1'}",
16 | returnStdout: true)
17 |
18 | // Get the issue number from the PR Body
19 | def prBodyJira = sh(
20 | script: "echo \${GITHUB_PR_BODY}|awk {'print \$1'}",
21 | returnStdout: true)
22 |
23 | // Convert the discovered issue to a string
24 | def prIssue = prBodyJira.trim()
25 |
26 | // Validate that the issue exists in JIRA
27 | def issue = jiraGetIssue (
28 | site: "JIRA",
29 | idOrKey: "${prIssue}")
30 |
31 | // Validate the state of the ticket in JIRA
32 | def transitions = jiraGetIssueTransitions (
33 | site: "JIRA",
34 | idOrKey: "${prIssue}")
35 |
36 | // Create a variable from the issue state
37 | def statusId = issue.data.fields.status.statusCategory.id.toString()
38 | def statusName = issue.data.fields.status.statusCategory.name.toString()
39 |
40 | // Validate that it's in the state that we want... in this case, 4 = 'In Progress'
41 | if (statusId == '4') {
42 | setGitHubPullRequestStatus (
43 | context: "",
44 | message: "${prIssue} is in the correct status",
45 | state: "SUCCESS")
46 | } else {
47 | setGitHubPullRequestStatus (
48 | context: "",
49 | message: "${prIssue} is not properly prepared in JIRA. Please place it in the current sprint and begin working on it",
50 | state: "FAILURE")
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/hooks/jenkins/jira-workflow/.github/jira-workflow.yml:
--------------------------------------------------------------------------------
1 | project:
2 | - name: GitHub-Demo
3 | org: GitHub-Demo
4 | repos:
5 | - sample-core
6 | - sample-api
7 | - sample-ui
8 |
--------------------------------------------------------------------------------
/hooks/python/configuring-your-server/requirements.txt:
--------------------------------------------------------------------------------
1 | flask==2.3.2
--------------------------------------------------------------------------------
/hooks/python/configuring-your-server/server.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | from flask import Flask, request
3 |
4 | app = Flask(__name__)
5 |
6 | # Change ngrok listening port accordingly
7 | # ./ngrok http 5000
8 |
9 |
10 | @app.route("/payload", methods=['POST'])
11 | def payload():
12 | print('I got some JSON: {}'.format(request.json))
13 | return 'ok'
14 |
--------------------------------------------------------------------------------
/hooks/python/flask-github-webhooks/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:2.7
2 | LABEL version="1.0"
3 | LABEL description="Flask-based webhook receiver"
4 |
5 | WORKDIR /app
6 |
7 | COPY webhooks.py /app/webhooks.py
8 | COPY config.json.sample /app/config.json
9 | COPY requirements.txt /app/requirements.txt
10 | COPY hooks /app/hooks
11 | RUN pip install -r requirements.txt
12 |
13 | EXPOSE 5000
14 | CMD ["python", "webhooks.py"]
15 |
--------------------------------------------------------------------------------
/hooks/python/flask-github-webhooks/config.json.sample:
--------------------------------------------------------------------------------
1 | {
2 | "github_ips_only": true,
3 | "enforce_secret": "",
4 | "return_scripts_info": true
5 | }
--------------------------------------------------------------------------------
/hooks/python/flask-github-webhooks/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask
2 | ipaddress
3 | requests
4 | pyOpenSSL==17.5.0
--------------------------------------------------------------------------------
/hooks/ruby/configuring-your-server/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "json", "~> 2.3"
4 | gem "sinatra", "~> 2.2.3"
5 |
--------------------------------------------------------------------------------
/hooks/ruby/configuring-your-server/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | json (2.3.0)
5 | mustermann (2.0.2)
6 | ruby2_keywords (~> 0.0.1)
7 | rack (2.2.8.1)
8 | rack-protection (2.2.3)
9 | rack
10 | ruby2_keywords (0.0.5)
11 | sinatra (2.2.3)
12 | mustermann (~> 2.0)
13 | rack (~> 2.2)
14 | rack-protection (= 2.2.3)
15 | tilt (~> 2.0)
16 | tilt (2.1.0)
17 |
18 | PLATFORMS
19 | ruby
20 |
21 | DEPENDENCIES
22 | json (~> 2.3)
23 | sinatra (~> 2.2.3)
24 |
25 | BUNDLED WITH
26 | 1.11.2
27 |
--------------------------------------------------------------------------------
/hooks/ruby/configuring-your-server/server.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra'
2 | require 'json'
3 |
4 | post '/payload' do
5 | push = JSON.parse(request.body.read)
6 | puts "I got some JSON: #{push.inspect}"
7 | end
8 |
--------------------------------------------------------------------------------
/hooks/ruby/delete-repository-event/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "octokit"
4 | gem "sinatra"
5 |
--------------------------------------------------------------------------------
/hooks/ruby/delete-repository-event/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | addressable (2.8.0)
5 | public_suffix (>= 2.0.2, < 5.0)
6 | faraday (1.5.1)
7 | faraday-em_http (~> 1.0)
8 | faraday-em_synchrony (~> 1.0)
9 | faraday-excon (~> 1.1)
10 | faraday-httpclient (~> 1.0.1)
11 | faraday-net_http (~> 1.0)
12 | faraday-net_http_persistent (~> 1.1)
13 | faraday-patron (~> 1.0)
14 | multipart-post (>= 1.2, < 3)
15 | ruby2_keywords (>= 0.0.4)
16 | faraday-em_http (1.0.0)
17 | faraday-em_synchrony (1.0.0)
18 | faraday-excon (1.1.0)
19 | faraday-httpclient (1.0.1)
20 | faraday-net_http (1.0.1)
21 | faraday-net_http_persistent (1.2.0)
22 | faraday-patron (1.0.0)
23 | multipart-post (2.1.1)
24 | mustermann (2.0.2)
25 | ruby2_keywords (~> 0.0.1)
26 | octokit (4.6.2)
27 | sawyer (~> 0.8.0, >= 0.5.3)
28 | public_suffix (4.0.6)
29 | rack (2.2.8.1)
30 | rack-protection (2.2.3)
31 | rack
32 | ruby2_keywords (0.0.4)
33 | sawyer (0.8.2)
34 | addressable (>= 2.3.5)
35 | faraday (> 0.8, < 2.0)
36 | sinatra (2.2.3)
37 | mustermann (~> 2.0)
38 | rack (~> 2.2)
39 | rack-protection (= 2.2.3)
40 | tilt (~> 2.0)
41 | tilt (2.0.11)
42 |
43 | PLATFORMS
44 | ruby
45 |
46 | DEPENDENCIES
47 | octokit
48 | sinatra
49 |
50 | BUNDLED WITH
51 | 1.14.6
52 |
--------------------------------------------------------------------------------
/hooks/ruby/delete-repository-event/README.md:
--------------------------------------------------------------------------------
1 | # :x: Delete Repository Event
2 |
3 | ### :dart: Purpose
4 |
5 | This Ruby server:
6 |
7 | 1. Listens for when a [repository is deleted](https://help.github.com/enterprise/user/articles/deleting-a-repository/) using the [`repository`](https://developer.github.com/enterprise/v3/activity/events/types/#repositoryevent) event and `deleted` action.
8 |
9 | 2. Creates an issue in `GITHUB_NOTIFICATION_REPOSITORY` as a notification and includes:
10 |
11 | - a link to restore the repository
12 | - the delete repository payload
13 |
14 | ### :gear: Configuration
15 |
16 | 1. See the [webhooks](https://developer.github.com/webhooks/) documentation for information on how to [create webhooks](https://developer.github.com/webhooks/creating/) and [configure your server](https://developer.github.com/webhooks/configuring/).
17 |
18 | 2. Set the following required environment variables:
19 |
20 | - `GITHUB_HOST` - the domain of the GitHub Enterprise instance. e.g. github.example.com
21 | - `GITHUB_API_TOKEN` - a [Personal Access Token](https://help.github.com/enterprise/user/articles/creating-a-personal-access-token-for-the-command-line/) that has the ability to create an issue in the notification repository
22 | - `GITHUB_NOTIFICATION_REPOSITORY` - the repository in which to create the notification issue. e.g. github.example.com/administrative-notifications. Should be in the form of `:owner/:repository`.
23 |
--------------------------------------------------------------------------------
/hooks/ruby/dismiss-review-server/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "json", "~> 2.3"
4 | gem "rest-client"
5 | gem "sinatra", "~> 2.2.3"
6 |
--------------------------------------------------------------------------------
/hooks/ruby/dismiss-review-server/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | domain_name (0.5.20161129)
5 | unf (>= 0.0.5, < 1.0.0)
6 | http-cookie (1.0.3)
7 | domain_name (~> 0.5)
8 | json (2.3.0)
9 | mime-types (3.1)
10 | mime-types-data (~> 3.2015)
11 | mime-types-data (3.2016.0521)
12 | mustermann (2.0.2)
13 | ruby2_keywords (~> 0.0.1)
14 | netrc (0.11.0)
15 | rack (2.2.8.1)
16 | rack-protection (2.2.3)
17 | rack
18 | rest-client (2.0.1)
19 | http-cookie (>= 1.0.2, < 2.0)
20 | mime-types (>= 1.16, < 4.0)
21 | netrc (~> 0.8)
22 | ruby2_keywords (0.0.5)
23 | sinatra (2.2.3)
24 | mustermann (~> 2.0)
25 | rack (~> 2.2)
26 | rack-protection (= 2.2.3)
27 | tilt (~> 2.0)
28 | tilt (2.1.0)
29 | unf (0.1.4)
30 | unf_ext
31 | unf_ext (0.0.7.2)
32 |
33 | PLATFORMS
34 | ruby
35 |
36 | DEPENDENCIES
37 | json (~> 2.3)
38 | rest-client
39 | sinatra (~> 2.2.3)
40 |
41 | BUNDLED WITH
42 | 1.14.4
43 |
--------------------------------------------------------------------------------
/hooks/ruby/dismiss-review-server/README.md:
--------------------------------------------------------------------------------
1 | # Dismiss Review Server
2 |
3 | A ruby server that listens for GitHub webhook `push` events, based on [the documentation](https://developer.github.com/webhooks/configuring/#writing-the-server), that will dismiss any `APPROVED` [Pull Request Reviews](https://help.github.com/articles/about-pull-request-reviews/).
4 |
5 | ## Configuration
6 |
7 | Follow the [instructions](https://developer.github.com/webhooks/) of setting up a Webhook on GitHub to this server. Set the following environment variables:
8 | - GITHUB_API_TOKEN - (Required) [OAuth token](https://developer.github.com/v3/#authentication) with write access to the repository.
9 | - SECRET_TOKEN - (Optional) [Shared secret token](https://developer.github.com/webhooks/securing/#validating-payloads-from-github) between the GitHub Webhook and this application. Leave this unset if not using a secret token.
10 |
--------------------------------------------------------------------------------
/pre-receive-hooks/always_reject.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | #
4 | # Pre-receive hook that will reject all pushes
5 | # Useful for locking a repository
6 | #
7 | # More details on pre-receive hooks and how to apply them can be found on
8 | # https://help.github.com/enterprise/admin/guides/developer-workflow/managing-pre-receive-hooks-on-the-github-enterprise-appliance/
9 | #
10 |
11 | echo "You are attempting to push to the ${GITHUB_REPO_NAME} repository which has been made read-only"
12 | echo "Access denied, push blocked. Please contact the repository administrator."
13 |
14 | exit 1
15 |
--------------------------------------------------------------------------------
/pre-receive-hooks/block_branch_names.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | #
4 | # Pre-receive hook that will block any new commits that their names contain
5 | # other than lower-case alphabet characters (a-z).
6 | #
7 | # More details on pre-receive hooks and how to apply them can be found on
8 | # https://help.github.com/enterprise/admin/guides/developer-workflow/managing-pre-receive-hooks-on-the-github-enterprise-appliance/
9 | #
10 |
11 | zero_commit="0000000000000000000000000000000000000000"
12 |
13 | # Ensure that [a-z] means only lower case ASCII characters => set LC_COLLATE to 'C'
14 | # See http://unix.stackexchange.com/questions/227070/why-does-a-z-match-lowercase-letters-in-bash
15 | # See https://www.gnu.org/software/bash/manual/bashref.html#Pattern-Matching
16 | LC_COLLATE='C'
17 |
18 | while read oldrev newrev refname; do
19 | # Only check new branches ($oldrev is zero commit), don't block tags
20 | if [[ $oldrev == $zero_commit && $refname =~ ^refs/heads/ ]]; then
21 | # Check if the branch name is lower case characters (ASCII only), '-', '_', "/" or numbers
22 | if [[ ! $refname =~ ^refs/heads/[-a-z0-9_/]+$ ]]; then
23 | echo "Blocking creation of new branch $refname because it must only contain lower-case alpha-numeric characters, '-', '_' or '/'."
24 | exit 1
25 | fi
26 | fi
27 | done
28 | exit 0
29 |
--------------------------------------------------------------------------------
/pre-receive-hooks/block_branch_names_not_starting_with_userID.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | #
4 | # Pre-receive hook that will block any new commits that their names do not being with the userID
5 | #
6 | # More details on pre-receive hooks and how to apply them can be found on
7 | # https://help.github.com/enterprise/admin/guides/developer-workflow/managing-pre-receive-hooks-on-the-github-enterprise-appliance/
8 | #
9 |
10 | zero_commit="0000000000000000000000000000000000000000"
11 |
12 | while read oldrev newrev refname; do
13 | # Only check new branches ($oldrev is zero commit), don't block tags
14 | if [[ $oldrev == $zero_commit && $refname =~ ^refs/heads/ ]]; then
15 | # Check if the branch name begins with the userID - NOTE THIS IS CASE SENSITIVE AT THE MOMENT
16 | if [[ ! $refname =~ ^refs/heads/$GITHUB_USER_LOGIN ]]; then
17 | echo "Hi, $GITHUB_USER_LOGIN Blocking creation of new branch $refname"
18 | echo "because it does not start with your username ($GITHUB_USER_LOGIN)"
19 | echo "as outlined in the branch naming policy guide"
20 | exit 1
21 | fi
22 | fi
23 | done
24 | # The following echoes may be enabled if you like. They are a purely a cosmetic
25 | # demo item to show that it does not have to be just error messages passed back.
26 | # echo "Hi $GITHUB_USER_LOGIN, allowing creation of new branch $refname"
27 | # echo "because it does start with your username ($GITHUB_USER_LOGIN)"
28 | # echo "as outlined in the branch naming policy guide - thank you!"
29 | exit 0
30 |
--------------------------------------------------------------------------------
/pre-receive-hooks/block_file_extensions.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | #
4 | # Pre-receive hook that will block any new commits that contain files ending
5 | # with .gz, .zip or .tgz
6 | #
7 | # More details on pre-receive hooks and how to apply them can be found on
8 | # https://help.github.com/enterprise/admin/guides/developer-workflow/managing-pre-receive-hooks-on-the-github-enterprise-appliance/
9 | #
10 |
11 | zero_commit="0000000000000000000000000000000000000000"
12 |
13 | # Do not traverse over commits that are already in the repository
14 | # (e.g. in a different branch)
15 | # This prevents funny errors if pre-receive hooks got enabled after some
16 | # commits got already in and then somebody tries to create a new branch
17 | # If this is unwanted behavior, just set the variable to empty
18 | excludeExisting="--not --all"
19 |
20 | while read oldrev newrev refname; do
21 | # echo "payload"
22 | echo $refname $oldrev $newrev
23 |
24 | # branch or tag get deleted
25 | if [ "$newrev" = "$zero_commit" ]; then
26 | continue
27 | fi
28 |
29 | # Check for new branch or tag
30 | if [ "$oldrev" = "$zero_commit" ]; then
31 | span=`git rev-list $newrev $excludeExisting`
32 | else
33 | span=`git rev-list $oldrev..$newrev $excludeExisting`
34 | fi
35 |
36 | for COMMIT in $span;
37 | do
38 | for FILE in `git log -1 --name-only --pretty=format:'' $COMMIT`;
39 | do
40 | case $FILE in
41 | *.zip|*.gz|*.tgz )
42 | echo "Hello there! We have restricted committing that filetype. Please see Dave in IT to discuss alternatives."
43 | exit 1
44 | ;;
45 | esac
46 | done
47 | done
48 | done
49 | exit 0
50 |
--------------------------------------------------------------------------------
/pre-receive-hooks/block_ip_range.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | #
4 | # Pre-receive hook that will reject all pushes received from IPv4 addresses
5 | # between `IP_LOW` and `IP_HIGH`
6 | #
7 | # More details on pre-receive hooks and how to apply them can be found on
8 | # https://help.github.com/enterprise/admin/guides/developer-workflow/managing-pre-receive-hooks-on-the-github-enterprise-appliance/
9 | #
10 | # NOTE: Use at your own risk!
11 |
12 | function ip2dec {
13 | # see http://stackoverflow.com/a/10768196/1525223
14 | local a b c d ip=$@
15 | IFS=. read -r a b c d <<< "$ip"
16 | echo "$((a * 256 ** 3 + b * 256 ** 2 + c * 256 + d))"
17 | }
18 |
19 | # define lower IPv4 limit
20 | IP_LOW="192.168.0.0"
21 | IP_LOW_DEC=$(ip2dec "${IP_LOW}")
22 |
23 | # define upper IPv4 limit
24 | IP_HIGH="192.168.255.255"
25 | IP_HIGH_DEC=$(ip2dec "${IP_HIGH}")
26 |
27 | # get IPv4 from pre-receive hook variable
28 | IP_IN="${GITHUB_USER_IP}"
29 | IP_DEC=$(ip2dec "${IP_IN}")
30 |
31 | # reject push if `IP_IN` is between `IP_LOW` and IP_HIGH
32 | if [ "${IP_DEC}" -ge "${IP_LOW_DEC}" ] && [ "${IP_DEC}" -le "${IP_HIGH_DEC}" ]; then
33 | echo "Hello there! We have restricted pushes from your IP (${IP_IN}) address. Please see Dave in IT to discuss alternatives."
34 | exit 1
35 | fi
36 |
37 | exit 0
38 |
--------------------------------------------------------------------------------
/pre-receive-hooks/block_self_merge_prs.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | #
4 | # Pre-receive hook that will reject all merge attempts
5 | # of a PR attempted by the author
6 | #
7 | # More details on pre-receive hooks and how to apply them can be found on
8 | # https://help.github.com/enterprise/admin/guides/developer-workflow/managing-pre-receive-hooks-on-the-github-enterprise-appliance/
9 | #
10 |
11 | if [[ "$GITHUB_VIA" = *"merge"* ]] && [[ "$GITHUB_PULL_REQUEST_AUTHOR_LOGIN" = "$GITHUB_USER_LOGIN" ]]; then
12 | echo "Blocking merging of your own pull request."
13 | exit 1
14 | fi
15 |
16 | exit 0
17 |
--------------------------------------------------------------------------------
/pre-receive-hooks/block_unknown_pushers.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | #
4 | # Pre-receive hook that will block any pushes / repository modifications
5 | # not performed by a user in the list (foo, bar, foobar)
6 | #
7 | # More details on pre-receive hooks and how to apply them can be found on
8 | # https://help.github.com/enterprise/admin/guides/developer-workflow/managing-pre-receive-hooks-on-the-github-enterprise-appliance/
9 | #
10 |
11 | case $GITHUB_USER_LOGIN in
12 | foo|bar|foobar) echo "User $GITHUB_USER_LOGIN is allowed to push";;
13 | *) echo "User $GITHUB_USER_LOGIN is not in the list of authorized pushers"
14 | exit 1;;
15 | esac
16 |
--------------------------------------------------------------------------------
/pre-receive-hooks/force_push_restricted_branches.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | zero_commit="0000000000000000000000000000000000000000"
4 |
5 | # This example allows force pushes for branches named scratch/* and test/*
6 | force_push_prefix="
7 | scratch
8 | test
9 | "
10 |
11 | is_force_push() {
12 | # If this is a new branch there's no history to overwrite
13 | if [[ ${oldrev} == ${zero_commit} ]]; then
14 | return 1
15 | fi
16 |
17 | if git merge-base --is-ancestor ${oldrev} ${newrev}; then
18 | return 1
19 | else
20 | return 0
21 | fi
22 | }
23 |
24 | while read -r oldrev newrev refname; do
25 | if is_force_push; then
26 | force_push_permitted=false
27 | for push_prefix in ${force_push_prefix}; do
28 | if [[ ${refname} == "refs/heads/${push_prefix}/"* ]]; then
29 | force_push_permitted=true
30 | break
31 | fi
32 | done
33 | if [[ ${force_push_permitted} == true ]]; then
34 | continue
35 | else
36 | echo "force push detected in restricted branch ${refname}"
37 | exit 1
38 | fi
39 | fi
40 | done
41 |
--------------------------------------------------------------------------------
/pre-receive-hooks/reject-commits.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Reject certain commits from being pushed to the repository
4 | #
5 | # This can be a useful pre-receive hook [1] if you rewrote the history
6 | # of a repository and you want to ensure nobody pushes the old commits
7 | # again.
8 | #
9 | # Usage: Add the commits you want to reject in the
10 | # "" below.
11 | #
12 | # [1] https://help.github.com/en/enterprise/user/articles/working-with-pre-receive-hooks
13 | #
14 | set -e
15 |
16 | zero_commit="0000000000000000000000000000000000000000"
17 | rejected_commits=$(mktemp /tmp/rejected-commits.XXXXXX)
18 | trap "rm -f $rejected_commits" EXIT
19 | cat < $rejected_commits
20 |
21 | EOF
22 |
23 | while read -r oldrev newrev refname; do
24 |
25 | # Branch or tag got deleted, ignore the push
26 | [ "$newrev" = "$zero_commit" ] && continue
27 |
28 | # Calculate range for new branch/updated branch
29 | [ "$oldrev" = "$zero_commit" ] && range="$newrev" || range="$oldrev..$newrev"
30 |
31 | # Iterate over all new hashes and try to match "rejected hashes"
32 | # Return "success" if there are no matches
33 | match=$(git rev-list "$range" --not --all \
34 | | fgrep --max-count=1 --file=$rejected_commits \
35 | ) || continue
36 |
37 | echo "ERROR:"
38 | echo "ERROR: Your push was rejected because it contained the commit"
39 | echo "ERROR: '$match' in '${refname#refs/heads/}'."
40 | echo "ERROR:"
41 | echo "ERROR: Please contact your GitHub Enterprise administrator."
42 | echo "ERROR"
43 | exit 1
44 | done
45 |
--------------------------------------------------------------------------------
/pre-receive-hooks/require-jira-issue.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Reject pushes that contain commits with messages that do not adhere
4 | # to the defined regex.
5 |
6 | # This can be a useful pre-receive hook [1] if you want to ensure every
7 | # commit is associated with a ticket ID.
8 | #
9 | # As an example this hook ensures that the commit message contains a
10 | # JIRA issue formatted as [JIRA-].
11 | #
12 | # [1] https://help.github.com/en/enterprise/user/articles/working-with-pre-receive-hooks
13 | #
14 |
15 | set -e
16 |
17 | zero_commit='0000000000000000000000000000000000000000'
18 | msg_regex='[JIRA\-[0-9]+\]'
19 |
20 | while read -r oldrev newrev refname; do
21 |
22 | # Branch or tag got deleted, ignore the push
23 | [ "$newrev" = "$zero_commit" ] && continue
24 |
25 | # Calculate range for new branch/updated branch
26 | [ "$oldrev" = "$zero_commit" ] && range="$newrev" || range="$oldrev..$newrev"
27 |
28 | for commit in $(git rev-list "$range" --not --all); do
29 | if ! git log --max-count=1 --format=%B $commit | grep -iqE "$msg_regex"; then
30 | echo "ERROR:"
31 | echo "ERROR: Your push was rejected because the commit"
32 | echo "ERROR: $commit in ${refname#refs/heads/}"
33 | echo "ERROR: is missing the JIRA Issue 'JIRA-123'."
34 | echo "ERROR:"
35 | echo "ERROR: Please fix the commit message and push again."
36 | echo "ERROR: https://help.github.com/en/articles/changing-a-commit-message"
37 | echo "ERROR"
38 | exit 1
39 | fi
40 | done
41 |
42 | done
43 |
--------------------------------------------------------------------------------
/pre-receive-hooks/restrict-master-to-cli.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # This hook restricts changes on the default branch to disallow the Web UI blob editor
4 | #
5 | DEFAULT_BRANCH=$(git symbolic-ref HEAD)
6 | while read -r oldrev newrev refname; do
7 | if [[ "${refname}" != "${DEFAULT_BRANCH:=refs/heads/master}" ]]; then
8 | continue
9 | else
10 | if [[ "${GITHUB_VIA}" = 'blob#save' ]]; then
11 | echo "Changes to the default branch must be made by cli. Web UI edits are not allowed."
12 | exit 1
13 | else
14 | continue
15 | fi
16 | fi
17 | done
18 |
--------------------------------------------------------------------------------
/pre-receive-hooks/restrict-master-to-gui-merges.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # This hook restricts changes on the default branch to those made with the GUI Pull Request Merge button, or the Pull Request Merge API.
4 | #
5 | DEFAULT_BRANCH=$(git symbolic-ref HEAD)
6 | while read -r oldrev newrev refname; do
7 | if [[ "${refname}" != "${DEFAULT_BRANCH:=refs/heads/master}" ]]; then
8 | continue
9 | else
10 | if [[ "${GITHUB_VIA}" != 'pull request merge button' && \
11 | "${GITHUB_VIA}" != 'pull request merge api' ]]; then
12 | echo "Changes to the default branch must be made by Pull Request. Direct pushes, edits, or merges are not allowed."
13 | exit 1
14 | else
15 | continue
16 | fi
17 | fi
18 | done
19 |
--------------------------------------------------------------------------------
/scripts/README.md:
--------------------------------------------------------------------------------
1 | # Git Repo Analysis Scripts
2 |
3 | Git can become slow if a repository exceeds certain thresholds ([read this for details](http://larsxschneider.github.io/2016/09/21/large-git-repos)). Use the scripts explained below to identify possible culprits in a repository. The scripts have been tested on macOS but they should run on Linux as is.
4 |
5 | _Hint:_ The scripts can run for a long time and output a lot lines. Pipe their output to a file (`./script > myfile`) for further processing.
6 |
7 | ## Large by File Size
8 | Use the [git-find-large-files](git-find-large-files) script to identity large files in your Git repository that you could move to [Git LFS](https://git-lfs.github.com/) (e.g. using [git-lfs-migrate](https://github.com/git-lfs/git-lfs/blob/master/docs/man/git-lfs-migrate.1.ronn)).
9 |
10 | Use the [git-find-lfs-extensions](git-find-lfs-extensions) script to identify certain file types that you could move to [Git LFS](https://git-lfs.github.com/).
11 |
12 | ## Large by File Count
13 | Use the [git-find-dirs-many-files](git-find-dirs-many-files) and [git-find-dirs-unwanted](git-find-dirs-unwanted) scripts to identify directories with a large number of files. These might indicate 3rd party components that could be extracted.
14 |
15 | Use the [git-find-dirs-deleted-files](git-find-dirs-deleted-files) to identify directories that have been deleted and used to contain a lot of files. If you purge all files under these directories from your history then you might be able significantly reduce the overall size of your repository.
16 |
17 |
18 |
--------------------------------------------------------------------------------
/scripts/boostrap/boot.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | pushd %~dp0
3 | "%ProgramFiles%"\Git\bin\sh.exe -c "./boot"
4 | popd
5 |
--------------------------------------------------------------------------------
/scripts/git-change-author:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Fix an invalid committer/author all commits of your repository.
4 | #
5 | # Usage:
6 | # git-change-author
7 | #
8 | # Author: Lars Schneider, https://github.com/larsxschneider
9 | #
10 |
11 | filter=$(cat <&2 echo "error: unknown option “$1”")
33 | print_help
34 | exit 1
35 | fi
36 | ;;
37 | esac
38 |
39 | # Find all ignored files
40 | files=$(git ls-files --ignored --exclude-standard)
41 |
42 | # Stop if no ignored files were found
43 | if [[ -z $files ]]
44 | then
45 | (>&2 echo "info: no ignored files in working tree or index")
46 | exit 0
47 | fi
48 |
49 | # Compute the file sizes of all these files
50 | file_sizes=$(echo "$files" | tr '\n' '\0' | xargs -0 du -sh)
51 |
52 | # Obtain the origins why these files are ignored
53 | gitignore_origins=$(echo "$files" | git check-ignore --verbose --stdin --no-index)
54 |
55 | # Merge the two lists into one
56 | command="join -1 2 -2 2 -t $'\t' -o 1.1,1.2,2.1 <(echo \"$file_sizes\") <(echo \"$gitignore_origins\")"
57 |
58 | if [[ $1 =~ ^-s|--sort-by-size$ ]]
59 | then
60 | command="$command | sort -h"
61 | fi
62 |
63 | eval "$command"
64 |
--------------------------------------------------------------------------------
/scripts/git-find-stale-branches:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Find unmerged branches that haven't been modified for more than a year.
4 | #
5 | # # Why would you do this?
6 | #
7 | # Although branches are cheap in Git, they can clutter the repository in
8 | # large quantities. Unmerged branches also might introduce large files
9 | # that are unnecessarily kept in the repository. If those branches get
10 | # deleted, than Git can cleanup those files automatically.
11 | #
12 | # Usage:
13 | # git-find-stale-branches
14 | #
15 | # Author: Lars Schneider, https://github.com/larsxschneider
16 | #
17 |
18 | [[ $(git rev-parse --is-bare-repository) == true ]] || remote=--remote
19 |
20 | git branch --list --no-merged $(git symbolic-ref --short HEAD) $remote \
21 | --sort=committerdate \
22 | --format='%(refname:short) (%(committerdate:relative))' \
23 | | grep '([[:digit:]]* year.* ago)'
24 |
--------------------------------------------------------------------------------
/scripts/git-find-utf-16-encoded-files:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Find and print files that are encoded with UTF-16
4 | #
5 | # Usage:
6 | # git-find-utf-16-encoded-files
7 | #
8 | # Author: Lars Schneider, https://github.com/larsxschneider
9 | #
10 |
11 | find . -type f -not -path "./.git/*" -exec file {} \; |
12 | grep --ignore-case utf-16
13 |
--------------------------------------------------------------------------------
/scripts/tests/t0001-git-purge-symlinks:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | out=/dev/null
4 |
5 | function test_expect_success {
6 | if ! eval "$* >$out"; then
7 | echo "FAILURE: $(basename "${BASH_SOURCE[0]}: $*")"
8 | exit 1
9 | fi
10 | }
11 |
12 | function test_expect_failure {
13 | if eval "$* >$out"; then
14 | echo "SUCCESS although FAILURE expected: $(basename "${BASH_SOURCE[0]}: $*")"
15 | exit 1
16 | fi
17 | }
18 |
19 | script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/..">/dev/null && pwd)"
20 | test_dir="$script_dir/tmp"
21 |
22 | rm -rf "$test_dir"
23 | mkdir "$test_dir"
24 | pushd "$test_dir" >/dev/null
25 |
26 | git init -q .
27 |
28 | mkdir foo
29 | echo "foo" >foo/baz
30 | git add .
31 | git commit -qm "add foo dir with file"
32 |
33 | ln -s foo bar
34 | git add .
35 | git commit -qm "add bar dir as link"
36 |
37 | rm bar
38 | mkdir bar
39 | echo "bar" >bar/baz
40 | git add .
41 | git commit -qm "remove link and make bar dir real"
42 |
43 | test_expect_success ../git-purge-files -c
44 |
45 | popd >/dev/null
46 |
47 | rm -rf "$test_dir"
48 | mkdir "$test_dir"
49 | pushd "$test_dir" >/dev/null
50 |
51 | git init -q .
52 |
53 | mkdir foo
54 | echo "foo" >foo/baz
55 | git add .
56 | git commit -qm "add foo dir with file"
57 |
58 | ln -s foo bar
59 | git add .
60 | git commit -qm "add bar dir as link"
61 |
62 | rm bar
63 | mkdir bar
64 | echo "bar" >bar/baz
65 | git add .
66 | git commit -qm "remove link and make bar dir real"
67 |
68 | # see https://public-inbox.org/git/95EF0665-9882-4707-BB6A-94182C01BE91@gmail.com/
69 | test_expect_failure ../git-purge-files -c -d
70 |
71 | popd >/dev/null
72 |
--------------------------------------------------------------------------------
/sql/audit/admin-tokens.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This pulls a list of all apps, tokens, and scopes associated with that token
3 | * as well as when it was last used, created, and updated for anything with
4 | * the `site_admin` scope.
5 | */
6 | SELECT
7 | z.id,
8 | u.login as owner_name,
9 | u.type as owner_type,
10 | a.name as app_name,
11 | z.accessed_at,
12 | z.created_at,
13 | z.updated_at,
14 | z.description,
15 | z.scopes
16 | FROM
17 | github_enterprise.oauth_authorizations z
18 | JOIN github_enterprise.users u ON
19 | z.user_id = u.id
20 | LEFT JOIN github_enterprise.oauth_applications a ON
21 | z.application_id = a.id
22 | WHERE
23 | z.scopes LIKE "%site_admin%"
--------------------------------------------------------------------------------
/sql/audit/authorizations.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This pulls a list of all apps, tokens, and scopes associated with that token
3 | * as well as when it was last used, created, and updated.
4 | */
5 | SELECT
6 | z.id,
7 | u.login as owner_name,
8 | u.type as owner_type,
9 | a.name as app_name,
10 | z.accessed_at,
11 | z.created_at,
12 | z.updated_at,
13 | z.description,
14 | z.scopes
15 | FROM
16 | github_enterprise.oauth_authorizations z
17 | JOIN github_enterprise.users u ON
18 | z.user_id = u.id
19 | LEFT JOIN github_enterprise.oauth_applications a ON
20 | z.application_id = a.id;
--------------------------------------------------------------------------------
/sql/audit/deploy-keys.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This query returns SSH deploy keys and what repo they're tied to, when last
3 | * used, etc.
4 | */
5 | SELECT
6 | d.title as key_name,
7 | d.created_at,
8 | d.updated_at,
9 | d.verified_at,
10 | d.accessed_at as last_used,
11 | length(d.key) as key_length,
12 | u.login as created_by_name,
13 | d.created_by as created_by_type,
14 | r.name as repo_name,
15 | x.login as repo_owner_name
16 | FROM
17 | github_enterprise.public_keys d
18 | LEFT JOIN github_enterprise.users u ON
19 | d.creator_id = u.id
20 | LEFT JOIN github_enterprise.repositories r ON
21 | d.repository_id = r.id
22 | LEFT JOIN (
23 | SELECT
24 | id,
25 | login,
26 | type
27 | FROM
28 | github_enterprise.users u2
29 | ) x ON
30 | x.id = r.owner_id
31 | WHERE
32 | d.repository_id IS NOT NULL;
--------------------------------------------------------------------------------
/sql/audit/github-apps.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This pulls a list of all github apps, who owns them, and when they were
3 | * created or updated.
4 | */
5 | SELECT
6 | i.id,
7 | i.bot_id,
8 | i.name as integration_name,
9 | u.login as owner,
10 | u.type,
11 | i.url,
12 | i.created_at,
13 | i.updated_at,
14 | i.public,
15 | i.slug as friendly_name,
16 | i.public
17 | FROM
18 | github_enterprise.integrations i
19 | JOIN github_enterprise.users u ON
20 | i.owner_id = u.id;
--------------------------------------------------------------------------------
/sql/audit/hooks-repos.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This brings up the list of REPOSITORY webhooks that have been active in the
3 | * past week, who owns them, and where the webhook goes.
4 | */
5 | SELECT
6 | DISTINCT h.id,
7 | u.login as creator,
8 | h.updated_at,
9 | r.name as repo_name,
10 | u.login as repo_owner,
11 | u.type as owner_type,
12 | c.value as url,
13 | MAX(l.delivered_at) as latest_delivery
14 | FROM
15 | github_enterprise.hooks h
16 | JOIN github_enterprise.hook_config_attributes c ON
17 | h.id = c.hook_id
18 | JOIN github_enterprise.users u ON
19 | h.creator_id = u.id
20 | JOIN github_enterprise.hookshot_delivery_logs l ON
21 | h.id = l.hook_id
22 | JOIN github_enterprise.repositories r ON
23 | h.installation_target_id = r.id
24 | WHERE
25 | c.key = 'url'
26 | AND h.installation_target_type = 'Repository'
27 | GROUP BY
28 | h.id
29 | ORDER BY
30 | MAX(l.delivered_at) DESC;
--------------------------------------------------------------------------------
/sql/audit/hooks-users.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This brings up the list of USER webhooks that have been active in the past
3 | * week, who owns them, and where the webhook goes.
4 | */
5 | SELECT
6 | DISTINCT h.id,
7 | u.login as creator,
8 | h.updated_at,
9 | u.login as repo_owner,
10 | u.type as owner_type,
11 | c.value as url,
12 | MAX(l.delivered_at) as latest_delivery
13 | FROM
14 | github_enterprise.hooks h
15 | JOIN github_enterprise.hook_config_attributes c ON
16 | h.id = c.hook_id
17 | JOIN github_enterprise.users u ON
18 | h.creator_id = u.id
19 | JOIN github_enterprise.hookshot_delivery_logs l ON
20 | h.id = l.hook_id
21 | WHERE
22 | c.key = 'url'
23 | AND h.installation_target_type = 'User'
24 | GROUP BY
25 | h.id
26 | ORDER BY
27 | MAX(l.delivered_at) DESC;
--------------------------------------------------------------------------------
/sql/audit/oauth-apps.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This pulls up a list of all OAuth apps and where they go, as well as when
3 | * they were last updated and what login they are associated with.
4 | */
5 | SELECT
6 | o.name,
7 | o.url,
8 | o.callback_url,
9 | o.created_at,
10 | o.updated_at,
11 | u.login,
12 | u.type
13 | FROM
14 | github_enterprise.oauth_applications o
15 | JOIN github_enterprise.users u ON
16 | o.user_id = u.id;
--------------------------------------------------------------------------------
/sql/audit/user-emails.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This pulls a list of all email addresses and the user account it is tied to
3 | * that don't match the list of domains in the WHERE clause. Add however many
4 | * "%domain.com" needed to cover your company's approved domains.
5 | *
6 | * This query should be deprecated by this issue:
7 | * https://github.com/github/roadmap/issues/204
8 | *
9 | * If you want a list of all emails, remove the WHERE clause.
10 | */
11 | SELECT
12 | u.login,
13 | e.email,
14 | u.suspended_at
15 | FROM
16 | github_enterprise.users u
17 | JOIN github_enterprise.user_emails e ON
18 | e.user_id = u.id
19 | WHERE
20 | u.gravatar_email != e.email
21 | AND e.email not like "%company.com"
22 | AND e.email not like "%.tld";
--------------------------------------------------------------------------------
/sql/audit/user-ssh-keys.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This query returns user SSH keys and when they were last used.
3 | */
4 | SELECT
5 | d.title as key_name,
6 | d.created_at,
7 | d.updated_at,
8 | d.verified_at,
9 | d.accessed_at as last_used,
10 | length(d.key) as key_length,
11 | u.login as created_by_name,
12 | d.created_by as created_by_type
13 | FROM
14 | github_enterprise.public_keys d
15 | LEFT JOIN github_enterprise.users u ON
16 | d.creator_id = u.id
17 | WHERE
18 | d.user_id IS NOT NULL;
--------------------------------------------------------------------------------
/sql/metrics/actions-summary.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This query generates a monthly summary of runtime hours, seconds waiting
3 | * in queue before dispatch, and job count for GitHub Actions usage.
4 | */
5 | SELECT
6 | month(j.completed_at) as month,
7 | year(j.completed_at) as year,
8 | round(
9 | sum(
10 | unix_timestamp(j.completed_at) - unix_timestamp(
11 | coalesce(j.started_at, j.queued_at, j.created_at)
12 | )
13 | ) / 3600
14 | ) as compute_hours,
15 | round(
16 | avg(
17 | unix_timestamp(j.started_at) - unix_timestamp(j.queued_at)
18 | )
19 | ) as seconds_queued,
20 | count(j.completed_at) as job_count
21 | FROM
22 | github_enterprise.workflow_builds j
23 | GROUP BY
24 | month,
25 | year
26 | ORDER BY
27 | year,
28 | month
--------------------------------------------------------------------------------
/sql/metrics/commit-count.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This pulls a "high score" report of all users, all commits, from all time.
3 | */
4 | SELECT
5 | u.login,
6 | SUM(commit_count)
7 | FROM
8 | github_enterprise.commit_contributions c
9 | JOIN github_enterprise.users u ON
10 | u.id = c.user_id
11 | GROUP BY
12 | user_id
13 | ORDER BY
14 | COUNT(c.user_id) DESC;
--------------------------------------------------------------------------------
/sql/metrics/commit-summary.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This query generates a monthly summary of commit activity by committed date.
3 | */
4 | SELECT
5 | month(c.committed_date) as month,
6 | year(c.committed_date) as year,
7 | sum(c.commit_count) as commits
8 | FROM
9 | github_enterprise.commit_contributions c
10 | GROUP BY
11 | month,
12 | year
13 | ORDER BY
14 | year,
15 | month
--------------------------------------------------------------------------------
/sql/metrics/count-tabs.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * These are custom tabs set by a repository owner that show up to their users.
3 | */
4 | SELECT
5 | t.anchor as name,
6 | t.url,
7 | t.created_at,
8 | t.updated_at,
9 | r.name as repo_name,
10 | u.login as owner_name,
11 | u.type as owner_type
12 | FROM
13 | github_enterprise.tabs t
14 | JOIN github_enterprise.repositories r ON
15 | t.repository_id = r.id
16 | JOIN github_enterprise.users u ON
17 | r.owner_id = u.id;
--------------------------------------------------------------------------------
/sql/metrics/issue-report.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This query returns a report of active issues within the past X days.
3 | */
4 | SELECT
5 | r.name as repo_name,
6 | u.login as created_by,
7 | v.login as assigned_to,
8 | i.state as issue_state,
9 | i.created_at,
10 | i.updated_at,
11 | i.closed_at,
12 | i.issue_comments_count,
13 | DATEDIFF(i.closed_at, i.created_at) as days_open
14 | FROM
15 | github_enterprise.issues i
16 | LEFT JOIN github_enterprise.users u ON
17 | i.user_id = u.id
18 | LEFT JOIN github_enterprise.users v ON
19 | i.assignee_id = v.id
20 | INNER JOIN github_enterprise.repositories r ON
21 | i.repository_id = r.id
22 | WHERE
23 | DATEDIFF(NOW(), i.created_at) <= 365
24 | ORDER BY
25 | days_open DESC;
--------------------------------------------------------------------------------
/sql/metrics/issue-summary.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This query generates a monthly summary of issues created.
3 | */
4 | SELECT
5 | month(i.created_at) as month,
6 | year(i.created_at) as year,
7 | count(i.created_at) as issues
8 | FROM
9 | github_enterprise.issues i
10 | GROUP BY
11 | month,
12 | year
13 | ORDER BY
14 | year,
15 | month
--------------------------------------------------------------------------------
/sql/metrics/linguist-report.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This lists the "size" of each language in each repository and when the repo
3 | * was last updated.
4 | */
5 | SELECT
6 | r.name,
7 | l.updated_at,
8 | l.public,
9 | l.size,
10 | n.name
11 | FROM
12 | github_enterprise.languages l
13 | JOIN github_enterprise.language_names n ON
14 | l.language_name_id = n.id
15 | JOIN github_enterprise.repositories r ON
16 | l.repository_id = r.id;
--------------------------------------------------------------------------------
/sql/metrics/linguist-stats.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This pulls the number of repositories containing any individual language
3 | * that have been pushed to in the past year.
4 | *
5 | * If you comment out the WHERE clause, it'll return the stats for your server
6 | * for all time.
7 | */
8 | SELECT
9 | n.name as language_name,
10 | COUNT(l.language_name_id) as repo_count,
11 | ROUND(SUM(l.size) /(1024 * 1024)) as language_size_mb
12 | FROM
13 | github_enterprise.languages l
14 | JOIN github_enterprise.language_names n ON l.language_name_id = n.id
15 | JOIN github_enterprise.repositories r ON l.repository_id = r.id
16 | WHERE
17 | r.id IN (
18 | SELECT
19 | r.id
20 | FROM
21 | github_enterprise.repositories r
22 | WHERE
23 | DATEDIFF(NOW(), r.updated_at) < 365
24 | )
25 | GROUP BY
26 | language_name_id
27 | ORDER BY
28 | COUNT(l.language_name_id) DESC;
--------------------------------------------------------------------------------
/sql/metrics/most-recent-active-repos.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This pulls a list of repositories, when they were last updated, who owns
3 | * them, and the disk space associated with each.
4 | */
5 | SELECT
6 | r.name as repo_name,
7 | r.updated_at,
8 | r.disk_usage,
9 | u.login
10 | FROM
11 | github_enterprise.repositories r
12 | JOIN github_enterprise.users u ON
13 | r.owner_id = u.id
14 | ORDER BY
15 | updated_at DESC;
--------------------------------------------------------------------------------
/sql/metrics/pr-report.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This pulls a report of pull requests including the repo name, user name,
3 | * files included, times it was created/updated/merged, and comments.
4 | *
5 | * If you know the organization ID you're interested in, uncomment and put it
6 | * in line 27 to filter this to a specific org. Otherwise, this query returns
7 | * all pull requests in GitHub Enterprise Server.
8 | */
9 | SELECT
10 | r.name,
11 | u.login,
12 | path as filename,
13 | p.id as pr_id,
14 | p.created_at as created_time,
15 | p.updated_at as updated_time,
16 | p.merged_at as merged_time,
17 | CONVERT(body
18 | USING utf8) as comment
19 | FROM
20 | github_enterprise.pull_request_review_comments c
21 | JOIN github_enterprise.users u ON
22 | u.id = c.user_id
23 | JOIN github_enterprise.pull_requests p ON
24 | p.id = c.pull_request_id
25 | JOIN github_enterprise.repositories r ON
26 | r.id = c.repository_id
27 | -- WHERE r.owner_id = (org id here)
28 | ;
--------------------------------------------------------------------------------
/sql/metrics/prereceive-hooks.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This returns a list of pre-receive hooks that are enabled by each repository
3 | * and who owns the repo.
4 | */
5 | SELECT
6 | h.name as hook_name,
7 | r.name as repo_name,
8 | u.login as owner_name
9 | FROM
10 | github_enterprise.pre_receive_hook_targets t
11 | JOIN github_enterprise.pre_receive_hooks h ON
12 | h.id = t.hook_id
13 | JOIN github_enterprise.repositories r ON
14 | r.id = t.hookable_id
15 | JOIN github_enterprise.users u ON
16 | r.owner_id = u.id;
--------------------------------------------------------------------------------
/sql/metrics/public-repo-owners.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This query returns a report of the owners of public repositories in GHES,
3 | * their user or organization email address, and how many repos they publicly
4 | * own.
5 | */
6 | SELECT
7 | u.login,
8 | e.email,
9 | u.organization_billing_email,
10 | count(r.owner_id) as repo_count
11 | FROM
12 | github_enterprise.repositories r
13 | JOIN github_enterprise.users u ON
14 | r.owner_id = u.id
15 | LEFT JOIN github_enterprise.user_emails e ON
16 | u.id = e.user_id
17 | WHERE
18 | r.public = 1
19 | GROUP BY
20 | u.login,
21 | e.email
22 | ORDER BY
23 | repo_count DESC;
--------------------------------------------------------------------------------
/sql/metrics/reactions-stats.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This query returns a count of all the reactions used in GHES for fun facts.
3 | */
4 | SELECT
5 | content,
6 | COUNT(content) as count
7 | FROM
8 | github_enterprise.reactions
9 | GROUP BY
10 | content
11 | ORDER BY
12 | COUNT(content) DESC;
--------------------------------------------------------------------------------
/sql/metrics/staff-notes.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This query returns a list of organizations or users with staff_notes.
3 | *
4 | * Optionally, you can search for a specific string in the WHERE clause.
5 | */
6 | SELECT
7 | u.login as "User Name",
8 | u.type as Type,
9 | s.note as Note,
10 | s.created_at as "Created At",
11 | s.updated_at as "Last Updated"
12 | FROM
13 | github_enterprise.staff_notes s
14 | JOIN github_enterprise.users u ON
15 | s.notable_id = u.id
16 | -- WHERE
17 | -- s.note LIKE '%string-to-search-for%';
--------------------------------------------------------------------------------
/sql/metrics/user-report.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This query returns the username, id, created/suspended date, issues created
3 | * for all time and in the past 30 days, number of repos owned, and how many
4 | * pull requests they've opened.
5 | */
6 | SELECT
7 | u.login,
8 | u.id,
9 | u.created_at,
10 | u.suspended_at,
11 | i.cnt issues_created_all_time,
12 | i2.cnt issues_created_30_days,
13 | r.cnt repos_owned,
14 | pr.cnt prs_opened
15 | FROM
16 | github_enterprise.users u
17 | LEFT JOIN (
18 | SELECT
19 | user_id,
20 | count(id) cnt
21 | FROM
22 | github_enterprise.issues
23 | GROUP BY
24 | user_id ) i ON
25 | i.user_id = u.id
26 | LEFT JOIN (
27 | SELECT
28 | user_id,
29 | count(id) cnt
30 | FROM
31 | github_enterprise.issues
32 | WHERE
33 | DATEDIFF(NOW(), created_at) <= 30
34 | GROUP BY
35 | user_id ) i2 ON
36 | i2.user_id = u.id
37 | LEFT JOIN (
38 | SELECT
39 | owner_id,
40 | count(id) cnt
41 | FROM
42 | github_enterprise.repositories
43 | GROUP BY
44 | owner_id ) r ON
45 | r.owner_id = u.id
46 | LEFT JOIN (
47 | SELECT
48 | user_id,
49 | count(id) cnt
50 | FROM
51 | github_enterprise.pull_requests
52 | GROUP BY
53 | user_id ) pr ON
54 | pr.user_id = u.id
55 | ;
56 |
--------------------------------------------------------------------------------
/sql/security/active-repo-report.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This pulls a list of all detected HIGH and CRITICAL vulnerabilities from
3 | * repositories pushed to in the past 90 days. It also returns who owns it and
4 | * further details on the exact vulnerability.
5 | *
6 | * If you comment line 32, it will both root and fork repositories. As is,
7 | * it will only report root repos.
8 | */
9 | SELECT
10 | r.name AS repo_name,
11 | u.login AS repo_owner,
12 | u.type AS owner_type,
13 | pushed_at AS last_update,
14 | platform,
15 | severity,
16 | cve_id,
17 | ghsa_id,
18 | white_source_id,
19 | external_reference
20 | FROM
21 | github_enterprise.repository_vulnerability_alerts z
22 | JOIN github_enterprise.vulnerabilities v ON
23 | z.vulnerability_id = v.id
24 | JOIN github_enterprise.repositories r ON
25 | z.repository_id = r.id
26 | JOIN github_enterprise.users u ON
27 | r.owner_id = u.id
28 | WHERE
29 | (v.severity = "critical"
30 | OR v.severity = "high")
31 | AND DATEDIFF(NOW(), r.pushed_at) < 91
32 | AND r.parent_id IS NULL
33 | ORDER BY
34 | last_update DESC;
--------------------------------------------------------------------------------
/sql/security/vuln-critical-count.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This pulls a count of repos affected by each _critical_ vulnerability.
3 | */
4 | SELECT
5 | v.id,
6 | v.cve_id,
7 | v.ghsa_id,
8 | v.white_source_id,
9 | v.published_at as published,
10 | v.external_reference,
11 | v.platform as ecosystem,
12 | COUNT(z.vulnerability_id) as repo_count
13 | FROM
14 | github_enterprise.repository_vulnerability_alerts z
15 | JOIN github_enterprise.vulnerabilities v ON
16 | z.vulnerability_id = v.id
17 | WHERE
18 | v.severity = 'critical'
19 | GROUP BY
20 | v.id
21 | ORDER BY
22 | COUNT(z.vulnerability_id) DESC;
--------------------------------------------------------------------------------
/sql/security/vuln-report.sql:
--------------------------------------------------------------------------------
1 | /*
2 | * This pulls a list of all detected vulnerabilities, what it is, who owns the
3 | * associated repo, and when the repo was last updated. This can be a very
4 | * large report!
5 | */
6 | SELECT
7 | r.name as repo_name,
8 | u.login as repo_owner,
9 | u.type as owner_type,
10 | pushed_at as last_update,
11 | platform,
12 | severity,
13 | cve_id,
14 | ghsa_id,
15 | white_source_id,
16 | external_reference
17 | FROM
18 | github_enterprise.repository_vulnerability_alerts z
19 | JOIN github_enterprise.vulnerabilities v ON
20 | z.vulnerability_id = v.id
21 | JOIN github_enterprise.repositories r ON
22 | z.repository_id = r.id
23 | JOIN github_enterprise.users u ON
24 | r.owner_id = u.id
25 | ORDER BY
26 | last_update DESC;
--------------------------------------------------------------------------------