diff --git a/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/extension/BlackExtension.java b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/extension/BlackExtension.java new file mode 100644 index 00000000..7f9c2054 --- /dev/null +++ b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/extension/BlackExtension.java @@ -0,0 +1,22 @@ +/* + * Copyright 2016 LinkedIn Corp. + * + * 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 + * + * http://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 com.linkedin.gradle.python.extension; + +import com.linkedin.gradle.python.extension.internal.DefaultExternalTool; + + +public class BlackExtension extends DefaultExternalTool { +} diff --git a/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/extension/IsortExtension.java b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/extension/IsortExtension.java new file mode 100644 index 00000000..0de880f0 --- /dev/null +++ b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/extension/IsortExtension.java @@ -0,0 +1,22 @@ +/* + * Copyright 2016 LinkedIn Corp. + * + * 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 + * + * http://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 com.linkedin.gradle.python.extension; + +import com.linkedin.gradle.python.extension.internal.DefaultExternalTool; + + +public class IsortExtension extends DefaultExternalTool { +} diff --git a/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/extension/MypyExtension.java b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/extension/MypyExtension.java index ca3ca085..e3e30866 100644 --- a/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/extension/MypyExtension.java +++ b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/extension/MypyExtension.java @@ -15,24 +15,8 @@ */ package com.linkedin.gradle.python.extension; +import com.linkedin.gradle.python.extension.internal.DefaultExternalTool; -public class MypyExtension { - private boolean run; - private String[] arguments = null; - public boolean isRun() { - return run; - } - - public void setRun(boolean run) { - this.run = run; - } - - public void setArguments(String argumentString) { - arguments = argumentString.split("\\s+"); - } - - public String[] getArguments() { - return arguments; - } +public class MypyExtension extends DefaultExternalTool { } diff --git a/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/extension/internal/DefaultExternalTool.java b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/extension/internal/DefaultExternalTool.java new file mode 100644 index 00000000..273d6643 --- /dev/null +++ b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/extension/internal/DefaultExternalTool.java @@ -0,0 +1,38 @@ +/* + * Copyright 2016 LinkedIn Corp. + * + * 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 + * + * http://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 com.linkedin.gradle.python.extension.internal; + + +public class DefaultExternalTool { + private boolean run; + private String[] arguments = null; + + public boolean isRun() { + return run; + } + + public void setRun(boolean run) { + this.run = run; + } + + public void setArguments(String argumentString) { + arguments = argumentString.split("\\s+"); + } + + public String[] getArguments() { + return arguments; + } +} diff --git a/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/plugin/internal/ValidationPlugin.java b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/plugin/internal/ValidationPlugin.java index 835ca98a..6931831d 100644 --- a/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/plugin/internal/ValidationPlugin.java +++ b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/plugin/internal/ValidationPlugin.java @@ -16,13 +16,17 @@ package com.linkedin.gradle.python.plugin.internal; import com.linkedin.gradle.python.PythonExtension; +import com.linkedin.gradle.python.extension.BlackExtension; +import com.linkedin.gradle.python.extension.IsortExtension; import com.linkedin.gradle.python.extension.MypyExtension; import com.linkedin.gradle.python.extension.CoverageExtension; import com.linkedin.gradle.python.tasks.AbstractPythonMainSourceDefaultTask; import com.linkedin.gradle.python.tasks.AbstractPythonTestSourceDefaultTask; +import com.linkedin.gradle.python.tasks.BlackTask; import com.linkedin.gradle.python.tasks.CheckStyleGeneratorTask; import com.linkedin.gradle.python.tasks.Flake8Task; import com.linkedin.gradle.python.tasks.MypyTask; +import com.linkedin.gradle.python.tasks.IsortTask; import com.linkedin.gradle.python.tasks.PyCoverageTask; import com.linkedin.gradle.python.tasks.PyTestTask; import com.linkedin.gradle.python.util.ExtensionUtils; @@ -32,6 +36,7 @@ import org.gradle.api.logging.Logger; import org.gradle.api.logging.Logging; +import static com.linkedin.gradle.python.util.StandardTextValues.TASK_BLACK; import static com.linkedin.gradle.python.util.StandardTextValues.TASK_CHECK; import static com.linkedin.gradle.python.util.StandardTextValues.TASK_CHECKSTYLE; import static com.linkedin.gradle.python.util.StandardTextValues.TASK_COVERAGE; @@ -39,6 +44,7 @@ import static com.linkedin.gradle.python.util.StandardTextValues.TASK_INSTALL_BUILD_REQS; import static com.linkedin.gradle.python.util.StandardTextValues.TASK_INSTALL_PROJECT; import static com.linkedin.gradle.python.util.StandardTextValues.TASK_MYPY; +import static com.linkedin.gradle.python.util.StandardTextValues.TASK_ISORT; import static com.linkedin.gradle.python.util.StandardTextValues.TASK_PYTEST; public class ValidationPlugin implements Plugin { @@ -112,7 +118,7 @@ public void apply(final Project project) { /* * Run mypy. * - * This uses the mypy.ini file if present to configure mypy. + * This uses the setup.cfg (or mypy.ini) file if present to configure mypy. */ MypyExtension mypy = ExtensionUtils.maybeCreate(project, "mypy", MypyExtension.class); project.getTasks().create(TASK_MYPY.getValue(), MypyTask.class, @@ -122,6 +128,28 @@ public void apply(final Project project) { project.getTasks().getByName(TASK_CHECK.getValue()) .dependsOn(project.getTasks().getByName(TASK_MYPY.getValue())); + /* + * Run isort. + */ + IsortExtension isort = ExtensionUtils.maybeCreate(project, "isort", IsortExtension.class); + project.getTasks().create(TASK_ISORT.getValue(), IsortTask.class, + task -> task.onlyIf(it -> project.file(settings.srcDir).exists() && isort.isRun())); + + // Make task "check" depend on isort task. + project.getTasks().getByName(TASK_CHECK.getValue()) + .dependsOn(project.getTasks().getByName(TASK_ISORT.getValue())); + + /* + * Run black. + */ + BlackExtension black = ExtensionUtils.maybeCreate(project, "black", BlackExtension.class); + project.getTasks().create(TASK_BLACK.getValue(), BlackTask.class, + task -> task.onlyIf(it -> project.file(settings.srcDir).exists() && black.isRun())); + + // Make task "check" depend on black task. + project.getTasks().getByName(TASK_CHECK.getValue()) + .dependsOn(project.getTasks().getByName(TASK_BLACK.getValue())); + /* * Create checkstyle styled report from flake */ diff --git a/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/tasks/BlackTask.java b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/tasks/BlackTask.java new file mode 100644 index 00000000..754d19c1 --- /dev/null +++ b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/tasks/BlackTask.java @@ -0,0 +1,46 @@ +/* + * Copyright 2016 LinkedIn Corp. + * + * 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 + * + * http://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 com.linkedin.gradle.python.tasks; + +import com.linkedin.gradle.python.extension.BlackExtension; +import com.linkedin.gradle.python.extension.PythonDetails; +import com.linkedin.gradle.python.util.ExtensionUtils; +import org.gradle.api.Project; +import org.gradle.process.ExecResult; + + +public class BlackTask extends AbstractPythonMainSourceDefaultTask { + + public void preExecution() { + PythonDetails blackDetails = getPythonDetails(); + args(blackDetails.getVirtualEnvironment().findExecutable("black").getAbsolutePath()); + + Project project = getProject(); + BlackExtension black = ExtensionUtils.getPythonComponentExtension(project, BlackExtension.class); + + String[] arguments = black.getArguments(); + + if (arguments == null) { + // Default to longer line length (160) than the default (88) + // Default to check only + arguments = new String[] {"--check", "-l", "160", getPythonExtension().srcDir, getPythonExtension().testDir}; + } + args(arguments); + } + + public void processResults(ExecResult results) { + } +} diff --git a/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/tasks/IsortTask.java b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/tasks/IsortTask.java new file mode 100644 index 00000000..ff8cbe34 --- /dev/null +++ b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/tasks/IsortTask.java @@ -0,0 +1,45 @@ +/* + * Copyright 2016 LinkedIn Corp. + * + * 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 + * + * http://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 com.linkedin.gradle.python.tasks; + +import com.linkedin.gradle.python.extension.IsortExtension; +import com.linkedin.gradle.python.extension.PythonDetails; +import com.linkedin.gradle.python.util.ExtensionUtils; +import org.gradle.api.Project; +import org.gradle.process.ExecResult; + + +public class IsortTask extends AbstractPythonMainSourceDefaultTask { + + public void preExecution() { + PythonDetails isortDetails = getPythonDetails(); + args(isortDetails.getVirtualEnvironment().findExecutable("isort").getAbsolutePath()); + + Project project = getProject(); + IsortExtension isort = ExtensionUtils.getPythonComponentExtension(project, IsortExtension.class); + + String[] arguments = isort.getArguments(); + + if (arguments == null) { + // Default to --check-only --recursive src/ test/ + arguments = new String[]{"--check-only", "--recursive", getPythonExtension().srcDir, getPythonExtension().testDir}; + } + args(arguments); + } + + public void processResults(ExecResult results) { + } +} diff --git a/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/util/StandardTextValues.java b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/util/StandardTextValues.java index a39617b3..f35d8f69 100644 --- a/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/util/StandardTextValues.java +++ b/pygradle-plugin/src/main/groovy/com/linkedin/gradle/python/util/StandardTextValues.java @@ -31,6 +31,7 @@ public enum StandardTextValues { CONFIGURATION_VENV("venv"), CONFIGURATION_WHEEL("wheel"), CONFIGURATION_FLAKE8("flake8"), + TASK_BLACK("runBlack"), TASK_BUILD_DOCS("buildDocs"), TASK_CLEAN_SAVE_VENV("cleanSaveVenv"), TASK_CHECK("check"), @@ -42,6 +43,7 @@ public enum StandardTextValues { TASK_INSTALL_PROJECT("installProject"), TASK_INSTALL_PYTHON_REQS("installPythonRequirements"), TASK_INSTALL_TEST_REQS("installTestRequirements"), + TASK_ISORT("runIsort"), TASK_MYPY("runMypy"), TASK_PACKAGE_DOCS("packageDocs"), TASK_PACKAGE_JSON_DOCS("packageJsonDocs"),