Skip to content

Commit

Permalink
Merge branch 'master' into feat/chore-delete-branch-and-associated-ve…
Browse files Browse the repository at this point in the history
…rsions
  • Loading branch information
bethesque authored Aug 20, 2024
2 parents e644cb2 + e84de4f commit 2aa1974
Show file tree
Hide file tree
Showing 172 changed files with 2,631 additions and 617 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release_gem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Notify ${{ matrix.repository }} of gem release
uses: peter-evans/repository-dispatch@v2
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.GHTOKENNOTIFYPBRELEASED }}
repository: ${{ matrix.repository }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/trigger_pact_docs_update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Trigger docs.pact.io update workflow
uses: peter-evans/repository-dispatch@v2
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.GHTOKENFORTRIGGERINGPACTDOCSUPDATE }}
repository: pact-foundation/docs.pact.io
Expand Down
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.2
3.2.4
106 changes: 106 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,109 @@
<a name="v2.111.0"></a>
### v2.111.0 (2024-07-26)

#### Features

* add new label api (#703) ([ff3f84e2](/../../commit/ff3f84e2))
* search pacticipants by display_name ([c5945801](/../../commit/c5945801))

#### Bug Fixes

* **docs**
* Update OAS with correct ref to Notice schema ([6729b7f8](/../../commit/6729b7f8))

<a name="v2.110.0"></a>
### v2.110.0 (2024-04-02)

#### Features

* reduce contention when updating the contract_data_updated_at field for integrations (#671) ([ff72d03c](/../../commit/ff72d03c))
* support consumer version selector for all branches (#667) ([34334ca8](/../../commit/34334ca8))

* **clean**
* use postgres advisory locks to ensure only one process can run a clean at a time (#672) ([637c25fa](/../../commit/637c25fa))

#### Bug Fixes

* use for_all_tag_heads instead of latest_by_consumer_tag when fetching wip by branch ([14148a34](/../../commit/14148a34))
* optimise WIP pacts by using branch/tag heads (#668) ([871209e1](/../../commit/871209e1))
* improve performance of WIP pacts by using branch heads instead of calculating latest pact for branch ([f9705583](/../../commit/f9705583))

<a name="v2.109.1"></a>
### v2.109.1 (2024-02-21)

#### Bug Fixes

* improve performance for 'pacts for verification' queries ([299a6abe](/../../commit/299a6abe))
* correct spelling in message when pact is modified ([ae62ae7a](/../../commit/ae62ae7a))

<a name="v2.109.0"></a>
### v2.109.0 (2024-02-01)

#### Features

* use SemanticLogger for Padrino (#662) ([5d9d7002](/../../commit/5d9d7002))
* improve performance of publication for very large pacts by calculating the content SHA only once per request ([a947e409](/../../commit/a947e409))

#### Bug Fixes

* pass in environment to environment policy when getting an individual environment ([5c386a43](/../../commit/5c386a43))
* Dockerfile to reduce vulnerabilities (#650) ([9aaa3484](/../../commit/9aaa3484))

<a name="v2.108.0"></a>
### v2.108.0 (2024-01-05)

#### Features

* bulk delete branches (#652) ([14ac33c8](/../../commit/14ac33c8))
* add latest version for branch endpoint (#644) ([c216bec8](/../../commit/c216bec8))
* add no-cache header ([9a637327](/../../commit/9a637327))
* suppport `page` + `size` as pagination params (#642) ([c71089fe](/../../commit/c71089fe))
* do not include pb:record-deployment or pb:record-release relations for versions embedded in resources ([2f43590c](/../../commit/2f43590c))
* remove status from individual error in problem+error response ([a4b3ec58](/../../commit/a4b3ec58))
* add version_id indexes to deployed_versions and released_versions ([00fc7d10](/../../commit/00fc7d10))
* add endpoint to list branches for a pacticipant (#638) ([ff7e3a53](/../../commit/ff7e3a53))
* stop running tests for ruby 2.7 ([034aba3b](/../../commit/034aba3b))
* update sinatra and rack-protection to ~> 3.0 ([92ebbdd3](/../../commit/92ebbdd3))
* add branch endpoint supporting GET and DELETE (#635) ([1bb6088d](/../../commit/1bb6088d))
* optimise matrix by applying specified limit to pact publications before joining to verifications ([c61c324e](/../../commit/c61c324e))
* optimise matrix query when selectors with pacticipant names only are used ([b98f5d1a](/../../commit/b98f5d1a))
* include environment name in pact metadata ([e120c4e7](/../../commit/e120c4e7))
* improve wording of 'no version exits' messaging in can-i-deploy response ([9529c679](/../../commit/9529c679))
* improve performance of matrix when multiple selectors are specified (#631) ([58a28604](/../../commit/58a28604))
* add pagination parameter validation for paginated endpoints. (#626) ([abb0a1c6](/../../commit/abb0a1c6))
* add endpoint to list pacticipant versions by branch ([9b4e3f61](/../../commit/9b4e3f61))
* add endpoint to return latest pact for consumer, provider and consumer branch ([f77086ef](/../../commit/f77086ef))
* update required ruby version from 2.2 to 2.7 ([f1b1e906](/../../commit/f1b1e906))
* add pagination and filtering for integrations endpoint ([68d7cf30](/../../commit/68d7cf30))
* add contract_data_updated_at to integrations table to speed up dashboard query (#617) ([e43c10f2](/../../commit/e43c10f2))
* support setting feature toggles via individual environment variables (#609) ([be7d9d52](/../../commit/be7d9d52))

* **metrics**
* hardcode matrix count to -1 as calculating it causes performance issues and it has no meaning ([62e121b8](/../../commit/62e121b8))

* **matrix**
* optimise identification of the 'latest tag' ([824c516a](/../../commit/824c516a))

#### Bug Fixes

* **metrics**
* correct the query for pactRevisionsPerConsumerVersion ([f76b9935](/../../commit/f76b9935))

* fix performance issues due to contention in the integrations table when publishing a large number of contracts (> 20) per request, in parallel (#654) ([321a2291](/../../commit/321a2291))
* raise 404 on paths with missing path segments (#648) ([930b45cd](/../../commit/930b45cd))
* do not error when no environment is found by name ([d1501618](/../../commit/d1501618))
* ensure pact associations are eager loaded when finding a single pact ([c98abda6](/../../commit/c98abda6))
* gracefully handle validating an array when a hash is expected ([b26ddb46](/../../commit/b26ddb46))
* fix error occuring when can-i-deploy badge is requested and no version is found ([db7dee3a](/../../commit/db7dee3a))
* fix bug in error handling for 'can-i-deploy branch to environment' badge ([c23beb6b](/../../commit/c23beb6b))
* improve performance of network diagram (#614) ([ffd3ec4b](/../../commit/ffd3ec4b))
* fix error raised when attempting to log warning when webhook_redact_sensitive_data is set to false ([9b66270e](/../../commit/9b66270e))
* gracefully handle execution of webhooks that are deleted between execution attempts (#613) ([1127b41f](/../../commit/1127b41f))
* add extra validation to ensure parsed content is a hash when publishing pacts ([913e0a52](/../../commit/913e0a52))

* **matrix**
* return only most recent row missing verification when latestby=cp ([b7550e53](/../../commit/b7550e53))

<a name="v2.107.1"></a>
### v2.107.1 (2023-05-02)

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ruby:3.2.1-alpine3.17
FROM ruby:3.2.4-alpine3.18

WORKDIR /home

Expand Down
2 changes: 0 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ source "https://rubygems.org"

gemspec

# While https://github.com/brandonhilkert/sucker_punch/pull/253 is outstanding
gem "sucker_punch", git: "https://github.com/pact-foundation/sucker_punch.git", ref: "fix/rename-is-singleton-class-method-2"

gem "rake", "~>12.3.3"
gem "sqlite3", "~>1.3"
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
[![Gem Version](https://badge.fury.io/rb/pact_broker.svg)](http://badge.fury.io/rb/pact_broker)
![Build status](https://github.com/pact-foundation/pact_broker/workflows/Test/badge.svg)
[![Join the chat at https://pact-foundation.slack.com/](https://img.shields.io/badge/chat-on%20slack-blue.svg?logo=slack)](https://slack.pact.io)
[![security](https://hakiri.io/github/pact-foundation/pact_broker/master.svg)](https://hakiri.io/github/pact-foundation/pact_broker/master)

The Pact Broker is an application for sharing of consumer driven contracts and verification results. It is optimised for use with "pacts" (contracts created by the [Pact][pact-docs] framework), but can be used for any type of contract that can be serialized to JSON.

Expand Down Expand Up @@ -151,7 +150,7 @@ You can use the [Pact Broker Docker image][docker] or [Terraform on AWS][terrafo

* Are you sure you don't just want to use the [Pact Broker Docker image][docker]? No Docker at your company yet? Ah well, keep reading.
* Create a PostgreSQL database.
* To ensure you're on a supported version of the database that you choose, check the [travis.yml][travisyml] file to see which versions we're currently running our tests against.
* To ensure you're on a supported version of the database that you choose, check the [.github/workflows/test.yml](.github/workflows/test.yml) file to see which versions we're currently running our tests against.
* MySQL was supported for the native Ruby application until around 2021, but the official `pactfoundation/pact-broker` Docker image does not support it. New features will not be optimised for MySQL, and some new features may not even be supported on it (eg. the database clean feature).
* You'll find a sample database creation script in the [example/config.ru](https://github.com/pact-foundation/pact_broker/blob/master/example/config.ru).
* Install ruby 2.7 and the latest version of bundler (if you've come this far, I'm assuming you know how to do both of these. Did I mention there was a [Docker][docker] image?)
Expand Down
2 changes: 1 addition & 1 deletion docker-compose-dev-postgres.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ services:
- ./Rakefile:/home/Rakefile

shell:
image: ruby:2.5.3-alpine
image: ruby:3.2.4-alpine
depends_on:
- pact-broker
entrypoint: /bin/sh
Expand Down
23 changes: 23 additions & 0 deletions docs/developer/design_pattern_for_eager_loading_collections.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Design pattern for eager loading collections

For collection resources (eg. `/versions` ), associations included in the items (eg. branch versions) must be eager loaded for performance reasons.

The responsiblities of each class used to render a collection resource are as follows:

* collection decorator (eg. `VersionsDecorator`) - delegate each item in the collection to be rendered by the decorator for the individual item, render pagination links
* item decorator (eg. `VersionDecorator`) - render the JSON for each item
* resource (eg. `PactBroker::Api::Resources::Versions`) - coordinate between, and delegate to, the service and the decorator
* service (eg. `PactBroker::Versions::Service`) - just delegate to repository, as there is no business logic required
* repository (eg. `PactBroker::Versions::Repository`) - load the domain objects from the database

If the associations for a model are not eager loaded, then each individual association will be lazy loaded when the decorator for the item calls the association method to render it. This results in at least `<number of items in the collection> * <number of associations to render>` calls to the database, and potentially more if any of the associations have their own associations that are required to render the item. This can cause significant performance issues.

To efficiently render a collection resource, associations must be eager loaded when the collection items are loaded from the database in the repository. Since the repository method for loading the collection may be used in multiple places, and the eager loaded associations required for each of those places may be different (some may not require any associations to be eager loaded), we do not want to hard code the repository to load a fixed set of associations. The list of associations to eager load is therefore passed in to the repository finder method as an argument `eager_load_associations`.

The decorator is the class that knows what associations are going to be called on the model to render the JSON, so following the design guideline of "put things together that change together", the best place for the declaration of "what associations should be eager loaded for this decorator" is in the decorator itself. The `PactBroker::Api::Decorators::BaseDecorator` has a default implementation of this method called `eager_load_associations` which attempts to automatically identify the required associations, but this can be overridden when necessary.

We can therefore add the following responsiblities to our previous list:

* item decorator - return a list of all the associations (including nested associations) that should be eager loaded in order to render its item
* repository - eager load the associations that have been passed into it
* resource - pass in the eager load associations to the repository from the decorator
File renamed without changes.
11 changes: 11 additions & 0 deletions docs/developer/rack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Rack

https://medium.com/quick-code/rack-middleware-vs-rack-application-vs-rack-the-gem-vs-rack-the-architecture-912cd583ed24
https://github.com/rack/rack/blob/main/SPEC.rdoc
https://www.rubyguides.com/2018/09/rack-middleware/


* Responds to `call`
* Accepts a hash of parameters
* Returns an array where the first item is the http status, the second is a hash of headers, and the third is an object that responds to `each` (or `call`) that provides the body (99% of the time it's an array of length 1 with a string)

1 change: 0 additions & 1 deletion example/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ gem "pact_broker" # Would pin this to a known minor version when using properly
gem "puma", "~> 5.3" # Can be replaced with your choice of application server
gem "sqlite3", "~>1.3" # Sqlite is just for testing. Replace this with "pg" for production.
# gem "pg" # Production database gem
gem "sucker_punch", git: "https://github.com/pact-foundation/sucker_punch.git", ref: "fix/rename-is-singleton-class-method-2"
6 changes: 5 additions & 1 deletion lib/pact_broker/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
require "pact_broker/api/contracts"
require "pact_broker/application_context"
require "pact_broker/feature_toggle"
require "pact_broker/initializers/subscriptions"

module Webmachine
class Request
Expand Down Expand Up @@ -86,17 +85,22 @@ def self.build_api(application_context = PactBroker::ApplicationContext.default_
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" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class ConsumerVersionSelectorContract < BaseContract
json do
optional(:mainBranch).filled(included_in?: [true])
optional(:tag).filled(:str?)
optional(:branch).filled(:str?)
optional(:branch).filled { str? | eql?(true) }
optional(:matchingBranch).filled(included_in?: [true])
optional(:latest).filled(included_in?: [true, false])
optional(:fallbackTag).filled(:str?)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ module Api
module Contracts
class PaginationQueryParamsSchema < BaseContract
params do
# legacy format
optional(:pageNumber).maybe(:integer).value(gteq?: 1)
optional(:pageSize).maybe(:integer).value(gteq?: 1)

# desired format
optional(:page).maybe(:integer).value(gteq?: 1)
optional(:size).maybe(:integer).value(gteq?: 1)
end
end
end
Expand Down
12 changes: 10 additions & 2 deletions lib/pact_broker/api/decorators/base_decorator.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
require "roar/decorator"
require "roar/json/hal"
require "pact_broker/api/pact_broker_urls"
require "pact_broker/api/decorators/decorator_context"
require "pact_broker/api/decorators/format_date_time"
require "pact_broker/string_refinements"
require "pact_broker/hash_refinements"
Expand Down Expand Up @@ -35,7 +34,16 @@ def self.property(name, options={}, &block)
end
end

# Returns the names of the model associations to eager load for use with this decorator
# Returns the names of the model associations to eager load for use with this decorator.
# The default implementation attempts to do an "auto detect" of the associations.
# For single item decorators, it attempts to identify the attributes that are themselves models.
# For collection decorators, it delegates to the eager_load_associations
# method of the single item decorator used to decorate the collection.
#
# The "auto detect" logic can only go so far. It cannot identify when a child object needs its own
# child object(s) to render the attribute.
# This method should be overridden when the "auto detect" logic cannot identify the correct associations
# to load. eg VersionDecorator
# @return [Array<Symbol>]
def self.eager_load_associations
if is_collection_resource?
Expand Down
2 changes: 1 addition & 1 deletion lib/pact_broker/api/decorators/branch_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class BranchDecorator < BaseDecorator
link "pb:latest-version" do | user_options |
{
title: "Latest version for branch",
href: branch_versions_url(represented, user_options.fetch(:base_url)) + "?pageSize=1"
href: latest_version_for_branch_url(represented, user_options.fetch(:base_url))
}
end

Expand Down
Loading

0 comments on commit 2aa1974

Please sign in to comment.