Checklist for cutting a tagged release, archiving it on Zenodo for a DOI, and (optional/stretch) getting it CRAN-ready. Steps that need your own login/account action are marked (you) -- I can prepare everything else, but account creation, OAuth grants, and clicking "publish" on an external service are outside what I can do for you.
-
DESCRIPTION: bumpVersion:from0.0.0.9000to a real release version, e.g.0.1.0(semantic versioning; this is a first public release, so0.1.0rather than1.0.0is reasonable unless you consider the API stable). Done 2026-08-19. - Review/expand
NEWS.md(a starter draft exists) and retitle its# CodeCarbonR (development version)heading to the real release version once you bumpDESCRIPTION. Heading retitled; content itself was already substantive, not just a stub. - Run the full check locally one more time:
R CMD build .thenR CMD check --no-manual <tarball>-- should be 0 errors, 0 warnings, ideally 0 notes. Ran--as-cran(stricter than--no-manual) 2026-08-19: 0 errors/warnings/notes on every package-level check (Rd, namespace, examples, tests, vignettes, URLs). The only ERROR/WARNINGs left are this machine's local LaTeX toolchain (a flaky CTAN mirror blocked one font package tinytex needed for the PDF manual) and a missing localqpdfbinary -- both irrelevant to CRAN's own build servers, which are fully provisioned. Also ranurlchecker::url_check(): all URLs OK. - Confirm CI is green on
mainfor all three OSes (.github/workflows/R-CMD-check.yaml). Confirmed 2026-08-19. - Update
CITATION.cff'sversion:anddate-released:to match. Also fixedinst/CITATION, which had0.0.0.9000hardcoded into itsnotefield -- now pullsmeta$Versiondynamically socitation("CodeCarbonR")never goes stale again. - Update
comparison/coverage_matrix.mdif case 07 (GPU) has been validated by then -- don't ship a release implying GPU coverage that hasn't actually been run. Still not validated as of 2026-08-19; seehpc/monsoon/README.mdfor the Monsoon run plan.
git tag -a v0.1.0 -m "v0.1.0"
git push origin v0.1.0Then create a GitHub Release from that tag (via the GitHub UI, or
gh release create v0.1.0 --title "v0.1.0" --notes "..."). The release
notes are what Zenodo will show alongside the archived version, so it's
worth writing a real paragraph, not just "release", e.g.:
Initial public release of CodeCarbonR. Wraps codecarbon's
OfflineEmissionsTrackervia reticulate for tracking R code's energy consumption and estimated CO2 emissions. Validated against equivalent Python/codecarbon workloads across 6 test cases (ML training, data wrangling, statistical modeling, long-running simulation, large-file I/O, multi-phase tracking) on Windows; seecomparison/coverage_matrix.mdfor exact status per case and platform.
- Log into zenodo.org with your GitHub account (or link an existing Zenodo account to GitHub under Account Settings -> GitHub).
- Find
beabock/CodeCarbonRin the repository list and toggle it on before creating the GitHub release -- Zenodo only archives releases made after the toggle is flipped, it won't retroactively pick up a release you already published. If you already created the v0.1.0 release before flipping the toggle, either delete and recreate the release, or cut a v0.1.1 tag after enabling Zenodo. - Publish the GitHub release (or re-trigger it) -- Zenodo picks it up automatically via its GitHub webhook and mints a DOI within a few minutes.
- On the Zenodo record page, copy:
- the version DOI (specific to
v0.1.0) - the concept DOI (stable across all versions -- this is the one to put in a paper's citation, since it'll keep resolving to the latest version if you cut v0.1.1, v0.2.0, etc. later)
- the version DOI (specific to
- Fill in
CITATION.cff's commented-outdoi:/identifiers:fields with those, commit, and this becomes the canonical citation metadata GitHub shows in the "Cite this repository" sidebar button too. - Add the Zenodo DOI badge to
README.md(Zenodo gives you the markdown snippet directly on the record page, looks like[](https://doi.org/10.5281/zenodo.XXXXXXX)).
This is what gets you the EDS Open Practice Badge and a citable DOI for the code, independent of whether you ever publish to CRAN.
Not required for the Zenodo DOI or the paper's reproducibility claims -- only pursue this if you specifically want CRAN's discoverability/CI guarantees on top. Frictions specific to this package:
R CMD check --as-cranmust stay clean. Validated 2026-08-05 with--as-cranspecifically (which is what actually caught the issues below -- a plainR CMD checkmisses some of these).CITATION.cffandRELEASING.mdare.Rbuildignored, so they stay at the repo root for GitHub's "Cite this repository" button and Zenodo to find (Zenodo/GitHub read them from the git repo directly, not from the built R package tarball, so excluding them from the tarball costs nothing there), whileinst/CITATIONis what makescitation("CodeCarbonR")work from R. TheLICENSEfile is the short DCF stub R expects forLicense: MIT + file LICENSE(YEAR:/COPYRIGHT HOLDER:); the full MIT text lives inLICENSE.mdinstead (also.Rbuildignored), which is what GitHub's license detector reads.setup_carbon_tracker()installs software and touches the network. CRAN's policy forbids examples/tests/vignettes that install software, write outsidetempdir(), or require network access duringR CMD check, and forbids interactive prompts entirely (utils::menu()insidesetup_carbon_tracker()would need to not run at all underR CMD check). Concretely:- Any
@examplesblock callingsetup_carbon_tracker(),carbon_tracker(), orwith_emissions_tracked()needs\donttest{}(or\dontrun{}if it truly can't run under any CI) so CRAN's check machines don't execute it. tests/testthat/*.R's live-tracker tests already useskip_if_no_codecarbon()(seetests/testthat/helper.R), which is the right idea, but CRAN's check machines will have codecarbon unavailable, so addtestthat::skip_on_cran()alongside it (or replace it) so these don't even attempt to check for codecarbon on CRAN's infrastructure --skip_if_no_codecarbon()alone should already result in a skip there since codecarbon won't be importable, butskip_on_cran()makes the intent explicit and doesn't depend on that assumption holding.- The
vignettes/quickstart.Rmdwalkthrough already useseval = FALSEon every chunk for this reason -- it shows realistic example output as literal text rather than executing against a live tracker, so building it never touches Python/network. setup_carbon_tracker()itself already refuses to run non-interactively (seeR/setup.R), which is the correct behavior for CRAN but means nothing exercises it in automated checks; that's an intentional gap, not something to "fix" for CRAN's sake.
- Any
- A CRAN maintainer will ask why this needs a whole Python install.
Worth a line in the CRAN submission comments (
cran-comments.md) explaining thatcodecarbonhas no R equivalent and that setup is opt-in, confirmed, and isolated to its own conda environment rather than touching the user's system Python.
Pre-submission (in addition to the package-specific fixes above):
-
Every exported function (
setup_carbon_tracker(),carbon_tracker(),with_emissions_tracked(),list_carbon_tracker_countries(),carbon_tracker_ready()) needs an@examplesblock in its roxygen comment. Added 2026-08-19. One correction to the plan as originally written:list_carbon_tracker_countries()actually does callensure_codecarbon_available()internally, so (unlikecarbon_tracker_ready(), which is genuinely safe unwrapped) it needed\donttest{}too, not an unwrapped example.setup_carbon_tracker()got\dontrun{}since it can never run non-interactively under any CI. The first--as-cranrun also caught a real bug: thecarbon_tracker()/with_emissions_tracked()examples didn't passoutput_dir, so on any machine that has codecarbon installed they wroteemissions.csvinto the check directory -- fixed by addingoutput_dir = tempdir(). -
Confirm
Authors@Rincludes a copyright holder role -- add"cph"to Beatrice Bock'srole = c(...)inDESCRIPTIONif it's onlyc("aut", "cre")currently (CRAN wants an explicit copyright holder, not just author/maintainer). Done. -
Write
cran-comments.mdat the repo root (.Rbuildignoreit if you don't want it in the built tarball, though CRAN's web form also asks for these comments directly). Cover: this is a first submission; what the package does in one line; and the Python/conda point noted above --codecarbonhas no R equivalent,setup_carbon_tracker()is opt-in/interactive/confirmed and installs into its own isolated conda environment, never touches the user's system Python, and never runs duringR CMD check(it errors intentionally in non-interactive contexts, which is what the test suite checks for). Written and.Rbuildignored. -
From R, in the package directory:
r usethis::use_version("minor") # bumps 0.0.0.9000 -> 0.1.0, tags NEWS.md devtools::check(remote = TRUE, manual = TRUE) # full local check devtools::check_win_devel() # builds on R's Windows dev servers, emails you the log urlchecker::url_check() # catches dead links in docs/README/vignetteAll three should come back clean (0 errors, 0 warnings, ideally 0 notes) before submitting.check_win_devel()in particular catches things your local machine's R version won't.Done manually rather than via `usethis::use_version()` (version was already bumped by hand). `R CMD check --as-cran` run instead of `devtools::check(remote = TRUE, manual = TRUE)` -- equivalent package-level coverage, but note it didn't check reverse dependencies (moot for a first submission with none). `urlchecker::url_check()`: all URLs OK. `check_win_devel()` submitted 2026-08-19 09:2X; results email to beabockm@gmail.com ~15-30 min later -- **check that email and address anything it flags before submitting.** Results email arrived 2026-08-19 18:53: 2 NOTEs, 0 warnings, 0 errors on R-devel/Windows. - "Possibly misspelled words in DESCRIPTION: conda (9:35)" -- false positive, `conda` isn't in the spellchecker's dictionary but is a real, correctly-spelled term. Left as-is; noted in `cran-comments.md` so it doesn't look overlooked. - `carbon_tracker_ready()` example took 13.09s (>10s threshold) -- real issue, not a flake: on a machine with no Python configured (like a fresh check server), `reticulate::py_module_available()`'s interpreter discovery alone exceeds 10s before returning `FALSE`. Fixed by wrapping the example in `\donttest{}` in `R/setup.R` and regenerating `man/carbon_tracker_ready.Rd` via `roxygen2::roxygenise()` (landed in commit `6eed5f3`, not `8ded4c5` as originally logged here -- that hash was actually the unrelated Ceres/HPC conda-discovery fix). Reverified locally with `R CMD check --as-cran` 2026-08-19: `checking examples ... OK`, no >5s flag. Resubmitted to `check_win_devel()` the same day (~14:00); results email arrived ~14:08 (server-side check took 270s): **1 NOTE, 0 warnings, 0 errors** -- only the expected "conda" spelling false-positive remains. Timing NOTE confirmed gone on a real bare check server, not just this machine. This item is done. -
Update
NEWS.md's heading from# CodeCarbonR (development version)(or0.0.0.9000) to the real version, andCITATION.cff'sversion:/date-released:to match.
Submission:
-
devtools::submit_cran()-- builds the source tarball, uploads it to CRAN's submission form, and pulls maintainer info + yourcran-comments.mdcontent into the form automatically. (Manual alternative: build withR CMD build ., then upload the resulting.tar.gzyourself at cran.r-project.org/submit.html.)First attempt (2026-08-21) was blocked by CRAN's automated incoming pretest before reaching human review -- 1 NOTE on Windows ("conda" spelling, expected/false-positive), 2 on Debian (same conda NOTE, plus a real one: `tests/testthat/test-setup.R` had "CPU time 3.4x elapsed time", traced to `carbon_tracker_ready()`'s unguarded call forcing `reticulate`'s interpreter-discovery machinery to spin up threads on a Python-less check machine). Fixed by adding `skip_on_cran()` to that one test (kept running everywhere else); `cran-comments.md` updated with a Resubmission section. No version bump -- the blocked attempt never reached a human reviewer or entered the actual queue, so standard practice doesn't call for one. Resubmitted same day, confirmation email clicked. -
(you) CRAN emails a confirmation link to the maintainer address in
DESCRIPTION-- click it. The submission doesn't enter the queue until confirmed. -
Resubmission (2026-08-24) cleared the automated incoming pretest -- "package was uploaded to CRAN" confirmation received, meaning it actually entered the processing pipeline this time rather than being blocked before human review like the first attempt.
-
Wait. CRAN's automated checks (multiple OSes/R versions) typically report back within a day or two; a human CRAN team member reviews after that. Total time is unpredictable -- same-day acceptances and multi-week back-and-forth both happen, and a package installing external software during setup (even opt-in) is exactly the kind of thing that can prompt a question rather than an immediate accept.
-
If CRAN comes back with required changes: fix them, bump the patch version again (e.g.
0.1.0->0.1.1), add a line tocran-comments.mdunder a "Resubmission" heading explaining what changed, and resubmit the same way. -
On acceptance: tag/release on GitHub if you haven't already (Section 2 above), then bump
DESCRIPTION's version to a new.9000development suffix (e.g.0.1.0.9000) so it's clearmainis past the released version.