diff --git a/docs/rules.md b/docs/rules.md index f3f1ad3..746aaff 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -9,7 +9,7 @@ Android Lint rules
 android_lint(name, android_lint_config, autofix, custom_rules, deps, disable_checks, enable_checks,
-             is_test_sources, lib, manifest, resource_files, srcs, warnings_as_errors)
+             is_test_sources, lib, manifest, output_formats, resource_files, srcs, warnings_as_errors)
 
@@ -29,6 +29,7 @@ android_lint(name, is_test_sources | True when linting test sources, otherwise false. | Boolean | optional | False | | lib | The target being linted. This is needed to get the compiled R files. | Label | required | | | manifest | Android manifest to run Android Lint against. | Label | optional | None | +| output_formats | List of output formats to produce. Supported [xml, html] | List of strings | optional | ["xml"] | | resource_files | Android resource files to run Android Lint against. | List of labels | optional | [] | | srcs | Sources to run Android Lint against. | List of labels | required | | | warnings_as_errors | When true, lint will treat warnings as errors. | Boolean | optional | False | @@ -40,7 +41,7 @@ android_lint(name, name, android_lint_config, autofix, baseline, custom_rules, deps, disable_checks, - enable_checks, is_test_sources, lib, manifest, resource_files, srcs, + enable_checks, is_test_sources, lib, manifest, output_formats, resource_files, srcs, warnings_as_errors) @@ -62,6 +63,7 @@ android_lint_test(name, is_test_sources | True when linting test sources, otherwise false. | Boolean | optional | False | | lib | The target being linted. This is needed to get the compiled R files. | Label | required | | | manifest | Android manifest to run Android Lint against. | Label | optional | None | +| output_formats | List of output formats to produce. Supported [xml, html] | List of strings | optional | ["xml"] | | resource_files | Android resource files to run Android Lint against. | List of labels | optional | [] | | srcs | Sources to run Android Lint against. | List of labels | required | | | warnings_as_errors | When true, lint will treat warnings as errors. | Boolean | optional | False | @@ -72,7 +74,7 @@ android_lint_test(name, output) +AndroidLintResultsInfo(baseline, xml_output, html_output) Info needed to evaluate lint results @@ -82,6 +84,8 @@ Info needed to evaluate lint results | Name | Description | | :------------- | :------------- | -| output | The Android Lint baseline output | +| baseline | The Android Lint baseline output | +| xml_output | The Android Lint xml output | +| html_output | The Android Lint html output | diff --git a/rules/android_lint.bzl b/rules/android_lint.bzl index 4668539..fa6209a 100644 --- a/rules/android_lint.bzl +++ b/rules/android_lint.bzl @@ -21,12 +21,17 @@ def _impl(ctx): android_lint_results = _process_android_lint_issues(ctx, regenerate = False) inputs = [] - inputs.append(android_lint_results.output) + inputs.append(android_lint_results.xml_output) + files_output = [] + if android_lint_results.xml_output != None: + files_output.append(android_lint_results.xml_output) + if android_lint_results.html_output != None: + files_output.append(android_lint_results.html_output) return [ DefaultInfo( runfiles = ctx.runfiles(files = inputs), - files = depset([android_lint_results.output]), + files = depset(files_output), ), ] + android_lint_results.providers diff --git a/rules/android_lint_test.bzl b/rules/android_lint_test.bzl index cc2739f..8afe537 100644 --- a/rules/android_lint_test.bzl +++ b/rules/android_lint_test.bzl @@ -21,7 +21,7 @@ def _test_impl(ctx): android_lint_results = _process_android_lint_issues(ctx, regenerate = False) inputs = [] - inputs.append(android_lint_results.output) + inputs.append(android_lint_results.xml_output) inputs.extend(ctx.attr._android_lint_output_validator.default_runfiles.files.to_list()) ctx.actions.write( @@ -33,15 +33,19 @@ def _test_impl(ctx): {executable} --lint_baseline "{lint_baseline}" """.format( executable = ctx.executable._android_lint_output_validator.short_path, - lint_baseline = android_lint_results.output.short_path, + lint_baseline = android_lint_results.xml_output.short_path, ), ) - + files_info = [ctx.outputs.executable] + if android_lint_results.xml_output != None: + files_info.append(android_lint_results.xml_output) + if android_lint_results.html_output != None: + files_info.append(android_lint_results.html_output) return [ DefaultInfo( runfiles = ctx.runfiles(files = inputs), executable = ctx.outputs.executable, - files = depset([ctx.outputs.executable, android_lint_results.output]), + files = depset(files_info), ), ] + android_lint_results.providers diff --git a/rules/attrs.bzl b/rules/attrs.bzl index 1945a4e..44c292c 100644 --- a/rules/attrs.bzl +++ b/rules/attrs.bzl @@ -77,5 +77,11 @@ ATTRS = dict( default = [], doc = "Custom lint rules to run.", ), + output_formats = attr.string_list( + mandatory = False, + allow_empty = False, + default = ["xml"], + doc = "List of output formats to produce. Supported [xml, html]", + ), _use_auto_exec_groups = attr.bool(default = True), ) diff --git a/rules/impl.bzl b/rules/impl.bzl index 23d2a94..0c91e53 100644 --- a/rules/impl.bzl +++ b/rules/impl.bzl @@ -19,7 +19,8 @@ def _run_android_lint( ctx, android_lint, module_name, - output, + xml_output, + html_output, srcs, deps, resource_files, @@ -43,7 +44,8 @@ def _run_android_lint( ctx: The target context android_lint: The Android Lint binary to use module_name: The name of the module - output: The output file + xml_output: The xml_output file + html_output: The html_output file srcs: The source files deps: Depset of aars and jars to include on the classpath resource_files: The Android resource files @@ -63,7 +65,7 @@ def _run_android_lint( android_lint_skip_bytecode_verifier: Disables bytecode verification """ inputs = [] - outputs = [output] + outputs = [] args = ctx.actions.args() args.set_param_file_format("multiline") @@ -114,9 +116,14 @@ def _run_android_lint( if android_lint_enable_check_dependencies: args.add("--enable-check-dependencies") - # Declare the output file - args.add("--output", output) - outputs.append(output) + if xml_output != None: + args.add("--xml-output", xml_output) + outputs.append(xml_output) + if html_output != None: + args.add("--html-output", html_output) + outputs.append(html_output) + if len(outputs) == 0: + fail("Lint cannot have no outputs!") ctx.actions.run( mnemonic = "AndroidLint", @@ -163,7 +170,7 @@ def process_android_lint_issues(ctx, regenerate): regenerate: Whether to regenerate the baseline files Returns: - A struct containing the output file and the providers + A struct containing the output files and the providers """ # Append the Android manifest file. Lint requires that the input manifest files be named @@ -197,12 +204,21 @@ def process_android_lint_issues(ctx, regenerate): _utils.list_or_depset_to_list(_utils.get_android_lint_toolchain(ctx).android_lint_config.files), ) - output = ctx.actions.declare_file("{}.xml".format(ctx.label.name)) + baseline = getattr(ctx.file, "baseline", None) + xml_output = None + html_output = None + for output_format in ctx.attr.output_formats: + if output_format == "xml": + xml_output = ctx.actions.declare_file("{}.xml".format(ctx.label.name)) + if output_format == "html": + html_output = ctx.actions.declare_file("{}.html".format(ctx.label.name)) + _run_android_lint( ctx, android_lint = _utils.only(_utils.list_or_depset_to_list(_utils.get_android_lint_toolchain(ctx).android_lint.files)), module_name = _get_module_name(ctx), - output = output, + xml_output = xml_output, + html_output = html_output, srcs = ctx.files.srcs, deps = depset(transitive = deps), resource_files = ctx.files.resource_files, @@ -210,7 +226,7 @@ def process_android_lint_issues(ctx, regenerate): compile_sdk_version = _utils.get_android_lint_toolchain(ctx).compile_sdk_version, java_language_level = _utils.get_android_lint_toolchain(ctx).java_language_level, kotlin_language_level = _utils.get_android_lint_toolchain(ctx).kotlin_language_level, - baseline = getattr(ctx.file, "baseline", None), + baseline = baseline, config = config, warnings_as_errors = ctx.attr.warnings_as_errors, custom_rules = ctx.files.custom_rules, @@ -223,10 +239,14 @@ def process_android_lint_issues(ctx, regenerate): ) return struct( - output = output, + baseline = baseline, + xml_output = xml_output, + html_output = html_output, providers = [ _AndroidLintResultsInfo( - output = output, + baseline = baseline, + xml_output = xml_output, + html_output = html_output, ), ], ) diff --git a/rules/providers.bzl b/rules/providers.bzl index 2992a84..8cd359b 100644 --- a/rules/providers.bzl +++ b/rules/providers.bzl @@ -4,6 +4,8 @@ AndroidLintResultsInfo = provider( "Info needed to evaluate lint results", fields = { - "output": "The Android Lint baseline output", + "baseline": "The Android Lint baseline output", + "xml_output": "The Android Lint xml output", + "html_output": "The Android Lint html output", }, ) diff --git a/src/cli/AndroidLintActionArgs.kt b/src/cli/AndroidLintActionArgs.kt index 12aa735..b1a9643 100644 --- a/src/cli/AndroidLintActionArgs.kt +++ b/src/cli/AndroidLintActionArgs.kt @@ -32,11 +32,17 @@ internal class AndroidLintActionArgs( transform = argsParserPathTransformer, ) - val output: Path by parser.storing( - names = arrayOf("--output"), + val xmlOutput: Path? by parser.storing( + names = arrayOf("--xml-output"), help = "", transform = argsParserPathTransformer, - ) + ).default { null } + + val htmlOutput: Path? by parser.storing( + names = arrayOf("--html-output"), + help = "", + transform = argsParserPathTransformer, + ).default { null } val resources: List by parser.adding( names = arrayOf("--resource"), diff --git a/src/cli/AndroidLintRunner.kt b/src/cli/AndroidLintRunner.kt index 3b339d3..93f6782 100644 --- a/src/cli/AndroidLintRunner.kt +++ b/src/cli/AndroidLintRunner.kt @@ -92,8 +92,6 @@ internal class AndroidLintRunner { val args = mutableListOf( "--project", projectFilePath.pathString, - "--xml", - actionArgs.output.pathString, "--path-variables", "PWD=$rootDirPath", "--exitcode", @@ -113,6 +111,16 @@ internal class AndroidLintRunner { cacheDirectoryPath.pathString, "--client-id", "cli", ) + if (actionArgs.xmlOutput != null) { + args.add("--xml") + args.add(actionArgs.xmlOutput!!.pathString) + } + + if (actionArgs.htmlOutput != null) { + args.add("--html") + args.add(actionArgs.htmlOutput!!.pathString) + } + if (actionArgs.warningsAsErrors) { args.add("-Werror") } else { diff --git a/tests/src/cli/AndroidLintActionArgsTest.kt b/tests/src/cli/AndroidLintActionArgsTest.kt index 01e77e9..316726a 100644 --- a/tests/src/cli/AndroidLintActionArgsTest.kt +++ b/tests/src/cli/AndroidLintActionArgsTest.kt @@ -19,8 +19,10 @@ class AndroidLintActionArgsTest { "path/to/cli.jar", "--src", "path/to/Foo.kt", - "--output", - "output.jar", + "--xml-output", + "xml_output.xml", + "--html-output", + "html_output.html", "--resource", "path/to/resource/strings.xml", "--android-manifest", @@ -54,7 +56,8 @@ class AndroidLintActionArgsTest { assertThat(parseArgs.label).isEqualTo("test") assertThat(parseArgs.srcs).containsExactly(Paths.get("path/to/Foo.kt")) - assertThat(parseArgs.output).isEqualTo(Paths.get("output.jar")) + assertThat(parseArgs.xmlOutput).isEqualTo(Paths.get("xml_output.xml")) + assertThat(parseArgs.htmlOutput).isEqualTo(Paths.get("html_output.html")) assertThat(parseArgs.resources).containsExactly(Paths.get("path/to/resource/strings.xml")) assertThat(parseArgs.baselineFile).isEqualTo(Paths.get("lib_lint_baseline.xml")) assertThat(parseArgs.config).isEqualTo(Paths.get("lint_config.xml"))