Skip to content

workflows/lint-changed-files: bypass gh PAT validation for ghs_ token format#865

Open
d-morrison wants to merge 6 commits into
mainfrom
claude/fix-lint-gh-pat
Open

workflows/lint-changed-files: bypass gh PAT validation for ghs_ token format#865
d-morrison wants to merge 6 commits into
mainfrom
claude/fix-lint-gh-pat

Conversation

@d-morrison

Copy link
Copy Markdown
Owner

Summary

The lint-changed-files job has been failing on every recent PR (observed across three consecutive runs on #706) with:

Error in `validate_gh_pat()`:
! Invalid GitHub PAT format
ℹ A GitHub PAT must have one of three forms:
• 40 hexadecimal digits (older PATs)
• A 'ghp_' prefix followed by 36 to 251 more characters (newer PATs)
• A 'github_pat_' prefix followed by 36 to 244 more characters (fine-grained PATs)

GitHub Actions now hands secrets.GITHUB_TOKEN as a ghs_* server-to-server token, which gh 1.5.0's validate_gh_pat() doesn't recognize. The validator aborts before any lint can run — LINTR_ERROR_ON_LINT: true then halts the script and the job exits 1. No lint findings ever existed; CI just couldn't reach the lint step.

Fix

Pass .token = Sys.getenv("GITHUB_PAT") explicitly to gh::gh(). When .token= is supplied, gh uses it directly via the Authorization header and skips validate_gh_pat() entirely. The token authenticates fine against the API — the only issue was gh's own format check.

Why not bump the gh pin

The proper fix is r-lib/gh#233, merged into gh main on 2026-05-28. But the latest CRAN/tagged release is still v1.5.0 (May 2025) — the fix has not yet shipped in a CRAN release, so bumping the renv pin isn't an option yet. Once a CRAN release containing #233 lands, swap this workaround for a clean renv::install("gh"); renv::snapshot().

Test plan

  • lint-changed-files job goes green on this PR (and on every other open PR after merge).
  • No behavioral change to lintr itself — same files linted, same config.

https://claude.ai/code/session_01PtDgktdMme5SZtze1EGx9U


Generated by Claude Code

GitHub now hands secrets.GITHUB_TOKEN as a `ghs_*` server-to-server
token. gh 1.5.0's `validate_gh_pat()` only accepts 40-hex / `ghp_*` /
`github_pat_*` formats, so the `gh::gh()` call that fetches the PR's
changed-files list aborts before lintr ever runs and the job fails with
"Invalid GitHub PAT format". This affects every PR (recently seen on
#706 across multiple consecutive runs).

Pass `.token = Sys.getenv("GITHUB_PAT")` explicitly so gh uses the token
directly via the Authorization header and skips the validator. The
proper fix (r-lib/gh PR #233) is merged into gh main but not in any
CRAN release yet, so bumping the renv pin is not yet an option.

https://claude.ai/code/session_01PtDgktdMme5SZtze1EGx9U
@claude

claude Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Claude finished @d-morrison's task in 56s —— View job


Code Review: workflows/lint-changed-files: bypass gh PAT validation for ghs_ token format

Tasks:

  • Gather context from PR description
  • Read changed file(s)
  • Review the diff
  • Post review findings

Summary

The fix is correct and well-reasoned. The root cause is accurately diagnosed, and the workaround is the right minimal approach given that r-lib/gh PR #233 hasn't shipped in a CRAN release yet.


Review Findings

Fix correctness — ✅ Looks good

Passing .token = Sys.getenv("GITHUB_PAT") works because gh::gh() only runs validate_gh_pat() on tokens it retrieves automatically from the environment (via gitcreds/gh's own credential lookup). When a token is provided explicitly via .token, the validation is bypassed and the raw value is used directly in the Authorization header. Since GitHub's ghs_* tokens are valid bearer tokens for the REST API, the API call succeeds fine.

The GITHUB_PAT env var is correctly populated at the job level (line 14: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}), so Sys.getenv("GITHUB_PAT") will return the ghs_* token as expected.

Comment verbosity — minor nit

The in-code comment is quite long for an R snippet inside a YAML workflow. The project's CLAUDE.md policy is "only add a comment when the WHY is non-obvious" — this qualifies because the version-mismatch context would be genuinely baffling without it. That said, the comment could be condensed without losing meaning:

# Bypass gh's validate_gh_pat(): gh 1.5.0 rejects the `ghs_*` server-to-server
# token that Actions now issues. Passing `.token` explicitly skips validation.
# Remove once r-lib/gh#233 lands on CRAN.

Not blocking, just a readability suggestion.

Pre-existing: no pagination on the files API call — not blocking

.github/workflows/lint-changed-files.yaml:46-49gh::gh() fetches a single page (max 30 items by default). PRs with more than 30 changed files will silently lint only a subset. This predates this PR and is out of scope for this fix, but worth a follow-up issue.

No security concerns

The ghs_* token was already present in the GITHUB_PAT environment variable — passing it explicitly as .token doesn't increase its exposure.


Verdict

Approve. The fix is minimal, correct, and includes a clear upgrade path (swap for a renv pin bump once r-lib/gh > 1.5.0 ships on CRAN). The comment verbosity is a nit, not a blocker.

@d-morrison d-morrison marked this pull request as ready for review June 2, 2026 08:35
@claude

claude Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Claude finished @d-morrison's task in 53s —— View job


Claude Code Review — PR #865


Tasks

  • Gather context from PR description
  • Read changed file
  • Review the diff
  • Post review findings

Code Review: workflows/lint-changed-files: bypass gh PAT validation for ghs_ token format

Summary

The fix is correct, minimal, and well-motivated. Root cause is accurately diagnosed; the workaround is the right call given r-lib/gh PR #233 hasn't shipped on CRAN yet.


Fix correctness — ✅

Passing .token = Sys.getenv("GITHUB_PAT") (line 48) works because gh::gh() only invokes validate_gh_pat() on tokens it resolves through its own credential-lookup chain (gitcreds / keyring). When .token is supplied explicitly, the value goes straight into the Authorization header without any format checking. GitHub's ghs_* installation tokens are valid bearer tokens for the REST API, so authentication succeeds as expected.

The GITHUB_PAT env var is set at job scope (line 14: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}), so Sys.getenv("GITHUB_PAT") reliably returns the ghs_* value. This is already the existing pattern used for r-lib/actions/setup-renv@v2 (line 30), so the approach is internally consistent.

Comment verbosity — minor nit

The 6-line comment (lines 39–45) is the right call: this is exactly the "hidden constraint / workaround for a specific bug" category that CLAUDE.md says warrants a comment. The upgrade path (r-lib/gh#233) is especially valuable so future maintainers know when to remove the workaround.

If you want to tighten it slightly:

# Explicit `.token` bypasses gh 1.5.0's validate_gh_pat(), which rejects the
# `ghs_*` server-to-server token that Actions now issues. Remove once
# r-lib/gh#233 lands on CRAN (merged main 2026-05-28, not yet released).

Not a blocker — the current comment is fine.

Pre-existing: no pagination — out of scope

Lines 46–49: gh::gh() returns at most 30 items per page by default. PRs touching >30 files will silently lint only the first page. This predates this PR and is out of scope here, but worth a follow-up.

No security concerns

GITHUB_PAT was already in scope as an env var; passing it as .token introduces no new exposure.


Verdict

Approve. The fix is correct and the upgrade path is clearly documented. Nothing blocking.


@claude

claude Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Claude finished @d-morrison's task in 52s —— View job


Code Review — PR #865

Tasks:

  • Gather context from PR description
  • Read changed file
  • Review the diff
  • Post review findings

Summary

The fix is correct, minimal, and well-motivated. Root cause is accurately diagnosed; the workaround is the right call given that r-lib/gh PR #233 hasn't shipped on CRAN yet.


Fix correctness — ✅

Passing .token = Sys.getenv("GITHUB_PAT") (line 48) correctly bypasses validate_gh_pat() in gh 1.5.0. When .token is supplied explicitly, gh::gh() uses the value directly in the Authorization header without any format checks. GitHub's ghs_* installation tokens are valid bearer tokens for the REST API, so the API call authenticates successfully.

The GITHUB_PAT env var is populated at job scope (line 14: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}), so Sys.getenv("GITHUB_PAT") reliably returns the ghs_* token. This matches the existing pattern used for r-lib/actions/setup-renv@v2 at line 30, keeping the approach internally consistent.

Comment verbosity — minor nit

The 6-line comment (lines 39–45) is warranted — this is exactly the "workaround for a specific bug" category that CLAUDE.md says merits a comment, and the upgrade path (r-lib/gh#233, merged 2026-05-28) is valuable for future maintainers. Could be tightened slightly if desired:

# Explicit `.token` bypasses gh 1.5.0's validate_gh_pat(), which rejects the
# `ghs_*` server-to-server token Actions now issues. Remove once
# r-lib/gh#233 lands on CRAN (merged main 2026-05-28, not yet released).

Not a blocker — the current comment is fine as-is.

Pre-existing: no pagination on files API — out of scope

Lines 46–49: gh::gh() returns at most 30 items by default. PRs touching >30 files will silently lint only the first page. This predates this PR and is out of scope for this fix, but worth a follow-up issue. Fix this →

Security — no concerns

GITHUB_PAT was already in scope as a job-level env var; passing it as .token introduces no new token exposure.


Verdict

Approve. The fix is correct and includes a clear upgrade path. Nothing blocking.


@d-morrison

Copy link
Copy Markdown
Owner Author

@claude review

@claude

claude Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Claude finished @d-morrison's task in 1m 6s —— View job


Code Review — PR #865

Tasks:

  • Gather context from PR description
  • Read changed file
  • Review the diff
  • Post review findings

Summary

The fix is correct, minimal, and well-motivated. The root cause is accurately diagnosed; the workaround is appropriate given that r-lib/gh PR #233 hasn't shipped on CRAN yet. The most recent commits are a merge from main to keep the branch up to date — no substantive logic changed.


Fix correctness — ✅

Passing .token = Sys.getenv("GITHUB_PAT") (line 48) correctly bypasses validate_gh_pat() in gh 1.5.0. When .token is supplied explicitly, gh::gh() uses the value directly in the Authorization header without any format checks. GitHub's ghs_* installation tokens are valid bearer tokens for the REST API, so the API call authenticates successfully.

The GITHUB_PAT env var is set at job scope (line 14: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}), so Sys.getenv("GITHUB_PAT") reliably returns the ghs_* token. This matches the existing pattern used for r-lib/actions/setup-renv@v2 (line 30), keeping the approach internally consistent.

Comment quality — ✅

The 6-line comment (lines 39–45) is warranted — this is exactly the "workaround for a specific bug / hidden constraint" category that CLAUDE.md says merits a comment. The upgrade path (gh PR #233, merged 2026-05-28) is especially valuable so future maintainers know when to remove the workaround. Could be condensed slightly:

# Explicit `.token` bypasses gh 1.5.0's validate_gh_pat(), which rejects the
# `ghs_*` server-to-server token Actions now issues. Remove once
# r-lib/gh#233 lands on CRAN (merged main 2026-05-28, not yet released).

Not a blocker — current form is fine.

Pre-existing: no pagination on files API — out of scope

Lines 46–49: gh::gh() returns at most 30 items per page by default. PRs touching >30 changed files will silently lint only the first page. This predates this PR and is out of scope here, but worth a follow-up. Fix this →

Security — no concerns

GITHUB_PAT was already in scope as a job-level env var; passing it as .token introduces no new token exposure. For fork PRs, secrets.GITHUB_TOKEN is the built-in runner token (always available), so empty-string edge cases don't apply here.


Verdict

Approve. The fix is correct, the comment documents the upgrade path clearly, and the change is exactly as minimal as it should be.


@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

👀 Picked up by workflow run #26916102523. R/Quarto/renv setup runs first (~3-5 min); Claude itself responds after that.

@d-morrison

Copy link
Copy Markdown
Owner Author

Claude Code CLI (local session) is working on this — paws off until I'm done.

Tightens the explanatory comment to the reviewer-suggested form while
keeping the r-lib/gh#233 upgrade pointer. No logic change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@d-morrison

Copy link
Copy Markdown
Owner Author

Addressed the two items from the latest review:

  • Comment quality (condense suggestion): Applied — tightened the PAT-bypass comment to the reviewer-suggested form, keeping the r-lib/gh#233 upgrade pointer. (commit 6c22c9a)
  • No pagination on the /files API (out-of-scope, pre-existing): Deferred to a tracked follow-up — lint-changed-files: paginate the PR /files API call #878. It predates this PR and is unrelated to the ghs_* token bypass, so it was kept out of this PR's scope.

@claude review

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

👀 Picked up by workflow run #26916399055. R/Quarto/renv setup runs first (~3-5 min); Claude itself responds after that.

@claude

claude Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Claude finished @d-morrison's task in 43s —— View job


Code Review — PR #865

Tasks:

  • Gather context from PR description
  • Read changed file and diff against origin/main
  • Review the diff
  • Post review findings

Summary

The two items from the previous review have been addressed. The comment is now condensed to 4 lines and matches the reviewer-suggested form closely; the pagination follow-up is tracked in #878. The underlying fix is unchanged and remains correct.


Fix correctness — ✅

Passing .token = Sys.getenv("GITHUB_PAT") (line 45) correctly bypasses validate_gh_pat() in gh 1.5.0. When .token is supplied explicitly, gh::gh() uses the value directly in the Authorization header without format-checking. GitHub's ghs_* installation tokens are valid bearer tokens for the REST API, so authentication succeeds. GITHUB_PAT is set at job scope via GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} (line 14), so Sys.getenv("GITHUB_PAT") reliably returns the token.

Comment quality — ✅

Lines 39–42 are now 4 lines, down from 6. Content matches the reviewer-suggested form: the validate_gh_pat() bypass reason, the ghs_* token context, and the r-lib/gh#233 upgrade pointer are all present. No issues.

Pre-existing: no pagination — deferred ✅

Tracked in #878 as noted. Out of scope for this PR.


Verdict

Approve. The fix is correct, the comment is appropriately condensed, and the pagination follow-up is tracked. Nothing blocking.

@d-morrison

Copy link
Copy Markdown
Owner Author

@claude now that gh 1.6.0 has landed on CRAN, can we simplify this workflow? also, resolve merge conflicts

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

👀 Picked up by workflow run #26988008542. R/Quarto/renv setup runs first (~3-5 min); Claude itself responds after that.

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

I've confirmed the blocker: the session is checked out on main (not the PR branch claude/fix-lint-gh-pat) because issue_comment events don't auto-check out the PR head, and the workflows write permission isn't in the action token's scope, so I can't update the workflow file via the GitHub API either.

Here's the exact simplified content the PR branch needs, along with the resolution for the merge conflict:


Good news: I can see exactly what the simplified workflow should look like, though I hit a permission wall applying it automatically (the issue_comment-on-PR trigger checks out main rather than the PR branch, and the action token lacks workflows: write).

Here's what to do:

On claude/fix-lint-gh-pat, replace the entire Extract and lint files changed by this PR step (and remove the two-step CLI approach that landed on main) with:

      - name: Extract and lint files changed by this PR
        run: |
          files <- gh::gh(
            "GET https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files",
            .limit = Inf
          )
          changed_files <- files |>
            purrr::keep(~ .$status != "renamed" || .$changes > 0) |>
            purrr::map_chr("filename")
          changed_files <- setdiff(changed_files, "renv/activate.R")
          if (length(changed_files) == 0) {
            message("No changed files to lint.")
          } else {
            all_files <- list.files(recursive = TRUE)
            exclusions_list <- as.list(setdiff(all_files, changed_files))
            lintr::lint_dir(exclusions = exclusions_list)
          }
        shell: Rscript {0}
        env:
          LINTR_ERROR_ON_LINT: true

The full simplified file (drop the 4-line comment, replace .token = Sys.getenv("GITHUB_PAT") with .limit = Inf, add the empty-files guard from main, and undo main's CLI two-step approach back to a single R step):

# 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
    env:
      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/checkout@v5

      - uses: r-lib/actions/setup-r@v2
        with:
          r-version: '4.6.0'
          use-public-rspm: true

      - name: Install system dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y jags libcurl4-openssl-dev libpng-dev libfontconfig1-dev libjpeg-dev libglpk-dev libharfbuzz-dev libfribidi-dev libfreetype6-dev libtiff5-dev libwebp-dev libnode109

      - uses: r-lib/actions/setup-renv@v2
        env:
          GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}

      - name: Add lintr options
        run: |
          cat('\noptions(lintr.linter_file = ".lintr")\n', file = "~/.Rprofile", append = TRUE)
        shell: Rscript {0}

      - name: Extract and lint files changed by this PR
        run: |
          files <- gh::gh(
            "GET https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files",
            .limit = Inf
          )
          changed_files <- files |>
            purrr::keep(~ .$status != "renamed" || .$changes > 0) |>
            purrr::map_chr("filename")
          changed_files <- setdiff(changed_files, "renv/activate.R")
          if (length(changed_files) == 0) {
            message("No changed files to lint.")
          } else {
            all_files <- list.files(recursive = TRUE)
            exclusions_list <- as.list(setdiff(all_files, changed_files))
            lintr::lint_dir(exclusions = exclusions_list)
          }
        shell: Rscript {0}
        env:
          LINTR_ERROR_ON_LINT: true

What this does vs. the current PR branch:

  • Removes the 4-line # Explicit .token bypasses... comment (no longer needed with gh 1.6.0)
  • Replaces .token = Sys.getenv("GITHUB_PAT") with .limit = Inf (pagination fix, closes lint-changed-files: paginate the PR /files API call #878)
  • Adds the empty-files guard (if (length(changed_files) == 0))
  • Single R step — reverts main's CLI two-step (which was a workaround, also no longer needed)

Why I couldn't apply this automatically: The issue_comment-on-PR trigger checks out main rather than the PR head branch, and the claude.yml action token doesn't include workflows: write in its permissions scope. Applying this from a local Claude CLI session (which uses your personal token) would work.

— posted by @claude post-step from workflow run

Resolves merge conflict against main and lands the simplified form @claude
identified but couldn't push (the @claude session was checked out on main
and its token lacks `workflows: write`).

What this does, end-to-end on the `lint-changed-files.yaml` step:
- Single R step (revert main's CLI two-step that worked around gh 1.5.0).
- Drop the `.token = Sys.getenv("GITHUB_PAT")` bypass — gh 1.6.0's
  `validate_gh_pat()` accepts the `ghs_*` server-to-server tokens
  Actions issues, so the default token resolution works without override.
- Pass `.limit = Inf` so the gh::gh files-API call follows pagination
  (closes the concern split out as #878).
- Keep the empty-files guard added on main so a PR that only changes
  non-R/qmd files reports cleanly instead of trying to lint nothing.
- Drop the obsolete 4-line comment explaining the bypass.

renv.lock: bump gh 1.5.0 → 1.6.0. Mirrors the upstream DESCRIPTION
diff: tighter rlang dep (>=1.0.0 → >=1.1.0), Suggests adds vctrs and
webfakes (>=1.5.0), new Config/roxygen2/version, and the docs URL drops
its `#readme` suffix.

https://claude.ai/code/session_01PtDgktdMme5SZtze1EGx9U
@claude

claude Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @d-morrison's task in 1m 57s —— View job


Code Review — PR #865

Tasks:

  • Gather context from PR description and comment history
  • Read changed files and diff against origin/main
  • Review the diff
  • Post review findings

Summary

This is the simplification d-morrison requested once gh 1.6.0 landed on CRAN. The two-step CLI workaround on main (which used the gh CLI binary to bypass validate_gh_pat()) is replaced by a clean, single R step using the gh R package directly. The renv.lock pin is updated to 1.6.0. Both changes are correct.


Fix correctness — ✅

Workflow (lint-changed-files.yaml):

main had a two-step workaround:

  1. A gh api --paginate shell step (CLI binary, not the R package) to list changed files → changed_files.txt
  2. An R step that read changed_files.txt and ran lintr

The branch replaces both with a single R step calling gh::gh(..., .limit = Inf). This is correct because:

  • gh 1.6.0 includes the fix from r-lib/gh#233validate_gh_pat() now accepts ghs_* server-to-server tokens. The workaround is no longer needed.
  • .limit = Inf correctly enables automatic pagination through all API pages, resolving the pre-existing lint-changed-files: paginate the PR /files API call #878 concern identified in earlier reviews.
  • The job-level GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} (line 14) is inherited by all steps; gh 1.6.0 will find it through its standard env-var lookup and no longer reject it.

Filter predicate (line 44):

purrr::keep(~ .$status != "renamed" || .$changes > 0)

The logic is equivalent to the original jq select(.status != "renamed" or .changes > 0): keep a file if its status is not "renamed", OR if it has content changes. This correctly excludes pure no-content renames. Since purrr::keep() calls the predicate with one element at a time, || (scalar short-circuit OR) is correct here — no vectorization issue.

renv.lock:

The gh entry is updated from 1.5.0 → 1.6.0 with accurate metadata (raised rlang >= 1.1.0 floor, added vctrs/webfakes to Suggests, updated URL). No unrelated packages are modified. ✅


No leftover workaround artifacts — ✅

The step no longer passes .token = Sys.getenv("GITHUB_PAT") explicitly (removed in the simplification). The comment explaining the validate_gh_pat() bypass is gone. Nothing vestigial remains.


Pagination — resolved ✅

Issue #878 (silently linting only the first 30 files for large PRs) is resolved by .limit = Inf. No separate follow-up needed.


One minor note — not blocking

The empty-files guard added on main:

if (length(changed_files) == 0) {
  message("No changed files to lint.")
} else {
  ...
}

This was also included in the simplification (lines 47–53), which is good — it preserves the behavior from main's version and avoids lintr::lint_dir() running over the whole repo when nothing relevant changed.


Verdict

Approve. The simplification is correct, complete, and exactly as minimal as it should be. No workaround artifacts remain, pagination is fixed, and the renv.lock pin matches the new code.

@claude

claude Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @d-morrison's task in 1m 44s —— View job


Code Review — PR #865

Tasks:

  • Gather context from PR description and comment history
  • Read changed files and diff against origin/main
  • Review the diff
  • Post review findings

Summary

This PR has evolved through several iterations. The current state is the clean simplification requested once gh 1.6.0 landed on CRAN: the two-step CLI workaround that main introduced is replaced by a single R step using gh::gh() directly. Both changed files look correct.


Workflow — ✅

Consolidation from two steps to one:

main had split the work into:

  1. A shell step running gh api --paginate (CLI binary) → changed_files.txt
  2. An R step reading changed_files.txt → lint

This branch replaces both with a single R step calling gh::gh(..., .limit = Inf). This is the right simplification: the CLI workaround existed only to bypass validate_gh_pat() in the R package; with gh 1.6.0 accepting ghs_* tokens natively, the R package can be used directly again.

Token lookup — ✅

The job-level GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} (line 14) is inherited by the lint step. gh 1.6.0 finds it through its standard env-var lookup and no longer rejects ghs_* format. No explicit .token = parameter needed.

Filter predicate — ✅

purrr::keep(~ .$status != "renamed" || .$changes > 0)

Correctly mirrors the jq select(.status != "renamed" or .changes > 0) from the removed CLI step: keep a file unless it is a pure rename with no content changes. || (scalar OR) is correct inside purrr::keep()'s single-element predicate — no vectorization issue.

Pagination — ✅ (resolves #878)

.limit = Inf enables automatic page-walking via gh::gh(). PRs with more than 30 changed files are now fully linted. The pre-existing gap noted in earlier reviews is closed.

Empty-files guard — ✅

The if (length(changed_files) == 0) guard is preserved from the main version.

No workaround artifacts — ✅

The 4-line # Explicit .token bypasses... comment and the explicit .token = Sys.getenv("GITHUB_PAT") argument are both gone. Nothing vestigial remains.


renv.lock — ✅

The gh entry is updated from 1.5.0 → 1.6.0 with accurate metadata changes:

Field Before After
Version 1.5.0 1.6.0
URL ...gh#readme ...gh (removed #readme)
rlang requirement >= 1.0.0 >= 1.1.0
Suggests adds vctrs, webfakes (>= 1.5.0)
Config/roxygen2/version absent "8.0.0"

No unrelated packages are touched. The RoxygenNote: "7.3.2.9000" in the entry is the package author's dev-cycle metadata in their DESCRIPTION file; it has no effect on how renv installs the package and is not our concern.


Verdict

Approve. The simplification is correct, complete, and exactly as minimal as it should be. The gh 1.6.0 upgrade makes the workaround unnecessary, the pagination gap is resolved, and no artifacts remain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants