This file defines the working conventions for contributing to {brickster}. The goal is consistent API ergonomics, maintainable code, and tests that validate behavior (not just coverage).
- Must: required for all new/modified code unless explicitly agreed otherwise in review.
- Should: strong default; deviate only with clear, documented rationale.
{brickster} is a pragmatic R toolkit for Databricks:
- thin, readable wrappers over Databricks REST APIs
- predictable function naming and return shapes
- first-class auth ergonomics (
PAT, OAuth U2M, OAuth M2M) - practical workflows (
DBI/dbplyr, Unity Catalog volumes)
Prefer clear behavior over abstraction-heavy internals.
- Must keep functions grouped by API domain in existing
R/*.Rfiles (clusters, jobs, volumes, auth, etc.). - Must follow naming pattern:
db_<resource>_<action>. - Should add to an existing domain file before creating a new file.
- Should keep helper functions internal unless there is clear end-user value.
- Must build requests via
db_request(). - Must execute JSON API requests via
db_perform_request(). - Should execute non-JSON/binary/header requests via
db_perform_response()unless that helper clearly cannot support the endpoint. - Should include in public API wrappers:
host = db_host()token = db_token()perform_request = TRUEwhen request inspection/testing is useful
- Must maintain stable return contracts:
perform_request = FALSEreturns anhttr2_request- action/delete endpoints default to
TRUE/FALSE; return richer details only when meaningful endpoint data exists (for example: path/id/status details) - list/get endpoints should follow API response shape; return full bodies when pagination or metadata is needed and avoid dropping useful fields
- explicitly document return shape differences in roxygen when endpoints in the same family differ
- Must validate early.
- Should use
cli::cli_abort()for user-facing argument errors when it can express the check clearly. - Should use
stopifnot()for compact multi-condition assertions or internal invariants where it is clearer. - Must make error messages actionable and specific (what is wrong, and how to fix).
- Should avoid hidden side effects and stateful behavior unless required.
- Must use
TRUE/FALSEoverT/Fin new code. - Must use
{fs}for path manipulation and filesystem checks. - Must use
{purrr}for iteration in new/modified code (including tests); do not introduce new*apply/vapplyiteration unless required for a specific external interface. - Should keep comments sparse and only where behavior is non-obvious.
- Must use roxygen for all exported functions and run
devtools::document()after API changes. - Must include explicit
@returnsdocs for every exported function, includingperform_request = TRUEvsFALSEbehavior when relevant. - Should reuse parameter docs with
@inheritParams(notablyauth_paramsand shared request args). - Must place functions in the correct
@familyfor reference-site grouping. - Must use
{lifecycle}consistently for lifecycle changes:- add lifecycle badge in roxygen where relevant
- emit deprecation warnings in each deprecated function (no hidden global helper if explicit per-function messaging is preferred)
- Should ensure new/changed public functions appear correctly in pkgdown reference structure (
_pkgdown.yml) when needed.
Tests are organized in three layers. Keep this structure.
- Must validate argument handling and request construction using
perform_request = FALSE. - Must check returned type (
httr2_request) and key validation paths.
- Must validate branching/business logic without network calls.
- Must use
local_mocked_bindings()and assert behavior/output explicitly.
- Must guard real API tests with skip helpers (
skip_on_cran(), auth/cloud guards). - Should keep integration tests focused on key live behavior, not exhaustive API permutations.
- Must use
withr::local_envvar()/withr::local_options()for temporary state. - Must not use
options()directly in tests. - Must not use
Sys.unsetenv()directly in tests. - Must not use
brickster:::in tests. - Must not use
<<-; track state withnew.env(parent = emptyenv()). - Must avoid nested mocking blocks.
- Should use at most one
local_mocked_bindings()call per package within a singletest_that()block; split phases into separate tests when needed. - Should keep tests behavior-oriented; remove tests that only assert expected network failure with no additional value.
- Must treat coverage as a signal, not the goal. Meaningful coverage is preferred over theater.
- Should treat ~80% project coverage as acceptable when critical paths are tested.
- Must prioritize tests for risk-bearing logic and user-visible behavior first.
- Should ignore coverage only when justified and hard to test (startup hooks, truly environment-specific branches, deprecated legacy code).
- Must use
.covrignoreor# nocov start/endsparingly and document rationale in PR notes.
- Must update
NEWS.mdfor user-visible changes. - Must use concise bullets with clear impact.
- Should use explicit references to function names in backticks.
- Must state replacement path and migration guidance for deprecations.
devtools::document()testthat::test_local()(or targeted files while iterating)covr::package_coverage(type = "tests")when coverage impact is relevant
- Public behavior changes are documented in
NEWS.md. - Roxygen docs are updated and regenerated.
- Tests validate behavior changes (not just coverage lines).
- Coverage exceptions (
.covrignore/# nocov) are justified and minimal.
Reference sources for endpoint work:
- Databricks REST API docs: https://docs.databricks.com/api/workspace/introduction
- Databricks Python SDK (repo): https://github.com/databricks/databricks-sdk-py
- Databricks Python SDK service implementations: https://github.com/databricks/databricks-sdk-py/tree/main/databricks/sdk/service
- Confirm endpoint contract from Databricks docs (method, path, version, request/response shape), then compare behavior and naming against the Python SDK implementation when useful.
- Add wrapper(s) in correct domain file using existing naming and argument conventions.
- Add validation and predictable return shape.
- Add/extend request-shape tests (
perform_request = FALSE). - Add offline helper tests for non-trivial logic.
- Add/adjust integration tests only for high-value live behaviors.
- Update roxygen, run
devtools::document(), verifyNAMESPACE/manoutput. - Update
NEWS.mdfor user-visible behavior. - Update vignette/README when workflow or recommended usage changes.
- Make common workflows obvious and short.
- Keep defaults safe and unsurprising.
- Prioritize consistent argument names across related functions.
- Prefer migration guidance over hard breaks.