diff --git a/core/pactbroker/src/main/kotlin/au/com/dius/pact/core/pactbroker/PactBrokerClient.kt b/core/pactbroker/src/main/kotlin/au/com/dius/pact/core/pactbroker/PactBrokerClient.kt index 17e3c0ba0f..eb3053b098 100644 --- a/core/pactbroker/src/main/kotlin/au/com/dius/pact/core/pactbroker/PactBrokerClient.kt +++ b/core/pactbroker/src/main/kotlin/au/com/dius/pact/core/pactbroker/PactBrokerClient.kt @@ -158,6 +158,7 @@ interface IPactBrokerClient { providerName: String, selectors: List, providerTags: List = emptyList(), + providerBranches: List = emptyList(), enablePending: Boolean = false, includeWipPactsSince: String? ): Result, Exception> @@ -299,6 +300,7 @@ open class PactBrokerClient( providerName: String, selectors: List, providerTags: List, + providerBranches: List, enablePending: Boolean, includeWipPactsSince: String? ): Result, Exception> { @@ -314,9 +316,9 @@ open class PactBrokerClient( return if (pactsForVerification != null) { val selectorsRawJson = System.getProperty("pactbroker.consumerversionselectors.rawjson") if(!selectorsRawJson.isNullOrBlank()){ - fetchPactsUsingNewEndpointRaw(selectorsRawJson, enablePending, providerTags, includeWipPactsSince, halClient, pactsForVerification, providerName) + fetchPactsUsingNewEndpointRaw(selectorsRawJson, enablePending, providerTags, providerBranches, includeWipPactsSince, halClient, pactsForVerification, providerName) } else { - fetchPactsUsingNewEndpointTyped(selectors, enablePending, providerTags, includeWipPactsSince, halClient, pactsForVerification, providerName) + fetchPactsUsingNewEndpointTyped(selectors, enablePending, providerTags, providerBranches, includeWipPactsSince, halClient, pactsForVerification, providerName) } } else { handleWith { @@ -341,31 +343,34 @@ open class PactBrokerClient( selectorsTyped: List, enablePending: Boolean, providerTags: List, + providerBranches: List, includeWipPactsSince: String?, halClient: IHalClient, pactsForVerification: String, providerName: String ): Result, Exception> { val selectorsJson = jsonArray(selectorsTyped.map { it.toJson() }) - return fetchPactsUsingNewEndpoint(selectorsJson, enablePending, providerTags, includeWipPactsSince, halClient, pactsForVerification, providerName) + return fetchPactsUsingNewEndpoint(selectorsJson, enablePending, providerTags, providerBranches, includeWipPactsSince, halClient, pactsForVerification, providerName) } private fun fetchPactsUsingNewEndpointRaw( selectorsRaw: String, enablePending: Boolean, providerTags: List, + providerBranches: List, includeWipPactsSince: String?, halClient: IHalClient, pactsForVerification: String, providerName: String ): Result, Exception> { - return fetchPactsUsingNewEndpoint(JsonParser.parseString(selectorsRaw), enablePending, providerTags, includeWipPactsSince, halClient, pactsForVerification, providerName) + return fetchPactsUsingNewEndpoint(JsonParser.parseString(selectorsRaw), enablePending, providerTags, providerBranches, includeWipPactsSince, halClient, pactsForVerification, providerName) } private fun fetchPactsUsingNewEndpoint( selectorsJson: JsonValue, enablePending: Boolean, providerTags: List, + providerBranches: List, includeWipPactsSince: String?, halClient: IHalClient, pactsForVerification: String, @@ -379,6 +384,7 @@ open class PactBrokerClient( body["includePendingStatus"] = enablePending if (enablePending) { body["providerVersionTags"] = jsonArray(providerTags) + body["providerVersionBranches"] = jsonArray(providerBranches) if (includeWipPactsSince.isNotEmpty()) { body["includeWipPactsSince"] = includeWipPactsSince } diff --git a/core/pactbroker/src/test/groovy/au/com/dius/pact/core/pactbroker/PactBrokerClientSpec.groovy b/core/pactbroker/src/test/groovy/au/com/dius/pact/core/pactbroker/PactBrokerClientSpec.groovy index 041b6412e4..0cf4cc5ce1 100644 --- a/core/pactbroker/src/test/groovy/au/com/dius/pact/core/pactbroker/PactBrokerClientSpec.groovy +++ b/core/pactbroker/src/test/groovy/au/com/dius/pact/core/pactbroker/PactBrokerClientSpec.groovy @@ -95,7 +95,7 @@ class PactBrokerClientSpec extends Specification { } when: - def consumers = client.fetchConsumersWithSelectors('provider', [], [], false, '').value + def consumers = client.fetchConsumersWithSelectors('provider', [], [], [], false, '').value then: consumers == [] @@ -113,7 +113,7 @@ class PactBrokerClientSpec extends Specification { } when: - def consumers = client.fetchConsumersWithSelectors('provider', [], [], false, '').value + def consumers = client.fetchConsumersWithSelectors('provider', [], [], [], false, '').value then: consumers != [] @@ -134,7 +134,7 @@ class PactBrokerClientSpec extends Specification { when: def consumers = client.fetchConsumersWithSelectors('provider', - [ new ConsumerVersionSelector('tag', true, null, null) ], [], false, '').value + [ new ConsumerVersionSelector('tag', true, null, null) ], [], [], false, '').value then: consumers != [] @@ -156,7 +156,7 @@ class PactBrokerClientSpec extends Specification { when: def consumers = client.fetchConsumersWithSelectors('provider', [ new ConsumerVersionSelector('tag', true, null, null), - new ConsumerVersionSelector('anotherTag', true, null, null) ], [], false, '').value + new ConsumerVersionSelector('anotherTag', true, null, null) ], [], [], false, '').value then: consumers.size() == 2 @@ -185,7 +185,7 @@ class PactBrokerClientSpec extends Specification { when: def consumers = client.fetchConsumersWithSelectors('provider', - [ new ConsumerVersionSelector('tag', true, null, null) ], [], false, '').value + [ new ConsumerVersionSelector('tag', true, null, null) ], [], [], false, '').value then: consumers != [] @@ -206,7 +206,7 @@ class PactBrokerClientSpec extends Specification { when: def consumers = client.fetchConsumersWithSelectors('provider', - [ new ConsumerVersionSelector('tag', true, null, null) ], [], false, '').value + [ new ConsumerVersionSelector('tag', true, null, null) ], [], [], false, '').value then: consumers == [] @@ -399,7 +399,7 @@ class PactBrokerClientSpec extends Specification { ''') when: - def result = client.fetchConsumersWithSelectors('provider', selectors, [], false, '') + def result = client.fetchConsumersWithSelectors('provider', selectors, [], [], false, '') then: 1 * halClient.navigate() >> halClient @@ -432,7 +432,7 @@ class PactBrokerClientSpec extends Specification { ''') when: - def result = client.fetchConsumersWithSelectors('provider', [], [], false, '') + def result = client.fetchConsumersWithSelectors('provider', [], [], [], false, '') then: 1 * halClient.navigate() >> halClient @@ -450,7 +450,7 @@ class PactBrokerClientSpec extends Specification { } when: - def result = client.fetchConsumersWithSelectors('provider', [], [], false, '') + def result = client.fetchConsumersWithSelectors('provider', [], [], [], false, '') then: 1 * halClient.navigate() >> halClient @@ -478,7 +478,7 @@ class PactBrokerClientSpec extends Specification { } ''') when: - def result = client.fetchConsumersWithSelectors('provider', selectors, [], false, '2020-24-06') + def result = client.fetchConsumersWithSelectors('provider', selectors, [], [], false, '2020-24-06') then: 1 * halClient.navigate() >> halClient @@ -495,7 +495,7 @@ class PactBrokerClientSpec extends Specification { } def selectors = [ new ConsumerVersionSelector('DEV', true, null, null) ] def json = '{"consumerVersionSelectors":[{"latest":true,"tag":"DEV"}],"includePendingStatus":true,' + - '"includeWipPactsSince":"2020-24-06","providerVersionTags":[]}' + '"includeWipPactsSince":"2020-24-06","providerVersionBranches":[],"providerVersionTags":[]}' def jsonResult = JsonParser.INSTANCE.parseString(''' { "_embedded": { @@ -505,7 +505,7 @@ class PactBrokerClientSpec extends Specification { } ''') when: - def result = client.fetchConsumersWithSelectors('provider', selectors, [], true, '2020-24-06') + def result = client.fetchConsumersWithSelectors('provider', selectors, [], [], true, '2020-24-06') then: 1 * halClient.navigate() >> halClient @@ -524,7 +524,7 @@ class PactBrokerClientSpec extends Specification { when: def result = client.fetchConsumersWithSelectors('provider', - [ new ConsumerVersionSelector(null, true, 'consumer', null) ], [], false, '') + [ new ConsumerVersionSelector(null, true, 'consumer', null) ], [], [], false, '') then: 1 * halClient.navigate() >> halClient @@ -580,7 +580,7 @@ class PactBrokerClientSpec extends Specification { ] when: - def result = client.fetchConsumersWithSelectors('provider', selectors, [], false, '') + def result = client.fetchConsumersWithSelectors('provider', selectors, [], [], false, '') then: 1 * halClient.navigate() >> halClient @@ -604,7 +604,7 @@ class PactBrokerClientSpec extends Specification { ] when: - def result = client.fetchConsumersWithSelectors('provider', selectors, [], false, '') + def result = client.fetchConsumersWithSelectors('provider', selectors, [], [], false, '') then: 1 * halClient.navigate() >> { @@ -664,7 +664,7 @@ class PactBrokerClientSpec extends Specification { def expectedJson = '{"consumerVersionSelectors":[{"mainBranch":true}],"includePendingStatus":false}' when: - client.fetchConsumersWithSelectors('provider', [], [], false, '') + client.fetchConsumersWithSelectors('provider', [], [], [], false, '') then: 1 * halClient.postJson('pb:provider-pacts-for-verification', _, expectedJson) diff --git a/pact-publish/src/test/groovy/broker/PactBrokerClientPactSpec.groovy b/pact-publish/src/test/groovy/broker/PactBrokerClientPactSpec.groovy index 4a342df243..22c1d955d9 100644 --- a/pact-publish/src/test/groovy/broker/PactBrokerClientPactSpec.groovy +++ b/pact-publish/src/test/groovy/broker/PactBrokerClientPactSpec.groovy @@ -11,7 +11,7 @@ import com.github.michaelbull.result.Err import com.github.michaelbull.result.Ok import spock.lang.Specification -@SuppressWarnings(['UnnecessaryGetter', 'LineLength', 'NestedBlockDepth', 'AbcMetric', 'MethodSize', 'ClassSize']) +@SuppressWarnings(['GroovyAssignabilityCheck','UnnecessaryGetter', 'LineLength', 'NestedBlockDepth', 'AbcMetric', 'MethodSize', 'ClassSize']) class PactBrokerClientPactSpec extends Specification { private PactBrokerClient pactBrokerClient @@ -917,7 +917,7 @@ class PactBrokerClientPactSpec extends Specification { def result = pactBroker.runTest { server, context -> def consumerPacts = pactBrokerClient.fetchConsumersWithSelectors('Activity Service', [ new ConsumerVersionSelector('test', true, null, null) - ], [], false, '') + ], [], [], false, '') assert consumerPacts instanceof Ok assert consumerPacts.value.size == 2 assert !consumerPacts.value[0].pending @@ -960,7 +960,8 @@ class PactBrokerClientPactSpec extends Specification { latest true } ]) - providerVersionTags(['master']) + providerVersionTags(['tag']) + providerVersionBranches(['master']) includePendingStatus true } willRespondWith(status: 200) @@ -1030,7 +1031,7 @@ class PactBrokerClientPactSpec extends Specification { def result = pactBroker.runTest { server, context -> def consumerPacts = pactBrokerClient.fetchConsumersWithSelectors('Activity Service', [ new ConsumerVersionSelector('test', true, null, null) - ], ['master'], true, '') + ], ['tag'], ['master'], true, '') assert consumerPacts instanceof Ok assert consumerPacts.value.size == 2 assert !consumerPacts.value[0].pending @@ -1073,7 +1074,8 @@ class PactBrokerClientPactSpec extends Specification { latest true } ]) - providerVersionTags(['master']) + providerVersionTags(['tag']) + providerVersionBranches(['master']) includePendingStatus true includeWipPactsSince '2020-06-24' } @@ -1154,7 +1156,7 @@ class PactBrokerClientPactSpec extends Specification { def result = pactBroker.runTest { server, context -> def consumerPacts = pactBrokerClient.fetchConsumersWithSelectors('Activity Service', [ new ConsumerVersionSelector('test', true, null, null) - ], ['master'], true, '2020-06-24') + ], ['tag'], ['master'], true, '2020-06-24') assert consumerPacts instanceof Ok assert consumerPacts.value.size == 2 assert !consumerPacts.value[0].wip diff --git a/provider/gradle/src/main/kotlin/au/com/dius/pact/provider/gradle/GradleProviderInfo.kt b/provider/gradle/src/main/kotlin/au/com/dius/pact/provider/gradle/GradleProviderInfo.kt index 2640056e5b..3fa7cda939 100644 --- a/provider/gradle/src/main/kotlin/au/com/dius/pact/provider/gradle/GradleProviderInfo.kt +++ b/provider/gradle/src/main/kotlin/au/com/dius/pact/provider/gradle/GradleProviderInfo.kt @@ -105,10 +105,11 @@ open class GradleProviderInfo(name: String, val project: Project) : ProviderInfo val pending = brokerConfig!!.enablePending ?: false if (pending && (brokerConfig!!.providerTags.isNullOrEmpty() || - brokerConfig!!.providerTags!!.any { it.trim().isEmpty() })) { + brokerConfig!!.providerTags!!.any { it.trim().isEmpty() }) && (brokerConfig!!.providerBranches.isNullOrEmpty() || + brokerConfig!!.providerBranches!!.any { it.trim().isEmpty() })) { throw GradleScriptException( """ - |No providerTags: To use the pending pacts feature, you need to provide the list of provider names for the provider application version that will be published with the verification results. + |No providerTags or providerBranches: To use the pending pacts feature, you need to provide the list of provider names for the provider application version that will be published with the verification results. | |For instance: | diff --git a/provider/gradle/src/main/kotlin/au/com/dius/pact/provider/gradle/PactBrokerConsumerConfig.kt b/provider/gradle/src/main/kotlin/au/com/dius/pact/provider/gradle/PactBrokerConsumerConfig.kt index bdd5ff1210..c564ae69a6 100644 --- a/provider/gradle/src/main/kotlin/au/com/dius/pact/provider/gradle/PactBrokerConsumerConfig.kt +++ b/provider/gradle/src/main/kotlin/au/com/dius/pact/provider/gradle/PactBrokerConsumerConfig.kt @@ -8,7 +8,8 @@ import au.com.dius.pact.core.pactbroker.ConsumerVersionSelector data class PactBrokerConsumerConfig @JvmOverloads constructor( var selectors: List? = listOf(), var enablePending: Boolean? = false, - var providerTags: List? = listOf() + var providerTags: List? = listOf(), + var providerBranches: List? = listOf() ) { companion object { @JvmStatic diff --git a/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/GradleProviderInfoSpec.groovy b/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/GradleProviderInfoSpec.groovy index b5333a73e3..429ab1cd6f 100644 --- a/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/GradleProviderInfoSpec.groovy +++ b/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/GradleProviderInfoSpec.groovy @@ -32,15 +32,16 @@ class GradleProviderInfoSpec extends Specification { selectors = latestTags('test') enablePending = true providerTags = ['master'] + providerBranches = ['master'] } then: provider.brokerConfig == new PactBrokerConsumerConfig([new ConsumerVersionSelector('test', true, null, null)], - true, ['master']) + true, ['master'], ['master']) } @Unroll - def 'fromPactBroker throws an exception if pending pacts is enabled but there are no provider tags'() { + def 'fromPactBroker throws an exception if pending pacts is enabled but there are no provider tags or provider branches'() { given: def provider = new GradleProviderInfo('provider', Mock(Project)) @@ -49,16 +50,18 @@ class GradleProviderInfoSpec extends Specification { selectors = latestTags('test') enablePending = true providerTags = tags + providerBranches = branches } then: def ex = thrown(GradleScriptException) - ex.message.trim().startsWith('No providerTags: To use the pending pacts feature, you need to provide the list of ' + + ex.message.trim().startsWith('No providerTags or providerBranches: To use the pending pacts feature, you need to provide the list of ' + 'provider names') where: tags << [null, [], ['']] + branches << [null, [], ['']] } def 'supports specifying a fallback tag'() { diff --git a/provider/junit/src/test/groovy/au/com/dius/pact/provider/junit/loader/PactBrokerLoaderSpec.groovy b/provider/junit/src/test/groovy/au/com/dius/pact/provider/junit/loader/PactBrokerLoaderSpec.groovy index 3fcd1746f6..c48c9453d8 100644 --- a/provider/junit/src/test/groovy/au/com/dius/pact/provider/junit/loader/PactBrokerLoaderSpec.groovy +++ b/provider/junit/src/test/groovy/au/com/dius/pact/provider/junit/loader/PactBrokerLoaderSpec.groovy @@ -42,6 +42,7 @@ class PactBrokerLoaderSpec extends Specification { private List consumers private String enablePendingPacts private List providerTags + private List providerBranches private String includeWipPactsSince private IPactBrokerClient brokerClient private Pact mockPact @@ -59,6 +60,7 @@ class PactBrokerLoaderSpec extends Specification { consumers = [] enablePendingPacts = '' providerTags = [] + providerBranches = [] includeWipPactsSince = '' brokerClient = Mock(IPactBrokerClient) { getOptions() >> [:] @@ -73,8 +75,8 @@ class PactBrokerLoaderSpec extends Specification { pactBrokerLoader = { boolean failIfNoPactsFound = true -> IPactBrokerClient client = brokerClient def loader = new PactBrokerLoader(host, port, protocol, tags, consumerVersionSelectors, consumers, - failIfNoPactsFound, null, null, valueResolver, enablePendingPacts, providerTags, includeWipPactsSince, url, - enableInsecureTls) { + failIfNoPactsFound, null, null, valueResolver, enablePendingPacts, providerTags, providerBranches, + includeWipPactsSince, url, enableInsecureTls) { @Override IPactBrokerClient newPactBrokerClient(URI url, ValueResolver resolver) { client @@ -90,7 +92,7 @@ class PactBrokerLoaderSpec extends Specification { def list = pactBrokerLoader().load('test') then: - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _, _) >> new Ok([]) notThrown(NoPactsFoundException) list.empty } @@ -100,13 +102,13 @@ class PactBrokerLoaderSpec extends Specification { def result = pactBrokerLoader(false).load('test') then: - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _, _) >> new Ok([]) result == [] } def 'Throws any Exception On Execution Exception'() { given: - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Err(new InvalidHalResponse('message')) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _, _) >> new Err(new InvalidHalResponse('message')) when: pactBrokerLoader().load('test') @@ -155,7 +157,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _, _) >> new Ok([]) } @RestoreSystemProperties @@ -179,7 +181,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _, _) >> new Ok([]) } @RestoreSystemProperties @@ -203,7 +205,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _, _) >> new Ok([]) } @RestoreSystemProperties @@ -275,7 +277,7 @@ class PactBrokerLoaderSpec extends Specification { then: noExceptionThrown() - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _, _) >> new Ok([]) } def 'Loads pacts for each provided tag'() { @@ -297,7 +299,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -325,7 +327,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -349,7 +351,7 @@ class PactBrokerLoaderSpec extends Specification { def result = pactBrokerLoader().load('test') then: - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) result.size() == 2 } @@ -373,7 +375,7 @@ class PactBrokerLoaderSpec extends Specification { def result = pactBrokerLoader().load('test') then: - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) result.size() == 2 } @@ -387,7 +389,7 @@ class PactBrokerLoaderSpec extends Specification { then: result.size() == 1 - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], [], false, '') >> new Ok(expected) } @SuppressWarnings('GStringExpressionWithinString') @@ -408,7 +410,7 @@ class PactBrokerLoaderSpec extends Specification { then: 1 * brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 1 } @@ -436,7 +438,7 @@ class PactBrokerLoaderSpec extends Specification { then: 1 * brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 1 } @@ -461,7 +463,7 @@ class PactBrokerLoaderSpec extends Specification { def result = pactBrokerLoader().load('test') then: - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) result.size() == 2 } @@ -500,7 +502,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -529,7 +531,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 4 } @@ -557,7 +559,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -577,7 +579,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 4 } @@ -599,7 +601,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 4 } @@ -625,7 +627,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -647,7 +649,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -673,7 +675,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok([]) } @Issue('#1208') @@ -700,7 +702,7 @@ class PactBrokerLoaderSpec extends Specification { then: valueResolver.propertyDefined('pactbroker.consumerversionselectors.tags') >> true valueResolver.resolveValue('pactbroker.consumerversionselectors.tags') >> 'one,two,three' - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) } def 'Loads pacts with consumer version selectors when consumer version selectors and tags are both present'() { @@ -720,7 +722,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 4 } @@ -743,7 +745,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], [], false, '') >> new Ok([]) } def 'Does not loads wip pacts when pending is false'() { @@ -768,7 +770,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -797,7 +799,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, ['dev'], true, '2020-06-25') >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, ['dev'], [], true, '2020-06-25') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -824,7 +826,7 @@ class PactBrokerLoaderSpec extends Specification { pactBrokerLoader().load('test') then: - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], [], false, '') >> new Ok([]) noExceptionThrown() } @@ -848,7 +850,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], [], false, '') >> new Ok([]) } def 'configured from annotation with https and no port'() { @@ -873,7 +875,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], [], false, '') >> new Ok([]) } def 'Auth: Uses no auth if no auth is provided'() { @@ -1207,6 +1209,96 @@ class PactBrokerLoaderSpec extends Specification { ] } + def 'building the list of selectors expands any consumer name expressions'() { + given: + valueResolver = Mock(ValueResolver) { + it.propertyDefined(_) >> { it[0] == 'two' || it[0] == 'X' } + it.resolveValue(_) >> { + if (it[0] == 'two') { + '2,3' + } else if (it[0] == 'X') { + 'Y' + } else { + null + } + } + } + consumerVersionSelectors = [ + createVersionSelector(consumer: '${two}') + ] + + when: + def result = pactBrokerLoader.call().buildConsumerVersionSelectors(valueResolver) + + then: + result == [ + new ConsumerVersionSelector(null, true, '2', null), + new ConsumerVersionSelector(null, true, '3', null) + ] + } + + def 'building the list of selectors with both tag and consumer name expressions'() { + given: + valueResolver = Mock(ValueResolver) { + it.propertyDefined(_) >> { it[0] == 'two' || it[0] == 'X' } + it.resolveValue(_) >> { + if (it[0] == 'two') { + '2,3,4' + } else if (it[0] == 'X') { + 'Y,Z' + } else { + null + } + } + } + consumerVersionSelectors = [ + createVersionSelector(tag: '${X}', consumer: '${two}') + ] + + when: + def result = pactBrokerLoader.call().buildConsumerVersionSelectors(valueResolver) + + then: + result == [ + new ConsumerVersionSelector('Y', true, '2', null), + new ConsumerVersionSelector('Y', true, '3', null), + new ConsumerVersionSelector('Y', true, '4', null), + new ConsumerVersionSelector('Z', true, '2', null), + new ConsumerVersionSelector('Z', true, '3', null), + new ConsumerVersionSelector('Z', true, '4', null) + ] + } + + @RestoreSystemProperties + void 'test annotation with system properties with both tag and consumer name expressions'() { + given: + System.setProperty('pactbroker.consumerversionselectors.tags', '1,2,3') + System.setProperty('pactbroker.consumers', 'A,B') + pactBrokerLoader = { + new PactBrokerLoader(PactBrokerAnnotationNoPort.getAnnotation(PactBroker)) { + @Override + IPactBrokerClient newPactBrokerClient(URI url, ValueResolver resolver) { + brokerClient + } + } + } + def selectors = [ + new ConsumerVersionSelector('1', true, 'A', ''), + new ConsumerVersionSelector('1', true, 'B', ''), + new ConsumerVersionSelector('2', true, 'A', ''), + new ConsumerVersionSelector('2', true, 'B', ''), + new ConsumerVersionSelector('3', true, 'A', ''), + new ConsumerVersionSelector('3', true, 'B', '') + ] + + when: + def result = pactBrokerLoader().load('test') + + then: + result == [] + 1 * brokerClient.fetchConsumersWithSelectors(_, selectors, _, _, _, _) >> new Ok([]) + } + @Unroll @SuppressWarnings('LineLength') def 'getPactBrokerSource uses the URL if it is set'() { @@ -1260,7 +1352,7 @@ class PactBrokerLoaderSpec extends Specification { pactBrokerLoader().load('test') then: - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> { + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], [], false, '') >> { throw new InvalidNavigationRequest('PKIX path building failed', new SSLHandshakeException('PKIX path building failed')) } thrown(InvalidNavigationRequest) @@ -1283,7 +1375,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _, _) >> new Ok([]) } void 'Enables insecure TLS from explicit PactBroker annotation setting'() { @@ -1303,7 +1395,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _, _) >> new Ok([]) } @RestoreSystemProperties @@ -1327,7 +1419,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _, _) >> new Ok([]) } def 'Uses the insecure TlS setting when creating the PactBrokerClient'() { diff --git a/provider/src/main/java/au/com/dius/pact/provider/junitsupport/loader/PactBroker.java b/provider/src/main/java/au/com/dius/pact/provider/junitsupport/loader/PactBroker.java index e9044b19de..7e18219a6b 100644 --- a/provider/src/main/java/au/com/dius/pact/provider/junitsupport/loader/PactBroker.java +++ b/provider/src/main/java/au/com/dius/pact/provider/junitsupport/loader/PactBroker.java @@ -96,6 +96,11 @@ PactBrokerAuth authentication() default @PactBrokerAuth(username = "${pactbroker */ String[] providerTags() default "${pactbroker.providerTags:}"; + /** + * Provider Branches to use to evaluate pending pacts + */ + String[] providerBranches() default "${pactbroker.providerBranches:}"; + /** * The earliest date WIP pacts should be included (ex: YYYY-MM-DD). If no date is provided, WIP pacts will not be * included. diff --git a/provider/src/main/kotlin/au/com/dius/pact/provider/PactBrokerOptions.kt b/provider/src/main/kotlin/au/com/dius/pact/provider/PactBrokerOptions.kt index a9f7b8791e..7f4df5eb6c 100644 --- a/provider/src/main/kotlin/au/com/dius/pact/provider/PactBrokerOptions.kt +++ b/provider/src/main/kotlin/au/com/dius/pact/provider/PactBrokerOptions.kt @@ -11,10 +11,15 @@ data class PactBrokerOptions @JvmOverloads constructor( val enablePending: Boolean = false, /** - * Provider tags. Required if pending pacts are enabled + * Provider tags. Either this or providerBranches if pending pacts are enabled */ val providerTags: List = listOf(), + /** + * Provider branches. Either this or providerTags if pending pacts are enabled + */ + val providerBranches: List = listOf(), + /** * Only include WIP pacts since the provided date. Dates need to be in ISO format (YYYY-MM-DD). * See https://docs.pact.io/pact_broker/advanced_topics/wip_pacts/ diff --git a/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderInfo.kt b/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderInfo.kt index 32a6fe2074..05ce97bb31 100644 --- a/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderInfo.kt +++ b/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderInfo.kt @@ -78,9 +78,14 @@ open class ProviderInfo @JvmOverloads constructor ( } else { emptyList() } + val providerBranches = if (enablePending) { + options["providerBranches"] as List? + } else { + emptyList() + } val includePactsSince = Utils.lookupInMap(options, "includeWipPactsSince", String::class.java, "") - val pactBrokerOptions = PactBrokerOptions(enablePending, providerTags.orEmpty(), includePactsSince, false, - PactBrokerOptions.parseAuthSettings(options)) + val pactBrokerOptions = PactBrokerOptions(enablePending, providerTags.orEmpty(), providerBranches.orEmpty(), + includePactsSince, false, PactBrokerOptions.parseAuthSettings(options)) return hasPactsFromPactBrokerWithSelectors(pactBrokerUrl, selectors, pactBrokerOptions) } @@ -91,14 +96,16 @@ open class ProviderInfo @JvmOverloads constructor ( selectors: List, options: PactBrokerOptions ): List { - if (options.enablePending && options.providerTags.isEmpty()) { - throw RuntimeException("No providerTags: To use the pending pacts feature, you need to provide the list of " + - "provider names for the provider application version that will be published with the verification results") + if (options.enablePending && options.providerTags.isEmpty() && options.providerBranches.isEmpty()) { + throw RuntimeException("No providerTags or providerBranches: To use the pending pacts feature, you need to" + + " provide the list of provider names for the provider application version that will be published with the" + + " verification results") } val client = pactBrokerClient(pactBrokerUrl, options) val consumersFromBroker = client.fetchConsumersWithSelectors(name, selectors, options.providerTags, - options.enablePending, options.includeWipPactsSince) + options.providerBranches, options.enablePending, options.includeWipPactsSince) .map { results -> results.map { ConsumerInfo.from(it) } } + return when (consumersFromBroker) { is Ok> -> { val list = consumersFromBroker.value diff --git a/provider/src/main/kotlin/au/com/dius/pact/provider/junitsupport/loader/PactBrokerLoader.kt b/provider/src/main/kotlin/au/com/dius/pact/provider/junitsupport/loader/PactBrokerLoader.kt index 4e1140b215..9987a36251 100644 --- a/provider/src/main/kotlin/au/com/dius/pact/provider/junitsupport/loader/PactBrokerLoader.kt +++ b/provider/src/main/kotlin/au/com/dius/pact/provider/junitsupport/loader/PactBrokerLoader.kt @@ -55,6 +55,7 @@ open class PactBrokerLoader( valueResolver: ValueResolver? = null, val enablePendingPacts: String = "false", val providerTags: List = emptyList(), + val providerBranches: List = emptyList(), val includeWipPactsSince: String = "", val pactBrokerUrl: String? = null, val enableInsecureTls: String = "false" @@ -79,6 +80,7 @@ open class PactBrokerLoader( null, pactBroker.enablePendingPacts, pactBroker.providerTags.toList(), + pactBroker.providerBranches.toList(), pactBroker.includeWipPactsSince, pactBroker.url, pactBroker.enableInsecureTls @@ -198,6 +200,7 @@ open class PactBrokerLoader( } @Throws(IOException::class, IllegalArgumentException::class) + @Suppress("ThrowsCount") private fun loadPactsForProvider( providerName: String, selectors: List, @@ -207,11 +210,12 @@ open class PactBrokerLoader( "$selectors" } val pending = parseExpression(enablePendingPacts, DataType.BOOLEAN, resolver) as Boolean val providerTags = providerTags.flatMap { parseListExpression(it, resolver) }.filter { it.isNotEmpty() } - if (pending && providerTags.none { it.isNotEmpty() }) { - throw IllegalArgumentException("Pending pacts feature has been enabled, but no provider tags have been " + - "specified. To use the pending pacts feature, you need to provide the list of provider names for the " + - "provider application version with the providerTags property that will be published with the verification " + - "results.") + val providerBranches = providerBranches.flatMap { parseListExpression(it, resolver) }.filter { it.isNotEmpty() } + if (pending && providerTags.none { it.isNotEmpty() } && providerBranches.none { it.isNotEmpty() }) { + throw IllegalArgumentException("Pending pacts feature has been enabled, but no provider tags or branches have " + + "been specified. To use the pending pacts feature, you need to provide the list of provider names for the " + + "provider application version with the providerTags or providerBranches property that will be published with " + + "the verification results.") } val wipSinceDate = if (pending) parseExpression(includeWipPactsSince, DataType.STRING, resolver) as String else "" @@ -219,8 +223,8 @@ open class PactBrokerLoader( try { val pactBrokerClient = newPactBrokerClient(uriBuilder.build(), resolver) - val result = pactBrokerClient.fetchConsumersWithSelectors(providerName, selectors, providerTags, pending, - wipSinceDate) + val result = pactBrokerClient.fetchConsumersWithSelectors(providerName, selectors, providerTags, + providerBranches, pending, wipSinceDate) var consumers = when (result) { is Ok -> result.value is Err -> throw result.error diff --git a/provider/src/test/groovy/au/com/dius/pact/provider/ProviderInfoSpec.groovy b/provider/src/test/groovy/au/com/dius/pact/provider/ProviderInfoSpec.groovy index 58741c281d..3622b636da 100644 --- a/provider/src/test/groovy/au/com/dius/pact/provider/ProviderInfoSpec.groovy +++ b/provider/src/test/groovy/au/com/dius/pact/provider/ProviderInfoSpec.groovy @@ -76,7 +76,7 @@ class ProviderInfoSpec extends Specification { def result = providerInfo.hasPactsFromPactBrokerWithSelectors(options, url, selectors) then: - pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, [], false, '') >> new Ok([ + pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, [], [], false, '') >> new Ok([ new PactBrokerResult('consumer', '', url, [], [], false, null, false, false, null) ]) result.size == 1 @@ -84,7 +84,7 @@ class ProviderInfoSpec extends Specification { !result[0].pending } - def 'hasPactsFromPactBrokerWithSelectors - does include pending pacts if the option is present'() { + def 'hasPactsFromPactBrokerWithSelectors - does include pending pacts if the option is present and tags are specified'() { given: def options = [ enablePending: true, @@ -99,7 +99,7 @@ class ProviderInfoSpec extends Specification { def result = providerInfo.hasPactsFromPactBrokerWithSelectors(options, url, selectors) then: - pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, ['master'], true, '') >> new Ok([ + pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, ['master'], [], true, '') >> new Ok([ new PactBrokerResult('consumer', '', url, [], [], true, null, false, false, null) ]) result.size == 1 @@ -107,7 +107,30 @@ class ProviderInfoSpec extends Specification { result[0].pending } - def 'hasPactsFromPactBrokerWithSelectors - throws an exception if the pending pacts option is present but there is no provider tags'() { + def 'hasPactsFromPactBrokerWithSelectors - does include pending pacts if the option is present and branches are specified'() { + given: + def options = [ + enablePending: true, + providerBranches: ['master'] + ] + def url = 'http://localhost:8080' + def selectors = [ + new ConsumerVersionSelector('test', true, null, null) + ] + + when: + def result = providerInfo.hasPactsFromPactBrokerWithSelectors(options, url, selectors) + + then: + pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, [], ['master'], true, '') >> new Ok([ + new PactBrokerResult('consumer', '', url, [], [], true, null, false, false, null) + ]) + result.size == 1 + result[0].name == 'consumer' + result[0].pending + } + + def 'hasPactsFromPactBrokerWithSelectors - throws an exception if the pending pacts option is present but there is no provider tags or provider branches'() { given: def options = [ enablePending: true @@ -122,7 +145,7 @@ class ProviderInfoSpec extends Specification { then: def exception = thrown(RuntimeException) - exception.message == 'No providerTags: To use the pending pacts feature, you need to provide the list of ' + + exception.message == 'No providerTags or providerBranches: To use the pending pacts feature, you need to provide the list of ' + 'provider names for the provider application version that will be published with the verification results' } @@ -141,7 +164,7 @@ class ProviderInfoSpec extends Specification { def result = providerInfo.hasPactsFromPactBrokerWithSelectors(options, url, selectors) then: - pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, ['master'], true, '') >> new Ok([ + pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, ['master'], [], true, '') >> new Ok([ new PactBrokerResult('consumer', '', url, [], [], false, null, false, false, null) ]) result.size == 1 @@ -165,7 +188,7 @@ class ProviderInfoSpec extends Specification { def result = providerInfo.hasPactsFromPactBrokerWithSelectors(options, url, selectors) then: - pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, ['master'], true, '2020-05-23') >> new Ok([ + pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, ['master'], [], true, '2020-05-23') >> new Ok([ new PactBrokerResult('consumer', '', url, [], [], true, null, true, false, null) ]) result.size == 1 @@ -187,7 +210,7 @@ class ProviderInfoSpec extends Specification { then: providerInfo.pactBrokerClient(_, { it.auth == new Auth.BearerAuthentication('123ABC') }) >> pactBrokerClient - pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, [], false, '') >> new Ok([ + pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, [], [], false, '') >> new Ok([ new PactBrokerResult('consumer', '', url, [], [], true, null, true, false, null) ]) result.size == 1