├── .github └── workflows │ ├── codeql.yml │ └── combine-prs.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── SUPPORT.md ├── api ├── bash │ ├── .gitignore │ ├── app-installs.sh │ ├── create-teams.sh │ ├── delete-empty-repos.sh │ ├── migrate-repos-in-org.sh │ ├── repo-list-export.sh │ ├── repo-name-collision-detection.sh │ ├── repo-sizer.sh │ └── update-user-and-team-dn-for-ldap.sh ├── golang │ └── basics-of-authentication │ │ ├── README.md │ │ ├── server.go │ │ └── views │ │ ├── basic.tmpl │ │ └── index.tmpl ├── groovy │ ├── AuditUsers.groovy │ ├── ListMembersInOrgs.groovy │ ├── ListReposInOrg.groovy │ ├── MigrateRepositories.groovy │ └── PrintRepoAccess.groovy ├── java │ └── deployment │ │ ├── .gitignore │ │ ├── README.md │ │ ├── dependency-reduced-pom.xml │ │ ├── pom.xml │ │ └── src │ │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── DeployServer.java │ │ └── test │ │ └── java │ │ └── com │ │ └── github │ │ └── DeployServerTest.java ├── javascript │ ├── .gitignore │ ├── enable-org-security-alerts.md │ ├── es2015-nodejs │ │ ├── README.md │ │ ├── libs │ │ │ ├── GitHubClient.js │ │ │ └── features │ │ │ │ ├── commits.js │ │ │ │ ├── contents.js │ │ │ │ ├── hooks.js │ │ │ │ ├── issues.js │ │ │ │ ├── labels.js │ │ │ │ ├── milestones.js │ │ │ │ ├── octocat.js │ │ │ │ ├── organizations.js │ │ │ │ ├── pullrequests.js │ │ │ │ ├── refs.js │ │ │ │ ├── repositories.js │ │ │ │ ├── stats.js │ │ │ │ ├── teams.js │ │ │ │ └── users.js │ │ ├── node_modules │ │ │ ├── encoding │ │ │ │ ├── .npmignore │ │ │ │ ├── .travis.yml │ │ │ │ ├── LICENSE │ │ │ │ ├── README.md │ │ │ │ ├── lib │ │ │ │ │ ├── encoding.js │ │ │ │ │ └── iconv-loader.js │ │ │ │ ├── package.json │ │ │ │ └── test │ │ │ │ │ └── test.js │ │ │ ├── iconv-lite │ │ │ │ ├── .npmignore │ │ │ │ ├── .travis.yml │ │ │ │ ├── Changelog.md │ │ │ │ ├── LICENSE │ │ │ │ ├── README.md │ │ │ │ ├── encodings │ │ │ │ │ ├── dbcs-codec.js │ │ │ │ │ ├── dbcs-data.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── internal.js │ │ │ │ │ ├── sbcs-codec.js │ │ │ │ │ ├── sbcs-data-generated.js │ │ │ │ │ ├── sbcs-data.js │ │ │ │ │ ├── tables │ │ │ │ │ │ ├── big5-added.json │ │ │ │ │ │ ├── cp936.json │ │ │ │ │ │ ├── cp949.json │ │ │ │ │ │ ├── cp950.json │ │ │ │ │ │ ├── eucjp.json │ │ │ │ │ │ ├── gb18030-ranges.json │ │ │ │ │ │ ├── gbk-added.json │ │ │ │ │ │ └── shiftjis.json │ │ │ │ │ ├── utf16.js │ │ │ │ │ └── utf7.js │ │ │ │ ├── lib │ │ │ │ │ ├── bom-handling.js │ │ │ │ │ ├── extend-node.js │ │ │ │ │ ├── index.js │ │ │ │ │ └── streams.js │ │ │ │ └── package.json │ │ │ ├── is-stream │ │ │ │ ├── index.js │ │ │ │ ├── license │ │ │ │ ├── package.json │ │ │ │ └── readme.md │ │ │ └── node-fetch │ │ │ │ ├── .npmignore │ │ │ │ ├── .travis.yml │ │ │ │ ├── CHANGELOG.md │ │ │ │ ├── ERROR-HANDLING.md │ │ │ │ ├── LICENSE.md │ │ │ │ ├── LIMITS.md │ │ │ │ ├── README.md │ │ │ │ ├── index.js │ │ │ │ ├── lib │ │ │ │ ├── body.js │ │ │ │ ├── fetch-error.js │ │ │ │ ├── headers.js │ │ │ │ ├── request.js │ │ │ │ └── response.js │ │ │ │ ├── package.json │ │ │ │ └── test │ │ │ │ ├── dummy.txt │ │ │ │ ├── server.js │ │ │ │ └── test.js │ │ ├── package.json │ │ └── recipes │ │ │ ├── 00-zen-of-github.js │ │ │ ├── 01-user-informations.js │ │ │ ├── 02-user-suspend.js │ │ │ ├── 03-user-unsuspend.js │ │ │ ├── 04-organizations-repositories.js │ │ │ ├── 05-teams.js │ │ │ ├── 06-milestones.js │ │ │ ├── 07-labels.js │ │ │ ├── 08-issues.js │ │ │ └── 09-pull-request.js │ ├── gha-cleanup │ │ ├── .gitignore │ │ ├── README.md │ │ ├── cli.js │ │ ├── package-lock.json │ │ ├── package.json │ │ └── screenshot.png │ └── org-invite │ │ ├── .gitignore │ │ ├── README.md │ │ ├── cli.js │ │ ├── package-lock.json │ │ ├── package.json │ │ └── screenshot.png ├── powershell │ └── invite_members_to_org.ps1 ├── python │ └── building-a-ci-server │ │ ├── requirements.txt │ │ └── server.py ├── ruby │ ├── 2fa_checker.rb │ ├── basics-of-authentication │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── README.md │ │ ├── advanced_server.rb │ │ ├── server.rb │ │ └── views │ │ │ ├── advanced.erb │ │ │ ├── basic.erb │ │ │ └── index.erb │ ├── building-a-ci-server │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── config.ru │ │ └── server.rb │ ├── building-your-first-github-app │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── README.md │ │ ├── advanced_server.rb │ │ ├── config.ru │ │ └── server.rb │ ├── delivering-deployments │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── config.ru │ │ └── server.rb │ ├── discovering-resources-for-a-user │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── discovering_organizations.rb │ │ └── discovering_repositories.rb │ ├── enterprise │ │ ├── change-domains-in-links.rb │ │ ├── list_all_ssh_keys.rb │ │ └── list_issue_attached_files.rb │ ├── find-inactive-members │ │ ├── README.md │ │ └── find_inactive_members.rb │ ├── fork_checker.rb │ ├── ghe-org-permissions-report.rb │ ├── instance-auditing │ │ ├── .gitignore │ │ ├── README.md │ │ └── instance_auditor.rb │ ├── rendering-data-as-graphs │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── README.md │ │ ├── config.ru │ │ ├── server.rb │ │ └── views │ │ │ └── lang_freq.erb │ ├── team_audit.rb │ ├── traversing-with-pagination │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── changing_number_of_items.rb │ │ ├── constructing_results.rb │ │ └── navigating_results.rb │ ├── user-auditing │ │ ├── README.md │ │ └── suspended_user_audit.rb │ └── working-with-comments │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── comments_on_a_commit.rb │ │ ├── comments_on_an_entire_diff.rb │ │ └── pull_request_comment.rb └── scala.with.sbt │ └── octocat-samples │ ├── .gitignore │ ├── README.md │ ├── build.sbt │ └── src │ └── main │ └── scala │ ├── DemoOrganizations.scala │ ├── DemoRepositories.scala │ ├── DemoUser.scala │ ├── DemoZen.scala │ ├── github │ ├── Client.scala │ └── features │ │ ├── Organizations.scala │ │ ├── RESTMethods.scala │ │ ├── Repositories.scala │ │ ├── Users.scala │ │ └── Zen.scala │ └── http │ ├── Header.scala │ ├── Response.scala │ └── package.scala ├── app └── ruby │ └── app-issue-creator │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ └── server.rb ├── graphql ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── README.md ├── bin │ └── run-query ├── enterprise │ ├── .gitignore │ ├── .nojekyll │ ├── README.md │ ├── dist │ │ ├── graphiql.css │ │ ├── graphiql.min.js │ │ ├── primer-css.css │ │ ├── react-dom.min.js │ │ └── react.min.js │ ├── index.html │ ├── package.json │ ├── scripts │ │ └── build.js │ └── yarn.lock ├── package.json └── queries │ ├── emu-list-enterprise-member-email-addresses.graphql │ ├── emu-scim-list-scim-identities.graphql │ ├── emu-scim-oidc-list-scim-identities.graphql │ ├── enterprise-audit-log.graphql │ ├── enterprise-get-ip-allow-list.graphql │ ├── enterprise-members-2fa-disabled.graphql │ ├── enterprise-members-2fa-insecure.graphql │ ├── enterprise-members-2fa-secure.graphql │ ├── enterprise-outside-collaborators-2fa-disabled.graphql │ ├── enterprise-outside-collaborators-2fa-insecure.graphql │ ├── enterprise-outside-collaborators-2fa-secure.graphql │ ├── enterprise-saml-identities-filtered-by-nameid.graphql │ ├── enterprise-saml-identities.graphql │ ├── enterprise-scim-identities-all-orgs.graphql │ ├── introspection_query.graphql │ ├── ip-allow-list-add-ip.graphql │ ├── ip-allow-list-disable-github-apps-only.graphql │ ├── ip-allow-list-disable-ip-address-only.graphql │ ├── ip-allow-list-disable.graphql │ ├── ip-allow-list-enable-github-apps-only.graphql │ ├── ip-allow-list-enable-ip-address-only.graphql │ ├── ip-allow-list-enable.graphql │ ├── ip-allow-list-remove-ip-entry.graphql │ ├── issue-add-comment.graphql │ ├── issue-search-for-issue-or-bug-requests.graphql │ ├── org-audit-log-api-example.graphql │ ├── org-branches-and-commits-by-repository.graphql │ ├── org-get-ip-allow-list.graphql │ ├── org-list-outside-collaborators-by-repo.graphql │ ├── org-members-by-team.graphql │ ├── org-members-commit-msgs.graphql │ ├── org-members-with-role.graphql │ ├── org-members.graphql │ ├── org-pr-merged-info-by-repository.graphql │ ├── org-repos-fragment-2.graphql │ ├── org-repos-fragment-directive-2.graphql │ ├── org-repos-fragment-directive.graphql │ ├── org-repos-fragment.graphql │ ├── org-saml-identities-filtered-by-nameid-username.graphql │ ├── org-saml-identities.graphql │ ├── org-scim-identities.graphql │ ├── org-with-alias.graphql │ ├── org-with-variables.graphql │ ├── repo-get-all-branches.graphql │ ├── repos-get-last-issue-comment.graphql │ ├── repositories_with_stargazers.graphql │ ├── repository_overview.graphql │ ├── simple-pagination-example.graphql │ └── viewer.graphql ├── hooks ├── jenkins │ ├── jira-issue-validator │ │ ├── README.md │ │ └── jira-issue-validator.Jenkinsfile │ ├── jira-workflow │ │ ├── .github │ │ │ └── jira-workflow.yml │ │ ├── Jenkinsfile │ │ └── README.md │ └── master-branch-protect │ │ ├── README.md │ │ └── branch-protect.Jenkinsfile ├── python │ ├── configuring-your-server │ │ ├── requirements.txt │ │ └── server.py │ └── flask-github-webhooks │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── config.json.sample │ │ ├── hooks │ │ └── example │ │ ├── requirements.txt │ │ └── webhooks.py └── ruby │ ├── configuring-your-server │ ├── Gemfile │ ├── Gemfile.lock │ └── server.rb │ ├── delete-repository-event │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ └── app.rb │ └── dismiss-review-server │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ └── server.rb ├── microsoft-graph-api └── EMU-OIDC-tokenlifetime-policy.md ├── pre-receive-hooks ├── README.md ├── always_reject.sh ├── block-outdated-clients.sh ├── block_branch_names.sh ├── block_branch_names_not_starting_with_userID.sh ├── block_confidentials.sh ├── block_file_extensions.sh ├── block_ip_range.sh ├── block_self_merge_prs.sh ├── block_unknown_pushers.sh ├── block_unsigned_commits.sh ├── commit-current-user-check.sh ├── force_push_restricted_branches.sh ├── reject-commits.sh ├── reject-external-email.sh ├── require-jira-issue.sh ├── restrict-master-to-cli.sh └── restrict-master-to-gui-merges.sh ├── scripts ├── README.md ├── boostrap │ ├── boot │ ├── boot.bat │ └── create-bootstrap ├── git-append-commit-trailer ├── git-change-author ├── git-find-dirs-deleted-files ├── git-find-dirs-many-files ├── git-find-dirs-unwanted ├── git-find-ignored-files ├── git-find-large-files ├── git-find-lfs-extensions ├── git-find-stale-branches ├── git-find-utf-16-encoded-files ├── git-normalize-pathnames ├── git-purge-files └── tests │ └── t0001-git-purge-symlinks └── sql ├── README.md ├── USAGE.md ├── audit ├── admin-tokens.sql ├── authorizations.sql ├── deploy-keys.sql ├── github-apps.sql ├── hooks-repos.sql ├── hooks-users.sql ├── oauth-apps.sql ├── repos-audit.sql ├── user-emails.sql └── user-ssh-keys.sql ├── metrics ├── actions-summary.sql ├── commit-count.sql ├── commit-summary.sql ├── count-tabs.sql ├── issue-report.sql ├── issue-summary.sql ├── linguist-report.sql ├── linguist-stats.sql ├── most-recent-active-repos.sql ├── pr-report.sql ├── prereceive-hooks.sql ├── public-repo-owners.sql ├── reactions-stats.sql ├── staff-notes.sql └── user-report.sql └── security ├── active-repo-report.sql ├── vuln-critical-count.sql └── vuln-report.sql /.gitignore: -------------------------------------------------------------------------------- 1 | access_token 2 | .DS_Store 3 | .bundle 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | platform-samples 2 | ================ 3 | 4 | This is a public place for all sample projects related to the GitHub Platform. 5 | 6 | ## Hierarchy 7 | 8 | The directories are organized to correlate with guides found on developer.github.com. 9 | But here it is, broken down: 10 | 11 | * _api_: here's a bunch of sample code relating to the GitHub API. Subdirectories in this 12 | category are broken up by language. Do you have a language sample you'd like added? 13 | Make a pull request and we'll consider it. 14 | * _graphql_: here's a bunch of sample GraphQL queries that can be run against our [GitHub GraphQL API](https://docs.github.com/graphql). 15 | * _hooks_: want to find out how to write a consumer for [our web hooks](https://docs.github.com/webhooks-and-events/webhooks/about-webhooks)? The examples in this subdirectory show you how. We are open for more contributions via pull requests. 16 | * _microsoft-graph-api_: here's a bunch of sample [Microsoft Graph](https://learn.microsoft.com/en-us/graph/use-the-api) commands related to integrations for GitHub, such as EMU (Enterprise Managed User) OIDC authentication for Azure AD/Entra. 17 | * _pre-receive-hooks_: this one contains [pre-receive-hooks](https://docs.github.com/enterprise-server/admin/policies/enforcing-policy-with-pre-receive-hooks) that can block commits on GitHub Enterprise that do not fit your requirements. Do you have more great examples? Create a pull request and we will check it out. 18 | * _scripts_: want to analyze or clean-up your Git repository? The scripts in this subdirectory show you how. We are open for more contributions via pull requests. 19 | * _sql_: here are sql scripts for custom reporting for GitHub Enterprise Server. We are open for more contributions via pull requests. 20 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | This repository contains sample code provided by GitHub for demonstration purposes. 4 | 5 | - **No Official Support**: These samples are provided "as-is" without official support. 6 | - **Use at Your Own Risk**: Intended for learning and experimentation, not for production use. 7 | 8 | Thank you for understanding. 9 | -------------------------------------------------------------------------------- /api/bash/.gitignore: -------------------------------------------------------------------------------- 1 | *.txt 2 | -------------------------------------------------------------------------------- /api/bash/app-installs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The first argument passed to the script is assigned to the variable ENTERPRISE 4 | ENTERPRISE="$1" 5 | 6 | # This is a GraphQL query that fetches the first 50 organizations of an enterprise 7 | # The query takes two variables: slug (the enterprise's slug) and endCursor (for pagination) 8 | QUERY=' 9 | query($slug:String!, $endCursor:String) { 10 | enterprise(slug:$slug){ 11 | organizations(first:50, after:$endCursor){ 12 | pageInfo{ 13 | endCursor 14 | hasNextPage 15 | } 16 | nodes { 17 | login 18 | } 19 | } 20 | } 21 | }' 22 | 23 | # This loop iterates over each organization in the enterprise 24 | # The 'gh api graphql' command is used to execute the GraphQL query 25 | # The '-f' option is used to pass the query string 26 | # The '-F' option is used to pass the enterprise's slug 27 | # The '--jq' option is used to parse the JSON response and extract the login of each organization 28 | for organization in $(gh api graphql -f query="${QUERY}" -F slug="${ENTERPRISE}" --jq '.data.enterprise.organizations.nodes[].login'); do 29 | # This line prints a message to the console 30 | echo "Installations for $organization" 31 | # This line fetches the installations for the current organization 32 | # The 'gh api' command is used to make a request to the GitHub API 33 | gh api "/orgs/$organization/installations" 34 | done -------------------------------------------------------------------------------- /api/bash/create-teams.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Replace the "xxxxx" with the required values 3 | # Author: @ppremk 4 | 5 | # Script to create GitHub Teams in bulk on GitHub.com Organization 6 | # PAT Tokens needs to have the correct scope to be able to create teams in an organization 7 | # Teams are added as an Array. Teams are created as stand alone teams. Team relationship is not defined 8 | 9 | # To run the script: 10 | # 11 | # - Update VARS section in script 12 | # - chmod +x script.sh 13 | # - ./script.sh 14 | 15 | # VARS 16 | orgname="xxx" 17 | pattoken="xxxxxxx" 18 | teams=("team-name-1" "team-name-2") 19 | 20 | echo "Bulk creating teams in:" 21 | echo $orgname 22 | 23 | for i in "${teams[@]}" 24 | do 25 | curl --request POST \ 26 | --url "https://api.github.com/orgs/$orgname/teams" \ 27 | --header "accept: application/vnd.github.v3+json" \ 28 | --header "authorization: Bearer ${pattoken}" \ 29 | --header "content-type: application/json" \ 30 | --data "{\"name\": \"$i\", \"privacy\": \"closed\" }" \ 31 | -- fail 32 | 33 | retVal=$? 34 | if [ $retVal -ne 0 ]; then 35 | echo "Team creation failed! Please verify validity of supplied configurations." 36 | exit 1 37 | fi 38 | done 39 | echo "Teams succesfully created!" 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /api/golang/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 - ported to Go. 5 | 6 | As the Go standard library does not come with built-in web session handling, only the [simple example](https://github.com/github/platform-samples/blob/master/api/ruby/basics-of-authentication/server.rb) was ported. The example also shows how to use the [GitHub golang SDK](https://github.com/google/go-github). 7 | 8 | ## Install and Run project 9 | 10 | First, of all, you would need to [follow the steps](https://developer.github.com/v3/guides/basics-of-authentication/#registering-your-app) in the GitHub OAuth Developer Guide to register an OAuth application with callback URL `http://localhost:4567/callback`. 11 | 12 | Copy the client id and the secret of your newly created app and set them as environmental variables: 13 | 14 | `export GH_BASIC_SECRET_ID=` 15 | 16 | `export GH_BASIC_CLIENT_ID=` 17 | 18 | Make sure you have Go [installed](https://golang.org/doc/install); then retrieve the modules needed for the [go-github client library](https://github.com/google/go-github) by running 19 | 20 | `go get github.com/google/go-github/github` and 21 | 22 | `go get golang.org/x/oauth2` on the command line. 23 | 24 | Finally, type `go run server.go` on the command line. 25 | 26 | This command will run the server at `localhost:4567`. Visit `http://localhost:4567` with your browser to get your GitHub email addresses revealed (after authorizing the GitHub OAuth App). 27 | 28 | If you should get any errors while redirecting to GitHub, double check your environmental variables and the callback URL you set while registering your OAuth app. 29 | 30 | [basics of auth]: http://developer.github.com/guides/basics-of-authentication/ 31 | -------------------------------------------------------------------------------- /api/golang/basics-of-authentication/views/basic.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Hello, {{.User.Login}}

11 |

12 | {{if not .User.Email}} 13 | It looks like you don't have a public email. That's cool. 14 | {{else}} 15 | It looks like your public email address is {{.User.Email}}. 16 | {{end}} 17 |

18 |

19 | {{if not .Emails}} 20 | Also, you're a bit secretive about your private email addresses. 21 | {{else}} 22 | With your permission, we were also able to dig up your private email addresses: 23 | {{range .Emails}} 24 |

{{.Email}} (verified: {{.Verified}})

25 | {{end}} 26 | {{end}} 27 |

28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /api/golang/basics-of-authentication/views/index.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Well, hello there!

10 |

We're going to now talk to the GitHub API. Ready? Click here to begin!

11 |

If that link doesn't work, remember to provide your own Client ID!

12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /api/groovy/ListMembersInOrgs.groovy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | 3 | /** 4 | * groovy script to show all members (that are visible to the personal access token) of the specified GitHub organizations 5 | * 6 | * The script will first print all visible members of each org individually, then provide a summary for all orgs 7 | * 8 | * Run 'groovy ListMembersInOrgs.groovy' to see the list of command line options 9 | * 10 | * First run may take some time as required dependencies have to get downloaded, then it should be quite fast 11 | * 12 | * If you do not have groovy yet, run 'brew install groovy' 13 | */ 14 | 15 | package org.kohsuke.github 16 | 17 | @Grab(group='org.kohsuke', module='github-api', version='1.75') 18 | import org.kohsuke.github.GitHub 19 | 20 | class ListMembersInOrgs extends GitHub { 21 | 22 | static void main(args) { 23 | 24 | def cli = new CliBuilder(usage: 'groovy -t ListMembersInOrgs.groovy [organizations]') 25 | cli.t(longOpt: 'token', 'personal access token', required: false , args: 1 ) 26 | 27 | OptionAccessor opt = cli.parse(args) 28 | 29 | if(opt.arguments().size() < 1) { 30 | cli.usage() 31 | return 32 | } 33 | 34 | def githubCom 35 | 36 | if (opt.t) { 37 | githubCom = GitHub.connectUsingOAuth(opt.t); 38 | } else { 39 | githubCom = GitHub.connect(); 40 | } 41 | 42 | def uniqueUsers = new HashSet(); 43 | 44 | opt.arguments().each { 45 | println "Org ${it} members:" 46 | githubCom.getOrganization(it).listMembers().each { 47 | println it.getLogin(); 48 | uniqueUsers << it.getLogin() 49 | } 50 | println "---" 51 | } 52 | 53 | println "Unique members of all processed orgs:" 54 | uniqueUsers.each {println it} 55 | 56 | println "---"; 57 | println "Total member count: ${uniqueUsers.size()}" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /api/groovy/ListReposInOrg.groovy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | 3 | // run with groovy ListReposInOrg -t 4 | 5 | package org.kohsuke.github 6 | 7 | @Grab(group='org.kohsuke', module='github-api', version='1.75') 8 | import org.kohsuke.github.GitHub 9 | 10 | class ListReposInOrg extends GitHub { 11 | 12 | static void main(args) { 13 | 14 | def cli = new CliBuilder(usage: 'groovy -t ListReposInOrg.groovy ') 15 | cli.t(longOpt: 'token', 'personal access token', required: false , args: 1 ) 16 | 17 | OptionAccessor opt = cli.parse(args) 18 | 19 | if(opt.arguments().size() != 1) { 20 | cli.usage() 21 | return 22 | } 23 | 24 | def org = opt.arguments()[0]; 25 | def githubCom 26 | 27 | if (opt.t) { 28 | githubCom = GitHub.connectUsingOAuth(opt.t); 29 | } else { 30 | githubCom = GitHub.connect(); 31 | } 32 | 33 | githubCom.getOrganization(org).listRepositories().each { 34 | println it.getFullName(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /api/java/deployment/.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | .settings 3 | .project 4 | .classpath 5 | target/ 6 | .idea 7 | *.iml 8 | 9 | # Mobile Tools for Java (J2ME) 10 | .mtj.tmp/ 11 | 12 | # Package Files # 13 | *.jar 14 | *.war 15 | *.ear 16 | 17 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 18 | hs_err_pid* 19 | -------------------------------------------------------------------------------- /api/java/deployment/README.md: -------------------------------------------------------------------------------- 1 | # DeployServer 2 | 3 | A sample implementation for using GitHub Deployment API. 4 | 5 | Ported [this](https://developer.github.com/guides/delivering-deployments/) by Java. Powered by [Spark](http://sparkjava.com/). 6 | 7 | ## Prerequisite 8 | - JDK8 9 | - Maven3 10 | - GitHub OAuth Token 11 | 12 | ## Getting Started 13 | First, you should set your OAuth token into an environment variable somewhere, like: 14 | ``` 15 | export GITHUB_OAUTH=xxxxxxx 16 | ``` 17 | 18 | After that, you can: 19 | 20 | - For development 21 | 22 | ``` 23 | $ mvn compile exec:java 24 | ``` 25 | 26 | If you aren't familiar with CLI, you can just run the main class via an execution button in your IDE as well. 27 | 28 | - For deployment 29 | 30 | ``` 31 | $ mvn clean package 32 | $ java -jar target/DeployServer-{version}.jar 33 | ``` 34 | 35 | Then you can see it works on `http://localhost:4567`. 36 | 37 | After you make sure this sever deployed a place where GitHub can reach out to, you can test how it interacts with GitHub via its Deployment API. 38 | 39 | You can also place it on your local pc, then expose it by using ngrok. Please refer the direction described [here](https://developer.github.com/guides/delivering-deployments/). 40 | -------------------------------------------------------------------------------- /api/java/deployment/src/test/java/com/github/DeployServerTest.java: -------------------------------------------------------------------------------- 1 | package com.github; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple DeployServer. 9 | */ 10 | public class DeployServerTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public DeployServerTest(String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( DeployServerTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /api/javascript/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | /node_modules/* -------------------------------------------------------------------------------- /api/javascript/enable-org-security-alerts.md: -------------------------------------------------------------------------------- 1 | ## Enable Security Alerts for an Organization 2 | 3 | The linked repository below contains sample scripts for Node and Bash which can be used to enable security alerts and automated security fixes in all of the repositories in a given organization. 4 | 5 | This project is a being provided as a sample only which illustrates how to [enable vulnerability alerts](https://developer.github.com/v3/repos/#enable-vulnerability-alerts) and [enable automated security fixes](https://developer.github.com/v3/repos/#enable-automated-security-fixes) in all repositories in a given organization. 6 | 7 | Please see repo https://github.com/github/enable-security-alerts-sample for both the Node and Bash scripts, and instructions to execute them. 8 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/libs/features/commits.js: -------------------------------------------------------------------------------- 1 | /* 2 | # Commits features 3 | 4 | ## Setup 5 | 6 | ```javascript 7 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 8 | const commits = require('../libs/features/commits'); 9 | 10 | 11 | let githubCli = new GitHubClient({ 12 | baseUri: "http://github.at.home/api/v3", 13 | token: process.env.TOKEN_GHITHUB_ENTERPRISE 14 | }, commits); //<-- add commits features 15 | ``` 16 | */ 17 | 18 | /* 19 | ## fetchCommitBySHA 20 | 21 | - parameter: `sha, owner, repository` 22 | - return: `Promise` 23 | 24 | ### Description 25 | 26 | `fetchCommitBySHA` gets a commit by its sha 27 | 28 | */ 29 | function fetchCommitBySHA({sha, owner, repository}){ 30 | return this.getData({path:`/repos/${owner}/${repository}/git/commits/${sha}`}) 31 | .then(response => { 32 | return response.data; 33 | }); 34 | } 35 | 36 | module.exports = { 37 | fetchCommitBySHA: fetchCommitBySHA 38 | }; 39 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/libs/features/hooks.js: -------------------------------------------------------------------------------- 1 | /* 2 | # Hooks features 3 | 4 | ## Setup 5 | 6 | ```javascript 7 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 8 | const hooks = require('../libs/features/hooks'); 9 | 10 | 11 | let githubCli = new GitHubClient({ 12 | baseUri: "http://github.at.home/api/v3", 13 | token: process.env.TOKEN_GHITHUB_ENTERPRISE 14 | }, hooks); //<-- add hooks features 15 | ``` 16 | */ 17 | 18 | /* 19 | ## createHook 20 | 21 | - parameter: `owner, repository, hookName, hookConfig, hookEvents, active` 22 | - return: `Promise` 23 | 24 | ### Description 25 | 26 | `createHook` creates a hook for a repository 27 | 28 | */ 29 | function createHook({owner, repository, hookName, hookConfig, hookEvents, active}) { 30 | return this.postData({path:`/repos/${owner}/${repository}/hooks`, data:{ 31 | name: hookName 32 | , config: hookConfig 33 | , events: hookEvents 34 | , active: active 35 | }}).then(response => { 36 | return response.data; 37 | }); 38 | } 39 | 40 | /* 41 | ## createOrganizationHook 42 | 43 | - parameter: `org, hookName, hookConfig, hookEvents, active` 44 | - return: `Promise` 45 | 46 | ### Description 47 | 48 | `createOrganizationHook` creates a hook for an organization 49 | 50 | */ 51 | function createOrganizationHook({org, hookName, hookConfig, hookEvents, active}) { 52 | return this.postData({path:`/orgs/${org}/hooks`, data:{ 53 | name: hookName 54 | , config: hookConfig 55 | , events: hookEvents 56 | , active: active 57 | }}).then(response => { 58 | return response.data; 59 | }); 60 | } 61 | 62 | module.exports = { 63 | createHook: createHook, 64 | createOrganizationHook: createOrganizationHook 65 | }; 66 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/libs/features/labels.js: -------------------------------------------------------------------------------- 1 | /* 2 | # Labels features 3 | 4 | ## Setup 5 | 6 | ```javascript 7 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 8 | const labels = require('../libs/features/labels'); 9 | 10 | 11 | let githubCli = new GitHubClient({ 12 | baseUri: "http://github.at.home/api/v3", 13 | token: process.env.TOKEN_GHITHUB_ENTERPRISE 14 | }, labels); //<-- add labels features 15 | ``` 16 | */ 17 | 18 | /* 19 | ## createLabel 20 | 21 | - parameter: `name, color, owner, repository` 22 | - return: `Promise` 23 | 24 | ### Description 25 | 26 | `createLabel` creates a label for a repository 27 | 28 | */ 29 | function createLabel({name, color, owner, repository}) { 30 | return this.postData({path:`/repos/${owner}/${repository}/labels`, data:{ 31 | name: name, 32 | color: color 33 | }}).then(response => { 34 | return response.data; 35 | }); 36 | } 37 | 38 | module.exports = { 39 | createLabel: createLabel 40 | }; 41 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/libs/features/octocat.js: -------------------------------------------------------------------------------- 1 | /* 2 | # Zen of GitHub 3 | 4 | ## Setup 5 | 6 | ```javascript 7 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 8 | const octocat = require('../libs/features/octocat'); 9 | 10 | 11 | let githubCli = new GitHubClient({ 12 | baseUri: "http://github.at.home/api/v3", 13 | token: process.env.TOKEN_GHITHUB_ENTERPRISE 14 | }, octocat); //<-- add octocat feature 15 | ``` 16 | */ 17 | const fetch = require('node-fetch'); 18 | 19 | /* 20 | ## octocat 21 | 22 | - return: `Promise` 23 | 24 | ### Description 25 | 26 | `octocat` gets octocat mindset 27 | 28 | */ 29 | function octocat() { 30 | let _response = {}; 31 | return fetch(this.baseUri + `/octocat`, { 32 | method: 'GET', 33 | headers: this.headers 34 | }) 35 | .then(response => { 36 | if (response.ok) { 37 | return response.text() 38 | } else { 39 | throw new HttpException({ 40 | message: "HttpException", 41 | status:response.status, 42 | statusText:response.statusText, 43 | url: response.url 44 | }); 45 | } 46 | }) 47 | } 48 | 49 | module.exports = { 50 | octocat: octocat 51 | }; 52 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/libs/features/organizations.js: -------------------------------------------------------------------------------- 1 | /* 2 | # Organizations features 3 | 4 | ## Setup 5 | 6 | ```javascript 7 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 8 | const organizations = require('../libs/features/organizations'); 9 | 10 | 11 | let githubCli = new GitHubClient({ 12 | baseUri: "http://github.at.home/api/v3", 13 | token: process.env.TOKEN_GHITHUB_ENTERPRISE 14 | }, organizations); //<-- add organizations features 15 | ``` 16 | */ 17 | 18 | /* 19 | ## createOrganization 20 | 21 | - parameters: `login, admin, profile_name` 22 | - return: `Promise` 23 | 24 | ``` 25 | login: The organization's username. 26 | admin: The login of the user who will manage this organization. 27 | profile_name: The organization's display name. 28 | ``` 29 | 30 | ### Description 31 | 32 | `createOrganization` creates an organization 33 | 34 | */ 35 | function createOrganization({login, admin, profile_name}) { 36 | return this.postData({path:`/admin/organizations`, data:{ 37 | login: login, 38 | admin: admin, 39 | profile_name: profile_name 40 | }}).then(response => { 41 | return response.data; 42 | }); 43 | } 44 | 45 | /* 46 | ## addOrganizationMembership 47 | 48 | - parameters: `org, userName, role` 49 | - return: `Promise` 50 | 51 | 52 | ### Description 53 | 54 | `addOrganizationMembership` adds a role for a user of an organization 55 | 56 | */ 57 | function addOrganizationMembership({org, userName, role}) { 58 | return this.putData({path:`/orgs/${org}/memberships/${userName}`, data:{ 59 | role: role // member, maintener 60 | }}).then(response => { 61 | return response.data; 62 | }); 63 | } 64 | 65 | module.exports = { 66 | createOrganization: createOrganization, 67 | addOrganizationMembership: addOrganizationMembership 68 | }; -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/libs/features/pullrequests.js: -------------------------------------------------------------------------------- 1 | /* 2 | # Pull Requests features 3 | 4 | ## Setup 5 | 6 | ```javascript 7 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 8 | const pullrequests = require('../libs/features/pullrequests'); 9 | 10 | 11 | let githubCli = new GitHubClient({ 12 | baseUri: "http://github.at.home/api/v3", 13 | token: process.env.TOKEN_GHITHUB_ENTERPRISE 14 | }, pullrequests); //<-- add pullrequests features 15 | ``` 16 | */ 17 | 18 | /* 19 | ## createPullRequest 20 | 21 | - parameter: `title, body, head, base, owner, repository` 22 | - return: `Promise` 23 | 24 | ### Description 25 | 26 | `createPullRequest` creates a PR 27 | 28 | */ 29 | function createPullRequest({title, body, head, base, owner, repository}) { 30 | return this.postData({path:`/repos/${owner}/${repository}/pulls`, data:{ 31 | title, body, head, base 32 | }}).then(response => { 33 | return response.data; 34 | }); 35 | } 36 | 37 | module.exports = { 38 | createPullRequest: createPullRequest 39 | }; 40 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/libs/features/stats.js: -------------------------------------------------------------------------------- 1 | /* 2 | # Stats features (only for GitHub Enterprise) 3 | 4 | ## Setup 5 | 6 | ```javascript 7 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 8 | const stats = require('../libs/features/stats'); 9 | 10 | 11 | let githubCli = new GitHubClient({ 12 | baseUri: "http://github.at.home/api/v3", 13 | token: process.env.TOKEN_GHITHUB_ENTERPRISE 14 | }, stats); //<-- add stats features 15 | ``` 16 | */ 17 | 18 | /* 19 | ## fetchStats 20 | 21 | - parameter: `type` see: https://developer.github.com/v3/enterprise/admin_stats/ 22 | - return: `Promise` 23 | 24 | ### Description 25 | 26 | `fetchStats` gets statistics from a type (issues, hooks, ...) 27 | 28 | */ 29 | function fetchStats({type}){ 30 | return this.getData({path:`/enterprise/stats/${type}`}) 31 | .then(response => { 32 | return response.data; 33 | }); 34 | } 35 | 36 | module.exports = { 37 | fetchStats: fetchStats 38 | }; 39 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/libs/features/users.js: -------------------------------------------------------------------------------- 1 | /* 2 | # Users features 3 | 4 | ## Setup 5 | 6 | ```javascript 7 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 8 | const users = require('../libs/features/users'); 9 | 10 | 11 | let githubCli = new GitHubClient({ 12 | baseUri: "http://github.at.home/api/v3", 13 | token: process.env.TOKEN_GHITHUB_ENTERPRISE 14 | }, users); //<-- add users features 15 | ``` 16 | */ 17 | 18 | /* 19 | ## fetchUser 20 | 21 | - parameter: `handle` 22 | - return: `Promise` 23 | 24 | ### Description 25 | 26 | `fetchUser` gets the information of a user (`handle`) 27 | 28 | */ 29 | function fetchUser({handle}) { // get user data 30 | return this.getData({path:`/users/${handle}`}) 31 | .then(response => { 32 | return response.data; 33 | }); 34 | } 35 | 36 | /* 37 | ## suspendUser 38 | 39 | - parameter: `handle` 40 | - return: `Promise` 41 | 42 | ### Description 43 | 44 | `suspendUser` suspends a user (`handle`) 45 | 46 | */ 47 | function suspendUser({handle}) { //https://developer.github.com/v3/users/administration/#suspend-a-user 48 | this.headers["Content-Length"] = 0; 49 | return this.putData({path:`/users/${handle}/suspended`, data:null}) 50 | .then(response => { 51 | delete this.headers["Content-Length"]; 52 | return response 53 | }) 54 | } 55 | 56 | /* 57 | ## unsuspendUser 58 | 59 | - parameter: `handle` 60 | - return: `Promise` 61 | 62 | ### Description 63 | 64 | `unsuspendUser` cancels a user suspension (`handle`) 65 | 66 | */ 67 | function unsuspendUser({handle}) { 68 | return this.deleteData({path:`/users/${handle}/suspended`}) 69 | .then(response => { 70 | delete this.headers["Content-Length"]; 71 | return response 72 | }) 73 | } 74 | 75 | module.exports = { 76 | fetchUser: fetchUser, 77 | suspendUser: suspendUser, 78 | unsuspendUser: unsuspendUser 79 | }; 80 | 81 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/encoding/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/encoding/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - "0.10" 5 | - 0.12 6 | - iojs 7 | - 4 8 | - 5 9 | env: 10 | - CXX=g++-4.8 11 | addons: 12 | apt: 13 | sources: 14 | - ubuntu-toolchain-r-test 15 | packages: 16 | - g++-4.8 17 | notifications: 18 | email: 19 | - andris@kreata.ee 20 | webhooks: 21 | urls: 22 | - https://webhooks.gitter.im/e/0ed18fd9b3e529b3c2cc 23 | on_success: change # options: [always|never|change] default: always 24 | on_failure: always # options: [always|never|change] default: always 25 | on_start: false # default: false 26 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/encoding/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2014 Andris Reinman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 11 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 13 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 14 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 15 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 16 | SOFTWARE. 17 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/encoding/README.md: -------------------------------------------------------------------------------- 1 | # Encoding 2 | 3 | **encoding** is a simple wrapper around [node-iconv](https://github.com/bnoordhuis/node-iconv) and [iconv-lite](https://github.com/ashtuchkin/iconv-lite/) to convert strings from one encoding to another. If node-iconv is not available for some reason, 4 | iconv-lite will be used instead of it as a fallback. 5 | 6 | [![Build Status](https://secure.travis-ci.org/andris9/encoding.svg)](http://travis-ci.org/andris9/Nodemailer) 7 | [![npm version](https://badge.fury.io/js/encoding.svg)](http://badge.fury.io/js/encoding) 8 | 9 | ## Install 10 | 11 | Install through npm 12 | 13 | npm install encoding 14 | 15 | ## Usage 16 | 17 | Require the module 18 | 19 | var encoding = require("encoding"); 20 | 21 | Convert with encoding.convert() 22 | 23 | var resultBuffer = encoding.convert(text, toCharset, fromCharset); 24 | 25 | Where 26 | 27 | * **text** is either a Buffer or a String to be converted 28 | * **toCharset** is the characterset to convert the string 29 | * **fromCharset** (*optional*, defaults to UTF-8) is the source charset 30 | 31 | Output of the conversion is always a Buffer object. 32 | 33 | Example 34 | 35 | var result = encoding.convert("ÕÄÖÜ", "Latin_1"); 36 | console.log(result); // 37 | 38 | ## iconv support 39 | 40 | By default only iconv-lite is bundled. If you need node-iconv support, you need to add it 41 | as an additional dependency for your project: 42 | 43 | ..., 44 | "dependencies":{ 45 | "encoding": "*", 46 | "iconv": "*" 47 | }, 48 | ... 49 | 50 | ## License 51 | 52 | **MIT** 53 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/encoding/lib/iconv-loader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var iconv_package; 4 | var Iconv; 5 | 6 | try { 7 | // this is to fool browserify so it doesn't try (in vain) to install iconv. 8 | iconv_package = 'iconv'; 9 | Iconv = require(iconv_package).Iconv; 10 | } catch (E) { 11 | // node-iconv not present 12 | } 13 | 14 | module.exports = Iconv; 15 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/iconv-lite/.npmignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *sublime-* 3 | generation 4 | test 5 | wiki 6 | coverage 7 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/iconv-lite/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | env: 3 | - CXX=g++-4.8 4 | language: node_js 5 | node_js: 6 | - "0.8" 7 | - "0.10" 8 | - "0.11" 9 | - "0.12" 10 | - "iojs" 11 | - "4.0" 12 | addons: 13 | apt: 14 | sources: 15 | - ubuntu-toolchain-r-test 16 | packages: 17 | - gcc-4.8 18 | - g++-4.8 19 | before_install: 20 | - "test $TRAVIS_NODE_VERSION != '0.8' || npm install -g npm@1.2.8000" 21 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/iconv-lite/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Alexander Shtuchkin 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/iconv-lite/encodings/index.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | // Update this array if you add/rename/remove files in this directory. 4 | // We support Browserify by skipping automatic module discovery and requiring modules directly. 5 | var modules = [ 6 | require("./internal"), 7 | require("./utf16"), 8 | require("./utf7"), 9 | require("./sbcs-codec"), 10 | require("./sbcs-data"), 11 | require("./sbcs-data-generated"), 12 | require("./dbcs-codec"), 13 | require("./dbcs-data"), 14 | ]; 15 | 16 | // Put all encoding/alias/codec definitions to single object and export it. 17 | for (var i = 0; i < modules.length; i++) { 18 | var module = modules[i]; 19 | for (var enc in module) 20 | if (Object.prototype.hasOwnProperty.call(module, enc)) 21 | exports[enc] = module[enc]; 22 | } 23 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/iconv-lite/encodings/tables/gbk-added.json: -------------------------------------------------------------------------------- 1 | [ 2 | ["a140","",62], 3 | ["a180","",32], 4 | ["a240","",62], 5 | ["a280","",32], 6 | ["a2ab","",5], 7 | ["a2e3","€"], 8 | ["a2ef",""], 9 | ["a2fd",""], 10 | ["a340","",62], 11 | ["a380","",31," "], 12 | ["a440","",62], 13 | ["a480","",32], 14 | ["a4f4","",10], 15 | ["a540","",62], 16 | ["a580","",32], 17 | ["a5f7","",7], 18 | ["a640","",62], 19 | ["a680","",32], 20 | ["a6b9","",7], 21 | ["a6d9","",6], 22 | ["a6ec",""], 23 | ["a6f3",""], 24 | ["a6f6","",8], 25 | ["a740","",62], 26 | ["a780","",32], 27 | ["a7c2","",14], 28 | ["a7f2","",12], 29 | ["a896","",10], 30 | ["a8bc",""], 31 | ["a8bf","ǹ"], 32 | ["a8c1",""], 33 | ["a8ea","",20], 34 | ["a958",""], 35 | ["a95b",""], 36 | ["a95d",""], 37 | ["a989","〾⿰",11], 38 | ["a997","",12], 39 | ["a9f0","",14], 40 | ["aaa1","",93], 41 | ["aba1","",93], 42 | ["aca1","",93], 43 | ["ada1","",93], 44 | ["aea1","",93], 45 | ["afa1","",93], 46 | ["d7fa","",4], 47 | ["f8a1","",93], 48 | ["f9a1","",93], 49 | ["faa1","",93], 50 | ["fba1","",93], 51 | ["fca1","",93], 52 | ["fda1","",93], 53 | ["fe50","⺁⺄㑳㑇⺈⺋㖞㘚㘎⺌⺗㥮㤘㧏㧟㩳㧐㭎㱮㳠⺧⺪䁖䅟⺮䌷⺳⺶⺷䎱䎬⺻䏝䓖䙡䙌"], 54 | ["fe80","䜣䜩䝼䞍⻊䥇䥺䥽䦂䦃䦅䦆䦟䦛䦷䦶䲣䲟䲠䲡䱷䲢䴓",6,"䶮",93] 55 | ] 56 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/iconv-lite/lib/bom-handling.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | var BOMChar = '\uFEFF'; 4 | 5 | exports.PrependBOM = PrependBOMWrapper 6 | function PrependBOMWrapper(encoder, options) { 7 | this.encoder = encoder; 8 | this.addBOM = true; 9 | } 10 | 11 | PrependBOMWrapper.prototype.write = function(str) { 12 | if (this.addBOM) { 13 | str = BOMChar + str; 14 | this.addBOM = false; 15 | } 16 | 17 | return this.encoder.write(str); 18 | } 19 | 20 | PrependBOMWrapper.prototype.end = function() { 21 | return this.encoder.end(); 22 | } 23 | 24 | 25 | //------------------------------------------------------------------------------ 26 | 27 | exports.StripBOM = StripBOMWrapper; 28 | function StripBOMWrapper(decoder, options) { 29 | this.decoder = decoder; 30 | this.pass = false; 31 | this.options = options || {}; 32 | } 33 | 34 | StripBOMWrapper.prototype.write = function(buf) { 35 | var res = this.decoder.write(buf); 36 | if (this.pass || !res) 37 | return res; 38 | 39 | if (res[0] === BOMChar) { 40 | res = res.slice(1); 41 | if (typeof this.options.stripBOM === 'function') 42 | this.options.stripBOM(); 43 | } 44 | 45 | this.pass = true; 46 | return res; 47 | } 48 | 49 | StripBOMWrapper.prototype.end = function() { 50 | return this.decoder.end(); 51 | } 52 | 53 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/is-stream/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var isStream = module.exports = function (stream) { 4 | return stream !== null && typeof stream === 'object' && typeof stream.pipe === 'function'; 5 | }; 6 | 7 | isStream.writable = function (stream) { 8 | return isStream(stream) && stream.writable !== false && typeof stream._write === 'function' && typeof stream._writableState === 'object'; 9 | }; 10 | 11 | isStream.readable = function (stream) { 12 | return isStream(stream) && stream.readable !== false && typeof stream._read === 'function' && typeof stream._readableState === 'object'; 13 | }; 14 | 15 | isStream.duplex = function (stream) { 16 | return isStream.writable(stream) && isStream.readable(stream); 17 | }; 18 | 19 | isStream.transform = function (stream) { 20 | return isStream.duplex(stream) && typeof stream._transform === 'function' && typeof stream._transformState === 'object'; 21 | }; 22 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/is-stream/license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Sindre Sorhus (sindresorhus.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/is-stream/readme.md: -------------------------------------------------------------------------------- 1 | # is-stream [![Build Status](https://travis-ci.org/sindresorhus/is-stream.svg?branch=master)](https://travis-ci.org/sindresorhus/is-stream) 2 | 3 | > Check if something is a [Node.js stream](https://nodejs.org/api/stream.html) 4 | 5 | 6 | ## Install 7 | 8 | ``` 9 | $ npm install --save is-stream 10 | ``` 11 | 12 | 13 | ## Usage 14 | 15 | ```js 16 | const fs = require('fs'); 17 | const isStream = require('is-stream'); 18 | 19 | isStream(fs.createReadStream('unicorn.png')); 20 | //=> true 21 | 22 | isStream({}); 23 | //=> false 24 | ``` 25 | 26 | 27 | ## API 28 | 29 | ### isStream(stream) 30 | 31 | #### isStream.writable(stream) 32 | 33 | #### isStream.readable(stream) 34 | 35 | #### isStream.duplex(stream) 36 | 37 | #### isStream.transform(stream) 38 | 39 | 40 | ## License 41 | 42 | MIT © [Sindre Sorhus](https://sindresorhus.com) 43 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/node-fetch/.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | 30 | # OS files 31 | .DS_Store 32 | 33 | # Coveralls token files 34 | .coveralls.yml 35 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/node-fetch/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | - "0.12" 5 | - "node" 6 | env: 7 | - FORMDATA_VERSION=1.0.0 8 | - FORMDATA_VERSION=2.1.0 9 | before_script: 10 | - 'if [ "$FORMDATA_VERSION" ]; then npm install form-data@^$FORMDATA_VERSION; fi' 11 | before_install: npm install -g npm 12 | script: npm run coverage -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/node-fetch/ERROR-HANDLING.md: -------------------------------------------------------------------------------- 1 | 2 | Error handling with node-fetch 3 | ============================== 4 | 5 | Because `window.fetch` isn't designed to transparent about the cause of request errors, we have to come up with our own solutions. 6 | 7 | The basics: 8 | 9 | - All [operational errors](https://www.joyent.com/node-js/production/design/errors) are rejected as [FetchError](https://github.com/bitinn/node-fetch/blob/master/lib/fetch-error.js), you can handle them all through promise `catch` clause. 10 | 11 | - All errors comes with `err.message` detailing the cause of errors. 12 | 13 | - All errors originated from `node-fetch` are marked with custom `err.type`. 14 | 15 | - All errors originated from Node.js core are marked with `err.type = system`, and contains addition `err.code` and `err.errno` for error handling, they are alias to error codes thrown by Node.js core. 16 | 17 | - [Programmer errors](https://www.joyent.com/node-js/production/design/errors) are either thrown as soon as possible, or rejected with default `Error` with `err.message` for ease of troubleshooting. 18 | 19 | List of error types: 20 | 21 | - Because we maintain 100% coverage, see [test.js](https://github.com/bitinn/node-fetch/blob/master/test/test.js) for a full list of custom `FetchError` types, as well as some of the common errors from Node.js 22 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/node-fetch/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 David Frank 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/node-fetch/LIMITS.md: -------------------------------------------------------------------------------- 1 | 2 | Known differences 3 | ================= 4 | 5 | *As of 1.x release* 6 | 7 | - Topics such as Cross-Origin, Content Security Policy, Mixed Content, Service Workers are ignored, given our server-side context. 8 | 9 | - URL input must be an absolute URL, using either `http` or `https` as scheme. 10 | 11 | - On the upside, there are no forbidden headers, and `res.url` contains the final url when following redirects. 12 | 13 | - For convenience, `res.body` is a transform stream, so decoding can be handled independently. 14 | 15 | - Similarly, `req.body` can either be a string, a buffer or a readable stream. 16 | 17 | - Also, you can handle rejected fetch requests through checking `err.type` and `err.code`. 18 | 19 | - Only support `res.text()`, `res.json()`, `res.buffer()` at the moment, until there are good use-cases for blob/arrayBuffer. 20 | 21 | - There is currently no built-in caching, as server-side caching varies by use-cases. 22 | 23 | - Current implementation lacks server-side cookie store, you will need to extract `Set-Cookie` headers manually. 24 | 25 | - If you are using `res.clone()` and writing an isomorphic app, note that stream on Node.js have a smaller internal buffer size (16Kb, aka `highWaterMark`) from client-side browsers (>1Mb, not consistent across browsers). 26 | 27 | - ES6 features such as `headers.entries()` are missing at the moment, but you can use `headers.raw()` to retrieve the raw headers object. 28 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/node-fetch/lib/fetch-error.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * fetch-error.js 4 | * 5 | * FetchError interface for operational errors 6 | */ 7 | 8 | module.exports = FetchError; 9 | 10 | /** 11 | * Create FetchError instance 12 | * 13 | * @param String message Error message for human 14 | * @param String type Error type for machine 15 | * @param String systemError For Node.js system error 16 | * @return FetchError 17 | */ 18 | function FetchError(message, type, systemError) { 19 | 20 | // hide custom error implementation details from end-users 21 | Error.captureStackTrace(this, this.constructor); 22 | 23 | this.name = this.constructor.name; 24 | this.message = message; 25 | this.type = type; 26 | 27 | // when err.type is `system`, err.code contains system error code 28 | if (systemError) { 29 | this.code = this.errno = systemError.code; 30 | } 31 | 32 | } 33 | 34 | require('util').inherits(FetchError, Error); 35 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/node-fetch/lib/response.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * response.js 4 | * 5 | * Response class provides content decoding 6 | */ 7 | 8 | var http = require('http'); 9 | var Headers = require('./headers'); 10 | var Body = require('./body'); 11 | 12 | module.exports = Response; 13 | 14 | /** 15 | * Response class 16 | * 17 | * @param Stream body Readable stream 18 | * @param Object opts Response options 19 | * @return Void 20 | */ 21 | function Response(body, opts) { 22 | 23 | opts = opts || {}; 24 | 25 | this.url = opts.url; 26 | this.status = opts.status || 200; 27 | this.statusText = opts.statusText || http.STATUS_CODES[this.status]; 28 | this.headers = new Headers(opts.headers); 29 | this.ok = this.status >= 200 && this.status < 300; 30 | 31 | Body.call(this, body, opts); 32 | 33 | } 34 | 35 | Response.prototype = Object.create(Body.prototype); 36 | 37 | /** 38 | * Clone this response 39 | * 40 | * @return Response 41 | */ 42 | Response.prototype.clone = function() { 43 | return new Response(this._clone(this), { 44 | url: this.url 45 | , status: this.status 46 | , statusText: this.statusText 47 | , headers: this.headers 48 | , ok: this.ok 49 | }); 50 | }; 51 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/node_modules/node-fetch/test/dummy.txt: -------------------------------------------------------------------------------- 1 | i am a dummy -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-octokit", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "test": "./node_modules/.bin/mocha tests/**" 6 | }, 7 | "author": "@k33g", 8 | "dependencies": { 9 | "node-fetch": "^3.3.2" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/recipes/00-zen-of-github.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Zen of GitHub 3 | */ 4 | 5 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 6 | const octocat = require('../libs/features/octocat'); 7 | 8 | 9 | let githubCli = new GitHubClient({ 10 | baseUri:"http://github.at.home/api/v3", 11 | token:process.env.TOKEN_GHITHUB_ENTERPRISE 12 | }, octocat); 13 | 14 | githubCli.octocat() 15 | .then(data => { 16 | console.log(data); 17 | }) 18 | .catch(error => { 19 | console.log("error", error) 20 | }); 21 | 22 | /* 23 | 24 | MMM. .MMM 25 | MMMMMMMMMMMMMMMMMMM 26 | MMMMMMMMMMMMMMMMMMM _________________________________ 27 | MMMMMMMMMMMMMMMMMMMMM | | 28 | MMMMMMMMMMMMMMMMMMMMMMM | Responsive is better than fast. | 29 | MMMMMMMMMMMMMMMMMMMMMMMM |_ _____________________________| 30 | MMMM::- -:::::::- -::MMMM |/ 31 | MM~:~ 00~:::::~ 00~:~MM 32 | .. MMMMM::.00:::+:::.00::MMMMM .. 33 | .MM::::: ._. :::::MM. 34 | MMMM;:::::;MMMM 35 | -MM MMMMMMM 36 | ^ M+ MMMMMMMMM 37 | MMMMMMM MM MM MM 38 | MM MM MM MM 39 | MM MM MM MM 40 | .~~MM~MM~MM~MM~~. 41 | ~~~~MM:~MM~~~MM~:MM~~~~ 42 | ~~~~~~==~==~~~==~==~~~~~~ 43 | ~~~~~~==~==~==~==~~~~~~ 44 | :~==~==~==~==~~ 45 | 46 | */ -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/recipes/01-user-informations.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Get GitHub user informations 3 | */ 4 | 5 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 6 | const users = require('../libs/features/users'); 7 | 8 | 9 | let githubCli = new GitHubClient({ 10 | baseUri:"http://github.at.home/api/v3", 11 | token:process.env.TOKEN_GHITHUB_ENTERPRISE 12 | }, users); 13 | 14 | 15 | githubCli.fetchUser({handle:'k33g'}) 16 | .then(user => { 17 | console.log(user); 18 | }) 19 | .catch(error => { 20 | console.log("error", error) 21 | }); 22 | 23 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/recipes/02-user-suspend.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Suspend user 3 | */ 4 | 5 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 6 | const users = require('../libs/features/users'); 7 | 8 | 9 | let githubCli = new GitHubClient({ 10 | baseUri:"http://github.at.home/api/v3", 11 | token:process.env.TOKEN_GHITHUB_ENTERPRISE 12 | }, users); 13 | 14 | 15 | githubCli.suspendUser({handle:'ripley'}) 16 | .then(resp => { 17 | console.log(resp); 18 | }) 19 | .catch(error => { 20 | console.log("error", error) 21 | }); 22 | 23 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/recipes/03-user-unsuspend.js: -------------------------------------------------------------------------------- 1 | /** 2 | * UnSuspend user 3 | */ 4 | 5 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 6 | const users = require('../libs/features/users'); 7 | 8 | 9 | let githubCli = new GitHubClient({ 10 | baseUri:"http://github.at.home/api/v3", 11 | token:process.env.TOKEN_GHITHUB_ENTERPRISE 12 | }, users); 13 | 14 | 15 | githubCli.unsuspendUser({handle:'ripley'}) 16 | .then(resp => { 17 | console.log(resp); 18 | }) 19 | .catch(error => { 20 | console.log("error", error) 21 | }); 22 | 23 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/recipes/04-organizations-repositories.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Organizations & Repositories 3 | */ 4 | 5 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 6 | const repositories = require('../libs/features/repositories'); 7 | const organizations = require('../libs/features/organizations'); 8 | 9 | 10 | let githubCli = new GitHubClient({ 11 | baseUri:"http://github.at.home/api/v3", 12 | token:process.env.TOKEN_GHITHUB_ENTERPRISE 13 | } 14 | , repositories 15 | , organizations); 16 | 17 | // Create an organization 18 | githubCli.createOrganization({ 19 | login:'ZeiraCorp', 20 | admin:'k33g', 21 | profile_name:'Zeira Corporation' 22 | }).then(orga => { 23 | console.log(orga); 24 | // Create a repository for these organization 25 | githubCli.createPublicOrganizationRepository({ 26 | name:"toys", 27 | description:"my little repo", 28 | organization:"ZeiraCorp" 29 | }).then(repo => { 30 | console.log(repo) 31 | }) 32 | }); 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/recipes/05-teams.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Teams 3 | */ 4 | 5 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 6 | const teams = require('../libs/features/teams'); 7 | 8 | let githubCli = new GitHubClient({ 9 | baseUri:"http://github.at.home/api/v3", 10 | token:process.env.TOKEN_GHITHUB_ENTERPRISE 11 | }, teams); 12 | 13 | 14 | githubCli.createTeam({ 15 | org: 'ZeiraCorp', 16 | name: 'DreamTeam', 17 | description: 'the dream team', 18 | repo_names:[ 19 | 'ZeiraCorp/toys', 20 | 'ZeiraCorp/tools' 21 | ], 22 | privacy: 'closed', 23 | permission:'admin' 24 | }).then(team => { 25 | console.log(team) 26 | // Add members to team of an organization 27 | githubCli.addTeamMembership({ 28 | teamId: team.id, 29 | userName: 'spocky', 30 | role: 'maintener' 31 | }).then(results=>console.log(results)) 32 | 33 | githubCli.addTeamMembership({ 34 | teamId: team.id, 35 | userName: 'jeanlouc', 36 | role: 'maintener' 37 | }).then(results=>console.log(results)) 38 | 39 | githubCli.addTeamMembership({ 40 | teamId: team.id, 41 | userName: 'k33g', 42 | role: 'maintener' 43 | }).then(results=>console.log(results)) 44 | }).catch(error => { 45 | console.log("error", error) 46 | }); 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/recipes/06-milestones.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Milestones 3 | */ 4 | 5 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 6 | const milestones = require('../libs/features/milestones'); 7 | 8 | let githubCli = new GitHubClient({ 9 | baseUri:"http://github.at.home/api/v3", 10 | token:process.env.TOKEN_GHITHUB_ENTERPRISE 11 | }, milestones); 12 | 13 | githubCli.createMilestone({ 14 | title: 'Inception', 15 | state: 'open', 16 | description: 'A discover phase, where an initial problem statement and functional requirements are created.', 17 | due_on: '2016-11-01T09:00:00Z', 18 | owner: 'ZeiraCorp', // organization in this case 19 | repository: 'toys' 20 | }).then(milestone => console.log(milestone)); 21 | 22 | githubCli.createMilestone({ 23 | title: 'Elaboration', 24 | state: 'open', 25 | description: 'The product vision and architecture are defined, construction cycles are planned.', 26 | due_on: '2016-12-01T09:00:00Z', 27 | owner: 'ZeiraCorp', // organization in this case 28 | repository: 'toys' 29 | }).then(milestone => console.log(milestone)); 30 | 31 | githubCli.createMilestone({ 32 | title: 'Construction', 33 | state: 'open', 34 | description: 'The software is taken from an architectural baseline to the point where it is ready to make the transition to the user community.', 35 | due_on: '2017-01-01T09:00:00Z', 36 | owner: 'ZeiraCorp', // organization in this case 37 | repository: 'toys' 38 | }).then(milestone => console.log(milestone)); 39 | 40 | githubCli.createMilestone({ 41 | title: 'Transition', 42 | state: 'open', 43 | description: "The software is turned into the hands of the user's community.", 44 | due_on: '2017-02-01T09:00:00Z', 45 | owner: 'ZeiraCorp', // organization in this case 46 | repository: 'toys' 47 | }).then(milestone => console.log(milestone)); 48 | 49 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/recipes/08-issues.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Issues, comments and reactions 3 | */ 4 | 5 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 6 | const issues = require('../libs/features/issues'); 7 | 8 | let githubCli = new GitHubClient({ 9 | baseUri:"http://github.at.home/api/v3", 10 | token:process.env.TOKEN_GHITHUB_ENTERPRISE 11 | }, issues); 12 | 13 | let babs = new GitHubClient({ 14 | baseUri:"http://github.at.home/api/v3", 15 | token:process.env.TOKEN_GHE_27_BABS 16 | }, issues); 17 | 18 | let buster = new GitHubClient({ 19 | baseUri:"http://github.at.home/api/v3", 20 | token:process.env.TOKEN_GHE_27_BUSTER 21 | }, issues); 22 | 23 | let issueBody=` 24 | ## I've got a problem 25 | 26 | > this a WIP 27 | 28 | :octocat: :heart: 29 | `; 30 | 31 | githubCli.createIssue({ 32 | title: "Huston?", 33 | body: issueBody, 34 | labels: ["point: 21", "priority: high", "type: bug"], 35 | milestone: 1, 36 | assignees: ["k33g"], 37 | owner: 'ZeiraCorp', 38 | repository: 'toys' 39 | }).then(issue => { 40 | 41 | babs.addIssueReaction({ 42 | owner: 'ZeiraCorp' 43 | , repository: 'toys' 44 | , number: issue.number 45 | , content: "hooray" 46 | }).then(res => console.log(res)) 47 | .catch(err => console.log("err", err)) 48 | 49 | babs.addIssueComment({ 50 | owner: 'ZeiraCorp' 51 | , repository: 'toys' 52 | , number: issue.number 53 | , body: [ 54 | "Hey @k33g :wave:!" 55 | , "It's a nice issue" 56 | , ":octocat: :heart:" 57 | ].join('\n') 58 | }).then(comment => { 59 | 60 | buster.addIssueCommentReaction({ 61 | owner: 'ZeiraCorp' 62 | , repository: 'toys' 63 | , id: comment.id 64 | , content: "+1" 65 | }) 66 | 67 | }).catch(err => console.log("err", err)) 68 | 69 | }); 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /api/javascript/es2015-nodejs/recipes/09-pull-request.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Pull Request 3 | */ 4 | 5 | const GitHubClient = require('../libs/GitHubClient.js').GitHubClient; 6 | const contents = require('../libs/features/contents'); 7 | const refs = require('../libs/features/refs'); 8 | const pullrequests = require('../libs/features/pullrequests'); 9 | 10 | let githubCli = new GitHubClient({ 11 | baseUri:"http://github.at.home/api/v3", 12 | token:process.env.TOKEN_GHITHUB_ENTERPRISE 13 | } 14 | , contents 15 | , refs 16 | , pullrequests 17 | ); 18 | 19 | let optionsBranch = { 20 | branch: "wip-killer-feature" 21 | , from: "master" 22 | , owner: "ZeiraCorp" 23 | , repository: "toys" 24 | }; 25 | 26 | let optionsFile = Object.assign({ 27 | file:"docs/hello-worls=d.md" 28 | , message: "my hello world file :octocat:" 29 | , content:[ 30 | '# Hello World!' 31 | , '> WIP' 32 | , 'this is a test' 33 | , '## And ...' 34 | , '*to be continued* ...' 35 | ].join('\n') 36 | }, optionsBranch); 37 | 38 | let optionsPR = { 39 | title: "!!!Hey, I've a great idea!" 40 | , body: "It's amazing!" 41 | , head: optionsBranch.branch 42 | , base: optionsBranch.from 43 | , owner: optionsBranch.owner 44 | , repository: optionsBranch.repository 45 | }; 46 | 47 | githubCli.createBranch(optionsBranch) 48 | .then(res => { 49 | githubCli.createFile(optionsFile) 50 | .then(res => { 51 | githubCli.createPullRequest(optionsPR) 52 | .then(res => { 53 | console.log("PR OK") 54 | }) 55 | }) 56 | }); 57 | -------------------------------------------------------------------------------- /api/javascript/gha-cleanup/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | .env 4 | -------------------------------------------------------------------------------- /api/javascript/gha-cleanup/README.md: -------------------------------------------------------------------------------- 1 | # gha-cleanup - Clean up GitHub Actions artifacts 2 | 3 | List and delete artifacts created by GitHub Actions in your repository. 4 | Requires a Personal Access Token with full repo permissions. 5 | 6 | ![Screenshot](screenshot.png?raw=true "Script in action") 7 | 8 | # Instructions 9 | 10 | ``` 11 | yarn install 12 | npm link // Optional step. Call ./cli.js instead 13 | 14 | // Options can be supplied interactively or via flags 15 | 16 | $ gha-cleanup --help 17 | Usage: gha-cleanup [options] 18 | 19 | Options: 20 | -t, --token Your GitHub PAT 21 | -u, --user Your GitHub username 22 | -r, --repo Repository name 23 | -h, --help output usage information 24 | 25 | ``` 26 | 27 | # Configuration 28 | 29 | You can pass the PAT and username directly from the prompt. To avoid repeating yourself all the time, create a .env file in the root (don't worry, it will be ignored by git) and set: 30 | 31 | ``` 32 | $GH_PAT= 33 | $GH_USER= 34 | ``` 35 | 36 | Then you can simply invoke `gha-cleanup` and confirm the prefilled values. 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /api/javascript/gha-cleanup/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "actions-admin", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "bin": { 7 | "gha-cleanup": "./cli.js" 8 | }, 9 | "dependencies": { 10 | "@octokit/rest": "^16.39.0", 11 | "chalk": "^3.0.0", 12 | "commander": "^4.1.0", 13 | "dotenv": "^8.2.0", 14 | "inquirer": "^7.0.4", 15 | "lodash": "^4.17.21", 16 | "moment": "^2.29.4", 17 | "octokit": "^3.1.2", 18 | "pretty-bytes": "^5.3.0", 19 | "terminal-kit": "^2.1.8" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /api/javascript/gha-cleanup/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github/platform-samples/4fe2f31287f0a6f005479c36e3de367fc2730cc2/api/javascript/gha-cleanup/screenshot.png -------------------------------------------------------------------------------- /api/javascript/org-invite/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | .env 4 | -------------------------------------------------------------------------------- /api/javascript/org-invite/README.md: -------------------------------------------------------------------------------- 1 | # org-invite 2 | 3 | Use this script send invites in bulk to join a team (new or existing) under an organization on GitHub. 4 | 5 | ![Screenshot](screenshot.png?raw=true "Script in action") 6 | 7 | # Instructions 8 | 9 | Checkout this repo and make sure you're using Node v10 or more recent. 10 | You can supply default values in an `.env` file (gitignored for security reasons): 11 | 12 | ``` 13 | GH_PAT=YOUR_PAT_GOES_HERE 14 | GH_USER=octocat 15 | GH_ORG=github 16 | ``` 17 | You will need to be an owner of the organization and the PAT will need read/write access to the Org permission scope. 18 | To run the first time: 19 | ``` 20 | npm install # do this only once 21 | node cli.js 22 | ``` 23 | 24 | Follow the interactive prompt to supply the team you want to invite members to, and the comma-separated list of email addresses (or existing usernames) you want to invite. 25 | 26 | -------------------------------------------------------------------------------- /api/javascript/org-invite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "actions-admin", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "bin": { 7 | "org-invite": "./cli.js" 8 | }, 9 | "dependencies": { 10 | "@octokit/rest": "^20.0.2", 11 | "chalk": "^3.0.0", 12 | "commander": "^4.1.0", 13 | "dotenv": "^8.2.0", 14 | "inquirer": "^7.0.4", 15 | "lodash": "^4.17.21", 16 | "octokit": "^3.1.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /api/javascript/org-invite/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github/platform-samples/4fe2f31287f0a6f005479c36e3de367fc2730cc2/api/javascript/org-invite/screenshot.png -------------------------------------------------------------------------------- /api/python/building-a-ci-server/requirements.txt: -------------------------------------------------------------------------------- 1 | pyramid==1.9.2 2 | -------------------------------------------------------------------------------- /api/ruby/2fa_checker.rb: -------------------------------------------------------------------------------- 1 | # GitHub & GitHub Enterprise 2FA auditor 2 | # ====================================== 3 | # 4 | # Usage: ruby 2fa_checker.rb 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; --------------------------------------------------------------------------------