diff --git a/.github/workflows/bump-dev-version.yml b/.github/workflows/bump-dev-version.yml new file mode 100644 index 00000000..1afe3717 --- /dev/null +++ b/.github/workflows/bump-dev-version.yml @@ -0,0 +1,24 @@ +# Calls Morrison-Lab/gha's bump-dev-version workflow: bumps DESCRIPTION's +# dev-version counter after every merge to main and auto-merges the one-line +# PR that carries it. Pairs with version-check.yml, which fails a PR that +# touches Version: itself. +# +# The repo already has both settings this needs: Settings -> Actions -> +# General -> "Allow GitHub Actions to create and approve pull requests", and +# Settings -> General -> "Allow auto-merge". No WORKFLOW_TOKEN is needed +# because main has no required status checks -- add one if that changes. +name: Bump dev version + +on: + push: + branches: [main] + +jobs: + bump: + permissions: + contents: write + pull-requests: write + uses: Morrison-Lab/gha/.github/workflows/bump-dev-version.yml@v2 + with: + # Keeps news.yaml from demanding a NEWS.md entry on the automation PR. + pr-labels: 'no changelog' diff --git a/.github/workflows/check-junk-files.yml b/.github/workflows/check-junk-files.yml new file mode 100644 index 00000000..1f902e33 --- /dev/null +++ b/.github/workflows/check-junk-files.yml @@ -0,0 +1,14 @@ +# Fails when the repository tracks OS or editor detritus (.DS_Store, +# AppleDouble ._*, .Rhistory, .RData, Thumbs.db). The tree is clean of these +# today; this keeps it that way. +name: Check Junk Files + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + check: + uses: Morrison-Lab/gha/.github/workflows/check-junk-files.yml@v2 diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml new file mode 100644 index 00000000..116b4c25 --- /dev/null +++ b/.github/workflows/check-links.yml @@ -0,0 +1,21 @@ +# lychee link check, with a weekly cron to catch link rot and an auto-filed +# issue when links break on main. +name: Check Links + +on: + push: + branches: [main] + pull_request: + types: [opened, synchronize, reopened, labeled, unlabeled] + schedule: + # Weekly, Mondays at 9:00 UTC. + - cron: '0 9 * * 1' + workflow_dispatch: + +jobs: + check: + permissions: + contents: read + issues: write + pull-requests: read + uses: Morrison-Lab/gha/.github/workflows/check-links.yml@v2 diff --git a/.github/workflows/check-new-line-breaks.yml b/.github/workflows/check-new-line-breaks.yml new file mode 100644 index 00000000..6b5bd159 --- /dev/null +++ b/.github/workflows/check-new-line-breaks.yml @@ -0,0 +1,16 @@ +# Diff-scoped check: flags newly-added Markdown lines packing more than one +# sentence or clause onto a single source line, so new prose lands with +# semantic line breaks. +# +# pull_request only, deliberately, for the same reason as check-typos.yml: +# gha derives the base from the pull_request event and skips (reporting +# success) when there is none, so a push trigger would add a green check on +# main that examined nothing. +name: Check new markdown lines for missing semantic breaks + +on: + pull_request: + +jobs: + check: + uses: Morrison-Lab/gha/.github/workflows/check-new-line-breaks.yml@v2 diff --git a/.github/workflows/check-phi.yml b/.github/workflows/check-phi.yml new file mode 100644 index 00000000..ceb5808d --- /dev/null +++ b/.github/workflows/check-phi.yml @@ -0,0 +1,21 @@ +# Scans for content that looks like Protected Health Information -- SSNs, +# medical record numbers, dates of birth, study/participant identifier +# literals, PHI column headers in data files. On PRs only the added lines are +# scanned; on push the whole tree is. +# +# Worth having here specifically: this repo carries Shigella serology data and +# grows chapter-level analysis code on long-lived branches. +# +# Suppress a synthetic-data false positive with a `phi-allow` comment on the +# line, or a regex in .github/phi-allowlist.txt. +name: Check for PHI + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + check: + uses: Morrison-Lab/gha/.github/workflows/check-phi.yml@v2 diff --git a/.github/workflows/check-secrets.yml b/.github/workflows/check-secrets.yml new file mode 100644 index 00000000..3afe6f14 --- /dev/null +++ b/.github/workflows/check-secrets.yml @@ -0,0 +1,17 @@ +# Scans the repository's git HISTORY for committed credentials with gitleaks. +# History rather than the diff: a secret committed and later removed is still +# exposed, because the orphaned commit stays fetchable until GC. +# +# Complements GitHub's own secret scanning rather than replacing it, and +# neither substitutes for ROTATING an exposed credential. +name: Check for secrets + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + check: + uses: Morrison-Lab/gha/.github/workflows/check-secrets.yml@v2 diff --git a/.github/workflows/check-spelling.yaml b/.github/workflows/check-spelling.yaml deleted file mode 100644 index 6ae8dfa4..00000000 --- a/.github/workflows/check-spelling.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -name: Spellcheck - -on: - push: - branches: - - main - pull_request: - branches: - - main - -jobs: - check: - runs-on: ubuntu-latest - name: Spellcheck - container: - image: rocker/tidyverse:latest - steps: - - name: Checkout repo - uses: actions/checkout@v3 - - - name: Run Spelling Check test - uses: insightsengineering/r-spellcheck-action@v3.0.2 diff --git a/.github/workflows/check-typos.yml b/.github/workflows/check-typos.yml new file mode 100644 index 00000000..f2f88ccf --- /dev/null +++ b/.github/workflows/check-typos.yml @@ -0,0 +1,16 @@ +# Diff-scoped spellcheck of the files spellcheck.yml cannot see: Quarto pages, +# CONTRIBUTING.md-class Markdown, YAML, and code comments. Uses crate-ci/typos, +# a corrections-list checker, so it needs no curated wordlist. +# +# pull_request only, deliberately. The workflow diffs against the PR base, and +# a push run has no base to diff against -- gha skips it and reports success, +# which would put a green check on main that examined nothing. Pass +# `base-ref: all` and re-add a push trigger once the existing tree is clean. +name: Check typos + +on: + pull_request: + +jobs: + check: + uses: Morrison-Lab/gha/.github/workflows/check-typos.yml@v2 diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index d13f913d..e4501db5 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -28,7 +28,7 @@ jobs: issues: write id-token: write actions: read # lets the reviewer read CI status (github_ci MCP server) - uses: Morrison-Lab/gha/.github/workflows/claude-code-review.yml@v1 + uses: Morrison-Lab/gha/.github/workflows/claude-code-review.yml@v2 secrets: CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} # Max-plan OAuth; empty when using API key ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} # direct API key; empty when using OAuth diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index fe2f6f99..72cad8a1 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -38,7 +38,7 @@ jobs: issues: write id-token: write actions: write # dispatch the review workflow via `gh workflow run` - uses: Morrison-Lab/gha/.github/workflows/claude.yml@v1 + uses: Morrison-Lab/gha/.github/workflows/claude.yml@v2 secrets: CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} # Max-plan OAuth; empty when using API key ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} # direct API key; empty when using OAuth diff --git a/.github/workflows/lint-changed-files.yaml b/.github/workflows/lint-changed-files.yaml deleted file mode 100644 index d194ede6..00000000 --- a/.github/workflows/lint-changed-files.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples -# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help -on: - pull_request: - -name: lint-changed-files.yaml - -permissions: read-all - -jobs: - lint-changed-files: - runs-on: ubuntu-latest - - - steps: - - uses: actions/checkout@v4 - - - uses: r-lib/actions/setup-r@v2 - - - uses: r-lib/actions/setup-r-dependencies@v2 - with: - extra-packages: | - any::gh - any::lintr - any::purrr - needs: check - - - name: Add lintr options - run: | - cat('\noptions(lintr.linter_file = ".lintr")\n', file = "~/.Rprofile", append = TRUE) - shell: Rscript {0} - - - name: Install package - run: R CMD INSTALL . - - - name: Extract and lint files changed by this PR - run: | - Sys.unsetenv("GITHUB_PAT") - - files <- gh::gh( - "GET https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files", - .token = Sys.getenv("GITHUB_TOKEN") - ) - - changed_files <- purrr::map_chr(files, "filename") - all_files <- list.files(recursive = TRUE) - exclusions_list <- as.list(setdiff(all_files, changed_files)) - lintr::lint_package(exclusions = exclusions_list) - shell: Rscript {0} - env: - GITHUB_TOKEN: ${{ github.token }} - LINTR_ERROR_ON_LINT: true diff --git a/.github/workflows/lint-changed-lines.yml b/.github/workflows/lint-changed-lines.yml new file mode 100644 index 00000000..994aa667 --- /dev/null +++ b/.github/workflows/lint-changed-lines.yml @@ -0,0 +1,17 @@ +# Calls Morrison-Lab/gha's lint-changed-lines workflow. Replaces the +# hand-maintained lint-changed-files.yaml, which linted whole changed files; +# this lints only the lines a PR adds or modifies, so lint rules can be +# tightened incrementally without a whole-repo cleanup first. +# +# The old workflow's `R CMD INSTALL .` step is the workflow's own +# `install-package` default, so no inputs are needed here. +# +# Must be triggered by pull_request -- the changed-line set comes from the PR. +name: lint-changed-lines + +on: + pull_request: + +jobs: + lint: + uses: Morrison-Lab/gha/.github/workflows/lint-changed-lines.yml@v2 diff --git a/.github/workflows/lint-markdown.yml b/.github/workflows/lint-markdown.yml new file mode 100644 index 00000000..85f94027 --- /dev/null +++ b/.github/workflows/lint-markdown.yml @@ -0,0 +1,21 @@ +# Lints tracked Markdown with markdownlint-cli2, plus companion checks for +# long fenced code blocks, list-item merge splices, and blank lines that split +# a table. +# +# Warn-only for now, for the same pre-existing-backlog reason as +# lint-workflows.yml (tracked in #32). +name: Lint Markdown + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + lint: + uses: Morrison-Lab/gha/.github/workflows/lint-markdown.yml@v2 + with: + fail: false + # Diff-scopes the list-item splice check to what a PR actually adds. + base-ref: ${{ github.event.pull_request.base.sha }} diff --git a/.github/workflows/lint-workflows.yml b/.github/workflows/lint-workflows.yml new file mode 100644 index 00000000..14152bd5 --- /dev/null +++ b/.github/workflows/lint-workflows.yml @@ -0,0 +1,19 @@ +# Audits GitHub Actions workflows and composite actions with actionlint +# (syntax/semantics) and zizmor (security). +# +# Warn-only for now: this repo carries a pre-existing backlog of workflow +# findings, and a blocking check would go red on unrelated PRs. Flip +# `fail: true` once that backlog is cleared (tracked in #32). +name: Lint Workflows + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + lint: + uses: Morrison-Lab/gha/.github/workflows/lint-workflows.yml@v2 + with: + fail: false diff --git a/.github/workflows/lint-yaml.yml b/.github/workflows/lint-yaml.yml new file mode 100644 index 00000000..308d4fe2 --- /dev/null +++ b/.github/workflows/lint-yaml.yml @@ -0,0 +1,18 @@ +# Lints tracked YAML with yamllint, plus a companion check that flags long +# `run:` script blocks as decomposition candidates. +# +# Warn-only for now, for the same pre-existing-backlog reason as +# lint-workflows.yml (tracked in #32). +name: Lint YAML + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + lint: + uses: Morrison-Lab/gha/.github/workflows/lint-yaml.yml@v2 + with: + fail: false diff --git a/.github/workflows/news.yaml b/.github/workflows/news.yaml index d3ca11fd..c83b49aa 100644 --- a/.github/workflows/news.yaml +++ b/.github/workflows/news.yaml @@ -9,6 +9,6 @@ on: jobs: check: - uses: Morrison-Lab/gha/.github/workflows/check-news.yml@v1 + uses: Morrison-Lab/gha/.github/workflows/check-news.yml@v2 # with: # changelog: NEWS.md diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml new file mode 100644 index 00000000..0aa2ae78 --- /dev/null +++ b/.github/workflows/spellcheck.yml @@ -0,0 +1,21 @@ +# Calls Morrison-Lab/gha's spellcheck workflow. Replaces the hand-maintained +# check-spelling.yaml, which ran insightsengineering/r-spellcheck-action in a +# rocker/tidyverse container. +# +# Reference: +# https://morrison-lab.github.io/gha/reference/spellcheck.html +name: Spellcheck + +on: + push: + branches: [main] + pull_request: + +concurrency: + group: spellcheck-${{ github.ref }} + cancel-in-progress: true + +jobs: + spellcheck: + uses: Morrison-Lab/gha/.github/workflows/spellcheck.yml@v2 + # Accepts this package's own inst/WORDLIST. diff --git a/.github/workflows/version-check.yaml b/.github/workflows/version-check.yaml deleted file mode 100644 index 28ae8726..00000000 --- a/.github/workflows/version-check.yaml +++ /dev/null @@ -1,58 +0,0 @@ -# adapted from https://github.com/RMI-PACTA/actions/blob/main/.github/workflows/R-semver-check.yml - -on: - pull_request: - branches: - - main - -name: Version increment check - -jobs: - version-check: - if: ${{ github.event_name == 'pull_request' }} - runs-on: ubuntu-latest - - steps: - - - name: checkout working HEAD - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.ref }} - sparse-checkout: | - DESCRIPTION - path: working - - - name: checkout base HEAD - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.base.ref }} - sparse-checkout: | - DESCRIPTION - path: compare - - - name: show files - run: | - ls -lR working compare - echo "\nWORKING:\n" - cat working/DESCRIPTION - echo "\nCOMPARE:\n" - cat compare/DESCRIPTION - - - name: Setup R - uses: r-lib/actions/setup-r@v2 - with: - use-public-rspm: true - - - name: compare versions - run: | - Rscript -e " \ - install.packages('desc'); \ - working_version <- desc::desc_get_version('working/DESCRIPTION'); \ - message('PR branch version: ', working_version); \ - compare_version <- desc::desc_get_version('compare/DESCRIPTION'); \ - message('main branch version: ', compare_version); \ - if (working_version <= compare_version) { \ - message('Call usethis::use_version() in the R Console to increment the "dev" version number.'); \ - stopifnot(working_version > compare_version); \ - } else message('All set!'); \ - " diff --git a/.github/workflows/version-check.yml b/.github/workflows/version-check.yml new file mode 100644 index 00000000..7ae2553d --- /dev/null +++ b/.github/workflows/version-check.yml @@ -0,0 +1,20 @@ +# Calls Morrison-Lab/gha's version-check workflow. Replaces the +# hand-maintained version-check.yaml, and INVERTS its convention: a PR must +# now leave DESCRIPTION's Version: alone, rather than increment it. The bump +# moves to bump-dev-version.yml, which runs after each merge to main -- two +# PRs both required to bump the same line are guaranteed to collide. +# +# Bypass on a PR that genuinely must set a version (a release) with the +# 'no version increment' label. +name: Version check + +on: + pull_request: + branches: [main] + +jobs: + version-check: + permissions: + pull-requests: read + contents: read + uses: Morrison-Lab/gha/.github/workflows/version-check.yml@v2 diff --git a/.gitignore b/.gitignore index daf8d693..869d1c18 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ README_files shigella.Rcheck/ shigella*.tar.gz shigella*.tgz +.DS_Store diff --git a/DESCRIPTION b/DESCRIPTION index 55311d20..05bf1b57 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -21,7 +21,7 @@ Suggests: VignetteBuilder: knitr Depends: R (>= 3.5) +Config/roxygen2/version: 8.1.0 Config/testthat/edition: 3 Config/Needs/website: quarto Language: en-US -RoxygenNote: 8.0.0 diff --git a/NEWS.md b/NEWS.md index 46c946bc..dd2f7c17 100644 --- a/NEWS.md +++ b/NEWS.md @@ -11,6 +11,18 @@ * Moved helper functions into `R/` subdirectory (#1) * simplified spell-check GitHub Action (#3) * Migrated the Claude Code and NEWS-changelog workflows to `d-morrison/gha` reusable workflows, and removed the obsolete upstream-fix watcher (#29) +* Finished the `Morrison-Lab/gha` migration: replaced the hand-maintained + spellcheck, changed-file lint, and version-check workflows with their gha + counterparts, added the `bump-dev-version` companion, and added checks for + workflow, YAML, and Markdown lint, junk files, typos, committed secrets, + PHI, broken links, and semantic line breaks (#32) + +* Moved the Claude, Claude-review, and NEWS callers from `@v1` to `@v2`, + fixing the startup failure every Claude Code run hit because `@v1` does + not declare the `ANTHROPIC_API_KEY` secret the callers pass (#32) + +* Recorded the roxygen2 version in `Config/roxygen2/version`, which roxygen2 + 8.1.0 uses in place of `RoxygenNote` (#32) # shigella 0.0.0 diff --git a/inst/WORDLIST b/inst/WORDLIST index da167ea1..a6e525a0 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -7,18 +7,21 @@ Iso Isotype MFI ORCID +PHI Postprocess SOSAR Seroresponse changelog df ggplot +gha ipab isotype isotypes newperson pre repo +roxygen serodynamics serotype tibble