Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions .github/skills/create-issue/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
name: create-issue
trigger: create GitHub issues
description: Creates GitHub issues for the package repository. Use when asked to create, file, or open a GitHub issue, or when planning new features or functions that need to be tracked.
compatibility: Requires the `gh` CLI and an authenticated GitHub session.
---
Expand Down Expand Up @@ -53,7 +54,6 @@ Which sections to include depends on the issue type:
| `## Details` | optional | optional | optional | optional |
| `## Proposed signature` | ✓ | — | — | — |
| `## Behavior` | ✓ | ✓ | — | — |
| `## Implementation` | optional | optional | optional | optional |
| `## References` | optional | optional | optional | optional |

### `## Summary` (all types)
Expand All @@ -74,7 +74,7 @@ Example:

### `## Details` (optional, all types)

For information that's important to capture but doesn't fit naturally into any other section. Use sparingly — if the content belongs in `## Behavior`, `## Proposed signature`, or `## References`, put it there instead.
For information that's important to capture but doesn't fit naturally into any other section, including implementation details such as packages to add to `Imports` in `DESCRIPTION` or files to add to `inst`. Use sparingly — if the content belongs in `## Behavior`, `## Proposed signature`, or `## References`, put it there instead.

### `## Proposed signature` (Feature only)

Expand All @@ -100,10 +100,6 @@ function_name(arg1, arg2)
- **Feature**: bullet points describing expected behavior, edge cases, and any internal helpers to implement as part of this issue.
- **Bug**: describe the current (broken) behavior, the expected behavior, and steps to reproduce if known.

### `## Implementation` (optional, all types)

Bullet points describing additional details about implementation of the feature, such as packages to add to `Imports` in `DESCRIPTION` or files to add to `inst`.

### `## References` (optional, all types)

Only include when there are specific reference implementations, external URLs, or related code to link to. Omit it entirely when there are none.
Expand Down
4 changes: 3 additions & 1 deletion .github/skills/document/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
name: document
trigger: document functions
description: Document package functions. Use when asked to document functions.
---

Expand All @@ -10,6 +11,7 @@ description: Document package functions. Use when asked to document functions.
- Run `air format .` then `devtools::document()` after changing any roxygen2 docs.
- Use sentence case for all headings.
- Files matching `R/import-standalone-*.R` are imported from other packages and have their own conventions. Do not modify their documentation.
- After documenting functions, run `devtools::document(roclets = c('rd', 'collate', 'namespace'))`.

## Shared parameters

Expand Down Expand Up @@ -113,7 +115,7 @@ Internal helpers (identified by a dot prefix, e.g. `.parse_response()`) use abbr
#' @keywords internal
```

No description paragraph, fewer blank `#'` lines, and no `@examples`.
Description paragraph is optional (only include when usage isn't obvious), fewer blank `#'` lines, and no `@examples`.

## S3 methods and `@rdname` grouping

Expand Down
1 change: 1 addition & 0 deletions .github/skills/github/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
name: github
trigger: from github
description: GitHub workflows using the `gh` CLI, including viewing issues/PRs and commit message conventions. Use when interacting with GitHub in any way, such as viewing, creating, or editing issues and pull requests, making commits, or running any `gh` command.
compatibility: Requires the `gh` CLI and an authenticated GitHub session.
---
Expand Down
1 change: 1 addition & 0 deletions .github/skills/implement-issue/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
name: implement-issue
trigger: implement issue / work on #NNN
description: Implements a GitHub issue end-to-end. Use when asked to implement, work on, or fix a specific issue number.
compatibility: Requires the `gh` CLI and an authenticated GitHub session.
---
Expand Down
1 change: 1 addition & 0 deletions .github/skills/r-code/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
name: r-code
trigger: writing R functions / API design / error handling
description: Guide for writing R code. Use when writing new functions, designing APIs, or reviewing/modifying existing R code.
---

Expand Down
1 change: 1 addition & 0 deletions .github/skills/search-code/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
name: search-code
trigger: search / rewrite code
description: Search and rewrite R source code by syntax using astgrepr. Use when asked to find patterns in code, search for function calls, identify usage of specific arguments, locate structural patterns across R files, or perform find-and-replace on code structure.
---

Expand Down
18 changes: 11 additions & 7 deletions .github/skills/tdd-workflow/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
name: tdd-workflow
trigger: writing or reviewing tests
description: Test-driven development workflow. Use when writing any R code (writing new features, fixing bugs, refactoring, or reviewing tests).
---

Expand Down Expand Up @@ -72,9 +73,12 @@ For complex outputs that are hard to specify with equality assertions:
test_that("build_summary print method is stable (#123)", {
expect_snapshot(print(build_summary(sample_data)))
})
```

For errors, wrap expect_error() inside expect_snapshot() so both the error
class and the message text are captured in the snapshot:

# For errors, wrap expect_error() inside expect_snapshot() so both the error
# class and the message text are captured in the snapshot:
```r
test_that("fetch_records errors on invalid input (#456)", {
expect_snapshot(
(expect_error(
Expand All @@ -84,15 +88,15 @@ test_that("fetch_records errors on invalid input (#456)", {
)
})
```
(see also "Testing errors with `stbl::expect_pkg_error_classes()`" below)

When snapshots change intentionally:
When snapshots change intentionally, check the content of the file corresponding to the edited test file, then accept:

```r
testthat::snapshot_review("test_name")
testthat::snapshot_accept("test_name")
```

Snapshots are stored in `tests/testthat/_snaps/`.
Snapshots are stored in `tests/testthat/_snaps/`. The filename corresponds to the R file being tested, ending with `.md`.

## Test design principles

Expand Down Expand Up @@ -195,11 +199,11 @@ Combine with `expect_snapshot()` to lock down both the class hierarchy and the u
```r
test_that("process_data() error message is stable (#42)", {
expect_snapshot(
stbl::expect_pkg_error_classes(
(stbl::expect_pkg_error_classes(
process_data(data.frame()),
"mypkg",
"empty_input"
)
))
)
})
```
Expand Down
8 changes: 5 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,20 @@ License: MIT + file LICENSE
URL: https://github.com/api2r/pkgskills,
https://api2r.github.io/pkgskills/
BugReports: https://github.com/api2r/pkgskills/issues
Depends:
R (>= 4.1.0)
Imports:
cli,
desc,
fs,
gh,
rlang,
stbl,
stringr,
usethis
Suggests:
gh,
testthat (>= 3.0.0),
withr,
yaml
withr
Remotes:
stbl=wranglezone/stbl
Config/testthat/edition: 3
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Generated by roxygen2: do not edit by hand

export(use_agent)
export(use_skill_create_issue)
importFrom(rlang,caller_arg)
importFrom(rlang,caller_env)
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# pkgskills (development version)

* `use_skill_create_issue()` installs the `create-issue` skill, fetching
repository metadata from GitHub and rendering a tailored skill template into
the project (#3).
* `use_agent()` installs a structured `AGENTS.md` file, populating the
repository overview from the project's `DESCRIPTION` (#2).

Expand Down
20 changes: 20 additions & 0 deletions R/aaa-conditions.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#' Raise a package-scoped error
#'
#' @inheritParams .shared-params
#' @inheritParams stbl::pkg_abort
#' @returns Does not return.
#' @keywords internal
.pkg_abort <- function(
message,
subclass,
call = caller_env(),
message_env = caller_env()
) {
stbl::pkg_abort(
"pkgskills",
message,
subclass,
call = call,
message_env = message_env
)
}
23 changes: 22 additions & 1 deletion R/aaa-shared_params.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,30 @@
#' These parameters are used in multiple functions. They are defined here to
#' make them easier to import and to find.
#'
#' @param agents_lines (`character`) Lines of `AGENTS.md`.
#' @param call (`environment`) The caller environment for error messages.
#' @param data (`list`) Named list of whisker template variables for rendering.
#' @param gh_token (`character(1)`) A GitHub personal access token. Defaults to
#' `gh::gh_token()`.
#' @param lines (`character`) Lines of a file, as returned by [readLines()].
#' @param new_row (`character(1)`) A pre-built skill row string, as produced by
#' `.make_skill_row()`.
#' @param open (`logical(1)`) Whether to open the file after creation.
#' @param save_as (`character(1)`) Output file path, relative to project root.
#' @param overwrite (`logical(1)`) Whether to overwrite an existing file.
#' Defaults to `TRUE`.
#' @param owner (`character(1)`) GitHub repository owner (user or organization).
#' @param repo (`character(1)`) GitHub repository name.
#' @param save_as (`character(1)`) Output file path, relative to the project
#' root.
#' @param skill (`character(1)`) Skill name. A folder name under
#' `inst/templates/skills/`, e.g. `"create-issue"`. Determines the template
#' path and the install subdirectory.
#' @param target_dir (`character(1)`) Directory where the skill will be
#' installed, relative to the project root. Defaults to `".github"`.
#' @param trigger (`character(1)`) Trigger phrase for the skill.
#' @param use_skills_subdir (`logical(1)`) Whether to place the skill folder
#' under a `skills` subdirectory of `target_dir`. Defaults to `TRUE`,
#' producing `.github/skills/{skill}/SKILL.md`.
#' @param x_arg (`character(1)`) Argument name for `x`, used in error messages.
#'
#' @name .shared-params
Expand Down
7 changes: 3 additions & 4 deletions R/use_agent.R
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ use_agent <- function(save_as = "AGENTS.md", open = rlang::is_interactive()) {
file = usethis::proj_path("DESCRIPTION")
)
))
path <- usethis::proj_path(save_as)
fs::dir_create(fs::path_dir(path))
.use_template("AGENTS.md", save_as, data, open)
cli::cli_inform(c(
"{.file AGENTS.md} created.",
Expand All @@ -28,20 +26,21 @@ use_agent <- function(save_as = "AGENTS.md", open = rlang::is_interactive()) {
"Focus on the **Repository overview** and the **Key files** table.\""
)
))
invisible(path)
invisible(usethis::proj_path(save_as))
}

#' Wrapper around [usethis::use_template()]
#'
#' @param template (`character(1)`) Template name within `inst/templates/`.
#' @param data (`list`) Named list of values for whisker rendering.
#' @inheritParams .shared-params
#' @returns Called for side effects.
#' @keywords internal
.use_template <- function(template, save_as, data, open, call = caller_env()) {
save_as <- .to_string(save_as, call = call)
data <- stbl::to_list(data, call = call)
template <- .to_string(template, call = call)
open <- stbl::to_lgl_scalar(open, allow_null = FALSE, call = call)
fs::dir_create(fs::path_dir(usethis::proj_path(save_as)))
usethis::use_template(
template,
save_as = save_as,
Expand Down
Loading
Loading