Skip to content

Commit 3ece87a

Browse files
committed
Merge branch 'epic-pricing-3' into epic-pricing-rc
2 parents f0f50eb + 18264ef commit 3ece87a

File tree

72 files changed

+956
-150
lines changed

Some content is hidden

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

72 files changed

+956
-150
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
language: ruby
22

33
import:
4-
- travis-ci/build-configs:db-setup.yml
4+
- travis-ci/build-configs:db-setup.yml@epic-pricing
55

66
rvm: 2.6.5
77

lib/travis/api/enqueue/services/restart_model.rb

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module Services
44

55
class RestartModel
66
attr_reader :current_user, :target
7-
ABUSE_DETECTED = "abuse_detected"
7+
ABUSE_DETECTED = 'abuse_detected'
88

99
def initialize(current_user, params)
1010
@current_user = current_user
@@ -15,23 +15,43 @@ def initialize(current_user, params)
1515
def push(event, payload)
1616
if current_user && target && accept?
1717
::Sidekiq::Client.push(
18-
'queue' => 'hub',
19-
'class' => 'Travis::Hub::Sidekiq::Worker',
20-
'args' => [event, payload]
21-
)
18+
'queue' => 'hub',
19+
'class' => 'Travis::Hub::Sidekiq::Worker',
20+
'args' => [event, payload]
21+
)
22+
23+
Result.new(value: payload)
2224
else
23-
@cause_of_denial
25+
Result.new(error: @cause_of_denial || 'restart failed')
2426
end
2527
end
2628

2729
def accept?
28-
current_user && permission? && resetable?
30+
current_user && permission? && resetable? && billing?
31+
end
32+
33+
def billing?
34+
@_billing_ok ||= begin
35+
jobs = target.is_a?(Job) ? [target] : target.matrix
36+
37+
jobs_attrs = jobs.map do |job|
38+
job.config ? job.config.slice(:os) : {}
39+
end
40+
41+
client = Travis::API::V3::BillingClient.new(current_user.id)
42+
client.authorize_build(repository, current_user.id, jobs_attrs)
43+
true
44+
rescue Travis::API::V3::InsufficientAccess => e
45+
@cause_of_denial = e.message
46+
false
47+
end
2948
end
3049

3150
def messages
3251
messages = []
3352
messages << { notice: "The #{type} was successfully restarted." } if accept?
3453
messages << { error: 'You do not seem to have sufficient permissions.' } unless permission?
54+
messages << { error: 'You do not have enough credits.' } unless billing?
3555
messages << { error: "This #{type} currently can not be restarted." } unless resetable?
3656
messages
3757
end
@@ -54,23 +74,36 @@ def target
5474

5575
private
5676

57-
def permission?
58-
current_user && current_user.permission?(required_role, repository_id: target.repository_id) && !abusive?
59-
end
77+
def permission?
78+
current_user && current_user.permission?(required_role, repository_id: target.repository_id) && !abusive?
79+
end
6080

61-
def abusive?
62-
abusive = Travis.redis.sismember("abuse:offenders", "#{@target.owner.class.name}:#{@target.owner_id}")
63-
@cause_of_denial = ABUSE_DETECTED if abusive
64-
abusive
65-
end
81+
def abusive?
82+
abusive = Travis.redis.sismember("abuse:offenders", "#{@target.owner.class.name}:#{@target.owner_id}")
83+
@cause_of_denial = ABUSE_DETECTED if abusive
84+
abusive
85+
end
86+
87+
def resetable?
88+
target.resetable?
89+
end
6690

67-
def resetable?
68-
target.resetable?
91+
def required_role
92+
Travis.config.roles.reset_model
93+
end
94+
95+
class Result
96+
attr_reader :error, :value
97+
98+
def initialize(value: nil, error: nil)
99+
@value = value
100+
@error = error
69101
end
70102

71-
def required_role
72-
Travis.config.roles.reset_model
103+
def success?
104+
!@error
73105
end
106+
end
74107
end
75108
end
76109
end

lib/travis/api/v3/billing_client.rb

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,40 @@ module Travis::API::V3
22
class BillingClient
33
class ConfigurationError < StandardError; end
44

5+
ALLOWANCE_TIMEOUT = 1 # second
6+
57
def initialize(user_id)
68
@user_id = user_id
79
end
810

911
def allowance(owner_type, owner_id)
10-
response = connection.get("/usage/#{owner_type.downcase}s/#{owner_id}/allowance")
12+
response = connection(timeout: ALLOWANCE_TIMEOUT).get("/usage/#{owner_type.downcase}s/#{owner_id}/allowance")
1113
return BillingClient.default_allowance_response unless response.status == 200
1214

1315
Travis::API::V3::Models::Allowance.new(2, owner_id, response.body)
1416
end
1517

18+
def authorize_build(repo, sender_id, jobs)
19+
response = connection.post("/#{repo.owner.class.name.downcase.pluralize}/#{repo.owner.id}/authorize_build", { repository: { private: repo.private? }, sender_id: sender_id, jobs: jobs })
20+
handle_errors_and_respond(response)
21+
end
22+
1623
def self.default_allowance_response(id = 0)
17-
Travis::API::V3::Models::Allowance.new(1, id, { "public_repos" => true, "private_repos" => false, "concurrency_limit" => 1 }.freeze)
24+
Travis::API::V3::Models::Allowance.new(1, id, {
25+
"public_repos" => true,
26+
"private_repos" => false,
27+
"concurrency_limit" => 1,
28+
"user_usage" => false,
29+
"pending_user_licenses" => false
30+
}.freeze)
31+
end
32+
33+
def executions(owner_type, owner_id, page, per_page, from, to)
34+
response = connection.get("/usage/#{owner_type.downcase}s/#{owner_id}/executions?page=#{page}&per_page=#{per_page}&from=#{from}&to=#{to}")
35+
executions = response.body.map do |execution_data|
36+
Travis::API::V3::Models::Execution.new(execution_data)
37+
end
38+
executions
1839
end
1940

2041
def all
@@ -202,24 +223,28 @@ def handle_errors_and_respond(response)
202223
true
203224
when 204
204225
true
205-
when 404
206-
raise Travis::API::V3::NotFound, response.body['error']
207226
when 400
208227
raise Travis::API::V3::ClientError, response.body['error']
228+
when 403
229+
raise Travis::API::V3::InsufficientAccess, response.body['rejection_code']
230+
when 404
231+
raise Travis::API::V3::NotFound, response.body['error']
209232
when 422
210233
raise Travis::API::V3::UnprocessableEntity, response.body['error']
211234
else
212235
raise Travis::API::V3::ServerError, 'Billing system failed'
213236
end
214237
end
215238

216-
def connection
239+
def connection(timeout: 10)
217240
@connection ||= Faraday.new(url: billing_url, ssl: { ca_path: '/usr/lib/ssl/certs' }) do |conn|
218241
conn.basic_auth '_', billing_auth_key
219242
conn.headers['X-Travis-User-Id'] = @user_id.to_s
220243
conn.headers['Content-Type'] = 'application/json'
221244
conn.request :json
222245
conn.response :json
246+
conn.options[:open_timeout] = timeout
247+
conn.options[:timeout] = timeout
223248
conn.use OpenCensus::Trace::Integrations::FaradayMiddleware if Travis::Api::App::Middleware::OpenCensus.enabled?
224249
conn.adapter :net_http
225250
end

lib/travis/api/v3/models/allowance.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
module Travis::API::V3
22
class Models::Allowance
3-
attr_reader :subscription_type, :public_repos, :private_repos, :concurrency_limit, :id
3+
attr_reader :subscription_type, :public_repos, :private_repos, :concurrency_limit, :user_usage, :pending_user_licenses, :id
44

55
def initialize(subscription_type, owner_id, attributes = {})
66
@subscription_type = subscription_type
77
@id = owner_id
88
@public_repos = attributes.fetch('public_repos')
99
@private_repos = attributes.fetch('private_repos')
1010
@concurrency_limit = attributes.fetch('concurrency_limit')
11+
@user_usage = attributes.fetch('user_usage')
12+
@pending_user_licenses = attributes.fetch('pending_user_licenses')
1113
end
1214
end
1315
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module Travis::API::V3
2+
class Models::BuildPermission
3+
attr_accessor :user, :permission, :role
4+
5+
def initialize(attrs = {})
6+
@user = attrs.fetch(:user)
7+
@role = attrs.fetch(:role)
8+
@permission = attrs.fetch(:permission)
9+
end
10+
end
11+
end
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
module Travis::API::V3
2+
class Models::Execution
3+
attr_reader :id, :os, :instance_size, :arch, :virtualization_type, :queue, :job_id, :repository_id, :owner_id,
4+
:owner_type, :plan_id, :sender_id, :credits_consumed, :started_at, :finished_at, :created_at,
5+
:updated_at
6+
7+
def initialize(attributes = {})
8+
@id = attributes.fetch('id')
9+
@os = attributes.fetch('os')
10+
@instance_size = attributes.fetch('instance_size')
11+
@arch = attributes.fetch('arch')
12+
@virtualization_type = attributes.fetch('virtualization_type')
13+
@queue = attributes.fetch('queue')
14+
@job_id = attributes.fetch('job_id')
15+
@repository_id = attributes.fetch('repository_id')
16+
@owner_id = attributes.fetch('owner_id')
17+
@owner_type = attributes.fetch('owner_type')
18+
@plan_id = attributes.fetch('plan_id')
19+
@sender_id = attributes.fetch('sender_id')
20+
@credits_consumed = attributes.fetch('credits_consumed')
21+
@started_at = attributes.fetch('started_at')
22+
@finished_at = attributes.fetch('finished_at')
23+
@created_at = attributes.fetch('created_at')
24+
@updated_at = attributes.fetch('updated_at')
25+
end
26+
end
27+
end

lib/travis/api/v3/models/invoice.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
module Travis::API::V3
22
class Models::Invoice
3-
attr_reader :id, :created_at, :url, :amount_due
3+
attr_reader :id, :created_at, :status, :url, :amount_due
44

55
def initialize(attributes = {})
66
@id = attributes.fetch('id')
77
@created_at = attributes.fetch('created_at') && DateTime.parse(attributes.fetch('created_at'))
8+
@status = attributes.fetch('status')
89
@url = attributes.fetch('url')
910
@amount_due = attributes.fetch('amount_due')
1011
end

lib/travis/api/v3/models/organization_preferences.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ module Travis::API::V3
44
class Models::OrganizationPreferences < Models::JsonSlice
55
child Models::Preference
66

7+
attribute :consume_oss_credits, Boolean, default: true
8+
79
# whether to show insights about the organization's private repositories to
810
# only admins, all members of the organization, or everybody (public) (note:
911
# insights about public repositories are always public)

lib/travis/api/v3/models/user_preferences.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ class Models::UserPreferences < Models::JsonSlice
66

77
attribute :build_emails, Boolean, default: true
88

9+
attribute :consume_oss_credits, Boolean, default: true
10+
911
# whether to show insights about the user's private repositories to
1012
# everybody or keep them only for the user (note: insights about public
1113
# repositories are always public)

lib/travis/api/v3/models/v2_addon_usage.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module Travis::API::V3
22
class Models::V2AddonUsage
3-
attr_reader :id, :addon_id, :addon_quantity, :addon_usage, :remaining, :purchase_date, :valid_to, :active
3+
attr_reader :id, :addon_id, :addon_quantity, :addon_usage, :remaining, :purchase_date, :valid_to, :active, :status
44

55
def initialize(attrs)
66
@id = attrs.fetch('id')
@@ -11,6 +11,7 @@ def initialize(attrs)
1111
@purchase_date = attrs.fetch('purchase_date')
1212
@valid_to = attrs.fetch('valid_to')
1313
@active = attrs.fetch('active')
14+
@status = attrs.fetch('status')
1415
end
1516
end
1617
end

0 commit comments

Comments
 (0)