From 94c46b7370617e286fbd21a1744ddb3c22624f65 Mon Sep 17 00:00:00 2001 From: Nic Crane Date: Mon, 13 Jul 2026 10:54:12 +0100 Subject: [PATCH 01/10] initial commit of skill --- .claude/skills/r-cran-release/SKILL.md | 377 +++++++++++++++++++++++++ 1 file changed, 377 insertions(+) create mode 100644 .claude/skills/r-cran-release/SKILL.md diff --git a/.claude/skills/r-cran-release/SKILL.md b/.claude/skills/r-cran-release/SKILL.md new file mode 100644 index 000000000000..3ac55ac962e3 --- /dev/null +++ b/.claude/skills/r-cran-release/SKILL.md @@ -0,0 +1,377 @@ +# R CRAN Release + +Guide the R package maintainer through the CRAN release process for the Apache Arrow R package. Only use this skill when explicitly doing a CRAN release. + +Use exactly this sequence of steps. Use a checklist as you go. Do not skip ahead, and ask the user to confirm step completion. + +## 1. Create GitHub Tracking Issue + +Ask the user for the release version number. + +```bash +gh issue create --repo apache/arrow \ + --title "[R] CRAN packaging checklist for version " \ + --body "$(cat r/PACKAGING.md | sed -n '/^- \[ \]/,$p')" +``` + +Track the issue number - update checkboxes as you complete each step. + +## 2. Create CRAN Release Branch + +Ask the user which RC number to use (e.g., rc1, rc2), then confirm before creating and pushing. + +```bash +git fetch upstream +git checkout apache-arrow--rc +git checkout -b maint--r +git push upstream maint--r +``` + +All subsequent steps should be done on this branch. + +## 3. Remove Badges from README + +In `r/README.md`, delete everything between `` and `` (inclusive): + +```bash +sed -i '//,//d' r/README.md +``` + +## 4. Review Deprecated Functions + +Find functions using `.Deprecated()` that may need to advance (deprecated -> defunct/removed): + +```bash +grep -rn "\.Deprecated" r/R/*.R +``` + +Review each match and decide if the deprecation should advance for this release (e.g., remove the function entirely or change to `.Defunct()`). + +## 5. Evaluate Nightly Build Status + +First, find the release candidate date: + +```bash +gh api repos/apache/arrow/releases --jq '.[] | select(.tag_name | contains("-rc")) | {tag_name, created_at}' +``` + +Then check R nightly builds were passing at that time: + +1. Go to https://github.com/ursacomputing/crossbow/actions +2. Click the "Logs" tab +3. Filter by the RC date +4. Filter by task status: failure +5. Look for any failing R jobs (jobs starting with `test-r-` or `r-`) + +All R jobs should have been passing at RC time. If any were failing, investigate whether they would cause CRAN rejection. + +For failed job logs, search: https://github.com/ursacomputing/crossbow/branches/all?query= + +## 6. Check Current CRAN Check Results + +Fetch https://cran.r-project.org/web/checks/check_results_arrow.html and extract the check results table showing platform, version, and status. Also check for any "Additional issues" section. + +All platforms should show OK or NOTE status. NOTEs about package size (e.g., "installed size is 130+ Mb") are expected due to bundled Arrow C++ and can be ignored. Other NOTEs or any ERROR/WARN should be investigated. + +## 7. Ensure README is Accurate + +Read `r/README.md` and verify: +- Installation instructions are current +- Feature descriptions match current functionality +- Version-specific notes (e.g., C++ version requirements) are correct +- No outdated information + +Report any issues found. + +## 8. Run URL Checker + +Confirm on the `maint--r` branch: + +```bash +git branch --show-current +``` + +Then run: + +```bash +cd r && Rscript -e 'urlchecker::url_check()' +``` + +All URLs should pass (badges were already removed). Fix any broken links. + +## 9. Polish NEWS + +Review `r/NEWS.md` and polish following tidyverse style: + +- Use present tense ("X now does Y", not "X did Y") +- Name contributors with `@username` if they're not a listed package author +- Use categories: "New features", "Minor improvements and fixes", "Installation" (if relevant) +- Keep entries concise - match the style of previous releases +- Only include user-facing changes - no CI updates or internal refactoring + +Find the previous version from NEWS.md: + +```bash +grep "^# arrow" r/NEWS.md | head -5 +``` + +Then find R commits since that version: + +```bash +git log --oneline apache-arrow-..HEAD | grep "\[R\]" +``` + +Do NOT update version numbers - this is done automatically later. + +Open a GitHub issue for the NEWS updates, submit a PR to main, then cherry-pick into the `maint--r` branch later. + +## 10. Cherry-pick Necessary Changes + +Check if there are any fixes that need to be cherry-picked into the `maint--r` branch: + +1. Check the comments on the release tracking issue for any noted cherry-picks +2. Ask if there are any other fixes merged to main after the RC + +Common reasons to cherry-pick: +- Fixes for CRAN check failures identified in earlier steps +- NEWS updates (from step 9) +- Critical bug fixes + +For each PR noted, get the merge commit SHA: + +```bash +gh pr view --repo apache/arrow --json mergeCommit,title --jq '{sha: .mergeCommit.oid, title: .title}' +``` + +Present the list of commits and ask for confirmation before cherry-picking. + +For each confirmed commit: + +```bash +git cherry-pick +``` + +Ask before pushing: + +```bash +git push upstream maint--r +``` + +## 11. Create Crossbow Verification PR + +Create a PR to run all R crossbow jobs against the CRAN release branch: + +```bash +gh pr create --repo apache/arrow \ + --base maint- \ + --head maint--r \ + --title "WIP: [R] Verify CRAN release " \ + --body "Do not merge: Running R crossbow jobs against the CRAN release branch." \ + --draft +``` + +Then add a comment to trigger crossbow: + +```bash +gh pr comment --repo apache/arrow --body "@github-actions crossbow submit --group r" +``` + +Add a link to this PR in the tracking issue so progress can be monitored. + +Before proceeding to CRAN submission, verify all crossbow jobs pass. + +## 12. Build and Check Package Locally + +Ensure on the `maint--r` branch with a clean working directory: + +```bash +git fetch upstream +git checkout maint--r +git clean -f -d +``` + +Check if `ARROW_HOME` is set: + +```bash +echo "ARROW_HOME=${ARROW_HOME:-}" +``` + +If set, unset it so the build uses the vendored C++ version: + +```bash +unset ARROW_HOME +``` + +Run the build (this takes a while): + +```bash +cd r && make build +``` + +After the build, check for any generated doc changes that need to be committed: + +```bash +git status +``` + +If there are modified `.Rd` files or other doc changes, commit them: + +```bash +git add r/man/ r/inst/NOTICE.txt +git commit -m "[R] Update generated documentation" +``` + +Ask before pushing. + +Then run the check: + +```r +devtools::check_built("arrow_.tar.gz") +``` + +Fix any issues before proceeding. + +## 13. Wait for Release Vote + +Check if the Apache Arrow release vote has passed before continuing. + +## 14. Update Checksums + +Download checksums for pre-compiled binaries from ASF artifactory. Ask for the libarrow version (usually matches the release version): + +```bash +cd r && Rscript tools/update-checksums.R +``` + +Then commit the checksums: + +```bash +git add -f tools/checksums/ +git commit -m "[CRAN] Add checksums" +``` + +Ask before pushing. + +## 15. Rebuild Package + +Rebuild the tarball with checksums added: + +```bash +cd r && make build +``` + +Check for any new doc changes after rebuild: + +```bash +git status +``` + +Commit any changes and ask before pushing. + +## 16. Check Binary Distributions + +Test that the package works with pre-compiled Arrow C++ binaries on different platforms. + +### Windows (win-builder) + +Upload `r/arrow_.tar.gz` to https://win-builder.r-project.org/upload.aspx (r-devel only). + +Results are emailed to Jon (the package maintainer). Ping Jon and wait for confirmation that the check is clean - no ERRORs, WARNINGs, or unexpected NOTEs. NOTEs about package size are expected. + +### macOS Builder + +Upload `r/arrow_.tar.gz` to https://mac.r-project.org/macbuilder/submit.html + +Check the results link for any issues. + +### Ubuntu Binary Installation + +Test on Ubuntu that hosted binaries are used: + +```r +install.packages("r/arrow_.tar.gz", repos = NULL) +``` + +The installation should download pre-compiled binaries rather than building from source. + +### Final Local Check + +Run one final local check: + +```r +devtools::check_built("r/arrow_.tar.gz") +``` + +## 17. Submit to CRAN + +Upload `r/arrow_.tar.gz` to https://xmpalantir.wu.ac.at/cransubmit/ + +Ping Jon to confirm the submission email when it arrives. + +## 18. Tag for r-universe + +After CRAN accepts the package: + +```bash +git tag -f r-universe-release maint--r +git push upstream r-universe-release --force +``` + +## 19. Update Backwards Compatibility Matrix + +Add a new line to `dev/tasks/r/github.linux.arrow.version.back.compat.yml` with the new version. + +Create a PR to main for this change. + +## 20. Wait for CRAN Binaries + +Monitor https://cran.r-project.org/package=arrow until CRAN-hosted binaries reflect the new version. + +## 21. Prepare Social Media Content (Major Releases) + +For major releases, prepare content for social media highlighting new features. + +Format (thread of toots): +1. Opening: "We're excited to announce the release of {arrow} . Here's a roundup of the new features and changes. Full details can be found at https://arrow.apache.org/docs/r/news/ #rstats" +2. Feature highlights: One toot per major user-facing feature, with code screenshots from https://carbon.now.sh/ where appropriate. Skip minor fixes and CI/internal changes. +3. Contributor stats: Total contributors, C++ only, R only, both, first-timers. + +To generate contributor stats, run from the arrow repo root: + +```r +source("r/tools/contributor_stats.R") +release_contributor_stats("apache-arrow-", "apache-arrow-") +``` + +## 22. Patch Releases Only: Update Version Numbers + +For patch releases (e.g., X.Y.1), update the version in: +- `ci/scripts/PKGBUILD` +- `r/DESCRIPTION` +- `r/NEWS.md` + +## 23. CRAN-Only Releases: Update Documentation + +For CRAN-only releases (no corresponding Arrow release): + +Rebuild news page: + +```r +pkgdown::build_news() +``` + +Submit a PR to the `asf-site` branch of https://github.com/apache/arrow-site with contents of `arrow/r/docs/news/index.html` replacing `arrow-site/docs/r/news/index.html`. + +Bump the version in `r/pkgdown/assets/versions.json` and update on the `asf-site` branch too. + +## 24. Check C++ Updates + +Review C++ changes in this release and create GitHub issues for any items that need R bindings: + +```bash +git log --oneline apache-arrow-..apache-arrow- -- cpp/ | head -50 +``` + +## 25. Review Checklist + +Review this packaging checklist and update as needed based on any issues encountered during this release. From 50cc8116e5daf6168b696d28cb78d98e5f084d6d Mon Sep 17 00:00:00 2001 From: Nic Crane Date: Mon, 13 Jul 2026 12:07:12 +0100 Subject: [PATCH 02/10] Update release skill Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/skills/r-cran-release/SKILL.md | 30 ++++++++------------------ dev/release/rat_exclude_files.txt | 1 + r/PACKAGING.md | 6 ------ 3 files changed, 10 insertions(+), 27 deletions(-) diff --git a/.claude/skills/r-cran-release/SKILL.md b/.claude/skills/r-cran-release/SKILL.md index 3ac55ac962e3..7c79569506ad 100644 --- a/.claude/skills/r-cran-release/SKILL.md +++ b/.claude/skills/r-cran-release/SKILL.md @@ -2,7 +2,9 @@ Guide the R package maintainer through the CRAN release process for the Apache Arrow R package. Only use this skill when explicitly doing a CRAN release. -Use exactly this sequence of steps. Use a checklist as you go. Do not skip ahead, and ask the user to confirm step completion. +Use exactly this sequence of steps. Print a checklist of all steps at the start, and update it as you go. Do not skip ahead. After completing each step, ask the user to confirm before moving on. Once confirmed, update the corresponding checkbox on the tracking issue. Use exactly the commands and approaches specified in each step — do not improvise or substitute alternatives without checking with the user. + +If any earlier step reveals something that needs to be cherry-picked into the release branch, note it as a comment on the tracking issue. When you reach the cherry-pick step later, check the tracking issue comments for anything noted earlier. ## 1. Create GitHub Tracking Issue @@ -37,6 +39,8 @@ In `r/README.md`, delete everything between `` and `/,//d' r/README.md ``` +Commit this change to the `maint--r` branch. + ## 4. Review Deprecated Functions Find functions using `.Deprecated()` that may need to advance (deprecated -> defunct/removed): @@ -49,23 +53,7 @@ Review each match and decide if the deprecation should advance for this release ## 5. Evaluate Nightly Build Status -First, find the release candidate date: - -```bash -gh api repos/apache/arrow/releases --jq '.[] | select(.tag_name | contains("-rc")) | {tag_name, created_at}' -``` - -Then check R nightly builds were passing at that time: - -1. Go to https://github.com/ursacomputing/crossbow/actions -2. Click the "Logs" tab -3. Filter by the RC date -4. Filter by task status: failure -5. Look for any failing R jobs (jobs starting with `test-r-` or `r-`) - -All R jobs should have been passing at RC time. If any were failing, investigate whether they would cause CRAN rejection. - -For failed job logs, search: https://github.com/ursacomputing/crossbow/branches/all?query= +Ask the user to check that R nightly builds were passing around RC time. They can check on Zulip or at https://crossbow.arrow-dev.org/ ## 6. Check Current CRAN Check Results @@ -101,10 +89,10 @@ All URLs should pass (badges were already removed). Fix any broken links. ## 9. Polish NEWS -Review `r/NEWS.md` and polish following tidyverse style: +Review `r/NEWS.md` and polish following tidyverse style (see https://style.tidyverse.org/news.html): - Use present tense ("X now does Y", not "X did Y") -- Name contributors with `@username` if they're not a listed package author +- Name contributors with `@username` if they're not a listed package author. Listed authors (do not credit): @nealrichardson, @ianmcook, @thisisnic, @paleolimbot, @romainfrancois, @jkeane, @brycemecum, @dragosmg, @jeroenooms, @assignUser - Use categories: "New features", "Minor improvements and fixes", "Installation" (if relevant) - Keep entries concise - match the style of previous releases - Only include user-facing changes - no CI updates or internal refactoring @@ -123,7 +111,7 @@ git log --oneline apache-arrow-..HEAD | grep "\[R\]" Do NOT update version numbers - this is done automatically later. -Open a GitHub issue for the NEWS updates, submit a PR to main, then cherry-pick into the `maint--r` branch later. +Open a GitHub issue for the NEWS updates, submit a PR to main from a branch on the fork (origin, not upstream), then cherry-pick into the `maint--r` branch later. ## 10. Cherry-pick Necessary Changes diff --git a/dev/release/rat_exclude_files.txt b/dev/release/rat_exclude_files.txt index 7b3f9eebe582..db74b8066b80 100644 --- a/dev/release/rat_exclude_files.txt +++ b/dev/release/rat_exclude_files.txt @@ -103,3 +103,4 @@ ruby/red-arrow/.yardopts ruby/red-arrow-format/lib/arrow-format/org/* .github/copilot-instructions.md .github/pull_request_template.md +.claude/* diff --git a/r/PACKAGING.md b/r/PACKAGING.md index 80da15619194..67bb32747755 100644 --- a/r/PACKAGING.md +++ b/r/PACKAGING.md @@ -40,12 +40,6 @@ _Wait for the release candidate to be created._ - [ ] Create a CRAN-release branch from the release candidate commit, name the new branch `maint-X.Y.Z-r` and push to upstream. -## Prepare and Check Package That Will Be Released to CRAN - -- [ ] `git fetch upstream && git checkout maint-X.Y.Z-r && git clean -f -d`. -- [ ] Run `make build`. This copies Arrow C++ into tools/cpp, prunes some unnecessary components, and runs `R CMD build` to generate the source tarball. Because this will install the package, you will need to ensure that the version of Arrow C++ available to the configure script is the same as the version that is vendored into the R package (e.g., you may need to unset `ARROW_HOME`). -- [ ] `devtools::check_built("arrow_X.Y.Z.tar.gz")` locally. - ## Wait for Arrow Release Vote - [ ] Release vote passed From f31580efe5c57bf16a8f25c34aa82081731f1997 Mon Sep 17 00:00:00 2001 From: Nic Crane Date: Mon, 20 Jul 2026 12:00:20 -0400 Subject: [PATCH 03/10] Apply suggestion from @thisisnic --- .claude/skills/r-cran-release/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.claude/skills/r-cran-release/SKILL.md b/.claude/skills/r-cran-release/SKILL.md index 7c79569506ad..868759bc6256 100644 --- a/.claude/skills/r-cran-release/SKILL.md +++ b/.claude/skills/r-cran-release/SKILL.md @@ -307,7 +307,7 @@ git push upstream r-universe-release --force ## 19. Update Backwards Compatibility Matrix -Add a new line to `dev/tasks/r/github.linux.arrow.version.back.compat.yml` with the new version. +Add a new line to `dev/tasks/r/github.linux.arrow.version.back.compat.yml` with the previous version. Create a PR to main for this change. From ce896164646a51f9f1b24a1df38655c65129df8e Mon Sep 17 00:00:00 2001 From: Nic Crane Date: Tue, 18 Aug 2026 13:02:32 +0100 Subject: [PATCH 04/10] Add contributor stats script --- .claude/skills/r-cran-release/SKILL.md | 23 +++-- r/PACKAGING.md | 2 +- r/tools/contributor_stats.R | 127 +++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 7 deletions(-) create mode 100644 r/tools/contributor_stats.R diff --git a/.claude/skills/r-cran-release/SKILL.md b/.claude/skills/r-cran-release/SKILL.md index 868759bc6256..4d1c3bc76d99 100644 --- a/.claude/skills/r-cran-release/SKILL.md +++ b/.claude/skills/r-cran-release/SKILL.md @@ -260,19 +260,19 @@ Commit any changes and ask before pushing. Test that the package works with pre-compiled Arrow C++ binaries on different platforms. -### Windows (win-builder) +### 16.1 Windows (win-builder) Upload `r/arrow_.tar.gz` to https://win-builder.r-project.org/upload.aspx (r-devel only). Results are emailed to Jon (the package maintainer). Ping Jon and wait for confirmation that the check is clean - no ERRORs, WARNINGs, or unexpected NOTEs. NOTEs about package size are expected. -### macOS Builder +### 16.2 macOS Builder Upload `r/arrow_.tar.gz` to https://mac.r-project.org/macbuilder/submit.html Check the results link for any issues. -### Ubuntu Binary Installation +### 16.3 Ubuntu Binary Installation Test on Ubuntu that hosted binaries are used: @@ -282,7 +282,7 @@ install.packages("r/arrow_.tar.gz", repos = NULL) The installation should download pre-compiled binaries rather than building from source. -### Final Local Check +### 16.4 Final Local Check Run one final local check: @@ -345,12 +345,23 @@ For CRAN-only releases (no corresponding Arrow release): Rebuild news page: ```r -pkgdown::build_news() +pkgdown::build_news("./r") ``` Submit a PR to the `asf-site` branch of https://github.com/apache/arrow-site with contents of `arrow/r/docs/news/index.html` replacing `arrow-site/docs/r/news/index.html`. -Bump the version in `r/pkgdown/assets/versions.json` and update on the `asf-site` branch too. +```bash +cd ~/arrow-site +git fetch upstream +git checkout upstream/asf-site +git checkout -b "r-25.0.0" +cp ~/arrow/r/docs/news/index.html ./docs/r/news/index.html +git add docs/r/news/index.html +git commit -m "update R news page" +git push --set-upstream origin r-25.0.0 +``` + +If necessary, bump the version in `r/pkgdown/assets/versions.json` too. ## 24. Check C++ Updates diff --git a/r/PACKAGING.md b/r/PACKAGING.md index 67bb32747755..0de598f3ff5f 100644 --- a/r/PACKAGING.md +++ b/r/PACKAGING.md @@ -80,5 +80,5 @@ _This step must be done by the current package maintainer._ - [ ] Review the packaging checklist template and update as needed. - [ ] Wait for CRAN-hosted binaries on the [CRAN package page](https://cran.r-project.org/package=arrow) to reflect the new version. - [ ] Post already-prepared content to social media. - - Use Bryce's [script](https://gist.githubusercontent.com/amoeba/4e26c064d1a0d0227cd8c2260cf0072a/raw/bc0d983152bdde4820de9074d4caee9986624bc5/new_contributors.R) for contributor calculation. + - Use `r/tools/contributor_stats.R` (`release_contributor_stats()`) for contributor calculation. - [ ] Check C++ updates for this release and create issues for any items which need bindings in R diff --git a/r/tools/contributor_stats.R b/r/tools/contributor_stats.R new file mode 100644 index 000000000000..597f446422ff --- /dev/null +++ b/r/tools/contributor_stats.R @@ -0,0 +1,127 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Contributor statistics for release announcements. +# +# The `print_new_contributors()` helper below is copied from Bryce Mecum's gist: +# https://gist.github.com/amoeba/4e26c064d1a0d0227cd8c2260cf0072a +# +# Usage: launch R from the root of the arrow git repo, then: +# +# source("r/tools/contributor_stats.R") +# release_contributor_stats("apache-arrow-20.0.0", "apache-arrow-21.0.0") +# +# or, for just the list of first-time contributors to a subdirectory: +# +# print_new_contributors("apache-arrow-20.0.0", "apache-arrow-21.0.0", "r") + +#' new_contributors.R +#' +#' Produce a list of names of new contributors between two git refs. The method +#' this uses is to first get the list of unique contrbutors referancable from +#' the first ref, then the second ref, and then compute the set difference and +#' return that. +#' +#' Usage +#' +#' Launch an R session from the directory containing the git repo you want to +#' query against. +#' +#' Run this to get a list of new contributors between the refs +#' "apache-arrow-13.0.0" and "apache-arrow-14.0.0" for commits that touched +#' the "r" subdirectory": +# +#' print_new_contributors( +#' "apache-arrow-13.0.0", +#' "apache-arrow-14.0.0", +#' "r" +#' ) +#' +#' Note that the third argument, subdirectory, is optional. If omitted, it +#' will use the root directory. + +stopunlesscommand <- function(command, arguments) { + out <- tryCatch( + { + system2("git", arguments, stdout = TRUE) + }, + warning = function(w) { + stop(w) + }, + error = function(e) { + stop(e) + } + ) + + TRUE +} + +stopfinotinrepo <- function() { + stopunlesscommand("git", "reflog main") +} + +stopifnotref <- function(ref) { + stopifnot(is.character(ref)) + stopifnot(nchar(ref) > 0) + stopunlesscommand("git", paste("reflog", ref)) +} + +make_git_log_prev_args <- function(ref_from, subdirectory) { + paste0("log --pretty='format: %an' ", ref_from, " ", subdirectory, " | sort | uniq") +} + +make_git_log_next_args <- function(ref_from, ref_to, subdirectory) { + paste0("log --pretty='format: %an' ", ref_from, "..", ref_to, " ", subdirectory, " | sort | uniq") +} + +print_new_contributors <- function(ref_from, ref_to, subdirectory = ".") { + stopfinotinrepo() + stopifnotref(ref_from) + stopifnotref(ref_to) + stopifnot(file.exists(subdirectory)) + + prev_out <- trimws(system2("git", make_git_log_prev_args(ref_from, subdirectory), stdout = TRUE)) + new_out <- trimws(system2("git", make_git_log_next_args(ref_from, ref_to, subdirectory), stdout = TRUE)) + + setdiff(new_out, prev_out) +} + +# Contributors (author names) to `subdirectory` between two refs +contributors_between <- function(ref_from, ref_to, subdirectory = ".") { + trimws(system2("git", make_git_log_next_args(ref_from, ref_to, subdirectory), stdout = TRUE)) +} + +# Summary stats for the release announcement: total contributors, and how +# many touched only C++, only R, or both, plus first-time contributors. +release_contributor_stats <- function(ref_from, ref_to) { + stopfinotinrepo() + stopifnotref(ref_from) + stopifnotref(ref_to) + + all_contribs <- contributors_between(ref_from, ref_to) + cpp_contribs <- contributors_between(ref_from, ref_to, "cpp") + r_contribs <- contributors_between(ref_from, ref_to, "r") + + list( + total = length(all_contribs), + cpp_only = length(setdiff(cpp_contribs, r_contribs)), + r_only = length(setdiff(r_contribs, cpp_contribs)), + both = length(intersect(cpp_contribs, r_contribs)), + first_timers = print_new_contributors(ref_from, ref_to), + first_timers_r = print_new_contributors(ref_from, ref_to, "r") + ) +} From 5245400e651fda54d0f6d824f98fee6f337670ae Mon Sep 17 00:00:00 2001 From: Nic Crane Date: Tue, 18 Aug 2026 13:06:19 +0100 Subject: [PATCH 05/10] Preserve ref to unsetting ARROW_HOME --- r/PACKAGING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/r/PACKAGING.md b/r/PACKAGING.md index 0de598f3ff5f..3dbe9c2d375b 100644 --- a/r/PACKAGING.md +++ b/r/PACKAGING.md @@ -22,6 +22,8 @@ For a high-level overview of the Arrow release process see the [Apache Arrow Release Management Guide](https://arrow.apache.org/docs/developers/release.html#post-release-tasks). +This checklist is also available as a Claude Code skill at [`.claude/skills/r-cran-release/SKILL.md`](../.claude/skills/r-cran-release/SKILL.md), which walks through the same steps in more detail. + ## Before the Arrow Release Candidate Is Created - [ ] [Create a GitHub issue](https://github.com/apache/arrow/issues/new/) entitled `[R] CRAN packaging checklist for version X.Y.Z` and copy this checklist to the issue. @@ -53,7 +55,7 @@ _Wait for the release candidate to be created._ - [ ] Create a PR entitled `WIP: [R] Verify CRAN release-X.Y.Z-rcX`. Add a comment `@github-actions crossbow submit --group r` to run all R crossbow jobs against the CRAN-specific release branch. - [ ] Run `Rscript tools/update-checksums.R ` to download the checksums for the pre-compiled binaries from the ASF artifactory into the tools directory. - [ ] Commit the checksums: `git add -f tools/checksums/ && git commit -m "[CRAN] Add checksums"` -- [ ] Regenerate arrow_X.Y.Z.tar.gz (i.e., `make build`). This will clean old artifacts, regenerate documentation, sync C++ files, and build the package. +- [ ] Regenerate arrow_X.Y.Z.tar.gz (i.e., `make build`). This will clean old artifacts, regenerate documentation, sync C++ files, and build the package. Because this will install the package, you will need to ensure that the version of Arrow C++ available to the configure script is the same as the version that is vendored into the R package (e.g., you may need to unset `ARROW_HOME`). ## Check Binary Arrow C++ Distributions Specific to the R Package From abeb66613451127e316a1ccbd43a3316a86e69ae Mon Sep 17 00:00:00 2001 From: Nic Crane Date: Thu, 3 Sep 2026 15:23:38 +0100 Subject: [PATCH 06/10] Never push, always ask user --- .claude/skills/r-cran-release/SKILL.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.claude/skills/r-cran-release/SKILL.md b/.claude/skills/r-cran-release/SKILL.md index 4d1c3bc76d99..7dd392df1771 100644 --- a/.claude/skills/r-cran-release/SKILL.md +++ b/.claude/skills/r-cran-release/SKILL.md @@ -4,6 +4,8 @@ Guide the R package maintainer through the CRAN release process for the Apache A Use exactly this sequence of steps. Print a checklist of all steps at the start, and update it as you go. Do not skip ahead. After completing each step, ask the user to confirm before moving on. Once confirmed, update the corresponding checkbox on the tracking issue. Use exactly the commands and approaches specified in each step — do not improvise or substitute alternatives without checking with the user. +Never run `git push` yourself, under any circumstances. Whenever a step requires pushing, show the user the exact command to run and wait for them to confirm they have pushed before continuing. The `git push` commands in this file are for the user to run, not you. + If any earlier step reveals something that needs to be cherry-picked into the release branch, note it as a comment on the tracking issue. When you reach the cherry-pick step later, check the tracking issue comments for anything noted earlier. ## 1. Create GitHub Tracking Issue @@ -20,7 +22,7 @@ Track the issue number - update checkboxes as you complete each step. ## 2. Create CRAN Release Branch -Ask the user which RC number to use (e.g., rc1, rc2), then confirm before creating and pushing. +Ask the user which RC number to use (e.g., rc1, rc2), then confirm before creating the branch. Ask the user to run the push command themselves. ```bash git fetch upstream @@ -139,7 +141,7 @@ For each confirmed commit: git cherry-pick ``` -Ask before pushing: +Ask the user to push: ```bash git push upstream maint--r @@ -209,7 +211,7 @@ git add r/man/ r/inst/NOTICE.txt git commit -m "[R] Update generated documentation" ``` -Ask before pushing. +Ask the user to push. Then run the check: @@ -238,7 +240,7 @@ git add -f tools/checksums/ git commit -m "[CRAN] Add checksums" ``` -Ask before pushing. +Ask the user to push. ## 15. Rebuild Package @@ -254,7 +256,7 @@ Check for any new doc changes after rebuild: git status ``` -Commit any changes and ask before pushing. +Commit any changes and ask the user to push. ## 16. Check Binary Distributions @@ -298,7 +300,7 @@ Ping Jon to confirm the submission email when it arrives. ## 18. Tag for r-universe -After CRAN accepts the package: +After CRAN accepts the package, ask the user to run: ```bash git tag -f r-universe-release maint--r @@ -348,7 +350,7 @@ Rebuild news page: pkgdown::build_news("./r") ``` -Submit a PR to the `asf-site` branch of https://github.com/apache/arrow-site with contents of `arrow/r/docs/news/index.html` replacing `arrow-site/docs/r/news/index.html`. +Submit a PR to the `asf-site` branch of https://github.com/apache/arrow-site with contents of `arrow/r/docs/news/index.html` replacing `arrow-site/docs/r/news/index.html`. Ask the user to run the final push command. ```bash cd ~/arrow-site From 6ec153c8f31af62fa465a480c5d5fb8b88481695 Mon Sep 17 00:00:00 2001 From: Nic Crane Date: Thu, 3 Sep 2026 15:25:18 +0100 Subject: [PATCH 07/10] Check in re the release vote --- .claude/skills/r-cran-release/SKILL.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/.claude/skills/r-cran-release/SKILL.md b/.claude/skills/r-cran-release/SKILL.md index 7dd392df1771..0604052f4071 100644 --- a/.claude/skills/r-cran-release/SKILL.md +++ b/.claude/skills/r-cran-release/SKILL.md @@ -22,11 +22,28 @@ Track the issue number - update checkboxes as you complete each step. ## 2. Create CRAN Release Branch -Ask the user which RC number to use (e.g., rc1, rc2), then confirm before creating the branch. Ask the user to run the push command themselves. +First check whether the final release tag exists: + +```bash +git fetch upstream --tags +git tag -l 'apache-arrow-*' +``` + +If `apache-arrow-` (no rc suffix) exists, the vote has already passed. Always branch from the final tag in this case — do not ask about RCs, as an earlier RC may be a different commit from the final release: + +```bash +git checkout apache-arrow- +``` + +Only if the final tag does not exist yet (vote still in progress), ask the user which RC number to use (e.g., rc1, rc2), then branch from it: ```bash -git fetch upstream git checkout apache-arrow--rc +``` + +Confirm with the user before creating the branch, then ask them to run the push command themselves: + +```bash git checkout -b maint--r git push upstream maint--r ``` @@ -223,7 +240,7 @@ Fix any issues before proceeding. ## 13. Wait for Release Vote -Check if the Apache Arrow release vote has passed before continuing. +Check if the Apache Arrow release vote has passed before continuing. If the release branch was created from the final `apache-arrow-` tag in step 2, the vote has already passed and this step is a no-op. ## 14. Update Checksums From fcc12e6fb5a7fbb30f54d20befbc025e88cdc4a7 Mon Sep 17 00:00:00 2001 From: Nic Crane Date: Thu, 3 Sep 2026 15:27:22 +0100 Subject: [PATCH 08/10] Don't harcode version --- .claude/skills/r-cran-release/SKILL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.claude/skills/r-cran-release/SKILL.md b/.claude/skills/r-cran-release/SKILL.md index 0604052f4071..4b1ee872e0f7 100644 --- a/.claude/skills/r-cran-release/SKILL.md +++ b/.claude/skills/r-cran-release/SKILL.md @@ -373,11 +373,11 @@ Submit a PR to the `asf-site` branch of https://github.com/apache/arrow-site wit cd ~/arrow-site git fetch upstream git checkout upstream/asf-site -git checkout -b "r-25.0.0" +git checkout -b "r-" cp ~/arrow/r/docs/news/index.html ./docs/r/news/index.html git add docs/r/news/index.html git commit -m "update R news page" -git push --set-upstream origin r-25.0.0 +git push --set-upstream origin r- ``` If necessary, bump the version in `r/pkgdown/assets/versions.json` too. From 8562573ee00266d02a9cdc946d6af3e76097efff Mon Sep 17 00:00:00 2001 From: Nic Crane Date: Thu, 3 Sep 2026 15:55:03 +0100 Subject: [PATCH 09/10] Tweak contirbutor script --- r/tools/contributor_stats.R | 96 ++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 56 deletions(-) diff --git a/r/tools/contributor_stats.R b/r/tools/contributor_stats.R index 597f446422ff..975740e065bf 100644 --- a/r/tools/contributor_stats.R +++ b/r/tools/contributor_stats.R @@ -17,7 +17,7 @@ # Contributor statistics for release announcements. # -# The `print_new_contributors()` helper below is copied from Bryce Mecum's gist: +# The `print_new_contributors()` helper below is adapted from Bryce Mecum's gist: # https://gist.github.com/amoeba/4e26c064d1a0d0227cd8c2260cf0072a # # Usage: launch R from the root of the arrow git repo, then: @@ -29,86 +29,70 @@ # # print_new_contributors("apache-arrow-20.0.0", "apache-arrow-21.0.0", "r") -#' new_contributors.R -#' -#' Produce a list of names of new contributors between two git refs. The method -#' this uses is to first get the list of unique contrbutors referancable from -#' the first ref, then the second ref, and then compute the set difference and -#' return that. -#' -#' Usage -#' -#' Launch an R session from the directory containing the git repo you want to -#' query against. -#' -#' Run this to get a list of new contributors between the refs -#' "apache-arrow-13.0.0" and "apache-arrow-14.0.0" for commits that touched -#' the "r" subdirectory": -# -#' print_new_contributors( -#' "apache-arrow-13.0.0", -#' "apache-arrow-14.0.0", -#' "r" -#' ) -#' -#' Note that the third argument, subdirectory, is optional. If omitted, it -#' will use the root directory. - -stopunlesscommand <- function(command, arguments) { - out <- tryCatch( - { - system2("git", arguments, stdout = TRUE) - }, - warning = function(w) { - stop(w) - }, - error = function(e) { - stop(e) - } - ) - - TRUE +# Run a git command, erroring if it fails. Returns stdout as a character vector. +git <- function(...) { + out <- suppressWarnings(system2("git", c(...), stdout = TRUE, stderr = TRUE)) + status <- attr(out, "status") + if (!is.null(status) && status != 0) { + stop("git ", paste(c(...), collapse = " "), " failed:\n", paste(out, collapse = "\n")) + } + as.character(out) } -stopfinotinrepo <- function() { - stopunlesscommand("git", "reflog main") +stopifnotinrepo <- function() { + git("rev-parse", "--is-inside-work-tree") + invisible(TRUE) } stopifnotref <- function(ref) { - stopifnot(is.character(ref)) - stopifnot(nchar(ref) > 0) - stopunlesscommand("git", paste("reflog", ref)) -} - -make_git_log_prev_args <- function(ref_from, subdirectory) { - paste0("log --pretty='format: %an' ", ref_from, " ", subdirectory, " | sort | uniq") + stopifnot(is.character(ref), length(ref) == 1, nchar(ref) > 0) + status <- system2( + "git", + c("rev-parse", "--verify", "--quiet", paste0(ref, "^{commit}")), + stdout = FALSE, + stderr = FALSE + ) + if (status != 0) { + stop( + "'", + ref, + "' is not a git ref in this repo. Release tags look like ", + "'apache-arrow-", + sub("^apache-arrow-", "", ref), + "'." + ) + } + invisible(TRUE) } -make_git_log_next_args <- function(ref_from, ref_to, subdirectory) { - paste0("log --pretty='format: %an' ", ref_from, "..", ref_to, " ", subdirectory, " | sort | uniq") +# Unique author names for commits in `revision_range` that touched `subdirectory` +git_authors <- function(revision_range, subdirectory) { + sort(unique(trimws(git("log", "--pretty=format:%an", revision_range, "--", subdirectory)))) } +# Contributors to `subdirectory` between `ref_from` and `ref_to` with no +# commits reachable from `ref_from`, i.e. first-time contributors in that range. print_new_contributors <- function(ref_from, ref_to, subdirectory = ".") { - stopfinotinrepo() + stopifnotinrepo() stopifnotref(ref_from) stopifnotref(ref_to) stopifnot(file.exists(subdirectory)) - prev_out <- trimws(system2("git", make_git_log_prev_args(ref_from, subdirectory), stdout = TRUE)) - new_out <- trimws(system2("git", make_git_log_next_args(ref_from, ref_to, subdirectory), stdout = TRUE)) + prev_out <- git_authors(ref_from, subdirectory) + new_out <- git_authors(paste0(ref_from, "..", ref_to), subdirectory) setdiff(new_out, prev_out) } # Contributors (author names) to `subdirectory` between two refs contributors_between <- function(ref_from, ref_to, subdirectory = ".") { - trimws(system2("git", make_git_log_next_args(ref_from, ref_to, subdirectory), stdout = TRUE)) + git_authors(paste0(ref_from, "..", ref_to), subdirectory) } # Summary stats for the release announcement: total contributors, and how # many touched only C++, only R, or both, plus first-time contributors. release_contributor_stats <- function(ref_from, ref_to) { - stopfinotinrepo() + stopifnotinrepo() stopifnotref(ref_from) stopifnotref(ref_to) From c6624d07d538d80ec0ca2b790b5e2a0a137540df Mon Sep 17 00:00:00 2001 From: Nic Crane Date: Thu, 3 Sep 2026 15:57:17 +0100 Subject: [PATCH 10/10] Mkae portable --- .claude/skills/r-cran-release/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.claude/skills/r-cran-release/SKILL.md b/.claude/skills/r-cran-release/SKILL.md index 4b1ee872e0f7..8c5329e7836d 100644 --- a/.claude/skills/r-cran-release/SKILL.md +++ b/.claude/skills/r-cran-release/SKILL.md @@ -55,7 +55,7 @@ All subsequent steps should be done on this branch. In `r/README.md`, delete everything between `` and `` (inclusive): ```bash -sed -i '//,//d' r/README.md +sed -i.bak '//,//d' r/README.md && rm r/README.md.bak ``` Commit this change to the `maint--r` branch.