Skip to content

Commit f586340

Browse files
committed
feat: Add support for gradle/maven plugin canideploy on specific env #1668
1 parent 06cfc8f commit f586340

File tree

12 files changed

+163
-63
lines changed

12 files changed

+163
-63
lines changed

core/pactbroker/src/main/kotlin/au/com/dius/pact/core/pactbroker/PactBrokerClient.kt

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ sealed class Latest {
9898
data class UseLatestTag(val latestTag: String) : Latest()
9999
}
100100

101+
/**
102+
* Specifies the target for the can-i-deploy check (tag or environment)
103+
*/
104+
data class To @JvmOverloads constructor(val tag: String? = null, val environment: String? = null)
105+
101106
/**
102107
* Model for a CanIDeploy result
103108
*/
@@ -992,7 +997,7 @@ open class PactBrokerClient(
992997
pacticipant: String,
993998
pacticipantVersion: String,
994999
latest: Latest,
995-
to: String?,
1000+
to: To?,
9961001
ignore: List<IgnoreSelector> = emptyList()
9971002
): CanIDeployResult {
9981003
val halClient = newHalClient()
@@ -1109,7 +1114,7 @@ open class PactBrokerClient(
11091114
pacticipant: String,
11101115
pacticipantVersion: String,
11111116
latest: Latest,
1112-
to: String?,
1117+
to: To?,
11131118
ignore: List<IgnoreSelector>
11141119
): String {
11151120
val escaper = urlFormParameterEscaper()
@@ -1124,9 +1129,17 @@ open class PactBrokerClient(
11241129
is Latest.UseLatestTag -> params.add("q[][tag]" to escaper.escape(latest.latestTag))
11251130
}
11261131

1127-
if (to.isNotEmpty()) {
1128-
params.add("latest" to "true")
1129-
params.add("tag" to escaper.escape(to))
1132+
if (to != null) {
1133+
if (to.environment.isNotEmpty()) {
1134+
params.add("environment" to escaper.escape(to.environment))
1135+
}
1136+
1137+
if (to.tag.isNotEmpty()) {
1138+
params.add("latest" to "true")
1139+
params.add("tag" to escaper.escape(to.tag))
1140+
} else if (to.environment.isNullOrEmpty()) {
1141+
params.add("latest" to "true")
1142+
}
11301143
} else {
11311144
params.add("latest" to "true")
11321145
}

core/pactbroker/src/test/groovy/au/com/dius/pact/core/pactbroker/PactBrokerClientSpec.groovy

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ class PactBrokerClientSpec extends Specification {
560560
|}'''.stripMargin())
561561

562562
when:
563-
def result = client.canIDeploy('test', '1.2.3', new Latest.UseLatest(true), '')
563+
def result = client.canIDeploy('test', '1.2.3', new Latest.UseLatest(true), null)
564564

565565
then:
566566
3 * halClient.getJson(_, _) >> new Result.Ok(json1) >> new Result.Ok(json1) >> new Result.Ok(json2)
@@ -677,18 +677,21 @@ class PactBrokerClientSpec extends Specification {
677677

678678
where:
679679

680-
pacticipant | pacticipantVersion | latest | to | ignore || result
681-
'Test' | '' | new Latest.UseLatest(true) | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true'
682-
'Test' | '100' | new Latest.UseLatest(false) | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][version]=100&latest=true'
683-
'Test' | '' | new Latest.UseLatestTag('tst') | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][tag]=tst&latest=true'
684-
'Test' | '' | new Latest.UseLatest(true) | 'tst' | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&tag=tst'
685-
'Test 1 2 3' | '' | new Latest.UseLatest(true) | null | [] || 'q[][pacticipant]=Test+1+2+3&latestby=cvp&q[][latest]=true&latest=true'
686-
'Test' | '1 0 0' | new Latest.UseLatest(false) | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][version]=1+0+0&latest=true'
687-
'Test' | '' | new Latest.UseLatestTag('tst 3/4') | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][tag]=tst+3%2F4&latest=true'
688-
'Test' | '' | new Latest.UseLatest(true) | 'tst 3/4' | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&tag=tst+3%2F4'
689-
'Test' | '' | new Latest.UseLatest(true) | null | [new IgnoreSelector('bob', null)] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&ignore[][pacticipant]=bob'
690-
'Test' | '' | new Latest.UseLatest(true) | null | [new IgnoreSelector('bob', '100')] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&ignore[][pacticipant]=bob&ignore[][version]=100'
691-
'Test' | '' | new Latest.UseLatest(true) | null | [new IgnoreSelector('bob', null), new IgnoreSelector('fred', null)] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&ignore[][pacticipant]=bob&ignore[][pacticipant]=fred'
680+
pacticipant | pacticipantVersion | latest | to | ignore || result
681+
'Test' | '' | new Latest.UseLatest(true) | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true'
682+
'Test' | '100' | new Latest.UseLatest(false) | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][version]=100&latest=true'
683+
'Test' | '' | new Latest.UseLatestTag('tst') | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][tag]=tst&latest=true'
684+
'Test' | '' | new Latest.UseLatest(true) | new To('tst') | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&tag=tst'
685+
'Test 1 2 3' | '' | new Latest.UseLatest(true) | null | [] || 'q[][pacticipant]=Test+1+2+3&latestby=cvp&q[][latest]=true&latest=true'
686+
'Test' | '1 0 0' | new Latest.UseLatest(false) | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][version]=1+0+0&latest=true'
687+
'Test' | '' | new Latest.UseLatestTag('tst 3/4') | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][tag]=tst+3%2F4&latest=true'
688+
'Test' | '' | new Latest.UseLatest(true) | new To('tst 3/4') | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&tag=tst+3%2F4'
689+
'Test' | '' | new Latest.UseLatest(true) | null | [new IgnoreSelector('bob', null)] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&ignore[][pacticipant]=bob'
690+
'Test' | '' | new Latest.UseLatest(true) | null | [new IgnoreSelector('bob', '100')] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&ignore[][pacticipant]=bob&ignore[][version]=100'
691+
'Test' | '' | new Latest.UseLatest(true) | null | [new IgnoreSelector('bob', null), new IgnoreSelector('fred', null)] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&ignore[][pacticipant]=bob&ignore[][pacticipant]=fred'
692+
'Test' | '' | new Latest.UseLatest(true) | new To(null, 'env1') | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&environment=env1'
693+
'Test' | '' | new Latest.UseLatest(true) | new To('tag1', 'env1') | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&environment=env1&latest=true&tag=tag1'
694+
'Test' | '' | new Latest.UseLatest(true) | new To(null, 'env 1') | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&environment=env+1'
692695
}
693696

694697
@Issue('#1511')
@@ -784,7 +787,7 @@ class PactBrokerClientSpec extends Specification {
784787
|}'''.stripMargin())
785788

786789
when:
787-
def result = client.canIDeploy('test', '1.2.3', new Latest.UseLatest(true), '')
790+
def result = client.canIDeploy('test', '1.2.3', new Latest.UseLatest(true), null)
788791

789792
then:
790793
1 * halClient.getJson(_, _) >> new Result.Ok(json)

pact-publish/src/test/groovy/broker/PactBrokerClientPactSpec.groovy

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import au.com.dius.pact.core.pactbroker.Latest
77
import au.com.dius.pact.core.pactbroker.PactBrokerClient
88
import au.com.dius.pact.core.pactbroker.PactBrokerClientConfig
99
import au.com.dius.pact.core.pactbroker.TestResult
10+
import au.com.dius.pact.core.pactbroker.To
1011
import au.com.dius.pact.core.support.Result
1112
import spock.lang.Specification
1213

@@ -820,7 +821,7 @@ class PactBrokerClientPactSpec extends Specification {
820821

821822
when:
822823
def result = pactBroker.runTest { server, context ->
823-
pactBrokerClient.canIDeploy('Foo', '1.2.3', new Latest.UseLatest(false), 'prod')
824+
pactBrokerClient.canIDeploy('Foo', '1.2.3', new Latest.UseLatest(false), new To('prod'))
824825
}
825826

826827
then:

provider/gradle/README.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,9 @@ There is a `canIDeploy` Gradle task that you can use to preform a deployment saf
11431143
parameters: `pacticipant` and either `pacticipantVersion` or `latest=true`. It will use the configuration from the
11441144
`broker` section of your Gradle build.
11451145

1146+
**NOTE:** It is recommended to use the [Pact CLI](https://docs.pact.io/implementation_guides/cli) to execute the
1147+
Can I Deploy check, as it will always be up to date with features in the Pact broker.
1148+
11461149
```console
11471150
$ ./gradlew canideploy -Ppacticipant='Activity Service' -Platest=true
11481151

@@ -1171,10 +1174,10 @@ It can happen that there are still unknown results in the Pact broker because th
11711174
You can enable a retry with a wait interval to poll for the results to become available. There are two settings that can
11721175
be added to the `broker` configuration to enable this: `retryCountWhileUnknown` and `retryWhileUnknownInterval`.
11731176

1174-
|Field|Description|Default|
1175-
|-----|-----------|-------|
1176-
|retryCountWhileUnknown|The amount of times to retry while there are unknown results|0|
1177-
|retryWhileUnknownInterval|The number of seconds to wait between retries|10|
1177+
| Field | Description | Default |
1178+
|---------------------------|--------------------------------------------------------------|---------|
1179+
| retryCountWhileUnknown | The amount of times to retry while there are unknown results | 0 |
1180+
| retryWhileUnknownInterval | The number of seconds to wait between retries | 10 |
11781181

11791182
Example use:
11801183

@@ -1188,6 +1191,10 @@ pact {
11881191
}
11891192
```
11901193

1194+
## Support for environments (4.5.0+)
1195+
1196+
You can specify the environment into which the pacticipant(s) are to be deployed with the `toEnvironment` property.
1197+
11911198
# Verifying V4 Pact files that require plugins (version 4.3.0+)
11921199

11931200
Pact files that require plugins can be verified with version 4.3.0+. For details on how plugins work, see the

provider/gradle/src/main/groovy/au/com/dius/pact/provider/gradle/PactCanIDeployTask.groovy

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package au.com.dius.pact.provider.gradle
22

33
import au.com.dius.pact.core.pactbroker.Latest
44
import au.com.dius.pact.core.pactbroker.PactBrokerClient
5+
import au.com.dius.pact.core.pactbroker.To
56
import com.github.ajalt.mordant.TermColors
67
import org.gradle.api.GradleScriptException
78
import org.gradle.api.provider.Property
@@ -19,6 +20,7 @@ abstract class PactCanIDeployTask extends PactCanIDeployBaseTask {
1920
static final String PACTICIPANT = 'pacticipant'
2021
static final String PACTICIPANT_VERSION = 'pacticipantVersion'
2122
static final String TO = 'toTag'
23+
static final String TO_ENVIRONMENT = 'toEnvironment'
2224
static final String LATEST = 'latest'
2325

2426
@Internal
@@ -40,6 +42,10 @@ abstract class PactCanIDeployTask extends PactCanIDeployBaseTask {
4042
@Optional
4143
abstract Property<Object> getToProp()
4244

45+
@Input
46+
@Optional
47+
abstract Property<Object> getToEnvironment()
48+
4349
@Input
4450
@Optional
4551
abstract Property<Object> getLatestProp()
@@ -65,10 +71,15 @@ abstract class PactCanIDeployTask extends PactCanIDeployBaseTask {
6571
throw new GradleScriptException('The CanIDeploy task requires -PpacticipantVersion=... or -Platest=true', null)
6672
}
6773
String pacticipantVersion = pacticipantVersion.orElse('').get()
68-
String to = null
74+
String toTag = null
6975
if (toProp.present) {
70-
to = toProp.get()
76+
toTag = toProp.get()
77+
}
78+
String environment = null
79+
if (toEnvironment.present) {
80+
environment = toEnvironment.get()
7181
}
82+
def to = new To(toTag, environment)
7283
def t = new TermColors()
7384
logger.debug(
7485
"Calling canIDeploy(pacticipant=$pacticipant, pacticipantVersion=$pacticipantVersion, latest=$latest, to=$to)"

provider/gradle/src/main/groovy/au/com/dius/pact/provider/gradle/PactPlugin.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class PactPlugin extends PactPluginBase {
3939
: null)
4040
toProp.set(project.hasProperty(TO) ? project.property(TO) : null)
4141
latestProp.set(project.hasProperty(LATEST) ? project.property(LATEST) : null)
42+
toEnvironment.set(project.hasProperty(TO_ENVIRONMENT) ? project.property(TO_ENVIRONMENT) : null)
4243
}
4344

4445
project.afterEvaluate {

provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/PactCanIDeployTaskSpec.groovy

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ package au.com.dius.pact.provider.gradle
33
import au.com.dius.pact.core.pactbroker.CanIDeployResult
44
import au.com.dius.pact.core.pactbroker.Latest
55
import au.com.dius.pact.core.pactbroker.PactBrokerClient
6+
import au.com.dius.pact.core.pactbroker.To
67
import org.gradle.api.GradleScriptException
78
import org.gradle.api.Project
89
import org.gradle.testfixtures.ProjectBuilder
910
import spock.lang.Specification
1011

12+
@SuppressWarnings('LineLength')
1113
class PactCanIDeployTaskSpec extends Specification {
1214

1315
private PactPlugin plugin
@@ -127,7 +129,7 @@ class PactCanIDeployTaskSpec extends Specification {
127129
then:
128130
notThrown(GradleScriptException)
129131
1 * project.tasks.canIDeploy.brokerClient.canIDeploy('pacticipant', '1.0.0',
130-
new Latest.UseLatest(true), 'prod', _) >> new CanIDeployResult(true, '', '', null, 'verificationResultUrl')
132+
new Latest.UseLatest(true), new To('prod'), _) >> new CanIDeployResult(true, '', '', null, 'verificationResultUrl')
131133
}
132134

133135
def 'passes optional parameters to the pact broker client'() {
@@ -151,7 +153,31 @@ class PactCanIDeployTaskSpec extends Specification {
151153
then:
152154
notThrown(GradleScriptException)
153155
1 * project.tasks.canIDeploy.brokerClient.canIDeploy('pacticipant', '1.0.0',
154-
new Latest.UseLatest(true), 'prod', _) >> new CanIDeployResult(true, '', '', null, null)
156+
new Latest.UseLatest(true), new To('prod'), _) >> new CanIDeployResult(true, '', '', null, null)
157+
}
158+
159+
def 'passes toEnvironment parameter to the pact broker client'() {
160+
given:
161+
project.pact {
162+
broker {
163+
pactBrokerUrl = 'pactBrokerUrl'
164+
}
165+
}
166+
project.ext.pacticipant = 'pacticipant'
167+
project.ext.pacticipantVersion = '1.0.0'
168+
project.ext.latest = 'true'
169+
project.ext.toEnvironment = 'prod'
170+
project.evaluate()
171+
172+
project.tasks.canIDeploy.brokerClient = Mock(PactBrokerClient)
173+
174+
when:
175+
project.tasks.canIDeploy.canIDeploy()
176+
177+
then:
178+
notThrown(GradleScriptException)
179+
1 * project.tasks.canIDeploy.brokerClient.canIDeploy('pacticipant', '1.0.0',
180+
new Latest.UseLatest(true), new To(null, 'prod'), _) >> new CanIDeployResult(true, '', '', null, null)
155181
}
156182

157183
def 'throws an exception if the pact broker client says no'() {

provider/maven/README.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,9 @@ There is a `can-i-deploy` goal that you can use to preform a deployment safety c
11381138
parameters: `pacticipant` and either `pacticipantVersion` or `latest=true`. It will use the broker configuration values
11391139
from the your POM.
11401140

1141+
**NOTE:** It is recommended to use the [Pact CLI](https://docs.pact.io/implementation_guides/cli) to execute the
1142+
Can I Deploy check, as it will always be up to date with features in the Pact broker.
1143+
11411144
```console
11421145
$ mvn pact:can-i-deploy -Dpacticipant='Activity Service' -Dlatest=true
11431146
[INFO] Scanning for projects...
@@ -1165,10 +1168,10 @@ It can happen that there are still unknown results in the Pact broker because th
11651168
You can enable a retry with a wait interval to poll for the results to become available. There are two settings that can
11661169
be added to the configuration in the POM to enable this: `retriesWhenUnknown` and `retryInterval`.
11671170

1168-
|Field|Description|Default|
1169-
|-----|-----------|-------|
1170-
|retriesWhenUnknown|The amount of times to retry while there are unknown results|0|
1171-
|retryInterval|The number of seconds to wait between retries|10|
1171+
| Field | Description | Default |
1172+
|--------------------|--------------------------------------------------------------|---------|
1173+
| retriesWhenUnknown | The amount of times to retry while there are unknown results | 0 |
1174+
| retryInterval | The number of seconds to wait between retries | 10 |
11721175

11731176
## Ignoring pacticipant by name and version (4.1.28+, 4.2.13+)
11741177

@@ -1202,6 +1205,10 @@ To configure it in the POM file, add an ignore section to the `configuration` el
12021205
Or add it to the command line using the format `-Dignore=<pacticipant>:<version>?,<pacticipant>:<version>?,...`.
12031206
For example, `-Dignore=bob,fred:1.2.3` to ignore pacticipant named Bob and pacticipant name Fred with version 1.2.3.
12041207

1208+
## Support for environments (4.5.0+)
1209+
1210+
You can specify the environment into which the pacticipant(s) are to be deployed with the `toEnvironment` property.
1211+
12051212
# Verifying V4 Pact files that require plugins (version 4.3.0+)
12061213

12071214
Pact files that require plugins can be verified with version 4.3.0+. For details on how plugins work, see the

0 commit comments

Comments
 (0)