Skip to content

Commit 22ef7ca

Browse files
committed
Add plugin spec metadata generation
Signed-off-by: Paolo Di Tommaso <[email protected]>
1 parent 82ec31b commit 22ef7ca

File tree

5 files changed

+636
-0
lines changed

5 files changed

+636
-0
lines changed

CONFIG_METADATA.md

Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
# Config Metadata Generation
2+
3+
## Overview
4+
5+
The `nextflow-plugin-gradle` plugin provides automatic generation of JSON metadata from configuration classes annotated with `@Description`, `@ConfigOption`, and `@ScopeName` annotations. This metadata enables IDE autocomplete, validation, and documentation tooling for Nextflow plugin configuration options.
6+
7+
## How It Works
8+
9+
The `ConfigMetadataTask` uses runtime reflection to scan compiled Groovy/Java classes that implement the `ConfigScope` interface and extract annotation metadata. The task:
10+
11+
1. Loads compiled classes from the plugin's classpath
12+
2. Scans specified packages for classes implementing `ConfigScope`
13+
3. Extracts `@ScopeName`, `@Description`, and `@ConfigOption` annotations
14+
4. Generates a schema-compliant JSON file at `build/generated/resources/META-INF/plugin.json`
15+
5. Includes the JSON file in the plugin JAR automatically
16+
17+
### Why Not Annotation Processors?
18+
19+
This implementation uses a Gradle task with runtime reflection instead of Java annotation processors because:
20+
21+
- **Groovy Compatibility**: Annotation processors don't reliably work with Groovy's joint compilation
22+
- **Runtime Annotations**: Existing annotations use `@Retention(RUNTIME)`, which aren't visible to annotation processors
23+
- **Simplicity**: Gradle task approach is easier to debug and maintain
24+
- **No Breaking Changes**: Works with existing annotation definitions
25+
26+
## Usage
27+
28+
### Basic Setup
29+
30+
In your plugin's `build.gradle`:
31+
32+
```groovy
33+
plugins {
34+
id 'io.nextflow.nextflow-plugin' version '1.0.0-beta.11'
35+
}
36+
37+
nextflowPlugin {
38+
// ... other plugin configuration ...
39+
40+
// Enable config metadata generation
41+
configPackages = ['your.plugin.config.package']
42+
}
43+
```
44+
45+
### Configuration Options
46+
47+
#### `configPackages` (optional)
48+
49+
List of package names to scan for configuration classes.
50+
51+
```groovy
52+
nextflowPlugin {
53+
// Scan specific packages
54+
configPackages = ['nextflow.cloud.aws.config', 'nextflow.cloud.aws.batch']
55+
56+
// Or scan all packages (leave empty or omit)
57+
configPackages = []
58+
}
59+
```
60+
61+
**Default behavior:** If `configPackages` is empty or not specified, all compiled classes will be scanned.
62+
63+
## Annotations
64+
65+
### Required Annotations
66+
67+
Your configuration classes must use these annotations:
68+
69+
#### `@ConfigScope` Interface
70+
71+
Marker interface that identifies a class as a configuration scope:
72+
73+
```groovy
74+
import nextflow.config.schema.ConfigScope
75+
76+
class AwsConfig implements ConfigScope {
77+
// ...
78+
}
79+
```
80+
81+
#### `@ScopeName` (optional)
82+
83+
Defines the configuration scope name:
84+
85+
```groovy
86+
import nextflow.config.schema.ScopeName
87+
88+
@ScopeName("aws")
89+
class AwsConfig implements ConfigScope {
90+
// ...
91+
}
92+
```
93+
94+
#### `@Description` (optional)
95+
96+
Documents configuration scopes and options:
97+
98+
```groovy
99+
import nextflow.script.dsl.Description
100+
101+
@Description("""
102+
The `aws` scope controls interactions with AWS.
103+
""")
104+
class AwsConfig implements ConfigScope {
105+
106+
@ConfigOption
107+
@Description("""
108+
AWS region (e.g. `us-east-1`).
109+
""")
110+
String region
111+
}
112+
```
113+
114+
#### `@ConfigOption` (required for fields)
115+
116+
Marks a field as a configuration option:
117+
118+
```groovy
119+
import nextflow.config.schema.ConfigOption
120+
121+
@ConfigOption
122+
String region
123+
124+
@ConfigOption
125+
Integer maxConnections
126+
```
127+
128+
## Output Format
129+
130+
The generated `META-INF/plugin.json` conforms to the [Nextflow plugin schema v1](https://raw.githubusercontent.com/nextflow-io/schemas/main/plugin/v1/schema.json).
131+
132+
### Example Output
133+
134+
```json
135+
{
136+
"definitions": [
137+
{
138+
"type": "ConfigScope",
139+
"spec": {
140+
"name": "aws",
141+
"description": "The `aws` scope controls interactions with AWS.",
142+
"children": [
143+
{
144+
"type": "ConfigOption",
145+
"spec": {
146+
"name": "region",
147+
"type": "String",
148+
"description": "AWS region (e.g. `us-east-1`)."
149+
}
150+
},
151+
{
152+
"type": "ConfigOption",
153+
"spec": {
154+
"name": "maxConnections",
155+
"type": "Integer",
156+
"description": "Maximum number of connections."
157+
}
158+
}
159+
]
160+
}
161+
}
162+
]
163+
}
164+
```
165+
166+
### Schema Structure
167+
168+
- **`definitions`**: Array of configuration scopes
169+
- **`type`**: Always `"ConfigScope"` for scope definitions
170+
- **`spec.name`**: Scope name from `@ScopeName` (optional)
171+
- **`spec.description`**: Scope description from `@Description` (optional)
172+
- **`spec.children`**: Array of configuration options
173+
- **`type`**: Always `"ConfigOption"` for option definitions
174+
- **`spec.name`**: Field name
175+
- **`spec.type`**: Java type name (e.g., `String`, `Integer`, `Boolean`)
176+
- **`spec.description`**: Option description from `@Description` (optional)
177+
178+
## Build Integration
179+
180+
### Task Dependencies
181+
182+
The `configMetadata` task:
183+
- Depends on `compileGroovy` (runs after compilation)
184+
- Is a dependency of `jar` (runs before JAR packaging)
185+
- Outputs to `build/generated/resources/META-INF/plugin.json`
186+
187+
### Generated Resources
188+
189+
The generated JSON file is automatically included in the plugin JAR:
190+
191+
```
192+
plugin.jar
193+
└── META-INF/
194+
└── plugin.json
195+
```
196+
197+
### Manual Task Execution
198+
199+
To generate metadata without building the entire plugin:
200+
201+
```bash
202+
./gradlew configMetadata
203+
```
204+
205+
To force regeneration:
206+
207+
```bash
208+
./gradlew configMetadata --rerun-tasks
209+
```
210+
211+
## Complete Example
212+
213+
### Configuration Class
214+
215+
```groovy
216+
package nextflow.cloud.aws.config
217+
218+
import nextflow.config.schema.ConfigOption
219+
import nextflow.config.schema.ConfigScope
220+
import nextflow.config.schema.ScopeName
221+
import nextflow.script.dsl.Description
222+
223+
@ScopeName("aws")
224+
@Description("""
225+
The `aws` scope controls interactions with AWS, including AWS Batch and S3.
226+
""")
227+
class AwsConfig implements ConfigScope {
228+
229+
@ConfigOption
230+
@Description("""
231+
AWS region (e.g. `us-east-1`).
232+
""")
233+
String region
234+
235+
@ConfigOption
236+
@Description("""
237+
AWS account access key.
238+
""")
239+
String accessKey
240+
241+
@ConfigOption
242+
@Description("""
243+
AWS account secret key.
244+
""")
245+
String secretKey
246+
}
247+
```
248+
249+
### Plugin Build Configuration
250+
251+
```groovy
252+
plugins {
253+
id 'io.nextflow.nextflow-plugin' version '1.0.0-beta.11'
254+
}
255+
256+
nextflowPlugin {
257+
nextflowVersion = '25.08.0-edge'
258+
provider = 'Your Name'
259+
description = 'AWS cloud integration plugin'
260+
className = 'nextflow.cloud.aws.AwsPlugin'
261+
262+
// Enable config metadata generation
263+
configPackages = ['nextflow.cloud.aws.config']
264+
}
265+
```
266+
267+
### Build and Verify
268+
269+
```bash
270+
# Build the plugin
271+
./gradlew build
272+
273+
# Verify generated metadata
274+
cat build/generated/resources/META-INF/plugin.json
275+
276+
# Verify it's included in JAR
277+
jar tf build/libs/your-plugin.jar | grep plugin.json
278+
```
279+
280+
## Troubleshooting
281+
282+
### No Metadata Generated
283+
284+
**Problem:** Task runs but generates empty `definitions` array.
285+
286+
**Solutions:**
287+
1. Ensure `configPackages` includes the correct package names
288+
2. Verify config classes implement `ConfigScope` interface
289+
3. Check that classes are compiled (run `compileGroovy` first)
290+
4. Enable debug logging: `./gradlew configMetadata --debug`
291+
292+
### Classes Not Found
293+
294+
**Problem:** `ClassNotFoundException` or `NoClassDefFoundError` in logs.
295+
296+
**Solutions:**
297+
1. Ensure all dependencies are available at compile time
298+
2. Check that annotation classes are in `compileOnly` dependencies
299+
3. Verify classpath includes both `classesDirs` and `compileClasspath`
300+
301+
### Groovy Method Dispatch Errors
302+
303+
**Problem:** `Could not find method` errors during task execution.
304+
305+
**Cause:** Groovy's dynamic method dispatch doesn't work across classloaders.
306+
307+
**Solution:** The task already handles this by inlining all method calls and using `invokeMethod()` for annotation value access. If you see this error, report it as a bug.
308+
309+
### Annotations Not Visible
310+
311+
**Problem:** `@Description` or `@ConfigOption` values are null or missing.
312+
313+
**Solutions:**
314+
1. Verify annotations have `@Retention(RetentionPolicy.RUNTIME)`
315+
2. Check annotation imports are correct
316+
3. Ensure annotations are on the correct elements (TYPE, FIELD)
317+
318+
## Advanced Usage
319+
320+
### Custom Output Location
321+
322+
The output file location is configurable via task properties:
323+
324+
```groovy
325+
tasks.named('configMetadata') {
326+
outputFile = layout.buildDirectory.file('custom/path/metadata.json')
327+
}
328+
```
329+
330+
### Additional Processing
331+
332+
To post-process the generated JSON:
333+
334+
```groovy
335+
tasks.register('validateMetadata') {
336+
dependsOn configMetadata
337+
338+
doLast {
339+
def json = file('build/generated/resources/META-INF/plugin.json')
340+
// Validate against schema, generate TypeScript definitions, etc.
341+
}
342+
}
343+
```
344+
345+
## Related Documentation
346+
347+
- [Nextflow Plugin Schema v1](https://raw.githubusercontent.com/nextflow-io/schemas/main/plugin/v1/schema.json)
348+
- [Nextflow Plugin Development Guide](https://www.nextflow.io/docs/latest/plugins.html)
349+
- [nf-amazon Example](https://github.com/nextflow-io/nextflow/tree/master/plugins/nf-amazon) - Reference implementation
350+
351+
## Version History
352+
353+
- **1.0.0-beta.11** (Oct 2025)
354+
- Initial release of config metadata generation
355+
- Schema-compliant JSON output
356+
- Support for @Description, @ConfigOption, @ScopeName annotations

changelog.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
1.0.0-beta.11 - 9 Oct 2025
2+
- Add ConfigMetadataTask to generate schema-compliant JSON metadata from @Description annotations
3+
- Add configPackages configuration option to NextflowPluginConfig
4+
- Automatically generate and include configuration metadata in plugin JARs as META-INF/plugin.json
5+
- Support for @Description, @ConfigOption, and @ScopeName annotations
6+
- Generated JSON conforms to Nextflow plugin schema v1
7+
18
1.0.0-beta.10 - 8 Oct 2025
29
- Add CLAUDE.md documentation for AI-assisted development
310
- Update RegistryClient to use JSON POST for createRelease endpoint

0 commit comments

Comments
 (0)