Skip to content

Commit

Permalink
feat: Add support for gradle/maven plugin canideploy on specific env #…
Browse files Browse the repository at this point in the history
  • Loading branch information
rholshausen committed Feb 24, 2023
1 parent 06cfc8f commit f586340
Show file tree
Hide file tree
Showing 12 changed files with 163 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ sealed class Latest {
data class UseLatestTag(val latestTag: String) : Latest()
}

/**
* Specifies the target for the can-i-deploy check (tag or environment)
*/
data class To @JvmOverloads constructor(val tag: String? = null, val environment: String? = null)

/**
* Model for a CanIDeploy result
*/
Expand Down Expand Up @@ -992,7 +997,7 @@ open class PactBrokerClient(
pacticipant: String,
pacticipantVersion: String,
latest: Latest,
to: String?,
to: To?,
ignore: List<IgnoreSelector> = emptyList()
): CanIDeployResult {
val halClient = newHalClient()
Expand Down Expand Up @@ -1109,7 +1114,7 @@ open class PactBrokerClient(
pacticipant: String,
pacticipantVersion: String,
latest: Latest,
to: String?,
to: To?,
ignore: List<IgnoreSelector>
): String {
val escaper = urlFormParameterEscaper()
Expand All @@ -1124,9 +1129,17 @@ open class PactBrokerClient(
is Latest.UseLatestTag -> params.add("q[][tag]" to escaper.escape(latest.latestTag))
}

if (to.isNotEmpty()) {
params.add("latest" to "true")
params.add("tag" to escaper.escape(to))
if (to != null) {
if (to.environment.isNotEmpty()) {
params.add("environment" to escaper.escape(to.environment))
}

if (to.tag.isNotEmpty()) {
params.add("latest" to "true")
params.add("tag" to escaper.escape(to.tag))
} else if (to.environment.isNullOrEmpty()) {
params.add("latest" to "true")
}
} else {
params.add("latest" to "true")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ class PactBrokerClientSpec extends Specification {
|}'''.stripMargin())

when:
def result = client.canIDeploy('test', '1.2.3', new Latest.UseLatest(true), '')
def result = client.canIDeploy('test', '1.2.3', new Latest.UseLatest(true), null)

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

where:

pacticipant | pacticipantVersion | latest | to | ignore || result
'Test' | '' | new Latest.UseLatest(true) | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true'
'Test' | '100' | new Latest.UseLatest(false) | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][version]=100&latest=true'
'Test' | '' | new Latest.UseLatestTag('tst') | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][tag]=tst&latest=true'
'Test' | '' | new Latest.UseLatest(true) | 'tst' | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&tag=tst'
'Test 1 2 3' | '' | new Latest.UseLatest(true) | null | [] || 'q[][pacticipant]=Test+1+2+3&latestby=cvp&q[][latest]=true&latest=true'
'Test' | '1 0 0' | new Latest.UseLatest(false) | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][version]=1+0+0&latest=true'
'Test' | '' | new Latest.UseLatestTag('tst 3/4') | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][tag]=tst+3%2F4&latest=true'
'Test' | '' | new Latest.UseLatest(true) | 'tst 3/4' | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&tag=tst+3%2F4'
'Test' | '' | new Latest.UseLatest(true) | null | [new IgnoreSelector('bob', null)] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&ignore[][pacticipant]=bob'
'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'
'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'
pacticipant | pacticipantVersion | latest | to | ignore || result
'Test' | '' | new Latest.UseLatest(true) | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true'
'Test' | '100' | new Latest.UseLatest(false) | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][version]=100&latest=true'
'Test' | '' | new Latest.UseLatestTag('tst') | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][tag]=tst&latest=true'
'Test' | '' | new Latest.UseLatest(true) | new To('tst') | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&tag=tst'
'Test 1 2 3' | '' | new Latest.UseLatest(true) | null | [] || 'q[][pacticipant]=Test+1+2+3&latestby=cvp&q[][latest]=true&latest=true'
'Test' | '1 0 0' | new Latest.UseLatest(false) | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][version]=1+0+0&latest=true'
'Test' | '' | new Latest.UseLatestTag('tst 3/4') | null | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][tag]=tst+3%2F4&latest=true'
'Test' | '' | new Latest.UseLatest(true) | new To('tst 3/4') | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&tag=tst+3%2F4'
'Test' | '' | new Latest.UseLatest(true) | null | [new IgnoreSelector('bob', null)] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&latest=true&ignore[][pacticipant]=bob'
'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'
'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'
'Test' | '' | new Latest.UseLatest(true) | new To(null, 'env1') | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&environment=env1'
'Test' | '' | new Latest.UseLatest(true) | new To('tag1', 'env1') | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&environment=env1&latest=true&tag=tag1'
'Test' | '' | new Latest.UseLatest(true) | new To(null, 'env 1') | [] || 'q[][pacticipant]=Test&latestby=cvp&q[][latest]=true&environment=env+1'
}

@Issue('#1511')
Expand Down Expand Up @@ -784,7 +787,7 @@ class PactBrokerClientSpec extends Specification {
|}'''.stripMargin())

when:
def result = client.canIDeploy('test', '1.2.3', new Latest.UseLatest(true), '')
def result = client.canIDeploy('test', '1.2.3', new Latest.UseLatest(true), null)

then:
1 * halClient.getJson(_, _) >> new Result.Ok(json)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import au.com.dius.pact.core.pactbroker.Latest
import au.com.dius.pact.core.pactbroker.PactBrokerClient
import au.com.dius.pact.core.pactbroker.PactBrokerClientConfig
import au.com.dius.pact.core.pactbroker.TestResult
import au.com.dius.pact.core.pactbroker.To
import au.com.dius.pact.core.support.Result
import spock.lang.Specification

Expand Down Expand Up @@ -820,7 +821,7 @@ class PactBrokerClientPactSpec extends Specification {

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

then:
Expand Down
15 changes: 11 additions & 4 deletions provider/gradle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,9 @@ There is a `canIDeploy` Gradle task that you can use to preform a deployment saf
parameters: `pacticipant` and either `pacticipantVersion` or `latest=true`. It will use the configuration from the
`broker` section of your Gradle build.

**NOTE:** It is recommended to use the [Pact CLI](https://docs.pact.io/implementation_guides/cli) to execute the
Can I Deploy check, as it will always be up to date with features in the Pact broker.

```console
$ ./gradlew canideploy -Ppacticipant='Activity Service' -Platest=true

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

|Field|Description|Default|
|-----|-----------|-------|
|retryCountWhileUnknown|The amount of times to retry while there are unknown results|0|
|retryWhileUnknownInterval|The number of seconds to wait between retries|10|
| Field | Description | Default |
|---------------------------|--------------------------------------------------------------|---------|
| retryCountWhileUnknown | The amount of times to retry while there are unknown results | 0 |
| retryWhileUnknownInterval | The number of seconds to wait between retries | 10 |

Example use:

Expand All @@ -1188,6 +1191,10 @@ pact {
}
```

## Support for environments (4.5.0+)

You can specify the environment into which the pacticipant(s) are to be deployed with the `toEnvironment` property.

# Verifying V4 Pact files that require plugins (version 4.3.0+)

Pact files that require plugins can be verified with version 4.3.0+. For details on how plugins work, see the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package au.com.dius.pact.provider.gradle

import au.com.dius.pact.core.pactbroker.Latest
import au.com.dius.pact.core.pactbroker.PactBrokerClient
import au.com.dius.pact.core.pactbroker.To
import com.github.ajalt.mordant.TermColors
import org.gradle.api.GradleScriptException
import org.gradle.api.provider.Property
Expand All @@ -19,6 +20,7 @@ abstract class PactCanIDeployTask extends PactCanIDeployBaseTask {
static final String PACTICIPANT = 'pacticipant'
static final String PACTICIPANT_VERSION = 'pacticipantVersion'
static final String TO = 'toTag'
static final String TO_ENVIRONMENT = 'toEnvironment'
static final String LATEST = 'latest'

@Internal
Expand All @@ -40,6 +42,10 @@ abstract class PactCanIDeployTask extends PactCanIDeployBaseTask {
@Optional
abstract Property<Object> getToProp()

@Input
@Optional
abstract Property<Object> getToEnvironment()

@Input
@Optional
abstract Property<Object> getLatestProp()
Expand All @@ -65,10 +71,15 @@ abstract class PactCanIDeployTask extends PactCanIDeployBaseTask {
throw new GradleScriptException('The CanIDeploy task requires -PpacticipantVersion=... or -Platest=true', null)
}
String pacticipantVersion = pacticipantVersion.orElse('').get()
String to = null
String toTag = null
if (toProp.present) {
to = toProp.get()
toTag = toProp.get()
}
String environment = null
if (toEnvironment.present) {
environment = toEnvironment.get()
}
def to = new To(toTag, environment)
def t = new TermColors()
logger.debug(
"Calling canIDeploy(pacticipant=$pacticipant, pacticipantVersion=$pacticipantVersion, latest=$latest, to=$to)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class PactPlugin extends PactPluginBase {
: null)
toProp.set(project.hasProperty(TO) ? project.property(TO) : null)
latestProp.set(project.hasProperty(LATEST) ? project.property(LATEST) : null)
toEnvironment.set(project.hasProperty(TO_ENVIRONMENT) ? project.property(TO_ENVIRONMENT) : null)
}

project.afterEvaluate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package au.com.dius.pact.provider.gradle
import au.com.dius.pact.core.pactbroker.CanIDeployResult
import au.com.dius.pact.core.pactbroker.Latest
import au.com.dius.pact.core.pactbroker.PactBrokerClient
import au.com.dius.pact.core.pactbroker.To
import org.gradle.api.GradleScriptException
import org.gradle.api.Project
import org.gradle.testfixtures.ProjectBuilder
import spock.lang.Specification

@SuppressWarnings('LineLength')
class PactCanIDeployTaskSpec extends Specification {

private PactPlugin plugin
Expand Down Expand Up @@ -127,7 +129,7 @@ class PactCanIDeployTaskSpec extends Specification {
then:
notThrown(GradleScriptException)
1 * project.tasks.canIDeploy.brokerClient.canIDeploy('pacticipant', '1.0.0',
new Latest.UseLatest(true), 'prod', _) >> new CanIDeployResult(true, '', '', null, 'verificationResultUrl')
new Latest.UseLatest(true), new To('prod'), _) >> new CanIDeployResult(true, '', '', null, 'verificationResultUrl')
}

def 'passes optional parameters to the pact broker client'() {
Expand All @@ -151,7 +153,31 @@ class PactCanIDeployTaskSpec extends Specification {
then:
notThrown(GradleScriptException)
1 * project.tasks.canIDeploy.brokerClient.canIDeploy('pacticipant', '1.0.0',
new Latest.UseLatest(true), 'prod', _) >> new CanIDeployResult(true, '', '', null, null)
new Latest.UseLatest(true), new To('prod'), _) >> new CanIDeployResult(true, '', '', null, null)
}

def 'passes toEnvironment parameter to the pact broker client'() {
given:
project.pact {
broker {
pactBrokerUrl = 'pactBrokerUrl'
}
}
project.ext.pacticipant = 'pacticipant'
project.ext.pacticipantVersion = '1.0.0'
project.ext.latest = 'true'
project.ext.toEnvironment = 'prod'
project.evaluate()

project.tasks.canIDeploy.brokerClient = Mock(PactBrokerClient)

when:
project.tasks.canIDeploy.canIDeploy()

then:
notThrown(GradleScriptException)
1 * project.tasks.canIDeploy.brokerClient.canIDeploy('pacticipant', '1.0.0',
new Latest.UseLatest(true), new To(null, 'prod'), _) >> new CanIDeployResult(true, '', '', null, null)
}

def 'throws an exception if the pact broker client says no'() {
Expand Down
15 changes: 11 additions & 4 deletions provider/maven/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,9 @@ There is a `can-i-deploy` goal that you can use to preform a deployment safety c
parameters: `pacticipant` and either `pacticipantVersion` or `latest=true`. It will use the broker configuration values
from the your POM.

**NOTE:** It is recommended to use the [Pact CLI](https://docs.pact.io/implementation_guides/cli) to execute the
Can I Deploy check, as it will always be up to date with features in the Pact broker.

```console
$ mvn pact:can-i-deploy -Dpacticipant='Activity Service' -Dlatest=true
[INFO] Scanning for projects...
Expand Down Expand Up @@ -1165,10 +1168,10 @@ It can happen that there are still unknown results in the Pact broker because th
You can enable a retry with a wait interval to poll for the results to become available. There are two settings that can
be added to the configuration in the POM to enable this: `retriesWhenUnknown` and `retryInterval`.

|Field|Description|Default|
|-----|-----------|-------|
|retriesWhenUnknown|The amount of times to retry while there are unknown results|0|
|retryInterval|The number of seconds to wait between retries|10|
| Field | Description | Default |
|--------------------|--------------------------------------------------------------|---------|
| retriesWhenUnknown | The amount of times to retry while there are unknown results | 0 |
| retryInterval | The number of seconds to wait between retries | 10 |

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

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

## Support for environments (4.5.0+)

You can specify the environment into which the pacticipant(s) are to be deployed with the `toEnvironment` property.

# Verifying V4 Pact files that require plugins (version 4.3.0+)

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

0 comments on commit f586340

Please sign in to comment.