webhookdb 0.1.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 86109800d36b097754f33ad1319331d4de0c4f90345a062c7f3222e57ce020db
4
- data.tar.gz: 4ac7ca8c78b01ea0144f3c7b4ecba7f89bebd581a1eb119a580526d9c99a3c67
3
+ metadata.gz: cd104a25c13b1c3d4a9500bdb618c2f704692c26a09a307eb926cf87bcb2befe
4
+ data.tar.gz: e61ed8994471efa0ab7ab448cf12b68cf4cbb44152df3e98024da3ffa1985c5c
5
5
  SHA512:
6
- metadata.gz: 98e8f1f6dc67c6be2921270bf8c577c2702cf438251606bb0dbf58cb24660b078d9b2e5c54e5f4c4794aa6b2bf168abefafd5be620c56d5d8b8ca37cea9e32a3
7
- data.tar.gz: 1f0800e477cb27e927debf7e7a05bb0eed867ff972f036eaaca733d8a3ca1927f7b73f1e006a49b85a79e5c781e8b8295b9c1c208773ae6df1790b08fada1076
6
+ metadata.gz: 7a0839a974acd4cc643501fe544461e0848f3ee01e1e2b47bcb325dba10636556d15bb597532adb7039caa2dd4b8cf9be6fe487a4cfa211bdd82505dda1c3cc2
7
+ data.tar.gz: 4b619d15175fefaea0eafe39a57aa127c2a1b41beadf5f87fb7586e233170f30c51c02b4e20aa4701e695a42031459d9b1f11fb2ddae4ff1aa8f3d94a98aa4ee
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec/eventually"
4
+
5
+ require "webhookdb/async"
6
+
7
+ RSpec.describe "async workers", :integration do
8
+ it "emails the customer on reset code create" do
9
+ cu = with_async_publisher do
10
+ Webhookdb::Fixtures.reset_code.email.create
11
+ end
12
+
13
+ expect { cu.customer.refresh.message_deliveries }.to eventually(have_attributes(length: 1))
14
+ end
15
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "auth", :integration do
4
+ let(:password) { Webhookdb::Fixtures::Customers::PASSWORD }
5
+
6
+ it "allows me to sign up with a token, and log out" do
7
+ customer = Webhookdb::Fixtures.customer.create
8
+ code = Webhookdb::Fixtures.reset_code(customer:).create
9
+
10
+ login_resp = post(
11
+ "/v1/auth",
12
+ body: {email: customer.email, token: code.token},
13
+ )
14
+ expect(login_resp).to party_status(200)
15
+
16
+ customer_resp = get("/v1/me")
17
+ expect(customer_resp).to party_status(200)
18
+
19
+ logout_resp = post("/v1/auth/logout")
20
+ expect(logout_resp).to party_status(200)
21
+ end
22
+
23
+ it "allows me to login via OTP, and logout" do
24
+ customer = Webhookdb::Fixtures.customer.instance
25
+
26
+ login_resp = post("/v1/auth", body: {email: customer.email})
27
+ expect(login_resp).to party_status(202)
28
+
29
+ customer = Webhookdb::Customer[email: customer.email]
30
+ login_resp = post("/v1/auth/login_otp/#{customer.opaque_id}", body: {value: customer.reset_codes.last.token})
31
+ expect(login_resp).to party_status(200)
32
+
33
+ customer_resp = get("/v1/me")
34
+ expect(customer_resp).to party_status(200)
35
+
36
+ logout_resp = post("/v1/auth/logout")
37
+ expect(logout_resp).to party_status(200)
38
+ end
39
+
40
+ it "can access admin endpoints only if the customer authed as an admin and retains the role" do
41
+ customer = Webhookdb::Fixtures.customer.admin.instance
42
+ auth_customer(customer)
43
+
44
+ resp = get("/admin/v1/auth")
45
+ expect(resp).to party_status(200)
46
+ expect(resp).to party_response(match(hash_including(name: customer.name)))
47
+
48
+ customer.remove_role(Webhookdb::Role.admin_role)
49
+
50
+ resp = get("/admin/v1/auth")
51
+ expect(resp).to party_status(401)
52
+ end
53
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "database", :integration do
4
+ def setup_integration_with_data(rows)
5
+ org = Webhookdb::Fixtures.organization.create
6
+ org.prepare_database_connections
7
+ sint = Webhookdb::Fixtures.service_integration(organization: org).create
8
+ sint.replicator.create_table
9
+ Array.new(rows) do |i|
10
+ t = (Time.now - i.days).iso8601
11
+ sint.replicator.upsert_webhook_body({"my_id" => i.to_s, "at" => t})
12
+ end
13
+ Webhookdb::Organization::DbBuilder.new(org).prepare_database_connections
14
+ return sint
15
+ end
16
+
17
+ it "can sync to database sync targets" do
18
+ sint = setup_integration_with_data(5)
19
+ sync_tgt = Webhookdb::Fixtures.sync_target(
20
+ service_integration: sint,
21
+ connection_url: sint.organization.admin_connection_url,
22
+ ).create
23
+ @to_destroy << sync_tgt
24
+ require "webhookdb/jobs/sync_target_run_sync"
25
+ Webhookdb::Jobs::SyncTargetRunSync.perform_async(sync_tgt.id)
26
+ expect { sync_tgt.refresh }.to eventually(have_attributes(last_synced_at: be_present))
27
+ Sequel.connect(sint.organization.readonly_connection_url) do |db|
28
+ expect(db[sint.table_name.to_sym].all).to have_attributes(size: 5)
29
+ end
30
+ expect(sync_tgt.advisory_lock(sync_tgt.db).dataset(this: true).all).to be_empty
31
+ end
32
+
33
+ it "can sync to http sync targets" do
34
+ sint = setup_integration_with_data(5)
35
+ sync_tgt = Webhookdb::Fixtures.sync_target(
36
+ service_integration: sint,
37
+ connection_url: "http://u:p@localhost:18015/mypath",
38
+ ).create
39
+ @to_destroy << sync_tgt
40
+
41
+ require "socket"
42
+ server = TCPServer.new "localhost", 18_015
43
+ received = []
44
+ server_thread = Thread.new do
45
+ # Will only have one session
46
+ session = server.accept
47
+ # Processing line by line isn't needed here, we're just testing so grab the whole body
48
+ received << session.recv(4096)
49
+ session.print "HTTP/1.1 200\r\n"
50
+ session.print "Content-Type: text/plain\r\n"
51
+ session.print "\r\n"
52
+ session.print "ok"
53
+ session.close
54
+ end
55
+
56
+ # We need to do this in-process so the sync can POST back to localhost;
57
+ # if the worker was on another machine, the tcp server wouldn't be reachable.
58
+ sync_tgt.run_sync(now: Time.now)
59
+ expect { sync_tgt.refresh }.to eventually(have_attributes(last_synced_at: be_present))
60
+ expect { received }.to eventually(contain_exactly(include("POST /mypath").and(include('"rows":'))))
61
+ Thread.kill(server_thread)
62
+ expect(sync_tgt.advisory_lock(sync_tgt.db).dataset(this: true).all).to be_empty
63
+ end
64
+
65
+ it "can run a database migration" do
66
+ sint = setup_integration_with_data(5)
67
+ org = sint.organization
68
+ dbmigration = with_async_publisher do
69
+ Webhookdb::Organization::DatabaseMigration.enqueue(
70
+ admin_connection_url_raw: org.admin_connection_url,
71
+ readonly_connection_url_raw: org.readonly_connection_url,
72
+ public_host: org.public_host,
73
+ started_by: nil,
74
+ organization: org,
75
+ )
76
+ end
77
+ expect { dbmigration.refresh }.to eventually(have_attributes(status: "finished"))
78
+ Sequel.connect(org.readonly_connection_url) do |db|
79
+ expect(db[Sequel[org.replication_schema.to_sym][sint.table_name.to_sym]].all).to have_attributes(size: 5)
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "helpers", :integration do
4
+ it "can use the redis cache" do
5
+ key = "integration-test-key"
6
+ Webhookdb::Redis.cache.with do |r|
7
+ r.call("SET", key, "1")
8
+ expect(r.call("GET", key)).to eq("1")
9
+ end
10
+ t = Thread.start do
11
+ Webhookdb::Redis.cache.with do |r|
12
+ r.call("DEL", key)
13
+ expect(r.call("GET", key)).to be_nil
14
+ end
15
+ end
16
+ t.join
17
+ Webhookdb::Redis.cache.with do |r|
18
+ expect(r.call("GET", key)).to be_nil
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec/eventually"
4
+
5
+ RSpec.describe "service integrations", :integration do
6
+ def catch_missing_db(default)
7
+ yield
8
+ rescue Sequel::DatabaseError
9
+ return default
10
+ end
11
+
12
+ it "can create a full webhookdb customer integration and POST webhooks" do
13
+ c = auth_customer
14
+ expect { c.refresh.all_memberships }.to eventually(have_attributes(length: 1))
15
+ org = c.verified_memberships.last.organization
16
+ expect { org.refresh }.to eventually(have_attributes(readonly_connection_url: be_present))
17
+ org.add_feature_role(Webhookdb::Role.find_or_create(name: "internal"))
18
+
19
+ resp = post(
20
+ "/v1/organizations/#{org.id}/service_integrations/create",
21
+ body: {service_name: "webhookdb_customer_v1"},
22
+ )
23
+ expect(resp).to party_status(200)
24
+
25
+ expect(org.refresh.service_integrations).to have_attributes(length: 1)
26
+ sint = org.service_integrations.first
27
+
28
+ expect do
29
+ catch_missing_db(["default"]) { sint.replicator.readonly_dataset(&:all) }
30
+ end.to eventually(be_empty)
31
+
32
+ with_async_publisher do
33
+ Webhookdb::Fixtures.customer.create
34
+ end
35
+
36
+ expect do
37
+ catch_missing_db(["default"]) { sint.replicator.readonly_dataset(&:all) }
38
+ end.to eventually(have_attributes(length: 1))
39
+
40
+ # puts sint.opaque_id, "/v1/service_integrations/#{sint.opaque_id}"
41
+ resp = post(
42
+ "/v1/service_integrations/#{sint.opaque_id}",
43
+ body: c.values.as_json,
44
+ headers: {"Whdb-Secret" => sint.webhook_secret},
45
+ json: true,
46
+ )
47
+ expect(resp).to party_status(202)
48
+ expect(resp).to party_response(match(o: "k"))
49
+ logged_whs = Webhookdb::LoggedWebhook.where(service_integration_opaque_id: sint.opaque_id).all
50
+ expect(logged_whs).to_not be_empty
51
+ end
52
+
53
+ it "can upsert data synchrononously through endpoint" do
54
+ c = auth_customer
55
+ expect { c.refresh.all_memberships }.to eventually(have_attributes(length: 1))
56
+ org = c.verified_memberships.last.organization
57
+ expect { org.refresh }.to eventually(have_attributes(readonly_connection_url: be_present))
58
+ org.add_feature_role(Webhookdb::Role.find_or_create(name: "internal"))
59
+ sint = Webhookdb::Fixtures.service_integration(organization: org).create
60
+ sint.replicator.create_table
61
+
62
+ resp = post(
63
+ "/v1/organizations/#{org.id}/service_integrations/#{sint.opaque_id}/upsert",
64
+ body: {my_id: "id", at: Time.now},
65
+ json: true,
66
+ )
67
+ expect(resp).to party_status(200)
68
+ expect(resp).to party_response(match(hash_including(message: /You have upserted/)))
69
+
70
+ expect(sint.replicator.readonly_dataset(&:all)).to contain_exactly(include(my_id: "id"))
71
+ end
72
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "system", :integration do
4
+ it "responds to a health check" do
5
+ response = HTTParty.get(url("/healthz"))
6
+ expect(response).to party_status(200)
7
+ expect(response).to party_response(eq(o: "k"))
8
+ end
9
+
10
+ it "responds to a status check" do
11
+ response = HTTParty.get(url("/statusz"))
12
+ expect(response).to party_status(200)
13
+ expect(response).to party_response(include(:version))
14
+ end
15
+ end
@@ -13,7 +13,10 @@ class Webhookdb::API::System < Webhookdb::Service
13
13
  helpers Webhookdb::Service::Helpers
14
14
 
15
15
  get :healthz do
16
- Webhookdb::Postgres::Model.db.execute("SELECT 1=1")
16
+ # Do not bother looking at dependencies like databases.
17
+ # If the primary is down, we can still accept webhooks
18
+ # if LoggedWebhook resiliency is configured,
19
+ # which is the primary thing about whether we're healthy or not.
17
20
  status 200
18
21
  {o: "k"}
19
22
  end
@@ -29,9 +32,11 @@ class Webhookdb::API::System < Webhookdb::Service
29
32
  }
30
33
  end
31
34
 
32
- resource :debug do
33
- get :echo do
34
- pp params.to_h
35
+ if ["development", "test"].include?(Webhookdb::RACK_ENV)
36
+ resource :debug do
37
+ get :echo do
38
+ pp params.to_h
39
+ end
35
40
  end
36
41
  end
37
42
  end
@@ -34,6 +34,32 @@ require "webhookdb/admin_api/roles"
34
34
  require "webterm/apps"
35
35
 
36
36
  module Webhookdb::Apps
37
+ # Call this from your rackup file, like config.ru.
38
+ #
39
+ # @example
40
+ # lib = File.expand_path("lib", __dir__)
41
+ # $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
42
+ # require "webhookdb"
43
+ # Webhookdb.load_app
44
+ # require "webhookdb/apps"
45
+ # Webhookdb::Apps.rack_up(self)
46
+ #
47
+ def self.rack_up(config_ru)
48
+ Webhookdb::Async.setup_web
49
+ config_ru.instance_exec do
50
+ map "/admin" do
51
+ run Webhookdb::Apps::AdminAPI.build_app
52
+ end
53
+ map "/sidekiq" do
54
+ run Webhookdb::Apps::SidekiqWeb.to_app
55
+ end
56
+ map "/terminal" do
57
+ run Webhookdb::Apps::Webterm.to_app
58
+ end
59
+ run Webhookdb::Apps::API.build_app
60
+ end
61
+ end
62
+
37
63
  class API < Webhookdb::Service
38
64
  mount Webhookdb::API::Auth
39
65
  mount Webhookdb::API::Db
@@ -9,7 +9,7 @@ module Webhookdb::Async::Autoscaler
9
9
  include Appydays::Configurable
10
10
  include Appydays::Loggable
11
11
 
12
- AVAILABLE_PROVIDERS = ["heroku"].freeze
12
+ AVAILABLE_PROVIDERS = ["heroku", "fake"].freeze
13
13
 
14
14
  def self._check_provider!
15
15
  return if AVAILABLE_PROVIDERS.include?(self.provider)
@@ -26,6 +26,8 @@ module Webhookdb::Async::Autoscaler
26
26
  setting :max_additional_workers, 2
27
27
  setting :latency_restored_threshold, 0
28
28
  setting :hostname_regex, /^web\.1$/, convert: ->(s) { Regexp.new(s) }
29
+ setting :heroku_app_id_or_app_name, "", key: "HEROKU_APP_NAME"
30
+ setting :heroku_formation_id_or_formation_type, "worker"
29
31
 
30
32
  after_configured do
31
33
  self._check_provider!
@@ -35,19 +37,25 @@ module Webhookdb::Async::Autoscaler
35
37
  class << self
36
38
  def enabled? = self.enabled
37
39
 
38
- def start
39
- raise "already started" unless @instance.nil?
40
+ def build_implementation
40
41
  case self.provider
41
42
  when "heroku"
42
43
  opts = {heroku: Webhookdb::Heroku.client, max_additional_workers: self.max_additional_workers}
43
44
  (opts[:app_id_or_app_name] = self.heroku_app_id_or_app_name) if
44
- self.heroku_app_id_or_app_name
45
+ self.heroku_app_id_or_app_name.present?
45
46
  (opts[:formation_id_or_formation_type] = self.heroku_formation_id_or_formation_type) if
46
- self.heroku_formation_id_or_formation_type
47
- @impl = Amigo::Autoscaler::Heroku.new(**opts)
47
+ self.heroku_formation_id_or_formation_type.present?
48
+ return Amigo::Autoscaler::Heroku.new(**opts)
49
+ when "fake"
50
+ return FakeImplementation.new
48
51
  else
49
52
  self._check_provider!
50
53
  end
54
+ end
55
+
56
+ def start
57
+ raise "already started" unless @instance.nil?
58
+ @impl = self.build_implementation
51
59
  @instance = Amigo::Autoscaler.new(
52
60
  poll_interval: self.poll_interval,
53
61
  latency_threshold: self.latency_threshold,
@@ -81,4 +89,21 @@ module Webhookdb::Async::Autoscaler
81
89
  self.logger.warn("high_latency_queues_resolved", depth:, duration:, scale_action:)
82
90
  end
83
91
  end
92
+
93
+ class FakeImplementation
94
+ attr_reader :scale_ups, :scale_downs
95
+
96
+ def initialize
97
+ @scale_ups = []
98
+ @scale_downs = []
99
+ end
100
+
101
+ def scale_up(*args)
102
+ @scale_ups << args
103
+ end
104
+
105
+ def scale_down(*args)
106
+ @scale_downs << args
107
+ end
108
+ end
84
109
  end
@@ -14,7 +14,7 @@ class Webhookdb::Heroku
14
14
  end
15
15
 
16
16
  def self.client
17
- raise "No heroku:oauth_token configured" if self.oauth_token.blank?
17
+ raise "WEBHOOKDB_HEROKU_OAUTH_TOKEN not set" if self.oauth_token.blank?
18
18
  @client ||= PlatformAPI.connect_oauth(self.oauth_token)
19
19
  return @client
20
20
  end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb"
4
+
5
+ module Webhookdb::Pry
6
+ # Call this from .pryrc.
7
+ #
8
+ # @example
9
+ # lib = File.expand_path("lib", __dir__)
10
+ # $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
11
+ #
12
+ # require "appydays/dotenviable"
13
+ # Appydays::Dotenviable.load
14
+ #
15
+ # require "webhookdb/pry"
16
+ # Webhookdb::Pry.setup(self)
17
+ def self.setup(main)
18
+ main.instance_exec do
19
+ require "pry/clipboard"
20
+
21
+ Pry.config.commands.alias_command "ch", "copy-history"
22
+ Pry.config.commands.alias_command "cr", "copy-result"
23
+
24
+ # Decode the given cookie string. Since cookies are encrypted,
25
+ # this is useful for debugging what they contain.
26
+ def decode_cookie(s)
27
+ require "webhookdb/service"
28
+ return Webhookdb::Service.decode_cookie(s)
29
+ end
30
+
31
+ # Connect this session of Pry to the database.
32
+ # It also registers subscribers, so changes to the models are handled
33
+ # by their correct async jobs (since async jobs are handled in-process).
34
+ def connect
35
+ require "webhookdb"
36
+ Webhookdb.load_app
37
+ Webhookdb::Async.setup_web if Amigo.subscribers.empty?
38
+ return
39
+ end
40
+
41
+ def copt
42
+ rc = Appydays::Loggable[self].silence(:fatal) do
43
+ Webhookdb::Customer::ResetCode.order(:id).last
44
+ end
45
+ tok = rc.token
46
+ Clipboard.copy tok
47
+ puts "Copied OTP #{tok} for #{rc.customer.email} to clipboard"
48
+ return tok
49
+ end
50
+
51
+ # Load models and fixtures. Use this when riffing locally.
52
+ def repl
53
+ require "webhookdb"
54
+ Webhookdb.load_app
55
+ require "webhookdb/fixtures"
56
+ Webhookdb::Fixtures.load_all
57
+ return
58
+ end
59
+
60
+ def console
61
+ connect
62
+ require "webhookdb/console"
63
+ Webhookdb::Console.enable_safe_mode
64
+ self.extend Webhookdb::Console::MainMethods
65
+ Amigo.register_subscriber do |ev|
66
+ Webhookdb::Console.console_logger(ev)
67
+ end
68
+ return
69
+ end
70
+ end
71
+ end
72
+ end
@@ -3,9 +3,10 @@
3
3
  # Write docs for docs.webhookdb.com Jekyll site.
4
4
  class Webhookdb::Replicator::Docgen
5
5
  def self.documentable_descriptors
6
- return Webhookdb::Replicator.registry.values.reject do |repl|
7
- repl.name.start_with?("webhookdb_", "fake_")
8
- end.sort_by(&:name)
6
+ return Webhookdb::Replicator.registry.
7
+ values.
8
+ select(&:documentable?).
9
+ sort_by(&:name)
9
10
  end
10
11
 
11
12
  # @!attribute desc
@@ -79,6 +79,8 @@ class Webhookdb::Replicator
79
79
  # Is this an enterprise-only replicator?
80
80
  attr_reader :enterprise
81
81
 
82
+ def documentable? = @documentable
83
+
82
84
  def initialize(
83
85
  name:,
84
86
  ctor:,
@@ -91,7 +93,8 @@ class Webhookdb::Replicator
91
93
  api_docs_url: "",
92
94
  description: nil,
93
95
  enterprise: false,
94
- documentation_url: nil
96
+ documentation_url: nil,
97
+ documentable: nil
95
98
  )
96
99
  raise ArgumentError, "must support one or both of webhooks and backfill" unless
97
100
  supports_webhooks || supports_backfill
@@ -109,7 +112,7 @@ class Webhookdb::Replicator
109
112
  @ctor = ctor.is_a?(Class) ? ctor.method(:new) : ctor
110
113
  @resource_name_plural = resource_name_plural || "#{self.resource_name_singular}s"
111
114
  @description = description || "Replicate #{self.resource_name_plural} into your database."
112
- self.feature_roles
115
+ @documentable = documentable.nil? ? !self.name.start_with?("webhookdb_", "fake_", "theranest_") : documentable
113
116
  end
114
117
 
115
118
  def inspect
@@ -26,12 +26,12 @@ module Webhookdb::IntegrationSpecHelpers
26
26
  example.metadata[:integration]
27
27
 
28
28
  @to_destroy = []
29
- WebMock.allow_net_connect!
29
+ WebMock.allow_net_connect! if defined?(WebMock)
30
30
  end
31
31
 
32
32
  context.after(:each) do
33
33
  @to_destroy.each(&:destroy)
34
- WebMock.disable_net_connect!
34
+ WebMock.disable_net_connect! if defined?(WebMock)
35
35
  end
36
36
  super
37
37
  end
@@ -22,6 +22,12 @@ module Webhookdb::Tasks
22
22
  Rake::Task["specs:heroku_integration_step1"].invoke
23
23
  end
24
24
  end
25
+
26
+ desc "Print version info and exit"
27
+ task :version do
28
+ sha = Webhookdb::COMMIT[..8]
29
+ puts "#{sha} (#{Webhookdb::RELEASE}) - #{Webhookdb::RELEASE_CREATED_AT} - #{Webhookdb::RACK_ENV}"
30
+ end
25
31
  end
26
32
  end
27
33
  end
@@ -36,7 +36,7 @@ module Webhookdb::Tasks
36
36
  require "webhookdb/heroku"
37
37
  Webhookdb::Heroku.client.dyno.create(
38
38
  Webhookdb::Heroku.app_name,
39
- command: "bundle exec rake specs:integration_step3",
39
+ command: "bundle exec rake specs:heroku_integration_step3",
40
40
  env: {"INTEGRATION_TESTS" => "true"},
41
41
  attach: false,
42
42
  time_to_live: 10.minute.to_i,
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb"
4
+
5
+ module Webhookdb::Tasks
6
+ # Load all Webhookdb Rake tasks.
7
+ # You can also load them individually.
8
+ def self.load_all
9
+ require "webhookdb/tasks/admin"
10
+ Webhookdb::Tasks::Admin.new
11
+ require "webhookdb/tasks/annotate"
12
+ Webhookdb::Tasks::Annotate.new
13
+ require "webhookdb/tasks/db"
14
+ Webhookdb::Tasks::DB.new
15
+ require "webhookdb/tasks/docs"
16
+ Webhookdb::Tasks::Docs.new
17
+ require "webhookdb/tasks/fixture"
18
+ Webhookdb::Tasks::Fixture.new
19
+ require "webhookdb/tasks/release"
20
+ Webhookdb::Tasks::Release.new
21
+ require "webhookdb/tasks/message"
22
+ Webhookdb::Tasks::Message.new
23
+ require "webhookdb/tasks/regress"
24
+ Webhookdb::Tasks::Regress.new
25
+ require "webhookdb/tasks/sidekiq"
26
+ Webhookdb::Tasks::Sidekiq.new
27
+ require "webhookdb/tasks/specs"
28
+ Webhookdb::Tasks::Specs.new
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Webhookdb
4
- VERSION = "0.1.1"
4
+ VERSION = "1.0.1"
5
5
  end
data/lib/webhookdb.rb CHANGED
@@ -22,6 +22,17 @@ Money.locale_backend = :i18n
22
22
  Money.default_currency = "USD"
23
23
  Money.rounding_mode = BigDecimal::ROUND_HALF_UP
24
24
 
25
+ module Appydays::Configurable
26
+ def self.fetch_env(keys, default=:__keyerror, env: ENV)
27
+ keys = [keys] unless keys.respond_to?(:to_ary)
28
+ keys.to_ary.each do |k|
29
+ return env.fetch(k) if env.key?(k)
30
+ end
31
+ raise KeyError, "no key found in env: #{keys}" if default == :__keyerror
32
+ return default
33
+ end
34
+ end
35
+
25
36
  module Webhookdb
26
37
  include Appydays::Loggable
27
38
  include Appydays::Configurable
@@ -49,11 +60,15 @@ module Webhookdb
49
60
  class RegressionModeSkip < StandardError; end
50
61
 
51
62
  APPLICATION_NAME = "Webhookdb"
52
- RACK_ENV = ENV.fetch("RACK_ENV", "development")
53
- COMMIT = ENV.fetch("HEROKU_SLUG_COMMIT", "unknown-commit")
54
- RELEASE = ENV.fetch("HEROKU_RELEASE_VERSION", "unknown-release")
55
- RELEASE_CREATED_AT = ENV.fetch("HEROKU_RELEASE_CREATED_AT") { Time.at(0).utc.iso8601 }
63
+ RACK_ENV = Appydays::Configurable.fetch_env(["RACK_ENV", "RUBY_ENV"], "development")
64
+ COMMIT = Appydays::Configurable.fetch_env(["COMMIT", "GIT_SHA", "HEROKU_SLUG_COMMIT"], "00000000")
65
+ RELEASE = Appydays::Configurable.fetch_env(["RELEASE", "GIT_REF", "HEROKU_RELEASE_VERSION"], "unknown-release")
66
+ RELEASE_CREATED_AT = Appydays::Configurable.fetch_env(
67
+ ["RELEASE_CREATED_AT", "BUILT_AT", "HEROKU_RELEASE_CREATED_AT"],
68
+ Time.at(0).utc.iso8601,
69
+ )
56
70
  INTEGRATION_TESTS_ENABLED = ENV.fetch("INTEGRATION_TESTS", false)
71
+ require "webhookdb/version"
57
72
 
58
73
  DATA_DIR = Pathname(__FILE__).dirname.parent + "data"
59
74
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webhookdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - WebhookDB
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-08 00:00:00.000000000 Z
11
+ date: 2024-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '1.8'
111
+ - !ruby/object:Gem::Dependency
112
+ name: clipboard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.3'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.3'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: concurrent-ruby
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -810,6 +824,12 @@ files:
810
824
  - db/migrations/035_synchronous_backfill.rb
811
825
  - db/migrations/036_oauth.rb
812
826
  - db/migrations/037_oauth_used.rb
827
+ - integration/async_spec.rb
828
+ - integration/auth_spec.rb
829
+ - integration/database_spec.rb
830
+ - integration/helpers_spec.rb
831
+ - integration/service_integrations_spec.rb
832
+ - integration/system_spec.rb
813
833
  - lib/amigo/durable_job.rb
814
834
  - lib/pry/clipboard.rb
815
835
  - lib/sequel/advisory_lock.rb
@@ -974,6 +994,7 @@ files:
974
994
  - lib/webhookdb/postgres/testing_pixie.rb
975
995
  - lib/webhookdb/postgres/validations.rb
976
996
  - lib/webhookdb/postmark.rb
997
+ - lib/webhookdb/pry.rb
977
998
  - lib/webhookdb/redis.rb
978
999
  - lib/webhookdb/replicator.rb
979
1000
  - lib/webhookdb/replicator/atom_single_feed_v1.rb
@@ -1081,6 +1102,7 @@ files:
1081
1102
  - lib/webhookdb/stripe.rb
1082
1103
  - lib/webhookdb/subscription.rb
1083
1104
  - lib/webhookdb/sync_target.rb
1105
+ - lib/webhookdb/tasks.rb
1084
1106
  - lib/webhookdb/tasks/admin.rb
1085
1107
  - lib/webhookdb/tasks/annotate.rb
1086
1108
  - lib/webhookdb/tasks/db.rb