Skip to content

Latest commit

 

History

History
200 lines (152 loc) · 11.5 KB

File metadata and controls

200 lines (152 loc) · 11.5 KB

AGENTS.md - export

Project Overview

This is a Grails Plugin that adds export functionality supporting different formats e.g. CSV, Excel (xls, xlsx), Open Document Spreadsheet, PDF and XML and can be extended to add additional formats.

  • Language: Groovy 4.0.30 on Java 17
  • Framework: Grails 7.x
  • Build System: Gradle 8.14.4 (with wrapper)
  • Current Version: 7.0.x-SNAPSHOT
  • License: Apache 2.0

Skill Files (Best Practices)

Detailed best practices are documented in .skills/:

Skill File Purpose
.skills/repository-structure.md Canonical directory layout and architectural rules
.skills/gradle-best-practices.md Gradle best practices, convention plugins, and idioms
.skills/plugin-project.md Plugin project scope: source code + unit tests only
.skills/example-apps.md Example app patterns: integration & functional tests

Read these skill files before making structural changes to the repository.

Critical Rules

  1. NEVER add code to the root build.gradle to configure subprojects. No subprojects {}, allprojects {}, or configure() blocks. All shared configuration goes through convention plugins in build-logic/.
  2. The plugin project contains ONLY plugin code and unit tests. No integration tests, no functional tests, no example controllers or views.
  3. Example apps under examples/ host all integration and functional tests. They depend on the plugin via implementation project(':grails-export') and test it as a real consumer would.
  4. Use Gradle convention plugins to deduplicate. If two or more subprojects share build logic, extract it into a convention plugin in build-logic/.
  5. Always use lazy Gradle APIs to avoid eager initialization (tasks.register(), tasks.named(), configureEach, provider {}).

Repository Structure

export/
├── .skills/             # Best practice skill files
├── plugin/              # Core Grails plugin (artifact: grails-export)
│   ├── grails-app/      #   Plugin services, taglibs, and conf
│   └── src/main/        #   Plugin source code (exporters, builder, etc.)
├── examples/app1/       # Example Grails app
│   └── grails-app/      #   Controllers and conf for integration testing
├── docs/                # Asciidoctor documentation
├── build-logic/         # Gradle convention plugins (composite build)
├── .github/workflows/   # CI, release, and release-notes workflows
├── build.gradle         # Root build file (docs + root-publish ONLY)
├── settings.gradle      # Multi-project settings
└── gradle.properties    # Version properties

Build and Test Commands

# Full build (compile + test)
./gradlew build

# Run only unit tests (plugin module)
./gradlew :grails-export:test

# Run integration tests (example app)
./gradlew :app1:integrationTest

# Skip tests
./gradlew build -PskipTests

# Run the example app
./gradlew :app1:bootRun

# Generate documentation
./gradlew docs

# Clean build
./gradlew clean build

# Run code style checks only
./gradlew codeStyle

# Skip code style checks
./gradlew build -PskipCodeStyle

SDK Requirements

Use SDKMAN to install the correct tool versions (see .sdkmanrc):

  • Java: 17.0.18-librca
  • Gradle: 8.14.4
  • Groovy: 4.0.30

Run sdk env install to set up the environment.

Architecture

The plugin provides a service-oriented export mechanism with a tag library for UI integration:

  1. ExportGrailsPlugin registers the exporterFactory Spring bean on startup, and loads any custom exporter classes declared in application.groovy under the exporters key.
  2. ExportService is the main entry point for application code. It accepts a format type, output stream (or HTTP response), data list, field list, label map, formatter map, and parameter map. It delegates to exporterFactory to obtain the correct Exporter and calls export().
  3. ExporterFactory / DefaultExporterFactory resolves an Exporter implementation by format string (e.g. "csv", "excel", "pdf") and configures it with the supplied fields, labels, formatters, and parameters.
  4. Exporter interface / AbstractExporter — Base contract and shared logic for all format exporters.
  5. ExportTagLib exposes <export:formats /> (renders an export button bar) and <export:resource /> (renders the CSS <link>) for use in GSP views.

Core Classes

Class / Interface Location Purpose
ExportGrailsPlugin plugin/src/main/groovy/grails/plugins/export/ Plugin descriptor; registers beans and custom exporters
ExportService plugin/grails-app/services/grails/plugins/export/ Main service; sets response headers, delegates to exporter
ExportTagLib plugin/grails-app/taglib/grails/plugins/export/ Tag library: export:formats, export:resource
ExporterFactory / DefaultExporterFactory plugin/src/main/groovy/grails/plugins/export/exporter/ Creates Exporter instances by type string
Exporter / AbstractExporter plugin/src/main/groovy/grails/plugins/export/exporter/ Exporter interface and shared base class
DefaultCSVExporter plugin/src/main/groovy/grails/plugins/export/exporter/ Exports data as CSV
DefaultExcelExporter plugin/src/main/groovy/grails/plugins/export/exporter/ Exports data as Excel (xls / xlsx) via ExcelBuilder
DefaultODSExporter plugin/src/main/groovy/grails/plugins/export/exporter/ Exports data as ODS (Open Document Spreadsheet)
DefaultPDFExporter plugin/src/main/groovy/grails/plugins/export/exporter/ Exports data as PDF
DefaultRTFExporter plugin/src/main/groovy/grails/plugins/export/exporter/ Exports data as RTF
DefaultXMLExporter plugin/src/main/groovy/grails/plugins/export/exporter/ Exports data as XML
ExcelBuilder plugin/src/main/groovy/grails/plugins/export/builder/ Helper for constructing Excel workbooks
ExporterUtil plugin/src/main/groovy/grails/plugins/export/exporter/ Utility methods for exporters
RenderUtils plugin/src/main/groovy/grails/plugins/export/taglib/util/ Utility methods for tag library resource path resolution
ExportingException / ExporterNotFoundException plugin/src/main/groovy/grails/plugins/export/exporter/ Export error types

Configuration

Custom exporters can be registered in application.groovy (or equivalent):

exporters {
    myformat = "com.example.export.MyCustomExporter"
}

An existing exporter class can be overridden by setting export.<type> to a replacement class name.

MIME types for the built-in formats must be declared in grails.mime.types (application config):

Format key Typical MIME type
csv text/csv
excel application/vnd.ms-excel
ods application/vnd.oasis.opendocument.spreadsheet
pdf application/pdf
rtf application/rtf
xml text/xml

Testing

Unit Tests (plugin/src/test/)

Unit tests use the Spock Framework and run on JUnit Platform.

Integration / Functional Tests (examples/app1/)

The TestController in the example app exercises ExportService with real format requests. Integration and functional tests added here depend on the plugin as a real consumer would.

Build-Logic Convention Plugins

Convention plugins in build-logic/src/main/groovy/ standardize build configuration:

Plugin Purpose
app-run.gradle Debug flags for bootRun
compile.gradle Java/Groovy compilation settings (UTF-8, incremental, Java release from .sdkmanrc)
docs.gradle Documentation aggregation (Groovydoc + Asciidoctor)
example-app.gradle Example app config (grails-web, GSP, assets)
grails-assets.gradle Asset pipeline with Bootstrap/jQuery WebJars
grails-plugin.gradle Grails plugin application
publish.gradle Per-project Maven publishing metadata
publish-root.gradle Root-level Nexus publishing workaround
testing.gradle Test framework config (Spock, JUnit Platform, test-logger)

CI/CD

  • CI (.github/workflows/ci.yml): Builds and tests on push/PR; publishes snapshots to Maven Central Snapshots on push to release branches.
  • Release (.github/workflows/release.yml): 4-stage pipeline triggered by GitHub release — stage artifacts, release to Maven Central, publish docs to GitHub Pages, bump version.
  • Release Notes (.github/workflows/release-notes.yml): Auto-drafts release notes using release-drafter with category labels.

Code Conventions

  • Groovy source files use standard Grails conventions (services and taglibs in grails-app/, other classes in src/main/groovy/).
  • Use def for local variables where the type is inferred from the right-hand side (e.g., constructor calls, method calls, casts, factory methods). Explicit types should only be used for local variables when the type cannot be inferred or when needed for @CompileStatic compilation. This applies to both production code and tests.
  • When writing Gradle, always use the latest best practices to avoid eager initialization.