Skip to content
This repository was archived by the owner on Mar 29, 2022. It is now read-only.

Commit ba2641d

Browse files
authored
Move maturity timing to PR (#449)
2 parents 94c67f1 + 041137d commit ba2641d

File tree

82 files changed

+1127
-6324
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+1127
-6324
lines changed

app/models/github_pull_request.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ def created_at
3131
@graphql_hash.createdAt
3232
end
3333

34+
def merged?
35+
@graphql_hash.merged
36+
end
37+
3438
def label_names
3539
@graphql_hash.labels.edges.map do |e|
3640
e.node.name.downcase

app/models/pull_request.rb

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,89 @@
11
# frozen_string_literal: true
22

3-
class PullRequest
3+
class PullRequest < ApplicationRecord
44
attr_reader :github_pull_request
55

6-
def initialize(github_pull_request)
7-
@github_pull_request = github_pull_request
8-
end
6+
delegate :title, :body, :url, :created_at, :name, :owner, :repo_id,
7+
:name_with_owner, :label_names, :merged?, to: :github_pull_request
8+
9+
state_machine initial: :new do
10+
event :spam_repo do
11+
transition %i[new waiting] => :spam_repo,
12+
if: ->(pr) { pr.spammy? }
13+
end
14+
15+
event :invalid_label do
16+
transition %i[new waiting] => :invalid_label,
17+
if: ->(pr) { pr.labelled_invalid? }
18+
end
19+
20+
event :eligible do
21+
transition %i[new waiting] => :eligible,
22+
if: ->(pr) { !pr.spammy_or_invalid? && pr.older_than_week? }
23+
end
924

10-
delegate :id, :title, :body, :url, :created_at, :name, :owner, :repo_id,
11-
:name_with_owner, :label_names, to: :github_pull_request
25+
event :waiting do
26+
transition %i[new spam_repo invalid_label] => :waiting,
27+
if: ->(pr) { !pr.spammy_or_invalid? && !pr.older_than_week? }
28+
end
29+
30+
before_transition to: %i[waiting],
31+
from: %i[new] do |pr, _transition|
32+
pr.waiting_since = pr.created_at
33+
pr.save!
34+
end
1235

13-
def state
14-
if spammy?
15-
'spammy'
16-
elsif label_names.include?('invalid')
17-
'invalid'
18-
else
19-
'eligible'
36+
before_transition to: %i[waiting],
37+
from: %i[spam_repo invalid_label] do |pr, _transition|
38+
pr.waiting_since = Time.zone.now
39+
pr.save!
2040
end
2141
end
2242

23-
def eligible?
24-
state == 'eligible'
43+
def check_state
44+
return if spam_repo
45+
return if invalid_label
46+
return if eligible
47+
48+
waiting
49+
end
50+
51+
def most_recent_time
52+
return waiting_since unless waiting_since.nil?
53+
54+
github_pull_request.created_at
55+
end
56+
57+
def older_than_week?
58+
most_recent_time <= (Time.zone.now - 7.days)
59+
end
60+
61+
def labelled_invalid?
62+
return false if merged?
63+
64+
label_names.select { |l| l[/\binvalid\b/i] }.any?
2565
end
2666

2767
def spammy?
2868
SpamRepositoryService.call(repo_id)
2969
end
70+
71+
def spammy_or_invalid?
72+
labelled_invalid? || spammy?
73+
end
74+
75+
def github_id
76+
github_pull_request.id
77+
end
78+
79+
def define_github_pull_request(ghpr)
80+
@github_pull_request = ghpr
81+
end
82+
83+
def self.from_github_pull_request(ghpr)
84+
pr = find_or_create_by(gh_id: ghpr.id)
85+
pr.define_github_pull_request(ghpr)
86+
pr.check_state
87+
pr
88+
end
3089
end

app/models/user.rb

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,18 @@ class User < ApplicationRecord
1414
end
1515

1616
event :wait do
17-
transition registered: :waiting
17+
transition registered: :waiting,
18+
if: ->(user) { user.sufficient_waiting_or_eligible_prs? }
1819
end
1920

2021
event :complete do
21-
transition waiting: :completed
22+
transition waiting: :completed,
23+
if: ->(user) { user.sufficient_eligible_prs? }
24+
end
25+
26+
event :insufficient do
27+
transition waiting: :registered,
28+
unless: ->(user) { user.sufficient_waiting_or_eligible_prs? }
2229
end
2330

2431
event :won do
@@ -27,7 +34,8 @@ class User < ApplicationRecord
2734
end
2835

2936
event :incomplete do
30-
transition registered: :incompleted
37+
transition registered: :incompleted,
38+
unless: ->(user) { user.any_waiting_or_is_eligible? }
3139
end
3240

3341
event :gifted do
@@ -39,11 +47,6 @@ class User < ApplicationRecord
3947
transition incompleted: :completed
4048
end
4149

42-
event :ineligible do
43-
transition waiting: :registered,
44-
unless: ->(user) { user.sufficient_eligible_prs? }
45-
end
46-
4750
state all - [:new] do
4851
validates :terms_acceptance, acceptance: true
4952
validates :email, presence: true
@@ -66,13 +69,15 @@ class User < ApplicationRecord
6669
end
6770

6871
state :waiting do
69-
validates :sufficient_eligible_prs?, inclusion: {
70-
in: [true], message: 'user does not have sufficient eligible prs' }
72+
validates :sufficient_waiting_or_eligible_prs?, inclusion: {
73+
in: [true],
74+
message: 'user does not have sufficient waiting or eligible prs' }
7175
end
7276

7377
state :completed do
74-
validates :won_hacktoberfest?, inclusion: {
75-
in: [true], message: 'user has not met all winning conditions' }
78+
validates :sufficient_eligible_prs?, inclusion: {
79+
in: [true],
80+
message: 'user does not have sufficient eligible prs' }
7681

7782
def win
7883
assign_coupon
@@ -91,6 +96,8 @@ def win
9196
state :incompleted do
9297
validates :hacktoberfest_ended?, inclusion: {
9398
in: [true], message: 'hacktoberfest has not yet ended' }
99+
validates :any_waiting_prs?, inclusion: {
100+
in: [false], message: 'user has waiting prs' }
94101
validates :sufficient_eligible_prs?, inclusion: {
95102
in: [false], message: 'user has too many sufficient eligible prs' }
96103

@@ -113,10 +120,14 @@ def gift
113120
end
114121

115122
before_transition to: %i[completed incompleted] do |user, _transition|
116-
user.receipt = user.scoring_pull_requests
123+
user.receipt = user.scoring_pull_requests_receipt
117124
end
118125

119-
after_transition to: :waiting, do: :update_waiting_since
126+
after_transition to: :waiting do |user, _transition|
127+
# Some users might be able to go direct to winning
128+
# if their PRs are already all a week old
129+
user.complete
130+
end
120131

121132
after_transition to: :completed do |user, _transition|
122133
user.win
@@ -128,44 +139,44 @@ def pull_requests
128139
pull_request_service.all
129140
end
130141

131-
def score
132-
score = eligible_pull_requests_count
133-
score > 4 ? 4 : score
142+
def waiting_pull_requests_count
143+
pull_request_service.waiting_prs.count
134144
end
135145

136146
def eligible_pull_requests_count
137147
pull_request_service.eligible_prs.count
138148
end
139149

140-
delegate :scoring_pull_requests, :non_scoring_pull_requests,
141-
to: :pull_request_service
150+
def waiting_or_eligible_pull_requests_count
151+
waiting_pull_requests_count + eligible_pull_requests_count
152+
end
153+
154+
def sufficient_waiting_or_eligible_prs?
155+
waiting_or_eligible_pull_requests_count >= 4
156+
end
142157

143158
def sufficient_eligible_prs?
144159
eligible_pull_requests_count >= 4
145160
end
146161

147-
def won_hacktoberfest?
148-
sufficient_eligible_prs? && waiting_for_week?
162+
def any_waiting_prs?
163+
waiting_pull_requests_count.positive?
149164
end
150165

151-
def hacktoberfest_ended?
152-
Hacktoberfest.end_date.past?
166+
def any_waiting_or_is_eligible?
167+
any_waiting_prs? || sufficient_eligible_prs?
153168
end
154169

155-
def update_waiting_since
156-
latest_pr = scoring_pull_requests.max_by do |pr|
157-
pr.github_pull_request.created_at
158-
end
159-
160-
update(waiting_since: Time.zone.parse(
161-
latest_pr.github_pull_request.created_at
162-
))
170+
def score
171+
score = waiting_or_eligible_pull_requests_count
172+
score > 4 ? 4 : score
163173
end
164174

165-
def waiting_for_week?
166-
return false if waiting_since.nil?
175+
delegate :scoring_pull_requests, :non_scoring_pull_requests,
176+
:scoring_pull_requests_receipt, to: :pull_request_service
167177

168-
waiting_since <= (Time.zone.now - 7.days)
178+
def hacktoberfest_ended?
179+
Hacktoberfest.end_date.past?
169180
end
170181

171182
def completed_or_won?

app/presenters/profile_page_presenter.rb

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ def scoring_pull_requests
3737

3838
def persisted_winning_pull_requests
3939
@user.receipt.map do |pr|
40-
github_hash = Hashie::Mash.new(pr).github_pull_request.graphql_hash
41-
PullRequest.new(GithubPullRequest.new(github_hash))
40+
PullRequest.from_github_pull_request(
41+
GithubPullRequest.new(Hashie::Mash.new(pr))
42+
)
4243
end
4344
end
4445

@@ -62,10 +63,6 @@ def name
6263
@user.name
6364
end
6465

65-
def waiting_since_for_js
66-
@user.waiting_since&.httpdate
67-
end
68-
6966
def show_timer?
7067
@user.waiting?
7168
end

app/services/backfill_receipt_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ module BackfillReceiptService
44
module_function
55

66
def call(user)
7-
user.update(receipt: user.scoring_pull_requests)
7+
user.update(receipt: user.scoring_pull_requests_receipt)
88
end
99
end

app/services/gift_service.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ def call
1010
group.each do |u|
1111
last_pr = u.receipt.max_by do |pr_obj|
1212
Time.zone.parse(
13-
pr_obj['github_pull_request']['graphql_hash']['createdAt']
13+
pr_obj['createdAt']
1414
)
1515
end
16-
date = last_pr['github_pull_request']['graphql_hash']['createdAt']
16+
date = last_pr['createdAt']
1717
score = u.receipt.count
1818
user_dates << { id: u.id, score: score, date: date }
1919
end

app/services/pull_request_service.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ def all
1414
# in order to lookup all Repo Spammy states in SQL query
1515
# prs = PullRequestStateLookupService.new(filtered_github_pull_requests)
1616
filtered_github_pull_requests(github_pull_requests).map do |ghpr|
17-
PullRequest.new(ghpr)
17+
PullRequest.from_github_pull_request(ghpr)
1818
end
1919
end
2020

21+
def waiting_prs
22+
all.select(&:waiting?)
23+
end
24+
2125
def eligible_prs
2226
all.select(&:eligible?)
2327
end
@@ -30,6 +34,12 @@ def scoring_pull_requests
3034
end
3135
end
3236

37+
def scoring_pull_requests_receipt
38+
scoring_pull_requests.map do |pr|
39+
pr.github_pull_request.graphql_hash
40+
end
41+
end
42+
3343
def non_scoring_pull_requests
3444
all.drop(scoring_pull_requests.count)
3545
end

app/services/try_user_transition_from_waiting_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ def self.call(user)
66

77
return if user.complete
88

9-
user.ineligible
9+
user.insufficient
1010
end
1111
end

app/services/user_state_transition_segment_service.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def call(user, transition)
1313
when :complete then complete(user)
1414
when :retry_complete then complete(user)
1515
when :incomplete then incomplete(user)
16-
when :ineligible then ineligible(user)
16+
when :insufficient then insufficient(user)
1717
when :won then won(user, transition)
1818
when :gifted then gifted(user)
1919
end
@@ -43,9 +43,9 @@ def incomplete(user)
4343
segment(user).identify(state: 'incomplete')
4444
end
4545

46-
def ineligible(user)
47-
segment(user).track('user_ineligible')
48-
segment(user).identify(state: 'ineligible')
46+
def insufficient(user)
47+
segment(user).track('user_insufficient')
48+
segment(user).identify(state: 'insufficient')
4949
end
5050

5151
def won(user, transition)

0 commit comments

Comments
 (0)