pact_broker-client 1.66.1 → 1.67.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release_gem.yml +4 -4
  3. data/.github/workflows/smartbear-issue-label-added.yml +11 -0
  4. data/.github/workflows/test.yml +6 -7
  5. data/.github/workflows/trigger_pact_docs_update.yml +1 -0
  6. data/.ruby-version +1 -1
  7. data/CHANGELOG.md +15 -1
  8. data/Dockerfile +1 -1
  9. data/README.md +15 -9
  10. data/doc/pacts/markdown/Pact Broker Client - Pactflow.md +47 -4
  11. data/doc/pacts/markdown/README.md +1 -1
  12. data/example/scripts/oas.yml +116 -0
  13. data/example/scripts/publish-provider-contract.sh +12 -0
  14. data/lib/pact_broker/client/base_client.rb +1 -1
  15. data/lib/pact_broker/client/base_command.rb +12 -0
  16. data/lib/pact_broker/client/cli/can_i_deploy_long_desc.txt +4 -0
  17. data/lib/pact_broker/client/cli/custom_thor.rb +13 -0
  18. data/lib/pact_broker/client/cli/matrix_commands.rb +7 -0
  19. data/lib/pact_broker/client/cli/pact_commands.rb +1 -1
  20. data/lib/pact_broker/client/cli/webhook_commands.rb +1 -1
  21. data/lib/pact_broker/client/colorize_notices.rb +14 -3
  22. data/lib/pact_broker/client/deployments/record_release.rb +1 -1
  23. data/lib/pact_broker/client/environments/environment_command.rb +1 -1
  24. data/lib/pact_broker/client/hal/entity.rb +1 -1
  25. data/lib/pact_broker/client/hal_client_methods.rb +1 -1
  26. data/lib/pact_broker/client/version.rb +1 -1
  27. data/lib/pactflow/client/cli/provider_contract_commands.rb +1 -1
  28. data/lib/pactflow/client/provider_contracts/publish.rb +30 -5
  29. data/pact-broker-client.gemspec +2 -2
  30. data/script/update-cli-usage-in-readme.rb +8 -3
  31. data/spec/lib/pact_broker/client/cli/broker_can_i_deploy_spec.rb +10 -0
  32. data/spec/lib/pact_broker/client/cli/custom_thor_spec.rb +15 -0
  33. data/spec/lib/pact_broker/client/deployments/record_deployment_spec.rb +5 -5
  34. data/spec/pacts/pact_broker_client-pactflow.json +39 -1
  35. data/spec/service_providers/pact_helper.rb +1 -1
  36. data/spec/service_providers/pactflow_publish_provider_contract_spec.rb +37 -2
  37. data/spec/service_providers/pactflow_webhooks_create_spec.rb +1 -1
  38. metadata +10 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ff5c17fff5ecf49ba126154617cba59267fdfe34e3e0dae905ee476408319b1
4
- data.tar.gz: cd232d89597a0a2f79726a0464cf30a0e671056b8898ecb39f9fef8e1359df99
3
+ metadata.gz: 6f188bc33e3294bd2bea28a4bebd4f3d9c2047da2e36b1e4a435e04878d89b4b
4
+ data.tar.gz: fab940f0461e06d9ed0fb81be5947ad749a75616c85c42c312d8aecfc038eb86
5
5
  SHA512:
6
- metadata.gz: 352eb1d1ba20242adc03af2c0f51883ffaca332b7affaebb48db63358b8f5e13198cb280987a49ed4becd3e8c97b5a8d59f6fc2deabfda0b95ed1b990d2acc48
7
- data.tar.gz: 6682af8dce2ee94a56bc81cd03b633074e14a8e85a0c68a5e7c0393bf08faa3ab64fb26fcee7589f37f4c89cdbaa9b1ad83de95f5f41992cd5d6b2ea883b213f
6
+ metadata.gz: '0129bc2ee4f7e871adc49c1e21056dff0c49d8ff286582a0c01418c317e29c04b543ab70b41e52ccdffd64bfbffec712fd7fe930f1ffe8971d5c9d9b17fad747'
7
+ data.tar.gz: 3a76b75837e15f3e9a31a3bd8624a3d160d5c9e547235fb4d01f688906decd9ab2819a359c9fb22224707c6e17b5b1f8826bf93c1146439c6268ae20bb62d506
@@ -10,12 +10,12 @@ jobs:
10
10
  test:
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
- - uses: actions/checkout@v2
13
+ - uses: actions/checkout@v3
14
14
  - uses: ruby/setup-ruby@v1
15
15
  with:
16
- ruby-version: '2.6'
16
+ ruby-version: '3.2'
17
17
  - run: |
18
- gem install bundler -v 2.1
18
+ gem install bundler -v 2.4
19
19
  bundle install
20
20
  - name: Test
21
21
  run: bundle exec rake
@@ -28,7 +28,7 @@ jobs:
28
28
  version: ${{ steps.release.outputs.version }}
29
29
  increment: ${{ steps.release.outputs.increment }}
30
30
  steps:
31
- - uses: actions/checkout@v2
31
+ - uses: actions/checkout@v3
32
32
  with:
33
33
  fetch-depth: 0
34
34
  - uses: pact-foundation/release-gem@v0.0.13
@@ -0,0 +1,11 @@
1
+ name: SmartBear Supported Issue Label Added
2
+
3
+ on:
4
+ issues:
5
+ types:
6
+ - labeled
7
+
8
+ jobs:
9
+ call-workflow:
10
+ uses: pact-foundation/.github/.github/workflows/smartbear-issue-label-added.yml@master
11
+ secrets: inherit
@@ -4,15 +4,14 @@ on: [push, pull_request]
4
4
 
5
5
  jobs:
6
6
  test:
7
- runs-on: "ubuntu-latest"
8
- continue-on-error: ${{ matrix.experimental }}
7
+ runs-on: ${{ matrix.os }}
9
8
  strategy:
10
9
  fail-fast: false
11
10
  matrix:
12
- ruby_version: ["2.7", "3.0", "3.1"]
13
- experimental: [false]
11
+ ruby_version: ["2.7", "3.0", "3.1", "3.2"]
12
+ os: ["ubuntu-latest","windows-latest","macos-latest"]
14
13
  steps:
15
- - uses: actions/checkout@v2
14
+ - uses: actions/checkout@v3
16
15
  - uses: ruby/setup-ruby@v1
17
16
  with:
18
17
  ruby-version: ${{ matrix.ruby_version }}
@@ -26,10 +25,10 @@ jobs:
26
25
  matrix:
27
26
  feature: [""]
28
27
  steps:
29
- - uses: actions/checkout@v2
28
+ - uses: actions/checkout@v3
30
29
  - uses: ruby/setup-ruby@v1
31
30
  with:
32
- ruby-version: "2.7"
31
+ ruby-version: "3.2"
33
32
  - run: "bundle install"
34
33
  - run: |
35
34
  rm -rf spec/pacts/*
@@ -9,6 +9,7 @@ on:
9
9
  repository_dispatch:
10
10
  types:
11
11
  - gem-released
12
+ workflow_dispatch:
12
13
 
13
14
  jobs:
14
15
  build:
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.7
1
+ 3.2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ <a name="v1.67.0"></a>
2
+ ### v1.67.0 (2023-05-04)
3
+
4
+ #### Features
5
+
6
+ * colour first url in magenta for ease of reading ([90e8f51](/../../commit/90e8f51))
7
+ * output provider contract link on publish (#118) ([132b024](/../../commit/132b024))
8
+ * add helper text for Docker usage when pact file not found ([2aab2d5](/../../commit/2aab2d5))
9
+
10
+ #### Bug Fixes
11
+
12
+ * trim trailing slash from base url ([ccd6417](/../../commit/ccd6417))
13
+ * do not allow an empty environment name to be used in the can-i-deploy command ([a3bfe8a](/../../commit/a3bfe8a))
14
+
1
15
  <a name="v1.66.1"></a>
2
16
  ### v1.66.1 (2023-01-11)
3
17
 
@@ -214,7 +228,7 @@
214
228
 
215
229
  #### Features
216
230
 
217
- * support specifying team UUID when creating a webhook in Pactflow ([c4201e1](/../../commit/c4201e1))
231
+ * support specifying team UUID when creating a webhook in PactFlow ([c4201e1](/../../commit/c4201e1))
218
232
 
219
233
  <a name="v1.45.0"></a>
220
234
  ### v1.45.0 (2021-06-16)
data/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM ruby:3.1-alpine
1
+ FROM ruby:3.2-alpine
2
2
 
3
3
  RUN apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/testing hub
4
4
  RUN apk add --update --no-cache git openssh bash
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Pact Broker Client
2
2
 
3
- A client for the [Pact Broker](https://docs.pact.io/pact_broker/) and [Pactflow](https://pactflow.io/?utm_source=ossdocs&utm_campaign=pact_broker_client_readme). Publishes and retrieves pacts, pacticipants, pacticipant versions, environments, deployments and releases. Supports publishing provider contracts for Pactflow. The functionality is available via a CLI, or via Ruby Rake tasks. You can also use the [Pact CLI Docker image](https://hub.docker.com/r/pactfoundation/pact-cli).
3
+ A client for the [Pact Broker](https://docs.pact.io/pact_broker/) and [PactFlow](https://pactflow.io/?utm_source=ossdocs&utm_campaign=pact_broker_client_readme). Publishes and retrieves pacts, pacticipants, pacticipant versions, environments, deployments and releases. Supports publishing provider contracts for PactFlow. The functionality is available via a CLI, or via Ruby Rake tasks. You can also use the [Pact CLI Docker image](https://hub.docker.com/r/pactfoundation/pact-cli).
4
4
 
5
5
  ![Build status](https://github.com/pact-foundation/pact_broker-client/workflows/Test/badge.svg)
6
6
 
@@ -32,7 +32,7 @@ To connect to a Pact Broker that uses custom SSL cerificates, set the environmen
32
32
 
33
33
  ## Usage - CLI
34
34
 
35
- All commands prefixed with `pact-broker` can be used with the OSS Pact Broker and Pactflow. Commands prefixed with `pactflow` can only be used with Pactflow.
35
+ All commands prefixed with `pact-broker` can be used with the OSS Pact Broker and PactFlow. Commands prefixed with `pactflow` can only be used with PactFlow.
36
36
 
37
37
  The Pact Broker base URL can be specified either using the environment variable `$PACT_BROKER_BASE_URL` or the `-b` or `--broker-base-url` parameters.
38
38
 
@@ -40,7 +40,7 @@ Pact Broker authentication can be performed either using basic auth or a bearer
40
40
 
41
41
  Basic auth parameters can be specified using the `$PACT_BROKER_USERNAME` and `$PACT_BROKER_PASSWORD` environment variables, or the `-u` or `--broker-username` and `-p` or `--broker-password` parameters.
42
42
 
43
- Authentication using a bearer token can be specified using the environment variable `$PACT_BROKER_TOKEN` or the `-k` or `--broker-token` parameters. This bearer token authentication is used by [Pactflow](https://pactflow.io) and is not available in the [OSS Pact Broker](https://docs.pact.io/pact_broker/), which only supports basic auth.
43
+ Authentication using a bearer token can be specified using the environment variable `$PACT_BROKER_TOKEN` or the `-k` or `--broker-token` parameters. This bearer token authentication is used by [PactFlow](https://pactflow.io) and is not available in the [OSS Pact Broker](https://docs.pact.io/pact_broker/), which only supports basic auth.
44
44
 
45
45
 
46
46
  <!-- start-autogenerated-docs -->
@@ -522,6 +522,12 @@ Description:
522
522
 
523
523
  $ pact-broker can-i-deploy --pacticipant Foo 173153ae0 \ --pacticipant Bar --latest main
524
524
 
525
+ ##### Polling
526
+
527
+ If the verification process takes a long time and there are results missing when the can-i-deploy command runs in your CI/CD pipeline, you can configure the
528
+ command to poll and wait for the missing results to arrive. The arguments to specify are `--retry-while-unknown TIMES` and `--retry-interval SECONDS`, set to
529
+ appropriate values for your pipeline.
530
+
525
531
  ### Pacticipants
526
532
 
527
533
  #### create-or-update-pacticipant
@@ -650,8 +656,8 @@ Options:
650
656
  # Trigger this webhook when a contract is published that
651
657
  requires verification
652
658
  [--team-uuid=UUID]
653
- # UUID of the Pactflow team to which the webhook should be
654
- assigned (Pactflow only)
659
+ # UUID of the PactFlow team to which the webhook should be
660
+ assigned (PactFlow only)
655
661
  -b, --broker-base-url=BROKER_BASE_URL
656
662
  # The base URL of the Pact Broker
657
663
  -u, [--broker-username=BROKER_USERNAME]
@@ -713,8 +719,8 @@ Options:
713
719
  # Trigger this webhook when a contract is published that
714
720
  requires verification
715
721
  [--team-uuid=UUID]
716
- # UUID of the Pactflow team to which the webhook should be
717
- assigned (Pactflow only)
722
+ # UUID of the PactFlow team to which the webhook should be
723
+ assigned (PactFlow only)
718
724
  -b, --broker-base-url=BROKER_BASE_URL
719
725
  # The base URL of the Pact Broker
720
726
  -u, [--broker-username=BROKER_USERNAME]
@@ -875,7 +881,7 @@ Options:
875
881
 
876
882
  Generate a UUID for use when calling create-or-update-webhook
877
883
 
878
- ### Provider contracts (Pactflow only)
884
+ ### Provider contracts (PactFlow only)
879
885
 
880
886
  #### publish-provider-contract
881
887
 
@@ -931,7 +937,7 @@ Options:
931
937
  # Verbose output. Default: false
932
938
  ```
933
939
 
934
- Publish provider contract to Pactflow
940
+ Publish provider contract to PactFlow
935
941
 
936
942
  <!-- end-autogenerated-docs -->
937
943
 
@@ -1,11 +1,13 @@
1
- ### A pact between Pact Broker Client and Pactflow
1
+ ### A pact between Pact Broker Client and PactFlow
2
2
 
3
- #### Requests from Pact Broker Client to Pactflow
3
+ #### Requests from Pact Broker Client to PactFlow
4
4
 
5
5
  * [A request for the index resource](#a_request_for_the_index_resource)
6
6
 
7
7
  * [A request to create a provider contract](#a_request_to_create_a_provider_contract)
8
8
 
9
+ * [A request to create a provider contract](#a_request_to_create_a_provider_contract_given_there_is_a_pf:ui_href_in_the_response) given there is a pf:ui href in the response
10
+
9
11
  * [A request to create a webhook for a team](#a_request_to_create_a_webhook_for_a_team_given_a_team_with_UUID_2abbc12a-427d-432a-a521-c870af1739d9_exists) given a team with UUID 2abbc12a-427d-432a-a521-c870af1739d9 exists
10
12
 
11
13
  #### Interactions
@@ -21,7 +23,7 @@ Upon receiving **a request for the index resource** from Pact Broker Client, wit
21
23
  }
22
24
  }
23
25
  ```
24
- Pactflow will respond with:
26
+ PactFlow will respond with:
25
27
  ```json
26
28
  {
27
29
  "status": 200,
@@ -68,12 +70,53 @@ Upon receiving **a request to create a provider contract** from Pact Broker Clie
68
70
  }
69
71
  }
70
72
  ```
73
+ PactFlow will respond with:
74
+ ```json
75
+ {
76
+ "status": 201,
77
+ "headers": {
78
+ "Content-Type": "application/hal+json;charset=utf-8"
79
+ }
80
+ }
81
+ ```
82
+ <a name="a_request_to_create_a_provider_contract_given_there_is_a_pf:ui_href_in_the_response"></a>
83
+ Given **there is a pf:ui href in the response**, upon receiving **a request to create a provider contract** from Pact Broker Client, with
84
+ ```json
85
+ {
86
+ "method": "put",
87
+ "path": "/contracts/provider/Bar/version/1",
88
+ "headers": {
89
+ "Content-Type": "application/json",
90
+ "Accept": "application/hal+json"
91
+ },
92
+ "body": {
93
+ "content": "LS0tCjpzb21lOiBjb250cmFjdAo=",
94
+ "contractType": "oas",
95
+ "contentType": "application/yaml",
96
+ "verificationResults": {
97
+ "success": true,
98
+ "content": "c29tZSByZXN1bHRz",
99
+ "contentType": "text/plain",
100
+ "format": "text",
101
+ "verifier": "my custom tool",
102
+ "verifierVersion": "1.0"
103
+ }
104
+ }
105
+ }
106
+ ```
71
107
  Pactflow will respond with:
72
108
  ```json
73
109
  {
74
110
  "status": 201,
75
111
  "headers": {
76
112
  "Content-Type": "application/hal+json;charset=utf-8"
113
+ },
114
+ "body": {
115
+ "_links": {
116
+ "pf:ui": {
117
+ "href": "http://localhost:1235/contracts/bi-directional/provider/Bar/version/1/provider-contract"
118
+ }
119
+ }
77
120
  }
78
121
  }
79
122
  ```
@@ -109,7 +152,7 @@ Given **a team with UUID 2abbc12a-427d-432a-a521-c870af1739d9 exists**, upon rec
109
152
  }
110
153
  }
111
154
  ```
112
- Pactflow will respond with:
155
+ PactFlow will respond with:
113
156
  ```json
114
157
  {
115
158
  "status": 201,
@@ -1,4 +1,4 @@
1
1
  ### Pacts for Pact Broker Client
2
2
 
3
3
  * [Pact Broker](Pact%20Broker%20Client%20-%20Pact%20Broker.md)
4
- * [Pactflow](Pact%20Broker%20Client%20-%20Pactflow.md)
4
+ * [PactFlow](Pact%20Broker%20Client%20-%20Pactflow.md)
@@ -0,0 +1,116 @@
1
+ openapi: 3.0.1
2
+ info:
3
+ title: Product API
4
+ description: Pactflow Product API demo
5
+ version: 1.0.0
6
+ paths:
7
+ /products:
8
+ post:
9
+ summary: Create a product
10
+ description: Creates a new product
11
+ operationId: createProduct
12
+ requestBody:
13
+ description: Create a new Product
14
+ required: true
15
+ content:
16
+ application/json:
17
+ schema:
18
+ $ref: '#/components/schemas/Product'
19
+ examples:
20
+ application/json:
21
+ value:
22
+ id: "1234"
23
+ type: "food"
24
+ price: 42
25
+ responses:
26
+ "200":
27
+ description: successful operation
28
+ content:
29
+ "application/json; charset=utf-8":
30
+ schema:
31
+ $ref: '#/components/schemas/Product'
32
+ examples:
33
+ application/json:
34
+ value:
35
+ id: "1234"
36
+ type: "food"
37
+ price: 42
38
+ get:
39
+ summary: List all products
40
+ description: Returns all products
41
+ operationId: getAllProducts
42
+ responses:
43
+ "200":
44
+ description: successful operation
45
+ content:
46
+ "application/json; charset=utf-8":
47
+ schema:
48
+ type: "array"
49
+ items:
50
+ $ref: '#/components/schemas/Product'
51
+ examples:
52
+ application/json:
53
+ value:
54
+ - id: "1234"
55
+ type: "food"
56
+ price: 42
57
+ # name: "pizza"
58
+ # version: "1.0.0"
59
+ # see https://github.com/apiaryio/dredd/issues/1430 for why
60
+ "400":
61
+ description: Invalid ID supplied
62
+ content: {}
63
+ /product/{id}:
64
+ get:
65
+ summary: Find product by ID
66
+ description: Returns a single product
67
+ operationId: getProductByID
68
+ parameters:
69
+ - name: id
70
+ in: path
71
+ description: ID of product to get
72
+ schema:
73
+ type: string
74
+ required: true
75
+ example: 10
76
+ responses:
77
+ "200":
78
+ description: successful operation
79
+ content:
80
+ "application/json; charset=utf-8":
81
+ schema:
82
+ $ref: '#/components/schemas/Product'
83
+ examples:
84
+ application/json:
85
+ value:
86
+ id: "1234"
87
+ type: "food"
88
+ price: 42
89
+ # name: "pizza"
90
+ # version: "1.0.0"
91
+ # see https://github.com/apiaryio/dredd/issues/1430 for why
92
+ "400":
93
+ description: Invalid ID supplied
94
+ content: {}
95
+ "404":
96
+ description: Product not found
97
+ content: {}
98
+ components:
99
+ schemas:
100
+ Product:
101
+ type: object
102
+ required:
103
+ - id
104
+ - name
105
+ - price
106
+ properties:
107
+ id:
108
+ type: string
109
+ type:
110
+ type: string
111
+ name:
112
+ type: string
113
+ version:
114
+ type: string
115
+ price:
116
+ type: number
@@ -0,0 +1,12 @@
1
+ # assumes you've set PACT_BROKER_BASE_URL, PACT_BROKER_USERNAME and PACT_BROKER_PASSWORD already
2
+
3
+ bundle exec bin/pactflow publish-provider-contract $(dirname "$0")/oas.yml \
4
+ --provider pactflow-cli-test-provider \
5
+ --provider-app-version 1.0.0 \
6
+ --branch master \
7
+ --tag master \
8
+ --content-type application/yaml \
9
+ --verification-exit-code=0 \
10
+ --verification-results $(dirname "$0")/oas.yml \
11
+ --verification-results-content-type application/yaml \
12
+ --verifier pactflow-cli-test-provider
@@ -125,7 +125,7 @@ module PactBroker
125
125
  end
126
126
  url
127
127
  else
128
- raise PactBroker::Client::RelationNotFound.new("Could not find relation #{relation_name} in index resource. Try upgrading your Pact Broker as the feature you require may not exist in your version. If you are using Pactflow, you may not have the permissions required for this action.")
128
+ raise PactBroker::Client::RelationNotFound.new("Could not find relation #{relation_name} in index resource. Try upgrading your Pact Broker as the feature you require may not exist in your version. If you are using PactFlow, you may not have the permissions required for this action.")
129
129
  end
130
130
  end
131
131
  end
@@ -90,9 +90,21 @@ module PactBroker
90
90
  ::Term::ANSIColor.green(text)
91
91
  end
92
92
 
93
+ def blue(text)
94
+ ::Term::ANSIColor.blue(text)
95
+ end
96
+
97
+ def magenta(text)
98
+ ::Term::ANSIColor.magenta(text)
99
+ end
100
+
93
101
  def red(text)
94
102
  ::Term::ANSIColor.red(text)
95
103
  end
104
+
105
+ def yellow(text)
106
+ ::Term::ANSIColor.yellow(text)
107
+ end
96
108
  end
97
109
  end
98
110
  end
@@ -22,3 +22,7 @@ Can-i-deploy can also be used to check if arbitrary versions have a successful v
22
22
 
23
23
  $ pact-broker can-i-deploy --pacticipant Foo 173153ae0 \
24
24
  --pacticipant Bar --latest main
25
+
26
+ ##### Polling
27
+
28
+ If the verification process takes a long time and there are results missing when the can-i-deploy command runs in your CI/CD pipeline, you can configure the command to poll and wait for the missing results to arrive. The arguments to specify are `--retry-while-unknown TIMES` and `--retry-interval SECONDS`, set to appropriate values for your pipeline.
@@ -15,6 +15,19 @@ module PactBroker
15
15
  using PactBroker::Client::HashRefinements
16
16
 
17
17
  no_commands do
18
+ def initialize(args = [], options = {}, config = {})
19
+ super
20
+ postprocess_options
21
+ end
22
+
23
+ def postprocess_options
24
+ new_options = {}
25
+ if options.include?("broker_base_url")
26
+ new_options["broker_base_url"] = options["broker_base_url"].chomp('/')
27
+ end
28
+ self.options = options.merge(new_options)
29
+ end
30
+
18
31
  def self.exit_on_failure?
19
32
  true
20
33
  end
@@ -31,6 +31,7 @@ module PactBroker
31
31
  selectors = VersionSelectorOptionsParser.call(ARGV).select { |s| !s[:ignore] }
32
32
  ignore_selectors = VersionSelectorOptionsParser.call(ARGV).select { |s| s[:ignore] } + ignore_selectors_from_environment_variable
33
33
  validate_can_i_deploy_selectors(selectors)
34
+ validate_can_i_deploy_options
34
35
  dry_run = options.dry_run || ENV["PACT_BROKER_CAN_I_DEPLOY_DRY_RUN"] == "true"
35
36
  can_i_deploy_options = { output: options.output, retry_while_unknown: options.retry_while_unknown, retry_interval: options.retry_interval, dry_run: dry_run, verbose: options.verbose }
36
37
  result = CanIDeploy.call(selectors, { to_tag: options.to, to_environment: options.to_environment, limit: options.limit, ignore_selectors: ignore_selectors }, can_i_deploy_options, pact_broker_client_options)
@@ -82,6 +83,12 @@ module PactBroker
82
83
  raise ::Thor::RequiredArgumentMissingError, "The version must be specified using `--version VERSION`, `--branch BRANCH` `--latest`, `--latest TAG`, or `--all TAG` for pacticipant #{pacticipants_without_versions.join(", ")}" if pacticipants_without_versions.any?
83
84
  end
84
85
 
86
+ def validate_can_i_deploy_options
87
+ if options[:to_environment] && options[:to_environment].blank?
88
+ raise ::Thor::RequiredArgumentMissingError, "The environment name cannot be blank"
89
+ end
90
+ end
91
+
85
92
  def ignore_selectors_from_environment_variable
86
93
  ENV.fetch("PACT_BROKER_CAN_I_DEPLOY_IGNORE", "").split(",").collect(&:strip).collect{ |i| { pacticipant: i } }
87
94
  end
@@ -93,7 +93,7 @@ module PactBroker
93
93
  elsif path.start_with?("-")
94
94
  raise Thor::Error.new("ERROR: pact-broker publish was called with invalid arguments #{[path]}")
95
95
  else
96
- raise Thor::Error.new("Specified pact file '#{path}' does not exist. This sometimes indicates one of the arguments has been specified with the wrong name and has been incorrectly identified as a file path.")
96
+ raise Thor::Error.new("Specified pact file '#{path}' does not exist. This sometimes indicates one of the arguments has been specified with the wrong name and has been incorrectly identified as a file path. If you are using Docker, check that you have mounted the pact file or directory into the container correctly using `-v`, and have specified the location of the pact file or directory in the *Docker container*, not the *host*.")
97
97
  end
98
98
  end
99
99
  end
@@ -25,7 +25,7 @@ module PactBroker
25
25
  method_option :provider_verification_failed, type: :boolean, desc: "Trigger this webhook when a failed provider verification result is published"
26
26
  method_option :provider_verification_succeeded, type: :boolean, desc: "Trigger this webhook when a successful provider verification result is published"
27
27
  method_option :contract_requiring_verification_published, type: :boolean, desc: "Trigger this webhook when a contract is published that requires verification"
28
- method_option :team_uuid, banner: "UUID", desc: "UUID of the Pactflow team to which the webhook should be assigned (Pactflow only)"
28
+ method_option :team_uuid, banner: "UUID", desc: "UUID of the PactFlow team to which the webhook should be assigned (PactFlow only)"
29
29
  shared_authentication_options
30
30
  end
31
31
  end
@@ -1,5 +1,5 @@
1
1
  require 'term/ansicolor'
2
-
2
+ require "uri"
3
3
  module PactBroker
4
4
  module Client
5
5
  class ColorizeNotices
@@ -11,16 +11,27 @@ module PactBroker
11
11
 
12
12
  def self.colorized_message(notice)
13
13
  color = color_for_type(notice.type)
14
- if color
14
+ uri_strings = ::URI.extract(notice.text, %w(http https))
15
+ if color && uri_strings.any?
16
+ color_for_url(::Term::ANSIColor.color(color, notice.text || ''), uri_strings)
17
+ elsif color
15
18
  ::Term::ANSIColor.color(color, notice.text || '')
19
+ elsif uri_strings.any?
20
+ color_for_url(notice.text, uri_strings)
16
21
  else
17
22
  notice.text
18
23
  end
19
24
  end
20
25
 
26
+ def self.color_for_url(text, uris)
27
+ uris.inject(text) do | new_text, uri |
28
+ new_text.gsub(uri, ::Term::ANSIColor.magenta(uri))
29
+ end
30
+ end
31
+
21
32
  def self.color_for_type(type)
22
33
  case type
23
- when "warning", "prompt" then "yellow"
34
+ when "warning", "prompt" then :yellow
24
35
  when "error", "danger" then :red
25
36
  when "success" then :green
26
37
  else nil
@@ -31,7 +31,7 @@ module PactBroker
31
31
 
32
32
  def not_supported_message
33
33
  if is_pactflow?
34
- "This version of Pactflow does not support recording #{action}s, or you do not have the required permission to read environments. Please upgrade to the latest version if using Pactflow On-Premises, and ensure the user has the environment read permission."
34
+ "This version of PactFlow does not support recording #{action}s, or you do not have the required permission to read environments. Please upgrade to the latest version if using PactFlow On-Premises, and ensure the user has the environment read permission."
35
35
  else
36
36
  "This version of the Pact Broker does not support recording #{action}s. Please upgrade to version 2.80.0 or later."
37
37
  end
@@ -8,7 +8,7 @@ module PactBroker
8
8
  using PactBroker::Client::HashRefinements
9
9
 
10
10
  NOT_SUPPORTED_MESSAGE = "This version of the Pact Broker does not support environments. Please upgrade to version 2.80.0 or later."
11
- PACTFLOW_NOT_SUPPORTED_MESSAGE = "This version of Pactflow does not support environments or you do not have the required permission to read them. Please upgrade to the latest version if using Pactflow On-Premises and ensure the user has the environment read permission."
11
+ PACTFLOW_NOT_SUPPORTED_MESSAGE = "This version of PactFlow does not support environments or you do not have the required permission to read them. Please upgrade to the latest version if using PactFlow On-Premises and ensure the user has the environment read permission."
12
12
 
13
13
  private
14
14
 
@@ -163,7 +163,7 @@ module PactBroker
163
163
  end
164
164
 
165
165
  def relation_not_found_error_message(key, href)
166
- "Could not find relation '#{key}' in resource at #{href}. The most likely reason for this is that you are on an old version of the Pact Broker and you need to upgrade, or you are using Pactflow and you don't have the permissions required for this action."
166
+ "Could not find relation '#{key}' in resource at #{href}. The most likely reason for this is that you are on an old version of the Pact Broker and you need to upgrade, or you are using PactFlow and you don't have the permissions required for this action."
167
167
  end
168
168
  end
169
169
 
@@ -29,7 +29,7 @@ module PactBroker
29
29
  end
30
30
 
31
31
  def pact_broker_name
32
- is_pactflow? ? "Pactflow" : "the Pact Broker"
32
+ is_pactflow? ? "PactFlow" : "the Pact Broker"
33
33
  end
34
34
  end
35
35
  end
@@ -1,5 +1,5 @@
1
1
  module PactBroker
2
2
  module Client
3
- VERSION = '1.66.1'
3
+ VERSION = '1.67.0'
4
4
  end
5
5
  end
@@ -10,7 +10,7 @@ module Pactflow
10
10
 
11
11
  def self.included(thor)
12
12
  thor.class_eval do
13
- desc 'publish-provider-contract CONTRACT_FILE ...', "Publish provider contract to Pactflow"
13
+ desc 'publish-provider-contract CONTRACT_FILE ...', "Publish provider contract to PactFlow"
14
14
  method_option :provider, required: true, desc: "The provider name"
15
15
  method_option :provider_app_version, required: true, aliases: "-a", desc: "The provider application version"
16
16
  method_option :branch, aliases: "-h", desc: "Repository branch of the provider version"
@@ -1,5 +1,6 @@
1
1
  require "pact_broker/client/base_command"
2
2
  require "pact_broker/client/versions/create"
3
+ require 'pact_broker/client/colorize_notices'
3
4
  require "base64"
4
5
 
5
6
  module Pactflow
@@ -22,8 +23,33 @@ module Pactflow
22
23
 
23
24
  def do_call
24
25
  create_branch_version_and_tags
25
- create_contract
26
- PactBroker::Client::CommandResult.new(true, green("Successfully published provider contract for #{provider_name} version #{provider_version_number} to Pactflow"))
26
+ render_response(create_contract)
27
+ end
28
+
29
+ def render_response(res)
30
+ notices = [
31
+ { type: 'success', text: "Successfully published provider contract for #{provider_name} version #{provider_version_number} to PactFlow"},
32
+ ]
33
+ if res.body && res.body['_links'] && res.body['_links']['pf:ui']['href']
34
+ notices.concat([{ text: "View the uploaded contract at #{res.body['_links']['pf:ui']['href']}" }])
35
+ end
36
+ notices.concat(next_steps)
37
+ PactBroker::Client::CommandResult.new(true, PactBroker::Client::ColorizeNotices.call(notices.collect do |n|
38
+ OpenStruct.new(n)
39
+ end).join("\n"))
40
+ end
41
+
42
+ def next_steps
43
+ [
44
+ { type: 'prompt', text: 'Next steps:' },
45
+ { type: 'prompt',
46
+ text: ' * Check your application is safe to deploy - https://docs.pact.io/can_i_deploy' },
47
+ { text: " pact-broker can-i-deploy --pacticipant #{provider_name} --version #{provider_version_number} --to-environment <your environment name>" },
48
+ { type: 'prompt',
49
+ text: ' * Record deployment or release to specified environment (choose one) - https://docs.pact.io/go/record-deployment' },
50
+ { text: " pact-broker record-deployment --pacticipant #{provider_name} --version #{provider_version_number} --environment <your environment name>" },
51
+ { text: " pact-broker record-release --pacticipant #{provider_name} --version #{provider_version_number} --environment <your environment name>" }
52
+ ]
27
53
  end
28
54
 
29
55
  def create_branch_version_and_tags
@@ -44,7 +70,7 @@ module Pactflow
44
70
  def create_contract
45
71
  contract_path = "#{pact_broker_base_url}/contracts/provider/{provider}/version/{version}"
46
72
  entrypoint = create_entry_point(contract_path, pact_broker_client_options)
47
- entrypoint.expand(provider: provider_name, version: provider_version_number).put!(contract_params)
73
+ entrypoint.expand(provider: provider_name, version: provider_version_number).put!(contract_params).response
48
74
  end
49
75
 
50
76
  def contract_params
@@ -56,7 +82,7 @@ module Pactflow
56
82
  verifier: verification_results[:verifier],
57
83
  verifierVersion: verification_results[:verifier_version]
58
84
  }.compact
59
-
85
+
60
86
  body_params = {
61
87
  content: encode_content(contract[:content]),
62
88
  contractType: contract[:specification],
@@ -66,7 +92,6 @@ module Pactflow
66
92
  if verification_results_params.any?
67
93
  body_params[:verificationResults] = verification_results_params
68
94
  end
69
-
70
95
  body_params
71
96
  end
72
97
 
@@ -28,11 +28,11 @@ Gem::Specification.new do |gem|
28
28
  gem.add_runtime_dependency 'rake', '~> 13.0' #For FileList
29
29
  gem.add_runtime_dependency 'dig_rb', '~> 1.0'
30
30
 
31
- gem.add_development_dependency 'fakefs', '~> 0.4'
31
+ gem.add_development_dependency 'fakefs', '~> 2.4'
32
32
  gem.add_development_dependency 'webmock', '~> 3.0'
33
33
  gem.add_development_dependency 'conventional-changelog', '~>1.3'
34
34
  gem.add_development_dependency 'pact', '~> 1.16'
35
35
  gem.add_development_dependency 'pact-support', '~> 1.16'
36
- gem.add_development_dependency 'approvals', '0.0.18'
36
+ gem.add_development_dependency 'approvals', '0.0.26'
37
37
  gem.add_development_dependency 'rspec-its', '~> 1.3'
38
38
  end
@@ -22,7 +22,7 @@ PACT_BROKER_COMMAND_GROUPS = [
22
22
  ]
23
23
 
24
24
  PACTFLOW_COMMAND_GROUPS = [
25
- [Pactflow::Client::CLI::Pactflow, "Provider contracts (Pactflow only)", %w[publish-provider-contract]]
25
+ [Pactflow::Client::CLI::Pactflow, "Provider contracts (PactFlow only)", %w[publish-provider-contract]]
26
26
  ]
27
27
 
28
28
  def print_wrapped(message, options = {})
@@ -86,12 +86,16 @@ STATES = {
86
86
  /^Usage:/ => :usage
87
87
  },
88
88
  usage: {
89
- /^Options:/ => :options
89
+ /^Options:/ => :options,
90
90
  },
91
91
  options: {
92
92
  /^$/ => :after_options
93
93
  },
94
94
  after_options: {
95
+ /^Usage:/ => :usage,
96
+ /^ ##### / => :section_in_usage
97
+ },
98
+ section_in_usage: {
95
99
  /^Usage:/ => :usage
96
100
  }
97
101
  }
@@ -126,13 +130,14 @@ def reformat_docs(generated_thor_docs, command)
126
130
  @current_state = transitions[line_starts_with]
127
131
  end
128
132
 
129
-
130
133
  lines = if has_option_and_banner(line)
131
134
  option, banner = line.split("#", 2)
132
135
  [option] + format_banner("# " + banner)
133
136
  elsif has_only_banner(line)
134
137
  space, banner = line.split("#", 2)
135
138
  format_banner("# " + banner)
139
+ elsif @current_state == :section_in_usage
140
+ [line.strip]
136
141
  else
137
142
  [line]
138
143
  end
@@ -70,6 +70,16 @@ module PactBroker
70
70
  expect(CanIDeploy).to receive(:call).with(anything, {to_tag: nil, to_environment: 'prod', limit: 1000, ignore_selectors: []}, anything, anything)
71
71
  invoke_can_i_deploy
72
72
  end
73
+
74
+ context "when the environment is an empty string" do
75
+ before do
76
+ subject.options.to_environment = ' '
77
+ end
78
+
79
+ it "raises an error" do
80
+ expect { invoke_can_i_deploy }.to raise_error ::Thor::RequiredArgumentMissingError
81
+ end
82
+ end
73
83
  end
74
84
 
75
85
  context "with basic auth" do
@@ -72,6 +72,21 @@ module PactBroker::Client::CLI
72
72
  end
73
73
  end
74
74
 
75
+ it "removes trailing slashes from the broker base url when passed as an arg" do
76
+ expect(Delegate).to receive(:call) do | options |
77
+ expect(options.broker_base_url).to eq 'http://bar'
78
+ end
79
+ TestThor.start(%w{test_using_env_vars --broker-base-url http://bar/})
80
+ end
81
+
82
+ it "removes trailing slashes from the broker base url when passed as an env var" do
83
+ ENV['PACT_BROKER_BASE_URL'] = 'http://bar/'
84
+ expect(Delegate).to receive(:call) do | options |
85
+ expect(options.broker_base_url).to eq 'http://bar'
86
+ end
87
+ TestThor.start(%w{test_using_env_vars})
88
+ end
89
+
75
90
  describe ".turn_muliple_tag_options_into_array" do
76
91
  it "turns '--tag foo --tag bar' into '--tag foo bar'" do
77
92
  input = %w{--ignore this --tag foo --tag bar --wiffle --that}
@@ -96,7 +96,7 @@ module PactBroker
96
96
  expect(subject.message).to include "does not support"
97
97
  end
98
98
 
99
- context "when the server is Pactflow" do
99
+ context "when the server is PactFlow" do
100
100
  let(:index_headers) { { "Content-Type" => "application/hal+json", "Pactflow-Something" => "foo" } }
101
101
 
102
102
  it "returns an error response" do
@@ -165,7 +165,7 @@ module PactBroker
165
165
  expect(subject.message).to include "No environment found with name 'test'. Available options: prod"
166
166
  end
167
167
 
168
- context "when the server is Pactflow" do
168
+ context "when the server is PactFlow" do
169
169
  let(:index_headers) { { "Content-Type" => "application/hal+json", "X-Pactflow-Sha" => "123" } }
170
170
 
171
171
  it "returns a customised message" do
@@ -191,7 +191,7 @@ module PactBroker
191
191
  end
192
192
  end
193
193
 
194
- context "when the response headers contain Pactflow" do
194
+ context "when the response headers contain PactFlow" do
195
195
  before do
196
196
  allow_any_instance_of(RecordDeployment).to receive(:check_if_command_supported)
197
197
  allow_any_instance_of(RecordDeployment).to receive(:check_environment_exists)
@@ -205,8 +205,8 @@ module PactBroker
205
205
  double('PactBroker::Client::Hal::Entity', response: double('response', headers: response_headers) )
206
206
  end
207
207
 
208
- it "indicates the API was Pactflow" do
209
- expect(subject.message).to include "Recorded deployment of Foo version 1 to test environment (application instance blue) in Pactflow"
208
+ it "indicates the API was PactFlow" do
209
+ expect(subject.message).to include "Recorded deployment of Foo version 1 to test environment (application instance blue) in PactFlow"
210
210
  end
211
211
 
212
212
  context "when application_instance is nil" do
@@ -3,7 +3,7 @@
3
3
  "name": "Pact Broker Client"
4
4
  },
5
5
  "provider": {
6
- "name": "Pactflow"
6
+ "name": "PactFlow"
7
7
  },
8
8
  "interactions": [
9
9
  {
@@ -36,6 +36,44 @@
36
36
  }
37
37
  }
38
38
  },
39
+ {
40
+ "description": "a request to create a provider contract",
41
+ "providerState": "there is a pf:ui href in the response",
42
+ "request": {
43
+ "method": "put",
44
+ "path": "/contracts/provider/Bar/version/1",
45
+ "headers": {
46
+ "Content-Type": "application/json",
47
+ "Accept": "application/hal+json"
48
+ },
49
+ "body": {
50
+ "content": "LS0tCjpzb21lOiBjb250cmFjdAo=",
51
+ "contractType": "oas",
52
+ "contentType": "application/yaml",
53
+ "verificationResults": {
54
+ "success": true,
55
+ "content": "c29tZSByZXN1bHRz",
56
+ "contentType": "text/plain",
57
+ "format": "text",
58
+ "verifier": "my custom tool",
59
+ "verifierVersion": "1.0"
60
+ }
61
+ }
62
+ },
63
+ "response": {
64
+ "status": 201,
65
+ "headers": {
66
+ "Content-Type": "application/hal+json;charset=utf-8"
67
+ },
68
+ "body": {
69
+ "_links": {
70
+ "pf:ui": {
71
+ "href": "http://localhost:1235/contracts/bi-directional/provider/Bar/version/1/provider-contract"
72
+ }
73
+ }
74
+ }
75
+ }
76
+ },
39
77
  {
40
78
  "description": "a request for the index resource",
41
79
  "request": {
@@ -15,7 +15,7 @@ Pact.service_consumer 'Pact Broker Client' do
15
15
  end
16
16
  end
17
17
 
18
- has_pact_with "Pactflow" do
18
+ has_pact_with "PactFlow" do
19
19
  mock_service :pactflow do
20
20
  port 1235
21
21
  pact_specification_version "2.0"
@@ -2,7 +2,7 @@ require_relative "pact_helper"
2
2
  require "pactflow/client/provider_contracts/publish"
3
3
  require "yaml"
4
4
 
5
- RSpec.describe "publishing a provider contract to Pactflow", pact: true do
5
+ RSpec.describe "publishing a provider contract to PactFlow", pact: true do
6
6
  before do
7
7
  # no point re-testing this
8
8
  allow(PactBroker::Client::Versions::Create).to receive(:call).and_return(double("result", success: true))
@@ -87,6 +87,41 @@ RSpec.describe "publishing a provider contract to Pactflow", pact: true do
87
87
  expect(subject).to be_a PactBroker::Client::CommandResult
88
88
  expect(subject.success).to be true
89
89
  expect(subject.message).to include "Successfully published provider contract for Bar version 1"
90
+ expect(subject.message).not_to include pactflow.mock_service_base_url
90
91
  end
91
92
  end
92
- end
93
+
94
+ context "creating a provider contract with valid parameters with pf:ui return results" do
95
+ let(:success_response_with_pf_ui_url) do
96
+ {
97
+ status: response_status,
98
+ headers: pact_broker_response_headers,
99
+ body: { "_links": {
100
+ "pf:ui": {
101
+ "href": "#{pactflow.mock_service_base_url}/contracts/bi-directional/provider/Bar/version/1/provider-contract"
102
+ }
103
+ } }
104
+ }
105
+ end
106
+ before do
107
+ pactflow
108
+ .given("there is a pf:ui href in the response")
109
+ .upon_receiving("a request to create a provider contract")
110
+ .with(
111
+ method: :put,
112
+ path: "/contracts/provider/Bar/version/1",
113
+ headers: put_request_headers,
114
+ body: request_body
115
+ )
116
+ .will_respond_with(success_response_with_pf_ui_url)
117
+ end
118
+
119
+ it "returns a CommandResult with success = true and a provider contract ui url" do
120
+ expect(subject).to be_a PactBroker::Client::CommandResult
121
+ expect(subject.success).to be true
122
+ expect(subject.message).to include "Successfully published provider contract for Bar version 1"
123
+ expect(subject.message).to include "Next steps:"
124
+ expect(subject.message).to include success_response_with_pf_ui_url[:body][:_links][:'pf:ui'][:href]
125
+ end
126
+ end
127
+ end
@@ -1,7 +1,7 @@
1
1
  require_relative 'pact_helper'
2
2
  require 'pact_broker/client/webhooks/create'
3
3
 
4
- RSpec.describe "creating a webhook in Pactflow", pact: true do
4
+ RSpec.describe "creating a webhook in PactFlow", pact: true do
5
5
 
6
6
  include_context "pact broker"
7
7
  include PactBrokerPactHelperMethods
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact_broker-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.66.1
4
+ version: 1.67.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Beth Skurrie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-10 00:00:00.000000000 Z
11
+ date: 2023-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -112,14 +112,14 @@ dependencies:
112
112
  requirements:
113
113
  - - "~>"
114
114
  - !ruby/object:Gem::Version
115
- version: '0.4'
115
+ version: '2.4'
116
116
  type: :development
117
117
  prerelease: false
118
118
  version_requirements: !ruby/object:Gem::Requirement
119
119
  requirements:
120
120
  - - "~>"
121
121
  - !ruby/object:Gem::Version
122
- version: '0.4'
122
+ version: '2.4'
123
123
  - !ruby/object:Gem::Dependency
124
124
  name: webmock
125
125
  requirement: !ruby/object:Gem::Requirement
@@ -182,14 +182,14 @@ dependencies:
182
182
  requirements:
183
183
  - - '='
184
184
  - !ruby/object:Gem::Version
185
- version: 0.0.18
185
+ version: 0.0.26
186
186
  type: :development
187
187
  prerelease: false
188
188
  version_requirements: !ruby/object:Gem::Requirement
189
189
  requirements:
190
190
  - - '='
191
191
  - !ruby/object:Gem::Version
192
- version: 0.0.18
192
+ version: 0.0.26
193
193
  - !ruby/object:Gem::Dependency
194
194
  name: rspec-its
195
195
  requirement: !ruby/object:Gem::Requirement
@@ -215,6 +215,7 @@ extensions: []
215
215
  extra_rdoc_files: []
216
216
  files:
217
217
  - ".github/workflows/release_gem.yml"
218
+ - ".github/workflows/smartbear-issue-label-added.yml"
218
219
  - ".github/workflows/test.yml"
219
220
  - ".github/workflows/trigger_pact_docs_update.yml"
220
221
  - ".gitignore"
@@ -236,8 +237,10 @@ files:
236
237
  - doc/pacts/markdown/README.md
237
238
  - example/scripts/README.md
238
239
  - example/scripts/deploy-consumer.sh
240
+ - example/scripts/oas.yml
239
241
  - example/scripts/pact.json
240
242
  - example/scripts/publish-pact.sh
243
+ - example/scripts/publish-provider-contract.sh
241
244
  - example/scripts/publish-verification.sh
242
245
  - example/scripts/verification.json
243
246
  - example/scripts/verify-changed-pact.sh
@@ -446,7 +449,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
446
449
  - !ruby/object:Gem::Version
447
450
  version: '0'
448
451
  requirements: []
449
- rubygems_version: 3.4.3
452
+ rubygems_version: 3.4.13
450
453
  signing_key:
451
454
  specification_version: 4
452
455
  summary: See description