contribution-checker 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 19182ad1d31baf01f0dc6d78e7d3ba7d3f992bcb
4
+ data.tar.gz: a8f6d7d814d0637a965c93b43a98fe12465fecbe
5
+ SHA512:
6
+ metadata.gz: ecbddc0756b18773bb5be5ef195f2b96251b30bddd1b8c20b1291749a057a29fa23b9079bc0be43e0123974f2c552caec18432af88681f46a2a17be7fdbf3aee
7
+ data.tar.gz: dcb17c150028c981d7939ecc53e9f8f1fc8c60512766387577f00aab4b53593b2f8f7486b668d33f5de3c6bb518348c67e8c3c8e99846c3ca237e9a60825b48a
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 James Dennes
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # GitHub Contribution Checker
2
+
3
+ People :heart: GitHub Contributions. However, it's not always simple to tell why a commit isn't [counted as a contribution][contributions]. This library lets you check whether a specific commit qualifies as a contribution.
4
+
5
+ ## Usage
6
+
7
+ ```ruby
8
+ checker = ContributionChecker::Checker.new \
9
+ :access_token => "<Your 40 char GitHub API token>",
10
+ :commit_url => "https://github.com/user/repo/commit/sha"
11
+ )
12
+
13
+ checker.check
14
+ => {
15
+ :counted_as_contribution => true,
16
+ :and_criteria => {
17
+ :commit_in_valid_branch => true,
18
+ :commit_in_last_year => true,
19
+ :repo_not_a_fork => true,
20
+ :commit_email_linked_to_user => true
21
+ },
22
+ :or_criteria => {
23
+ :user_has_starred_repo => false,
24
+ :user_can_push_to_repo => false,
25
+ :user_is_repo_org_member => true,
26
+ :user_has_fork_of_repo => false
27
+ }
28
+ }
29
+ ```
30
+
31
+ [contributions]: https://help.github.com/articles/why-are-my-contributions-not-showing-up-on-my-profile
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'contribution-checker/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "contribution-checker"
8
+ spec.version = ContributionChecker::VERSION
9
+ spec.authors = ["James Dennes"]
10
+ spec.email = ["jdennes@gmail.com"]
11
+ spec.summary = %q{Check whether a commit is counted as a contribution.}
12
+ spec.description = %q{Check whether a GitHub commit is counted as a \
13
+ contribution for a specific GitHub user.}
14
+ spec.homepage = ""
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "octokit", "~> 3.1"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.6"
25
+ spec.add_development_dependency "rake"
26
+ end
@@ -0,0 +1,206 @@
1
+ require "octokit"
2
+
3
+ # Check whether a GitHub commit is counted as a contribution for a specific
4
+ # GitHub user.
5
+ #
6
+ # @see https://help.github.com/articles/why-are-my-contributions-not-showing-up-on-my-profile
7
+ module ContributionChecker
8
+
9
+ # The Checker.
10
+ class Checker
11
+
12
+ # Initialise a new Checker instance with an API access token and commit URL.
13
+ #
14
+ # @param options [Hash] Options which should take the form:
15
+ # {
16
+ # :access_token => "<Your 40 char GitHub API token>",
17
+ # :commit_url => "https://github.com/user/repo/commit/sha"
18
+ # }
19
+ #
20
+ # @return [ContributionChecker::Checker] Contribution checker initialised
21
+ # for an authenticated user and a specific commit
22
+ def initialize(options = {})
23
+ options.each do |key, val|
24
+ instance_variable_set :"@#{key}", val
25
+ end
26
+ @client = Octokit::Client.new(:access_token => @access_token)
27
+ end
28
+
29
+ # Checks whether the commit is counted as a contribution for the
30
+ # authenticated user.
31
+ #
32
+ # @return [Hash] The return value takes the following form:
33
+ # {
34
+ # :counted_as_contribution => true,
35
+ # :and_criteria => {
36
+ # :commit_in_valid_branch => true,
37
+ # :commit_in_last_year => true,
38
+ # :repo_not_a_fork => true,
39
+ # :commit_email_linked_to_user => true
40
+ # },
41
+ # :or_criteria => {
42
+ # :user_has_starred_repo => false,
43
+ # :user_can_push_to_repo => false,
44
+ # :user_is_repo_org_member => true,
45
+ # :user_has_fork_of_repo => false
46
+ # }
47
+ # }
48
+ def check
49
+ parts = URI.parse(@commit_url).path.split("/")
50
+ @nwo = "#{parts[1]}/#{parts[2]}"
51
+ @sha = parts[4]
52
+ @user = @client.user
53
+ @repo = @client.repository @nwo
54
+ @commit = @client.commit @nwo, @sha
55
+
56
+ @commit_in_valid_branch = commit_in_valid_branch?
57
+ @commit_in_last_year = commit_in_last_year?
58
+ @repo_not_a_fork = !repository_is_fork?
59
+ @commit_email_linked_to_user = commit_email_linked_to_user?
60
+ @user_has_starred_repo = user_has_starred_repo?
61
+ @user_can_push_to_repo = user_can_push_to_repo?
62
+ @user_is_repo_org_member = user_is_repo_org_member?
63
+ @user_has_fork_of_repo = user_has_fork_of_repo?
64
+
65
+ {
66
+ :contribution => and_criteria_met? && or_criteria_met?,
67
+ :and_criteria => {
68
+ :commit_in_valid_branch => @commit_in_valid_branch,
69
+ :commit_in_last_year => @commit_in_last_year,
70
+ :repo_not_a_fork => @repo_not_a_fork,
71
+ :commit_email_linked_to_user => @commit_email_linked_to_user,
72
+ },
73
+ :or_criteria => {
74
+ :user_has_starred_repo => @user_has_starred_repo,
75
+ :user_can_push_to_repo => @user_can_push_to_repo,
76
+ :user_is_repo_org_member => @user_is_repo_org_member,
77
+ :user_has_fork_of_repo => @user_has_fork_of_repo,
78
+ }
79
+ }
80
+ end
81
+
82
+ # Checks whether the commit is in a valid branch. A valid branch is defined
83
+ # as either the default branch of the repository, or the gh-pages branch.
84
+ #
85
+ # @return [Boolean]
86
+ def commit_in_valid_branch?
87
+ # If two refs are entirely different commit histories, the API responds
88
+ # with a 404. Rescue Octokit::NotFound in this case.
89
+ begin
90
+ default_compare = @client.compare @repo[:full_name],
91
+ @repo[:default_branch], @commit[:sha]
92
+ rescue Octokit::NotFound
93
+ default_compare = nil
94
+ end
95
+
96
+ # The compare status should be "identical" or "behind" if the commit is in
97
+ # the default branch
98
+ unless default_compare &&
99
+ %w(identical behind).include?(default_compare[:status])
100
+
101
+ # If the commit is not in the default branch, check the gh-pages branch
102
+ begin
103
+ gh_pages_compare = @client.compare @repo[:full_name], "gh-pages",
104
+ @commit[:sha]
105
+ rescue Octokit::NotFound
106
+ gh_pages_compare = nil
107
+ end
108
+ return false if !gh_pages_compare
109
+ return false if !%w(identical behind).include? gh_pages_compare [:status]
110
+ end
111
+
112
+ true
113
+ end
114
+
115
+ # Checks whether the commit was authored in the last year.
116
+ #
117
+ # @return [Boolean]
118
+ def commit_in_last_year?
119
+ a_year_ago = Time.now - (365.25 * 86400)
120
+ commit_time = @commit[:commit][:author][:date]
121
+ (commit_time <=> a_year_ago) == 1
122
+ end
123
+
124
+ # Checks whether the repository is a fork.
125
+ #
126
+ # @return [Boolean]
127
+ def repository_is_fork?
128
+ @repo[:fork]
129
+ end
130
+
131
+ # Checks whether the commit email is linked to the authenticated user's
132
+ # GitHub account.
133
+ #
134
+ # @return [Boolean]
135
+ def commit_email_linked_to_user?
136
+ @emails = @client.emails
137
+ @emails.map { |e| e[:email] }.include? @commit[:commit][:author][:email]
138
+ end
139
+
140
+ # Checks whether the authenticated user has starred the repository in which
141
+ # the commit exists.
142
+ #
143
+ # @return [Boolean]
144
+ def user_has_starred_repo?
145
+ @client.starred?(@nwo)
146
+ end
147
+
148
+ # Checks whether the authenticated user is a member of the organization
149
+ # that owns the repository (if the repository is owned by an organization
150
+ # account).
151
+ #
152
+ # @return [Boolean]
153
+ def user_is_repo_org_member?
154
+ false if @repo[:owner] != "Organization"
155
+ @client.organization_member? @repo[:owner][:login], @user[:login]
156
+ end
157
+
158
+ # Checks whether the authenticated user has push access to the repository in
159
+ # which the commit exists.
160
+ #
161
+ # @return [Boolean]
162
+ def user_can_push_to_repo?
163
+ @repo[:permissions][:push]
164
+ end
165
+
166
+ # Checks whether the authenticated user has forked the repository in which
167
+ # the commit exists.
168
+ #
169
+ # @return [Boolean]
170
+ def user_has_fork_of_repo?
171
+ # The API doesn't provide a simple means of checking whether a user has
172
+ # forked a repository. Here we need to get the user's forks and check the
173
+ # `parent` field of each fork to see whether it matches @repo.
174
+ @client.auto_paginate = true
175
+ @user_repos = @client.repos
176
+ @user_forks = @user_repos.select { |r| r[:fork] }
177
+ @user_forks.each do |f|
178
+ r = @client.repository f[:full_name]
179
+ return true if r[:parent][:full_name] == @repo[:full_name]
180
+ end
181
+ false
182
+ end
183
+
184
+ # Checks whether the "and" criteria for counting a commit as a contribution
185
+ # are correctly met.
186
+ #
187
+ # @return [Boolean]
188
+ def and_criteria_met?
189
+ @commit_in_valid_branch &&
190
+ @commit_in_last_year &&
191
+ @repo_not_a_fork &&
192
+ @commit_email_linked_to_user
193
+ end
194
+
195
+ # Checks whether the "or" criteria for counting a commit as a contribution
196
+ # are correctly met.
197
+ #
198
+ # @return [Boolean]
199
+ def or_criteria_met?
200
+ @user_has_starred_repo ||
201
+ @user_can_push_to_repo ||
202
+ @user_is_repo_org_member ||
203
+ @user_has_fork_of_repo
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,3 @@
1
+ module ContributionChecker
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,2 @@
1
+ require "contribution-checker/version"
2
+ require "contribution-checker/checker"
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: contribution-checker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - James Dennes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: octokit
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: |-
56
+ Check whether a GitHub commit is counted as a \
57
+ contribution for a specific GitHub user.
58
+ email:
59
+ - jdennes@gmail.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - .gitignore
65
+ - Gemfile
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - contribution-checker.gemspec
70
+ - lib/contribution-checker.rb
71
+ - lib/contribution-checker/checker.rb
72
+ - lib/contribution-checker/version.rb
73
+ homepage: ''
74
+ licenses:
75
+ - MIT
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 2.0.3
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Check whether a commit is counted as a contribution.
97
+ test_files: []