Hey,
We don't need the module-b jar built in the reactor to be included in the war 
if the changes made in module-b won't affect the war. Instead, in this 
scenario, we're fine with using a jar resolved from the local repository. The 
requisites for this scenario are:

  *   Any change made to module-b is only in its test tree
  *   The only changes made to the direct and transitive dependencies of 
module-b are to its test scoped dependencies
So basically module-b is only in the reactor for verification purposes rather 
than ‘src packaging’ purposes.
Thanks,
Joe

On 2024/02/08 12:12:03 Tamás Cservenák wrote:
> Hej,
>
> yes, basically the "hack" is well described by you:
> - it retains "full' reactor project
> - introduces "needs build" on project
> - when it comes to building, it skips the project if flag set
>
> This results that module-b -> app link is not lost.
> And as for your parallelization request: the truth is that there IS and
> edge between app and module-b (via module-a), so despite module-a is
> "done", its transitive module-b is not done, hence you cannot build these
> two in parallel, as you do have an edge between app and module-b.
>
> Or to invert the question: what module-b JAR you want to have included in
> app WAR, when building? The one built, or the one from the local
> repository? If the latter, why are you building it in the first place?
>
> On Thu, Feb 8, 2024 at 12:06 PM Joseph Leonard <
> joseph.leon...@alfasystems.com> wrote:
>
> > Hi Tamás,
> > Thank you for hacking around this so rapidly. I am not familiar with the
> > maven code base, so let me know if I have misinterpreted the change: Is
> > your hack to:
> >
> >   1.  Retain the full multi-module build dependency graph such that the
> > build graph always remains consistent regardless of whether a “-pl” arg has
> > been provided
> >   2.  Introduce a skip build option to satisfy the functionality of the
> > “-pl” arg: The reactor will report the module has been built but the build
> > is basically a no-op
> > If so, this does resolve the issue but at the cost of losing the
> > opportunity to gain extra parallelism in the build.
> > What I was wondering may be possible (without any idea of how feasible it
> > would be to implement) would be the opportunity to recognise in the
> > multi-build distinct build graphs and then keep isolation in the reactor
> > between these graphs. To elaborate, in the reproducer scenario there would
> > be two distinct graphs:
> >
> >   *   "testsupport-module-1" followed by "app"
> >   *   "testsupport-module-2" followed by "module-b"
> > Ideally these two graphs build in parallel to each other and even if
> > ultimately there is a dependency between them they NEVER resolve that
> > dependency from within reactor they instead always resolve from the
> > external Maven cache. The key statement here is that if a user presents a
> > list of modules to be built then they really need to be sure that the
> > DIRECT dependencies between these modules truly represent the build
> > graph(s) they want. For tools like gitflow-incremental-builder which are
> > designed to carefully work out change sets and what needs to build this
> > offers a really powerful opportunity to optimise builds. I appreciate this
> > functionality could also be seen as a gotcha (although tbf this already
> > exists).
> > Thanks,
> > Joe
> >
> >
> > On 2024/02/08 10:09:31 Tamás Cservenák wrote:
> > > Seems we are on track with this. To prove my last-night theory I created
> > a
> > > "hack" (is really just that) and guess what?
> > > It makes reproducer behave "as expected":
> > > https://github.com/apache/maven/pull/1406
> > >
> > > T
> > >
> > > On Wed, Feb 7, 2024 at 10:05 PM Tamás Cservenák <ta...@cservenak.net>
> > wrote:
> > >
> > > > Howdy,
> > > >
> > > > Thank you very much, the reproducer works. Did not dig thru it fully,
> > but
> > > > here are some related issues:
> > > >
> > > > https://issues.apache.org/jira/browse/MNG-8028 (funny thing, I created
> > > > this few weeks ago)
> > > > https://issues.apache.org/jira/browse/MNG-6300
> > > >
> > > > Will report back tomorrow (EU TZ)
> > > > T
> > > >
> > > >
> > > > On Wed, Feb 7, 2024 at 7:48 PM Joseph Leonard <
> > > > joseph.leon...@alfasystems.com> wrote:
> > > >
> > > >> Hi Tamás,
> > > >> I have created a simple example here:
> > > >> https://github.com/josple/mvn-multibuild-issue
> > > >> Hopefully the README is clear enough – let me know if I can clarify
> > > >> anything.
> > > >> Thanks,
> > > >> Joe
> > > >>
> > > >> On 2024/02/07 17:33:08 Tamás Cservenák wrote:
> > > >> > Howdy,
> > > >> >
> > > >> > In that case, there is something fishy with the project, my blind
> > guess
> > > >> > would be some "hidden" inter-module dependency maybe?
> > > >> >
> > > >> > Can you provide access to source, or, if not feasible, could you
> > provide
> > > >> > some reproducer and publish it on Github/Gitlab/whatever (maybe even
> > > >> just
> > > >> > send it privately as ML strips off attachments and images) for us
> > to see
> > > >> > this in action?
> > > >> >
> > > >> > Thanks
> > > >> > T
> > > >> >
> > > >> > On Wed, Feb 7, 2024 at 6:29 PM Joseph Leonard <
> > > >> > joseph.leon...@alfasystems.com> wrote:
> > > >> >
> > > >> > > Hi Tamás,
> > > >> > > We have previously played around a bit with mvnd but not takari
> > > >> directly –
> > > >> > > I will have a play with it. With regards to this issue, using the
> > > >> takari
> > > >> > > smart builder unfortunately doesn’t resolve the issue.
> > > >> > > Joe
> > > >> > >
> > > >> > > On 2024/02/07 11:41:22 Tamás Cservenák wrote:
> > > >> > > > Can you please try smart builder instead?
> > > >> > > > https://github.com/takari/takari-smart-builder
> > > >> > > >
> > > >> > > > (note: smart builder is used by mvnd as well)
> > > >> > > >
> > > >> > > > The difference between the two can be seen here:
> > > >> > > > http://takari.io/book/30-team-maven.html#takari-smart-builder
> > > >> > > >
> > > >> > > > On Wed, Feb 7, 2024 at 11:50 AM Joseph Leonard <
> > > >> > > > joseph.leon...@alfasystems.com> wrote:
> > > >> > > >
> > > >> > > > > Hi Tamás,
> > > >> > > > > Yeah, this was unexpected to me initially as well. From what I
> > > >> can tell
> > > >> > > > > the Maven reactor only considers direct dependencies (i.e. not
> > > >> > > transitive
> > > >> > > > > dependencies) between the modules in the reactor when working
> > out
> > > >> the
> > > >> > > build
> > > >> > > > > graph. For example if you have a simple linear dependency
> > chain
> > > >> of:
> > > >> > > > > One --> Two --> Three --> Four --> Five
> > > >> > > > > Then invoking “mvn clean verify -pl One,Two,Four,Five -T 2
> > will
> > > >> result
> > > >> > > in
> > > >> > > > > two ‘graphs’ being built in parallel ([One,Two] and
> > [Four,Five]).
> > > >> I
> > > >> > > assume
> > > >> > > > > this is as designed because it actually offers quite powerful
> > > >> > > functionality
> > > >> > > > > to improve the parallelism in your build. An example of where
> > > >> this is
> > > >> > > legit
> > > >> > > > > is when:
> > > >> > > > >
> > > >> > > > >   *   “Four” has a test scope dependency on “Five”
> > > >> > > > >   *   “One” has a test scoped dependency on “Two”
> > > >> > > > > If you made a src code change to “Five” and “Two” then it
> > would be
> > > >> > > safe to
> > > >> > > > > build [One,Two] and [Four,Five] in parallel because you know
> > the
> > > >> > > changes
> > > >> > > > > within these graphs cannot impact each other.
> > > >> > > > > Joe
> > > >> > > > >
> > > >> > > > > On 2024/02/06 21:37:42 Tamás Cservenák wrote:
> > > >> > > > > > Howdy,
> > > >> > > > > >
> > > >> > > > > > To me this looks like Maven is not aware that the App
> > depends on
> > > >> > > > > ModuleB...
> > > >> > > > > > Are they "plain dependency" linked? Or what kind of
> > dependency
> > > >> we
> > > >> > > talk
> > > >> > > > > > about here?
> > > >> > > > > > In short: why would App start while ModuleB (upstream dep)
> > is
> > > >> not
> > > >> > > done?
> > > >> > > > > > Something is fishy here.
> > > >> > > > > >
> > > >> > > > > > T
> > > >> > > > > >
> > > >> > > > > >
> > > >> > > > > > On Tue, Feb 6, 2024 at 11:40 AM Joseph Leonard <
> > > >> > > > > > joseph.leon...@alfasystems.com> wrote:
> > > >> > > > > >
> > > >> > > > > > > Hi all,
> > > >> > > > > > >
> > > >> > > > > > > It would be great to get any thoughts on whether the
> > > >> following is a
> > > >> > > > > defect:
> > > >> > > > > > >
> > > >> > > > > > >
> > > >> > > > > > > Issue details:
> > > >> > > > > > > tl;dr
> > > >> > > > > > >
> > > >> > > > > > > Maven can resolve dependencies either from:
> > > >> > > > > > >
> > > >> > > > > > >   *   an external repo
> > > >> > > > > > >   *   a class directory of a module being built within the
> > > >> reactor
> > > >> > > > > > >   *   a packaged jar of a module being built within the
> > > >> reactor
> > > >> > > > > > >
> > > >> > > > > > > If you run a concurrent multi-module build it is possible
> > to
> > > >> get a
> > > >> > > race
> > > >> > > > > > > condition whereby the build of module Foo may resolve
> > module
> > > >> Bar
> > > >> > > from
> > > >> > > > > > > either of the three resolution channels. This
> > inconsistency
> > > >> can
> > > >> > > result
> > > >> > > > > in
> > > >> > > > > > > the Maven war plugin sometimes failing to build a
> > functional
> > > >> war
> > > >> > > file.
> > > >> > > > > I
> > > >> > > > > > > would expect a consistent resolution would always take
> > place.
> > > >> > > > > > >
> > > >> > > > > > > Full details
> > > >> > > > > > > Scenario
> > > >> > > > > > >
> > > >> > > > > > > Consider you have a repo with the following structure:
> > > >> > > > > > >
> > > >> > > > > > >                        App
> > > >> > > > > > >
> > > >> > > > > > >                      /     \
> > > >> > > > > > >
> > > >> > > > > > >                     /       \
> > > >> > > > > > >
> > > >> > > > > > >        (compile scope)      (test scope)
> > > >> > > > > > >
> > > >> > > > > > >                   /           \
> > > >> > > > > > >
> > > >> > > > > > >                 \/_           _\/
> > > >> > > > > > >
> > > >> > > > > > >              ModuleA      TestSupportModule1
> > > >> > > > > > >
> > > >> > > > > > >                 /
> > > >> > > > > > >
> > > >> > > > > > >                /
> > > >> > > > > > >
> > > >> > > > > > >     (compile scope)
> > > >> > > > > > >
> > > >> > > > > > >              /
> > > >> > > > > > >
> > > >> > > > > > >            \/_
> > > >> > > > > > >
> > > >> > > > > > >         ModuleB
> > > >> > > > > > >
> > > >> > > > > > >            /
> > > >> > > > > > >
> > > >> > > > > > >           /
> > > >> > > > > > >
> > > >> > > > > > >     (test scope)
> > > >> > > > > > >
> > > >> > > > > > >         /
> > > >> > > > > > >
> > > >> > > > > > >       \/_
> > > >> > > > > > >
> > > >> > > > > > > TestSupportModule2
> > > >> > > > > > >
> > > >> > > > > > > If you were to make a src code change to the following
> > test
> > > >> support
> > > >> > > > > > > modules:
> > > >> > > > > > >
> > > >> > > > > > >   *   TestSupportModule1
> > > >> > > > > > >   *   TestSupportModule2
> > > >> > > > > > >
> > > >> > > > > > > Then the minimum number of modules we need to build to
> > verify
> > > >> the
> > > >> > > > > change
> > > >> > > > > > > set is OK is:
> > > >> > > > > > >
> > > >> > > > > > >   *   TestSupportModule1
> > > >> > > > > > >   *   TestSupportModule2
> > > >> > > > > > >   *   ModuleB
> > > >> > > > > > >   *   App
> > > >> > > > > > >
> > > >> > > > > > > i.e. there is no requirement to build ModuleA because we
> > know
> > > >> that
> > > >> > > > > none of
> > > >> > > > > > > the src code changes could impact the classpaths used in
> > its
> > > >> maven
> > > >> > > > > build.
> > > >> > > > > > >
> > > >> > > > > > > We know that despite 'App' depending (transitively) on
> > ModuleB
> > > >> > > there
> > > >> > > > > is no
> > > >> > > > > > > need for the 'App' build to wait for ModuleB to complete
> > its
> > > >> build
> > > >> > > > > because
> > > >> > > > > > > the src code change to TestSupportModule2 will not impact
> > any
> > > >> of
> > > >> > > the
> > > >> > > > > > > classpaths used in the App maven build. Therefore to get
> > the
> > > >> most
> > > >> > > > > efficient
> > > >> > > > > > > build possible we ideally would invoke Maven to run with 2
> > > >> threads
> > > >> > > and
> > > >> > > > > with
> > > >> > > > > > > instruction to build two distinct 'dependency graphs':
> > > >> > > > > > >
> > > >> > > > > > >   *   TestSupportModule1 followed by ModuleB
> > > >> > > > > > >   *   TestSupportModule1 followed by App
> > > >> > > > > > >
> > > >> > > > > > > The following Maven command achieves exactly what we want
> > > >> because
> > > >> > > the
> > > >> > > > > > > reactor build order is based only on the direct (i.e.
> > > >> > > non-transitive)
> > > >> > > > > > > dependencies of the modules provided to the reactor in the
> > > >> build
> > > >> > > > > command.
> > > >> > > > > > > Therefore the absence of ModuleA results in two distinct
> > > >> > > 'dependency
> > > >> > > > > > > graphs':
> > > >> > > > > > >
> > > >> > > > > > > mvn clean verify -pl
> > > >> > > TestSupportModule1,TestSupportModule2,ModuleB,App
> > > >> > > > > -T 2
> > > >> > > > > > >
> > > >> > > > > > > Note: In reality the code base I maintain has a very large
> > > >> > > monobuild
> > > >> > > > > with
> > > >> > > > > > > 100s of modules and this type of build optimisation makes
> > a
> > > >> > > significant
> > > >> > > > > > > difference to the speed of our monobuild (we use
> > > >> > > > > > >
> > > >> > > > >
> > > >> > >
> > > >>
> > https://github.com/gitflow-incremental-builder/gitflow-incremental-builder
> > > >> > > > > > > to automate the logic of determining which modules to
> > include
> > > >> in
> > > >> > > the
> > > >> > > > > > > reactor based on our change set).
> > > >> > > > > > >
> > > >> > > > > > > Issue
> > > >> > > > > > >
> > > >> > > > > > > We have encountered an issue in the above scenario
> > because the
> > > >> > > 'App'
> > > >> > > > > build
> > > >> > > > > > > has a race condition with the ModuleB build which will
> > result
> > > >> in
> > > >> > > one
> > > >> > > > > of the
> > > >> > > > > > > following three outcomes:
> > > >> > > > > > >
> > > >> > > > > > >   *   If the 'App' build starts before the ModuleB build
> > has
> > > >> > > compiled
> > > >> > > > > its
> > > >> > > > > > > src classes then the 'App' build will resolve ModuleB
> > from the
> > > >> > > external
> > > >> > > > > > > repo (i.e. equivalent to ModuleB not being in the reactor
> > at
> > > >> all)
> > > >> > > > > > >   *   If the 'App' build starts after ModuleB has compiled
> > > >> its src
> > > >> > > > > classes
> > > >> > > > > > > but before it has packaged these classes into a jar then
> > the
> > > >> 'App'
> > > >> > > > > build
> > > >> > > > > > > will resolve ModuleB's target/classes directory
> > > >> > > > > > >   *   If the 'App' build starts after ModuleB has packaged
> > > >> its jar
> > > >> > > file
> > > >> > > > > > > then the 'App' build will resolve ModuleB's
> > target/ModuleB.jar
> > > >> > > file.
> > > >> > > > > > >
> > > >> > > > > > > In many scenarios this dependency resolution inconsistency
> > > >> doesn't
> > > >> > > > > > > represent a challenge. However, it does cause an issue in
> > our
> > > >> case
> > > >> > > > > because
> > > >> > > > > > > the 'App' POM has its Maven packaging stanza configured to
> > > >> war and
> > > >> > > in
> > > >> > > > > the
> > > >> > > > > > > scenario where ModuleB's target/classes directory is
> > resolved
> > > >> by
> > > >> > > the
> > > >> > > > > 'App'
> > > >> > > > > > > then this results in the resultant 'App' war file being
> > > >> packaged
> > > >> > > with a
> > > >> > > > > > > completely empty ModuleB.jar file.
> > > >> > > > > > >
> > > >> > > > > > > Proposed solution
> > > >> > > > > > >
> > > >> > > > > > > Ideally we would like the Maven reactor to retain
> > isolation
> > > >> > > between the
> > > >> > > > > > > two distinct 'dependency graphs' it constructs at
> > > >> instantiation
> > > >> > > > > throughout
> > > >> > > > > > > the entire Maven build. This would mean, in the simple
> > example
> > > >> > > above,
> > > >> > > > > that
> > > >> > > > > > > the 'App' would always resolves ModuleB from the external
> > repo
> > > >> > > > > (regardless
>
[message truncated...]

Reply via email to