Skip to content

Commit 5e16e3b

Browse files
Merge branch 'master' into regex-based-linter-issue-441
2 parents 83acd5c + b4e3f72 commit 5e16e3b

21 files changed

+435
-110
lines changed

.github/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.html

.github/workflows/R-CMD-check.yaml

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
on:
2+
push:
3+
branches:
4+
- main
5+
- master
6+
pull_request:
7+
branches:
8+
- main
9+
- master
10+
11+
name: R-CMD-check
12+
13+
jobs:
14+
R-CMD-check:
15+
runs-on: ${{ matrix.config.os }}
16+
17+
name: ${{ matrix.config.os }} (${{ matrix.config.r }})
18+
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
config:
23+
- {os: macOS-latest, r: 'release'}
24+
- {os: windows-latest, r: 'release'}
25+
- {os: windows-latest, r: '3.6'}
26+
- {os: ubuntu-16.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/xenial/latest", http-user-agent: "R/4.0.0 (ubuntu-16.04) R (4.0.0 x86_64-pc-linux-gnu x86_64 linux-gnu) on GitHub Actions" }
27+
- {os: ubuntu-16.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/xenial/latest"}
28+
- {os: ubuntu-16.04, r: 'oldrel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/xenial/latest"}
29+
- {os: ubuntu-16.04, r: '3.5', rspm: "https://packagemanager.rstudio.com/cran/__linux__/xenial/latest"}
30+
- {os: ubuntu-16.04, r: '3.4', rspm: "https://packagemanager.rstudio.com/cran/__linux__/xenial/latest"}
31+
- {os: ubuntu-16.04, r: '3.3', rspm: "https://packagemanager.rstudio.com/cran/__linux__/xenial/latest"}
32+
33+
env:
34+
R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
35+
RSPM: ${{ matrix.config.rspm }}
36+
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
37+
38+
steps:
39+
- uses: actions/checkout@v2
40+
41+
- uses: r-lib/actions/setup-r@v1
42+
with:
43+
r-version: ${{ matrix.config.r }}
44+
http-user-agent: ${{ matrix.config.http-user-agent }}
45+
46+
- uses: r-lib/actions/setup-pandoc@v1
47+
48+
- name: Query dependencies
49+
run: |
50+
install.packages('remotes')
51+
saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
52+
writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
53+
shell: Rscript {0}
54+
55+
- name: Cache R packages
56+
if: runner.os != 'Windows'
57+
uses: actions/cache@v2
58+
with:
59+
path: ${{ env.R_LIBS_USER }}
60+
key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }}
61+
restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-
62+
63+
- name: Install system dependencies
64+
if: runner.os == 'Linux'
65+
run: |
66+
while read -r cmd
67+
do
68+
eval sudo $cmd
69+
done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "16.04"))')
70+
71+
- name: Install dependencies
72+
run: |
73+
remotes::install_deps(dependencies = TRUE)
74+
remotes::install_cran("rcmdcheck")
75+
shell: Rscript {0}
76+
77+
- name: Session info
78+
run: |
79+
options(width = 100)
80+
pkgs <- installed.packages()[, "Package"]
81+
sessioninfo::session_info(pkgs, include_base = TRUE)
82+
shell: Rscript {0}
83+
84+
- name: Check
85+
env:
86+
_R_CHECK_CRAN_INCOMING_: false
87+
run: rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "warning", check_dir = "check")
88+
shell: Rscript {0}
89+
90+
- name: Show testthat output
91+
if: always()
92+
run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true
93+
shell: bash
94+
95+
- name: Upload check results
96+
if: failure()
97+
uses: actions/upload-artifact@main
98+
with:
99+
name: ${{ runner.os }}-r${{ matrix.config.r }}-results
100+
path: check

.github/workflows/lint.yaml

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
on:
2+
push:
3+
branches:
4+
- main
5+
- master
6+
- "**"
7+
pull_request:
8+
branches:
9+
- main
10+
- master
11+
12+
name: lint
13+
14+
jobs:
15+
lint:
16+
runs-on: macOS-latest
17+
env:
18+
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
19+
steps:
20+
- uses: actions/checkout@v2
21+
22+
- uses: r-lib/actions/setup-r@v1
23+
24+
- name: Query dependencies
25+
run: |
26+
install.packages('remotes')
27+
saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
28+
writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
29+
shell: Rscript {0}
30+
31+
- name: Cache R packages
32+
uses: actions/cache@v2
33+
with:
34+
path: ${{ env.R_LIBS_USER }}
35+
key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }}
36+
restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-
37+
38+
- name: Install dependencies
39+
run: |
40+
install.packages(c("remotes"))
41+
remotes::install_deps(dependencies = TRUE)
42+
remotes::install_github("jimhester/lintr")
43+
shell: Rscript {0}
44+
45+
- name: Lint
46+
run: lintr::lint_package()
47+
shell: Rscript {0}

.github/workflows/test-coverage.yaml

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
on:
2+
push:
3+
branches:
4+
- main
5+
- master
6+
- '**'
7+
pull_request:
8+
branches:
9+
- main
10+
- master
11+
12+
name: test-coverage
13+
14+
jobs:
15+
test-coverage:
16+
runs-on: macOS-latest
17+
env:
18+
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
19+
steps:
20+
- uses: actions/checkout@v2
21+
22+
- uses: r-lib/actions/setup-r@v1
23+
24+
- uses: r-lib/actions/setup-pandoc@v1
25+
26+
- name: Query dependencies
27+
run: |
28+
install.packages('remotes')
29+
saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
30+
writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
31+
shell: Rscript {0}
32+
33+
- name: Cache R packages
34+
uses: actions/cache@v2
35+
with:
36+
path: ${{ env.R_LIBS_USER }}
37+
key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }}
38+
restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-
39+
40+
- name: Install dependencies
41+
run: |
42+
install.packages(c("remotes"))
43+
remotes::install_deps(dependencies = TRUE)
44+
remotes::install_cran("covr")
45+
shell: Rscript {0}
46+
47+
- name: Test coverage
48+
run: covr::codecov()
49+
shell: Rscript {0}

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
.Rhistory
33
.RData
44
.Ruserdata
5+
.idea
56
bad.R
67
script.R

.lintr

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
linters: with_defaults( # The following TODOs are part of an effort to have {lintr} lint-free (#584)
22
line_length_linter = line_length_linter(120),
33
infix_spaces_linter = NULL, # TODO enable (#594)
4-
commented_code_linter = NULL, # TODO enable (#595)
54
cyclocomp_linter = cyclocomp_linter(29), # TODO reduce to 15
65
object_name_linter = NULL, # TODO enable (#597)
76
spaces_inside_linter = NULL, # TODO enable (#598)

.travis.yml

-25
This file was deleted.

NEWS.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# lintr (development version)
22

3+
* Switched CI from Travis to GitHub Actions, using the full tidyverse recommended R CMD check. Code coverage and linting are implemented using separate GitHub Actions workflows (#572, @dragosmg)
34
* `save_cache` will now recursively create the cache directory; this avoids errors that could arise if any parent directories do not exist (#60, @dankessler).
45
* `extract_r_source` handles Rmd containing unevaluated code blocks with named
56
format specifiers (#472, @russHyde)
@@ -17,6 +18,7 @@
1718
and support excluding entire directories (#158, #438, @AshesITR)
1819
* `object_name_linter()` now excludes special R hook functions such as `.onLoad` (#500, #614, @AshesITR)
1920
* `equals_na_linter()` now lints `x != NA` and `NA == x`, and skips usages in comments (#545, @michaelchirico)
21+
* Malformed Rmd files now cause a lint instead of an error (#571, #575, @AshesITR)
2022
* `paren_brace_linter` and `no_tab_linter` also use more reliable matching (e.g.,
2123
excluding matches found in comments; #441 and #545, @russHyde)
2224

R/actions.R

-31
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,3 @@ github_actions_log_lints <- function(lints) {
1111
)
1212
}
1313
}
14-
15-
16-
rstudio_source_markers <- function(lints) {
17-
18-
# package path will be NULL unless it is a relative path
19-
package_path <- attr(lints, "path")
20-
21-
# generate the markers
22-
markers <- lapply(lints, function(x) {
23-
filename <- if (!is.null(package_path)) {
24-
file.path(package_path, x$filename)
25-
} else {
26-
x$filename
27-
}
28-
29-
marker <- list()
30-
marker$type <- x$type
31-
marker$file <- filename
32-
marker$line <- x$line_number
33-
marker$column <- x$column_number
34-
marker$message <- x$message
35-
marker
36-
})
37-
38-
# request source markers
39-
rstudioapi::callFun("sourceMarkers",
40-
name = "lintr",
41-
markers = markers,
42-
basePath = package_path,
43-
autoSelect = "first")
44-
}

R/extract.R

+19-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
# content is the file content from readLines
2-
extract_r_source <- function(filename, lines) {
2+
extract_r_source <- function(filename, lines, error = identity) {
33
pattern <- get_knitr_pattern(filename, lines)
44
if (is.null(pattern$chunk.begin) || is.null(pattern$chunk.end)) {
55
return(lines)
66
}
77

8-
chunks <- get_chunk_positions(pattern = pattern, lines = lines)
8+
chunks <- tryCatch(get_chunk_positions(pattern = pattern, lines = lines), error = error)
9+
if (inherits(chunks, "error") || inherits(chunks, "lint")) {
10+
assign("e", chunks, envir = parent.frame())
11+
# error, so return empty code
12+
return(character())
13+
}
914

1015
# no chunks found, so just return the lines
1116
if (length(chunks[["starts"]]) == 0 || length(chunks[["ends"]]) == 0) {
@@ -67,15 +72,22 @@ filter_chunk_end_positions <- function(starts, ends) {
6772
if (length_difference == 0 && all(ends > starts)) {
6873
return(ends)
6974
}
70-
if (length_difference < 0) {
71-
stop("Malformed file!", call. = FALSE)
72-
}
7375

7476
positions <- sort(c(starts = starts, ends = ends))
7577
code_start_indexes <- grep("starts", names(positions))
76-
code_ends <- positions[1 + code_start_indexes]
7778

78-
stopifnot(all(grepl("ends", names(code_ends))))
79+
code_ends <- positions[pmin(1 + code_start_indexes, length(positions))]
80+
81+
bad_end_indexes <- grep("starts", names(code_ends), fixed = TRUE)
82+
if (length(bad_end_indexes)) {
83+
bad_start_positions <- positions[code_start_indexes[bad_end_indexes]]
84+
# This error message is formatted like a parse error
85+
stop(sprintf(
86+
"<rmd>:%1$d:1: Missing chunk end for chunk (maybe starting at line %1$d).\n",
87+
bad_start_positions[1L]
88+
), call. = FALSE)
89+
}
90+
7991
code_ends
8092
}
8193

0 commit comments

Comments
 (0)