apache / apache/grails-core

CLI command task discovery: configuration-cache compatibility and resolution scoping

Open
#16,008 0 comments 0 reactions 0 assignees View on GitHub
breaking-change design-required
Dominant language
Groovy
Stars
2.9k
Forks
975
Avg merge
1d 22h
Merged PRs (30d)
92

Description

## Context

Follow-up from the CLI dependency split (#15948, review thread: https://github.com/apache/grails-core/pull/15948#discussion_r3605219281).

Per-command Gradle tasks (`dbmUpdate`, `generate-*`, ...) are registered from command names discovered in the `META-INF/grails-cli.factories` files of resolved `grailsCliClasspath` jars. Gradle requires task names to exist when the task graph is assembled, so this discovery currently resolves the CLI dependency graph at configuration time — every invocation pays it (including `./gradlew help`), and Grails does not yet support the configuration cache, so the cost is never amortized.

There is no Gradle API for lazily-materialized task *names*: dynamically named tasks that are visible in `gradle tasks`/IDE sync require configuration-time resolution. The work below reduces or amortizes the cost within that constraint.

## Tactical follow-ups

1. **Configuration-cache compatibility for the CLI plugins.** Configuration-time resolution is supported under CC (the resolved result is serialized into the cache entry), so CC effectively becomes the caching mechanism: discovery is paid once and replayed until inputs change. The blockers in the current code are incidental rather than structural — cross-project `findProject` access during companion discovery, `Project` captures in task closures. Clean these up and add a `--configuration-cache` functional test to lock it in.
2. **Scope the resolution cost.** Cache the manifest/factories scan per resolved artifact set so jars are not re-opened repeatedly within a single invocation.
3. **Optional task-rule mode.** A `tasks.addRule`-based mode would defer discovery until an unmatched task name is actually requested, making unrelated builds pay nothing — at the cost of per-command tasks no longer being listed individually in `gradle tasks`/IDE task views. Consider offering it behind a flag for build-speed-sensitive projects, keeping eager registration (discoverability) as the default.

## Strategic note

Much of this complexity exists because commands are surfaced as Gradle tasks. A fuller separation — tracking dependencies in `grailsCli` but resolving/using them in the Grails CLI itself — would decouple the build system from the CLI system entirely, but that is a redesign tied to the unresolved profile/forge restructuring discussion and is explicitly out of scope here. See the PR thread for details.

Contributor guide

Open the contributing guide

Research direction

Start with the CLI plugin code that registers per-command Gradle tasks and scans META-INF/grails-cli.factories from resolved grailsCliClasspath jars. Trace companion discovery and task closures, then run the existing functional tests while adding a --configuration-cache case. Done means configuration-cache compatibility, one manifest scan per resolved artifact set, and a clearly decided approach for optional task-rule mode.

Written by the indexing model from the issue text.

Assessment

Tech stack
groovy
Domain
build-system, cli
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.