Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce ktlint_test and ktlint_fix #502

Merged
merged 3 commits into from
Mar 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion examples/trivial/app/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library", "ktlint_fix", "ktlint_test")

kt_jvm_library(
name = "app_lib",
Expand All @@ -8,6 +8,16 @@ kt_jvm_library(
],
)

ktlint_test(
name = "lint_test",
srcs = glob(["**/*.kt"]),
)

ktlint_fix(
name = "lint_fix",
srcs = glob(["**/*.kt"]),
)

java_binary(
name = "myapp",
main_class = "app.MyApp",
Expand Down
2 changes: 2 additions & 0 deletions kotlin/internal/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ release_archive(
deps = [
"//kotlin/internal/js:pkg",
"//kotlin/internal/jvm:pkg",
"//kotlin/internal/lint:pkg",
"//kotlin/internal/repositories:pkg",
"//kotlin/internal/utils:pkg",
],
Expand All @@ -39,6 +40,7 @@ bzl_library(
deps = [
"//kotlin/internal/js",
"//kotlin/internal/jvm",
"//kotlin/internal/lint",
"//kotlin/internal/utils",
"//kotlin/internal/repositories",
],
Expand Down
29 changes: 29 additions & 0 deletions kotlin/internal/lint/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright 2018 The Bazel Authors. All rights reserved.
#
# 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.
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("//kotlin/internal/utils:packager.bzl", "release_archive")

release_archive(
name = "pkg",
srcs = glob(["*.bzl"]),
src_map = {
"BUILD.release.bazel": "BUILD.bazel",
},
)

bzl_library(
name = "lint",
srcs = glob(["*.bzl"]),
visibility = ["//kotlin:__subpackages__"],
)
14 changes: 14 additions & 0 deletions kotlin/internal/lint/BUILD.release.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright 2020 The Bazel Authors. All rights reserved.
#
# 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.

4 changes: 4 additions & 0 deletions kotlin/internal/lint/editorconfig.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
load(":ktlint_config.bzl", "KtlintConfigInfo")

def get_editorconfig(config):
return config[KtlintConfigInfo].editorconfig if config else None
27 changes: 27 additions & 0 deletions kotlin/internal/lint/ktlint_config.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
KtlintConfigInfo = provider(
fields = {
"editorconfig": "Editor config file to use",
},
)

def _ktlint_config_impl(ctx):
return [
KtlintConfigInfo(
editorconfig = ctx.file.editorconfig,
),
]

ktlint_config = rule(
_ktlint_config_impl,
attrs = {
"editorconfig": attr.label(
doc = "Editor config file to use",
mandatory = False,
allow_single_file = True,
),
},
doc = """Used to configure ktlint.

`ktlint` can be configured to use a `.editorconfig`, as documented at
https://github.com/pinterest/ktlint/#editorconfig"""
)
135 changes: 135 additions & 0 deletions kotlin/internal/lint/ktlint_fix.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
load(":editorconfig.bzl", "get_editorconfig")
load(":ktlint_config.bzl", "KtlintConfigInfo")

def _ktlint_fix_impl(ctx):
editorconfig = get_editorconfig(ctx.attr.config)

editorconfig_arg = "--editorconfig={file}".format(file = editorconfig.path) if editorconfig else ""

# Much of the following is lifted from:
# https://cs.opensource.google/bazel/bazel/+/refs/tags/4.0.0:src/main/java/com/google/devtools/build/lib/bazel/rules/java/java_stub_template.txt;l=114
content = """#!/bin/bash
# Find our runfiles tree.
#
# Call this program X. X was generated by a rule.
# X may be invoked in many ways:
# 1a) directly by a user, with $0 in the output tree
# 1b) via 'bazel run' (similar to case 1a)
# 2) directly by a user, with $0 in X's runfiles tree
# 3) by another program Y which has a data dependency on X, with $0 in Y's runfiles tree
# 4) via 'bazel test'
# 5) by a genrule cmd, with $0 in the output tree
# 6) case 3 in the context of a genrule
#
# For case 1, $0 will be a regular file, and the runfiles tree will be
# at $0.runfiles.
# For case 2, $0 will be a symlink to the file seen in case 1.
# For case 3, we use Y's runfiles tree, which will be a superset of X's.
# For case 4, $JAVA_RUNFILES and $TEST_SRCDIR should already be set.
# Case 5 is handled like case 1.
# Case 6 is handled like case 3.

self="$0"

if [[ "$self" != /* ]]; then
self="$PWD/$self"
fi

if [[ -z "$RUNFILES" ]]; then
while true; do
if [[ -e "$self.runfiles" ]]; then
RUNFILES="$self.runfiles"
break
fi
if [[ $self == *.runfiles/* ]]; then
RUNFILES="${{self%%.runfiles/*}}.runfiles"
break
fi
if [[ ! -L "$self" ]]; then
break
fi
readlink="$(readlink "$self")"
if [[ "$readlink" = /* ]]; then
self="$readlink"
else
# resolve relative symlink
self="${{self%%/*}}/$readlink"
fi
done
if [[ -z "$RUNFILES" ]]; then
echo 'Cannot locate runfiles directory.'
exit 1
fi
fi

# This is the end of the portion copied from the java_stub_template - what's below is original code.

BUILD_DIR="$BUILD_WORKSPACE_DIRECTORY"
if [ -n "$BUILD_DIR" ]; then
BUILD_DIR="$BUILD_DIR/"
fi

TOOL={executable}
if [[ ! -f "$TOOL" ]]; then
# The path to the tool contains starts with `/external` but when
# using --nolegacy_external_runfiles we need to strip that from
# the path.
TOOL="$RUNFILES/${{TOOL/#external\\///}}"

if [[ ! -f "$TOOL" ]]; then
echo "Cannot locate linter. $TOOL"
exit 2
fi
fi

SRCS=({srcs})
SRCS=${{SRCS[@]/#/$BUILD_DIR}}

"$TOOL" --format {editorconfig_arg} $SRCS
""".format(
executable = ctx.executable._ktlint_tool.path,
editorconfig_arg = editorconfig_arg,
srcs = " ".join([src.path for src in ctx.files.srcs]),
)

content = ctx.expand_location(content, [ctx.attr._ktlint_tool])

executable = ctx.actions.declare_file("%s-lint-fix" % ctx.label.name)
ctx.actions.write(
output = executable,
content = content,
is_executable = True,
)
runfiles = ctx.runfiles(files = [ctx.executable._ktlint_tool])

return [
DefaultInfo(
executable = executable,
runfiles = runfiles,
),
]

ktlint_fix = rule(
_ktlint_fix_impl,
attrs = {
"srcs": attr.label_list(
allow_files = [".kt", ".kts"],
doc = "Source files to review and fix",
mandatory = True,
allow_empty = False,
),
"config": attr.label(
doc = "ktlint_config to use",
providers = [
[KtlintConfigInfo],
],
),
"_ktlint_tool": attr.label(
default = "@com_github_pinterest_ktlint//file",
executable = True,
cfg = "target",
),
},
executable = True,
doc = "Lint Kotlin files and automatically fix them as needed",
)
86 changes: 86 additions & 0 deletions kotlin/internal/lint/ktlint_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
load(":editorconfig.bzl", "get_editorconfig")
load(":ktlint_config.bzl", "KtlintConfigInfo")

def _ktlint(ctx, srcs, editorconfig):
"""Generates a test action linting the input files.

Args:
ctx: analysis context.
srcs: list of source files to be checked.
editorconfig: editorconfig file to use (optional)

Returns:
A script running ktlint on the input files.
"""
java_runtime_info = ctx.attr._javabase[java_common.JavaRuntimeInfo]
args = []
if editorconfig:
args.append("--editorconfig={file}".format(file = editorconfig.short_path))

for f in srcs:
args.append(f.path)

return "PATH=\"{path}/bin:$PATH\" ; {linter} {args}".format(
path = java_runtime_info.java_home,
linter = ctx.executable._ktlint_tool.short_path,
args = " ".join(args),
)

def _ktlint_test_impl(ctx):
editorconfig = get_editorconfig(ctx.attr.config)

script = _ktlint(
ctx,
srcs = ctx.files.srcs,
editorconfig = editorconfig,
)

ctx.actions.write(
output = ctx.outputs.executable,
content = script,
)

files = [ctx.executable._ktlint_tool] + ctx.files.srcs
if editorconfig:
files.append(editorconfig)

return [
DefaultInfo(
runfiles = ctx.runfiles(
files = files,
transitive_files = ctx.attr._javabase[java_common.JavaRuntimeInfo].files,
).merge(ctx.attr._ktlint_tool[DefaultInfo].default_runfiles),
executable = ctx.outputs.executable,
),
]

ktlint_test = rule(
_ktlint_test_impl,
attrs = {
"srcs": attr.label_list(
allow_files = [".kt", ".kts"],
doc = "Source files to lint",
mandatory = True,
allow_empty = False,
),
"config": attr.label(
doc = "ktlint_config to use",
providers = [
[KtlintConfigInfo],
],
),
"_ktlint_tool": attr.label(
default = "@com_github_pinterest_ktlint//file",
executable = True,
cfg = "host",
),
"_javabase": attr.label(
default = "@bazel_tools//tools/jdk:current_java_runtime",
),
},
doc = "Lint Kotlin files, and fail if the linter raises errors.",
test = True,
toolchains = [
"@bazel_tools//tools/jdk:toolchain_type",
],
)
9 changes: 9 additions & 0 deletions kotlin/internal/repositories/release_repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ load(
_http_archive = "http_archive",
_http_file = "http_file",
)
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
load(":tools.bzl", "absolute_target")

BAZEL_JAVA_LAUNCHER_VERSION = "3.7.0"
Expand Down Expand Up @@ -61,6 +62,14 @@ def kotlin_repositories(
sha256 = "a618e746e743f3119a9939e60645a02de40149aae9d63201c3cd05706010f6eb",
)

maybe(
_http_file,
name = "com_github_pinterest_ktlint",
sha256 = "4739662e9ac9a9894a1eb47844cbb5610971f15af332eac94d108d4f55ebc19e",
urls = ["https://github.com/pinterest/ktlint/releases/download/0.40.0/ktlint"],
executable = True,
)

def _kotlin_compiler_impl(repository_ctx):
"""Creates the kotlinc repository."""
attr = repository_ctx.attr
Expand Down
6 changes: 6 additions & 0 deletions kotlin/kotlin.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ load(
_kt_jvm_test = "kt_jvm_test",
_kt_kotlinc_options = "kt_kotlinc_options",
_kt_register_toolchains = "kt_register_toolchains",
_ktlint_config = "ktlint_config",
_ktlint_fix = "ktlint_fix",
_ktlint_test = "ktlint_test",
)

kotlin_repositories = _kotlin_repositories
Expand All @@ -47,3 +50,6 @@ kt_jvm_test = _kt_jvm_test
kt_android_library = _kt_android_library
kt_android_local_test = _kt_android_local_test
kt_compiler_plugin = _kt_compiler_plugin
ktlint_config = _ktlint_config
ktlint_fix = _ktlint_fix
ktlint_test = _ktlint_test
6 changes: 6 additions & 0 deletions kotlin/rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ load(
_kt_js_import = "kt_js_import_macro",
_kt_js_library = "kt_js_library_macro",
)
load("//kotlin/internal/lint:ktlint_config.bzl", _ktlint_config = "ktlint_config")
load("//kotlin/internal/lint:ktlint_fix.bzl", _ktlint_fix = "ktlint_fix")
load("//kotlin/internal/lint:ktlint_test.bzl", _ktlint_test = "ktlint_test")

define_kt_toolchain = _define_kt_toolchain
kt_kotlinc_options = _kt_kotlinc_options
Expand All @@ -56,3 +59,6 @@ kt_jvm_test = _kt_jvm_test
kt_android_library = _kt_android_library
kt_android_local_test = _kt_android_local_test
kt_compiler_plugin = _kt_compiler_plugin
ktlint_config = _ktlint_config
ktlint_fix = _ktlint_fix
ktlint_test = _ktlint_test