The GitHub Actions job "CI" on grails-core.git/8.0.x has failed.
Run started by GitHub user borinquenkid (triggered by borinquenkid).

Head commit for run:
3d3f4bbcff0314b3295f60e3432445318ceab032 / Scott Murphy <[email protected]>
Register a generated auto-configuration where it is generated (#16224)

* Register a generated auto-configuration where it is generated

The class a beans closure compiles to is created during compilation and is not a
source file anyone can open, so listing it in AutoConfiguration.imports required
knowing both that it exists and what the compiler decided to call it. Not 
knowing
either produced a plugin whose beans were silently never registered, which is a
poor thing to ask an author to notice.

The name is settled in createAutoConfigurationSibling and nowhere else, so that 
is
where the entry is now written - into the compilation's target directory, beside
the grails-plugin.xml and grails.factories that are already generated there.

A module that keeps the file by hand keeps it, and nothing is generated beside 
it:
two copies of one resource cannot both go into the jar, and folding the hand
authored entries into a copy under the build directory would lose them as soon 
as
anyone deleted the file they were written in. Such a module is warned at compile
time when the generated class is missing from its file, so the silent case is 
gone
either way, and deleting the file is what opts in. Hand-authored entries have to
stay possible: a class from another jar, one annotated with a composed 
annotation,
or one carrying no annotation at all - the imports file being the registration 
and
@AutoConfiguration only supplying ordering.

grails-databinding and the beans-dsl-plugin example no longer apply the
autoconfiguration-imports convention plugin, which generated the same entries a
second time. The beans-dsl example keeps it: what it registers is a standalone
@GrailsBeans class, which is a source file its author can see and so is left to 
be
registered by hand, as any other auto-configuration is.

* Drop an entry for a class that is no longer generated

The file was only ever added to. A descriptor that was renamed, deleted, or 
given
a different autoConfigurationName left an entry naming a class that no longer
exists, and Spring Boot does not start on an auto-configuration it cannot load.
An incremental build is where this shows: the stale class file is cleaned and 
the
entry that named it is not.

An entry is now kept only while the class it names is still generated into the
module's own output, which is what the scanning task this replaced recalculated
every time. Anything the current compilation registered is kept regardless, 
since
class generation runs in a later phase than this does - without that, two
descriptors rebuilt together would each prune the other, neither class file 
having
been written yet. The set is weakly keyed on the compilation, so it is per-build
rather than per-JVM in a daemon that reuses one.

The specification now compiles through to OUTPUT rather than stopping at
CLASS_GENERATION. Stopping earlier wrote no class files at all, so the output
directory it asserts against was empty and could not have shown any of this.

* Drop the entry when nothing is left to generate the class

Pruning ran only while writing, and writing happens only when a class is
generated. A descriptor deleted outright, or left with no beans closure or an
empty one, generates nothing and so said nothing about the entry naming the 
class
it used to generate - a build that removed the class kept the entry, and Spring
Boot does not start on an auto-configuration it cannot load. The rename covered
before only passed because the class replacing it did the writing.

Reconciling is now something the compilation does rather than something 
generating
a class does: the global Grails transform, which runs for every source unit of a
project and already writes generated metadata to the same directory, drops 
entries
whose classes are no longer generated there. Names registered by the 
compilation in
hand are kept, their class files being written in a later phase than any of this
runs in.

The file is deleted rather than left empty when the last entry goes, an imports
file with nothing in it being a resource that says nothing.

* Fix generated auto-configuration registration lifecycle

* Persist a write that only drops a stale entry, and warn once

Two things register the same descriptor in a standard compilation - the local
transform, and the global one from the node metadata it leaves - and neither
consequence of that was handled.

Comparing the set about to be written against the pruned set rather than against
what was on disk meant a call that only dropped a stale entry appeared to change
nothing and wrote nothing, leaving on disk the entry it had just decided was
naming a class that no longer exists. It is compared against the file's own
contents now, which also makes the className check that followed it redundant.

The missing hand-authored entry was reported by both, so one entry to add read 
as
two problems. The warning is gated on the name not already having been 
registered
by this compilation.

Also restores the coverage for a descriptor that is named like one but does not
extend Plugin: its closure is still compiled, onto the class itself, and nothing
is registered for it - which is what pins the scope to the sibling generated 
for a
plugin descriptor.

* Reach the beans transform the way the registering already does

compileBeansDsl loaded GrailsBeansASTTransformation reflectively and returned
quietly if it was absent, while the registering a few lines above referenced 
that
class and the imports writer directly. Only one of those can be describing the
class path truthfully.

It is the direct one: grails-core declares grails-beans-dsl api, which is what 
the
guard's own comment gave as the reason the branch could never be taken. Left as 
it
was, the guard caught a condition that the next statement would have failed on
anyway.

* Register the sibling under Groovy-Eclipse too

A descriptor carrying @GrailsBeans explicitly was registered by neither path
there. The local transform skipped its own write, the compiler configuration
holding no directory it could trust; the global transform registers from node
metadata, and the metadata is not set yet when it runs - the local transform is
what sets it, and for an annotated descriptor that happens afterwards. Only the
convention path, where the global transform compiles the closure itself, was
covered.

The global transform now seeds the directory it resolved onto every class of the
source unit before anything is transformed, and the local transform prefers it
over the compiler's own. That is the Eclipse resolution being passed in rather
than reached for: it lives in grails-core, which grails-beans-dsl cannot depend
on. With a directory it can trust, the local transform no longer skips.

* Register the sibling once, where its name is settled

The global transform registered from the node metadata the local transform 
leaves
behind, which was the only way the name reached a directory resolved for
Groovy-Eclipse. Seeding that directory the other way round, so the local 
transform
writes to it, leaves this reading metadata that either was written moments 
earlier
by a call that has already registered the same name, or - for a descriptor
carrying @GrailsBeans, compiled after this runs - is not there at all. Neither
case registers anything the local transform has not.

Removing it is what the duplicate reporting fixed earlier came from, so that 
guard
is now defence rather than the thing standing between one entry to add and two
reports of it.

Reconciling stays: it is not about a class being generated, but about entries 
for
classes that are not.

* Stop guarding a duplicate that one call site cannot produce

Registering happens in exactly one place now, so the same name cannot reach the
hand-authored branch twice in a compilation and the gate against that reported 
on
nothing. Its specification passed with the gate taken out, which is the worse 
half
of keeping it: a test that cannot fail reads as cover for a branch nobody is
holding.

What is left there is worth asserting, so the specification keeps the case and
drops the claim about counting - a hand-authored file missing the generated 
class
is told which name to add, and no second file is generated beside it. That one
fails when the warning is removed.

* Drop the metadata nothing reads, and cover the annotated entry path

The generated name was put on the class node for the global transform to read,
and the global transform no longer reads anything: the write and the constant
were the only references left, and the constant still described carrying a name
somewhere that stopped asking for it.

The specification also only reached the sibling through the convention, where 
the
global transform compiles the closure itself. A descriptor carrying the 
annotation
takes the other entry path - the local transform runs after this one and writes 
to
the directory seeded for it - and that path registering nothing is exactly what
went unnoticed before. It is covered now, and fails when the registering is 
taken
away from it.

Also removes a duplicate import of SourceUnit that codeStyle does not object to.

Report URL: https://github.com/apache/grails-core/actions/runs/33576592901

With regards,
GitHub Actions via GitBox

Reply via email to