diff --git a/.automation/test/r/README.md b/.automation/test/r/README.md new file mode 100644 index 00000000..19e0042f --- /dev/null +++ b/.automation/test/r/README.md @@ -0,0 +1,13 @@ +# R Test Cases +This folder holds the test cases for **R**. + +## Additional Docs +No Additional information is needed for this test case. + +## Good Test Cases +The test cases denoted: `LANGUAGE_good_FILE.EXTENSION` are all valid, and should pass successfully when linted. +- **Note:** They are linted utilizing the default linter rules. + +## Bad Test Cases +The test cases denoted: `LANGUAGE_bad_FILE.EXTENSION` are **NOT** valid, and should trigger errors when linted. +- **Note:** They are linted utilizing the default linter rules. \ No newline at end of file diff --git a/.automation/test/r/R_bad_1.R b/.automation/test/r/R_bad_1.R new file mode 100644 index 00000000..480eacd1 --- /dev/null +++ b/.automation/test/r/R_bad_1.R @@ -0,0 +1,43 @@ +# Each of the default linters should throw at least one lint on this file + +# assignment +# function_left_parentheses +# closed_curly +# commas +# paren_brace +f = function (x,y = 1){} + +# commented_code +# some <- commented("out code") + +# cyclocomp +# equals_na +# infix_spaces +# line_length +# object_length +# object_name +# object_usage +# open_curly +someComplicatedFunctionWithALongCameCaseName <- function(x) +{ + y <- 1 + if (1 > 2 && 2 > 3 && 3 > 4 && 4 > 5 && 5*10 > 6 && x == NA) {TRUE} else {FALSE} +} + +# pipe_continuation +# seq_linter +# spaces_inside +x <- 1:10 +x[ 2] +1:length(x) %>% lapply(function(x) x*2) %>% + head() + +# single_quotes +message('single_quotes') + +# spaces_left_parentheses +# trailing_whitespace +y <- 2 +(1:10) + +# trailing_blank_lines + diff --git a/.automation/test/r/R_good_1.R b/.automation/test/r/R_good_1.R new file mode 100644 index 00000000..e6c5c41d --- /dev/null +++ b/.automation/test/r/R_good_1.R @@ -0,0 +1,48 @@ +# Each of the default linters should throw at least one lint on this file + +# assignment +# function_left_parentheses +# closed_curly +# commas +# paren_brace +f <- function(x, y = 1) { + +} + +# commented_code + +# cyclocomp +# equals_na +# infix_spaces +# line_length +# object_length +# object_name +# object_usage +# open_curly +short_snake <- function(x) { + y <- 1 + y <- y^2 + if (1 > 2 && 5 * 10 > 6 && is.na(x)) { + TRUE + } else { + FALSE + } +} + +# pipe_continuation +# seq_linter +# spaces_inside +x <- 1:10 +x[2] +seq_len(x) %>% + lapply(function(x) x * 2) %>% + head() + +# single_quotes +message("single_quotes") + +# spaces_left_parentheses +# trailing_whitespace +y <- 2 + (1:10) + +# trailing_blank_lines \ No newline at end of file diff --git a/.github/linters/.lintr b/.github/linters/.lintr new file mode 100644 index 00000000..66c5ca46 --- /dev/null +++ b/.github/linters/.lintr @@ -0,0 +1,8 @@ +# see https://github.com/jimhester/lintr#project-configuration for details +# on how to configure lintr. +# Defaults mostly adhere to: https://style.tidyverse.org/ +# +# 'object_usage_linter' runs code with eval() and is deactivated by default +# for security reasons. + +linters: with_defaults(object_usage_linter = NULL) \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 98b7a3e2..9e5150b3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,6 +15,7 @@ FROM yoheimuta/protolint:v0.26.0 as protolint FROM koalaman/shellcheck:v0.7.1 as shellcheck FROM wata727/tflint:0.18.0 as tflint FROM hadolint/hadolint:latest-alpine as dockerfile-lint +FROM assignuser/lintr-lib:latest as lintr-lib ################## # Get base image # @@ -240,6 +241,12 @@ RUN wget --tries=5 https://github.com/cvega/luarocks/archive/v3.3.1-super-linter RUN luarocks install luacheck +################# +# Install lintr # +################# +COPY --from=lintr-lib /usr/lib/R/library/ /home/r-library +RUN R -e "install.packages(list.dirs('/home/r-library',recursive = FALSE), repos = NULL, type = 'source')" + ########################################### # Load GitHub Env Vars for GitHub Actions # ########################################### @@ -294,6 +301,7 @@ ENV ACTIONS_RUNNER_DEBUG=${ACTIONS_RUNNER_DEBUG} \ VALIDATE_PYTHON=${VALIDATE_PYTHON} \ VALIDATE_PYTHON_PYLINT=${VALIDATE_PYTHON_PYLINT} \ VALIDATE_PYTHON_FLAKE8=${VALIDATE_PYTHON_FLAKE8} \ + VALIDATE_R=${VALIDATE_R} \ VALIDATE_RAKU=${VALIDATE_RAKU} \ VALIDATE_RUBY=${VALIDATE_RUBY} \ VALIDATE_STATES=${VALIDATE_STATES} \ diff --git a/README.md b/README.md index 324a5aae..fd917855 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ Developers on **GitHub** can call the **GitHub Action** to lint their code base | **PowerShell** | [PSScriptAnalyzer](https://github.com/PowerShell/Psscriptanalyzer) | | **Protocol Buffers** | [protolint](https://github.com/yoheimuta/protolint) | | **Python3** | [pylint](https://www.pylint.org/) [flake8](https://flake8.pycqa.org/en/latest/) | +| **R** | [lintr](https://github.com/jimhester/lintr) | | **Raku** | [raku](https://raku.org) | | **Ruby** | [RuboCop](https://github.com/rubocop-hq/rubocop) | | **Shell** | [Shellcheck](https://github.com/koalaman/shellcheck) | @@ -227,6 +228,7 @@ But if you wish to select or exclude specific linters, we give you full control | **VALIDATE_PYTHON_PYLINT** | `true` | Flag to enable or disable the linting process of the Python language. (Utilizing: pylint) | | **VALIDATE_PYTHON_FLAKE8** | `true` | Flag to enable or disable the linting process of the Python language. (Utilizing: flake8) | | **VALIDATE_POWERSHELL** | `true` | Flag to enable or disable the linting process of the Powershell language. | +| **VALIDATE_R** | `true` | Flag to enable or disable the linting process of the R language. | | **VALIDATE_RAKU** | `true` | Flag to enable or disable the linting process of the Raku language. | | **VALIDATE_RUBY** | `true` | Flag to enable or disable the linting process of the Ruby language. | | **VALIDATE_STATES** | `true` | Flag to enable or disable the linting process for AWS States Language. | diff --git a/TEMPLATES/.lintr b/TEMPLATES/.lintr new file mode 100644 index 00000000..66c5ca46 --- /dev/null +++ b/TEMPLATES/.lintr @@ -0,0 +1,8 @@ +# see https://github.com/jimhester/lintr#project-configuration for details +# on how to configure lintr. +# Defaults mostly adhere to: https://style.tidyverse.org/ +# +# 'object_usage_linter' runs code with eval() and is deactivated by default +# for security reasons. + +linters: with_defaults(object_usage_linter = NULL) \ No newline at end of file diff --git a/docs/disabling-linters.md b/docs/disabling-linters.md index 13db1ee2..8cf1c6f1 100644 --- a/docs/disabling-linters.md +++ b/docs/disabling-linters.md @@ -42,6 +42,7 @@ For some linters it is also possible to override rules on a case by case level w - [Protocol Buffers](#protocol-buffers) - [Python3 pylint](#python3-pylint) - [Python3 flake8](#python3-flake8) + - [R](#r) - [Raku](#raku) - [Ruby](#ruby) - [Shell](#shell) @@ -896,7 +897,39 @@ var = "terrible code down here..." ``` --- +## R +- [lintr](https://github.com/jimhester/lintr) + +### lintr Config file + +- `.github/linters/.lintr` +- You can pass multiple rules and overwrite default rules +- File should be located at: `.github/linters/.lintr` +- **Note:** The defaults adhere to the [tidyverse styleguide](https://style.tidyverse.org/) + +### lintr disable single line + +```r +1++1/3+2 # nolint +``` + +### lintr disable code block + +```r + # nolint start + hotGarbage = 1++1/3+2 + #a very long comment line + # nolint end +``` +### lintr disable entire file + +Add files to exclude into the config file as a list of filenames to exclude from linting. You can use a named item to exclude only certain lines from a file. + +```r +exclusions: list("inst/doc/creating_linters.R" = 1, "inst/example/bad.R", "tests/testthat/exclusions-test") +``` +--- ## Raku - [raku](https://raku.org)