pact_broker 2.85.0 → 2.88.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/trigger_pact_docs_update.yml +22 -0
- data/CHANGELOG.md +67 -0
- data/DEVELOPER_DOCUMENTATION.md +0 -2
- data/db/migrations/20210914_add_labels_to_webhooks.rb +14 -0
- data/db/migrations/20210915_add_verified_by_to_verification.rb +6 -0
- data/db/migrations/20210929_increase_event_context_column_size.rb +14 -0
- data/docker-compose-ci-mysql.yml +1 -0
- data/docker-compose-test.yml +2 -0
- data/docs/CONFIGURATION.md +255 -66
- data/docs/api/WEBHOOKS.md +789 -0
- data/docs/configuration.yml +166 -101
- data/lib/db.rb +0 -1
- data/lib/pact/doc/interaction_view_model.rb +2 -2
- data/lib/pact/doc/markdown/consumer_contract_renderer.rb +1 -1
- data/lib/pact_broker/api/contracts/configuration.rb +33 -0
- data/lib/pact_broker/api/contracts/publish_contracts_schema.rb +35 -16
- data/lib/pact_broker/api/contracts/webhook_contract.rb +24 -2
- data/lib/pact_broker/api/decorators/matrix_decorator.rb +3 -1
- data/lib/pact_broker/api/decorators/pact_decorator.rb +12 -0
- data/lib/pact_broker/api/decorators/verification_decorator.rb +9 -3
- data/lib/pact_broker/api/decorators/webhook_decorator.rb +27 -4
- data/lib/pact_broker/api/pact_broker_urls.rb +30 -6
- data/lib/pact_broker/api/resources/all_webhooks.rb +2 -2
- data/lib/pact_broker/api/resources/default_base_resource.rb +5 -1
- data/lib/pact_broker/api/resources/environment.rb +4 -4
- data/lib/pact_broker/api/resources/environments.rb +1 -1
- data/lib/pact_broker/api/resources/index.rb +7 -1
- data/lib/pact_broker/api/resources/metadata_resource_methods.rb +33 -3
- data/lib/pact_broker/api/resources/pact_version.rb +4 -0
- data/lib/pact_broker/api/resources/previous_distinct_pact_version.rb +1 -1
- data/lib/pact_broker/api/resources/publish_contracts.rb +1 -1
- data/lib/pact_broker/api/resources/verification.rb +5 -2
- data/lib/pact_broker/api/resources/webhook_execution.rb +7 -3
- data/lib/pact_broker/api/resources/webhook_execution_methods.rb +23 -17
- data/lib/pact_broker/api.rb +6 -0
- data/lib/pact_broker/application_context.rb +5 -0
- data/lib/pact_broker/config/runtime_configuration.rb +4 -0
- data/lib/pact_broker/config/runtime_configuration_database_methods.rb +1 -1
- data/lib/pact_broker/db/clean.rb +1 -2
- data/lib/pact_broker/db/delete_overwritten_data.rb +41 -23
- data/lib/pact_broker/deployments/deployed_version.rb +1 -0
- data/lib/pact_broker/deployments/deployed_version_service.rb +1 -0
- data/lib/pact_broker/deployments/environment_service.rb +7 -2
- data/lib/pact_broker/deployments/released_version_service.rb +1 -0
- data/lib/pact_broker/doc/controllers/app.rb +1 -0
- data/lib/pact_broker/doc/views/can-i-deploy.markdown +2 -1
- data/lib/pact_broker/doc/views/index/publish-contracts.markdown +38 -9
- data/lib/pact_broker/doc/views/pacticipant/label.markdown +12 -0
- data/lib/pact_broker/doc/views/provider-pacts-for-verification.markdown +7 -7
- data/lib/pact_broker/doc/views/webhooks.markdown +17 -0
- data/lib/pact_broker/domain/index_item.rb +9 -0
- data/lib/pact_broker/domain/pacticipant.rb +4 -0
- data/lib/pact_broker/domain/verification.rb +19 -4
- data/lib/pact_broker/domain/webhook.rb +5 -5
- data/lib/pact_broker/domain/webhook_pacticipant.rb +6 -0
- data/lib/pact_broker/index/service.rb +4 -4
- data/lib/pact_broker/locale/en.yml +4 -1
- data/lib/pact_broker/matrix/head_row.rb +1 -1
- data/lib/pact_broker/matrix/parse_can_i_deploy_query.rb +5 -3
- data/lib/pact_broker/matrix/quick_row.rb +0 -1
- data/lib/pact_broker/matrix/repository.rb +0 -1
- data/lib/pact_broker/matrix/row.rb +2 -2
- data/lib/pact_broker/pacticipants/repository.rb +1 -1
- data/lib/pact_broker/pacts/latest_pact_publication_id_for_consumer_version.rb +0 -1
- data/lib/pact_broker/pacts/metadata.rb +7 -1
- data/lib/pact_broker/pacts/pact_publication.rb +7 -0
- data/lib/pact_broker/pacts/pact_publication_clean_selector_dataset_module.rb +19 -0
- data/lib/pact_broker/pacts/pact_publication_dataset_module.rb +30 -2
- data/lib/pact_broker/pacts/pact_version.rb +24 -1
- data/lib/pact_broker/pacts/pacts_for_verification_repository.rb +5 -4
- data/lib/pact_broker/pacts/repository.rb +50 -47
- data/lib/pact_broker/pacts/service.rb +5 -5
- data/lib/pact_broker/string_refinements.rb +1 -1
- data/lib/pact_broker/test/http_test_data_builder.rb +40 -10
- data/lib/pact_broker/test/test_data_builder.rb +28 -5
- data/lib/pact_broker/ui/helpers/url_helper.rb +12 -0
- data/lib/pact_broker/ui/view_models/index_item.rb +15 -1
- data/lib/pact_broker/ui/view_models/index_item_branch_head.rb +39 -0
- data/lib/pact_broker/ui/view_models/index_item_provider_branch_head.rb +39 -0
- data/lib/pact_broker/ui/views/dashboard/show.haml +14 -7
- data/lib/pact_broker/verifications/repository.rb +5 -2
- data/lib/pact_broker/verifications/service.rb +7 -4
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/versions/abbreviate_number.rb +8 -4
- data/lib/pact_broker/versions/branch_head.rb +0 -2
- data/lib/pact_broker/versions/branch_version.rb +1 -0
- data/lib/pact_broker/versions/repository.rb +0 -1
- data/lib/pact_broker/webhooks/event_listener.rb +4 -2
- data/lib/pact_broker/webhooks/pact_and_verification_parameters.rb +18 -3
- data/lib/pact_broker/webhooks/repository.rb +10 -4
- data/lib/pact_broker/webhooks/trigger_service.rb +1 -1
- data/lib/pact_broker/webhooks/webhook.rb +71 -8
- data/lib/webmachine/describe_routes.rb +62 -0
- data/public/stylesheets/index.css +5 -0
- data/script/data/auto-create-things-for-tags.rb +1 -0
- data/script/data/branches.rb +1 -1
- data/script/data/contract-published-requiring-verification.rb +0 -1
- data/script/data/verify-pact-for-multiple-selectors.rb +30 -0
- data/script/docs/generate-api-docs.rb +117 -0
- data/script/docs/generate-configuration-docs.rb +24 -3
- data/script/docs/regenerate-api-docs.sh +11 -0
- data/script/generate-erd +55 -0
- data/spec/features/create_webhook_spec.rb +55 -10
- data/spec/features/get_pact_spec.rb +2 -3
- data/spec/fixtures/approvals/docs_webhooks_executing_a_saved_webhook_options.approved.json +20 -0
- data/spec/fixtures/approvals/docs_webhooks_executing_a_saved_webhook_post.approved.json +43 -0
- data/spec/fixtures/approvals/docs_webhooks_executing_an_unsaved_webhook_options.approved.json +20 -0
- data/spec/fixtures/approvals/docs_webhooks_executing_an_unsaved_webhook_post.approved.json +63 -0
- data/spec/fixtures/approvals/docs_webhooks_logs_of_triggered_webhook_get.approved.json +20 -0
- data/spec/fixtures/approvals/docs_webhooks_logs_of_triggered_webhook_options.approved.json +20 -0
- data/spec/fixtures/approvals/docs_webhooks_pact_webhooks_get.approved.json +45 -0
- data/spec/fixtures/approvals/docs_webhooks_pact_webhooks_options.approved.json +20 -0
- data/spec/fixtures/approvals/docs_webhooks_triggered_webhooks_for_pact_publication_get.approved.json +52 -0
- data/spec/fixtures/approvals/docs_webhooks_triggered_webhooks_for_pact_publication_options.approved.json +20 -0
- data/spec/fixtures/approvals/docs_webhooks_triggered_webhooks_for_verification_publication_get.approved.json +32 -0
- data/spec/fixtures/approvals/docs_webhooks_triggered_webhooks_for_verification_publication_options.approved.json +20 -0
- data/spec/fixtures/approvals/docs_webhooks_webhook_get.approved.json +74 -0
- data/spec/fixtures/approvals/docs_webhooks_webhook_options.approved.json +20 -0
- data/spec/fixtures/approvals/docs_webhooks_webhook_put.approved.json +77 -0
- data/spec/fixtures/approvals/docs_webhooks_webhooks_for_a_provider_get.approved.json +41 -0
- data/spec/fixtures/approvals/docs_webhooks_webhooks_for_a_provider_options.approved.json +20 -0
- data/spec/fixtures/approvals/docs_webhooks_webhooks_for_consumer_and_provider_get.approved.json +45 -0
- data/spec/fixtures/approvals/docs_webhooks_webhooks_for_consumer_and_provider_options.approved.json +20 -0
- data/spec/fixtures/approvals/docs_webhooks_webhooks_for_consumer_get.approved.json +41 -0
- data/spec/fixtures/approvals/docs_webhooks_webhooks_for_consumer_options.approved.json +20 -0
- data/spec/fixtures/approvals/docs_webhooks_webhooks_get.approved.json +45 -0
- data/spec/fixtures/approvals/docs_webhooks_webhooks_options.approved.json +20 -0
- data/spec/fixtures/approvals/docs_webhooks_webhooks_post.approved.json +78 -0
- data/spec/fixtures/approvals/docs_webhooks_webhooks_status_get.approved.json +79 -0
- data/spec/fixtures/approvals/docs_webhooks_webhooks_status_options.approved.json +20 -0
- data/spec/fixtures/approvals/get_provider_pacts_for_verification.approved.json +1 -2
- data/spec/fixtures/approvals/publish_contract_no_branch.approved.json +1 -2
- data/spec/fixtures/approvals/publish_contract_nothing_exists.approved.json +1 -2
- data/spec/fixtures/approvals/publish_contract_nothing_exists_with_webhook.approved.json +1 -2
- data/spec/fixtures/approvals/publish_contract_verification_already_exists.approved.json +1 -2
- data/spec/fixtures/approvals/publish_contract_with_validation_error.approved.json +1 -2
- data/spec/fixtures/invalid-publish-contract-body.json +38 -0
- data/spec/fixtures/verification.json +4 -0
- data/spec/integration/pact_metdata_spec.rb +105 -0
- data/spec/integration/webhooks/contract_publication_spec.rb +68 -0
- data/spec/integration/webhooks/contract_requiring_verification_published_spec.rb +67 -0
- data/spec/integration/webhooks/pact_publication_spec.rb +51 -0
- data/spec/integration/webhooks_documentation_spec.rb +348 -0
- data/spec/lib/pact/doc/markdown/consumer_contract_renderer_spec.rb +2 -2
- data/spec/lib/pact_broker/api/contracts/publish_contracts_schema_spec.rb +13 -0
- data/spec/lib/pact_broker/api/contracts/webhook_contract_spec.rb +50 -0
- data/spec/lib/pact_broker/api/decorators/matrix_decorator_spec.rb +1 -1
- data/spec/lib/pact_broker/api/decorators/verification_decorator_spec.rb +15 -7
- data/spec/lib/pact_broker/api/decorators/verification_summary_decorator_spec.rb +4 -2
- data/spec/lib/pact_broker/api/decorators/webhook_decorator_spec.rb +4 -4
- data/spec/lib/pact_broker/api/pact_broker_urls_spec.rb +18 -0
- data/spec/lib/pact_broker/api/resources/triggered_webhook_logs_spec.rb +6 -5
- data/spec/lib/pact_broker/config/runtime_configuration_documentation_spec.rb +30 -0
- data/spec/lib/pact_broker/deployments/environment_service_spec.rb +22 -1
- data/spec/lib/pact_broker/domain/webhook_spec.rb +35 -0
- data/spec/lib/pact_broker/matrix/head_row_spec.rb +9 -5
- data/spec/lib/pact_broker/matrix/parse_can_i_deploy_query_spec.rb +13 -0
- data/spec/lib/pact_broker/pacts/{latest_tagged_pact_publications_spec.rb → pact_publication_clean_selector_dataset_module_spec.rb} +7 -9
- data/spec/lib/pact_broker/pacts/pact_version_spec.rb +32 -0
- data/spec/lib/pact_broker/pacts/repository_find_for_verification_spec.rb +4 -5
- data/spec/lib/pact_broker/pacts/repository_spec.rb +33 -0
- data/spec/lib/pact_broker/ui/view_models/index_item_spec.rb +1 -1
- data/spec/lib/pact_broker/verifications/service_spec.rb +22 -8
- data/spec/lib/pact_broker/versions/abbreviate_number_spec.rb +2 -1
- data/spec/lib/pact_broker/webhooks/render_spec.rb +3 -2
- data/spec/lib/pact_broker/webhooks/repository_spec.rb +158 -15
- data/spec/lib/pact_broker/webhooks/webhook_spec.rb +8 -5
- data/spec/support/documentation.rb +64 -0
- data/spec/support/rack_helpers.rb +1 -1
- data/tasks/db.rake +4 -1
- data/tasks/development.rake +14 -13
- metadata +89 -12
- data/lib/pact_broker/pacts/all_pact_publications.rb +0 -158
- data/lib/pact_broker/pacts/latest_pact_publications.rb +0 -48
- data/lib/pact_broker/pacts/latest_pact_publications_by_consumer_version.rb +0 -26
- data/lib/pact_broker/pacts/latest_tagged_pact_publications.rb +0 -45
- data/lib/pact_broker/verifications/latest_verification_for_pact_version.rb +0 -39
- data/spec/lib/pact_broker/verifications/latest_verification_for_pact_version_spec.rb +0 -18
@@ -1,6 +1,5 @@
|
|
1
1
|
require "sequel"
|
2
2
|
require "pact_broker/domain/verification"
|
3
|
-
require "pact_broker/verifications/latest_verification_for_pact_version"
|
4
3
|
require "pact_broker/verifications/sequence"
|
5
4
|
require "pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version"
|
6
5
|
|
@@ -61,6 +60,10 @@ module PactBroker
|
|
61
60
|
PactBroker::Pacts::PactPublication.where(id: pact.id).single_record.latest_verification
|
62
61
|
end
|
63
62
|
|
63
|
+
def find_latest_from_main_branch_for_pact(pact)
|
64
|
+
PactBroker::Pacts::PactPublication.where(id: pact.id).single_record.latest_main_branch_verification
|
65
|
+
end
|
66
|
+
|
64
67
|
def any_verifications?(consumer, provider)
|
65
68
|
PactBroker::Domain::Verification.where(consumer_id: consumer.id, provider_id: provider.id).any?
|
66
69
|
end
|
@@ -73,7 +76,7 @@ module PactBroker
|
|
73
76
|
end
|
74
77
|
|
75
78
|
def find_latest_verifications_for_consumer_version consumer_name, consumer_version_number
|
76
|
-
# Use
|
79
|
+
# Use remove_verifications_for_overridden_consumer_versions because we don't
|
77
80
|
# want verifications for shadowed revisions as it would be misleading.
|
78
81
|
PactBroker::Domain::Verification
|
79
82
|
.select_all_qualified
|
@@ -21,12 +21,13 @@ module PactBroker
|
|
21
21
|
using PactBroker::HashRefinements
|
22
22
|
extend PactBroker::Events::Publisher
|
23
23
|
|
24
|
-
delegate [:any_verifications
|
24
|
+
delegate [:any_verifications?, :find_latest_from_main_branch_for_pact] => :verification_repository
|
25
25
|
|
26
26
|
def next_number
|
27
27
|
verification_repository.next_number
|
28
28
|
end
|
29
29
|
|
30
|
+
# TODO use a decorator instead of passing in params, srsly, Beth
|
30
31
|
# verified_pacts is an array of SelectedPact objects
|
31
32
|
def create next_verification_number, params, verified_pacts, event_context
|
32
33
|
first_verified_pact = verified_pacts.first
|
@@ -37,6 +38,8 @@ module PactBroker
|
|
37
38
|
verification.wip = params.fetch("wip")
|
38
39
|
verification.pact_pending = params.fetch("pending")
|
39
40
|
verification.number = next_verification_number
|
41
|
+
verification.verified_by_implementation = params.dig("verifiedBy", "implementation")
|
42
|
+
verification.verified_by_version = params.dig("verifiedBy", "version")
|
40
43
|
verification.consumer_version_selector_hashes = event_context[:consumer_version_selectors]
|
41
44
|
pact_version = pact_repository.find_pact_version(first_verified_pact.consumer, first_verified_pact.provider, first_verified_pact.pact_version_sha)
|
42
45
|
verification = verification_repository.create(verification, provider_version_number, pact_version)
|
@@ -135,7 +138,7 @@ module PactBroker
|
|
135
138
|
latest_version_from_main_branch = [version_service.find_latest_version_from_main_branch(pact_version.provider)].compact
|
136
139
|
|
137
140
|
latest_version_from_main_branch.collect do | main_branch_version |
|
138
|
-
identify_required_verification(pact_version, main_branch_version, "latest
|
141
|
+
identify_required_verification(pact_version, main_branch_version, "latest from main branch")
|
139
142
|
end.compact
|
140
143
|
end
|
141
144
|
private :required_verifications_for_main_branch
|
@@ -145,7 +148,7 @@ module PactBroker
|
|
145
148
|
unscoped_service.find_currently_deployed_versions_for_pacticipant(pact_version.provider)
|
146
149
|
end
|
147
150
|
deployed_versions.collect do | deployed_version |
|
148
|
-
identify_required_verification(pact_version, deployed_version.version, "
|
151
|
+
identify_required_verification(pact_version, deployed_version.version, "deployed in #{deployed_version.environment_name}")
|
149
152
|
end.compact
|
150
153
|
end
|
151
154
|
private :required_verifications_for_deployed_versions
|
@@ -155,7 +158,7 @@ module PactBroker
|
|
155
158
|
unscoped_service.find_currently_supported_versions_for_pacticipant(pact_version.provider)
|
156
159
|
end
|
157
160
|
released_versions.collect do | released_version |
|
158
|
-
identify_required_verification(pact_version, released_version.version, "
|
161
|
+
identify_required_verification(pact_version, released_version.version, "released in #{released_version.environment_name}")
|
159
162
|
end.compact
|
160
163
|
end
|
161
164
|
private :required_verifications_for_released_versions
|
data/lib/pact_broker/version.rb
CHANGED
@@ -3,10 +3,14 @@ module PactBroker
|
|
3
3
|
class AbbreviateNumber
|
4
4
|
|
5
5
|
def self.call version_number
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
return version_number unless version_number
|
7
|
+
|
8
|
+
# hard limit of max 50 characters
|
9
|
+
version_length = version_number.length
|
10
|
+
return version_number[0...39] + "…" + version_number[version_length - 10...version_length] if version_length > 50
|
11
|
+
|
12
|
+
version_number.gsub(/[A-Za-z0-9]{40}/) do | val |
|
13
|
+
val[0..6]
|
10
14
|
end
|
11
15
|
end
|
12
16
|
end
|
@@ -28,14 +28,12 @@ end
|
|
28
28
|
|
29
29
|
# Table: branch_heads
|
30
30
|
# Columns:
|
31
|
-
# id | integer | PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
|
32
31
|
# branch_id | integer | NOT NULL
|
33
32
|
# branch_version_id | integer | NOT NULL
|
34
33
|
# version_id | integer | NOT NULL
|
35
34
|
# pacticipant_id | integer | NOT NULL
|
36
35
|
# branch_name | text | NOT NULL
|
37
36
|
# Indexes:
|
38
|
-
# branch_heads_pkey | PRIMARY KEY btree (id)
|
39
37
|
# branch_heads_branch_id_index | UNIQUE btree (branch_id)
|
40
38
|
# branch_heads_branch_name_index | btree (branch_name)
|
41
39
|
# branch_heads_pacticipant_id_index | btree (pacticipant_id)
|
@@ -51,6 +51,7 @@ end
|
|
51
51
|
# branch_name | text | NOT NULL
|
52
52
|
# created_at | timestamp without time zone | NOT NULL
|
53
53
|
# updated_at | timestamp without time zone | NOT NULL
|
54
|
+
# auto_created | boolean | DEFAULT false
|
54
55
|
# Indexes:
|
55
56
|
# branch_versions_pkey | PRIMARY KEY btree (id)
|
56
57
|
# branch_versions_branch_id_version_id_index | UNIQUE btree (branch_id, version_id)
|
@@ -53,7 +53,6 @@ module PactBroker
|
|
53
53
|
|
54
54
|
# There may be a race condition if two simultaneous requests come in to create the same version
|
55
55
|
def create(args)
|
56
|
-
logger.info "Upserting version #{args[:number]} for pacticipant_id=#{args[:pacticipant_id]}"
|
57
56
|
version_params = {
|
58
57
|
number: args[:number],
|
59
58
|
pacticipant_id: args[:pacticipant_id],
|
@@ -18,14 +18,16 @@ module PactBroker
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def contract_published(params)
|
21
|
-
|
21
|
+
main_branch_verification = verification_service.find_latest_from_main_branch_for_pact(params.fetch(:pact))
|
22
|
+
handle_event_for_webhook(PactBroker::Webhooks::WebhookEvent::CONTRACT_PUBLISHED, { verification: main_branch_verification }.compact.merge(params))
|
22
23
|
if verification_service.calculate_required_verifications_for_pact(params.fetch(:pact)).any?
|
23
24
|
handle_event_for_webhook(PactBroker::Webhooks::WebhookEvent::CONTRACT_REQUIRING_VERIFICATION_PUBLISHED, params)
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
27
28
|
def contract_content_changed(params)
|
28
|
-
|
29
|
+
main_branch_verification = verification_service.find_latest_from_main_branch_for_pact(params.fetch(:pact))
|
30
|
+
handle_event_for_webhook(PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, { verification: main_branch_verification }.compact.merge(params))
|
29
31
|
end
|
30
32
|
|
31
33
|
def contract_content_unchanged(params)
|
@@ -7,6 +7,7 @@ module PactBroker
|
|
7
7
|
PROVIDER_VERSION_NUMBER = "pactbroker.providerVersionNumber"
|
8
8
|
PROVIDER_VERSION_TAGS = "pactbroker.providerVersionTags"
|
9
9
|
PROVIDER_VERSION_BRANCH = "pactbroker.providerVersionBranch"
|
10
|
+
PROVIDER_VERSION_DESCRIPTIONS = "pactbroker.providerVersionDescriptions"
|
10
11
|
CONSUMER_VERSION_TAGS = "pactbroker.consumerVersionTags"
|
11
12
|
CONSUMER_VERSION_BRANCH = "pactbroker.consumerVersionBranch"
|
12
13
|
CONSUMER_NAME = "pactbroker.consumerName"
|
@@ -17,6 +18,7 @@ module PactBroker
|
|
17
18
|
GITLAB_VERIFICATION_STATUS = "pactbroker.gitlabVerificationStatus"
|
18
19
|
CONSUMER_LABELS = "pactbroker.consumerLabels"
|
19
20
|
PROVIDER_LABELS = "pactbroker.providerLabels"
|
21
|
+
BUILD_URL = "pactbroker.buildUrl"
|
20
22
|
EVENT_NAME = "pactbroker.eventName"
|
21
23
|
CURRENTLY_DEPLOYED_PROVIDER_VERSION_NUMBER = "pactbroker.currentlyDeployedProviderVersionNumber"
|
22
24
|
|
@@ -26,6 +28,7 @@ module PactBroker
|
|
26
28
|
CONSUMER_VERSION_NUMBER,
|
27
29
|
PROVIDER_VERSION_NUMBER,
|
28
30
|
PROVIDER_VERSION_TAGS,
|
31
|
+
PROVIDER_VERSION_DESCRIPTIONS,
|
29
32
|
PROVIDER_VERSION_BRANCH,
|
30
33
|
CONSUMER_VERSION_TAGS,
|
31
34
|
CONSUMER_VERSION_BRANCH,
|
@@ -38,9 +41,11 @@ module PactBroker
|
|
38
41
|
CONSUMER_LABELS,
|
39
42
|
PROVIDER_LABELS,
|
40
43
|
EVENT_NAME,
|
44
|
+
BUILD_URL,
|
41
45
|
CURRENTLY_DEPLOYED_PROVIDER_VERSION_NUMBER
|
42
46
|
]
|
43
47
|
|
48
|
+
# TODO change this verification to the latest main branch
|
44
49
|
def initialize(pact, trigger_verification, webhook_context)
|
45
50
|
@pact = pact
|
46
51
|
@verification = trigger_verification || (pact && pact.latest_verification)
|
@@ -56,6 +61,7 @@ module PactBroker
|
|
56
61
|
PROVIDER_VERSION_NUMBER => provider_version_number,
|
57
62
|
PROVIDER_VERSION_TAGS => provider_version_tags,
|
58
63
|
PROVIDER_VERSION_BRANCH => provider_version_branch,
|
64
|
+
PROVIDER_VERSION_DESCRIPTIONS => provider_version_descriptions,
|
59
65
|
CONSUMER_VERSION_TAGS => consumer_version_tags,
|
60
66
|
CONSUMER_VERSION_BRANCH => consumer_version_branch,
|
61
67
|
CONSUMER_NAME => pact ? pact.consumer_name : "",
|
@@ -67,6 +73,7 @@ module PactBroker
|
|
67
73
|
CONSUMER_LABELS => pacticipant_labels(pact && pact.consumer),
|
68
74
|
PROVIDER_LABELS => pacticipant_labels(pact && pact.provider),
|
69
75
|
EVENT_NAME => event_name,
|
76
|
+
BUILD_URL => build_url,
|
70
77
|
CURRENTLY_DEPLOYED_PROVIDER_VERSION_NUMBER => currently_deployed_provider_version_number
|
71
78
|
}
|
72
79
|
end
|
@@ -136,10 +143,10 @@ module PactBroker
|
|
136
143
|
end
|
137
144
|
|
138
145
|
def consumer_version_branch
|
139
|
-
if webhook_context
|
140
|
-
webhook_context[:consumer_version_branch]
|
146
|
+
if webhook_context.key?(:consumer_version_branch)
|
147
|
+
webhook_context[:consumer_version_branch] || ""
|
141
148
|
else
|
142
|
-
pact&.consumer_version&.
|
149
|
+
pact&.consumer_version&.branch_names&.last || ""
|
143
150
|
end
|
144
151
|
end
|
145
152
|
|
@@ -171,6 +178,10 @@ module PactBroker
|
|
171
178
|
end
|
172
179
|
end
|
173
180
|
|
181
|
+
def provider_version_descriptions
|
182
|
+
webhook_context[:provider_version_descriptions]&.join(", ") || ""
|
183
|
+
end
|
184
|
+
|
174
185
|
def pacticipant_labels pacticipant
|
175
186
|
pacticipant && pacticipant.labels ? pacticipant.labels.collect(&:name).join(", ") : ""
|
176
187
|
end
|
@@ -179,6 +190,10 @@ module PactBroker
|
|
179
190
|
webhook_context.fetch(:event_name)
|
180
191
|
end
|
181
192
|
|
193
|
+
def build_url
|
194
|
+
webhook_context[:build_url] || ""
|
195
|
+
end
|
196
|
+
|
182
197
|
def currently_deployed_provider_version_number
|
183
198
|
webhook_context[:currently_deployed_provider_version_number] || ""
|
184
199
|
end
|
@@ -17,8 +17,8 @@ module PactBroker
|
|
17
17
|
include Repositories
|
18
18
|
|
19
19
|
def create uuid, webhook, consumer, provider
|
20
|
-
consumer =
|
21
|
-
provider =
|
20
|
+
consumer = find_pacticipant_by_name(webhook.consumer) || consumer
|
21
|
+
provider = find_pacticipant_by_name(webhook.provider) || provider
|
22
22
|
db_webhook = Webhook.from_domain webhook, consumer, provider
|
23
23
|
db_webhook.uuid = uuid
|
24
24
|
db_webhook.save
|
@@ -36,8 +36,8 @@ module PactBroker
|
|
36
36
|
# policy applied at resource level
|
37
37
|
def update_by_uuid uuid, webhook
|
38
38
|
existing_webhook = deliberately_unscoped(Webhook).find(uuid: uuid)
|
39
|
-
existing_webhook.consumer_id =
|
40
|
-
existing_webhook.provider_id =
|
39
|
+
existing_webhook.consumer_id = find_pacticipant_by_name(webhook.consumer)&.id
|
40
|
+
existing_webhook.provider_id = find_pacticipant_by_name(webhook.provider)&.id
|
41
41
|
existing_webhook.update_from_domain(webhook).save
|
42
42
|
existing_webhook.events.collect(&:delete)
|
43
43
|
(webhook.events || []).each do | webhook_event |
|
@@ -187,6 +187,12 @@ module PactBroker
|
|
187
187
|
|
188
188
|
private
|
189
189
|
|
190
|
+
def find_pacticipant_by_name(pacticipant)
|
191
|
+
return unless pacticipant&.name
|
192
|
+
|
193
|
+
pacticipant_repository.find_by_name(pacticipant.name)
|
194
|
+
end
|
195
|
+
|
190
196
|
def deliberately_unscoped(scope)
|
191
197
|
scope
|
192
198
|
end
|
@@ -135,7 +135,7 @@ module PactBroker
|
|
135
135
|
required_verifications = verification_service.calculate_required_verifications_for_pact(pact)
|
136
136
|
event_contexts.flat_map do | event_context |
|
137
137
|
required_verifications.collect do | required_verification |
|
138
|
-
event_context.merge(provider_version_number: required_verification.provider_version.number, provider_version_descriptions: required_verification.provider_version_descriptions)
|
138
|
+
event_context.merge(provider_version_number: required_verification.provider_version.number, provider_version_descriptions: required_verification.provider_version_descriptions.uniq)
|
139
139
|
end
|
140
140
|
end
|
141
141
|
else
|
@@ -30,12 +30,14 @@ module PactBroker
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def find_by_consumer_and_or_provider consumer, provider
|
33
|
+
|
33
34
|
where(
|
34
35
|
Sequel.|(
|
35
36
|
{ consumer_id: consumer.id, provider_id: provider.id },
|
36
|
-
{ consumer_id: nil, provider_id: provider.id },
|
37
|
-
{ consumer_id: consumer.id, provider_id: nil },
|
38
|
-
{ consumer_id: nil, provider_id: nil}
|
37
|
+
{ consumer_id: nil, provider_id: provider.id, consumer_label: nil },
|
38
|
+
{ consumer_id: consumer.id, provider_id: nil, provider_label: nil },
|
39
|
+
{ consumer_id: nil, provider_id: nil, consumer_label: nil, provider_label: nil },
|
40
|
+
*labels_criteria_for_consumer_or_provider(consumer, provider)
|
39
41
|
)
|
40
42
|
)
|
41
43
|
end
|
@@ -51,6 +53,32 @@ module PactBroker
|
|
51
53
|
def enabled
|
52
54
|
where(enabled: true)
|
53
55
|
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def labels_criteria_for_consumer_or_provider(consumer, provider)
|
60
|
+
consumer_labels = consumer.labels.map(&:name)
|
61
|
+
provider_labels = provider.labels.map(&:name)
|
62
|
+
|
63
|
+
[].then do |criteria|
|
64
|
+
next criteria if consumer_labels.empty?
|
65
|
+
criteria + [
|
66
|
+
{ consumer_label: consumer_labels, provider_label: nil, provider_id: nil },
|
67
|
+
{ consumer_label: consumer_labels, provider_label: nil, provider_id: provider.id }
|
68
|
+
]
|
69
|
+
end.then do |criteria|
|
70
|
+
next criteria if provider_labels.empty?
|
71
|
+
criteria + [
|
72
|
+
{ provider_label: provider_labels, consumer_label: nil, consumer_id: nil },
|
73
|
+
{ provider_label: provider_labels, consumer_label: nil, consumer_id: consumer.id }
|
74
|
+
]
|
75
|
+
end.then do |criteria|
|
76
|
+
next criteria if consumer_labels.empty? || provider_labels.empty?
|
77
|
+
criteria + [
|
78
|
+
{ consumer_label: consumer_labels, provider_label: provider_labels }
|
79
|
+
]
|
80
|
+
end
|
81
|
+
end
|
54
82
|
end
|
55
83
|
|
56
84
|
def update_from_domain webhook
|
@@ -74,8 +102,8 @@ module PactBroker
|
|
74
102
|
Domain::Webhook.new(
|
75
103
|
uuid: uuid,
|
76
104
|
description: description,
|
77
|
-
consumer:
|
78
|
-
provider:
|
105
|
+
consumer: webhook_consumer,
|
106
|
+
provider: webhook_provider,
|
79
107
|
events: events,
|
80
108
|
request: Webhooks::WebhookRequestTemplate.new(request_attributes),
|
81
109
|
enabled: enabled,
|
@@ -100,7 +128,15 @@ module PactBroker
|
|
100
128
|
end
|
101
129
|
|
102
130
|
def is_for? integration
|
103
|
-
(
|
131
|
+
(
|
132
|
+
consumer_id == integration.consumer_id ||
|
133
|
+
match_label?(:consumer, integration) ||
|
134
|
+
match_all?(:consumer)
|
135
|
+
) && (
|
136
|
+
provider_id == integration.provider_id ||
|
137
|
+
match_label?(:provider, integration) ||
|
138
|
+
match_all?(:provider)
|
139
|
+
)
|
104
140
|
end
|
105
141
|
|
106
142
|
# Keep the triggered webhooks after the webhook has been deleted
|
@@ -110,7 +146,6 @@ module PactBroker
|
|
110
146
|
super
|
111
147
|
end
|
112
148
|
|
113
|
-
|
114
149
|
def self.properties_hash_from_domain webhook
|
115
150
|
is_json_request_body = !(String === webhook.request.body || webhook.request.body.nil?) # Can't rely on people to set content type
|
116
151
|
{
|
@@ -122,9 +157,32 @@ module PactBroker
|
|
122
157
|
enabled: webhook.enabled.nil? ? true : webhook.enabled,
|
123
158
|
body: (is_json_request_body ? webhook.request.body.to_json : webhook.request.body),
|
124
159
|
is_json_request_body: is_json_request_body,
|
125
|
-
headers: webhook.request.headers
|
160
|
+
headers: webhook.request.headers,
|
161
|
+
consumer_label: webhook.consumer&.label,
|
162
|
+
provider_label: webhook.provider&.label
|
126
163
|
}
|
127
164
|
end
|
165
|
+
|
166
|
+
def webhook_consumer
|
167
|
+
return if consumer.nil? && consumer_label.nil?
|
168
|
+
|
169
|
+
Domain::WebhookPacticipant.new(name: consumer&.name, label: consumer_label)
|
170
|
+
end
|
171
|
+
|
172
|
+
def webhook_provider
|
173
|
+
return if provider.nil? && provider_label.nil?
|
174
|
+
|
175
|
+
Domain::WebhookPacticipant.new(name: provider&.name, label: provider_label)
|
176
|
+
end
|
177
|
+
|
178
|
+
def match_all?(name)
|
179
|
+
public_send(:"#{name}_id").nil? && public_send(:"#{name}_label").nil?
|
180
|
+
end
|
181
|
+
|
182
|
+
def match_label?(name, integration)
|
183
|
+
label = public_send(:"#{name}_label")
|
184
|
+
public_send(:"#{name}_id").nil? && integration.public_send(name).label?(label)
|
185
|
+
end
|
128
186
|
end
|
129
187
|
end
|
130
188
|
end
|
@@ -146,9 +204,14 @@ end
|
|
146
204
|
# enabled | boolean | DEFAULT true
|
147
205
|
# description | text |
|
148
206
|
# headers | text |
|
207
|
+
# consumer_label | text |
|
208
|
+
# provider_label | text |
|
149
209
|
# Indexes:
|
150
210
|
# webhooks_pkey | PRIMARY KEY btree (id)
|
151
211
|
# uq_webhook_uuid | UNIQUE btree (uuid)
|
212
|
+
# Check constraints:
|
213
|
+
# consumer_label_exclusion | (consumer_id IS NULL OR consumer_id IS NOT NULL AND consumer_label IS NULL)
|
214
|
+
# provider_label_exclusion | (provider_id IS NULL OR provider_id IS NOT NULL AND provider_label IS NULL)
|
152
215
|
# Foreign key constraints:
|
153
216
|
# fk_webhooks_consumer | (consumer_id) REFERENCES pacticipants(id)
|
154
217
|
# fk_webhooks_provider | (provider_id) REFERENCES pacticipants(id)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require "webmachine/adapters/rack_mapped"
|
2
|
+
|
3
|
+
module Webmachine
|
4
|
+
class DescribeRoutes
|
5
|
+
|
6
|
+
def self.call(webmachine_applications, search_term: nil)
|
7
|
+
path_mappings = webmachine_applications.flat_map { | webmachine_application | paths_to_resource_class_mappings(webmachine_application) }
|
8
|
+
|
9
|
+
if search_term
|
10
|
+
path_mappings = path_mappings.select{ |(route, _)| route[:path].include?(search_term) }
|
11
|
+
end
|
12
|
+
|
13
|
+
path_mappings.sort_by{ | mapping | mapping[:path] }
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.paths_to_resource_class_mappings(webmachine_application)
|
17
|
+
webmachine_application.routes.collect do | route |
|
18
|
+
resource_path_absolute = Pathname.new(source_location_for(route.resource))
|
19
|
+
{
|
20
|
+
path: "/" + route.path_spec.collect{ |part| part.is_a?(Symbol) ? ":#{part}" : part }.join("/"),
|
21
|
+
resource_class: route.resource,
|
22
|
+
resource_name: route.instance_variable_get(:@bindings)[:resource_name],
|
23
|
+
resource_class_location: resource_path_absolute.relative_path_from(Pathname.pwd).to_s
|
24
|
+
}.merge(info_from_resource_instance(route))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.info_from_resource_instance(route)
|
29
|
+
with_no_logging do
|
30
|
+
path_info = { application_context: OpenStruct.new, pacticipant_name: "foo", pacticipant_version_number: "1", resource_name: "foo" }
|
31
|
+
path_info.default = "1"
|
32
|
+
dummy_request = Webmachine::Adapters::Rack::RackRequest.new("GET", "/", Webmachine::Headers["host" => "example.org"], nil, {}, {}, { "REQUEST_METHOD" => "GET" })
|
33
|
+
dummy_request.path_info = path_info
|
34
|
+
dummy_resource = route.resource.new(dummy_request, Webmachine::Response.new)
|
35
|
+
if dummy_resource
|
36
|
+
{
|
37
|
+
allowed_methods: dummy_resource.allowed_methods,
|
38
|
+
}
|
39
|
+
else
|
40
|
+
{}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
rescue StandardError => e
|
44
|
+
puts "Could not determine instance info for #{route.resource}. #{e.class} - #{e.message}"
|
45
|
+
{}
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.source_location_for(clazz)
|
49
|
+
first_instance_method_name = (clazz.instance_methods(false) + clazz.private_instance_methods(false)).first
|
50
|
+
clazz.instance_method(first_instance_method_name).source_location.first
|
51
|
+
end
|
52
|
+
|
53
|
+
# If we don't turn off the logging, we get metrics logging due to the instantiation of the Webmachine::RackRequest class
|
54
|
+
def self.with_no_logging
|
55
|
+
original_default_level = SemanticLogger.default_level
|
56
|
+
SemanticLogger.default_level = :fatal
|
57
|
+
yield
|
58
|
+
ensure
|
59
|
+
SemanticLogger.default_level = original_default_level
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -13,6 +13,7 @@ begin
|
|
13
13
|
.deploy_to_prod(pacticipant: "AutoDetectTestProvider", version: "1")
|
14
14
|
.publish_pact(consumer: "AutoDetectTestConsumer", provider: "AutoDetectTestProvider", consumer_version: "1", tag: "feat/x", content_id: "2111")
|
15
15
|
.publish_pact(consumer: "AutoDetectTestConsumer", provider: "AutoDetectTestProvider", consumer_version: "2", tag: "feat/y", content_id: "21asdfd")
|
16
|
+
.deploy_to_prod(pacticipant: "AutoDetectTestConsumer", version: "1")
|
16
17
|
|
17
18
|
rescue StandardError => e
|
18
19
|
puts "#{e.class} #{e.message}"
|
data/script/data/branches.rb
CHANGED
@@ -11,7 +11,7 @@ begin
|
|
11
11
|
.publish_contract(consumer: "branch-consumer", provider: "branch-provider", consumer_version: "1", content_id: "1111", branch: "main")
|
12
12
|
.publish_contract(consumer: "branch-consumer", provider: "branch-provider", consumer_version: "1", content_id: "1111", branch: "feat/x")
|
13
13
|
.publish_contract(consumer: "branch-consumer", provider: "branch-provider", consumer_version: "2", content_id: "1111", branch: "feat/x")
|
14
|
-
.get_pacts_for_verification(provider: "branch-provider", enable_pending: false)
|
14
|
+
.get_pacts_for_verification(provider: "branch-provider", enable_pending: false, consumer_version_selectors: [ { branch: "main" }, { branch: "feat/x" }])
|
15
15
|
.verify_pact(
|
16
16
|
provider_version_branch: "main",
|
17
17
|
provider_version: "1",
|
@@ -14,7 +14,6 @@ begin
|
|
14
14
|
.create_pacticipant("NewWebhookTestConsumer")
|
15
15
|
.create_pacticipant("NewWebhookTestProvider")
|
16
16
|
.create_tagged_pacticipant_version(pacticipant: "NewWebhookTestProvider", version: "1", tag: "main")
|
17
|
-
.deploy_to_prod(pacticipant: "NewWebhookTestProvider", version: "1")
|
18
17
|
.record_deployment(pacticipant: "NewWebhookTestProvider", version: "1", environment_name: "test")
|
19
18
|
.record_deployment(pacticipant: "NewWebhookTestProvider", version: "1", environment_name: "prod")
|
20
19
|
.create_version(pacticipant: "NewWebhookTestProvider", version: "2", branch: "main")
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
begin
|
3
|
+
|
4
|
+
$LOAD_PATH << "#{Dir.pwd}/lib"
|
5
|
+
require "pact_broker/test/http_test_data_builder"
|
6
|
+
base_url = ENV["PACT_BROKER_BASE_URL"] || "http://localhost:9292"
|
7
|
+
|
8
|
+
td = PactBroker::Test::HttpTestDataBuilder.new(base_url)
|
9
|
+
td.delete_pacticipant("some-consumer")
|
10
|
+
.delete_pacticipant("some-provider")
|
11
|
+
.create_pacticipant("some-consumer")
|
12
|
+
.create_pacticipant("some-provider")
|
13
|
+
.publish_pact(consumer: "some-consumer", consumer_version: "1", provider: "some-provider", content_id: "111", branch: "main")
|
14
|
+
.publish_pact(consumer: "some-consumer", consumer_version: "2", provider: "some-provider", content_id: "111", branch: "feat/x")
|
15
|
+
.get_pacts_for_verification(
|
16
|
+
provider_version_tag: "main",
|
17
|
+
consumer_version_selectors: [{ branch: "main" }, { branch: "feat/x" }]
|
18
|
+
)
|
19
|
+
.verify_pact(
|
20
|
+
index: 0,
|
21
|
+
provider_version_tag: "main",
|
22
|
+
provider_version: "1",
|
23
|
+
success: true
|
24
|
+
)
|
25
|
+
|
26
|
+
rescue StandardError => e
|
27
|
+
puts "#{e.class} #{e.message}"
|
28
|
+
puts e.backtrace
|
29
|
+
exit 1
|
30
|
+
end
|