pact_broker-client 1.44.0 → 1.47.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +15 -1
  3. data/CHANGELOG.md +36 -0
  4. data/README.md +54 -54
  5. data/doc/pacts/markdown/Pact Broker Client - Pact Broker.md +315 -1
  6. data/doc/pacts/markdown/Pact Broker Client - Pactflow.md +94 -0
  7. data/doc/pacts/markdown/README.md +1 -0
  8. data/lib/pact_broker/client/base_command.rb +3 -0
  9. data/lib/pact_broker/client/can_i_deploy.rb +40 -5
  10. data/lib/pact_broker/client/cli/broker.rb +7 -137
  11. data/lib/pact_broker/client/cli/custom_thor.rb +0 -16
  12. data/lib/pact_broker/client/cli/deployment_commands.rb +25 -5
  13. data/lib/pact_broker/client/cli/matrix_commands.rb +93 -0
  14. data/lib/pact_broker/client/cli/webhook_commands.rb +122 -0
  15. data/lib/pact_broker/client/deployments.rb +4 -4
  16. data/lib/pact_broker/client/deployments/record_support_ended.rb +103 -0
  17. data/lib/pact_broker/client/deployments/record_undeployment.rb +43 -36
  18. data/lib/pact_broker/client/hal/entity.rb +17 -2
  19. data/lib/pact_broker/client/matrix/resource.rb +4 -0
  20. data/lib/pact_broker/client/pacticipants/create.rb +1 -1
  21. data/lib/pact_broker/client/verification_required.rb +34 -0
  22. data/lib/pact_broker/client/version.rb +1 -1
  23. data/lib/pact_broker/client/webhooks/create.rb +14 -8
  24. data/script/record-deployment.sh +1 -1
  25. data/script/record-deployments-and-releases.sh +11 -5
  26. data/script/record-undeployment.sh +1 -1
  27. data/script/webhook-commands.sh +12 -0
  28. data/spec/fixtures/approvals/can_i_deploy_failure_dry_run.approved.txt +7 -0
  29. data/spec/fixtures/approvals/can_i_deploy_success_dry_run.approved.txt +7 -0
  30. data/spec/lib/pact_broker/client/can_i_deploy_spec.rb +62 -2
  31. data/spec/lib/pact_broker/client/cli/broker_can_i_deploy_spec.rb +15 -2
  32. data/spec/lib/pact_broker/client/cli/broker_run_webhook_commands_spec.rb +4 -2
  33. data/spec/lib/pact_broker/client/deployments/record_support_ended_spec.rb +208 -0
  34. data/spec/lib/pact_broker/client/deployments/record_undeployment_spec.rb +219 -0
  35. data/spec/pacts/pact_broker_client-pact_broker.json +317 -1
  36. data/spec/pacts/pact_broker_client-pactflow.json +118 -0
  37. data/spec/service_providers/pact_broker_client_register_repository_spec.rb +2 -2
  38. data/spec/service_providers/pact_helper.rb +15 -10
  39. data/spec/service_providers/pactflow_webhooks_create_spec.rb +86 -0
  40. data/spec/service_providers/record_deployment_spec.rb +1 -3
  41. data/spec/service_providers/record_release_spec.rb +2 -7
  42. data/spec/service_providers/record_undeployment_spec.rb +164 -0
  43. data/spec/service_providers/webhooks_create_spec.rb +1 -1
  44. data/spec/spec_helper.rb +1 -0
  45. data/spec/support/shared_context.rb +2 -1
  46. data/tasks/pact.rake +8 -6
  47. metadata +23 -3
@@ -0,0 +1,219 @@
1
+ require 'pact_broker/client/deployments/record_undeployment'
2
+
3
+ module PactBroker
4
+ module Client
5
+ module Deployments
6
+ describe RecordUndeployment do
7
+ let(:params) do
8
+ {
9
+ pacticipant_name: "Foo",
10
+ target: target,
11
+ environment_name: "test"
12
+ }
13
+ end
14
+ let(:target) { "customer-1" }
15
+ let(:output) { "text" }
16
+ let(:options) { { output: output, verbose: true } }
17
+ let(:pact_broker_base_url) { "http://broker" }
18
+ let(:pact_broker_client_options) { { pact_broker_base_url: pact_broker_base_url } }
19
+
20
+ let(:index_body_hash) do
21
+ {
22
+ _links: {
23
+ :'pb:environments' => {
24
+ href: environments_url
25
+ },
26
+ :'pb:pacticipant' => {
27
+ href: pacticipant_url
28
+ }
29
+ }
30
+ }
31
+ end
32
+
33
+ let(:environments_hash) do
34
+ {
35
+ _links: {
36
+ :'pb:environments' => [
37
+ {
38
+ name: "test",
39
+ href: test_environment_url
40
+ }
41
+ ]
42
+ }
43
+ }
44
+ end
45
+
46
+ let(:environment_hash) do
47
+ {
48
+ _links: {
49
+ :'pb:currently-deployed-deployed-versions' => {
50
+ href: currently_deployed_versions_url
51
+ }
52
+ }
53
+ }
54
+ end
55
+
56
+ let(:deployed_versions_hash) do
57
+ {
58
+ _embedded: {
59
+ deployedVersions: [
60
+ {
61
+ target: "customer-1",
62
+ _links: {
63
+ self: {
64
+ href: deployed_version_url_1
65
+ }
66
+ }
67
+ },
68
+ {
69
+ target: returned_target_2,
70
+ _links: {
71
+ self: {
72
+ href: deployed_version_url_2
73
+ }
74
+ }
75
+ }
76
+ ]
77
+ }
78
+ }
79
+ end
80
+
81
+ let(:returned_target_2) { nil }
82
+ let(:deployed_version_hash) do
83
+ {
84
+ _embedded: {
85
+ version: {
86
+ number: "2"
87
+ }
88
+ }
89
+ }
90
+ end
91
+
92
+ let(:environments_url) { "#{webmock_base_url}/environments" }
93
+ let(:test_environment_url) { "#{webmock_base_url}/environments/1234" }
94
+ let(:currently_deployed_versions_url) { "#{webmock_base_url}/currently-deployed-versions" }
95
+ let(:deployed_version_url_1) { "#{webmock_base_url}/deployed-version-1" }
96
+ let(:deployed_version_url_2) { "#{webmock_base_url}/deployed-version-2" }
97
+ let(:pacticipant_url) { "#{webmock_base_url}/pacticipant" }
98
+
99
+ let(:webmock_base_url) { "http://broker" }
100
+
101
+ let!(:index_request) do
102
+ stub_request(:get, "http://broker").to_return(status: 200, body: index_body_hash.to_json, headers: { "Content-Type" => "application/hal+json" } )
103
+ end
104
+
105
+ let!(:environments_request) do
106
+ stub_request(:get, "http://broker/environments").to_return(status: 200, body: environments_hash.to_json, headers: { "Content-Type" => "application/hal+json" } )
107
+ end
108
+
109
+ let!(:environment_request) do
110
+ stub_request(:get, test_environment_url).to_return(status: 200, body: environment_hash.to_json, headers: { "Content-Type" => "application/hal+json" } )
111
+ end
112
+
113
+ let!(:deployed_versions_request) do
114
+ stub_request(:get, currently_deployed_versions_url + "?pacticipant=Foo").to_return(status: 200, body: deployed_versions_hash.to_json, headers: { "Content-Type" => "application/hal+json" } )
115
+ end
116
+
117
+ let!(:deployed_version_patch_request_1) do
118
+ stub_request(:patch, deployed_version_url_1).with(body: { currentlyDeployed: false}.to_json).to_return(status: 200, body: deployed_version_hash.to_json, headers: { "Content-Type" => "application/hal+json" })
119
+ end
120
+
121
+ let!(:deployed_version_patch_request_2) do
122
+ stub_request(:patch, deployed_version_url_2).with(body: { currentlyDeployed: false}.to_json).to_return(status: 200, body: deployed_version_hash.to_json, headers: { "Content-Type" => "application/hal+json" })
123
+ end
124
+
125
+ let!(:pacticipant_request) do
126
+ stub_request(:get, pacticipant_url).to_return(status: pacticipant_request_status, body: {}.to_json, headers: { "Content-Type" => "application/hal+json" })
127
+ end
128
+
129
+ let(:pacticipant_request_status) { 200 }
130
+
131
+ subject { RecordUndeployment.call(params, options, pact_broker_client_options) }
132
+
133
+ its(:success) { is_expected.to eq true }
134
+ its(:message) { is_expected.to include "Recorded undeployment of Foo version 2 from test environment (target customer-1) in the Pact Broker" }
135
+
136
+ context "when there is no pb:environments relation in the index" do
137
+ let(:index_body_hash) do
138
+ {
139
+ _links: {}
140
+ }
141
+ end
142
+
143
+ its(:success) { is_expected.to be false }
144
+ its(:message) { is_expected.to include "support" }
145
+ end
146
+
147
+ context "when output is json" do
148
+ let(:output) { "json" }
149
+ its(:message) { is_expected.to eq [deployed_version_hash].to_json }
150
+ end
151
+
152
+ context "when there is an error returned from one of the deployed version updates (there should only ever be one deployed version, but testing just for the sake of it)" do
153
+ let!(:deployed_version_patch_request_2) do
154
+ stub_request(:patch, deployed_version_url_2).to_return(status: 400, body: { errors: { foo: ["some error"]}}.to_json, headers: { "Content-Type" => "application/hal+json" })
155
+ end
156
+
157
+ let(:returned_target_2) { "customer-1" }
158
+
159
+ its(:success) { is_expected.to be false }
160
+ its(:message) { is_expected.to include "Recorded undeployment of Foo version 2" }
161
+ its(:message) { is_expected.to include "some error" }
162
+ end
163
+
164
+ context "when there is no currently-deployed-versions relation in the environment resource" do
165
+ let(:environment_hash) do
166
+ {
167
+ _links: {}
168
+ }
169
+ end
170
+
171
+ its(:success) { is_expected.to be false }
172
+ its(:message) { is_expected.to include "support" }
173
+ end
174
+
175
+ context "when a target is provided and there is no deployed version with a matching target" do
176
+ let(:target) { "wrong" }
177
+ let(:expected_message) { "Foo is not currently deployed to target 'wrong' in test environment. Please specify one of the following targets to record the undeployment from: customer-1, <no target>" }
178
+
179
+ its(:success) { is_expected.to be false }
180
+ its(:message) { is_expected.to include expected_message }
181
+
182
+ context "when output is json" do
183
+ let(:output) { "json" }
184
+
185
+ its(:message) { is_expected.to eq({ error: { message: expected_message } }.to_json) }
186
+ end
187
+ end
188
+
189
+ context "when a target is not provided and there is no deployed verison without a target" do
190
+ let(:target) { nil }
191
+ let(:returned_target_2) { "customer-2" }
192
+
193
+ its(:success) { is_expected.to be false }
194
+ its(:message) { is_expected.to include "Please specify one of the following targets to record the undeployment from: customer-1, customer-2" }
195
+ end
196
+
197
+ context "when there are no deployed versions for the pacticipant" do
198
+ let(:deployed_versions_hash) do
199
+ {
200
+ _embedded: {
201
+ deployedVersions: []
202
+ }
203
+ }
204
+ end
205
+
206
+ its(:success) { is_expected.to be false }
207
+ its(:message) { is_expected.to include "Foo is not currently deployed to test environment. Cannot record undeployment." }
208
+
209
+ context "when the pacticipant does not exist" do
210
+ let(:pacticipant_request_status) { 404 }
211
+
212
+ its(:success) { is_expected.to be false }
213
+ its(:message) { is_expected.to include "No pacticipant with name 'Foo' found" }
214
+ end
215
+ end
216
+ end
217
+ end
218
+ end
219
+ end
@@ -1638,6 +1638,323 @@
1638
1638
  }
1639
1639
  }
1640
1640
  },
1641
+ {
1642
+ "description": "a request for the index resource",
1643
+ "providerState": "the pb:pacticipant-version and pb:environments relations exist in the index resource",
1644
+ "request": {
1645
+ "method": "GET",
1646
+ "path": "/",
1647
+ "headers": {
1648
+ "Accept": "application/hal+json"
1649
+ }
1650
+ },
1651
+ "response": {
1652
+ "status": 200,
1653
+ "headers": {
1654
+ "Content-Type": "application/hal+json;charset=utf-8"
1655
+ },
1656
+ "body": {
1657
+ "_links": {
1658
+ "pb:pacticipant-version": {
1659
+ "href": "http://localhost:1234/HAL-REL-PLACEHOLDER-PB-PACTICIPANT-VERSION-{pacticipant}-{version}"
1660
+ },
1661
+ "pb:environments": {
1662
+ "href": "http://localhost:1234/HAL-REL-PLACEHOLDER-PB-ENVIRONMENTS"
1663
+ }
1664
+ }
1665
+ },
1666
+ "matchingRules": {
1667
+ "$.body._links.pb:pacticipant-version.href": {
1668
+ "match": "regex",
1669
+ "regex": "http:\\/\\/.*{pacticipant}.*{version}"
1670
+ },
1671
+ "$.body._links.pb:environments.href": {
1672
+ "match": "regex",
1673
+ "regex": "http:\\/\\/.*"
1674
+ }
1675
+ }
1676
+ }
1677
+ },
1678
+ {
1679
+ "description": "a request for a pacticipant version",
1680
+ "providerState": "version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment",
1681
+ "request": {
1682
+ "method": "GET",
1683
+ "path": "/HAL-REL-PLACEHOLDER-PB-PACTICIPANT-VERSION-Foo-5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
1684
+ "headers": {
1685
+ "Accept": "application/hal+json"
1686
+ }
1687
+ },
1688
+ "response": {
1689
+ "status": 200,
1690
+ "headers": {
1691
+ "Content-Type": "application/hal+json;charset=utf-8"
1692
+ },
1693
+ "body": {
1694
+ "_links": {
1695
+ "pb:record-deployment": [
1696
+ {
1697
+ "name": "test",
1698
+ "href": "http://localhost:1234/HAL-REL-PLACEHOLDER-PB-RECORD-DEPLOYMENT-FOO-5556B8149BF8BAC76BC30F50A8A2DD4C22C85F30-TEST"
1699
+ }
1700
+ ]
1701
+ }
1702
+ },
1703
+ "matchingRules": {
1704
+ "$.body._links.pb:record-deployment[0].href": {
1705
+ "match": "regex",
1706
+ "regex": "http:\\/\\/.*"
1707
+ }
1708
+ }
1709
+ }
1710
+ },
1711
+ {
1712
+ "description": "a request to record a deployment",
1713
+ "providerState": "version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment",
1714
+ "request": {
1715
+ "method": "POST",
1716
+ "path": "/HAL-REL-PLACEHOLDER-PB-RECORD-DEPLOYMENT-FOO-5556B8149BF8BAC76BC30F50A8A2DD4C22C85F30-TEST",
1717
+ "headers": {
1718
+ "Content-Type": "application/json",
1719
+ "Accept": "application/hal+json"
1720
+ },
1721
+ "body": {
1722
+ "target": "blue"
1723
+ }
1724
+ },
1725
+ "response": {
1726
+ "status": 201,
1727
+ "headers": {
1728
+ "Content-Type": "application/hal+json;charset=utf-8"
1729
+ },
1730
+ "body": {
1731
+ "target": "blue"
1732
+ }
1733
+ }
1734
+ },
1735
+ {
1736
+ "description": "a request for a pacticipant version",
1737
+ "providerState": "version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with 2 environments that aren't test available for deployment",
1738
+ "request": {
1739
+ "method": "GET",
1740
+ "path": "/HAL-REL-PLACEHOLDER-PB-PACTICIPANT-VERSION-Foo-5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
1741
+ "headers": {
1742
+ "Accept": "application/hal+json"
1743
+ }
1744
+ },
1745
+ "response": {
1746
+ "status": 200,
1747
+ "headers": {
1748
+ "Content-Type": "application/hal+json;charset=utf-8"
1749
+ },
1750
+ "body": {
1751
+ "_links": {
1752
+ "pb:record-deployment": [
1753
+ {
1754
+ "name": "prod",
1755
+ "href": "href"
1756
+ },
1757
+ {
1758
+ "name": "dev",
1759
+ "href": "href"
1760
+ }
1761
+ ]
1762
+ }
1763
+ },
1764
+ "matchingRules": {
1765
+ "$.body._links.pb:record-deployment[0]": {
1766
+ "match": "type"
1767
+ },
1768
+ "$.body._links.pb:record-deployment[1]": {
1769
+ "match": "type"
1770
+ }
1771
+ }
1772
+ }
1773
+ },
1774
+ {
1775
+ "description": "a request for the environments",
1776
+ "providerState": "an environment with name test exists",
1777
+ "request": {
1778
+ "method": "GET",
1779
+ "path": "/HAL-REL-PLACEHOLDER-PB-ENVIRONMENTS",
1780
+ "headers": {
1781
+ "Accept": "application/hal+json"
1782
+ }
1783
+ },
1784
+ "response": {
1785
+ "status": 200,
1786
+ "headers": {
1787
+ "Content-Type": "application/hal+json;charset=utf-8"
1788
+ },
1789
+ "body": {
1790
+ "_links": {
1791
+ "pb:environments": [
1792
+ {
1793
+ "name": "test",
1794
+ "href": "href"
1795
+ }
1796
+ ]
1797
+ }
1798
+ },
1799
+ "matchingRules": {
1800
+ "$.body._links.pb:environments[0].href": {
1801
+ "match": "type"
1802
+ }
1803
+ }
1804
+ }
1805
+ },
1806
+ {
1807
+ "description": "a request for a pacticipant version",
1808
+ "providerState": "version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for release",
1809
+ "request": {
1810
+ "method": "GET",
1811
+ "path": "/HAL-REL-PLACEHOLDER-PB-PACTICIPANT-VERSION-Foo-5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
1812
+ "headers": {
1813
+ "Accept": "application/hal+json"
1814
+ }
1815
+ },
1816
+ "response": {
1817
+ "status": 200,
1818
+ "headers": {
1819
+ "Content-Type": "application/hal+json;charset=utf-8"
1820
+ },
1821
+ "body": {
1822
+ "_links": {
1823
+ "pb:record-release": [
1824
+ {
1825
+ "name": "test",
1826
+ "href": "http://localhost:1234/HAL-REL-PLACEHOLDER-PB-RECORD-RELEASE-FOO-5556B8149BF8BAC76BC30F50A8A2DD4C22C85F30-TEST"
1827
+ }
1828
+ ]
1829
+ }
1830
+ },
1831
+ "matchingRules": {
1832
+ "$.body._links.pb:record-release[0].href": {
1833
+ "match": "regex",
1834
+ "regex": "http:\\/\\/.*"
1835
+ }
1836
+ }
1837
+ }
1838
+ },
1839
+ {
1840
+ "description": "a request to record a release",
1841
+ "providerState": "version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment",
1842
+ "request": {
1843
+ "method": "POST",
1844
+ "path": "/HAL-REL-PLACEHOLDER-PB-RECORD-RELEASE-FOO-5556B8149BF8BAC76BC30F50A8A2DD4C22C85F30-TEST",
1845
+ "headers": {
1846
+ "Content-Type": "application/json",
1847
+ "Accept": "application/hal+json"
1848
+ }
1849
+ },
1850
+ "response": {
1851
+ "status": 201,
1852
+ "headers": {
1853
+ "Content-Type": "application/hal+json;charset=utf-8"
1854
+ }
1855
+ }
1856
+ },
1857
+ {
1858
+ "description": "a request for an environment",
1859
+ "providerState": "an environment with name test and UUID 16926ef3-590f-4e3f-838e-719717aa88c9 exists",
1860
+ "request": {
1861
+ "method": "GET",
1862
+ "path": "/HAL-REL-PLACEHOLDER-PB-ENVIRONMENT-16926ef3-590f-4e3f-838e-719717aa88c9",
1863
+ "headers": {
1864
+ "Accept": "application/hal+json"
1865
+ }
1866
+ },
1867
+ "response": {
1868
+ "status": 200,
1869
+ "headers": {
1870
+ "Content-Type": "application/hal+json;charset=utf-8"
1871
+ },
1872
+ "body": {
1873
+ "_links": {
1874
+ "pb:currently-deployed-deployed-versions": {
1875
+ "href": "http://localhost:1234/PLACEHOLDER-ENVIRONMENT-CURRENTLY-DEPLOYED-16926ef3-590f-4e3f-838e-719717aa88c9"
1876
+ }
1877
+ }
1878
+ },
1879
+ "matchingRules": {
1880
+ "$.body._links.pb:currently-deployed-deployed-versions.href": {
1881
+ "match": "regex",
1882
+ "regex": "^http.*"
1883
+ }
1884
+ }
1885
+ }
1886
+ },
1887
+ {
1888
+ "description": "a request to list the versions deployed to an environment for a pacticipant name and target",
1889
+ "providerState": "an version is deployed to environment with UUID 16926ef3-590f-4e3f-838e-719717aa88c9 with target customer-1",
1890
+ "request": {
1891
+ "method": "GET",
1892
+ "path": "/PLACEHOLDER-ENVIRONMENT-CURRENTLY-DEPLOYED-16926ef3-590f-4e3f-838e-719717aa88c9",
1893
+ "query": "pacticipant=Foo",
1894
+ "headers": {
1895
+ "Accept": "application/hal+json"
1896
+ }
1897
+ },
1898
+ "response": {
1899
+ "status": 200,
1900
+ "headers": {
1901
+ "Content-Type": "application/hal+json;charset=utf-8"
1902
+ },
1903
+ "body": {
1904
+ "_embedded": {
1905
+ "deployedVersions": [
1906
+ {
1907
+ "target": "customer-1",
1908
+ "_links": {
1909
+ "self": {
1910
+ "href": "http://localhost:1234/PLACEHOLDER-DEPLOYED-VERSION-ff3adecf-cfc5-4653-a4e3-f1861092f8e0"
1911
+ }
1912
+ }
1913
+ }
1914
+ ]
1915
+ }
1916
+ },
1917
+ "matchingRules": {
1918
+ "$.body._embedded.deployedVersions[0]._links.self.href": {
1919
+ "match": "regex",
1920
+ "regex": "^http"
1921
+ }
1922
+ }
1923
+ }
1924
+ },
1925
+ {
1926
+ "description": "a request to mark a deployed version as not currently deploye",
1927
+ "providerState": "a currently deployed version exists",
1928
+ "request": {
1929
+ "method": "PATCH",
1930
+ "path": "/PLACEHOLDER-DEPLOYED-VERSION-ff3adecf-cfc5-4653-a4e3-f1861092f8e0",
1931
+ "headers": {
1932
+ "Content-Type": "application/merge-patch+json"
1933
+ },
1934
+ "body": {
1935
+ "currentlyDeployed": false
1936
+ }
1937
+ },
1938
+ "response": {
1939
+ "status": 200,
1940
+ "headers": {
1941
+ "Content-Type": "application/hal+json;charset=utf-8"
1942
+ },
1943
+ "body": {
1944
+ "currentlyDeployed": false,
1945
+ "_embedded": {
1946
+ "version": {
1947
+ "number": "2"
1948
+ }
1949
+ }
1950
+ },
1951
+ "matchingRules": {
1952
+ "$.body._embedded.version.number": {
1953
+ "match": "type"
1954
+ }
1955
+ }
1956
+ }
1957
+ },
1641
1958
  {
1642
1959
  "description": "a request to create a webhook with a JSON body for a consumer and provider",
1643
1960
  "providerState": "the 'Pricing Service' and 'Condor' already exist in the pact-broker",
@@ -1846,7 +2163,6 @@
1846
2163
  }
1847
2164
  ],
1848
2165
  "request": {
1849
- "url": null,
1850
2166
  "method": "POST",
1851
2167
  "headers": {
1852
2168
  "Foo": "bar",