module PactBroker

Allow contracts to be accessed by name and configured/overridden for pf

The contract for the contract object in the publish contracts request

Formats a message string into application/problem+json format.

Builds the Hash that is passed into the Decorator as the ‘user_options`. It contains the request details, rack env, the (optional) title and anything else that is required by the decorator to render the resource (eg. the pacticipant that the versions belong to)

Decorates Dry::Validation::MessageSet Defaults to displaying validation errors, but the top level details may be overridden to display error responses for other HTTP statuses (eg. 409)

Decorates the individual validation error message Dry::Validation::Message

Formats a nested Hash of errors into the “old” Pact Broker errors format TODO: delete this in favour of problem+json in the next major version

Pactflow notes: This decorator was added for Pactflow, but we needed to change it so much that there is a separate class in pact_broker_fork/lib/pactflow/api/decorators/extended_pact_decorator.rb now and this one isn’t used.

TODO remove this class

Formats a message string into application/problem+json format.

Formats a nested Hash of errors, or an Array of Strings, into the “old” Pact Broker errors format TODO: delete this in favour of problem+json in the next major version

Allows the load-time configuration to be overridden on a per-request basis (for Pactflow)

Not exposed yet as we’d need to support administrator auth first

Logs the error Reports the error Generates and returns response headers and response body

Generates the response headers and body for use when there is a runtime error in the business logic (services and repositories) when executing a Webmachine resource request. Obfuscates any exception messages that might expose vulnerablities in production. Uses the Accept header to determine whether to return application/problem+json or application/hal+json, for backwards compatibility. In the next major version of the Pact Broker, all error responses should use problem+json, regardless of Accept headers.

Saves a block for execution after the HTTP response has been sent to the user. When the block is executed, it connects to the database before executing the code. This is good for doing things that might take a while and don’t have to be done before the response is sent, and don’t need retries (in which case, it might be better to use a SuckerPunch Job).

This leverages a feature of Puma which I’m not sure is meant to be public or not. There are serveral mentions of it on the internet, so I assume it’s ok to use it. Puma itself uses the rack.after_reply for http request logging.

github.com/search?q=repo%3Apuma%2Fpuma%20rack.after_reply&type=code

An array that provides the pagination details

Uses a Postgres advisory lock to ensure that a given block of code can only have ONE thread in excution at a time against a given database. When the database is not Postgres, the block will yield without any locks, allowing this class to be used safely with other database types, but without the locking functionality.

This is a wrapper around the actual implementation code in the Sequel extension from github.com/yuryroot/sequel-pg_advisory_lock which was copied into this codebase and modified for usage in this codebase.

See www.postgresql.org/docs/16/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS for docs on lock types

Populate the newly created contract_data_updated_at date in the integrations table using the latest created_at date from the pact_publications or verifications tables.

Not required now we have the auto_detect_main_branch feature

Data migrations run every time the broker starts up, after the schema migrations. Their purpose is to ensure that data integrity is maintained during rolling migrations in architectures with multiple application instances running against the same database (eg. EC2 autoscaling group) where “old” data might be inserted by the application instance running the previous version of the code AFTER the schema migrations have been run on the first application instance with the new version of the code.

This class most accurately represents a PactPublication

The Wisper implementation of temporary listeners clears all listeners at the end of the block, rather the just the ones that were supplied in block. This implementation just clears the specified ones, allowing multiple temporary overlapping listeners.

Listens for events that happen in the Pact Broker that are relevant to the Integrations objects.

Same as PactBroker::Matrix::MatrixRow except the data is sourced from the pact_publications table, and contains every pact publication, not just the latest publication for the consumer version. This is used when there is no “latestby” in the matrix query.

Represents the integration relationship between a consumer and a provider in the context of a matrix or can-i-deploy query. If the required flag is set, then one of the pacticipants specified in the matrix query is a consumer and it requires the provider to be already deployed. An integration would not be required if a provider was specified, and it had an integration with a consumer, but that consumer wasn’t deployed yet.

A Sequel model used for identifying potential and required integrations between the versions described by the specified selectors and other applications. It is only meant to be used via the public dataset methods.

A “find only” repository for the PactBroker::Matrix::Integration object. The PactBroker::Matrix::Integration object is not a Sequel Model like the PactBroker::Integrations::Integration - it is built from the matrix data specifically for a given matrix query, and as well as the consumer/provider attributes, it also knows whether or not that particular depdency is required in the context of the specific matrix query. eg. a HTTP consumer will always require that a provider is deployed, but a provider can be deployed if the consumer does not exist in the given environment yet. The “integrations for selectors” query is used to work out what what integrations are involved for a can-i-deploy query.

The PactBroker::Matrix::MatrixRow represents a row in the table that is created when the consumer versions are joined to the provider versions via the pacts and verifications tables, aka “The Matrix”. The difference between this class and the EveryRow class is that the EveryRow class includes results for overridden pact verisons and verifications (used only when there is no latestby set in the matrix query), where as the MatrixRow class only includes the latest pact for each consumer version, and the latest verification for each provider version.

The dataset methods used by both the MatrixRow and the EveryRow classes Requires the following methods to be defined on the model

- verification_dataset
- select_pact_columns_with_aliases
- select_all_columns_after_join

The instance methods

The dataset methods to be included in the MatrixRow::Verification dataset module and the EveryRow::Verification dataset module. Expects the method ‘select_verification_columns_with_aliases` to be defined on the class

A selector with the pacticipant id, name, version number, and version id set This is created from either specified or inferred data, based on the user’s query eg. can-i-deploy –pacticipant Foo –version 1 (this is a specified selector)

--to prod (this is used to create inferred selectors, one for each integrated pacticipant in that environment)

When an UnresolvedSelector specifies multiple application versions (eg. { tag: “prod” }) then a ResolvedSelector is created for every Version object found for the original selector.

Builds a PactBroker::Matrix::UnresolvedSelector based on the given UnresolvedSelector, selector type, Pacticipant and Version objects, using the selector_ignorer to work out if the built ResolvedSelector should be marked as ignored or not.

Builds the array of ResolvedSelector objects using the ignore selectors, the specified selectors, and the inferred integrations.

The only reason why we need to resolve the ignore selectors is that we check in PactBroker::Matrix::DeploymentStatusSummary whether or not the pacticipant or version they specify actually exist. We could actually have performed the ignore checks just using the name and version number.

Take the selectors and options provided by the user (eg. [{ pacticipant_name: “Foo”, pacticipant_version_number: “1” }], { to_environment: “prod” }) that use pacticipant/version/branch/environment names, and look up the IDs of all the objects, and return them as ResolvedSelector objects. For unresolved selectors that specify a collection of versions (eg. { branch: “main” }) a ResolvedSelector will be returned for every pacticipant version found. This will eventually be used in the can-i-deploy logic in PactBroker::Matrix::DeploymentStatusSummary to work out if there are any missing verifications.

A head pact is the pact for the latest consumer version with the specified tag (ignoring later versions that might have the specified tag but no pact)

All of these pacts have the same underlying pact_version_sha (content) No point verifying them multiple times, so squash all the relevant info into one “verifiable pact”

This task is used to clean up old data in a Pact Broker database to stop performance issues from slowing down responses when there is too much data. See docs.pact.io/pact_broker/administration/maintenance

require ‘pact_broker/tasks’

PactBroker::DB::DataMigrationTask.new do | task |

require 'my_app/db'
task.database_connection = MyApp::DB

end

require ‘pact_broker/tasks’

PactBroker::DB::MigrationTask.new do | task |

require 'my_app/db'
task.database_connection = MyApp::DB

end

require ‘pact_broker/tasks’

PactBroker::DB::VersionTask.new do | task |

require 'my_app/db'
task.database_connection = MyApp::DB

end

TODO handle 404 gracefully

Represents a non WIP, successful verification for a provider version with a tag.

The concept of “stale” (the pact used to be verified but then it changed and we haven’t got a new verification result yet) only really make sense if we’re trying to summarise the state of an integration or pseudo branch. Once we start showing multiple pacts for each integration (ie. the latest for each tag) then each pact version is either verified, or it’s not verified.

Represents the relationship between a webhook and the event and object that caused it to be triggered. eg a pact publication

Constants

CONSUMER_VERSION_HEADER
DO_NOT_ROLLBACK
INTEGRATIONS_TABLES
PACT_PARSING_OPTIONS
VERSION

Public Class Methods

build_api(application_context = PactBroker::ApplicationContext.default_application_context) click to toggle source

rubocop: disable Metrics/MethodLength

# File lib/pact_broker/api.rb, line 28
def self.build_api(application_context = PactBroker::ApplicationContext.default_application_context)
  Webmachine.build_rack_api(application_context) do |app|
    app.routes do
      add(["trace", :*], Webmachine::Trace::TraceResource) unless ENV["RACK_ENV"] == "production"

      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "versions"], Api::Resources::PactVersions, {resource_name: "pact_publications"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "versions", :consumer_version_number], Api::Resources::Pact, {resource_name: "pact_publication", deprecated: true} # Not the standard URL, but keep for backwards compatibility
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "tag", :tag], Api::Resources::TaggedPactVersions, {resource_name: "tagged_pact_publications"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "branch", :branch_name], Api::Resources::PactVersionsForBranch, {resource_name: "pact_publications_for_branch"}

      # Pacts
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "version", :consumer_version_number], Api::Resources::Pact, {resource_name: "pact_publication"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "pact-version", :pact_version_sha], Api::Resources::PactVersion, {resource_name: "pact_publication"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "pact-version", :pact_version_sha, "metadata", :metadata], Api::Resources::PactVersion, {resource_name: "pact_publication"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "version", :consumer_version_number, "previous-distinct"], Api::Resources::PreviousDistinctPactVersion, {resource_name: "previous_distinct_pact_version"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "version", :consumer_version_number, "diff", "previous-distinct"], Api::Resources::PactContentDiff, {resource_name: "previous_distinct_pact_version_diff"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "version", :consumer_version_number, "diff", "version", :comparison_consumer_version], Api::Resources::PactContentDiff, {resource_name: "pact_version_diff_by_consumer_version"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "pact-version", :pact_version_sha, "diff", "pact-version", :comparison_pact_version_sha], Api::Resources::PactContentDiff, {resource_name: "pact_version_diff_by_pact_version_sha"}

      # Verifications
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "pact-version", :pact_version_sha, "verification-results"], Api::Resources::Verifications, {resource_name: "verification_results"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "pact-version", :pact_version_sha, "metadata", :metadata, "verification-results"], Api::Resources::Verifications, {resource_name: "verification_results"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "version", :consumer_version_number, "verification-results", "latest"], Api::Resources::LatestVerificationForPact, {resource_name: "latest_verification_results_for_pact_publication"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "pact-version", :pact_version_sha, "verification-results", "latest"], Api::Resources::LatestVerificationForPact, {resource_name: "latest_verification_results_for_pact_version"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "pact-version", :pact_version_sha, "verification-results", :verification_number], Api::Resources::Verification, {resource_name: "verification_result"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "pact-version", :pact_version_sha, "metadata", :metadata, "verification-results", :verification_number], Api::Resources::Verification, {resource_name: "verification_result"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "pact-version", :pact_version_sha, "verification-results", :verification_number, "triggered-webhooks"], Api::Resources::VerificationTriggeredWebhooks, {resource_name: "verification_result_triggered_webhooks"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "latest", "verification-results","latest"], Api::Resources::LatestVerificationForLatestPact, {resource_name: "latest_verification_results_for_latest_pact_publication"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "latest", :tag, "verification-results","latest"], Api::Resources::LatestVerificationForLatestPact, {resource_name: "latest_verification_results_for_latest_tagged_pact_publication"}
      add ["verification-results", "consumer", :consumer_name, "version", :consumer_version_number,"latest"], Api::Resources::LatestVerificationsForConsumerVersion, {resource_name: "verification_results_for_consumer_version"}

      # Badges
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "latest", "badge"], Api::Resources::Badge, {resource_name: "latest_pact_badge"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "latest", :tag, "badge"], Api::Resources::Badge, {resource_name: "latest_tagged_pact_badge"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "latest-untagged", "badge"], Api::Resources::Badge, {resource_name: "latest_untagged_pact_badge", tag: :untagged}

      # Latest pacts
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "latest"], Api::Resources::LatestPact, {resource_name: "latest_pact_publication"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "latest", :tag], Api::Resources::LatestPact, {resource_name: "latest_tagged_pact_publication"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "branch", :branch_name, "latest"], Api::Resources::LatestPact, {resource_name: "latest_pact_publication_for_branch"}
      add ["pacts", "provider", :provider_name], Api::Resources::ProviderPacts, {resource_name: "provider_pact_publications"}
      add ["pacts", "provider", :provider_name, "tag", :tag], Api::Resources::ProviderPacts, {resource_name: "tagged_provider_pact_publications"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "latest-untagged"], Api::Resources::LatestPact, {resource_name: "latest_untagged_pact_publication", tag: :untagged}
      add ["pacts", "provider", :provider_name, "latest"], Api::Resources::LatestProviderPacts, {resource_name: "latest_provider_pact_publications"}
      add ["pacts", "provider", :provider_name, "latest", :tag], Api::Resources::LatestProviderPacts, {resource_name: "latest_tagged_provider_pact_publications"}
      add ["pacts", "latest"], Api::Resources::LatestPacts, {resource_name: "latest_pacts"}

      # Pacts for verification
      add ["pacts", "provider", :provider_name, "for-verification"], Api::Resources::ProviderPactsForVerification, {resource_name: "pacts_for_verification"}

      # Deprecated pact
      add ["pact", "provider", :provider_name, "consumer", :consumer_name, "version", :consumer_version_number], Api::Resources::Pact, {resource_name: "pact_publication", deprecated: "true"} # Deprecate, singular /pact
      add ["pact", "provider", :provider_name, "consumer", :consumer_name, "latest"], Api::Resources::LatestPact, {resource_name: "latest_pact_publications", deprecated: "true"}

      # Pacticipants
      add ["pacticipants"], Api::Resources::Pacticipants, {resource_name: "pacticipants"}
      add ["pacticipants", "label", :label_name], PactBroker::Api::Resources::PacticipantsForLabel, {resource_name: "pacticipants_for_label"}
      add ["pacticipants", :pacticipant_name], Api::Resources::Pacticipant, {resource_name: "pacticipant"}
      add ["pacticipants", :pacticipant_name, "labels", :label_name], Api::Resources::Label, {resource_name: "pacticipant_label"}

      # Labels
      add ["labels"], Api::Resources::Labels, {resource_name: "labels"}

      # Versions
      add ["pacticipants", :pacticipant_name, "versions"], Api::Resources::Versions, {resource_name: "pacticipant_versions"}
      add ["pacticipants", :pacticipant_name, "branches", :branch_name, "versions"], Api::Resources::BranchVersions, {resource_name: "pacticipant_branch_versions"}
      add ["pacticipants", :pacticipant_name, "versions", :pacticipant_version_number], Api::Resources::Version, {resource_name: "pacticipant_version"}
      add ["pacticipants", :pacticipant_name, "latest-version", :tag], Api::Resources::LatestVersion, {resource_name: "latest_tagged_pacticipant_version"}
      add ["pacticipants", :pacticipant_name, "latest-version", :tag, "can-i-deploy", "to", :to], Api::Resources::CanIDeployPacticipantVersionByTagToTag, { resource_name: "can_i_deploy_latest_tagged_version_to_tag" }
      add ["pacticipants", :pacticipant_name, "latest-version", :tag, "can-i-deploy", "to", :to, "badge"], Api::Resources::CanIDeployPacticipantVersionByTagToTagBadge, { resource_name: "can_i_deploy_latest_tagged_version_to_tag_badge" }
      add ["pacticipants", :pacticipant_name, "main-branch", "can-i-merge", "badge"], Api::Resources::CanIMergeBadge, { resource_name: "can_i_merge_badge" }
      add ["pacticipants", :pacticipant_name, "latest-version"], Api::Resources::LatestVersion, {resource_name: "latest_pacticipant_version"}
      add ["pacticipants", :pacticipant_name, "versions", :pacticipant_version_number, "tags", :tag_name], Api::Resources::Tag, {resource_name: "pacticipant_version_tag"}
      add ["pacticipants", :pacticipant_name, "branches"], Api::Resources::PacticipantBranches, {resource_name: "pacticipant_branches"}
      add ["pacticipants", :pacticipant_name, "branches", :branch_name], Api::Resources::Branch, { resource_name: "branch" }
      add ["pacticipants", :pacticipant_name, "branches", :branch_name, "latest-version"], Api::Resources::LatestVersion, { resource_name: "latest_pacticipant_version_for_branch" }
      add ["pacticipants", :pacticipant_name, "branches", :branch_name, "versions", :version_number], Api::Resources::BranchVersion, { resource_name: "branch_version" }
      add ["pacticipants", :pacticipant_name, "branches", :branch_name, "latest-version", "can-i-deploy", "to-environment", :environment_name], Api::Resources::CanIDeployPacticipantVersionByBranchToEnvironment, { resource_name: "can_i_deploy_latest_branch_version_to_environment" }
      add ["pacticipants", :pacticipant_name, "branches", :branch_name, "latest-version", "can-i-deploy", "to-environment", :environment_name, "badge"], Api::Resources::CanIDeployPacticipantVersionByBranchToEnvironmentBadge, { resource_name: "can_i_deploy_latest_branch_version_to_environment_badge" }

      # Webhooks
      add ["webhooks", "provider", :provider_name, "consumer", :consumer_name ], Api::Resources::PacticipantWebhooks, {resource_name: "pacticipant_webhooks"}
      add ["webhooks", "provider", :provider_name], Api::Resources::PacticipantWebhooks, {resource_name: "provider_webhooks"}
      add ["webhooks", "consumer", :consumer_name], Api::Resources::PacticipantWebhooks, {resource_name: "consumer_webhooks"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "webhooks"], Api::Resources::PactWebhooks, {resource_name: "pact_webhooks"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "webhooks", "status"], Api::Resources::PactWebhooksStatus, {resource_name: "pact_webhooks_status"}
      add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "version", :consumer_version_number, "triggered-webhooks"], Api::Resources::PactTriggeredWebhooks, {resource_name: "pact_triggered_webhooks"}

      add ["webhooks", "execute" ], Api::Resources::WebhookExecution, {resource_name: "execute_unsaved_webhook"}
      add ["webhooks", :uuid ], Api::Resources::Webhook, {resource_name: "webhook"}
      add ["triggered-webhooks", :uuid, "logs" ], Api::Resources::TriggeredWebhookLogs, { resource_name: "triggered_webhook_logs" }
      add ["webhooks", :uuid, "execute" ], Api::Resources::WebhookExecution, {resource_name: "execute_webhook"}
      add ["webhooks"], Api::Resources::AllWebhooks, {resource_name: "webhooks"}

      add ["relationships"], Api::Resources::Relationships, {resource_name: "relationships"}
      add ["groups", :pacticipant_name], Api::Resources::Group, {resource_name: "group"}

      # matrix
      add ["matrix", "provider", :provider_name, "consumer", :consumer_name], Api::Resources::MatrixForConsumerAndProvider, {resource_name: "matrix_consumer_provider"}
      add ["matrix", "provider", :provider_name, "latest", :provider_tag, "consumer", :consumer_name, "latest", :tag, "badge"], Api::Resources::MatrixBadge, {resource_name: "matrix_tag_badge"}
      add ["matrix"], Api::Resources::Matrix, {resource_name: "matrix"}
      add ["can-i-deploy"], Api::Resources::CanIDeploy, {resource_name: "can_i_deploy"}

      add ["dashboard"], Api::Resources::Dashboard, {resource_name: "dashboard"}
      add ["dashboard", "provider", :provider_name, "consumer", :consumer_name ], Api::Resources::Dashboard, {resource_name: "integration_dashboard"}
      add ["test","error"], Api::Resources::ErrorTest, {resource_name: "error_test"}

      add ["contracts", "publish"], Api::Resources::PublishContracts, { resource_name: "publish_contracts" }

      add ["environments"], Api::Resources::Environments, { resource_name: "environments" }
      add ["environments", :environment_uuid], Api::Resources::Environment, { resource_name: "environment" }
      add ["environments", :environment_uuid, "deployed-versions", "currently-deployed"], Api::Resources::CurrentlyDeployedVersionsForEnvironment, { resource_name: "environment_currently_deployed_deployed_versions" }
      add ["environments", :environment_uuid, "released-versions", "currently-supported"], Api::Resources::CurrentlySupportedVersionsForEnvironment, { resource_name: "environment_currently_supported_released_versions" }
      add ["pacticipants", :pacticipant_name, "versions", :pacticipant_version_number, "deployed-versions", "environment", :environment_uuid], Api::Resources::DeployedVersionsForVersionAndEnvironment, { resource_name: "deployed_versions_for_version_and_environment" }
      add ["pacticipants", :pacticipant_name, "versions", :pacticipant_version_number, "released-versions", "environment", :environment_uuid], Api::Resources::ReleasedVersionsForVersionAndEnvironment, { resource_name: "released_versions_for_version_and_environment" }
      add ["released-versions", :uuid], Api::Resources::ReleasedVersion, { resource_name: "released_version" }
      add ["deployed-versions", :uuid], Api::Resources::DeployedVersion, { resource_name: "deployed_version" }

      add ["integrations"], Api::Resources::Integrations, {resource_name: "integrations"}
      add ["integrations", "provider", :provider_name, "consumer", :consumer_name], Api::Resources::Integration, {resource_name: "integration"}
      add ["metrics"], Api::Resources::Metrics, {resource_name: "metrics"}
      add [], Api::Resources::Index, {resource_name: "index"}
    end
  end
end
configuration() click to toggle source
# File lib/pact_broker/configuration.rb, line 10
def self.configuration
  RequestStore.store[:pact_broker_configuration] ||= Configuration.default_configuration
end
configure_connection(connection, connection_validation_timeout, enable_caller_logging) click to toggle source

Sequel by default does not test connections in its connection pool before handing them to a client. To enable connection testing you need to load the “connection_validator” extension like below. The connection validator extension is configurable, by default it only checks connections once per hour:

sequel.rubyforge.org/rdoc-plugins/files/lib/sequel/extensions/connection_validator_rb.html

A gotcha here is that it is not enough to enable the “connection_validator” extension, we also need to specify that we want to use the threaded connection pool, as noted in the documentation for the extension.

-1 means that connections will be validated every time, which avoids errors when databases are restarted and connections are killed. This has a performance penalty, so consider increasing this timeout if building a frequently accessed service.

# File lib/pact_broker/initializers/database_connection.rb, line 76
                     def self.configure_connection(connection, connection_validation_timeout, enable_caller_logging)
  connection.extension(:connection_validator)
  connection.extension(:caller_logging) if enable_caller_logging
  connection.pool.connection_validation_timeout = connection_validation_timeout if connection_validation_timeout
  connection
end
configure_logger(sequel_config, logger) click to toggle source
# File lib/pact_broker/initializers/database_connection.rb, line 50
                     def self.configure_logger(sequel_config, logger)
  if sequel_config[:sql_log_level] == :none
    sequel_config.delete(:sql_log_level)
  elsif logger
    sequel_config[:logger] = PactBroker::DB::LogQuietener.new(logger)
  end
end
create_database_connection(config, logger = nil) click to toggle source
# File lib/pact_broker/initializers/database_connection.rb, line 6
def self.create_database_connection(config, logger = nil)
  logger&.info("Connecting to database:", config.merge(password: "*****"))

  sequel_config = config.dup
  max_retries = sequel_config.delete(:connect_max_retries) || 0
  connection_validation_timeout = config.delete(:connection_validation_timeout)
  enable_caller_logging = config.delete(:enable_caller_logging)
  configure_logger(sequel_config, logger)
  create_sqlite_database_dir(config)

  connection = with_retries(max_retries, logger) do
    Sequel.connect(sequel_config)
  end

  logger&.info "Connected to database #{sequel_config[:database]}"

  configure_connection(connection, connection_validation_timeout, enable_caller_logging)
end
create_sqlite_database_dir(config) click to toggle source
# File lib/pact_broker/initializers/database_connection.rb, line 43
                     def self.create_sqlite_database_dir(config)
  if config[:adapter] == "sqlite" && config[:database] && !File.exist?(File.dirname(config[:database]))
    logger&.info "Creating directory #{File.expand_path(File.dirname(config[:database]))} for Sqlite database"
    FileUtils.mkdir_p(File.dirname(config[:database]))
  end
end
feature_enabled?(feature, ignore_env = false) click to toggle source
# File lib/pact_broker/feature_toggle.rb, line 22
def self.feature_enabled?(feature, ignore_env = false)
  FeatureToggle.enabled?(feature, ignore_env)
end
policy!(*args) click to toggle source
# File lib/pact_broker/policies.rb, line 46
def self.policy!(*args)
  PactBroker.configuration.policy_builder.call(*args)
end
policy_scope!(*args) click to toggle source
# File lib/pact_broker/policies.rb, line 50
def self.policy_scope!(*args)
  PactBroker.configuration.policy_scope_builder.call(*args)
end
project_root() click to toggle source
# File lib/pact_broker/project_root.rb, line 4
def self.project_root
  @project_root ||= Pathname.new(File.expand_path("../../../",__FILE__)).freeze
end
reset_configuration() click to toggle source

@private, for testing only

# File lib/pact_broker/configuration.rb, line 19
def self.reset_configuration
  RequestStore.store[:pact_broker_configuration] = Configuration.default_configuration
end
routes() click to toggle source
# File lib/pact_broker/api.rb, line 159
def self.routes
  require "webmachine/describe_routes"
  @routes ||= Webmachine::DescribeRoutes.call([API.application])
end
set_configuration(configuration) click to toggle source
# File lib/pact_broker/configuration.rb, line 14
def self.set_configuration(configuration)
  RequestStore.store[:pact_broker_configuration] = configuration
end
with_retries(max_retries, logger) { || ... } click to toggle source
# File lib/pact_broker/initializers/database_connection.rb, line 25
                     def self.with_retries(max_retries, logger)
  tries = 0
  max_tries = max_retries + 1
  wait = 3

  begin
    yield
  rescue StandardError => e
    if (tries += 1) < max_tries
      logger&.info "Error connecting to database (#{e.class}). Waiting #{wait} seconds and trying again. #{max_tries-tries} tries to go."
      sleep wait
      retry
    else
      raise e
    end
  end
end