spring-cloud-contract icon indicating copy to clipboard operation
spring-cloud-contract copied to clipboard

Eclipse integration of spring-cloud-contract-maven-plugin

Open aritzbastida opened this issue 6 years ago • 21 comments

I'm suffering a strange integration problem with Eclipse (m2e) and the spring-cloud-contract-maven-plugin.

  • If the generated-test-sources folder is included in the Build Path, Eclipse keeps generating the tests files over and over, in a very long loop.
  • Even if I don't include the folder in the Build Path, the tests are regenerated whenever I open the file in the Eclipse editor (just to view contents). To reproduce this, just open it, change focus to another file or tab, and then click on the file again.

This breaks the IDE experience a little bit, because the contract verifier tests cannot be launched using "Run as... -> Junit Test".

I have the following setup:

  • Spring Tool Suite 4.4.1 (Eclipse)
  • Contract Provider Maven project, with:
    • Dependency: spring-cloud-starter-contract-verifier 2.2.0.RELEASE
    • Plugin: spring-cloud-contract-maven-plugin 2.2.0.RELEASE

I attach a small recording to show this issue and the source code: scc_generateTest_loop_video.zip scc_generateTest_loop_code.zip

aritzbastida avatar Dec 05 '19 07:12 aritzbastida

I'm no expert with STS, but what I did was explicitly add this plugin


			<plugin>
	            <groupId>org.codehaus.mojo</groupId>
	            <artifactId>build-helper-maven-plugin</artifactId>
	            <executions>
	                <execution>
	                    <id>add-test-source</id>
	                    <phase>generate-test-sources</phase>
	                    <goals>
	                        <goal>add-test-source</goal>
	                    </goals>
	                    <configuration>
	                        <sources>
	                            <directory>${project.build.directory}/generated-test-sources/contracts</directory>
	                        </sources>
	                    </configuration>
	                </execution>
	            </executions>
        	</plugin>

to the build and I got the folder present in the test sources in my project view

marcingrzejszczak avatar Dec 13 '19 15:12 marcingrzejszczak

I can confirm this worked pretty well in my case. Thanks for the hint.

arnosthavelka avatar Dec 18 '19 07:12 arnosthavelka

Thanks @marcingrzejszczak! I added that plugin configuration, and now the auto-generated test folder is automatically added to the Eclipse classpath. However, the infinite loop still remains: the verification tests are regenerated over and over.

@arnosthavelka: Can you check that on your side?

aritzbastida avatar Dec 18 '19 08:12 aritzbastida

@aritzbastida I'll try to check it later, but I don't remember any issue. Everything worked like charm after the recommended plugin was added to pom.xml.

arnosthavelka avatar Dec 18 '19 12:12 arnosthavelka

I typically notice the issue when I open the verification tests in the Eclipse editor. For example, the auto-generated attributes (ids and the like) are changing all the time. You can watch the attached video, to see what I mean.

aritzbastida avatar Dec 18 '19 12:12 aritzbastida

@aritzbastida I saw that too, what I did and I think that helped was adding this (runOnIncremental and runOnConfiguration)


            <!--This plugin's configuration is used to store Eclipse m2e settings
                only. It has no influence on the Maven build itself. -->
            <plugin>
                <groupId>org.eclipse.m2e</groupId>
                <artifactId>lifecycle-mapping</artifactId>
                <version>1.0.0</version>
                <configuration>
                    <lifecycleMappingMetadata>                
                        <pluginExecutions>
                             <pluginExecution>
                                <pluginExecutionFilter>
                                    <groupId>org.springframework.cloud</groupId>
                                    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
                                    <versionRange>[1.0,)</versionRange>
                                    <goals>
                                        <goal>convert</goal>
                                    </goals>
                                </pluginExecutionFilter>
                                <action>
                                    <execute>
								         <runOnIncremental>false</runOnIncremental>
								         <runOnConfiguration>false</runOnConfiguration>
                                    </execute>
                                </action>
                             </pluginExecution>
                        </pluginExecutions>
                    </lifecycleMappingMetadata>
                </configuration>
            </plugin>

marcingrzejszczak avatar Dec 19 '19 08:12 marcingrzejszczak

Thanks!! I have just added that plugin into my pom.xml, but Eclipse still keeps generating the tests.

I will try again with a fresh Eclipse install, because, for some reason lifecycle-mapping is not working as expected. If i change the action to , then Maven -> Update Project, and finally open the project settings (Maven -> Lifecycle Mapping), they are still shown as "execute". So, for some reason, my changes are not getting caught.

aritzbastida avatar Dec 19 '19 18:12 aritzbastida

Sorry, I had added lifecycle-mapping into <plugins> section, instead of <pluginManagement>. My bad!

I have disabled <runOnIncremental> and <runOnConfiguration> for convert, generateStubs and generateTests goals. Now, the auto-generated tests are only created when I force a full rebuild of my Eclipse project. This is of course safer than the previous "loop", although not very convenient (one has to remember to force a clean on the project each time he touches the contract).

I guess that the spring-cloud-contract-maven-plugin should be made compatible with <runOnIncremental>, and this m2e configuration should not be necessary. Is that possible? Will you consider this feature for future releases?

aritzbastida avatar Jan 21 '20 07:01 aritzbastida

Sure, however I have extremely limited knowledge on Eclipse stuff.

marcingrzejszczak avatar Jan 21 '20 08:01 marcingrzejszczak

Maybe the guys working on Spring Tools project can help?

aritzbastida avatar Jan 21 '20 09:01 aritzbastida

Good point! @martinlippert, can you please assist us? :)

marcingrzejszczak avatar Jan 21 '20 09:01 marcingrzejszczak

Sure. Let me invite @BoykoAlex, @kdvolder, @nierajsingh to this, too.

martinlippert avatar Jan 21 '20 09:01 martinlippert

Thank you all!

aritzbastida avatar Jan 21 '20 09:01 aritzbastida

I guess that the spring-cloud-contract-maven-plugin should be made compatible with <runOnIncremental>, and this m2e configuration should not be necessary. Is that possible?

Whether that is possible may depend somewhat on what the plugin does. If someone can try explaining what the plugin does then maybe we can think about how/if it can be implemented to work properly in incremental builds.

kdvolder avatar Jan 21 '20 16:01 kdvolder

The Spring Cloud Contract developers will answer better than I do, but I'll give it a try:

  • You write your service contracts in src/test/resources/contracts, using a specific DSL (typically in Groovy or YAML). A contract specifies, for a given HTTP request or input message, the response that the provider service should produce.
  • Based on contract files, the Maven plugin creates two artifacts:
    • JUnit tests (generateTests goal): Used as acceptance tests in the provider, to verify that the contract is respected. It should be possible to execute these from the "JUnit" view. Currently, that is only possible after adding build-helper-maven-plugin to pom.xml (see above).
    • Stubs (convert and generateStubs goals). A "stubs" JAR artifact is generated, which is then imported and used at the client-side to mock the provider service (e.g. with Wiremock).

Now, without a specific m2e lifecycle-mapping configuration, JUnit tests are regenerated over and over. You can find the evidence and a example project at my first post.

Ideally, the JUnit tests should be generated each time we change the contract files (and no more). As for the stubs, I'm not sure whether they are necessary in Eclipse; as far as I know, they are only used in client projects. If so, it would be (somewhat) useful that client projects in the same Eclipse workspace can "see" and use the stub JARs in their integration tests right away.

aritzbastida avatar Jan 22 '20 07:01 aritzbastida

There are two questions we should try to answer. First is why do we get this infinite trigger loop. I'm guessing that the output of the source code generator re-triggers itself because it considers the output of the generator as part of its inputs. We should try to understand why this happens if perhaps there is some 'easy' fix for this through configuration.

Secondly the question was raised about makng sure the plugin is 'compatible' with incremental builds. Unfortunately it is not often the case when a plugin is not up-front designed to be able to work in an incremental way. It can depend greatly on what the plugin does exacly. E.g. if the plugin is given only the files that have changed, is it able to produce correct results and only re-generate the pieces of its 'output' that depend only on the changed parts? For some types of plugins, they are inherently designed to work on the entire project at once and are hard or even impossible to generalize in this way. When the input -> output mapping is more or less 1-to-1 it is somewhat easy. I.e. you change one input file and that cause the generation of one output file. However if you have some kind of process that sumarizes or amalgamates information from many sources into a single big output... this is much trickier. I'm trying to get some insight into what we are dealing with here. I.e. the question is really... could the plugin generation process easily be generalized to take only the changed files and produce correct output from that? Or does it need all the files at once to regenerate all of its output each time it runs?

kdvolder avatar Jan 23 '20 18:01 kdvolder

Hi, thanks for your input. Did you revise the plugin for integration for STS incremental builds?

aritzbastida avatar Feb 13 '20 12:02 aritzbastida

As @aritzbastida mentioned the flow looks like this

  • We have a set of input files (contracts)
  • We copy them to target/subfolder
  • From contracts we create some files under target/generated-test-sources and some other ones target/stubs

And that's pretty much it on the high level. @kdvolder what additional information do you need?

marcingrzejszczak avatar Feb 13 '20 12:02 marcingrzejszczak

@marcingrzejszczak To be honest I do not have that much experience with the whole m2e integration around incremental builds. But I think from a very birds-eye perspective. Whether a build process/step is conceptually compatible with incremental builds depends on whether it is possible to conceive of a way to have your generators operate correctly when provided only with some kind of partial input / diff. E.g. only the source files that have changed are presented to the builder and the builder has then to be able to update its outputs properly (i.e. remove outdated information that was based on those source files only and regenerate it). This is typically much harder to do than just write a generator that accepts the entire input.

I think there are probably ways around this but at the expense of doing basically a 'full build' of all that you generate on every small change.

In some cases the incrementality is not so hard to achieve because the stuff generated from a given input file does not at all interact or depend on the stuff generated from another input file. In that case, its more or less trivial to incremantalize. The extreme other end of the spectrum is when the build generates a kind of 'summary' which contains information from every source file in the project. (E.g. an example of this is spring boot annotation processor, it scans the whole project and collects information into one single big metadata file... this is almost impossible to make work correctly in incremental builds). Maybe that gives some sense of what I'm trying to assess. I.e. are we dealing with an easy or hard case?

kdvolder avatar Feb 19 '20 19:02 kdvolder

Is #1361 likely to resolve/alleviate this issue?

aviv-amdocs avatar Apr 13 '21 08:04 aviv-amdocs

Can an STS user try to confirm that #1361 solves this problem?

marcingrzejszczak avatar Apr 12 '22 07:04 marcingrzejszczak