How do I help task users understand what to do when a task is configured incorrectly?
When a test lacks its argument or worse delegates configuration to a closure the errors can be very confusing.
How do I help task users understand what to do when a task is configured incorrectly?
When a test lacks its argument or worse delegates configuration to a closure the errors can be very confusing.
I created a ClosureConfigurationDelegator and had my task + object implement it.
I create a usageError with sample usage, wrap the passing of closure to object in a try catch so I can display usage on those errors. I also note config problems so I can report them as well.
If my BuildValidationTask has a faulty content closure, the somewhat failure is easier to follow.
trait ClosureConfigurationDelegator {
abstract void usageError(def message)
/** * Always report delegation errors with usage - add railings to the learning curve * helping folks learn the system * @param configuration closure - see implementations for details */ public void delegateClosure(Closure config) { try { config.delegate = this config() } catch (Exception e) { usageError(e.getMessage()) } }
}
Usage
public FileContentsValidationSpec(Closure config) { delegateClosure(config) // Gradle @ Runtime via gradle file requires this even though unit tests do not. this.description = config.description this.contentFileTree = config.contentFileTree def configErrors = [] if (! description) { configErrors.add("contents lacks description configuration.") } if ( ! contentFileTree) { configErrors.add("contents lacks files filetree.") } if ( ! required && ! prohibited) { configErrors.add("contents lacks pattern lists for both required and prohibited text. Can't determine how to validate content.") } // Compile Regex try { required = stringsToPatterns(config.required) prohibited = stringsToPatterns(config.prohibited) } catch (Exception e) { configErrors.add("StringToPattern Failure: ${e.getMessage()}") } // Convert boolean into FaultType if (failOnError) { this.fType = FaultType.FAIL } else { this.fType = FaultType.WARN } // Throw on problems found if (configErrors.size() > 0) { usageError(configErrors.join("\n\t")) } } void usageError(def message) { throw new GradleException("""Misconfigured content:
${message}
Artifact:
${this.toString()}| Example:
| content {
| description = “installer”
| contentFileTree= fileTree(dir: “./build”, includes: [“**/target/dist/AIEinstall”])
| required= [“BUILD SUCCESSFUL”]
| prohibited= [“BUILD FAILED”, “Conflict Count [1-9]"]
| failOnError = true / Defaults to false */
| }
“””)
}