diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml
index 1da97de..9f9476b 100644
--- a/.github/workflows/R-CMD-check.yaml
+++ b/.github/workflows/R-CMD-check.yaml
@@ -22,61 +22,33 @@ jobs:
fail-fast: false
matrix:
config:
- - {os: macOS-latest, r: 'release'}
- - {os: ubuntu-20.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"}
+ - {os: macos-latest, r: 'release'}
+ - {os: ubuntu-latest, r: 'release'}
- {os: windows-latest, r: 'devel'}
- - {os: windows-latest, r: 'oldrel'}
+ - {os: windows-latest, r: 'oldrel-1'}
- {os: windows-latest, r: 'release'}
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
- R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
- RSPM: ${{ matrix.config.rspm }}
+ R_KEEP_PKG_SOURCE: yes
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
+
+ - uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
+ http-user-agent: ${{ matrix.config.http-user-agent }}
+ use-public-rspm: true
- - uses: r-lib/actions/setup-pandoc@v2
-
- - name: Query dependencies
- run: |
- install.packages('remotes')
- saveRDS(remotes::dev_package_deps(dependencies = TRUE), "depends.Rds", version = 2)
- shell: Rscript {0}
-
- - name: Cache R packages
- if: runner.os != 'Windows'
- uses: actions/cache@v1
+ - uses: r-lib/actions/setup-r-dependencies@v2
with:
- path: ${{ env.R_LIBS_USER }}
- key: ${{ runner.os }}-r-${{ matrix.config.r }}-3-${{ hashFiles('depends.Rds') }}
- restore-keys: ${{ runner.os }}-r-${{ matrix.config.r }}-3-
-
- - name: Install system dependencies
- if: runner.os == 'Linux'
- env:
- RHUB_PLATFORM: linux-x86_64-ubuntu-gcc
- run: |
- Rscript -e "remotes::install_github('r-hub/sysreqs')"
- sysreqs=$(Rscript -e "cat(sysreqs::sysreq_commands('DESCRIPTION'))")
- sudo -s eval "$sysreqs"
- - name: Install dependencies
- run: |
- remotes::install_deps(dependencies = TRUE)
- remotes::install_cran("rcmdcheck")
- shell: Rscript {0}
-
- - name: Check
- run: rcmdcheck::rcmdcheck(args = "--no-manual", error_on = "warning", check_dir = "check")
- shell: Rscript {0}
+ extra-packages: any::rcmdcheck
+ needs: check
- - name: Upload check results
- if: failure()
- uses: actions/upload-artifact@main
+ - uses: r-lib/actions/check-r-package@v2
with:
- name: ${{ runner.os }}-r${{ matrix.config.r }}-results
- path: check
+ upload-snapshots: true
+ args: 'c("--no-manual", "--as-cran")'
diff --git a/.github/workflows/claude-code-review.yaml b/.github/workflows/claude-code-review.yaml
new file mode 100644
index 0000000..10d2e3d
--- /dev/null
+++ b/.github/workflows/claude-code-review.yaml
@@ -0,0 +1,40 @@
+name: Claude Code Review
+
+on:
+ pull_request:
+ types: [opened, synchronize]
+
+jobs:
+ claude-review:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pull-requests: read
+ issues: read
+ id-token: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 1
+
+ - name: Run Claude Code Review
+ id: claude-review
+ uses: anthropics/claude-code-action@v1
+ with:
+ claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
+ prompt: |
+ REPO: ${{ github.repository }}
+ PR NUMBER: ${{ github.event.pull_request.number }}
+
+ Please review this pull request and think hard about correctness,
+ edge cases, and consistency with the rest of the codebase. Use the
+ repository's CLAUDE.md for guidance if available.
+ Focus on:
+ - Code quality and R package best practices
+ - Potential bugs or logic issues
+ - Test coverage
+ - Documentation (roxygen2) completeness
+ - Consistency with the existing codebase
+ claude_args: '--model claude-opus-4-7 --allowed-tools "mcp__github_inline_comment__create_inline_comment,Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"'
diff --git a/.github/workflows/claude.yaml b/.github/workflows/claude.yaml
new file mode 100644
index 0000000..49f70bf
--- /dev/null
+++ b/.github/workflows/claude.yaml
@@ -0,0 +1,38 @@
+name: Claude Code
+
+on:
+ issue_comment:
+ types: [created]
+ pull_request_review_comment:
+ types: [created]
+ issues:
+ types: [opened, assigned]
+ pull_request_review:
+ types: [submitted]
+
+jobs:
+ claude:
+ if: |
+ (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
+ (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
+ (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
+ (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pull-requests: read
+ issues: read
+ id-token: write
+ actions: read
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 1
+
+ - name: Run Claude Code
+ id: claude
+ uses: anthropics/claude-code-action@v1
+ with:
+ claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
+ claude_args: '--model claude-opus-4-7'
diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml
index 3b2a357..2d703f6 100644
--- a/.github/workflows/pkgdown.yaml
+++ b/.github/workflows/pkgdown.yaml
@@ -4,48 +4,49 @@ on:
- main
- master
- dev
+ pull_request:
+ branches:
+ - main
+ - master
+ - dev
+ release:
+ types: [published]
+ workflow_dispatch:
name: pkgdown
jobs:
pkgdown:
- runs-on: windows-latest
+ runs-on: ubuntu-latest
+ # Only restrict concurrency for non-PR jobs
+ concurrency:
+ group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }}
env:
- CURL_SSL_BACKEND: "openssl"
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
+ permissions:
+ contents: write
steps:
- - uses: actions/checkout@v2
-
- - uses: r-lib/actions/setup-r@v2
+ - uses: actions/checkout@v4
- uses: r-lib/actions/setup-pandoc@v2
- - name: Query dependencies
- run: |
- install.packages('remotes')
- saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
- writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
- shell: Rscript {0}
+ - uses: r-lib/actions/setup-r@v2
+ with:
+ use-public-rspm: true
- - name: Cache R packages
- uses: actions/cache@v2
+ - uses: r-lib/actions/setup-r-dependencies@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-
+ extra-packages: any::pkgdown, local::.
+ needs: website
- - name: Install dependencies
- run: |
- remotes::install_deps(dependencies = TRUE)
- install.packages("pkgdown", type = "binary")
+ - name: Build site
+ run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
shell: Rscript {0}
- - name: Install package
- run: R CMD INSTALL .
- shell: cmd
-
- - name: Deploy package
- run: |
- git config --local user.email "actions@github.com"
- git config --local user.name "GitHub Actions"
- Rscript -e 'pkgdown::deploy_to_branch(new_process = FALSE)'
+ - name: Deploy to GitHub pages
+ if: github.event_name != 'pull_request'
+ uses: JamesIves/github-pages-deploy-action@v4.5.0
+ with:
+ clean: false
+ branch: gh-pages
+ folder: docs
diff --git a/.github/workflows/pr-commands.yaml b/.github/workflows/pr-commands.yaml
index 0d3cb71..33cfb6c 100644
--- a/.github/workflows/pr-commands.yaml
+++ b/.github/workflows/pr-commands.yaml
@@ -1,51 +1,85 @@
on:
issue_comment:
types: [created]
+
name: Commands
+
jobs:
document:
- if: startsWith(github.event.comment.body, '/document')
+ if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/document') }}
name: document
- runs-on: macOS-latest
+ runs-on: ubuntu-latest
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
+ permissions:
+ contents: write
+ pull-requests: write
steps:
- - uses: actions/checkout@v2
- - uses: r-lib/actions/pr-fetch@master
+ - uses: actions/checkout@v4
+
+ - uses: r-lib/actions/pr-fetch@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- - uses: r-lib/actions/setup-r@master
- - name: Install dependencies
- run: Rscript -e 'install.packages(c("remotes", "roxygen2"))' -e 'remotes::install_deps(dependencies = TRUE)'
+
+ - uses: r-lib/actions/setup-r@v2
+ with:
+ use-public-rspm: true
+
+ - uses: r-lib/actions/setup-r-dependencies@v2
+ with:
+ extra-packages: any::roxygen2
+ needs: pr-document
+
- name: Document
- run: Rscript -e 'roxygen2::roxygenise()'
+ run: roxygen2::roxygenise()
+ shell: Rscript {0}
+
- name: commit
run: |
+ git config --local user.name "$GITHUB_ACTOR"
+ git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
git add man/\* NAMESPACE
git commit -m 'Document'
- - uses: r-lib/actions/pr-push@master
+
+ - uses: r-lib/actions/pr-push@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
+
style:
- if: startsWith(github.event.comment.body, '/style')
+ if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/style') }}
name: style
- runs-on: macOS-latest
+ runs-on: ubuntu-latest
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
+ permissions:
+ contents: write
+ pull-requests: write
steps:
- - uses: actions/checkout@v2
- - uses: r-lib/actions/pr-fetch@master
+ - uses: actions/checkout@v4
+
+ - uses: r-lib/actions/pr-fetch@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- - uses: r-lib/actions/setup-r@master
+
+ - uses: r-lib/actions/setup-r@v2
+ with:
+ use-public-rspm: true
+
- name: Install dependencies
- run: Rscript -e 'install.packages("styler")'
+ run: install.packages("styler")
+ shell: Rscript {0}
+
- name: Style
- run: Rscript -e 'styler::style_pkg()'
+ run: styler::style_pkg()
+ shell: Rscript {0}
+
- name: commit
run: |
+ git config --local user.name "$GITHUB_ACTOR"
+ git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
git add \*.R
git commit -m 'Style'
- - uses: r-lib/actions/pr-push@master
+
+ - uses: r-lib/actions/pr-push@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml
index 0f014df..254c6db 100644
--- a/.github/workflows/test-coverage.yaml
+++ b/.github/workflows/test-coverage.yaml
@@ -12,37 +12,50 @@ name: test-coverage
jobs:
test-coverage:
- runs-on: windows-latest
+ runs-on: ubuntu-latest
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
+
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2
+ with:
+ use-public-rspm: true
- - uses: r-lib/actions/setup-pandoc@v2
+ - uses: r-lib/actions/setup-r-dependencies@v2
+ with:
+ extra-packages: any::covr, any::xml2
+ needs: coverage
- - name: Query dependencies
+ - name: Test coverage
run: |
- install.packages('remotes')
- saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
- writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
+ cov <- covr::package_coverage(
+ quiet = FALSE,
+ clean = FALSE,
+ install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package")
+ )
+ covr::to_cobertura(cov)
shell: Rscript {0}
- - name: Cache R packages
- uses: actions/cache@v1
+ - uses: codecov/codecov-action@v4
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 dependencies
+ fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }}
+ file: ./cobertura.xml
+ plugin: noop
+ disable_search: true
+ token: ${{ secrets.CODECOV_TOKEN }}
+
+ - name: Show testthat output
+ if: always()
run: |
- install.packages(c("remotes"))
- remotes::install_deps(dependencies = TRUE)
- remotes::install_cran("covr")
- shell: Rscript {0}
+ ## --------------------------------------------------------------------
+ find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true
+ shell: bash
- - name: Test coverage
- run: covr::codecov()
- shell: Rscript {0}
+ - name: Upload test results
+ if: failure()
+ uses: actions/upload-artifact@v4
+ with:
+ name: coverage-test-failures
+ path: ${{ runner.temp }}/package
diff --git a/DESCRIPTION b/DESCRIPTION
index 5d19095..82531ae 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,6 +1,6 @@
Package: kwb.pkgbuild
Title: R package for standardised development at KWB
-Version: 0.2.3
+Version: 0.3.0
Authors@R:
c(person(given = "Michael",
family = "Rustler",
@@ -35,7 +35,6 @@ Imports:
processx,
rematch2,
sessioninfo,
- stringr,
usethis,
withr,
yaml
@@ -53,4 +52,4 @@ Remotes:
ByteCompile: true
Encoding: UTF-8
LazyData: true
-RoxygenNote: 7.2.1
+RoxygenNote: 7.3.1
diff --git a/NAMESPACE b/NAMESPACE
index 2704fe2..bb41de4 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -24,6 +24,7 @@ export(use_badge_travis)
export(use_codecov)
export(use_description)
export(use_ghactions)
+export(use_ghactions_claude)
export(use_gitlab_ci_blogdown)
export(use_gitlab_ci_docs)
export(use_gitlab_ci_ghpages)
@@ -64,15 +65,11 @@ importFrom(pkgdown,build_site)
importFrom(processx,run)
importFrom(rematch2,re_match)
importFrom(sessioninfo,package_info)
-importFrom(stringr,str_detect)
-importFrom(stringr,str_remove)
-importFrom(stringr,str_replace)
-importFrom(stringr,str_split)
importFrom(tools,toTitleCase)
importFrom(usethis,use_description)
importFrom(usethis,use_git_ignore)
importFrom(usethis,use_mit_license)
importFrom(usethis,use_pkgdown)
importFrom(usethis,use_template)
-importFrom(utils,tail)
+importFrom(utils,getFromNamespace)
importFrom(withr,with_dir)
diff --git a/NEWS.md b/NEWS.md
index 0bad1ce..52fa618 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,90 @@
+# [kwb.pkgbuild 0.3.0](https://github.com/KWB-R/kwb.pkgbuild/releases/tag/v0.3.0) 2026-05-07
+
+* Modernise GitHub Actions workflows (both in `.github/workflows/` of this
+ repo and the templates in `inst/templates/ci_github-actions/`) so that
+ they run on current GitHub-hosted runners again:
+
+ - Bump action versions: `actions/checkout@v4`, `actions/upload-artifact@v4`,
+ `codecov/codecov-action@v4`, and replace the deprecated `r-lib/actions@master`
+ references with `r-lib/actions@v2`.
+
+ - Switch from the retired `ubuntu-20.04` runner to `ubuntu-latest` and
+ rename the matrix entry `oldrel` to `oldrel-1`.
+
+ - Replace the archived `r-hub/sysreqs` step with
+ `r-lib/actions/setup-r-dependencies@v2`, which also handles dependency
+ caching out of the box.
+
+ - Fix a stale `if: runner.os == 'Linux (no, try without!)'` condition that
+ silently disabled the Linux system-dependency step.
+
+ - `pkgdown` workflow: deploy via `JamesIves/github-pages-deploy-action@v4`
+ on `ubuntu-latest`, with explicit `permissions: contents: write` and a
+ concurrency group.
+
+ - `test-coverage` workflow: produce a Cobertura report and upload via the
+ new `codecov/codecov-action@v4`; upload test artefacts on failure.
+
+ - `pr-commands` workflow: gate `/document` and `/style` jobs on
+ `github.event.issue.pull_request` so they no longer fire on plain issue
+ comments.
+
+* Add optional Claude Code GitHub Actions workflows (analogue to
+ [kwb.raindrop](https://github.com/KWB-R/kwb.raindrop/tree/main/.github/workflows)):
+
+ - New templates in `inst/templates/ci_github-actions-claude/`:
+ `claude.yaml` (responds to `@claude` mentions in issues and PR reviews)
+ and `claude-code-review.yaml` (automatic PR review on `opened` /
+ `synchronize`).
+
+ - New exported function `use_ghactions_claude()` to add only the Claude
+ workflows to an existing package.
+
+ - `use_ghactions()` and `use_pkg()` gain a `claude = FALSE` toggle that
+ additionally installs the Claude workflows when set to `TRUE`. The
+ workflows expect a `CLAUDE_CODE_OAUTH_TOKEN` repository secret to be
+ configured in GitHub.
+
+* Documentation cleanup:
+
+ - Remove dead duplicate definitions of `git()`, `construct_commit_message()`
+ and `github_push()` in `R/deploy_site_github_with_extra_files.R` (they
+ were silently overwritten by later definitions in the same file).
+
+ - Fix copy/paste errors in `@return` for `use_index_md()`,
+ `use_badge_ghactions_rcmdcheck()` and `use_badge_runiverse()` (which
+ referenced "travis" / "codecov" badges instead of the actual return
+ value).
+
+ - Mark internal helpers (`use_installation()`, `read_description()`,
+ `kwb_author()`, `kwb_package()`) with `@noRd` so they no longer create
+ public Rd entries.
+
+ - Rewrite the titles / descriptions for `use_pkgdown()`, `use_readme_md()`
+ and `use_index_md()` so the man pages describe what the function
+ actually does.
+
+ - Fix typos (`releveant`, `directoy`, `aleady`, `DESCIPTION`,
+ `(default: KWB-R")`, `file patern`) across roxygen blocks and Rd files.
+
+* `use_pkgdown()`: expose the KWB logo as parameters `kwb_logo_url`
+ (default: `https://logos.kompetenz-wasser.io/KWB_Logo_M_Blau_RGB.svg`)
+ and `kwb_logo_href` (default: `https://www.kompetenz-wasser.de`) so the
+ default logo URL is no longer hardcoded inside the function body and can
+ be overridden per package without forking the function.
+
+* Vignettes:
+
+ - New vignette `vignette("github-actions", package = "kwb.pkgbuild")`
+ describing the default workflows, the optional Claude Code integration,
+ the `CLAUDE_CODE_OAUTH_TOKEN` secret, and how to refresh workflows in
+ existing packages.
+
+ - Update `vignette("tutorial")`: replace stale Travis / AppVeyor
+ references with the GitHub Actions workflow set, document the new
+ `claude = TRUE` switch in `use_pkg()`, and fix the `kwb.pkgdown` /
+ `kwb.pkddown` typos.
+
# [kwb.pkgbuild 0.2.3](https://github.com/KWB-R/kwb.pkgbuild/releases/tag/v0.2.3) 2022-10-24
* Fix GitHub action worfklows:
diff --git a/R/.add_authors.R b/R/.add_authors.R
index bb92833..7902bcc 100644
--- a/R/.add_authors.R
+++ b/R/.add_authors.R
@@ -79,7 +79,7 @@ add_authors <- function(author_meta, role = "ctb", path = getwd())
#' @export
#' @importFrom purrr transpose
convert_author_metadata_tolist <- function(
- author_metadata_df = create_author_metadata_from_orcid()
+ author_metadata_df = create_author_metadata_from_orcid()
)
{
setNames(
@@ -94,31 +94,24 @@ convert_author_metadata_tolist <- function(
#' @param orcids named character vector with ORCIDs and names correspondig to
#' to "given_name family name" (defaults: kwb.orcid::get_kwb_orcids())
#' @importFrom kwb.orcid get_kwb_orcids
-#' @importFrom stringr str_trim str_split
-#' @importFrom magrittr %>%
+#' @importFrom kwb.utils extractSubstring setColumns
#' @return data frame with required metadata for R package DESCRIPTION as
#' required by desc::desc_add_author()
#' @export
create_author_metadata_from_orcid <- function(
- orcids = kwb.orcid::get_kwb_orcids()
+ orcids = kwb.orcid::get_kwb_orcids()
)
{
- orc_ids <- orcids[order(orcids)]
- orc_names <- names(orcids)
+ orc_ids <- sort(orcids)
- orc_names_matrix <- orc_names %>%
- stringr::str_trim() %>%
- stringr::str_split(pattern = "\\s+", simplify = TRUE, n = 2)
-
- kwb.utils::noFactorDataFrame(
- given = orc_names_matrix[,1],
- family = orc_names_matrix[,2],
- email = sprintf(
- "%s.%s@kompetenz-wasser.de",
- tolower(orc_names_matrix[, 1]),
- tolower(orc_names_matrix[, 2])
- ),
- orcid = orc_ids,
- row.names = NULL
- )
+ names(orcids) %>%
+ kwb.utils::extractSubstring(
+ pattern = "^\\s*(\\S+)\\s+(\\S+)\\s*$",
+ index = c(given = 1L, family = 2L)
+ ) %>%
+ kwb.utils::setColumns(
+ email = email_kwb(.[["given"]], .[["family"]]),
+ orcid = orc_ids,
+ dbg = FALSE
+ )
}
diff --git a/R/create_pkg_dir.R b/R/create_pkg_dir.R
index 567cba2..5bb228d 100644
--- a/R/create_pkg_dir.R
+++ b/R/create_pkg_dir.R
@@ -45,22 +45,21 @@ create_pkg_dir <- function(pkg_dir)
#' @noRd
#' @keywords internal
-#' @importFrom stringr str_split
-#' @importFrom utils tail
check_pkg_dir_nested <- function(pkg_dir)
{
- last_folders <- utils::tail(n = 2, as.character(
- stringr::str_split(pkg_dir, pattern = "/", simplify = TRUE)
- ))
+ leaf_folder <- basename(pkg_dir)
+ parent_folder <- basename(dirname(pkg_dir))
- if (last_folders[1] == last_folders[2]) clean_stop(
- sprintf("Package skeleton for '%s' cannot be created, ", last_folders[2]),
+ if (parent_folder == leaf_folder) clean_stop(
+ sprintf("Package skeleton for '%s' cannot be created, ", leaf_folder),
sprintf("as it would be nested in subfolder '%s'.\n\n", pkg_dir),
"Workaround: specify a different 'root_dir' in function use_pkg_skeleton()"
)
message(sprintf(
- "%s is a valid 'root_dir' for pkg '%s'", pkg_dir, last_folders[2]
+ "%s is a valid 'root_dir' for pkg '%s'",
+ pkg_dir,
+ leaf_folder
))
pkg_dir
diff --git a/R/deploy_site_github_with_extra_files.R b/R/deploy_site_github_with_extra_files.R
index 0120b6c..9c2a639 100644
--- a/R/deploy_site_github_with_extra_files.R
+++ b/R/deploy_site_github_with_extra_files.R
@@ -35,26 +35,6 @@ github_url_rx <- function() {
# pkgdown functions (missing in pkgdown >= 1.5.0) ------------------------------
-#' git
-#' @importFrom processx run
-#' @keywords internal
-#' @noRd
-#'
-git <- function(...) {
- processx::run("git", c(...), echo_cmd = TRUE, echo = TRUE)
-}
-
-#' construct_commit_message
-#'
-#' @keywords internal
-#' @noRd
-#'
-construct_commit_message <- function(pkg, commit = Sys.getenv("TRAVIS_COMMIT")) {
- pkg <- pkgdown::as_pkgdown(pkg)
-
- sprintf("Built site for %s: %s@%s", pkg$package, pkg$version, substr(commit, 1, 7))
-}
-
#' rule
#' @importFrom cli cat_rule
#' @importFrom crayon bold
@@ -83,27 +63,6 @@ github_clone <- function(dir, repo_slug) {
}
-#' github_push
-#'
-#' @importFrom withr with_dir
-#' @keywords internal
-#'
-github_push <- function(dir, commit_message) {
- # force execution before changing working directory
- force(commit_message)
-
- rule("Commiting updated site", line = 1)
-
- withr::with_dir(dir, {
- git("add", "-A", ".")
- git("commit", "--allow-empty", "-m", commit_message)
-
- rule("Deploying to GitHub Pages", line = 1)
- git("remote", "-v")
- git("push", "--force", "origin", "HEAD:gh-pages")
- })
-}
-
# deploy_site_github_with_extra_files ------------------------------------------
#' deploy_site_github_with_extra_files
@@ -111,7 +70,7 @@ github_push <- function(dir, commit_message) {
#' @description for details see pkgdown::deploy_site_github(), only parameter
#' vignettes_file_pattern_to_copy added
#' @param pkg "."
-#' @param vignettes_file_pattern_to_copy file patern for copying files from
+#' @param vignettes_file_pattern_to_copy file pattern for copying files from
#' vignettes directory into deploy directory (default: "\\.json$")
#' @param install Optionally, opt-out of automatic installation. This is
#' necessary if the package you're documenting is a dependency of pkgdown
@@ -211,7 +170,7 @@ copy_files_from_vignettes_dir_to_deploy_dir <- function(
#' Assumes that you're in a git clone of the project, and the package is
#' already installed.
#' @param pkg "."
-#' @param vignettes_file_pattern_to_copy file patern for copying files from
+#' @param vignettes_file_pattern_to_copy file pattern for copying files from
#' vignettes directory into deploy directory (default: "\\.json$")
#' @param branch The git branch to deploy to
#' @param remote The git remote to deploy to
@@ -258,7 +217,7 @@ deploy_to_branch_with_extra_files <- function(pkg = ".",
if (clean) {
rule("Cleaning files from old site", line = 1)
- pkgdown:::clean_site(pkg)
+ pkgdown::clean_site(pkg)
}
pkgdown::build_site(pkg, devel = FALSE, preview = FALSE, install = FALSE, ...)
@@ -271,7 +230,7 @@ deploy_to_branch_with_extra_files <- function(pkg = ".",
)
if (github_pages) {
- pkgdown:::build_github_pages(pkg)
+ getFromNamespace("build_github_pages", "pkgdown")(pkg)
}
github_push(dest_dir, commit_message, remote, branch)
diff --git a/R/helper.R b/R/helper.R
index 9837341..4b04fc9 100644
--- a/R/helper.R
+++ b/R/helper.R
@@ -4,13 +4,27 @@ clean_stop <- function(...)
stop(..., call. = FALSE)
}
+# email_kwb --------------------------------------------------------------------
+email_kwb <- function(
+ given,
+ family,
+ full_name = paste0(given, family, sep = ".")
+)
+{
+ paste0(tolower(full_name), "@kompetenz-wasser.de")
+}
+
+# get_from_namespace -----------------------------------------------------------
+#' @importFrom utils getFromNamespace
+get_from_namespace <- utils::getFromNamespace
+
# get_pkgname ------------------------------------------------------------------
#' Helper Function: Get Package Name
#'
-#' @param pkgname either package name or NULL. In this
-#' case the DESCRIPTION file in the current working
-#' directory is read and is package name ues (default: NULL)
+#' @param pkgname either package name or NULL. In the latter case the
+#' DESCRIPTION file in the current working directory is read and the
+#' package name from there is used (default: NULL)
#'
#' @return package name
#' @export
@@ -56,10 +70,13 @@ git_check_if_windows <- function(git_exe)
# kwb_author -------------------------------------------------------------------
-#' Get Information About KWB Author
+#' Get information about a KWB author
#'
+#' @param who key in the author registry (currently only "rustler")
+#' @return list with elements `name`, `orcid`, `url`
#' @importFrom kwb.utils selectElements
#' @keywords internal
+#' @noRd
kwb_author <- function(who)
{
kwb.utils::selectElements(elements = who, x = list(
@@ -71,10 +88,13 @@ kwb_author <- function(who)
))
}
-#' Get (Default) Information About KWB-R Package
+#' Get (default) information about a KWB-R package
#'
+#' @param pkg key in the package registry (currently only "kwb.umberto")
+#' @return list with elements `name`, `title`, `desc`
#' @importFrom kwb.utils selectElements
#' @keywords internal
+#' @noRd
kwb_package <- function(pkg)
{
kwb.utils::selectElements(elements = pkg, x = list(
@@ -121,7 +141,6 @@ path_to_git <- function()
#' @param dbg print debug messages (default: TRUE)
#' @return sets globally user.name and user.email in Git
#' @export
-#' @importFrom stringr str_replace
set_github_user <- function(
git_username = "kwb.pkgbuild::use_autopkgdown()",
git_fullname = "kwb.pkgbuild::use_autopkgdown()",
@@ -132,13 +151,9 @@ set_github_user <- function(
dbg = TRUE
)
{
+ # Compose KWB e-mail address
if (is.null(git_email)) {
-
- # Replace space with dot
- dot_name <- stringr::str_replace(git_fullname, "\\s+", ".")
-
- # Compose KWB e-mail address
- git_email <- paste0(tolower(dot_name), "@kompetenz-wasser.de")
+ git_email <- email_kwb(full_name = gsub("\\s+", ".", git_fullname))
}
git_exe <- git_check_if_windows(git_exe)
diff --git a/R/read_description.R b/R/read_description.R
index 721a61b..670f6b0 100644
--- a/R/read_description.R
+++ b/R/read_description.R
@@ -1,15 +1,17 @@
# read_description -------------------------------------------------------------
-#' Helper function: read_description
+#' Helper: read selected fields from a `DESCRIPTION` file
#'
-#' @param file path to DESCRIPTION file (default: DESCRIPTION)
+#' @param file path to DESCRIPTION file (default: "DESCRIPTION")
#' @importFrom desc desc
-#' @return list with pkg "name", "title", "desc", "version"
+#' @return list with elements `name`, `title`, `desc`, `version`
+#' @keywords internal
+#' @noRd
read_description <- function(file = "DESCRIPTION")
{
if (! file.exists(file)) clean_stop(
- sprintf("DESCIPTION file not found at: %s.\n", file.path(getwd(), file)),
+ sprintf("DESCRIPTION file not found at: %s.\n", file.path(getwd(), file)),
"Please set working directory with function setwd() properly!"
)
diff --git a/R/use_badges.R b/R/use_badges.R
index 9255450..be7942b 100644
--- a/R/use_badges.R
+++ b/R/use_badges.R
@@ -3,7 +3,7 @@
#' Badge appveyor
#' @param repo name of repository (default: NULL)
#' @param user user name or organisation under which repository defined in
-#' parameter "repo" is hosted (default: KWB-R")
+#' parameter "repo" is hosted (default: "KWB-R")
#' @param domain under which repository is hosted (default: "github")
#'
#' @return generates appveyor badge link
@@ -28,7 +28,7 @@ use_badge_appveyor <- function(repo = NULL, user = "KWB-R", domain = "github")
#' Badge travis
#' @param repo name of repository (default: NULL)
#' @param user user name or organisation under which repository defined in
-#' parameter "repo" is hosted (default: KWB-R")
+#' parameter "repo" is hosted (default: "KWB-R")
#' @return generates travis badge link
#' @export
use_badge_travis <- function(repo = NULL, user = "KWB-R")
@@ -47,10 +47,10 @@ use_badge_travis <- function(repo = NULL, user = "KWB-R")
#' Badge Github Actions RCMD Check
#' @param repo name of repository (default: NULL)
#' @param user user name or organisation under which repository defined in
-#' parameter "repo" is hosted (default: KWB-R")
+#' parameter "repo" is hosted (default: "KWB-R")
#' @param branch default: NULL (i.e. use "default" branch) or user defined branch
#' (e.g. "dev")
-#' @return generates travis badge link
+#' @return generates GitHub Actions R-CMD-check badge markdown
#' @export
use_badge_ghactions_rcmdcheck <- function(repo = NULL, user = "KWB-R",
branch = NULL)
@@ -70,7 +70,7 @@ use_badge_ghactions_rcmdcheck <- function(repo = NULL, user = "KWB-R",
#' Badge Github Actions Pkgdown
#' @param repo name of repository (default: NULL)
#' @param user user name or organisation under which repository defined in
-#' parameter "repo" is hosted (default: KWB-R")
+#' parameter "repo" is hosted (default: "KWB-R")
#' @param branch default: NULL (i.e. use "default" branch) or user defined branch
#' (e.g. "dev")
#' @return generates Github Actions Pkgdown badge link
@@ -93,7 +93,7 @@ use_badge_ghactions_pkgdown <- function(repo = NULL, user = "KWB-R", branch = NU
#' Badge Github Actions
#' @param repo name of repository (default: NULL)
#' @param user user name or organisation under which repository defined in
-#' parameter "repo" is hosted (default: KWB-R")
+#' parameter "repo" is hosted (default: "KWB-R")
#' @param branch default: NULL (i.e. use "default" branch) or user defined branch
#' (e.g. "dev")
#' @return generates Github Actions badges link
@@ -112,7 +112,7 @@ use_badge_ghactions <- function(repo = NULL, user = "KWB-R", branch = NULL)
#' Badge codecov
#' @param repo name of repository (default: NULL)
#' @param user user name or organisation under which repository defined in
-#' parameter "repo" is hosted (default: KWB-R")
+#' parameter "repo" is hosted (default: "KWB-R")
#' @param domain under which repository is hosted (default: "github")
#' @return generates codecov badge link
#' @export
@@ -140,7 +140,7 @@ use_badge_codecov <- function(repo = NULL, user = "KWB-R", domain = "github")
#' @export
use_badge_lifecycle <- function(stage = "experimental")
{
- stages <- usethis:::stages
+ stages <- getFromNamespace("stages", "usethis")
stage <- match.arg(tolower(stage), names(stages))
kwb.utils::resolve(
@@ -215,8 +215,8 @@ is_on_cran <- function(cran_link)
#' Badge R-Universe
#' @param repo name of repository (default: NULL)
#' @param user user name or organisation under which repository defined in
-#' parameter "repo" is hosted (default: KWB-R")
-#' @return generates codecov badge link
+#' parameter "repo" is hosted (default: "KWB-R")
+#' @return generates R-Universe badge markdown
#' @export
use_badge_runiverse <- function(repo = NULL, user = "KWB-R")
{
diff --git a/R/use_codecov.R b/R/use_codecov.R
index cda178a..d824391 100644
--- a/R/use_codecov.R
+++ b/R/use_codecov.R
@@ -6,8 +6,8 @@
#' @export
use_codecov <- function()
{
- usethis:::check_uses_github_actions()
- usethis:::use_dependency("covr", "Suggests")
+ getFromNamespace("check_uses_github_actions", "usethis")()
+ getFromNamespace("use_dependency", "usethis")("covr", "Suggests")
if (! usethis::use_template("codecov.yml", ignore = TRUE)) {
return(invisible(FALSE))
diff --git a/R/use_description.R b/R/use_description.R
index 1a776a2..e7a7a4b 100644
--- a/R/use_description.R
+++ b/R/use_description.R
@@ -16,7 +16,6 @@
#' @return writes DESCRIPTION file using usethis::use_description() with KWB
#' style
#' @importFrom usethis use_description
-#' @importFrom stringr str_split
#' @importFrom tools toTitleCase
#' @export
use_description <- function(
@@ -37,13 +36,11 @@ use_description <- function(
pkg$title <- tools::toTitleCase(pkg$title)
- full_name <- stringr::str_split(string = author$name,pattern = "\\s+")[[1]]
- author_name <- full_name[1]
- author_surname <- full_name[2]
+ full_name <- strsplit(author$name, "\\s+")[[1L]]
+ author_name <- full_name[1L]
+ author_surname <- full_name[2L]
- author_email <- sprintf(
- '%s.%s@kompetenz-wasser.de', tolower(author_name), tolower(author_surname)
- )
+ author_email <- email_kwb(given = author_name, family = author_surname)
author_comment <- if (is.null(author$orcid)) {
"NULL"
diff --git a/R/use_github_ci.R b/R/use_github_ci.R
index 8c65ce6..f69eca1 100644
--- a/R/use_github_ci.R
+++ b/R/use_github_ci.R
@@ -1,17 +1,57 @@
# use_ghactions-----------------------------------------------------------------
#' Adds default .github/workflows/
-#' @return writes .github/workflows/ and adds it .Rbuildignore
+#'
+#' Copies the default GitHub Actions workflows (R-CMD-check, pkgdown,
+#' pr-commands, test-coverage) into `.github/workflows/`. Optionally adds the
+#' Claude Code workflows (`claude.yaml`, `claude-code-review.yaml`) when
+#' `claude = TRUE`. Those workflows require a `CLAUDE_CODE_OAUTH_TOKEN`
+#' repository secret to be configured in GitHub.
+#'
+#' @param claude if `TRUE`, additionally copies the Claude Code workflows
+#' (`claude.yaml` and `claude-code-review.yaml`) into `.github/workflows/`.
+#' Defaults to `FALSE`.
+#' @return writes `.github/workflows/` and adds it to `.Rbuildignore`
#' @importFrom fs dir_copy
#' @export
+use_ghactions <- function(claude = FALSE)
+{
+ fs::dir_copy(
+ path = system.file("templates/ci_github-actions/", package = "kwb.pkgbuild"),
+ new_path = ".github/workflows",
+ overwrite = TRUE
+ )
+
+ if (isTRUE(claude)) {
+ use_ghactions_claude()
+ }
+
+ write_to_rbuildignore(ignore_pattern = "^\\.github$")
+}
+
+# use_ghactions_claude----------------------------------------------------------
-use_ghactions <- function()
+#' Adds Claude Code workflows to .github/workflows/
+#'
+#' Copies the Claude Code workflows (`claude.yaml` and `claude-code-review.yaml`)
+#' into `.github/workflows/`. Requires a `CLAUDE_CODE_OAUTH_TOKEN` repository
+#' secret to be configured in GitHub for the workflows to function.
+#'
+#' @return writes Claude workflow YAML files into `.github/workflows/`
+#' @importFrom fs dir_create file_copy dir_ls
+#' @export
+use_ghactions_claude <- function()
{
+ fs::dir_create(".github/workflows")
-fs::dir_copy(path = system.file("templates/ci_github-actions/",
- package = "kwb.pkgbuild"),
- new_path = ".github/workflows",
- overwrite = TRUE)
+ src_dir <- system.file(
+ "templates/ci_github-actions-claude/",
+ package = "kwb.pkgbuild"
+ )
-write_to_rbuildignore(ignore_pattern = "^\\.github$")
+ fs::file_copy(
+ path = fs::dir_ls(src_dir, glob = "*.yaml"),
+ new_path = ".github/workflows/",
+ overwrite = TRUE
+ )
}
diff --git a/R/use_gitlab_ci.R b/R/use_gitlab_ci.R
index 22f9433..f0feb5a 100644
--- a/R/use_gitlab_ci.R
+++ b/R/use_gitlab_ci.R
@@ -2,7 +2,7 @@
#' Adds .gitlab-ci.yml (if repo contains a "docs" subfolder)
#'
-#' @param dest_dir directoy to write (default: getwd())
+#' @param dest_dir directory to write (default: getwd())
#' @param yml_vector a yml imported as string vector (default:
#' gitlab_ci_template_docs())
#' @return writes .gitlab-ci.yml and adds it .Rbuildignore
@@ -26,7 +26,7 @@ use_gitlab_ci_docs <- function(
# use_gitlab_ci_ghpages---------------------------------------------------------
#' Adds .gitlab-ci.yml (which should be saved in root dir of "gh-pages" branch)
-#' @param dest_dir directoy to write (default:
+#' @param dest_dir directory to write (default:
#' getwd())
#' @param yml_vector a yml imported as string vector (default: gitlab_ci_template_ghpages())
#' @return writes .gitlab-ci.yml
@@ -43,7 +43,7 @@ use_gitlab_ci_ghpages <- function(
# use_gitlab_ci_blogdown--------------------------------------------------------
#' Adds .gitlab-ci.yml (if repo contains on root in a "gh-pages" branch)
-#' @param dest_dir directoy to write (default: getwd())
+#' @param dest_dir directory to write (default: getwd())
#' @param yml_vector a yml imported as string vector (default:
#' gitlab_ci_template_blogdown())
#' @return writes .gitlab-ci.yml
@@ -61,14 +61,13 @@ use_gitlab_ci_blogdown <- function(
#' Adds .gitlab-ci.yml
#'
-#' @param dest_dir directoy to write (default: getwd())
+#' @param dest_dir directory to write (default: getwd())
#' @param yml_vector a yml imported as string vector (default:
#' gitlab_ci_template_pkgdown(), where "/" is replaced with value
#' from DESCRIPTION specified in field URL, e.g.
#' https://github.com/KWB-R/kwb.pkgbuild" sets "KWB-R/kwb.pkgbuild" as
#' "/")
#' @return writes .gitlab-ci.yml
-#' @importFrom stringr str_remove
#' @importFrom desc desc_get
#' @export
@@ -76,10 +75,8 @@ use_gitlab_ci_pkgdown <- function(
dest_dir = getwd(), yml_vector = gitlab_ci_template_pkgdown()
)
{
- repo <- stringr::str_remove(desc::desc_get("URL"), "^http(s)?://github.com/")
-
- yml_vector <- stringr::str_replace(yml_vector, "/", repo)
-
+ owner_repo <- gsub("^http(s)?://github.com/", "", desc::desc_get("URL"))
+ yml_vector <- gsub("/", owner_repo, yml_vector)
write_gitlab_ci(yml_vector, dest_dir = dest_dir, ignore = TRUE)
}
diff --git a/R/use_index_md.R b/R/use_index_md.R
index ab50a5a..2b59377 100644
--- a/R/use_index_md.R
+++ b/R/use_index_md.R
@@ -1,14 +1,21 @@
# use_index_md ----------------------------------------------------------------
-#' Use index.md (used for pkgdown::build_home())
-#' @param user user name or organisation under which repository defined in\cr
-#' parameter "repo" is hosted (default: "KWB-R")\cr
-#' @param domain under which repository is hosted (default: "github")
-#' @param stage badge declares the developmental stage of a package, according
-#' to [https://www.tidyverse.org/lifecycle/](https://www.tidyverse.org/lifecycle/),
-#' valid arguments are: "experimental", "maturing", "stable", "retired",
-#' "archived", "dormant", "questioning"), (default: "experiment")
-#' @return generates travis badge link
+#' Create KWB-styled \code{index.md}
+#'
+#' Generates an \code{index.md} (used by \code{pkgdown::build_home()}) with the
+#' KWB default badge set (GitHub Actions, codecov, lifecycle, CRAN, R-universe),
+#' the package description from \code{DESCRIPTION} and an installation snippet.
+#' @param user user name or organisation under which the repository is hosted
+#' (default: "KWB-R")
+#' @param domain under which the repository is hosted (default: "github")
+#' @param stage badge declaring the developmental stage of the package
+#' according to
+#' [https://www.tidyverse.org/lifecycle/](https://www.tidyverse.org/lifecycle/);
+#' valid values are "experimental", "maturing", "stable", "retired",
+#' "archived", "dormant", "questioning" (default: "experimental")
+#' @return writes \code{index.md} (used as `pkgdown` home) and adds the
+#' pattern to \code{.Rbuildignore}. Invisibly returns the character vector
+#' that was written.
#' @export
#' @importFrom desc desc
diff --git a/R/use_installation.R b/R/use_installation.R
index fbd3e56..490040f 100644
--- a/R/use_installation.R
+++ b/R/use_installation.R
@@ -1,11 +1,13 @@
# use_installation -------------------------------------------------------------
-#' Helper function: describe pkg installation in index.Rmd / README.md
+#' Helper: describe pkg installation in index.md / README.md
#'
#' @param pkgname package name
-#' @param user user name or organisation under which repository defined in
-#' parameter "repo" is hosted
-#' @param domain under which repository is hosted
+#' @param user user/organisation hosting the repository
+#' @param domain under which repository is hosted (e.g. "github")
+#' @return character vector with markdown lines for the installation section
+#' @keywords internal
+#' @noRd
use_installation <- function(pkgname, user, domain)
{
url_tutorial_install <-
diff --git a/R/use_mit_license.R b/R/use_mit_license.R
index f34f3c4..882fbd6 100644
--- a/R/use_mit_license.R
+++ b/R/use_mit_license.R
@@ -6,48 +6,48 @@
#' (default: "list(name = kwb.pkgbuild:::kwb_string(), start_year = NULL)")
#' @return creates MIT licence file
#' @importFrom usethis use_mit_license
-#' @importFrom stringr str_detect
#' @importFrom fs file_copy
#' @importFrom kwb.utils catAndRun
#' @export
use_mit_license <- function(
- copyright_holder = list(name = kwb_string(), start_year = NULL)
+ copyright_holder = list(name = kwb_string(), start_year = NULL)
)
{
- kwb.utils::catAndRun("Creating KWB MIT LICENSE/LICENSE.md files",
- expr = {
- usethis::use_mit_license(copyright_holder = copyright_holder$name)})
+ kwb.utils::catAndRun("Creating KWB MIT LICENSE/LICENSE.md files", {
+ usethis::use_mit_license(copyright_holder = copyright_holder$name)
+ })
+ this_year <- format(Sys.Date(), format = "%Y")
- copyright_years <- ifelse(!is.null(copyright_holder$start_year),
- sprintf("%s-%s", as.character(copyright_holder$start_year),
- format(Sys.Date(), format = "%Y")),
- format(Sys.Date(), format = "%Y"))
+ copyright_years <- ifelse(
+ is.null(copyright_holder$start_year),
+ this_year,
+ sprintf("%s-%s", as.character(copyright_holder$start_year), this_year)
+ )
- if (! is.null(copyright_holder$start_year)) {
+ if (is.null(copyright_holder$start_year)) {
+ return()
+ }
- kwb.utils::catAndRun("Modifying start year in MIT LICENSE (CRAN version)",
- expr = {
- writeLines(text = sprintf("YEAR: %s\nCOPYRIGHT HOLDER: %s",
- copyright_years,
- copyright_holder$name),
- con = "LICENSE")
- })
+ kwb.utils::catAndRun("Modifying start year in MIT LICENSE (CRAN version)", {
+ writeLines(
+ text = sprintf(
+ "YEAR: %s\nCOPYRIGHT HOLDER: %s",
+ copyright_years,
+ copyright_holder$name
+ ),
+ con = "LICENSE"
+ )
+ })
- kwb.utils::catAndRun("Modifying start year in MIT LICENSE.md",
- expr = {
+ kwb.utils::catAndRun("Modifying start year in MIT LICENSE.md", {
lic_txt <- readLines("LICENSE.md")
- index <- stringr::str_detect(lic_txt,pattern = "^Copyright\\s+\\(c\\)")
-
+ index <- grep("^Copyright\\s+\\(c\\)", lic_txt)
lic_txt[index] <- sprintf(
"Copyright (c) %s %s",
copyright_years,
copyright_holder$name
)
-
- writeLines(lic_txt, "LICENSE.md")})
-
-
- }
-
+ writeLines(lic_txt, "LICENSE.md")
+ })
}
diff --git a/R/use_news_md.R b/R/use_news_md.R
index 8dabafc..ebbdd57 100644
--- a/R/use_news_md.R
+++ b/R/use_news_md.R
@@ -32,7 +32,7 @@ use_news_md <- function(
if (fs::file_exists(news_md)) {
warning(
"No 'NEWS.md' created by kwb.pkgbuild::use_news_md(),\n",
- "because 'NEWS.md' is aleady existing. Please delete it first!"
+ "because 'NEWS.md' already exists. Please delete it first!"
)
} else {
writeLines(news_txt, con = "NEWS.md")
diff --git a/R/use_pkg.R b/R/use_pkg.R
index 9ab845d..266980a 100644
--- a/R/use_pkg.R
+++ b/R/use_pkg.R
@@ -26,12 +26,14 @@
#' "archived", "dormant", "questioning"), (default: "experiment")
#' @return writes DESCRIPTION file using usethis::use_description() with KWB
#' style
-#' @importFrom stringr str_detect
#' @importFrom fs dir_create
#' @param auto_build_pkgdown prepare Travis for pkgdown::build_site() (default:
#' FALSE), only possible if GITHUB repo already existing
+#' @param claude if TRUE, additionally adds the Claude Code GitHub Actions
+#' workflows (claude.yaml, claude-code-review.yaml). Requires the repository
+#' secret CLAUDE_CODE_OAUTH_TOKEN to be configured in GitHub. (default: FALSE)
#' @param dbg print debug messages (default: TRUE)
-#' @param ... additional arguments passed to use_autopkgdown() (only releveant
+#' @param ... additional arguments passed to use_autopkgdown() (only relevant
#' if "auto_build_pkgdown" == TRUE)
#' @export
use_pkg <- function(
@@ -45,6 +47,7 @@ use_pkg <- function(
domain = "github",
stage = "experimental",
auto_build_pkgdown = FALSE,
+ claude = FALSE,
dbg = TRUE,
...
)
@@ -55,10 +58,8 @@ use_pkg <- function(
copyright_holder_name = copyright_holder$name, funder = funder
)
- # Create MIT LICENSE file
- mit_licence <- stringr::str_detect(string = license, pattern = "MIT")
-
- if (mit_licence) {
+ # Create MIT LICENSE file if applicable
+ if (grepl("MIT", license)) {
use_mit_license(copyright_holder)
}
@@ -66,7 +67,7 @@ use_pkg <- function(
use_pkgdown(author, copyright_holder$name, pkg$name, user, domain)
# Update Github Actions
- use_ghactions()
+ use_ghactions(claude = claude)
# Use codecov
use_codecov()
diff --git a/R/use_pkg_skeleton.R b/R/use_pkg_skeleton.R
index c981b85..a72072f 100644
--- a/R/use_pkg_skeleton.R
+++ b/R/use_pkg_skeleton.R
@@ -27,8 +27,7 @@ use_pkg_skeleton <- function(pkg_name)
usethis::use_git_ignore(".Rproj.user")
- if (usethis:::is_package()) {
-
+ if (getFromNamespace("is_package", "usethis")()) {
usethis::use_build_ignore(c(
rproj_file, ".Rhistory", ".RData", ".Rproj.user" , ".here"
))
diff --git a/R/use_pkgdown.R b/R/use_pkgdown.R
index cc124a4..dd2341d 100644
--- a/R/use_pkgdown.R
+++ b/R/use_pkgdown.R
@@ -1,14 +1,23 @@
-#' pkgdown for KWB
+#' Set up `pkgdown` with KWB styling
+#'
+#' Calls `usethis::use_pkgdown()` and additionally writes a `_pkgdown.yml`
+#' configured with KWB defaults (Bootstrap 5 + cerulean theme, KWB authors
+#' block, copyright holder logo).
#'
#' @param author list of author attributes (default:
#' kwb.pkgbuild:::kwb_author("rustler"))
#' @param copyright_holder_name name of copyright holder
-#' (default: kwb.pkgbuild:::kwb_string())
+#' (default: kwb.pkgbuild:::kwb_string())
#' @param pkg name of KWB package (default: get_pkgname())
#' @param user name of GitHub user/organisation (default: 'kwb-r')
#' @param domain name of domain for webpage publishing (default: 'github')
-#' @return performs usethis::use_pkgdown() and additionally writes _pkgdown.yml
-#' based on KWB styling
+#' @param kwb_logo_url URL of the KWB logo image embedded in the copyright
+#' holder's `pkgdown` author block (default:
+#' `"https://logos.kompetenz-wasser.io/KWB_Logo_M_Blau_RGB.svg"`)
+#' @param kwb_logo_href URL the KWB logo links to (default:
+#' `"https://www.kompetenz-wasser.de"`)
+#' @return invisibly; as a side effect writes `_pkgdown.yml` with KWB styling
+#' and adds it to `.Rbuildignore`.
#' @importFrom usethis use_pkgdown
#' @importFrom kwb.utils isNaOrEmpty
#' @export
@@ -17,7 +26,9 @@ use_pkgdown <- function(
copyright_holder_name = kwb_string(),
pkg = get_pkgname(),
user = "kwb-r",
- domain = "github"
+ domain = "github",
+ kwb_logo_url = "https://logos.kompetenz-wasser.io/KWB_Logo_M_Blau_RGB.svg",
+ kwb_logo_href = "https://www.kompetenz-wasser.de"
)
{
usethis::use_pkgdown()
@@ -36,10 +47,11 @@ use_pkgdown <- function(
if (copyright_holder_name == kwb_string()) {
authors <- c(authors, stats::setNames(nm = copyright_holder_name, list(list(
- href = "http://www.kompetenz-wasser.de",
- html = paste0(
- "
")
+ href = kwb_logo_href,
+ html = sprintf(
+ "
",
+ kwb_logo_url
+ )
))))
}
diff --git a/R/use_readme_md.R b/R/use_readme_md.R
index d3d4f15..384cef6 100644
--- a/R/use_readme_md.R
+++ b/R/use_readme_md.R
@@ -1,14 +1,20 @@
# use_readme_md ----------------------------------------------------------------
-#' Use README
-#' @param user user name or organisation under which repository defined in\cr
-#' parameter "repo" is hosted (default: "KWB-R")\cr
-#' @param domain under which repository is hosted (default: "github")
-#' @param stage badge declares the developmental stage of a package, according
-#' to [https://www.tidyverse.org/lifecycle/](https://www.tidyverse.org/lifecycle/),
-#' valid arguments are: "experimental", "maturing", "stable", "retired",
-#' "archived", "dormant", "questioning"), (default: "experiment")
-#' @return generates README.md
+#' Create KWB-styled `README.md`
+#'
+#' Generates a `README.md` with the KWB default badge set, the package
+#' description from `DESCRIPTION`, an installation snippet and links to the
+#' release and development documentation websites.
+#'
+#' @param user user name or organisation under which the repository is hosted
+#' (default: "KWB-R")
+#' @param domain under which the repository is hosted (default: "github")
+#' @param stage badge declaring the developmental stage of the package
+#' according to
+#' [https://www.tidyverse.org/lifecycle/](https://www.tidyverse.org/lifecycle/);
+#' valid values are "experimental", "maturing", "stable", "retired",
+#' "archived", "dormant", "questioning" (default: "experimental")
+#' @return writes `README.md` and adds it to `.Rbuildignore`
#' @export
#' @importFrom desc desc
diff --git a/_pkgdown.yml b/_pkgdown.yml
index e193371..f0d8678 100644
--- a/_pkgdown.yml
+++ b/_pkgdown.yml
@@ -10,7 +10,7 @@ authors:
alt='Project FAKIN' width='72' />
Kompetenzzentrum Wasser Berlin gGmbH (KWB):
href: https://www.kompetenz-wasser.de
- html:
template:
diff --git a/inst/extdata/delete-workflow-runs.R b/inst/extdata/delete-workflow-runs.R
new file mode 100644
index 0000000..1728d15
--- /dev/null
+++ b/inst/extdata/delete-workflow-runs.R
@@ -0,0 +1,118 @@
+if (FALSE)
+{
+ run_info <- get_info_on_last_workflow_runs(
+ repo = "kwb.nextcloud",
+ per_page = 50L,
+ "name",
+ "conclusion"
+ )
+
+ View(run_info)
+
+ nrow(run_info)
+
+ range(run_info$run_started_at)
+
+ delete_runs(urls = run_info$url)
+}
+
+`%>%` <- magrittr::`%>%`
+
+# get_info_on_last_workflow_runs -----------------------------------------------
+get_info_on_last_workflow_runs <- function(repo, per_page = 30L, ...)
+{
+ result <- get_workflow_runs(repo)
+
+ page <- last_page(result$total_count, per_page)
+
+ result <- get_workflow_runs(repo, per_page = per_page, page = page)
+
+ x <- result$workflow_runs
+
+ stopifnot(length(x) <= per_page)
+
+ do.call(rbind, lapply(x, function(xx) {
+ as.data.frame(kwb.utils::selectElements(xx, c(
+ "url",
+ "run_started_at",
+ "status",
+ ...
+ )))
+ }))
+}
+
+# get_workflow_runs ------------------------------------------------------------
+get_workflow_runs <- function(repo, per_page = 30L, page = 1L)
+{
+ endpoints <- list(
+ runs = "/repos///actions/runs?",
+ runs_pars = "per_page=&page=",
+ api = "https://api.github.com",
+ owner = "KWB-R"
+ )
+
+ # List workflow runs for a repository
+ response <- get_response(
+ url = kwb.utils::resolve(
+ "runs",
+ endpoints,
+ repo = repo,
+ per_page = per_page,
+ page = page
+ )
+ )
+
+ if (httr::status_code(response) == 403L) {
+ print(response)
+ }
+
+ httr::content(response)
+}
+
+# get_response -----------------------------------------------------------------
+get_response <- function(url, token = github_token(), ...)
+{
+ httr::GET(url, headers = create_header(token, ...))
+}
+
+# github_token -----------------------------------------------------------------
+github_token <- function()
+{
+ Sys.getenv("GITHUB_PAT")
+}
+
+# create_header ----------------------------------------------------------------
+create_header <- function(token, ...)
+{
+ list(
+ Authorization = paste("token", token),
+ ...
+ )
+}
+
+# last_page --------------------------------------------------------------------
+last_page <- function(n_runs, per_page)
+{
+ ((n_runs - 1L) %/% per_page) + 1L
+}
+
+# delete_runs ------------------------------------------------------------------
+delete_runs <- function(urls, token = github_token())
+{
+ invisible(sapply(seq_along(urls), function(i) {
+
+ url <- urls[i]
+
+ kwb.utils::catAndRun(
+ sprintf("Deleting %d/%d: %s ", i, length(urls), url),
+ expr = {
+ config <- do.call(httr::add_headers, create_header(token))
+ response <- httr::DELETE(url, config)
+ if (httr::status_code(response) != 204L) {
+ print(response)
+ stop("DELETE failed.")
+ }
+ }
+ )
+ }))
+}
diff --git a/inst/templates/ci_github-actions-claude/claude-code-review.yaml b/inst/templates/ci_github-actions-claude/claude-code-review.yaml
new file mode 100644
index 0000000..10d2e3d
--- /dev/null
+++ b/inst/templates/ci_github-actions-claude/claude-code-review.yaml
@@ -0,0 +1,40 @@
+name: Claude Code Review
+
+on:
+ pull_request:
+ types: [opened, synchronize]
+
+jobs:
+ claude-review:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pull-requests: read
+ issues: read
+ id-token: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 1
+
+ - name: Run Claude Code Review
+ id: claude-review
+ uses: anthropics/claude-code-action@v1
+ with:
+ claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
+ prompt: |
+ REPO: ${{ github.repository }}
+ PR NUMBER: ${{ github.event.pull_request.number }}
+
+ Please review this pull request and think hard about correctness,
+ edge cases, and consistency with the rest of the codebase. Use the
+ repository's CLAUDE.md for guidance if available.
+ Focus on:
+ - Code quality and R package best practices
+ - Potential bugs or logic issues
+ - Test coverage
+ - Documentation (roxygen2) completeness
+ - Consistency with the existing codebase
+ claude_args: '--model claude-opus-4-7 --allowed-tools "mcp__github_inline_comment__create_inline_comment,Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"'
diff --git a/inst/templates/ci_github-actions-claude/claude.yaml b/inst/templates/ci_github-actions-claude/claude.yaml
new file mode 100644
index 0000000..49f70bf
--- /dev/null
+++ b/inst/templates/ci_github-actions-claude/claude.yaml
@@ -0,0 +1,38 @@
+name: Claude Code
+
+on:
+ issue_comment:
+ types: [created]
+ pull_request_review_comment:
+ types: [created]
+ issues:
+ types: [opened, assigned]
+ pull_request_review:
+ types: [submitted]
+
+jobs:
+ claude:
+ if: |
+ (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
+ (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
+ (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
+ (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pull-requests: read
+ issues: read
+ id-token: write
+ actions: read
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 1
+
+ - name: Run Claude Code
+ id: claude
+ uses: anthropics/claude-code-action@v1
+ with:
+ claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
+ claude_args: '--model claude-opus-4-7'
diff --git a/inst/templates/ci_github-actions/R-CMD-check.yaml b/inst/templates/ci_github-actions/R-CMD-check.yaml
index 20bd49a..9f9476b 100644
--- a/inst/templates/ci_github-actions/R-CMD-check.yaml
+++ b/inst/templates/ci_github-actions/R-CMD-check.yaml
@@ -22,62 +22,33 @@ jobs:
fail-fast: false
matrix:
config:
- - {os: macOS-latest, r: 'release'}
- - {os: ubuntu-20.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"}
+ - {os: macos-latest, r: 'release'}
+ - {os: ubuntu-latest, r: 'release'}
- {os: windows-latest, r: 'devel'}
- - {os: windows-latest, r: 'oldrel'}
+ - {os: windows-latest, r: 'oldrel-1'}
- {os: windows-latest, r: 'release'}
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
- R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
- RSPM: ${{ matrix.config.rspm }}
+ R_KEEP_PKG_SOURCE: yes
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
+
+ - uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
+ http-user-agent: ${{ matrix.config.http-user-agent }}
use-public-rspm: true
- - uses: r-lib/actions/setup-pandoc@v2
-
- - name: Query dependencies
- run: |
- install.packages('remotes')
- saveRDS(remotes::dev_package_deps(dependencies = TRUE), "depends.Rds", version = 2)
- shell: Rscript {0}
-
- - name: Cache R packages
- if: runner.os != 'Windows'
- uses: actions/cache@v1
+ - uses: r-lib/actions/setup-r-dependencies@v2
with:
- path: ${{ env.R_LIBS_USER }}
- key: ${{ runner.os }}-r-${{ matrix.config.r }}-3-${{ hashFiles('depends.Rds') }}
- restore-keys: ${{ runner.os }}-r-${{ matrix.config.r }}-3-
-
- - name: Install system dependencies
- if: runner.os == 'Linux'
- env:
- RHUB_PLATFORM: linux-x86_64-ubuntu-gcc
- run: |
- Rscript -e "remotes::install_github('r-hub/sysreqs')"
- sysreqs=$(Rscript -e "cat(sysreqs::sysreq_commands('DESCRIPTION'))")
- sudo -s eval "$sysreqs"
- - name: Install dependencies
- run: |
- remotes::install_deps(dependencies = TRUE)
- remotes::install_cran("rcmdcheck")
- shell: Rscript {0}
-
- - name: Check
- run: rcmdcheck::rcmdcheck(args = "--no-manual", error_on = "warning", check_dir = "check")
- shell: Rscript {0}
+ extra-packages: any::rcmdcheck
+ needs: check
- - name: Upload check results
- if: failure()
- uses: actions/upload-artifact@main
+ - uses: r-lib/actions/check-r-package@v2
with:
- name: ${{ runner.os }}-r${{ matrix.config.r }}-results
- path: check
+ upload-snapshots: true
+ args: 'c("--no-manual", "--as-cran")'
diff --git a/inst/templates/ci_github-actions/pkgdown.yaml b/inst/templates/ci_github-actions/pkgdown.yaml
index ac3ba07..2d703f6 100644
--- a/inst/templates/ci_github-actions/pkgdown.yaml
+++ b/inst/templates/ci_github-actions/pkgdown.yaml
@@ -4,50 +4,49 @@ on:
- main
- master
- dev
+ pull_request:
+ branches:
+ - main
+ - master
+ - dev
+ release:
+ types: [published]
+ workflow_dispatch:
name: pkgdown
jobs:
pkgdown:
- runs-on: windows-latest
+ runs-on: ubuntu-latest
+ # Only restrict concurrency for non-PR jobs
+ concurrency:
+ group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }}
env:
- CURL_SSL_BACKEND: "openssl"
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
+ permissions:
+ contents: write
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
+
+ - uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true
- - uses: r-lib/actions/setup-pandoc@v2
-
- - name: Query dependencies
- run: |
- install.packages('remotes')
- saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
- writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
- shell: Rscript {0}
-
- - name: Cache R packages
- uses: actions/cache@v2
+ - uses: r-lib/actions/setup-r-dependencies@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-
+ extra-packages: any::pkgdown, local::.
+ needs: website
- - name: Install dependencies
- run: |
- remotes::install_deps(dependencies = TRUE)
- install.packages("pkgdown", type = "binary")
+ - name: Build site
+ run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
shell: Rscript {0}
- - name: Install package
- run: R CMD INSTALL .
- shell: cmd
-
- - name: Deploy package
- run: |
- git config --local user.email "actions@github.com"
- git config --local user.name "GitHub Actions"
- Rscript -e 'pkgdown::deploy_to_branch(new_process = FALSE)'
+ - name: Deploy to GitHub pages
+ if: github.event_name != 'pull_request'
+ uses: JamesIves/github-pages-deploy-action@v4.5.0
+ with:
+ clean: false
+ branch: gh-pages
+ folder: docs
diff --git a/inst/templates/ci_github-actions/pr-commands.yaml b/inst/templates/ci_github-actions/pr-commands.yaml
index 0d3cb71..33cfb6c 100644
--- a/inst/templates/ci_github-actions/pr-commands.yaml
+++ b/inst/templates/ci_github-actions/pr-commands.yaml
@@ -1,51 +1,85 @@
on:
issue_comment:
types: [created]
+
name: Commands
+
jobs:
document:
- if: startsWith(github.event.comment.body, '/document')
+ if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/document') }}
name: document
- runs-on: macOS-latest
+ runs-on: ubuntu-latest
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
+ permissions:
+ contents: write
+ pull-requests: write
steps:
- - uses: actions/checkout@v2
- - uses: r-lib/actions/pr-fetch@master
+ - uses: actions/checkout@v4
+
+ - uses: r-lib/actions/pr-fetch@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- - uses: r-lib/actions/setup-r@master
- - name: Install dependencies
- run: Rscript -e 'install.packages(c("remotes", "roxygen2"))' -e 'remotes::install_deps(dependencies = TRUE)'
+
+ - uses: r-lib/actions/setup-r@v2
+ with:
+ use-public-rspm: true
+
+ - uses: r-lib/actions/setup-r-dependencies@v2
+ with:
+ extra-packages: any::roxygen2
+ needs: pr-document
+
- name: Document
- run: Rscript -e 'roxygen2::roxygenise()'
+ run: roxygen2::roxygenise()
+ shell: Rscript {0}
+
- name: commit
run: |
+ git config --local user.name "$GITHUB_ACTOR"
+ git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
git add man/\* NAMESPACE
git commit -m 'Document'
- - uses: r-lib/actions/pr-push@master
+
+ - uses: r-lib/actions/pr-push@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
+
style:
- if: startsWith(github.event.comment.body, '/style')
+ if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/style') }}
name: style
- runs-on: macOS-latest
+ runs-on: ubuntu-latest
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
+ permissions:
+ contents: write
+ pull-requests: write
steps:
- - uses: actions/checkout@v2
- - uses: r-lib/actions/pr-fetch@master
+ - uses: actions/checkout@v4
+
+ - uses: r-lib/actions/pr-fetch@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- - uses: r-lib/actions/setup-r@master
+
+ - uses: r-lib/actions/setup-r@v2
+ with:
+ use-public-rspm: true
+
- name: Install dependencies
- run: Rscript -e 'install.packages("styler")'
+ run: install.packages("styler")
+ shell: Rscript {0}
+
- name: Style
- run: Rscript -e 'styler::style_pkg()'
+ run: styler::style_pkg()
+ shell: Rscript {0}
+
- name: commit
run: |
+ git config --local user.name "$GITHUB_ACTOR"
+ git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
git add \*.R
git commit -m 'Style'
- - uses: r-lib/actions/pr-push@master
+
+ - uses: r-lib/actions/pr-push@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/inst/templates/ci_github-actions/test-coverage.yaml b/inst/templates/ci_github-actions/test-coverage.yaml
index 0f014df..254c6db 100644
--- a/inst/templates/ci_github-actions/test-coverage.yaml
+++ b/inst/templates/ci_github-actions/test-coverage.yaml
@@ -12,37 +12,50 @@ name: test-coverage
jobs:
test-coverage:
- runs-on: windows-latest
+ runs-on: ubuntu-latest
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
+
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2
+ with:
+ use-public-rspm: true
- - uses: r-lib/actions/setup-pandoc@v2
+ - uses: r-lib/actions/setup-r-dependencies@v2
+ with:
+ extra-packages: any::covr, any::xml2
+ needs: coverage
- - name: Query dependencies
+ - name: Test coverage
run: |
- install.packages('remotes')
- saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
- writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
+ cov <- covr::package_coverage(
+ quiet = FALSE,
+ clean = FALSE,
+ install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package")
+ )
+ covr::to_cobertura(cov)
shell: Rscript {0}
- - name: Cache R packages
- uses: actions/cache@v1
+ - uses: codecov/codecov-action@v4
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 dependencies
+ fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }}
+ file: ./cobertura.xml
+ plugin: noop
+ disable_search: true
+ token: ${{ secrets.CODECOV_TOKEN }}
+
+ - name: Show testthat output
+ if: always()
run: |
- install.packages(c("remotes"))
- remotes::install_deps(dependencies = TRUE)
- remotes::install_cran("covr")
- shell: Rscript {0}
+ ## --------------------------------------------------------------------
+ find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true
+ shell: bash
- - name: Test coverage
- run: covr::codecov()
- shell: Rscript {0}
+ - name: Upload test results
+ if: failure()
+ uses: actions/upload-artifact@v4
+ with:
+ name: coverage-test-failures
+ path: ${{ runner.temp }}/package
diff --git a/man/get_pkgname.Rd b/man/get_pkgname.Rd
index 12f9da5..d1b5568 100644
--- a/man/get_pkgname.Rd
+++ b/man/get_pkgname.Rd
@@ -7,9 +7,9 @@
get_pkgname(pkgname = NULL)
}
\arguments{
-\item{pkgname}{either package name or NULL. In this
-case the DESCRIPTION file in the current working
-directory is read and is package name ues (default: NULL)}
+\item{pkgname}{either package name or NULL. In the latter case the
+DESCRIPTION file in the current working directory is read and the
+package name from there is used (default: NULL)}
}
\value{
package name
diff --git a/man/github_push.Rd b/man/github_push.Rd
deleted file mode 100644
index f148a96..0000000
--- a/man/github_push.Rd
+++ /dev/null
@@ -1,12 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/deploy_site_github_with_extra_files.R
-\name{github_push}
-\alias{github_push}
-\title{github_push}
-\usage{
-github_push(dir, commit_message, remote, branch)
-}
-\description{
-github_push
-}
-\keyword{internal}
diff --git a/man/kwb_author.Rd b/man/kwb_author.Rd
deleted file mode 100644
index 0ae53aa..0000000
--- a/man/kwb_author.Rd
+++ /dev/null
@@ -1,12 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/helper.R
-\name{kwb_author}
-\alias{kwb_author}
-\title{Get Information About KWB Author}
-\usage{
-kwb_author(who)
-}
-\description{
-Get Information About KWB Author
-}
-\keyword{internal}
diff --git a/man/kwb_package.Rd b/man/kwb_package.Rd
deleted file mode 100644
index 9e8520c..0000000
--- a/man/kwb_package.Rd
+++ /dev/null
@@ -1,12 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/helper.R
-\name{kwb_package}
-\alias{kwb_package}
-\title{Get (Default) Information About KWB-R Package}
-\usage{
-kwb_package(pkg)
-}
-\description{
-Get (Default) Information About KWB-R Package
-}
-\keyword{internal}
diff --git a/man/read_description.Rd b/man/read_description.Rd
deleted file mode 100644
index 81a2585..0000000
--- a/man/read_description.Rd
+++ /dev/null
@@ -1,17 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/read_description.R
-\name{read_description}
-\alias{read_description}
-\title{Helper function: read_description}
-\usage{
-read_description(file = "DESCRIPTION")
-}
-\arguments{
-\item{file}{path to DESCRIPTION file (default: DESCRIPTION)}
-}
-\value{
-list with pkg "name", "title", "desc", "version"
-}
-\description{
-Helper function: read_description
-}
diff --git a/man/use_badge_appveyor.Rd b/man/use_badge_appveyor.Rd
index 0aebcf9..ada8c9d 100644
--- a/man/use_badge_appveyor.Rd
+++ b/man/use_badge_appveyor.Rd
@@ -10,7 +10,7 @@ use_badge_appveyor(repo = NULL, user = "KWB-R", domain = "github")
\item{repo}{name of repository (default: NULL)}
\item{user}{user name or organisation under which repository defined in
-parameter "repo" is hosted (default: KWB-R")}
+parameter "repo" is hosted (default: "KWB-R")}
\item{domain}{under which repository is hosted (default: "github")}
}
diff --git a/man/use_badge_codecov.Rd b/man/use_badge_codecov.Rd
index 9a24ff8..03123f7 100644
--- a/man/use_badge_codecov.Rd
+++ b/man/use_badge_codecov.Rd
@@ -10,7 +10,7 @@ use_badge_codecov(repo = NULL, user = "KWB-R", domain = "github")
\item{repo}{name of repository (default: NULL)}
\item{user}{user name or organisation under which repository defined in
-parameter "repo" is hosted (default: KWB-R")}
+parameter "repo" is hosted (default: "KWB-R")}
\item{domain}{under which repository is hosted (default: "github")}
}
diff --git a/man/use_badge_ghactions.Rd b/man/use_badge_ghactions.Rd
index 52e5d21..364d76d 100644
--- a/man/use_badge_ghactions.Rd
+++ b/man/use_badge_ghactions.Rd
@@ -10,7 +10,7 @@ use_badge_ghactions(repo = NULL, user = "KWB-R", branch = NULL)
\item{repo}{name of repository (default: NULL)}
\item{user}{user name or organisation under which repository defined in
-parameter "repo" is hosted (default: KWB-R")}
+parameter "repo" is hosted (default: "KWB-R")}
\item{branch}{default: NULL (i.e. use "default" branch) or user defined branch
(e.g. "dev")}
diff --git a/man/use_badge_ghactions_pkgdown.Rd b/man/use_badge_ghactions_pkgdown.Rd
index 9cce992..a6b8146 100644
--- a/man/use_badge_ghactions_pkgdown.Rd
+++ b/man/use_badge_ghactions_pkgdown.Rd
@@ -10,7 +10,7 @@ use_badge_ghactions_pkgdown(repo = NULL, user = "KWB-R", branch = NULL)
\item{repo}{name of repository (default: NULL)}
\item{user}{user name or organisation under which repository defined in
-parameter "repo" is hosted (default: KWB-R")}
+parameter "repo" is hosted (default: "KWB-R")}
\item{branch}{default: NULL (i.e. use "default" branch) or user defined branch
(e.g. "dev")}
diff --git a/man/use_badge_ghactions_rcmdcheck.Rd b/man/use_badge_ghactions_rcmdcheck.Rd
index 1213649..e845a37 100644
--- a/man/use_badge_ghactions_rcmdcheck.Rd
+++ b/man/use_badge_ghactions_rcmdcheck.Rd
@@ -10,13 +10,13 @@ use_badge_ghactions_rcmdcheck(repo = NULL, user = "KWB-R", branch = NULL)
\item{repo}{name of repository (default: NULL)}
\item{user}{user name or organisation under which repository defined in
-parameter "repo" is hosted (default: KWB-R")}
+parameter "repo" is hosted (default: "KWB-R")}
\item{branch}{default: NULL (i.e. use "default" branch) or user defined branch
(e.g. "dev")}
}
\value{
-generates travis badge link
+generates GitHub Actions R-CMD-check badge markdown
}
\description{
Badge Github Actions RCMD Check
diff --git a/man/use_badge_runiverse.Rd b/man/use_badge_runiverse.Rd
index 7c2b382..d8bae9f 100644
--- a/man/use_badge_runiverse.Rd
+++ b/man/use_badge_runiverse.Rd
@@ -10,10 +10,10 @@ use_badge_runiverse(repo = NULL, user = "KWB-R")
\item{repo}{name of repository (default: NULL)}
\item{user}{user name or organisation under which repository defined in
-parameter "repo" is hosted (default: KWB-R")}
+parameter "repo" is hosted (default: "KWB-R")}
}
\value{
-generates codecov badge link
+generates R-Universe badge markdown
}
\description{
Badge R-Universe
diff --git a/man/use_badge_travis.Rd b/man/use_badge_travis.Rd
index 15b7843..e68027d 100644
--- a/man/use_badge_travis.Rd
+++ b/man/use_badge_travis.Rd
@@ -10,7 +10,7 @@ use_badge_travis(repo = NULL, user = "KWB-R")
\item{repo}{name of repository (default: NULL)}
\item{user}{user name or organisation under which repository defined in
-parameter "repo" is hosted (default: KWB-R")}
+parameter "repo" is hosted (default: "KWB-R")}
}
\value{
generates travis badge link
diff --git a/man/use_ghactions.Rd b/man/use_ghactions.Rd
index c1930a8..5d047b9 100644
--- a/man/use_ghactions.Rd
+++ b/man/use_ghactions.Rd
@@ -4,11 +4,20 @@
\alias{use_ghactions}
\title{Adds default .github/workflows/}
\usage{
-use_ghactions()
+use_ghactions(claude = FALSE)
+}
+\arguments{
+\item{claude}{if \code{TRUE}, additionally copies the Claude Code workflows
+(\code{claude.yaml} and \code{claude-code-review.yaml}) into \code{.github/workflows/}.
+Defaults to \code{FALSE}.}
}
\value{
-writes .github/workflows/ and adds it .Rbuildignore
+writes \code{.github/workflows/} and adds it to \code{.Rbuildignore}
}
\description{
-Adds default .github/workflows/
+Copies the default GitHub Actions workflows (R-CMD-check, pkgdown,
+pr-commands, test-coverage) into \code{.github/workflows/}. Optionally adds the
+Claude Code workflows (\code{claude.yaml}, \code{claude-code-review.yaml}) when
+\code{claude = TRUE}. Those workflows require a \code{CLAUDE_CODE_OAUTH_TOKEN}
+repository secret to be configured in GitHub.
}
diff --git a/man/use_ghactions_claude.Rd b/man/use_ghactions_claude.Rd
new file mode 100644
index 0000000..aa473c3
--- /dev/null
+++ b/man/use_ghactions_claude.Rd
@@ -0,0 +1,16 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/use_github_ci.R
+\name{use_ghactions_claude}
+\alias{use_ghactions_claude}
+\title{Adds Claude Code workflows to .github/workflows/}
+\usage{
+use_ghactions_claude()
+}
+\value{
+writes Claude workflow YAML files into \code{.github/workflows/}
+}
+\description{
+Copies the Claude Code workflows (\code{claude.yaml} and \code{claude-code-review.yaml})
+into \code{.github/workflows/}. Requires a \code{CLAUDE_CODE_OAUTH_TOKEN} repository
+secret to be configured in GitHub for the workflows to function.
+}
diff --git a/man/use_gitlab_ci_blogdown.Rd b/man/use_gitlab_ci_blogdown.Rd
index 086d596..76145ee 100644
--- a/man/use_gitlab_ci_blogdown.Rd
+++ b/man/use_gitlab_ci_blogdown.Rd
@@ -10,7 +10,7 @@ use_gitlab_ci_blogdown(
)
}
\arguments{
-\item{dest_dir}{directoy to write (default: getwd())}
+\item{dest_dir}{directory to write (default: getwd())}
\item{yml_vector}{a yml imported as string vector (default:
gitlab_ci_template_blogdown())}
diff --git a/man/use_gitlab_ci_docs.Rd b/man/use_gitlab_ci_docs.Rd
index 79deacc..8a577d3 100644
--- a/man/use_gitlab_ci_docs.Rd
+++ b/man/use_gitlab_ci_docs.Rd
@@ -7,7 +7,7 @@
use_gitlab_ci_docs(dest_dir = getwd(), yml_vector = gitlab_ci_template_docs())
}
\arguments{
-\item{dest_dir}{directoy to write (default: getwd())}
+\item{dest_dir}{directory to write (default: getwd())}
\item{yml_vector}{a yml imported as string vector (default:
gitlab_ci_template_docs())}
diff --git a/man/use_gitlab_ci_ghpages.Rd b/man/use_gitlab_ci_ghpages.Rd
index 94d90c1..e453184 100644
--- a/man/use_gitlab_ci_ghpages.Rd
+++ b/man/use_gitlab_ci_ghpages.Rd
@@ -10,7 +10,7 @@ use_gitlab_ci_ghpages(
)
}
\arguments{
-\item{dest_dir}{directoy to write (default:
+\item{dest_dir}{directory to write (default:
getwd())}
\item{yml_vector}{a yml imported as string vector (default: gitlab_ci_template_ghpages())}
diff --git a/man/use_gitlab_ci_pkgdown.Rd b/man/use_gitlab_ci_pkgdown.Rd
index 02c7ba9..08db798 100644
--- a/man/use_gitlab_ci_pkgdown.Rd
+++ b/man/use_gitlab_ci_pkgdown.Rd
@@ -10,7 +10,7 @@ use_gitlab_ci_pkgdown(
)
}
\arguments{
-\item{dest_dir}{directoy to write (default: getwd())}
+\item{dest_dir}{directory to write (default: getwd())}
\item{yml_vector}{a yml imported as string vector (default:
gitlab_ci_template_pkgdown(), where "/" is replaced with value
diff --git a/man/use_index_md.Rd b/man/use_index_md.Rd
index 082a3da..43246a3 100644
--- a/man/use_index_md.Rd
+++ b/man/use_index_md.Rd
@@ -2,24 +2,29 @@
% Please edit documentation in R/use_index_md.R
\name{use_index_md}
\alias{use_index_md}
-\title{Use index.md (used for pkgdown::build_home())}
+\title{Create KWB-styled \code{index.md}}
\usage{
use_index_md(user = "KWB-R", domain = "github", stage = "experimental")
}
\arguments{
-\item{user}{user name or organisation under which repository defined in\cr
-parameter "repo" is hosted (default: "KWB-R")\cr}
+\item{user}{user name or organisation under which the repository is hosted
+(default: "KWB-R")}
-\item{domain}{under which repository is hosted (default: "github")}
+\item{domain}{under which the repository is hosted (default: "github")}
-\item{stage}{badge declares the developmental stage of a package, according
-to [https://www.tidyverse.org/lifecycle/](https://www.tidyverse.org/lifecycle/),
-valid arguments are: "experimental", "maturing", "stable", "retired",
-"archived", "dormant", "questioning"), (default: "experiment")}
+\item{stage}{badge declaring the developmental stage of the package
+according to
+\url{https://www.tidyverse.org/lifecycle/};
+valid values are "experimental", "maturing", "stable", "retired",
+"archived", "dormant", "questioning" (default: "experimental")}
}
\value{
-generates travis badge link
+writes \code{index.md} (used as \code{pkgdown} home) and adds the
+pattern to \code{.Rbuildignore}. Invisibly returns the character vector
+that was written.
}
\description{
-Use index.md (used for pkgdown::build_home())
+Generates an \code{index.md} (used by \code{pkgdown::build_home()}) with the
+KWB default badge set (GitHub Actions, codecov, lifecycle, CRAN, R-universe),
+the package description from \code{DESCRIPTION} and an installation snippet.
}
diff --git a/man/use_installation.Rd b/man/use_installation.Rd
deleted file mode 100644
index f797ba0..0000000
--- a/man/use_installation.Rd
+++ /dev/null
@@ -1,19 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/use_installation.R
-\name{use_installation}
-\alias{use_installation}
-\title{Helper function: describe pkg installation in index.Rmd / README.md}
-\usage{
-use_installation(pkgname, user, domain)
-}
-\arguments{
-\item{pkgname}{package name}
-
-\item{user}{user name or organisation under which repository defined in
-parameter "repo" is hosted}
-
-\item{domain}{under which repository is hosted}
-}
-\description{
-Helper function: describe pkg installation in index.Rmd / README.md
-}
diff --git a/man/use_pkg.Rd b/man/use_pkg.Rd
index ac44d3b..263259d 100644
--- a/man/use_pkg.Rd
+++ b/man/use_pkg.Rd
@@ -15,6 +15,7 @@ use_pkg(
domain = "github",
stage = "experimental",
auto_build_pkgdown = FALSE,
+ claude = FALSE,
dbg = TRUE,
...
)
@@ -54,9 +55,13 @@ to
\item{auto_build_pkgdown}{prepare Travis for pkgdown::build_site() (default:
FALSE), only possible if GITHUB repo already existing}
+\item{claude}{if TRUE, additionally adds the Claude Code GitHub Actions
+workflows (claude.yaml, claude-code-review.yaml). Requires the repository
+secret CLAUDE_CODE_OAUTH_TOKEN to be configured in GitHub. (default: FALSE)}
+
\item{dbg}{print debug messages (default: TRUE)}
-\item{...}{additional arguments passed to use_autopkgdown() (only releveant
+\item{...}{additional arguments passed to use_autopkgdown() (only relevant
if "auto_build_pkgdown" == TRUE)}
}
\value{
diff --git a/man/use_pkgdown.Rd b/man/use_pkgdown.Rd
index 9ab4c1b..4f8981b 100644
--- a/man/use_pkgdown.Rd
+++ b/man/use_pkgdown.Rd
@@ -2,14 +2,16 @@
% Please edit documentation in R/use_pkgdown.R
\name{use_pkgdown}
\alias{use_pkgdown}
-\title{pkgdown for KWB}
+\title{Set up \code{pkgdown} with KWB styling}
\usage{
use_pkgdown(
author = kwb_author("rustler"),
copyright_holder_name = kwb_string(),
pkg = get_pkgname(),
user = "kwb-r",
- domain = "github"
+ domain = "github",
+ kwb_logo_url = "https://logos.kompetenz-wasser.io/KWB_Logo_M_Blau_RGB.svg",
+ kwb_logo_href = "https://www.kompetenz-wasser.de"
)
}
\arguments{
@@ -24,11 +26,20 @@ kwb.pkgbuild:::kwb_author("rustler"))}
\item{user}{name of GitHub user/organisation (default: 'kwb-r')}
\item{domain}{name of domain for webpage publishing (default: 'github')}
+
+\item{kwb_logo_url}{URL of the KWB logo image embedded in the copyright
+holder's \code{pkgdown} author block (default:
+\code{"https://logos.kompetenz-wasser.io/KWB_Logo_M_Blau_RGB.svg"})}
+
+\item{kwb_logo_href}{URL the KWB logo links to (default:
+\code{"https://www.kompetenz-wasser.de"})}
}
\value{
-performs usethis::use_pkgdown() and additionally writes _pkgdown.yml
-based on KWB styling
+invisibly; as a side effect writes \code{_pkgdown.yml} with KWB styling
+and adds it to \code{.Rbuildignore}.
}
\description{
-pkgdown for KWB
+Calls \code{usethis::use_pkgdown()} and additionally writes a \code{_pkgdown.yml}
+configured with KWB defaults (Bootstrap 5 + cerulean theme, KWB authors
+block, copyright holder logo).
}
diff --git a/man/use_readme_md.Rd b/man/use_readme_md.Rd
index ee56a7a..a1aca0e 100644
--- a/man/use_readme_md.Rd
+++ b/man/use_readme_md.Rd
@@ -2,24 +2,27 @@
% Please edit documentation in R/use_readme_md.R
\name{use_readme_md}
\alias{use_readme_md}
-\title{Use README}
+\title{Create KWB-styled \code{README.md}}
\usage{
use_readme_md(user = "KWB-R", domain = "github", stage = "experimental")
}
\arguments{
-\item{user}{user name or organisation under which repository defined in\cr
-parameter "repo" is hosted (default: "KWB-R")\cr}
+\item{user}{user name or organisation under which the repository is hosted
+(default: "KWB-R")}
-\item{domain}{under which repository is hosted (default: "github")}
+\item{domain}{under which the repository is hosted (default: "github")}
-\item{stage}{badge declares the developmental stage of a package, according
-to [https://www.tidyverse.org/lifecycle/](https://www.tidyverse.org/lifecycle/),
-valid arguments are: "experimental", "maturing", "stable", "retired",
-"archived", "dormant", "questioning"), (default: "experiment")}
+\item{stage}{badge declaring the developmental stage of the package
+according to
+\url{https://www.tidyverse.org/lifecycle/};
+valid values are "experimental", "maturing", "stable", "retired",
+"archived", "dormant", "questioning" (default: "experimental")}
}
\value{
-generates README.md
+writes \code{README.md} and adds it to \code{.Rbuildignore}
}
\description{
-Use README
+Generates a \code{README.md} with the KWB default badge set, the package
+description from \code{DESCRIPTION}, an installation snippet and links to the
+release and development documentation websites.
}
diff --git a/tests/testthat/.gitignore b/tests/testthat/.gitignore
new file mode 100644
index 0000000..9e5d89c
--- /dev/null
+++ b/tests/testthat/.gitignore
@@ -0,0 +1,2 @@
+#ignore docs
+docs
diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R
index 8b0d8a2..710ede8 100644
--- a/tests/testthat/helper.R
+++ b/tests/testthat/helper.R
@@ -1,13 +1,23 @@
## Helper for creating temporary R package
-create_pkg_temp <- function() {
-number <- sample(x = 1:10000000,size = 1)
-root_dir <- paste0(stringr::str_replace_all(tempdir(),"\\\\", "/"),
- sprintf("%d", number))
-pkg_name <- "testpkg"
-pkg_dir <- file.path(root_dir, pkg_name)
-kwb.pkgbuild::create_pkg_dir(pkg_dir)
-withr::with_dir(pkg_dir, {kwb.pkgbuild::use_pkg_skeleton(pkg_name)})
-pkg_dir
+create_pkg_temp <- function()
+{
+ number <- sample(x = 1:10000000, size = 1L)
+
+ root_dir <- paste0(
+ kwb.utils::rStylePath(tempdir()),
+ sprintf("%d", number)
+ )
+
+ pkg_name <- "testpkg"
+ pkg_dir <- file.path(root_dir, pkg_name)
+
+ kwb.pkgbuild::create_pkg_dir(pkg_dir)
+
+ withr::with_dir(pkg_dir, {
+ kwb.pkgbuild::use_pkg_skeleton(pkg_name)
+ })
+
+ pkg_dir
}
# create_pkg_temp <- function(root_dir = tempdir()) {
diff --git a/vignettes/github-actions.Rmd b/vignettes/github-actions.Rmd
new file mode 100644
index 0000000..f5e34db
--- /dev/null
+++ b/vignettes/github-actions.Rmd
@@ -0,0 +1,156 @@
+---
+title: "GitHub Actions for KWB-R Packages"
+author: "Michael Rustler, Hauke Sonnenberg"
+date: "`r Sys.Date()`"
+output: rmarkdown::html_vignette
+vignette: >
+ %\VignetteIndexEntry{GitHub Actions for KWB-R Packages}
+ %\VignetteEngine{knitr::rmarkdown}
+ %\VignetteEncoding{UTF-8}
+---
+
+```{r setup, include = FALSE}
+knitr::opts_chunk$set(
+ collapse = TRUE,
+ fig_caption = FALSE,
+ comment = "#>",
+ eval = FALSE
+)
+```
+
+`kwb.pkgbuild` ships a curated set of [GitHub
+Actions](https://github.com/features/actions) workflows that we use across
+all KWB-R packages. The workflows live as templates in
+`inst/templates/ci_github-actions/` (default workflows) and
+`inst/templates/ci_github-actions-claude/` (optional Claude Code
+integration), and are installed into a package's `.github/workflows/`
+directory by `use_ghactions()` / `use_pkg()`.
+
+This vignette explains what the workflows do, how to add or update them, and
+how to enable the optional Claude Code integration.
+
+# 1 Default workflows
+
+`kwb.pkgbuild::use_ghactions()` (also called from `kwb.pkgbuild::use_pkg()`)
+copies four workflows into `.github/workflows/`:
+
+| File | Purpose |
+|:----------------------|:---------------------------------------------------------------------------------------------------------|
+| `R-CMD-check.yaml` | Cross-platform `R CMD check` matrix (macOS, Ubuntu, Windows × `release`, `devel`, `oldrel-1`). |
+| `pkgdown.yaml` | Builds the `pkgdown` site and deploys it to the `gh-pages` branch on push to `main`/`master`/`dev`. |
+| `test-coverage.yaml` | Runs `covr::package_coverage()` and uploads the report to [codecov.io](https://codecov.io). |
+| `pr-commands.yaml` | Reacts to `/document` and `/style` comments on pull requests by running `roxygen2` / `styler` for you. |
+
+All four use the official [`r-lib/actions`](https://github.com/r-lib/actions)
+v2 building blocks, which means dependency installation and caching are
+handled by `r-lib/actions/setup-r-dependencies@v2`.
+
+To install or refresh the default workflows in a package, run:
+
+```{r}
+# from the package root
+kwb.pkgbuild::use_ghactions()
+```
+
+# 2 Optional: Claude Code workflows
+
+If you want [Claude Code](https://docs.claude.com/en/docs/claude-code/) to
+review your pull requests and answer `@claude` mentions in issues / PR
+comments, set `claude = TRUE` when bootstrapping a new package:
+
+```{r}
+kwb.pkgbuild::use_pkg(
+ author = author,
+ pkg = description,
+ version = "0.0.0.9000",
+ stage = "experimental",
+ claude = TRUE
+)
+```
+
+Or add the workflows to an existing package after the fact:
+
+```{r}
+kwb.pkgbuild::use_ghactions_claude()
+```
+
+This installs two additional workflow files:
+
+| File | Trigger |
+|:---------------------------|:------------------------------------------------------------------------------------------------------------|
+| `claude.yaml` | `issue_comment`, `pull_request_review_comment`, `pull_request_review`, `issues` — reacts to `@claude` mentions. |
+| `claude-code-review.yaml` | `pull_request` (`opened`, `synchronize`) — automatic PR review. |
+
+## 2.1 Required repository secret
+
+Both workflows authenticate via a GitHub Actions secret named
+`CLAUDE_CODE_OAUTH_TOKEN`. To create it:
+
+1. Open the repository on GitHub and go to
+ **Settings → Secrets and variables → Actions → New repository secret**.
+2. Set **Name** to `CLAUDE_CODE_OAUTH_TOKEN` and paste your Claude Code OAuth
+ token as **Value**.
+
+Without this secret the Claude jobs will fail at the
+`anthropics/claude-code-action@v1` step.
+
+## 2.2 What Claude does
+
+`claude.yaml` runs whenever someone mentions `@claude` in an issue body /
+title, an issue comment, a PR review or a PR review comment. Claude then
+opens a session with read access to issues / pull requests, plans, and
+posts a reply.
+
+`claude-code-review.yaml` runs on every newly opened or updated pull
+request. It reviews the diff with focus on:
+
+- code quality and R package best practices,
+- potential bugs or logic issues,
+- test coverage,
+- `roxygen2` documentation completeness,
+- consistency with the existing codebase.
+
+If your repository contains a `CLAUDE.md` file, Claude will use it as
+project-specific guidance.
+
+# 3 Updating workflows in existing packages
+
+The workflows in `inst/templates/ci_github-actions/` are the source of truth
+for KWB-R packages. When upstream actions are updated (e.g. a new version of
+`r-lib/actions`) we bump the templates here in `kwb.pkgbuild` and re-run
+`kwb.pkgbuild::use_ghactions()` in each package to refresh the local
+workflows.
+
+To check whether a package is using an outdated version, simply diff its
+`.github/workflows/` against the templates in the latest installed
+`kwb.pkgbuild`:
+
+```{r}
+template_dir <- system.file(
+ "templates/ci_github-actions",
+ package = "kwb.pkgbuild"
+)
+
+# from the package root
+list.files(".github/workflows", full.names = TRUE)
+list.files(template_dir, full.names = TRUE)
+```
+
+# 4 Troubleshooting
+
+- **The pkgdown workflow doesn't deploy.** Make sure the `gh-pages` branch
+ exists and that **Settings → Pages → Source** points to it. The first
+ time a package is set up, run `kwb.pkgbuild::use_autopkgdown()` to create
+ the orphan branch.
+
+- **`R CMD check` fails on `oldrel-1`.** Either pin a `Depends: R (>= ...)`
+ in `DESCRIPTION` to the lowest R version you actually want to support, or
+ remove `oldrel-1` from the matrix in `R-CMD-check.yaml`.
+
+- **Claude jobs are skipped.** The `if:` clause requires `@claude` to appear
+ in the comment / review / issue body. The Claude review workflow only
+ runs on `pull_request`, not on `issue_comment` events.
+
+- **Codecov upload fails on forks.** Configure the `CODECOV_TOKEN`
+ repository secret. The workflow has `fail_ci_if_error` set conditionally
+ so PRs from forks won't break the build.
diff --git a/vignettes/tutorial.Rmd b/vignettes/tutorial.Rmd
index 02bddeb..6fcf321 100644
--- a/vignettes/tutorial.Rmd
+++ b/vignettes/tutorial.Rmd
@@ -36,11 +36,11 @@ building and testing of the package.
# 1 Install required R packages
-Before you can use the package kwb.pkgdown you need to
+Before you can use the package `kwb.pkgbuild` you need to
-* install packages that kwb.pkgdown relies on from the
-[Comprehensive R Archive Network (CRAN)](https://cloud.r-project.org),
-* install kwb.pkddown from [GitHub](https://github.com).
+* install the packages that `kwb.pkgbuild` relies on from the
+ [Comprehensive R Archive Network (CRAN)](https://cloud.r-project.org),
+* install `kwb.pkgbuild` from [GitHub](https://github.com).
Install required packages that are not yet available in your local R user
library from CRAN:
@@ -59,7 +59,6 @@ packages <- setdiff(required, installed)
# Install the packages from CRAN
for (package in packages) {
-
install.packages(package, repos = "https://cloud.r-project.org")
}
```
@@ -192,10 +191,10 @@ The package description needs three entries
- **name**: name of the package
- **title**: title of your R package (which is automatically converted to title
-case with the function `tools::toTitleCase()`)
+ case with the function `tools::toTitleCase()`)
-- **desc:** package description. Should be at least one sentence long and
-needs to end with a period!
+- **desc:** package description. Should be at least one sentence long and needs
+ to end with a period!
```{r}
description <- list(
@@ -205,50 +204,73 @@ description <- list(
)
```
-## 2.4 Create R package structure in KWB-R style
+## 2.4 Create R package structure in KWB-R style
-Running the following code not only creates an R package structure but also adds
-some KWB-R specfic styling, e.g.:
+Running the following code not only creates an R package structure but also
+adds some KWB-R specific styling, e.g.:
-- Adding configution files for:
-
- + Continous integration on windows (https://appveyor.com) and linux
- (https://travis-ci.org/KWB-R)
-
- + Code coverage in R package using the servive [codecov.io](codecov.io)
-
- + Backup of Github repositories on our mirrored KWB-R group on
- [Gitlab](https://gitlab.com/KWB-R)
+- Configuration files for:
+
+ + Continuous integration via
+ [GitHub Actions](https://github.com/features/actions): the workflows
+ `R-CMD-check`, `pkgdown`, `pr-commands` and `test-coverage` are written
+ to `.github/workflows/` (see also the GitHub Actions vignette
+ `vignette("github-actions", package = "kwb.pkgbuild")`).
+
+ + Code coverage via [codecov.io](https://codecov.io)
+
+ + Backup of GitHub repositories on our mirrored KWB-R group on
+ [GitLab](https://gitlab.com/KWB-R)
- Indicates the current lifecycle of the R package according to
-https://www.tidyverse.org/lifecycle/
+ https://www.tidyverse.org/lifecycle/
- Uses by default the permissive
-[](https://opensource.org/licenses/MIT)
-for all public R packages currently hosted on Github (see:
-http://kwb-r.github.io/status/) and lists KWB as copyright holder (see e.g.
-[here](https://kwb-r.github.io/kwb.pkgbuild/authors.html))
+ [](https://opensource.org/licenses/MIT)
+ for all public R packages currently hosted on GitHub (see:
+ https://kwb-r.github.io/status/) and lists KWB as copyright holder (see e.g.
+ [here](https://kwb-r.github.io/kwb.pkgbuild/authors.html))
-- Creates `README` files (`README.Rmd` and `README.md`) for the above mentioned
-topics and
+- Creates `README.md` and `index.md` files for the above mentioned topics, and
-- Prepares a KWB-R flavored documentation website template named
-`_packagedown.yml` needed by http://pkgdown.r-lib.org/
+- Prepares a KWB-R flavoured documentation website template named
+ `_pkgdown.yml` (Bootstrap 5, KWB authors block) needed by
+ https://pkgdown.r-lib.org/
-Running the following R function will create the R package with the `version` =
-`0.0.0.9000` and development stage `experimental` (defined [here](https://www.tidyverse.org/lifecycle/#experimental)).
+Running the following R function will create the R package with `version =
+"0.0.0.9000"` and development stage `experimental` (defined
+[here](https://www.tidyverse.org/lifecycle/#experimental)).
```{r eval = FALSE}
setwd(pkg_dir)
kwb.pkgbuild::use_pkg(
- author,
- description,
- version = "0.0.0.9000",
+ author,
+ description,
+ version = "0.0.0.9000",
stage = "experimental"
)
```
+If you also want the [Claude Code](https://docs.claude.com/en/docs/claude-code/)
+GitHub Actions workflows (for `@claude` mentions in issues / PR review
+comments and automatic PR review on `opened` / `synchronize`), set
+`claude = TRUE`:
+
+```{r eval = FALSE}
+kwb.pkgbuild::use_pkg(
+ author,
+ description,
+ version = "0.0.0.9000",
+ stage = "experimental",
+ claude = TRUE
+)
+```
+
+The two extra workflows expect a `CLAUDE_CODE_OAUTH_TOKEN` repository secret
+to be configured in GitHub. You can also add the Claude workflows to an
+existing package later on with `kwb.pkgbuild::use_ghactions_claude()`.
+
## 2.5 Add your R functions
Add your R functions in the folder `R`/. By using `usethis::use_r` with the
@@ -301,7 +323,7 @@ possible problems (e.g. wrong documentation, missing package dependencies).
In case of missing package dependencies as shown below these should be added to
the [DESCRIPTION](http://r-pkgs.had.co.nz/description.html) file.
-```{r eval = FALSE}
+```
Namespace dependencies not required: 'fs' 'httr' 'stringr' 'usethis' 'yaml'
See section 'The DESCRIPTION file' in the 'Writing R Extensions'
manual.
@@ -318,7 +340,7 @@ Namespace dependencies not required: 'fs' 'httr' 'stringr' 'usethis' 'yaml'
This can be done using the function `usethis::use_package()` as shown below:
-```{r eval = FALSE}
+```
pkg_dependencies <- c('fs', 'httr', 'stringr', 'usethis', 'yaml')
sapply(pkg_dependencies, usethis::use_package)
@@ -338,7 +360,7 @@ sapply(pkg_dependencies, usethis::use_package)
Subsequently you should re-click on the `Check` button again and it should
finish without errors.
-```{r eval = FALSE}
+```
R CMD check results
0 errors | 0 warning | 0 note
@@ -351,7 +373,7 @@ Now you are ready for building your R package by clicking on the `Install and
Restart` button. A successful installation should finish with `Done` as shown
below:
-```{r eval = FALSE}
+```
** building package indices
** installing vignettes
** testing if installed package can be loaded
@@ -385,29 +407,28 @@ knitr::include_graphics("images/package_documentation.jpg")
## 5.2 Automatically
-In case you have already a Github repo defined for your R package you can
-also automate the process of updating the `pkgdown::build_site()` by with the
-wrapper function `kwb.pkgbuild::use_autopkgdown()`, which:
-
-- creates a new branch "gh-pages" where the documentation site is deployed
+If you already have a GitHub repository for your R package you can let the
+`pkgdown` workflow build and deploy the documentation site for you on every
+push. `kwb.pkgbuild::use_pkg()` already installs the workflow
+`.github/workflows/pkgdown.yaml`; the only one-off step that is left to do
+is creating the `gh-pages` branch and setting it as the GitHub Pages source.
-- sets "docs" folder to ".gitignore" (as these files are now build on Travis)
+The wrapper function `kwb.pkgbuild::use_autopkgdown()` does exactly that:
-- prepares Github Actions by:
+- adds the `docs/` folder to `.gitignore` (since the site is built on
+ GitHub Actions and pushed to the `gh-pages` branch),
-
- + creating ".github/workflows/" with `kwb.pkgbuild::use_ghactions()`
-
- + creating an empty "gh-pages" branch with
- `kwb.pkgbuild::create_empty_branch_ghpages()`
+- creates an empty `gh-pages` branch via
+ `kwb.pkgbuild::create_empty_branch_ghpages()`.
```{r eval = FALSE}
kwb.pkgbuild::use_autopkgdown()
```
-Finally to need to go to:
+Finally, go to
-https://github.com/KWB-R/ `kwb.mycoolrpackage` /settings
+`https://github.com/KWB-R//settings/pages`
-and set the "source" for Github Pages to the branch "gh-pages". After each
-successful Travis build the documentation website is now also updated!
+and set the GitHub Pages **Source** to the branch `gh-pages`. After every
+successful run of the `pkgdown` workflow the documentation website is now
+updated automatically.