Spring-cloud-contract: [Gradle] generateContractTest not copying contracts specified in contractDepencency due to wrong pattern to pick contracts

Created on 20 Feb 2018  ยท  6Comments  ยท  Source: spring-cloud/spring-cloud-contract

_This issue is extremely similar to https://github.com/spring-cloud/spring-cloud-contract/issues/495_

I've created a minimal reproduction here. This is what I was trying to accomplish.

I have a project, called _contracts_ that I want to include my API and my contracts (written in groovy in this case). The contracts project is published to (my local) artifactory on build. I have another project called _tests_. The _tests_ project needs the contracts defined in the _contracts_ project to generate the tests and stubs. The _tests_ project uses the contractDepenency setting to accomplish this:

contracts {
    contractDependency {
        stringNotation = 'com.test:contracts:+:stubs'
    }
    testMode = 'MockMvc'
    contractsWorkOffline = true
}

Unfortunately no tests or stubs are generated when building the _tests_ project. The folder generated-test-sources stays empty and the stubs folder contains com.test/tests/1.0/contracts but the contracts folder is empty.

I've debugged this issue by running gradlew generateContractTests -d > tmp.tmp. The most interesting part is:

Will download contracts for [com.test:contracts:+:stubs]
Desired version is [+] - will try to resolve the latest version
Resolved version range is [{1.0=C:\Users\rtriesscheijn\.m2\repository (enhanced)}]
Will download the stub for version [1.0]
Resolved version is [1.0]
Resolving artifact [com.test:contracts:jar:stubs:1.0] using remote repositories []
Resolved artifact [com.test:contracts:jar:stubs:1.0] to C:\Users\rtriesscheijn\.m2\repository\com\test\contracts\1.0\contracts-1.0-stubs.jar
Unpacking stub from JAR [URI: file:/C:/Users/rtriesscheijn/.m2/repository/com/test/contracts/1.0/contracts-1.0-stubs.jar]
Unpacked file to [C:\Users\RTRIES~1\AppData\Local\Temp\contracts3545973372033847890]
Will pick a pattern from group id and artifact id
Pattern to pick contracts equals [^C:\\Users\\RTRIES~1\\AppData\\Local\\Temp\\contracts3545973372033847890(\\)?.*com\\test\\tests\\.*$]
Ant Pattern to pick files equals [**/com/test/tests/**/]
[C:\Users\RTRIES~1\AppData\Local\Temp\contracts3545973372033847890] to [C:\Projects\tmp\spring-cloud-contracts\tests\build\stubs\META-INF\com.test\tests\1.0\contracts]. The inclusion ant pattern is [**/com/test/tests/**/*.*]

As you can see the jar file with the contracts is successfully downloaded and if I look inside the temporary folder the contract is present:

contracts3545973372033847890\META-INF\com.test\contracts\1.0\contracts\someContract.groovy

The pattern to pick the contract is definitely wrong in multiple ways:

  • It uses the artifact name tests instead of contracts
  • It uses the package name com\test instead of com.test

Am I doing something very wrong, or is this a bug in one of the gradle functions?

bug gradle plugin

Most helpful comment

Issue is in the slashSeparatedGroupId() (as pointed out in ticket#495): https://github.com/spring-cloud/spring-cloud-contract/blob/c354bffafbd37ad1da4d80294521445420634bf4/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ContractDownloader.java#L65

Workaround is to set the contractsPath to some text to not end up in L63-L65.

All 6 comments

Something that seems to work is changing the contracts section in the gradle file of the _tests_ project to this. Does this accidentally fix it, and is it still a bug? Because I don't see anything about this in the docs (or did I miss it?).

contracts {
    contractDependency {
        stringNotation = 'com.test:contracts:+:stubs'
    }
    contractsPath = '/'  // <---- using '' doesn't work but using '/' seems to fix it.
    testMode = 'MockMvc'
    contractsWorkOffline = true
}

Issue is in the slashSeparatedGroupId() (as pointed out in ticket#495): https://github.com/spring-cloud/spring-cloud-contract/blob/c354bffafbd37ad1da4d80294521445420634bf4/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ContractDownloader.java#L65

Workaround is to set the contractsPath to some text to not end up in L63-L65.

So maybe you want to create a test and file a PR? :D

I would make a PR, but I'm not sure what the expected logic should be in L63-L65 of ContractDownloader. I'm afraid I would make a fix that just works for me.

Sure, so maybe start with a test that is failing for you. That will be a good starting point :)

I think you've made a mistake and I've made a bug :)

THE BUG

The bug is related to the fact that initially, we were supporting slash-separated paths to projects. E.g. if the group id was a.b.c then we did checked for a/b/c folder. At certain point we've started building stubs with the groupid folder as such e.g. a.b.c/artifact-id. This is where the bug comes in. For Maven and Gradle we're using ant patterns for copying files. We're only providing the slash-separated ant pattern. With this fix, we're backward compatible (we're leaving the slash-separated one) and we're adding support for dot-delimited group id.

THE MISTAKE

โ”œโ”€โ”€ build.gradle
โ”œโ”€โ”€ settings.gradle
โ””โ”€โ”€ src
    โ””โ”€โ”€ test
        โ””โ”€โ”€ resources
            โ””โ”€โ”€ contracts
                โ””โ”€โ”€ someContract.groovy

If the contracts folder was to contain the contracts for all other apps then your structure is wrong and you're building the jar in the wrong way. First of all you're building the contract jar as if contracts was an app. So after building the jar your stub structure looks like this:

โ”œโ”€โ”€ build
โ”‚ย ย  โ”œโ”€โ”€ stubs
โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ META-INF
โ”‚ย ย  โ”‚ย ย      โ””โ”€โ”€ com.test
โ”‚ย ย  โ”‚ย ย          โ””โ”€โ”€ contracts
โ”‚ย ย  โ”‚ย ย              โ””โ”€โ”€ 1.0
โ”‚ย ย  โ”‚ย ย                  โ”œโ”€โ”€ contracts
โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ””โ”€โ”€ someContract.groovy
โ”‚ย ย  โ”‚ย ย                  โ””โ”€โ”€ mappings
โ”‚ย ย  โ”‚ย ย                      โ””โ”€โ”€ someContract.json

contracts is the name of the artifact id of the contracts project. That makes absolutely perfect sense. If you wanted contracts to contain contracts that all other projects were to use you should structure it like here https://cloud.spring.io/spring-cloud-static/Edgware.SR2/multi/multi__spring_cloud_contract_faq.html#_common_repo_with_contracts and package it differently. So in your case you should either NOT use the contractDependency closure, and pass the path to the other project as the source of contracts, or use the contractDependency and modify the contractsPath (as you already have).

Was this page helpful?
0 / 5 - 0 ratings