Skip to content

Commit 309b4a9

Browse files
committed
Merged origin/main into gh-download
2 parents 52495c9 + 79a9ed8 commit 309b4a9

16 files changed

+228
-89
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Claude Code Review
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize]
6+
# Optional: Only run on specific file changes
7+
# paths:
8+
# - "src/**/*.ts"
9+
# - "src/**/*.tsx"
10+
# - "src/**/*.js"
11+
# - "src/**/*.jsx"
12+
13+
jobs:
14+
claude-review:
15+
# Optional: Filter by PR author
16+
# if: |
17+
# github.event.pull_request.user.login == 'external-contributor' ||
18+
# github.event.pull_request.user.login == 'new-developer' ||
19+
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
20+
21+
runs-on: ubuntu-latest
22+
permissions:
23+
contents: read
24+
pull-requests: read
25+
issues: read
26+
id-token: write
27+
28+
steps:
29+
- name: Checkout repository
30+
uses: actions/checkout@v4
31+
with:
32+
fetch-depth: 1
33+
34+
- name: Run Claude Code Review
35+
id: claude-review
36+
uses: anthropics/claude-code-action@beta
37+
with:
38+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
39+
40+
# Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4.1)
41+
# model: "claude-opus-4-1-20250805"
42+
43+
# Direct prompt for automated review (no @claude mention needed)
44+
direct_prompt: |
45+
Please review this pull request and MINIMAL provide feedback on
46+
potential bugs or issues. Never praise or flatter. Be concise.
47+
Use simple, clear language. If you don't have anything significant
48+
to add, just reply LGTM.
49+
50+
# Optional: Use sticky comments to make Claude reuse the same comment on subsequent pushes to the same PR
51+
use_sticky_comment: true
52+
53+
# Optional: Add specific tools for running tests or linting
54+
# allowed_tools: "Bash(npm run test),Bash(npm run lint),Bash(npm run typecheck)"
55+
56+
# Optional: Skip review for certain conditions
57+
# if: |
58+
# !contains(github.event.pull_request.title, '[skip-review]') &&
59+
# !contains(github.event.pull_request.title, '[WIP]')

.github/workflows/claude.yml

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
name: Claude Code
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
pull_request_review_comment:
7+
types: [created]
8+
issues:
9+
types: [opened, assigned]
10+
pull_request_review:
11+
types: [submitted]
12+
13+
jobs:
14+
claude:
15+
if: |
16+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
17+
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
18+
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
19+
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
20+
runs-on: ubuntu-latest
21+
permissions:
22+
contents: read
23+
pull-requests: read
24+
issues: read
25+
id-token: write
26+
actions: read # Required for Claude to read CI results on PRs
27+
steps:
28+
- name: Checkout repository
29+
uses: actions/checkout@v4
30+
with:
31+
fetch-depth: 1
32+
33+
- name: Install air
34+
uses: posit-dev/setup-air@v1
35+
36+
- uses: r-lib/actions/setup-r@v2
37+
with:
38+
use-public-rspm: true
39+
40+
- uses: r-lib/actions/setup-r-dependencies@v2
41+
with:
42+
extra-packages: any::rcmdcheck,roxygen2
43+
needs: check
44+
45+
- name: Run Claude Code
46+
id: claude
47+
uses: anthropics/claude-code-action@beta
48+
with:
49+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
50+
51+
# This is an optional setting that allows Claude to read CI results on PRs
52+
additional_permissions: |
53+
actions: read
54+
55+
# Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4.1)
56+
# model: "claude-opus-4-1-20250805"
57+
58+
# Optional: Customize the trigger phrase (default: @claude)
59+
# trigger_phrase: "/claude"
60+
61+
# Optional: Trigger when specific user is assigned to an issue
62+
# assignee_trigger: "claude-bot"
63+
64+
# Optional: Allow Claude to run specific commands
65+
allowed_tools: "Bash(R:*);Bash(air format:*)"
66+
67+
# Optional: Add custom instructions for Claude to customize its behavior for your project
68+
# custom_instructions: |
69+
# Follow our coding standards
70+
# Ensure all new code has tests
71+
# Use TypeScript for new files
72+
73+
# Optional: Custom environment variables for Claude
74+
# claude_env: |
75+
# NODE_ENV: test

R/auto-test.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ auto_test_package <- function(
8383
test_path <- normalizePath(file.path(path, "tests", "testthat"))
8484

8585
# Start by loading all code and running all tests
86-
withr::local_envvar("NOT_CRAN" = "true")
86+
local_assume_not_on_cran()
8787
pkgload::load_all(path)
8888
test_dir(
8989
test_path,

R/local.R

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,7 @@ local_test_directory <- function(path, package = NULL, .env = parent.frame()) {
190190
}
191191

192192
local_interactive_reporter <- function(.env = parent.frame()) {
193-
# Definitely not on CRAN
194-
withr::local_envvar(NOT_CRAN = "true", .local_envir = .env)
193+
local_assume_not_on_cran(.env)
195194
withr::local_options(testthat_interactive = TRUE, .local_envir = .env)
196195

197196
# Use edition from working directory

R/parallel.R

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ test_files_parallel <- function(
6565
)
6666

6767
withr::with_dir(test_dir, {
68-
reporters <- test_files_reporter_parallel(reporter)
68+
reporters <- test_files_reporter(reporter, "parallel")
6969
with_reporter(reporters$multi, {
7070
parallel_updates <- reporter$capabilities$parallel_updates
7171
if (parallel_updates) {
@@ -83,23 +83,6 @@ test_files_parallel <- function(
8383
})
8484
}
8585

86-
test_files_reporter_parallel <- function(reporter, .env = parent.frame()) {
87-
lister <- ListReporter$new()
88-
snapshotter <- MainprocessSnapshotReporter$new("_snaps")
89-
reporters <- list(
90-
find_reporter(reporter),
91-
lister, # track data
92-
snapshotter
93-
)
94-
withr::local_options(
95-
"testthat.snapshotter" = snapshotter,
96-
.local_envir = .env
97-
)
98-
list(
99-
multi = MultiReporter$new(reporters = compact(reporters)),
100-
list = lister
101-
)
102-
}
10386

10487
default_num_cpus <- function() {
10588
# Use common option, if set

R/skip.R

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,14 @@ local_on_cran <- function(on_cran, frame = caller_env()) {
190190
withr::local_envvar(NOT_CRAN = tolower(!on_cran), .local_envir = frame)
191191
}
192192

193+
# Assert that we're not on CRAN, but don't override the user's setting
194+
local_assume_not_on_cran <- function(frame = caller_env()) {
195+
if (Sys.getenv("NOT_CRAN") != "") {
196+
return()
197+
}
198+
withr::local_envvar("NOT_CRAN" = "true", .local_envir = frame)
199+
}
200+
193201
#' @export
194202
#' @param os Character vector of one or more operating systems to skip on.
195203
#' Supported values are `"windows"`, `"mac"`, `"linux"`, `"solaris"`,

R/snapshot-file-snaps.R

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,6 @@ FileSnaps <- R6::R6Class(
3939
},
4040

4141
append = function(test, variant, data) {
42-
if (!has_name(self$snaps, variant)) {
43-
# Needed for R < 3.6
44-
self$snaps[[variant]] <- list()
45-
}
46-
4742
self$snaps[[variant]][[test]] <- c(self$snaps[[variant]][[test]], data)
4843
length(self$snaps[[variant]][[test]])
4944
},

R/snapshot-reporter.R

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ SnapshotReporter <- R6::R6Class(
140140
return()
141141
}
142142

143-
# If expectation errors or skips, need to reset remaining snapshots
143+
# If expectation errors or skips, need to copy snapshots from old to cur
144144
if (expectation_error(result) || expectation_skip(result)) {
145145
self$cur_snaps$reset(self$test, self$old_snaps)
146146
}
@@ -204,23 +204,19 @@ get_snapshotter <- function() {
204204
#' @export
205205
#' @keywords internal
206206
local_snapshotter <- function(
207-
snap_dir = NULL,
207+
reporter = SnapshotReporter,
208+
snap_dir = "_snaps",
208209
cleanup = FALSE,
209210
fail_on_new = NULL,
210-
.env = parent.frame()
211+
frame = caller_env()
211212
) {
212-
snap_dir <- snap_dir %||% withr::local_tempdir(.local_envir = .env)
213-
reporter <- SnapshotReporter$new(
214-
snap_dir = snap_dir,
215-
fail_on_new = fail_on_new
216-
)
217-
if (!identical(cleanup, FALSE)) {
218-
cli::cli_warn("{.arg cleanup} is deprecated.")
219-
}
213+
reporter <- reporter$new(snap_dir = snap_dir, fail_on_new = fail_on_new)
214+
withr::local_options("testthat.snapshotter" = reporter, .local_envir = frame)
220215

221-
withr::local_options(
222-
"testthat.snapshotter" = reporter,
223-
.local_envir = .env
224-
)
225216
reporter
226217
}
218+
219+
local_test_snapshotter <- function(snap_dir = NULL, frame = caller_env()) {
220+
snap_dir <- snap_dir %||% withr::local_tempdir(.local_envir = frame)
221+
local_snapshotter(snap_dir = snap_dir, fail_on_new = FALSE, frame = frame)
222+
}

R/test-files.R

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ test_files_serial <- function(
221221
local_testing_env(env)
222222

223223
test_files_setup_state(test_dir, test_package, load_helpers, env)
224-
reporters <- test_files_reporter(reporter)
224+
reporters <- test_files_reporter(reporter, "serial")
225225

226226
with_reporter(
227227
reporters$multi,
@@ -315,15 +315,30 @@ test_files_setup_state <- function(
315315
withr::defer(source_test_teardown(".", env), frame) # old school
316316
}
317317

318-
test_files_reporter <- function(reporter, .env = parent.frame()) {
318+
test_files_reporter <- function(
319+
reporter,
320+
mode = c("serial", "parallel"),
321+
frame = caller_env()
322+
) {
323+
mode <- arg_match(mode)
324+
325+
# User selected reporter
326+
user <- find_reporter(reporter)
327+
328+
# Reporter that collect test results
319329
lister <- ListReporter$new()
320-
reporters <- list(
321-
find_reporter(reporter),
322-
lister, # track data
323-
local_snapshotter("_snaps", .env = .env)
324-
)
330+
331+
# Snapshot reporter
332+
if (mode == "parallel") {
333+
snap_base <- MainprocessSnapshotReporter
334+
} else {
335+
snap_base <- SnapshotReporter
336+
}
337+
snap <- local_snapshotter(snap_base, fail_on_new = on_ci(), frame = frame)
338+
339+
reporters <- compact(list(user, lister, snap))
325340
list(
326-
multi = MultiReporter$new(reporters = compact(reporters)),
341+
multi = MultiReporter$new(reporters = reporters),
327342
list = lister
328343
)
329344
}

R/test-package.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ test_local <- function(
6969
package <- pkgload::pkg_name(path)
7070
test_path <- file.path(pkgload::pkg_path(path), "tests", "testthat")
7171

72-
withr::local_envvar(NOT_CRAN = "true")
72+
local_assume_not_on_cran()
7373
test_dir(
7474
test_path,
7575
package = package,

0 commit comments

Comments
 (0)