| name | koopa-r-release |
| description | koopa R package release — cloud-native S3 + CloudFront, acidgenomics profile, koopa app r publish/reindex/archive, sonoma-arm64 binaries, pre-release AcidDevTools::check() gate. Use when releasing, publishing, reindexing, or archiving an Acid Genomics R package. |
koopa R Package Release
Architecture: Cloud-Native S3
R packages are hosted at https://r.acidgenomics.com. S3 is the source of truth —
no local git repo or drat checkout required. Tarballs are uploaded directly; PACKAGES
manifests are regenerated by streaming only the DESCRIPTION file from each tarball
(ETag == MD5 for single-part uploads).
- S3 bucket: see
_BUCKET in lang/python/src/koopa/cran.py
- CloudFront distribution: set via
AWS_CLOUDFRONT_DISTRIBUTION_ID_R in <koopa-root>/.env (required; raises if unset)
- AWS profile:
acidgenomics
- CloudFront ID env var:
AWS_CLOUDFRONT_DISTRIBUTION_ID_R (required); falls back to
AWS_CLOUDFRONT_DISTRIBUTION_ID — both loaded from <koopa-root>/.env if not already in the environment
- Implementation:
lang/python/src/koopa/cran.py (mirrors pypi.py)
S3 layout
src/contrib/
<Pkg>_<ver>.tar.gz # current source tarballs (one per package)
PACKAGES / PACKAGES.gz / PACKAGES.rds
Archive/<Pkg>/<Pkg>_<old>.tar.gz # superseded versions
bin/macosx/sonoma-arm64/contrib/4.6/
<Pkg>_<ver>.tgz # current arm64 binaries (one per package)
PACKAGES / PACKAGES.gz / PACKAGES.rds
bin/macosx/big-sur-arm64/contrib/4.{3,4,5,6}/
PACKAGES # empty skeleton — suppresses R client warnings
# (no binaries; R falls back to source silently)
bin/windows/contrib/<Rver>/
PACKAGES # empty skeleton
Only sonoma-arm64/contrib/4.6/ carries real binaries. All other binary paths hold
empty PACKAGES skeletons. x86_64 and big-sur-x86_64 paths are not served at all
(deleted from S3).
Commands
koopa app r publish <package-dir>
Build source + macOS arm64 binary, upload both to S3, regenerate PACKAGES manifests
for src/contrib and sonoma-arm64/contrib/4.6, invalidate CloudFront, then create
an annotated git tag v<Version> and push it to origin. Tag message format:
<Package> v<Version> (<Date>) — sourced from DESCRIPTION (Date: falls back to
today). Tag step is a no-op when the package dir is not a git repo, and skipped with
a notice when the tag already exists locally (the push still runs to recover a prior
partial failure).
koopa app r publish ~/git/personal/r-syntactic
koopa app r publish ~/git/personal/r-syntactic --no-check
koopa app r publish ~/git/personal/r-syntactic --no-deploy
koopa app r publish ~/git/personal/r-syntactic --no-tag
koopa app r publish-from-github <repo>
Clone a GitHub repo into a temp dir and publish it. Used for packages not checked
out locally. Default org: acidgenomics.
koopa app r publish-from-github r-acidcli
koopa app r publish-from-github r-acidcli --org acidgenomics --no-check
Dep install: missing Imports/Depends are auto-installed into the system
R library before building the binary. BiocManager repos are included when available.
Note: pointillism 0.8.0 has been updated for Seurat 5 compatibility and
the binary build now succeeds.
koopa app r reindex [--no-invalidate]
Regenerate all PACKAGES manifests from current S3 contents. Discovers active binary
prefixes automatically. Writes empty skeleton PACKAGES for _SKELETON_BINARY_PREFIXES
(suppress R client warnings on big-sur-arm64 paths).
koopa app r reindex
koopa app r reindex --no-invalidate
koopa app r deploy [--no-invalidate]
Alias for reindex — kept for CLI symmetry and AcidDevTools compatibility.
koopa app r archive [--no-invalidate]
Move superseded source tarballs from src/contrib/ to src/contrib/Archive/<Pkg>/.
Keeps only the latest version flat in src/contrib/. Regenerates manifests.
koopa app r archive
Local Clone Setup
All 24 active packages are cloned under ~/git/personal/r-<pkgname> (HTTPS origin).
The canonical set is derived from S3 — not from gh repo list. The repo names
are the .tar.gz filenames stripped of version, lowercased, and prefixed with r-.
Branch convention: develop = active development; main = release-ready.
Always work on develop; switch to main only to publish (step 3 of the release flow).
To sync / bootstrap all clones (zsh-safe — for repo in $repos doesn't word-split):
aws --profile acidgenomics s3 ls \
s3://r-<account-id>-us-east-1-an/src/contrib/ \
| awk '/\.tar\.gz$/ {print $NF}' \
| sed -E 's/_[0-9].*\.tar\.gz$//' \
| awk '{print "r-" tolower($0)}' \
| sort -u \
| while IFS= read -r repo; do
target=~/git/personal/"$repo"
if [ -d "$target/.git" ]; then
git -C "$target" fetch --quiet origin develop
git -C "$target" checkout --quiet develop
git -C "$target" pull --quiet --ff-only origin develop
else
git clone --quiet -b develop \
"https://github.com/acidgenomics/$repo.git" "$target"
fi
done
Verify afterwards:
aws --profile acidgenomics s3 ls s3://r-<account-id>-us-east-1-an/src/contrib/ \
| awk '/\.tar\.gz$/ {print $NF}' | sed -E 's/_[0-9].*\.tar\.gz$//' \
| awk '{print "r-" tolower($0)}' | sort -u \
| while IFS= read -r repo; do
branch=$(git -C ~/git/personal/"$repo" rev-parse --abbrev-ref HEAD 2>/dev/null)
printf '%s\t%s\n' "$repo" "${branch:-MISSING}"
done
Expected: 24 lines, all develop.
End-to-End Release (packages in ~/git/personal)
- Bump
Version: and Date: in DESCRIPTION; add NEWS.md entry.
- Commit on
develop, open PR develop→main, merge.
- Publish from main (builds, uploads, tags, and pushes the tag in one step):
git -C ~/git/personal/r-<pkg> checkout main && git pull
koopa app r publish ~/git/personal/r-<pkg> --no-check
- Verify (smoke test below).
The tag v<ver> is created and pushed to origin automatically by publish. Use
--no-tag to opt out. No drat git commit needed — S3 is the source of truth.
Relicensing (AGPL-3 → Apache-2.0)
16 packages in the repo are still AGPL-3. The pattern (already done for 8, most
recently pointillism 0.8.0):
License: Apache License (>= 2) in DESCRIPTION (CRAN shipped-template form)
LICENSE.md at repo root (usethis::use_apache_license() output)
- Delete the old plain
LICENSE file
- Update
.Rbuildignore: ^LICENSE\.md$ (not ^LICENSE$)
- Add
License changes: section to NEWS.md
- Bump patch version (so the new Apache-2 tarball differs from the published AGPL one)
DESCRIPTION Conventions
Version: X.Y.Z — manual bump; no bumpver
Date: YYYY-MM-DD — update to release date
License: Apache License (>= 2) — do NOT use | file LICENSE
LICENSE.md — Apache-2.0 Markdown (usethis output); no plain LICENSE
.Rbuildignore: ^LICENSE\.md$
NEWS.md Format
## <Pkg> X.Y.Z (YYYY-MM-DD)
Major changes:
Minor changes:
Bug fixes:
License changes:
Omit empty sections. Top heading = current release.
Version-bump Rule
If Version: in DESCRIPTION matches what's already in src/contrib/PACKAGES,
bump the patch before publishing — S3 overwrites but the PACKAGES index must have
a new version to be useful. koopa app r archive will move the old one to Archive/.
Verification Smoke Test
tmp=$(mktemp -d)
TMP_LIB="$tmp" Rscript -e '
lib <- Sys.getenv("TMP_LIB")
install.packages("goalie", repos = "https://r.acidgenomics.com", lib = lib)
cat("OK", as.character(packageVersion("goalie", lib.loc = lib)), "\n")
'
rm -rf "$tmp"
Expected: binary pulled from sonoma-arm64/contrib/4.6/ with no warning.
Pre-Release Quality Gate
Run before publish (replaces manual R CMD check):
AcidDevTools::check(
path = "~/git/personal/r-<pkg>",
lints = TRUE,
urls = FALSE,
cran = FALSE,
biocCheck = TRUE
)
Gate order inside check(): lint → URL check → rcmdcheck() → BiocCheck().
All must pass. The function errors on any lint; it does NOT error on URL failures.
Always run with LANG=LC_ALL=en_US.UTF-8 to avoid Greek-letter translation
warnings from S4 method dispatch during load_all.
See skill acid-r-package for the full dev conventions (tooling, lintr, roxygen2 8.x).
AcidDevTools Integration
AcidDevTools::publish() calls koopa app r publish --no-check internally. The
check and pkgdown steps remain in R; build/upload/reindex are all koopa.
Source: ~/git/personal/r-aciddevtools/R/publish.R
Active Package List (src/contrib as of 2026-06-20)
25 active source packages; 25 with sonoma-arm64 binaries.
Packages still on AGPL-3 (need relicense): AcidCLI, AcidDevTools, AcidExperiment,
AcidGSEA, AcidGenerics, AcidMarkdown, AcidPlots, AcidRoxygen, AcidSingleCell,
AcidTest, Chromium, DESeqAnalysis, EggNOG, PANTHER, WormBase, basejump.
Archived / no longer maintained: bcbioBase, bcbioRNASeq, bcbioSingleCell,
cBioPortalAnalysis, DepMapAnalysis, koopa (R package).
_SKELETON_BINARY_PREFIXES (in cran.py)
Add a new entry whenever a new R minor version ships, before publishing any packages
for that version. Empty PACKAGES prevent R client warnings on macOS arm64 machines
running the old R version.
_SKELETON_BINARY_PREFIXES: list[str] = [
"bin/macosx/big-sur-arm64/contrib/4.3",
"bin/macosx/big-sur-arm64/contrib/4.4",
"bin/macosx/big-sur-arm64/contrib/4.5",
"bin/macosx/big-sur-arm64/contrib/4.6",
]
Comparison to Python Publish
| Concept | Python | R |
|---|
| Command | koopa app python publish | koopa app r publish |
| Module | koopa/pypi.py | koopa/cran.py |
| Build | uv build | R CMD build + R CMD INSTALL --build |
| Index format | PEP 503 HTML (hand-rolled) | CRAN PACKAGES DCF |
| Manifest regen | list S3 + SHA256 via download | stream DESCRIPTION only; ETag = MD5 |
| Version mgmt | bumpver | manual in DESCRIPTION |
| Index URL | https://python.acidgenomics.com/ | https://r.acidgenomics.com/ |
| Dep install on binary build | N/A (pure Python) | auto via install.packages() |