Skip to contents

Thanks for contributing. This guide covers the development workflow, the changelog convention, and the checks a pull request must pass. GEOquery is a Bioconductor package; devel is the working branch.

Issues vs. pull requests

Not every change needs an issue — file one where it helps users and contributors, not as ceremony.

  • Bug, feature, or behavior change → open an issue first (or link an existing one), then reference it from the PR with Fixes #123. These are user-facing, so they also get a NEWS.md bullet that links both the issue and the PR. For bugs, include a GEO accession + reproducible example + sessionInfo() (the bug issue form prompts for these).
  • Chore, CI, docs, or refactor → a pull request alone is fine. No issue needed; use a chore: / ci: / docs: / refactor: commit prefix.

Planned work is tracked on the 3.0 milestone; see ROADMAP.md for the broader plan.

Development workflow

  1. Start work off devel. With jujutsu (jj, the repo is colocated so git still works): jj new devel, make the change, then jj describe -m "...". With plain git: git switch -c fix/issue-123. Either way devel is trunk().

  2. Make the change. Keep PRs focused — one logical change per PR.

  3. Reload and test locally:

    devtools::load_all(".")
    devtools::test()                 # or devtools::test(filter = "GSE") for one file
  4. Regenerate docs if you touched roxygen:

    devtools::document()             # updates man/ and NAMESPACE — never hand-edit these
  5. Update NEWS.md (see below) and bump the version (see below).

  6. Push and open a pull request against devel. With jj: jj git push --named fix/issue-123=@ (creates, tracks, and pushes the bookmark). With git: git push -u origin fix/issue-123. The PR template’s checklist is the contract; CI runs R CMD check across a platform matrix.

  7. Merge when the required checks are green. (devel is branch-protected; the required legs are the Ubuntu and macOS R CMD check jobs.)

jj for git users (optional)

Entirely optional. The repo is a colocated jujutsu + git checkout, so every git command still works and the remote only ever sees plain git branches — use jj only if you want to. To set it up: jj git init --colocate in your clone. Then the common steps map like this (devel is trunk(), jj bookmarks are git branches):

git jj
git switch -c fix/x devel jj new devel
git status / git log --oneline jj st / jj log
git commit -m "..." jj describe -m "..." (the working copy is the commit — no staging)
git rebase devel jj rebase -o devel
git push -u origin fix/x jj git push --named fix/x=@
git push (updates) jj git push

Push still goes through a bookmark → PR against devel; nothing about the Bioconductor side changes.

Safety net: jj op log shows every operation jj has performed, and jj op restore <id> (or jj undo for the last one) rewinds the whole repo to that state — so a botched rebase or an accidental jj abandon is one command to recover.

Vignettes are precompiled

The vignettes hit the live NCBI GEO network, which must not happen during R CMD build/check on CRAN/Bioconductor build machines. So each vignette is authored in a vignettes/<name>.qmd.orig source (with live eval: true code) and precompiled into the shipped static vignettes/<name>.qmd, which has the real output baked in and executes nothing at build time. (This is the knitr *.Rmd.orig pattern; Quarto’s freeze does not help here, because the vignette engine renders each file individually and freeze only applies to full-project renders.)

Do not edit vignettes/*.qmd directly — they are generated. To change a vignette:

  1. Edit the vignettes/<name>.qmd.orig source.

  2. Regenerate (with network access and the Suggests deps installed):

    Rscript dev/precompute-vignettes.R            # all vignettes
    Rscript dev/precompute-vignettes.R rnaseq     # just one
  3. Commit both the .qmd.orig source and the regenerated .qmd.

Refresh whenever you change a vignette’s code, or periodically to pick up GEO-side changes. Chunks that can’t run at precompile time (private-token examples, very large single-cell downloads, Seurat coercions, pure pseudo-code) are marked #| eval: false in the source and carry hand-written output.

NEWS / changelog convention

We follow the tidyverse NEWS style. Every user-facing change gets one bullet in NEWS.md under the top # GEOquery (development version) header (this header is renamed to the release version at release time).

Rules:

  • Write a complete sentence describing the change from the user’s perspective. Put function/argument names in backticks.

  • End every bullet with the PR link, and credit the contributor:

    * `getGEO(parseCharacteristics = FALSE)` no longer parses characteristics;
      the flag is now threaded through `parseGSEMatrix()` (#166, @reporter).
  • Group bullets under ## Breaking changes, ## New features, or ## Bug fixes only once there are enough to warrant it; otherwise a flat list is fine. Most recent entries at the top.

  • The #NNN and @user references autolink in the pkgdown changelog and on GitHub (the repo URL comes from DESCRIPTION).

  • Skip NEWS for CI-only or internal-only changes (nothing user-visible).

Versioning

Bump Version: and Date: in DESCRIPTION on every code PR, following the Bioconductor convention (increment the z in x.y.z during the devel cycle). Build-excluded changes (anything matched by .Rbuildignore, e.g. .github/, CONTRIBUTING.md, ROADMAP.md) do not require a version bump.

Checks before merge

  • R CMD check — no errors or warnings.
  • BiocCheck::BiocCheck() — Bioconductor-specific requirements.
  • lintr::lint_package() — style (config in .lintr).

Architecture Decision Records

Non-trivial architectural decisions are recorded as ADRs in adr/ — numbered NNNN-title.md, copied from adr/template.md. Add one when a PR changes a parse path, a return type, a dependency, or makes a notable trade-off. Small, self-explanatory changes don’t need an ADR; a decision you’d otherwise re-litigate in a future PR review does.

These four artifacts answer different questions, and each points at the others so any one of them leads to the whole story:

  • Issuewhy (the user problem / requested behavior). Opened first for bugs, features, and behavior changes (see Issues vs. pull requests).
  • ADRwhat we decided and why (the design). Needed only when the change is architectural.
  • NEWSwhat changed, for users.
  • PR — the implementation that ties them together.

Conventions:

  1. PR → issue. Put Fixes #NNN in the PR body so the merge closes the issue.
  2. PR → ADR. If the PR realizes a decision, say Implements ADR-XXXX in the body.
  3. ADR → issue/PR. In the ADR’s Context, link the motivating issue(s) as #NNN; fill in Deciders, and set Status: accepted when the PR merges. To revise an accepted ADR, write a new one that supersedes it and set the old one’s status to superseded by ADR-YYYY (never edit an accepted ADR’s decision).
  4. NEWS → PR/ADR. End each user-facing bullet with the PR link, and cite the ADR when one drove the change, e.g. ... (see ADR-0007) (#154).

So the full chain reads: issue → ADR (links the issue) → PR (Fixes #NNN, Implements ADR-XXXX) → NEWS bullet (… (see ADR-XXXX) (#PR)). For a change with no architectural decision, drop the ADR link and keep issue ↔︎ PR ↔︎ NEWS.

Reporting bugs

Open an issue with a GEO accession, a minimal reproducible example, and sessionInfo(). Most GEOquery bugs are specific to how one record is formatted on NCBI, so the accession is essential for reproduction.