diff --git a/grails-cli/src/main/java/org/grails/forge/cli/command/CreateJobCommand.java b/grails-cli/src/main/java/org/grails/forge/cli/command/CreateJobCommand.java new file mode 100644 index 00000000..27bd5826 --- /dev/null +++ b/grails-cli/src/main/java/org/grails/forge/cli/command/CreateJobCommand.java @@ -0,0 +1,84 @@ +/* + * Copyright 2017-2020 original authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.grails.forge.cli.command; + +import io.micronaut.context.annotation.Parameter; +import io.micronaut.core.annotation.ReflectiveAccess; +import io.micronaut.core.util.functional.ThrowingSupplier; +import jakarta.inject.Inject; +import java.io.IOException; +import org.grails.forge.application.Project; +import org.grails.forge.cli.CodeGenConfig; +import org.grails.forge.cli.command.templates.job; +import org.grails.forge.feature.other.GrailsQuartz; +import org.grails.forge.io.ConsoleOutput; +import org.grails.forge.io.OutputHandler; +import org.grails.forge.template.RenderResult; +import org.grails.forge.template.RockerTemplate; +import picocli.CommandLine; + +@CommandLine.Command(name = CreateJobCommand.NAME, description = "Creates a new Quartz scheduled job") +public class CreateJobCommand extends CodeGenCommand { + + public static final String NAME = "create-job"; + + @ReflectiveAccess + @CommandLine.Parameters(paramLabel = "JOB-NAME", description = "The name of the job") + String jobName; + + @Inject + public CreateJobCommand(@Parameter CodeGenConfig config) { + super(config); + } + + public CreateJobCommand(CodeGenConfig config, + ThrowingSupplier outputHandlerSupplier, + ConsoleOutput consoleOutput) { + super(config, outputHandlerSupplier, consoleOutput); + } + + @Override + public boolean applies() { + return config.getFeatures().contains(GrailsQuartz.FEATURE_NAME); + } + + @Override + public Integer call() throws Exception { + if (!applies()) { + throw new IllegalArgumentException("Please first select Grails Quartz Plugin"); + } + final Project project = getProject(jobName); + final RenderResult result = getTemplateRenderer(project) + .render(new RockerTemplate("grails-app/jobs/{packagePath}/{className}Job.groovy", job.template(project)), overwrite); + if (result != null) { + logRenderResult(result); + } + + return 0; + } + + private void logRenderResult(RenderResult result) throws Exception { + if (result != null) { + if (result.isSuccess()) { + out("@|blue ||@ Rendered job to " + result.getPath()); + } else if (result.isSkipped()) { + warning("Rendering skipped for " + result.getPath() + " because it already exists. Run again with -f to overwrite."); + } else if (result.getError() != null) { + throw result.getError(); + } + } + } +} diff --git a/grails-cli/src/main/java/org/grails/forge/cli/command/templates/job.rocker.raw b/grails-cli/src/main/java/org/grails/forge/cli/command/templates/job.rocker.raw new file mode 100644 index 00000000..91dfd9de --- /dev/null +++ b/grails-cli/src/main/java/org/grails/forge/cli/command/templates/job.rocker.raw @@ -0,0 +1,22 @@ +@import org.grails.forge.application.Project + +@args ( + Project project +) + +@if(project.getPackageName() != null) { +package @project.getPackageName() + +} + + +class @project.getClassName()Job { + + static triggers = { + simple repeatInterval: 5000l // execute job once in 5 seconds + } + + def execute() { + // execute job + } +} \ No newline at end of file diff --git a/grails-cli/src/test/groovy/org/grails/forge/cli/command/CreateJobCommandSpec.groovy b/grails-cli/src/test/groovy/org/grails/forge/cli/command/CreateJobCommandSpec.groovy new file mode 100644 index 00000000..ae39e14b --- /dev/null +++ b/grails-cli/src/test/groovy/org/grails/forge/cli/command/CreateJobCommandSpec.groovy @@ -0,0 +1,56 @@ +package org.grails.forge.cli.command + +import io.micronaut.context.ApplicationContext +import org.grails.forge.application.ApplicationType +import org.grails.forge.cli.CodeGenConfig +import org.grails.forge.cli.CommandFixture +import org.grails.forge.cli.CommandSpec +import org.grails.forge.feature.other.GrailsQuartz +import org.grails.forge.io.ConsoleOutput +import spock.lang.AutoCleanup +import spock.lang.Shared + +class CreateJobCommandSpec extends CommandSpec implements CommandFixture { + + @Shared + @AutoCleanup + ApplicationContext beanContext = ApplicationContext.run() + + + void "test creating a job"() { + + setup: + generateProject(ApplicationType.WEB) + CodeGenConfig codeGenConfig = CodeGenConfig.load(beanContext, dir, ConsoleOutput.NOOP) + codeGenConfig.getFeatures().add(GrailsQuartz.FEATURE_NAME) + ConsoleOutput consoleOutput = Mock(ConsoleOutput) + CreateJobCommand command = new CreateJobCommand(codeGenConfig, getOutputHandler(consoleOutput), consoleOutput) + command.jobName = "Scheduled" + + when: + Integer exitCode = command.call() + File output = new File(dir, "grails-app/jobs/example/grails/ScheduledJob.groovy") + + then: + exitCode == 0 + output.exists() + 1 * consoleOutput.out({ it.contains("Rendered job") }) + } + + void "test plugin not selected"() { + + setup: + generateProject(ApplicationType.WEB) + CodeGenConfig codeGenConfig = CodeGenConfig.load(beanContext, dir, ConsoleOutput.NOOP) + ConsoleOutput consoleOutput = Mock(ConsoleOutput) + CreateJobCommand command = new CreateJobCommand(codeGenConfig, getOutputHandler(consoleOutput), consoleOutput) + command.jobName = "Scheduled" + + when: + command.call() + + then: + final e = thrown(IllegalArgumentException) + e.message == 'Please first select Grails Quartz Plugin' + } +} diff --git a/grails-forge-core/src/main/java/org/grails/forge/feature/other/GrailsQuartz.java b/grails-forge-core/src/main/java/org/grails/forge/feature/other/GrailsQuartz.java new file mode 100644 index 00000000..249963d7 --- /dev/null +++ b/grails-forge-core/src/main/java/org/grails/forge/feature/other/GrailsQuartz.java @@ -0,0 +1,69 @@ +/* + * Copyright 2017-2020 original authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.grails.forge.feature.other; + +import jakarta.inject.Singleton; +import org.grails.forge.application.ApplicationType; +import org.grails.forge.application.generator.GeneratorContext; +import org.grails.forge.build.dependencies.Dependency; +import org.grails.forge.feature.Category; +import org.grails.forge.feature.Feature; + +@Singleton +public class GrailsQuartz implements Feature { + + public static final String FEATURE_NAME = "grails-quartz"; + + @Override + public String getName() { + return FEATURE_NAME; + } + + @Override + public String getTitle() { + return "Grails Quartz Plugin"; + } + + @Override + public String getDescription() { + return "Provides integration of the Quartz scheduling framework into the Grails Framework."; + } + + @Override + public void apply(GeneratorContext generatorContext) { + generatorContext.getConfiguration().put("quartz.autoStartup", true); + generatorContext.addDependency(Dependency.builder() + .groupId("org.grails.plugins") + .lookupArtifactId("quartz") + .compile()); + } + + @Override + public boolean supports(ApplicationType applicationType) { + return true; + } + + @Override + public String getCategory() { + return Category.OTHER; + } + + @Override + public String getDocumentation() { + return "https://grails-plugins.github.io/grails-quartz/latest/guide/index.html"; + } + +}