diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index fdd38446fc..ec117017ac 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -43,5 +43,9 @@ gradlePlugin { id = "linea.solc-toolchain" implementationClass = "SolcToolchainPlugin" } + create("ConfigDocsPlugin") { + id = "linea.config-docs" + implementationClass = "ConfigDocsPlugin" + } } } diff --git a/buildSrc/src/main/groovy/ConfigDocsExtension.groovy b/buildSrc/src/main/groovy/ConfigDocsExtension.groovy new file mode 100644 index 0000000000..3375d39e5a --- /dev/null +++ b/buildSrc/src/main/groovy/ConfigDocsExtension.groovy @@ -0,0 +1,10 @@ +/** + * Configuration for the {@code linea.config-docs} convention plugin. + */ +class ConfigDocsExtension { + /** + * Fully-qualified name of the app's {@code linea.config.docs.ConfigDocsSpec} implementation + * (a Kotlin object), e.g. {@code "linea.coordinator.config.v2.docs.CoordinatorConfigDocsSpec"}. + */ + String spec +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/ConfigDocsPlugin.groovy b/buildSrc/src/main/groovy/ConfigDocsPlugin.groovy new file mode 100644 index 0000000000..c790dbeb6e --- /dev/null +++ b/buildSrc/src/main/groovy/ConfigDocsPlugin.groovy @@ -0,0 +1,62 @@ +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.JavaExec +import org.gradle.api.tasks.SourceSetContainer + +/** + * Wires the config-documentation check/generate tasks for an application module. + * + * Creates a dedicated {@code configDocs} source set (compiled against {@code main} plus the + * {@code jvm-libs:linea:config-docs} engine, and kept out of the production jar), and registers + * {@code checkConfigDocs} and {@code generateConfigDocs} tasks that run the engine's generic entry + * points against the app's {@code ConfigDocsSpec}. + * + * Apply after the Kotlin/application conventions plugin and configure the spec: + *
+ * plugins { id 'net.consensys.zkevm.kotlin-application-conventions'; id 'linea.config-docs' }
+ * configDocs { spec = "com.example.MyConfigDocsSpec" }
+ * 
+ */ +class ConfigDocsPlugin implements Plugin { + @Override + void apply(Project project) { + def extension = project.extensions.create('configDocs', ConfigDocsExtension) + + def sourceSets = project.extensions.getByType(SourceSetContainer) + def main = sourceSets.getByName('main') + def configDocs = sourceSets.create('configDocs') + configDocs.compileClasspath += main.output + main.compileClasspath + configDocs.runtimeClasspath += main.output + main.runtimeClasspath + + // Build-time only tooling engine; kept off the production runtime classpath. + project.dependencies.add( + 'configDocsImplementation', + project.project(':jvm-libs:linea:config-docs')) + + def specProvider = project.provider { + def spec = extension.spec + if (!spec) { + throw new IllegalStateException( + "configDocs.spec must be set to the fully-qualified ConfigDocsSpec class name") + } + spec + } + + project.tasks.register('checkConfigDocs', JavaExec) { + it.group = 'verification' + it.description = 'Verifies that every config key is documented.' + it.classpath = configDocs.runtimeClasspath + it.mainClass.set('linea.config.docs.ConfigDocsCheckMain') + it.argumentProviders.add({ [specProvider.get()] } as org.gradle.process.CommandLineArgumentProvider) + } + + project.tasks.register('generateConfigDocs', JavaExec) { + it.group = 'documentation' + it.description = 'Generates the config JSON schema snapshot and Markdown reference.' + it.classpath = configDocs.runtimeClasspath + it.mainClass.set('linea.config.docs.ConfigDocsGenerateMain') + it.workingDir = project.rootProject.projectDir + it.argumentProviders.add({ [specProvider.get()] } as org.gradle.process.CommandLineArgumentProvider) + } + } +} \ No newline at end of file diff --git a/coordinator/app/build.gradle b/coordinator/app/build.gradle index 2fa314cd87..2046a267d2 100644 --- a/coordinator/app/build.gradle +++ b/coordinator/app/build.gradle @@ -3,6 +3,13 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent plugins { id 'net.consensys.zkevm.kotlin-application-conventions' + id 'linea.config-docs' +} + +// Config documentation tooling: creates the `configDocs` source set and the +// checkConfigDocs/generateConfigDocs tasks, driven by the spec below. +configDocs { + spec = 'linea.coordinator.config.v2.docs.CoordinatorConfigDocsSpec' } configurations.configureEach { exclude group: "org.rocksdb", module: "rocksdbjni" diff --git a/coordinator/app/src/configDocs/kotlin/linea/coordinator/config/v2/docs/CoordinatorConfigDocsSpec.kt b/coordinator/app/src/configDocs/kotlin/linea/coordinator/config/v2/docs/CoordinatorConfigDocsSpec.kt new file mode 100644 index 0000000000..70fbc4f14a --- /dev/null +++ b/coordinator/app/src/configDocs/kotlin/linea/coordinator/config/v2/docs/CoordinatorConfigDocsSpec.kt @@ -0,0 +1,54 @@ +package linea.coordinator.config.v2.docs + +import linea.config.docs.ConfigDocsSpec +import linea.config.docs.ConfigFileRoot +import linea.config.docs.sectionByPackagePrefix +import linea.coordinator.config.v2.toml.CoordinatorConfigFileToml +import linea.coordinator.config.v2.toml.GasPriceCapTimeOfDayMultipliersConfigFileToml +import linea.coordinator.config.v2.toml.SmartContractErrorCodesConfigFileToml +import linea.coordinator.config.v2.toml.TracesLimitsConfigFileV4Toml +import linea.coordinator.config.v2.toml.TracesLimitsConfigFileV5Toml + +/** + * Coordinator-specific configuration for the generic `config-docs` tooling. Lives in the + * `configDocs` source set (compiled against the config classes but kept out of the production + * jar) and is named from `coordinator/app/build.gradle` via `configDocs { spec = "…" }`. + */ +object CoordinatorConfigDocsSpec : ConfigDocsSpec { + /** Config data classes live in this package; used to distinguish nested sections from leaves. */ + override val sectionDetector = sectionByPackagePrefix("linea.coordinator.config.v2.toml") + + /** The Coordinator config files documented by this tooling, keyed by a stable label. */ + override val files: List = listOf( + ConfigFileRoot( + label = "coordinator", + description = "Main Coordinator configuration.", + rootClass = CoordinatorConfigFileToml::class, + ), + ConfigFileRoot( + label = "traces-limits-v4", + description = "Per-module trace counter limits for v4 tracing modules.", + rootClass = TracesLimitsConfigFileV4Toml::class, + ), + ConfigFileRoot( + label = "traces-limits-v5", + description = "Per-module trace counter limits for v5 tracing modules.", + rootClass = TracesLimitsConfigFileV5Toml::class, + ), + ConfigFileRoot( + label = "gas-price-cap-time-of-day-multipliers", + description = "L1 dynamic gas price cap time-of-day multipliers.", + rootClass = GasPriceCapTimeOfDayMultipliersConfigFileToml::class, + ), + ConfigFileRoot( + label = "smart-contract-errors", + description = "Mapping of Linea smart-contract revert error codes to messages.", + rootClass = SmartContractErrorCodesConfigFileToml::class, + ), + ) + + override val jsonSchemaPath = "docs/tech/components/coordinator-config-schema.json" + override val markdownPath = "docs/tech/components/coordinator-config-reference.md" + override val markdownTitle = "Coordinator Configuration Reference" + override val regenerateCommand = "./gradlew :coordinator:app:generateConfigDocs" +}