webhookdb 0.1.1 → 1.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 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