diff --git a/.github/.gitignore b/.github/.gitignore index f57dbed16..5dd2c8dae 100644 --- a/.github/.gitignore +++ b/.github/.gitignore @@ -1,3 +1,4 @@ *.html R-version depends.rds +/pkg.lock diff --git a/.github/workflows/R-CMD-check-dev.yaml b/.github/workflows/R-CMD-check-dev.yaml index a819e0b3f..2311f1523 100644 --- a/.github/workflows/R-CMD-check-dev.yaml +++ b/.github/workflows/R-CMD-check-dev.yaml @@ -19,152 +19,19 @@ jobs: name: Collect deps - env: - R_REMOTES_NO_ERRORS_FROM_WARNINGS: true - RSPM: https://packagemanager.rstudio.com/cran/__linux__/bionic/latest - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - # prevent rgl issues because no X11 display is available - RGL_USE_NULL: true - # Begin custom: env vars - # End custom: env vars - steps: - - name: Check rate limits - run: | - curl -s --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit - shell: bash - - uses: actions/checkout@v2 - - uses: r-lib/actions/setup-r@v1 + - uses: ./.github/workflows/rate-limit + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: r-lib/actions/setup-r@v2 with: install-r: false - id: set-matrix - run: | - # Determine package dependencies - # From remotes - read_dcf <- function(path) { - fields <- colnames(read.dcf(path)) - as.list(read.dcf(path, keep.white = fields)[1, ]) - } - - re_match <- function(text, pattern, perl = TRUE, ...) { - - stopifnot(is.character(pattern), length(pattern) == 1, !is.na(pattern)) - text <- as.character(text) - - match <- regexpr(pattern, text, perl = perl, ...) - - start <- as.vector(match) - length <- attr(match, "match.length") - end <- start + length - 1L - - matchstr <- substring(text, start, end) - matchstr[ start == -1 ] <- NA_character_ - - res <- data.frame( - stringsAsFactors = FALSE, - .text = text, - .match = matchstr - ) - - if (!is.null(attr(match, "capture.start"))) { - - gstart <- attr(match, "capture.start") - glength <- attr(match, "capture.length") - gend <- gstart + glength - 1L - - groupstr <- substring(text, gstart, gend) - groupstr[ gstart == -1 ] <- NA_character_ - dim(groupstr) <- dim(gstart) - - res <- cbind(groupstr, res, stringsAsFactors = FALSE) - } - - names(res) <- c(attr(match, "capture.names"), ".text", ".match") - class(res) <- c("tbl_df", "tbl", class(res)) - res - } - - dev_split_ref <- function(x) { - re_match(x, "^(?[^@#]+)(?[@#].*)?$") - } - - has_dev_dep <- function(package) { - cran_url <- "https://cloud.r-project.org" - - refs <- dev_split_ref(package) - url <- file.path(cran_url, "web", "packages", refs[["pkg"]], "DESCRIPTION") - - f <- tempfile() - on.exit(unlink(f)) - - utils::download.file(url, f) - desc <- read_dcf(f) - - url_fields <- c(desc$URL, desc$BugReports) - - if (length(url_fields) == 0) { - return(FALSE) - } - - pkg_urls <- unlist(strsplit(url_fields, "[[:space:]]*,[[:space:]]*")) - - # Remove trailing "/issues" from the BugReports URL - pkg_urls <- sub("/issues$", "", pkg_urls) - - valid_domains <- c("github[.]com", "gitlab[.]com", "bitbucket[.]org") - - parts <- - re_match(pkg_urls, - sprintf("^https?://(?%s)/(?%s)/(?%s)(?:/(?%s))?", - domain = paste0(valid_domains, collapse = "|"), - username = "[^/]+", - repo = "[^/@#]+", - subdir = "[^/@$ ]+" - ) - )[c("domain", "username", "repo", "subdir")] - - # Remove cases which don't match and duplicates - - parts <- unique(stats::na.omit(parts)) - - nrow(parts) == 1 - } - - if (!requireNamespace("desc", quietly = TRUE)) { - install.packages("desc") - } - - deps_df <- desc::desc_get_deps() - deps_df <- deps_df[deps_df$type %in% c("Depends", "Imports", "LinkingTo", "Suggests"), ] - - packages <- sort(deps_df$package) - packages <- intersect(packages, rownames(available.packages())) - - valid_dev_dep <- vapply(packages, has_dev_dep, logical(1)) - - # https://github.com/r-lib/remotes/issues/576 - valid_dev_dep[packages %in% c("igraph", "duckdb", "logging")] <- FALSE - - deps <- packages[valid_dev_dep] - if (any(!valid_dev_dep)) { - msg <- paste0( - "Could not determine development repository for packages: ", - paste(packages[!valid_dev_dep], collapse = ", ") - ) - writeLines(paste0("::warning::", msg)) - } - - json <- paste0( - '{"package":[', - paste0('"', deps, '"', collapse = ","), - ']}' - ) - writeLines(json) - writeLines(paste0("::set-output name=matrix::", json)) - shell: Rscript {0} + uses: ./.github/workflows/dep-matrix check-matrix: runs-on: ubuntu-18.04 @@ -195,72 +62,24 @@ jobs: fail-fast: false matrix: ${{fromJson(needs.matrix.outputs.matrix)}} - env: - R_REMOTES_NO_ERRORS_FROM_WARNINGS: true - RSPM: https://packagemanager.rstudio.com/cran/__linux__/bionic/latest - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - # prevent rgl issues because no X11 display is available - RGL_USE_NULL: true - # Begin custom: env vars - # End custom: env vars - steps: - - name: Check rate limits - run: | - curl -s --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit - shell: bash - - uses: actions/checkout@v2 - # Begin custom: before install - # End custom: before install + - uses: ./.github/workflows/custom/before-install - - uses: r-lib/actions/setup-r@v1 + - uses: ./.github/workflows/install with: install-r: false + cache-version: rcc-dev-${{ matrix.package }}-1 + needs: check + extra-packages: "any::rcmdcheck any::remotes" + token: ${{ secrets.GITHUB_TOKEN }} - - uses: r-lib/actions/setup-pandoc@v1 - - - name: Install remotes - run: | - if (!requireNamespace("curl", quietly = TRUE)) install.packages("curl") - if (!requireNamespace("remotes", quietly = TRUE)) install.packages("remotes") - shell: Rscript {0} - - - name: Prepare cache keys - if: runner.os != 'Windows' - id: date - run: echo "::set-output name=date::$(date -Ihours)" - - - name: Cache R packages - if: runner.os != 'Windows' - uses: actions/cache@v2 - with: - path: ${{ env.R_LIBS_USER }} - key: ubuntu-20.04-r-dev-release-${{ matrix.package }}-1-${{steps.date.outputs.date}} - restore-keys: ubuntu-20.04-r-dev-release-${{ matrix.package }}-1- - - - name: Install system dependencies - if: runner.os == 'Linux' - run: | - sudo apt-get update -y - while read -r cmd - do - eval sudo $cmd - done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "18.04"))') - - - name: Add fake qpdf and checkbashisms - if: runner.os == 'Linux' - run: | - sudo ln -s $(which true) /usr/local/bin/qpdf - sudo ln -s $(which true) /usr/local/bin/checkbashisms - - - name: Install dependencies + - name: Install dev version of ${{ matrix.package }} + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} run: | - remotes::install_deps(dependencies = TRUE) - update.packages(.libPaths()[[1]], ask = FALSE) remotes::install_dev("${{ matrix.package }}", "https://cloud.r-project.org", upgrade = "always") - remotes::install_cran("rcmdcheck") shell: Rscript {0} - name: Session info @@ -271,37 +90,8 @@ jobs: sessioninfo::session_info(pkgs, include_base = TRUE) shell: Rscript {0} - # Begin custom: after install - # End custom: after install + - uses: ./.github/workflows/custom/after-install - - name: Check - env: - _R_CHECK_CRAN_INCOMING_: false - _R_CHECK_SYSTEM_CLOCK_: false - _R_CHECK_FUTURE_FILE_TIMESTAMPS_: false - run: | - options(crayon.enabled = TRUE) - error_on <- "note" - # Begin custom: rcmdcheck error_on - # End custom: rcmdcheck error_on - rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = error_on, check_dir = "check") - shell: Rscript {0} - - - name: Show test output - if: always() - run: | - find check -name '*.Rout*' -exec head -n 1000000 '{}' \; || true - shell: bash - - - name: Upload check results - if: failure() - uses: actions/upload-artifact@main + - uses: ./.github/workflows/check with: - name: ${{ matrix.package }}-results - path: check - - - name: Check rate limits - if: always() - run: | - curl -s --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit - shell: bash + results: ${{ matrix.package }} diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index d15825871..ac95cc958 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -1,176 +1,205 @@ -# NOTE: This workflow is overkill for most R packages -# check-standard.yaml is likely a better choice -# usethis::use_github_action("check-standard") will install it. +# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help # -# For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag. -# https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions +# NOTE: This workflow is overkill for most R packages and +# check-standard.yaml is likely a better choice. +# usethis::use_github_action("check-standard") will install it. on: push: branches: - main - master - - "r-*" pull_request: branches: - main - master - - "r-*" schedule: - cron: '10 0 * * *' name: rcc jobs: - R-CMD-check: - runs-on: ${{ matrix.config.os }}${{ matrix.config.os-version }} + rcc-smoke: + runs-on: ubuntu-latest + outputs: + sha: ${{ steps.commit.outputs.sha }} + + name: "Smoke test: stock R" + + # Begin custom: services + # End custom: services + + steps: + - uses: actions/checkout@v2 + + - uses: ./.github/workflows/rate-limit + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: ./.github/workflows/git-identity + + - uses: ./.github/workflows/custom/before-install + + - uses: ./.github/workflows/install + with: + token: ${{ secrets.GITHUB_TOKEN }} + install-r: false + cache-version: rcc-smoke-1 + needs: check + extra-packages: any::rcmdcheck any::roxygen2 any::styler + + - uses: ./.github/workflows/custom/after-install + + - uses: ./.github/workflows/style + + - uses: ./.github/workflows/roxygenize - name: ${{ matrix.config.os }}${{ matrix.config.os-version }} (${{ matrix.config.r }}) ${{ matrix.config.desc }} + - id: commit + uses: ./.github/workflows/commit + + - uses: ./.github/workflows/check + with: + results: ${{ runner.os }}-smoke-test + + # Runs in a separate workflow, because it's using dev pkgdown + # which might bring in other dev dependencies + pkgdown: + needs: rcc-smoke + + runs-on: ubuntu-latest + + name: "pkgdown" + + # Begin custom: services + # End custom: services + + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ needs.rcc-smoke.outputs.sha }} + + - uses: ./.github/workflows/rate-limit + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: ./.github/workflows/git-identity + if: github.event_name == 'push' + + - uses: ./.github/workflows/custom/before-install + + - uses: ./.github/workflows/install + with: + token: ${{ secrets.GITHUB_TOKEN }} + install-r: false + cache-version: pkgdown-1 + needs: website + extra-packages: r-lib/pkgdown local::. + + - uses: ./.github/workflows/custom/after-install + + - uses: ./.github/workflows/pkgdown-build + if: github.event_name != 'push' + + - uses: ./.github/workflows/pkgdown-deploy + if: github.event_name == 'push' + + # Windows checks can be run in parallel and independently + # when they alone take as long as the smoke and full tests combined. + # To achieve this, remove the "needs:" element below. + rcc-windows: + # Begin custom: early run + needs: rcc-smoke + # End custom: early run + + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) ${{ matrix.config.desc }} # Begin custom: services # End custom: services strategy: fail-fast: false - # Ensure that the "cancel" workflow gets a chance to run quickly, even if we just pushed - # Need to figure out how to smoke-test - max-parallel: 5 matrix: config: - - { os: macOS-latest, r: 'release' } - - { os: windows-latest, r: 'release', rspm: "https://packagemanager.rstudio.com/all/latest" } - - { os: windows-latest, r: 'oldrel', rspm: "https://packagemanager.rstudio.com/all/latest" } - - { os: ubuntu-, os-version: 20.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest" } - - { os: ubuntu-, os-version: 18.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest" } - - { os: ubuntu-, os-version: 18.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest", http-user-agent: "R/4.0.0 (ubuntu-18.04) R (4.0.0 x86_64-pc-linux-gnu x86_64 linux-gnu) on GitHub Actions" } - - { os: ubuntu-, os-version: 18.04, r: 'oldrel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest" } + - {os: windows-latest, r: 'release'} + # Use 3.6 to trigger usage of RTools35 + - {os: windows-latest, r: '3.6'} + + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ needs.rcc-smoke.outputs.sha }} + + - uses: ./.github/workflows/custom/before-install + + - uses: ./.github/workflows/install + with: + r-version: ${{ matrix.config.r }} + cache-version: rcc-main-1 + token: ${{ secrets.GITHUB_TOKEN }} + needs: check + + - uses: ./.github/workflows/custom/after-install + + - uses: ./.github/workflows/check + with: + results: ${{ runner.os }}-r${{ matrix.config.r }} + + rcc-full: + needs: rcc-smoke + + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) ${{ matrix.config.desc }} + + # Begin custom: services + # End custom: services + + strategy: + fail-fast: false + matrix: + config: + - {os: macOS-latest, r: 'release'} + + - {os: ubuntu-20.04, r: 'release'} + + # Use older ubuntu to maximise backward compatibility + - {os: ubuntu-18.04, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-18.04, r: 'release', covr: true, desc: 'with covr'} + - {os: ubuntu-18.04, r: 'oldrel-1'} # Begin custom: R 3.6 - - {os: ubuntu-, os-version: 18.04, r: '3.6', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} + - {os: ubuntu-18.04, r: 'oldrel-2'} # End custom: R 3.6 # Begin custom: R 3.5 - - {os: ubuntu-, os-version: 18.04, r: '3.5', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} + - {os: ubuntu-18.04, r: 'oldrel-3'} # End custom: R 3.5 # Begin custom: R 3.4 - - {os: ubuntu-, os-version: 18.04, r: '3.4', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} + - {os: ubuntu-18.04, r: 'oldrel-4'} # End custom: R 3.4 # Begin custom: matrix elements # End custom: matrix elements - env: - R_REMOTES_NO_ERRORS_FROM_WARNINGS: true - RSPM: ${{ matrix.config.rspm }} - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - # prevent rgl issues because no X11 display is available - RGL_USE_NULL: true - # Begin custom: env vars - # End custom: env vars steps: - - name: Check rate limits - run: | - curl -s --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit - shell: bash - - uses: actions/checkout@v2 + with: + ref: ${{ needs.rcc-smoke.outputs.sha }} - # Begin custom: before install - # FIXME: Remove with cran units - - name: Install system dependencies - if: runner.os == 'macOS' - run: | - brew install udunits - # End custom: before install + - uses: ./.github/workflows/custom/before-install - - uses: r-lib/actions/setup-r@v1 + - uses: ./.github/workflows/install with: r-version: ${{ matrix.config.r }} - http-user-agent: ${{ matrix.config.http-user-agent }} - - - uses: r-lib/actions/setup-pandoc@v1 - - - name: Install remotes - run: | - if (!requireNamespace("curl", quietly = TRUE)) install.packages("curl") - if (!requireNamespace("remotes", quietly = TRUE)) install.packages("remotes") - shell: Rscript {0} - - - name: Query dependencies - if: runner.os != 'Windows' - run: | - saveRDS(remotes::dev_package_deps(dependencies = TRUE, type = .Platform$pkgType), ".github/depends.Rds", version = 2) - writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") - shell: Rscript {0} - - - name: Restore R package cache - if: runner.os != 'Windows' - uses: actions/cache@v2 - with: - path: ${{ env.R_LIBS_USER }} - key: ${{ matrix.config.os }}${{ matrix.config.os-version }}-${{ hashFiles('.github/R-version') }}-2-${{ hashFiles('.github/depends.Rds') }} - restore-keys: ${{ matrix.config.os }}${{ matrix.config.os-version }}-${{ hashFiles('.github/R-version') }}-2- - - - name: Install system dependencies - if: runner.os == 'Linux' - run: | - sudo apt-get update -y - while read -r cmd - do - eval sudo $cmd - done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "${{matrix.config.os-version}}"))') - - - name: Add fake qpdf and checkbashisms - if: runner.os == 'Linux' - run: | - sudo ln -s $(which true) /usr/local/bin/qpdf - sudo ln -s $(which true) /usr/local/bin/checkbashisms - - - name: Install dependencies - run: | - remotes::install_deps(dependencies = TRUE, type = .Platform$pkgType) - remotes::install_cran("rcmdcheck") - shell: Rscript {0} - - - name: Session info - run: | - options(width = 100) - if (!requireNamespace("sessioninfo", quietly = TRUE)) install.packages("sessioninfo") - pkgs <- installed.packages()[, "Package"] - sessioninfo::session_info(pkgs, include_base = TRUE) - shell: Rscript {0} - - # Begin custom: after install - # End custom: after install - - - name: Check - env: - _R_CHECK_CRAN_INCOMING_: false - _R_CHECK_SYSTEM_CLOCK_: false - _R_CHECK_FUTURE_FILE_TIMESTAMPS_: false - run: | - options(crayon.enabled = TRUE) - error_on <- "note" - # Begin custom: rcmdcheck error_on - # End custom: rcmdcheck error_on - rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = error_on, check_dir = "check") - shell: Rscript {0} - - - name: Show test output - if: always() - run: | - find check -name '*.Rout*' -exec head -n 1000000 '{}' \; || true - shell: bash - - - name: Upload check results - if: failure() - uses: actions/upload-artifact@main + cache-version: rcc-main-1 + token: ${{ secrets.GITHUB_TOKEN }} + needs: check + + - uses: ./.github/workflows/custom/after-install + + - uses: ./.github/workflows/check with: - name: ${{ runner.os }}-r${{ matrix.config.r }}-results - path: check - - - name: Check rate limits - if: always() - run: | - curl -s --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit - shell: bash + results: ${{ runner.os }}-r${{ matrix.config.r }} diff --git a/.github/workflows/check/action.yml b/.github/workflows/check/action.yml new file mode 100644 index 000000000..0bd9f7463 --- /dev/null +++ b/.github/workflows/check/action.yml @@ -0,0 +1,35 @@ +name: 'Actions to check an R package' +inputs: + results: + description: Slug for check results + required: true + +runs: + using: "composite" + steps: + - uses: r-lib/actions/check-r-package@v2 + with: + error-on: ${{ env.RCMDCHECK_ERROR_ON || '"note"' }} + + - name: Run coverage check + if: ${{ matrix.config.covr }} + run: | + if (dir.exists("tests/testthat")) { + covr::codecov() + } else { + message("No tests found, coverage not tested.") + } + shell: Rscript {0} + + - name: Show test output + if: always() + run: | + find check -name '*.Rout*' -exec head -n 1000000 '{}' \; || true + shell: bash + + - name: Upload check results + if: failure() + uses: actions/upload-artifact@main + with: + name: ${{ inputs.results }}-results + path: check diff --git a/.github/workflows/commit/action.yml b/.github/workflows/commit/action.yml new file mode 100644 index 000000000..8e6e77b36 --- /dev/null +++ b/.github/workflows/commit/action.yml @@ -0,0 +1,29 @@ +name: 'Action to commit changes to the repository' +outputs: + sha: + description: "SHA of generated commit" + value: ${{ steps.commit.outputs.sha }} + +runs: + using: "composite" + steps: + - name: Commit if changed + id: commit + run: | + set -x + if [ -n "$(git status --porcelain)" ]; then + echo "Changed" + git fetch + if [ -n "${GITHUB_HEAD_REF}" ]; then + git add . + git stash save + git switch ${GITHUB_HEAD_REF} + git merge origin/${GITHUB_BASE_REF} --no-edit + git stash pop + fi + git add . + git commit -m "Auto-update from GitHub Actions"$'\n'$'\n'"Run: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + git push + echo ::set-output name=sha::$(git rev-parse HEAD) + fi + shell: bash diff --git a/.github/workflows/custom/after-install/action.yml b/.github/workflows/custom/after-install/action.yml new file mode 100644 index 000000000..e64eac0ac --- /dev/null +++ b/.github/workflows/custom/after-install/action.yml @@ -0,0 +1,9 @@ +name: 'Custom steps to run after R packages are installed' + +runs: + using: "composite" + steps: + - name: Empty + run: | + true + shell: bash diff --git a/.github/workflows/custom/before-install/action.yml b/.github/workflows/custom/before-install/action.yml new file mode 100644 index 000000000..b81a0e299 --- /dev/null +++ b/.github/workflows/custom/before-install/action.yml @@ -0,0 +1,12 @@ +name: 'Custom steps to run before R packages are installed' + +runs: + using: "composite" + steps: + # FIXME: Remove with cran units > 0.7.2 + - name: Install system dependencies + if: runner.os == 'macOS' + run: | + brew install udunits + shell: bash + diff --git a/.github/workflows/dep-matrix/action.yml b/.github/workflows/dep-matrix/action.yml new file mode 100644 index 000000000..64cafbc85 --- /dev/null +++ b/.github/workflows/dep-matrix/action.yml @@ -0,0 +1,134 @@ +name: 'Actions to compute a matrix with all dependent packages' +outputs: + matrix: + description: "Generated matrix" + value: ${{ steps.set-matrix.outputs.matrix }} + +runs: + using: "composite" + steps: + - id: set-matrix + run: | + # Determine package dependencies + # From remotes + read_dcf <- function(path) { + fields <- colnames(read.dcf(path)) + as.list(read.dcf(path, keep.white = fields)[1, ]) + } + + re_match <- function(text, pattern, perl = TRUE, ...) { + + stopifnot(is.character(pattern), length(pattern) == 1, !is.na(pattern)) + text <- as.character(text) + + match <- regexpr(pattern, text, perl = perl, ...) + + start <- as.vector(match) + length <- attr(match, "match.length") + end <- start + length - 1L + + matchstr <- substring(text, start, end) + matchstr[ start == -1 ] <- NA_character_ + + res <- data.frame( + stringsAsFactors = FALSE, + .text = text, + .match = matchstr + ) + + if (!is.null(attr(match, "capture.start"))) { + + gstart <- attr(match, "capture.start") + glength <- attr(match, "capture.length") + gend <- gstart + glength - 1L + + groupstr <- substring(text, gstart, gend) + groupstr[ gstart == -1 ] <- NA_character_ + dim(groupstr) <- dim(gstart) + + res <- cbind(groupstr, res, stringsAsFactors = FALSE) + } + + names(res) <- c(attr(match, "capture.names"), ".text", ".match") + class(res) <- c("tbl_df", "tbl", class(res)) + res + } + + dev_split_ref <- function(x) { + re_match(x, "^(?[^@#]+)(?[@#].*)?$") + } + + has_dev_dep <- function(package) { + cran_url <- "https://cloud.r-project.org" + + refs <- dev_split_ref(package) + url <- file.path(cran_url, "web", "packages", refs[["pkg"]], "DESCRIPTION") + + f <- tempfile() + on.exit(unlink(f)) + + utils::download.file(url, f) + desc <- read_dcf(f) + + url_fields <- c(desc$URL, desc$BugReports) + + if (length(url_fields) == 0) { + return(FALSE) + } + + pkg_urls <- unlist(strsplit(url_fields, "[[:space:]]*,[[:space:]]*")) + + # Remove trailing "/issues" from the BugReports URL + pkg_urls <- sub("/issues$", "", pkg_urls) + + valid_domains <- c("github[.]com", "gitlab[.]com", "bitbucket[.]org") + + parts <- + re_match(pkg_urls, + sprintf("^https?://(?%s)/(?%s)/(?%s)(?:/(?%s))?", + domain = paste0(valid_domains, collapse = "|"), + username = "[^/]+", + repo = "[^/@#]+", + subdir = "[^/@$ ]+" + ) + )[c("domain", "username", "repo", "subdir")] + + # Remove cases which don't match and duplicates + + parts <- unique(stats::na.omit(parts)) + + nrow(parts) == 1 + } + + if (!requireNamespace("desc", quietly = TRUE)) { + install.packages("desc") + } + + deps_df <- desc::desc_get_deps() + deps_df <- deps_df[deps_df$type %in% c("Depends", "Imports", "LinkingTo", "Suggests"), ] + + packages <- sort(deps_df$package) + packages <- intersect(packages, rownames(available.packages())) + + valid_dev_dep <- vapply(packages, has_dev_dep, logical(1)) + + # https://github.com/r-lib/remotes/issues/576 + valid_dev_dep[packages %in% c("igraph", "duckdb", "logging")] <- FALSE + + deps <- packages[valid_dev_dep] + if (any(!valid_dev_dep)) { + msg <- paste0( + "Could not determine development repository for packages: ", + paste(packages[!valid_dev_dep], collapse = ", ") + ) + writeLines(paste0("::warning::", msg)) + } + + json <- paste0( + '{"package":[', + paste0('"', deps, '"', collapse = ","), + ']}' + ) + writeLines(json) + writeLines(paste0("::set-output name=matrix::", json)) + shell: Rscript {0} diff --git a/.github/workflows/git-identity/action.yml b/.github/workflows/git-identity/action.yml new file mode 100644 index 000000000..7741d93ea --- /dev/null +++ b/.github/workflows/git-identity/action.yml @@ -0,0 +1,11 @@ +name: 'Actions to set up a Git identity' + +runs: + using: "composite" + steps: + - name: Configure Git identity + run: | + env | sort + git config --local user.name "$GITHUB_ACTOR" + git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" + shell: bash diff --git a/.github/workflows/install/action.yml b/.github/workflows/install/action.yml new file mode 100644 index 000000000..eb6fcf107 --- /dev/null +++ b/.github/workflows/install/action.yml @@ -0,0 +1,76 @@ +name: 'Actions to run for installing R packages' +inputs: + token: + description: GitHub token, set to secrets.GITHUB_TOKEN + required: true + r-version: + description: Passed on to r-lib/actions/setup-r@v2 + required: false + default: release + install-r: + description: Passed on to r-lib/actions/setup-r@v2 + required: false + default: true + needs: + description: Passed on to r-lib/actions/setup-r-dependencies@v2 + required: false + default: '' + extra-packages: + description: Passed on to r-lib/actions/setup-r-dependencies@v2 + required: false + default: any::rcmdcheck + cache-version: + description: Passed on to r-lib/actions/setup-r-dependencies@v2 + required: false + default: 1 + +runs: + using: "composite" + steps: + - name: Set environment variables + run: | + echo "R_REMOTES_NO_ERRORS_FROM_WARNINGS=true" | tee -a $GITHUB_ENV + echo "R_KEEP_PKG_SOURCE=yes" | tee -a $GITHUB_ENV + echo "_R_CHECK_SYSTEM_CLOCK_=false" | tee -a $GITHUB_ENV + echo "_R_CHECK_FUTURE_FILE_TIMESTAMPS_=false" | tee -a $GITHUB_ENV + # prevent rgl issues because no X11 display is available + echo "RGL_USE_NULL=true" | tee -a $GITHUB_ENV + shell: bash + + - name: Update apt + if: runner.os == 'Linux' + run: | + sudo apt-get update + shell: bash + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ inputs.r-version }} + install-r: ${{ inputs.install-r }} + http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + env: + GITHUB_PAT: ${{ inputs.token }} + with: + needs: ${{ inputs.needs }} + extra-packages: ${{ inputs.extra-packages }} ${{ matrix.config.covr && 'any::covr' }} + cache-version: ${{ inputs.cache-version }} + + - name: Add pkg.lock to .gitignore + run: | + set -x + if ! [ -f .github/.gitignore ] || [ -z "$(grep '^/pkg.lock$' .github/.gitignore)" ]; then + echo /pkg.lock >> .github/.gitignore + fi + shell: bash + + - name: Add fake qpdf and checkbashisms + if: runner.os == 'Linux' + run: | + sudo ln -s $(which true) /usr/local/bin/qpdf + sudo ln -s $(which true) /usr/local/bin/checkbashisms + shell: bash diff --git a/.github/workflows/pkgdown-build/action.yml b/.github/workflows/pkgdown-build/action.yml new file mode 100644 index 000000000..e9f0e7f38 --- /dev/null +++ b/.github/workflows/pkgdown-build/action.yml @@ -0,0 +1,9 @@ +name: 'Action to build a pkgdown website' + +runs: + using: "composite" + steps: + - name: Build site + run: | + pkgdown::build_site() + shell: Rscript {0} diff --git a/.github/workflows/pkgdown-deploy/action.yml b/.github/workflows/pkgdown-deploy/action.yml new file mode 100644 index 000000000..0e385df23 --- /dev/null +++ b/.github/workflows/pkgdown-deploy/action.yml @@ -0,0 +1,9 @@ +name: 'Action to deploy a pkgdown website' + +runs: + using: "composite" + steps: + - name: Deploy site + run: | + pkgdown::deploy_to_branch(new_process = FALSE) + shell: Rscript {0} diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 2ef0bdf5e..64db3bee8 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -1,148 +1,47 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Also included in R-CMD-check.yaml, this workflow only listens to pushes to branches +# that start with "docs*" on: push: branches: - - master - - main - - "docs*" - - "cran-*" - - "r-*" - tags: - - "v*" - pull_request: - branches: - - main - - master - - "r-*" - schedule: - - cron: '20 0 * * *' + - "docs*" + - "cran-*" name: pkgdown jobs: pkgdown: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest + + name: "pkgdown" # Begin custom: services # End custom: services - env: - R_REMOTES_NO_ERRORS_FROM_WARNINGS: true - RSPM: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest" - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - # prevent rgl issues because no X11 display is available - RGL_USE_NULL: true - # Begin custom: env vars - # End custom: env vars steps: - - name: Check rate limits - run: | - curl -s --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit - shell: bash - - uses: actions/checkout@v2 - - name: Install pkgdown sysdeps - if: runner.os == 'Linux' - env: - RHUB_PLATFORM: linux-x86_64-ubuntu-gcc - run: | - # Needed because of install-r: false - sudo apt-get update - # For some reason harfbuzz and gert are installed from source and needs this - sudo apt-get install -y libharfbuzz-dev libfribidi-dev libgit2-dev + - uses: ./.github/workflows/rate-limit + with: + token: ${{ secrets.GITHUB_TOKEN }} - - name: Configure Git identity + - uses: ./.github/workflows/git-identity if: github.event_name == 'push' - run: | - env | sort - git config --local user.name "$GITHUB_ACTOR" - git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" - shell: bash - # Begin custom: before install - # End custom: before install + - uses: ./.github/workflows/custom/before-install - - uses: r-lib/actions/setup-r@v1 + - uses: ./.github/workflows/install with: + token: ${{ secrets.GITHUB_TOKEN }} install-r: false + cache-version: pkgdown-1 + needs: website + extra-packages: r-lib/pkgdown local::. - - uses: r-lib/actions/setup-pandoc@v1 - - - name: Install remotes - run: | - if (!requireNamespace("curl", quietly = TRUE)) install.packages("curl") - if (!requireNamespace("remotes", quietly = TRUE)) install.packages("remotes") - shell: Rscript {0} - - - name: Query dependencies - if: runner.os != 'Windows' - run: | - saveRDS(remotes::dev_package_deps(dependencies = TRUE, type = .Platform$pkgType), ".github/depends.Rds", version = 2) - writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") - shell: Rscript {0} - - - name: Restore R package cache - if: runner.os != 'Windows' - uses: actions/cache@v2 - with: - path: ${{ env.R_LIBS_USER }} - key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} - restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- - - - name: Install system dependencies - if: runner.os == 'Linux' - run: | - sudo apt-get update -y - while read -r cmd - do - eval sudo $cmd - done < <(Rscript -e 'req <- remotes::system_requirements("ubuntu", "18.04"); if (length(req) > 0) cat(req, sep = "\n")') + - uses: ./.github/workflows/custom/after-install - - name: Add fake qpdf and checkbashisms - if: runner.os == 'Linux' - run: | - sudo ln -s $(which true) /usr/local/bin/qpdf - sudo ln -s $(which true) /usr/local/bin/checkbashisms - - - name: Install dependencies - run: | - remotes::install_deps(dependencies = TRUE, type = .Platform$pkgType) - remotes::install_github("r-lib/pkgdown") - # Begin custom: dep install - # End custom: dep install - shell: Rscript {0} - - # Begin custom: install - # End custom: install - - - name: Session info - run: | - options(width = 100) - if (!requireNamespace("sessioninfo", quietly = TRUE)) install.packages("sessioninfo") - pkgs <- installed.packages()[, "Package"] - sessioninfo::session_info(pkgs, include_base = TRUE) - shell: Rscript {0} - - # Begin custom: after install - # End custom: after install - - - name: Install package - run: R CMD INSTALL . --with-keep.source --with-keep.parse.data - - - name: Deploy package - if: github.event_name == 'push' - run: | - pkgdown::deploy_to_branch(new_process = FALSE) - shell: Rscript {0} - - - name: Build site + - uses: ./.github/workflows/pkgdown-build if: github.event_name != 'push' - run: | - pkgdown::build_site() - shell: Rscript {0} - - name: Check rate limits - if: always() - run: | - curl -s --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit - shell: bash + - uses: ./.github/workflows/pkgdown-deploy + if: github.event_name == 'push' diff --git a/.github/workflows/pr-commands.yaml b/.github/workflows/pr-commands.yaml index 20fff565c..9047d4ea4 100644 --- a/.github/workflows/pr-commands.yaml +++ b/.github/workflows/pr-commands.yaml @@ -26,7 +26,7 @@ jobs: shell: bash - name: Install dependencies run: | - install.packages(c("remotes", "roxygen2")) + install.packages(c("remotes", "roxygen2"), type = "binary") remotes::install_deps(dependencies = TRUE) shell: Rscript {0} - name: Document @@ -65,7 +65,7 @@ jobs: shell: bash - name: Install dependencies run: | - install.packages("styler") + install.packages(c("styler", "roxygen2"), type = "binary") shell: Rscript {0} - name: Style run: | diff --git a/.github/workflows/rate-limit/action.yml b/.github/workflows/rate-limit/action.yml new file mode 100644 index 000000000..03e321893 --- /dev/null +++ b/.github/workflows/rate-limit/action.yml @@ -0,0 +1,13 @@ +name: 'Check GitHub rate limits' +inputs: + token: # id of input + description: GitHub token, pass secrets.GITHUB_TOKEN + required: true + +runs: + using: "composite" + steps: + - name: Check rate limits + run: | + curl -s --header "authorization: Bearer ${{ inputs.token }}" https://api.github.com/rate_limit + shell: bash diff --git a/.github/workflows/revdep.yaml b/.github/workflows/revdep.yaml index a4b063fe0..dc8e608aa 100644 --- a/.github/workflows/revdep.yaml +++ b/.github/workflows/revdep.yaml @@ -107,7 +107,7 @@ jobs: if (!requireNamespace("remotes", quietly = TRUE)) install.packages("remotes") shell: Rscript {0} - - uses: r-lib/actions/setup-pandoc@v1 + - uses: r-lib/actions/setup-pandoc@v2 - name: Install system dependencies if: runner.os == 'Linux' diff --git a/.github/workflows/roxygenize/action.yml b/.github/workflows/roxygenize/action.yml new file mode 100644 index 000000000..3037b7011 --- /dev/null +++ b/.github/workflows/roxygenize/action.yml @@ -0,0 +1,9 @@ +name: 'Action to create documentation with roxygen2' + +runs: + using: "composite" + steps: + - name: Roxygenize + run: | + roxygen2::roxygenize() + shell: Rscript {0} diff --git a/.github/workflows/style/action.yml b/.github/workflows/style/action.yml new file mode 100644 index 000000000..5ac3b5761 --- /dev/null +++ b/.github/workflows/style/action.yml @@ -0,0 +1,37 @@ +name: 'Action to auto-style a package' + +runs: + using: "composite" + steps: + - name: Check styler options + id: check + run: | + set -x + scope=$( ( grep Config/autostyle/scope DESCRIPTION || true ) | cut -d " " -f 2) + strict=$( ( grep Config/autostyle/strict DESCRIPTION || true ) | cut -d " " -f 2) + echo ::set-output name=scope::$scope + echo ::set-output name=strict::$strict + shell: bash + + - name: Enable styler cache + if: ${{ steps.check.outputs.scope }} + run: | + styler::cache_activate(verbose = TRUE) + shell: Rscript {0} + + - uses: actions/cache@v2 + if: ${{ steps.check.outputs.scope }} + with: + path: | + ~/.cache/R/R.cache + key: ${{ runner.os }}- + + - name: Run styler + if: ${{ steps.check.outputs.scope }} + run: | + strict <- as.logical("${{ steps.check.outputs.strict }}") + if (is.na(strict)) { + strict = FALSE + } + styler::style_pkg(scope = "${{ steps.check.outputs.scope }}", strict = strict) + shell: Rscript {0} diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml deleted file mode 100644 index 1bd2592e5..000000000 --- a/.github/workflows/test-coverage.yaml +++ /dev/null @@ -1,106 +0,0 @@ -on: - push: - branches: - - main - - master - pull_request: - branches: - - main - - master - -name: covr - -jobs: - test-coverage: - runs-on: ubuntu-18.04 - - # Begin custom: services - # End custom: services - env: - R_REMOTES_NO_ERRORS_FROM_WARNINGS: true - RSPM: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest" - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - # prevent rgl issues because no X11 display is available - RGL_USE_NULL: true - # Begin custom: env vars - # End custom: env vars - - steps: - - name: Check rate limits - run: | - curl -s --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit - shell: bash - - - uses: actions/checkout@v2 - - # Begin custom: before install - # End custom: before install - - - uses: r-lib/actions/setup-r@v1 - with: - install-r: false - - - uses: r-lib/actions/setup-pandoc@v1 - - - name: Install remotes - run: | - if (!requireNamespace("curl", quietly = TRUE)) install.packages("curl") - if (!requireNamespace("remotes", quietly = TRUE)) install.packages("remotes") - shell: Rscript {0} - - - name: Query dependencies - if: runner.os != 'Windows' - run: | - saveRDS(remotes::dev_package_deps(dependencies = TRUE, type = .Platform$pkgType), ".github/depends.Rds", version = 2) - writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") - shell: Rscript {0} - - - name: Restore R package cache - if: runner.os != 'Windows' - uses: actions/cache@v2 - with: - path: ${{ env.R_LIBS_USER }} - key: ubuntu-18.04-${{ hashFiles('.github/R-version') }}-2-${{ hashFiles('.github/depends.Rds') }} - restore-keys: ubuntu-18.04-${{ hashFiles('.github/R-version') }}-2- - - - name: Install system dependencies - if: runner.os == 'Linux' - run: | - sudo apt-get update -y - while read -r cmd - do - eval sudo $cmd - done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "18.04"))') - - - name: Add fake qpdf and checkbashisms - if: runner.os == 'Linux' - run: | - sudo ln -s $(which true) /usr/local/bin/qpdf - sudo ln -s $(which true) /usr/local/bin/checkbashisms - - - name: Install dependencies - run: | - remotes::install_deps(dependencies = TRUE, type = .Platform$pkgType) - remotes::install_cran("covr") - shell: Rscript {0} - - - name: Session info - run: | - options(width = 100) - if (!requireNamespace("sessioninfo", quietly = TRUE)) install.packages("sessioninfo") - pkgs <- installed.packages()[, "Package"] - sessioninfo::session_info(pkgs, include_base = TRUE) - shell: Rscript {0} - - # Begin custom: after install - # End custom: after install - - - name: Test coverage - run: covr::codecov() - shell: Rscript {0} - - - name: Check rate limits - if: always() - run: | - curl -s --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit - shell: bash diff --git a/DESCRIPTION b/DESCRIPTION index 4a22a2172..4b01c4454 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -36,6 +36,7 @@ Suggests: ggplot2, knitr, lubridate, + nanotime, nycflights13, palmerpenguins, rmarkdown, @@ -60,3 +61,5 @@ Config/testthat/start-first: ctl_colonnade, ctl_colonnade_1, ctl_colonnade_2 +Config/autostyle/scope: spaces +Config/autostyle/strict: true diff --git a/R/char.R b/R/char.R index cdff9271b..ddcb46912 100644 --- a/R/char.R +++ b/R/char.R @@ -48,7 +48,7 @@ #' tibble::tibble( #' back = char(lipsum, shorten = "back"), #' front = char(lipsum, shorten = "front"), -#' mid = char(lipsum, shorten = "mid") +#' mid = char(lipsum, shorten = "mid") #' ) #' tibble::tibble(abbr = char(lipsum, shorten = "abbreviate")) char <- function(x, ..., min_chars = NULL, diff --git a/R/ctl_new_pillar.R b/R/ctl_new_pillar.R index 8e72a5d2a..1db1035f6 100644 --- a/R/ctl_new_pillar.R +++ b/R/ctl_new_pillar.R @@ -57,7 +57,6 @@ #' #' # Packed array #' ctl_new_compound_pillar(tibble::tibble(), Titanic, width = 60) -#' #' @examples #' #' # Customize output diff --git a/R/glimpse.R b/R/glimpse.R index e8f612987..b3a9bc603 100644 --- a/R/glimpse.R +++ b/R/glimpse.R @@ -25,10 +25,8 @@ #' @export #' @examples #' glimpse(mtcars) -#' #' @examplesIf rlang::is_installed("nycflights13") #' glimpse(nycflights13::flights) -#' glimpse <- function(x, width = NULL, ...) { UseMethod("glimpse") } diff --git a/R/num.R b/R/num.R index 75c01c31c..28cb2c137 100644 --- a/R/num.R +++ b/R/num.R @@ -61,7 +61,7 @@ #' #' # Maximum digits after the decimal points #' tibble::tibble( -#' x0 = num(9:11 * 100 + 0.5, digits = 0), +#' x0 = num(9:11 * 100 + 0.5, digits = 0), #' x1 = num(9:11 * 100 + 0.5, digits = -1), #' x2 = num(9:11 * 100 + 0.5, digits = -2), #' ) @@ -76,8 +76,8 @@ #' # Scale #' tibble::tibble( #' small = num(9:11 / 1000 + 0.00005, label = "%", scale = 100), -#' medium = num(9:11 / 100 + 0.0005 , label = "%", scale = 100), -#' large = num(9:11 / 10 + 0.005 , label = "%", scale = 100) +#' medium = num(9:11 / 100 + 0.0005, label = "%", scale = 100), +#' large = num(9:11 / 10 + 0.005, label = "%", scale = 100) #' ) #' #' # Notation @@ -92,7 +92,7 @@ #' tibble::tibble( #' scimin = num(10^(-7:6) * 123, notation = "sci", fixed_exponent = -Inf), #' engmin = num(10^(-7:6) * 123, notation = "eng", fixed_exponent = -Inf), -#' simin = num(10^(-7:6) * 123, notation = "si", fixed_exponent = -Inf) +#' simin = num(10^(-7:6) * 123, notation = "si", fixed_exponent = -Inf) #' ) #' #' tibble::tibble( diff --git a/R/shaft-.R b/R/shaft-.R index f3d285ed1..2b455529b 100644 --- a/R/shaft-.R +++ b/R/shaft-.R @@ -207,6 +207,10 @@ pillar_shaft_number <- function(x, sigfig, digits, notation, fixed_exponent, ext # registered in .onLoad() pillar_shaft.integer64 <- function(x, ..., sigfig = NULL) { + if (class(x)[[1]] != "integer64") { + return(NextMethod()) + } + pillar_shaft_number(x, sigfig, digits = NULL, notation = NULL, fixed_exponent = NULL, extra_sigfig = NULL) } diff --git a/R/sigfig.R b/R/sigfig.R index 74f5d792e..f583b59f2 100644 --- a/R/sigfig.R +++ b/R/sigfig.R @@ -186,7 +186,7 @@ within_tolerance <- function(x, y) { # Work around integer64 problem equal[x == y] <- FALSE "!!!!!!DEBUG `v(abs((x[equal] - y[equal]) * 2 ^ -l2x[equal]))`" - out[equal] <- abs((x[equal] - y[equal]) * 2 ^ -l2x[equal]) <= eps_2 + out[equal] <- abs((x[equal] - y[equal]) * 2^-l2x[equal]) <= eps_2 out } diff --git a/R/testthat.R b/R/testthat.R index 09ce62a5e..16e8c97b9 100644 --- a/R/testthat.R +++ b/R/testthat.R @@ -35,7 +35,6 @@ #' # Good: Use tidyeval to defer construction #' pillar_quo <- rlang::quo(pillar(1:3)) #' expect_known_display(!!pillar_quo, file, crayon = FALSE) -#' #' \dontrun{ #' # Bad: Options set in the active session may affect the display #' integer_pillar <- pillar(1:3) diff --git a/R/zzz.R b/R/zzz.R index 567bd8638..855933d36 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -32,7 +32,7 @@ NULL # nolint start .onLoad <- function(libname, pkgname) { -# nolint end + # nolint end # Can't use vctrs::s3_register() here with vctrs 0.1.0 # https://github.com/r-lib/vctrs/pull/314 register_s3_method("knitr", "knit_print", "pillar_squeezed_colonnade") diff --git a/README.Rmd b/README.Rmd index 0ff9e1f8c..ead7cf48c 100644 --- a/README.Rmd +++ b/README.Rmd @@ -20,7 +20,7 @@ knitr::opts_chunk$set( [![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) [![R build status](https://github.com/r-lib/pillar/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/pillar/actions) -[![Coverage status](https://codecov.io/gh/r-lib/pillar/branch/master/graph/badge.svg)](https://codecov.io/github/r-lib/pillar?branch=master) +[![Coverage status](https://codecov.io/gh/r-lib/pillar/branch/main/graph/badge.svg)](https://codecov.io/github/r-lib/pillar?branch=main) [![CRAN status](https://www.r-pkg.org/badges/version/pillar)](https://cran.r-project.org/package=pillar) diff --git a/README.md b/README.md index 8184b83ef..cc44dedb7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ -[![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) [![R build status](https://github.com/r-lib/pillar/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/pillar/actions) [![Coverage status](https://codecov.io/gh/r-lib/pillar/branch/master/graph/badge.svg)](https://codecov.io/github/r-lib/pillar?branch=master) [![CRAN status](https://www.r-pkg.org/badges/version/pillar)](https://cran.r-project.org/package=pillar) +[![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) [![R build status](https://github.com/r-lib/pillar/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/pillar/actions) [![Coverage status](https://codecov.io/gh/r-lib/pillar/branch/main/graph/badge.svg)](https://codecov.io/github/r-lib/pillar?branch=main) [![CRAN status](https://www.r-pkg.org/badges/version/pillar)](https://cran.r-project.org/package=pillar) diff --git a/man/char.Rd b/man/char.Rd index 6aa6bf5ec..de145a628 100644 --- a/man/char.Rd +++ b/man/char.Rd @@ -75,7 +75,7 @@ lipsum <- unlist(strsplit(stringi::stri_rand_lipsum(1), "(?<=[.]) +", perl = TRU tibble::tibble( back = char(lipsum, shorten = "back"), front = char(lipsum, shorten = "front"), - mid = char(lipsum, shorten = "mid") + mid = char(lipsum, shorten = "mid") ) tibble::tibble(abbr = char(lipsum, shorten = "abbreviate")) \dontshow{\}) # examplesIf} diff --git a/man/expect_known_display.Rd b/man/expect_known_display.Rd index 19f7e4847..518eb6994 100644 --- a/man/expect_known_display.Rd +++ b/man/expect_known_display.Rd @@ -46,7 +46,6 @@ expect_known_display(pillar(1:3), file, crayon = FALSE) # Good: Use tidyeval to defer construction pillar_quo <- rlang::quo(pillar(1:3)) expect_known_display(!!pillar_quo, file, crayon = FALSE) - \dontrun{ # Bad: Options set in the active session may affect the display integer_pillar <- pillar(1:3) diff --git a/man/glimpse.Rd b/man/glimpse.Rd index e5f306f11..e26b54e13 100644 --- a/man/glimpse.Rd +++ b/man/glimpse.Rd @@ -38,7 +38,6 @@ See \code{\link[=format_glimpse]{format_glimpse()}} for details on the formattin \examples{ glimpse(mtcars) - \dontshow{if (rlang::is_installed("nycflights13")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} glimpse(nycflights13::flights) \dontshow{\}) # examplesIf} diff --git a/man/num.Rd b/man/num.Rd index b40ccb28c..b6586d0b7 100644 --- a/man/num.Rd +++ b/man/num.Rd @@ -101,7 +101,7 @@ tibble::tibble( # Maximum digits after the decimal points tibble::tibble( - x0 = num(9:11 * 100 + 0.5, digits = 0), + x0 = num(9:11 * 100 + 0.5, digits = 0), x1 = num(9:11 * 100 + 0.5, digits = -1), x2 = num(9:11 * 100 + 0.5, digits = -2), ) @@ -116,8 +116,8 @@ tibble::tibble( # Scale tibble::tibble( small = num(9:11 / 1000 + 0.00005, label = "\%", scale = 100), - medium = num(9:11 / 100 + 0.0005 , label = "\%", scale = 100), - large = num(9:11 / 10 + 0.005 , label = "\%", scale = 100) + medium = num(9:11 / 100 + 0.0005, label = "\%", scale = 100), + large = num(9:11 / 10 + 0.005, label = "\%", scale = 100) ) # Notation @@ -132,7 +132,7 @@ tibble::tibble( tibble::tibble( scimin = num(10^(-7:6) * 123, notation = "sci", fixed_exponent = -Inf), engmin = num(10^(-7:6) * 123, notation = "eng", fixed_exponent = -Inf), - simin = num(10^(-7:6) * 123, notation = "si", fixed_exponent = -Inf) + simin = num(10^(-7:6) * 123, notation = "si", fixed_exponent = -Inf) ) tibble::tibble( diff --git a/tests/testthat/_snaps/ctl_colonnade.md b/tests/testthat/_snaps/ctl_colonnade.md index fcd34f973..ab0adb98f 100644 --- a/tests/testthat/_snaps/ctl_colonnade.md +++ b/tests/testthat/_snaps/ctl_colonnade.md @@ -352,7 +352,8 @@ Code - ctl_colonnade(list(`\n` = c("\n", "\""), `\r` = factor(c("\n", "\n"))), width = 30) + ctl_colonnade(list(` + ` = c("\n", "\""), `` = factor(c("\n", "\n"))), width = 30) Output $body `\n` `\r` diff --git a/tests/testthat/_snaps/format_integer64.md b/tests/testthat/_snaps/format_integer64.md index 807e2c611..02c4d7687 100644 --- a/tests/testthat/_snaps/format_integer64.md +++ b/tests/testthat/_snaps/format_integer64.md @@ -82,3 +82,72 @@ 1000000000002 NA +# nanotime works (#378) + + Code + pillar(x, width = 16) + Output + + + 2011-12-05T08:3~ + Code + pillar(x, width = 17) + Output + + + 2011-12-05T08:30~ + Code + pillar(x, width = 18) + Output + + + 2011-12-05T08:30:~ + Code + pillar(x, width = 19) + Output + + + 2011-12-05T08:30:0~ + Code + pillar(x, width = 20) + Output + + + 2011-12-05T08:30:00~ + Code + pillar(x, width = 21) + Output + + + 2011-12-05T08:30:00+~ + Code + pillar(x, width = 22) + Output + + + 2011-12-05T08:30:00+0~ + Code + pillar(x, width = 23) + Output + + + 2011-12-05T08:30:00+00~ + Code + pillar(x, width = 24) + Output + + + 2011-12-05T08:30:00+00:~ + Code + pillar(x, width = 25) + Output + + + 2011-12-05T08:30:00+00:00 + Code + pillar(x, width = 26) + Output + + + 2011-12-05T08:30:00+00:00 + diff --git a/tests/testthat/_snaps/format_multi.md b/tests/testthat/_snaps/format_multi.md index 0c337dc20..7caee7282 100644 --- a/tests/testthat/_snaps/format_multi.md +++ b/tests/testthat/_snaps/format_multi.md @@ -525,7 +525,8 @@ 2 3 Code - colonnade(list(`\n` = c("\n", "\""), `\r` = factor("\n")), width = 30) + colonnade(list(` + ` = c("\n", "\""), `` = factor("\n")), width = 30) Output `\n` `\r` diff --git a/tests/testthat/_snaps/glimpse.md b/tests/testthat/_snaps/glimpse.md index ec0bf2c30..0afadddd2 100644 --- a/tests/testthat/_snaps/glimpse.md +++ b/tests/testthat/_snaps/glimpse.md @@ -133,7 +133,7 @@ Columns: 0 Code # Non-syntactic names - df <- tibble::tibble(`mean(x)` = 5, `var(x)` = 3) + df <- tibble::tibble(!!!set_names(c(5, 3), c("mean(x)", "var(x)"))) glimpse(df, width = 28) Output Rows: 1 diff --git a/tests/testthat/_snaps/tbl-format-footer.md b/tests/testthat/_snaps/tbl-format-footer.md index f5610e50e..580f36fb5 100644 --- a/tests/testthat/_snaps/tbl-format-footer.md +++ b/tests/testthat/_snaps/tbl-format-footer.md @@ -21,11 +21,8 @@ # wrapping column names with spaces in the footer Code - tbl_format_footer(tbl_format_setup(new_tbl(list2(a = "a", b = "b", c = "c", d = "d", - e = "e", f = "f", g = "g", h = "h", i = "i", j = "j", k = "k", l = "l", m = "m", - n = "n", o = "o", p = "p", q = "q", r = "r", s = "s", t = "t", u = "u", v = "v", - w = "w", x = "x", y = "y", z = "z", - "a b c d e f g h i j k l m n o p q r s t u v w x y z" := 2)), width = 70)) + tbl_format_footer(tbl_format_setup(new_tbl(list2(!!!set_names(letters), !!paste( + letters, collapse = " ") := 2)), width = 70)) Output # ... with 16 more variables: l , m , n , o , @@ -36,24 +33,7 @@ # overflow Code - tbl_format_footer(tbl_format_setup(new_tbl(list2(a = "a", b = "b", c = "c", d = "d", - e = "e", f = "f", g = "g", h = "h", i = "i", j = "j", k = "k", l = "l", m = "m", - n = "n", o = "o", p = "p", q = "q", r = "r", s = "s", t = "t", u = "u", v = "v", - w = "w", x = "x", y = "y", z = "z", a = "a", b = "b", c = "c", d = "d", e = "e", - f = "f", g = "g", h = "h", i = "i", j = "j", k = "k", l = "l", m = "m", n = "n", - o = "o", p = "p", q = "q", r = "r", s = "s", t = "t", u = "u", v = "v", w = "w", - x = "x", y = "y", z = "z", a = "a", b = "b", c = "c", d = "d", e = "e", f = "f", - g = "g", h = "h", i = "i", j = "j", k = "k", l = "l", m = "m", n = "n", o = "o", - p = "p", q = "q", r = "r", s = "s", t = "t", u = "u", v = "v", w = "w", x = "x", - y = "y", z = "z", a = "a", b = "b", c = "c", d = "d", e = "e", f = "f", g = "g", - h = "h", i = "i", j = "j", k = "k", l = "l", m = "m", n = "n", o = "o", p = "p", - q = "q", r = "r", s = "s", t = "t", u = "u", v = "v", w = "w", x = "x", y = "y", - z = "z", a = "a", b = "b", c = "c", d = "d", e = "e", f = "f", g = "g", h = "h", - i = "i", j = "j", k = "k", l = "l", m = "m", n = "n", o = "o", p = "p", q = "q", - r = "r", s = "s", t = "t", u = "u", v = "v", w = "w", x = "x", y = "y", z = "z", - a = "a", b = "b", c = "c", d = "d", e = "e", f = "f", g = "g", h = "h", i = "i", - j = "j", k = "k", l = "l", m = "m", n = "n", o = "o", p = "p", q = "q", r = "r", - s = "s", t = "t", u = "u", v = "v", w = "w", x = "x", y = "y", z = "z")), + tbl_format_footer(tbl_format_setup(new_tbl(list2(!!!set_names(rep(letters, 6)))), width = 70)) Output diff --git a/tests/testthat/test-ctl_colonnade_1.R b/tests/testthat/test-ctl_colonnade_1.R index c7390a253..d2492883a 100644 --- a/tests/testthat/test-ctl_colonnade_1.R +++ b/tests/testthat/test-ctl_colonnade_1.R @@ -33,6 +33,6 @@ test_that("strings with varying widths", { ctl_colonnade(df_str[c(6L, 49L, 26L, 45L, 25L, 15L, 31L, 20L, 21L, 44L, 23L, 48L, 37L, 36L, 5L, 43L, 11L, 14L, 13L, 39L, 16L, 12L, 4L, 18L, 42L, 3L, 10L, 28L, 40L, 24L, 29L, 17L, 35L, 47L, 2L, 38L, 34L, 9L, 7L, 8L, 50L, 33L, 32L, 27L, 46L, 19L, 22L, 41L, 30L, 1L)], width = { options(width = 55); 779 }) ctl_colonnade(df_str[c(38L, 42L, 41L, 10L, 40L, 11L, 27L, 9L, 17L, 37L, 46L, 13L, 36L, 18L, 31L, 20L, 39L, 12L, 44L, 33L, 50L, 34L, 26L, 32L, 23L, 30L, 29L, 21L, 4L, 49L, 19L, 25L, 3L, 6L, 15L, 14L, 43L, 48L, 8L, 22L, 1L, 2L, 45L, 35L, 16L, 5L, 47L, 28L, 24L, 7L)], width = { options(width = 46); 694 }) - }) + }) # nolint end - }) +}) diff --git a/tests/testthat/test-format_integer64.R b/tests/testthat/test-format_integer64.R index 01ea6fe0e..13ef27742 100644 --- a/tests/testthat/test-format_integer64.R +++ b/tests/testthat/test-format_integer64.R @@ -15,3 +15,23 @@ test_that("integer64 output will use scientific if necessary", { pillar(add_special(x), width = 14) }) }) + +test_that("nanotime works (#378)", { + skip_if_not_installed("nanotime") + + # 0 tests for NA warning too + x <- nanotime::nanotime('2011-12-05 08:30:00.000', format = "%Y-%m-%d %H:%M:%E9S", tz = "GMT") + expect_snapshot({ + pillar(x, width = 16) + pillar(x, width = 17) + pillar(x, width = 18) + pillar(x, width = 19) + pillar(x, width = 20) + pillar(x, width = 21) + pillar(x, width = 22) + pillar(x, width = 23) + pillar(x, width = 24) + pillar(x, width = 25) + pillar(x, width = 26) + }) +}) diff --git a/tests/testthat/test-num.R b/tests/testthat/test-num.R index 8ebbb669d..5f1c56ddc 100644 --- a/tests/testthat/test-num.R +++ b/tests/testthat/test-num.R @@ -23,8 +23,8 @@ test_that("output test", { # Scale tibble::tibble( small = num(9:11 / 1000 + 0.00005, label = "%", scale = 100), - medium = num(9:11 / 100 + 0.0005 , label = "%", scale = 100), - large = num(9:11 / 10 + 0.005 , label = "%", scale = 100) + medium = num(9:11 / 100 + 0.0005, label = "%", scale = 100), + large = num(9:11 / 10 + 0.005, label = "%", scale = 100) ) # Notation @@ -39,13 +39,13 @@ test_that("output test", { tibble::tibble( scimin = num(10^(-7:6) * 123, notation = "sci", fixed_exponent = -Inf), engmin = num(10^(-7:6) * 123, notation = "eng", fixed_exponent = -Inf), - simin = num(10^(-7:6) * 123, notation = "si", fixed_exponent = -Inf) + simin = num(10^(-7:6) * 123, notation = "si", fixed_exponent = -Inf) ) tibble::tibble( scismall = num(10^(-7:6) * 123, notation = "sci", fixed_exponent = -3), scilarge = num(10^(-7:6) * 123, notation = "eng", fixed_exponent = 3), - scimax = num(10^(-7:6) * 123, notation = "si", fixed_exponent = Inf) + scimax = num(10^(-7:6) * 123, notation = "si", fixed_exponent = Inf) ) # Extra significant figures @@ -60,18 +60,18 @@ test_that("output test", { test_that("many digits", { expect_snapshot({ - num(123456789 * 10 ^ (-9:0)) - num(123456789 * 10 ^ (-9:1)) - num(123456789 * 10 ^ (-9:1), notation = "dec") - num(123456789 * 10 ^ (-9:1), notation = "sci") - num(123456789 * 10 ^ (-9:1), notation = "eng") - num(123456789 * 10 ^ (-9:1), notation = "si") - num(123456789 * 10 ^ (-9:1), notation = "sci", fixed_exponent = -Inf) - num(123456789 * 10 ^ (-9:1), notation = "eng", fixed_exponent = -Inf) - num(123456789 * 10 ^ (-9:1), notation = "si", fixed_exponent = -Inf) - num(123456789 * 10 ^ (-9:1), notation = "sci", fixed_exponent = -3) - num(123456789 * 10 ^ (-9:1), notation = "sci", fixed_exponent = 3) - num(123456789 * 10 ^ (-9:1), notation = "sci", fixed_exponent = Inf) + num(123456789 * 10^(-9:0)) + num(123456789 * 10^(-9:1)) + num(123456789 * 10^(-9:1), notation = "dec") + num(123456789 * 10^(-9:1), notation = "sci") + num(123456789 * 10^(-9:1), notation = "eng") + num(123456789 * 10^(-9:1), notation = "si") + num(123456789 * 10^(-9:1), notation = "sci", fixed_exponent = -Inf) + num(123456789 * 10^(-9:1), notation = "eng", fixed_exponent = -Inf) + num(123456789 * 10^(-9:1), notation = "si", fixed_exponent = -Inf) + num(123456789 * 10^(-9:1), notation = "sci", fixed_exponent = -3) + num(123456789 * 10^(-9:1), notation = "sci", fixed_exponent = 3) + num(123456789 * 10^(-9:1), notation = "sci", fixed_exponent = Inf) }) })