22  Liberando a CRAN

Hemos estado señalando inquietudes específicas de CRAN a lo largo del libro, en nuestro recorrido por las distintas partes de un paquete, como pruebas y ejemplos. En este capítulo, nos centramos en el proceso real de publicar un paquete en CRAN, por primera vez o como una actualización.

La expresión más concreta de nuestro proceso de lanzamiento es la lista de verificación producida por usethis::use_release_issue(), que abre una edición de GitHub que contiene una lista de tareas pendientes. Esta lista de verificación evoluciona constantemente y responde a algunas características del paquete, así que no se sorprenda si ve algo un poco diferente de lo que mostramos aquí. Las preocupaciones principales son bastante eternas y usaremos esta lista de verificación para ayudar a estructurar este capítulo.

Pero primero: tenga en cuenta que se arrepentirá profundamente si aborda la preparación de su paquete para CRAN como una actividad separada que realiza después de completar el desarrollo planificado para una versión. Este consejo es extremadamente relevante aquí:

Si te duele, hazlo con más frecuencia. – Martin Fowler1

En el contexto actual, interprete que esto significa que debe ejecutar R CMD check con regularidad, preferiblemente en múltiples plataformas, y abordar rápidamente cualquier problema que surja. Recuerde que nuestra forma preferida de hacer esto es a través de devtools::check() (Sección 4.5).

¿Por qué querrías hacer algo que te resulta doloroso con más frecuencia? Porque conduce a menos dolor en general. Primero, resolver 5 problemas es más de 5 veces más difícil que resolver 1. Es desmoralizador verse bloqueado por varios errores y la posibilidad de que se produzcan interacciones desagradables entre ellos hace que cada uno de ellos sea más difícil de aislar y corregir. En segundo lugar, la retroalimentación rápida tiende a reducir el número total de errores. Una vez que aprenda alguna lección de la manera más difícil, es poco probable que cometa el mismo error docenas de veces en otras partes de su paquete. ¡Finalmente, la práctica hace la perfección! Con una mayor exposición, mejorará en la interpretación y respuesta a los problemas que surjan en R CMD check.

Otra reacción natural es: ¿por qué no elimino este dolor por completo al no publicar mi paquete en CRAN? Para ciertos tipos de paquetes, esta puede ser la decisión correcta. Un ejemplo de ello es un paquete personal de funciones auxiliares. Otro ejemplo es un paquete que admite una organización específica, siempre que también tenga un método razonable para distribuir ese paquete a sus usuarios. La razón principal para tener su paquete en CRAN es darle mayor alcance. La gran mayoría de los usuarios de R sólo instalan paquetes de CRAN, ya sea por política personal o de la empresa o simplemente por falta de conocimiento sobre las alternativas. CRAN proporciona visibilidad, facilidad de instalación y un sello de autenticidad. El proceso de envío de CRAN puede ser frustrante, pero tiene muchas ventajas y este capítulo pretende hacerlo lo más sencillo posible.

El proceso de liberación que describimos aquí se utiliza mejor como una lista de verificación previa al vuelo, que complementa sus esfuerzos continuos para mantener su paquete pasando la R CMD check de manera limpia y compatible con CRAN. Hay dos grandes descubrimientos que a menudo surgen con el proceso de lanzamiento de CRAN:

Estos son los pasos principales en el proceso de liberación:

  1. Determine el tipo de versión, que dicta el número de versión.
  2. Si el paquete ya está en CRAN: realice la debida diligencia sobre los resultados de CRAN existentes. Si se trata de una primera versión: confirme que cumple con las políticas de CRAN.
  3. Actualice los archivos de documentación, como README.md y NEWS.md.
  4. Doble check() para que su paquete se transmita limpiamente en múltiples sistemas operativos y en la versión publicada y en desarrollo de R.
  5. Realice comprobaciones de dependencia inversa, si otros paquetes dependen del suyo.
  6. Envíe el paquete a CRAN y espere la aceptación.
  7. Cree una versión de GitHub y prepárese para la próxima versión incrementando el número de versión.
  8. Publicitar la nueva versión.

22.1 Decidir el tipo de lanzamiento

Cuando llame a use_release_issue(), se le preguntará qué tipo de lanzamiento desea realizar.

> use_release_issue()
✔ Setting active project to '/Users/jenny/rrr/usethis'
Current version is 2.1.6.9000.
What should the release version be? (0 to exit) 

1: major --> 3.0.0
2: minor --> 2.2.0
3: patch --> 2.1.7

Selection: 

La pregunta inmediata parece bastante mecánica: ¿qué componente del número de versión desea incrementar? Pero recuerde que analizamos las diferencias sustanciales en los tipos de lanzamiento en Sección 21.5.

En nuestro flujo de trabajo, este número de versión planificada se registra en la edición de GitHub que contiene la lista de verificación de lanzamiento, pero en realidad no incrementamos la versión en DESCRIPTION hasta más adelante en el proceso (Sección 22.7). Sin embargo, es importante declarar el tipo de versión por adelantado, porque el proceso (y, por lo tanto, la lista de verificación) se ve diferente, por ejemplo, para una versión de parche versus una versión principal.

22.2 Lanzamiento inicial de CRAN: consideraciones especiales

Cada nuevo paquete recibe un mayor nivel de escrutinio por parte de CRAN. Además de las habituales comprobaciones automatizadas, los nuevos paquetes también son revisados por un humano, lo que inevitablemente introduce cierta subjetividad y aleatoriedad. Hay muchos paquetes en CRAN que no serían aceptados en su forma actual si se presentaran hoy como un paquete completamente nuevo. Esto no pretende desanimarte. Pero debe tener en cuenta que, sólo porque vea algo de práctica en un paquete establecido (o incluso en base R), no significa que pueda hacer lo mismo en su nuevo paquete.

Afortunadamente, la comunidad mantiene listas de “errores” comunes para los nuevos paquetes. Si su paquete aún no está en CRAN, la lista de verificación comienza con una sección especial que refleja esta sabiduría colectiva reciente. Prestar atención a estos elementos de la lista de verificación ha mejorado drásticamente la tasa de éxito de nuestro equipo en los envíos iniciales.

Primer lanzamiento

Si aún no tiene un archivo NEWS.md, le recomendamos que cree uno ahora con usethis::use_news_md(). Eventualmente querrás este archivo y esto anticipa el hecho de que la descripción de tu eventual versión de GitHub (Sección 22.9) se extrae de NEWS.md.

usethis::use_cran_comments() inicia un archivo para contener los comentarios de envío de su paquete. Al principio es muy básico, por ejemplo:

## R CMD check results

0 errors | 0 warnings | 1 note

* This is a new release.

En versiones posteriores, este archivo deja de tener sentido; por ejemplo, es donde informamos los resultados de las comprobaciones de dependencia inversa. Este no es un lugar para extenderse con largas explicaciones sobre su envío. En general, debería eliminar la necesidad de tales explicaciones, especialmente para una presentación inicial.

Recomendamos encarecidamente que su paquete tenga un archivo README (Sección 18.1). Si es así, este es un buen momento para consultar las instrucciones de instalación que se proporcionan allí. Es posible que deba cambiar las instrucciones para instalarlo desde GitHub a instalarlo desde CRAN, en anticipación a la aceptación de su paquete.

Los campos Title y Description de DESCRIPTION son verdaderos puntos críticos durante la revisión humana de CRAN. Revise detenidamente los consejos proporcionados en Sección 9.2. Compruebe también que Authors@R incluya un titular de derechos de autor, indicado por la función ‘cph’. Los dos escenarios más comunes son que agrega ‘cph’ a sus otros roles (probablemente ‘cre’ y ‘aut’) o que agrega su empleador a Authors@R: con ‘cph’ y, tal vez, ‘fnd’ role. (Cuando acredita a un financiador a través del rol ‘fnd’, se reconoce en el pie de página de su sitio web pkgdown). Este también es un buen momento para asegurarse de que la dirección de correo electrónico del mantenedor sea apropiada. Ésta es la única manera en que CRAN puede comunicarse con usted. Si hay problemas y no pueden comunicarse con usted, eliminarán su paquete de CRAN. Asegúrese de que esta dirección de correo electrónico esté disponible por un tiempo y que no esté muy filtrada.

Verifique que cada una de sus funciones exportadas documente su valor de retorno (con la etiqueta @returns, Sección 16.4) y tenga una sección @examples (Sección 16.5). Si tiene ejemplos que no se pueden ejecutar en CRAN, es absolutamente necesario utilizar las técnicas en Sección 16.5.4 para expresar las condiciones previas relevantes correctamente. No tome atajos, como no tener ejemplos, comentar sus ejemplos o poner todos sus ejemplos dentro de \dontrun{}.

Si tiene código de terceros incrustado en su paquete, verifique que cumple y declara correctamente su licencia (Sección 12.4).

Finalmente, aproveche cualquier lista de comprobaciones ad hoc que otros desarrolladores de paquetes hayan experimentado recientemente con CRAN. En el momento de escribir, https://github.com/DavisVaughan/extrachecks es un buen lugar para encontrar este tipo de informes de primera mano. Leer dicha lista y modificar preventivamente su paquete a menudo puede marcar la diferencia entre una aceptación sin problemas y un proceso frustrante que requiere múltiples intentos.

22.2.1 Políticas de CRAN

Le alertamos sobre políticas CRAN específicas a lo largo de este libro y, especialmente, a través de este capítulo. Sin embargo, se trata de un objetivo en movimiento, por lo que vale la pena hacer un esfuerzo para mantenerse informado sobre los cambios futuros en la política de CRAN.

El hogar oficial de la política CRAN es https://cran.r-project.org/web/packages/policies.html. Sin embargo, no es muy práctico leer este documento, por ejemplo, una vez a la semana y simplemente esperar notar algún cambio. El repositorio de GitHub eddelbuettel/crp monitorea la Política del repositorio de CRAN al rastrear la evolución de los archivos subyacentes en la fuente del sitio web de CRAN. Por lo tanto, el historial de confirmaciones de ese repositorio hace que los cambios de políticas sean mucho más fáciles de navegar. Es posible que también desee seguir la cuenta de CRAN Policy Watch Mastodon, que suena cada vez que se detecta un cambio.2

La lista de correo de R-package-devel es otro buen recurso para aprender más sobre el desarrollo de paquetes. Puede suscribirse para estar al tanto de lo que hablan otros mantenedores. Incluso si no está suscrito, puede resultar útil buscar en esta lista cuando esté investigando un tema específico.

22.3 Mantenerse al día con el cambio

Ahora pasamos a los elementos principales de la lista de verificación para una versión menor o mayor de un paquete que ya está en CRAN. Muchos de estos elementos también aparecen en la lista de verificación de un parche o lanzamiento inicial.

Estos primeros elementos confirman que su paquete se mantiene al día con su entorno y consigo mismo. El primer elemento, “Verificar los resultados actuales de la verificación de CRAN”, será un hipervínculo a los resultados de la verificación de CRAN para la versión del paquete que se encuentra actualmente en CRAN. Si hay ADVERTENCIAS, ERRORES o NOTAS allí, debe investigar y determinar qué está pasando. Ocasionalmente puede haber un problema intermitente en CRAN, pero en términos generales, cualquier resultado que no sea “OK” es algo que debe abordar con la versión que está preparando. Es posible que descubra que su paquete se encuentra en un estado disfuncional debido a cambios en la base R, las políticas de CRAN, las herramientas de CRAN o los paquetes de los que depende.

Si está en el proceso de desaprobar una función o un argumento, una versión menor o mayor es un buen momento para considerar avanzar ese proceso como se describe en Sección 21.7. Este también es un buen momento para mirar todas las viñetas de NEWS que se han acumulado desde el último lanzamiento (“Pulir noticias”). Incluso si ha sido diligente al anotar todos los cambios dignos de noticia, es probable que estas viñetas se beneficien de alguna reorganización y edición para lograr coherencia y claridad (Sección 18.2).

Otra comprobación muy importante es ejecutar urlchecker::url_check(). Las comprobaciones de URL de CRAN se describen en https://cran.r-project.org/web/packages/URL_checks.html y se implementan mediante código que se incluye con el propio R. Sin embargo, estos controles no se exponen de una manera muy útil. El paquete urlchecker se creó para solucionar este problema y expone la lógica de verificación de URL de CRAN en la función url_check(). Los principales problemas que surgen tienden a ser las URL que ya no funcionan o las URL que utilizan la redirección. Obviamente, deberás actualizar o eliminar cualquier URL que ya no exista. La redirección, sin embargo, es más complicada. Si el código de estado es “301 movido permanentemente”, la opinión de CRAN es que su paquete debe usar la URL redirigida. El problema es que muchas personas no siguen RFC7231 al pie de la letra y utilizan este tipo de redirección incluso cuando tienen una intención diferente, es decir, su intención es proporcionar una URL estable y fácil de usar que luego redirige a algo menos fácil de usar o más volátil. Si una URL legítima que desea utilizar no cumple con las comprobaciones de CRAN, tendrá que elegir entre un par de opciones poco atractivas. Podría intentar explicar la situación a CRAN, pero esto requiere una revisión humana y, por lo tanto, no se recomienda. O puede convertir dichas URL en texto textual sin hipervínculos. Tenga en cuenta también que aunque urlchecker utiliza el mismo código que CRAN, sus resultados locales aún pueden diferir de los de CRAN, debido a diferencias en otras condiciones ambientales, como variables de entorno y capacidades del sistema.

Si tiene un archivo README.Rmd, también querrá reconstruir el archivo estático README.md con la versión actual de su paquete. La mejor función para usar para esto es devtools::build_readme(), porque se garantiza que renderizará README.Rmd contra el código fuente actual de su paquete.

22.4 Doble R CMD check

A continuación vienen un par de elementos relacionados con la R CMD check. Recuerde que esta no debería ser la primera vez que ejecuta R CMD check desde la versión anterior. Con suerte, está ejecutando R CMD check con frecuencia durante el desarrollo local y está utilizando un servicio de integración continua, como GitHub Actions. Este pretende ser un recordatorio final de último momento para comprobar que todo sigue bien:

Tenga en cuenta que la brevedad de esta lista refleja implícitamente que los paquetes de tidyverse se verifican después de cada envío a través de GitHub Actions, en múltiples sistemas operativos y versiones de R (incluida la versión de desarrollo), y que la mayor parte del equipo de tidyverse desarrolla principalmente en macOS. CRAN espera que usted “haga todos los esfuerzos razonables” para que su paquete funcione en todas las principales plataformas R y los paquetes que no funcionan en al menos dos normalmente no serán aceptados.

La siguiente subsección (Sección 22.4.1) es de lectura opcional con más detalles sobre todas las plataformas que le interesan a CRAN y cómo puede acceder a ellas. Si sus controles continuos son más limitados que los nuestros, es posible que desee compensarlo con controles previos al envío más exhaustivos. También puede necesitar este conocimiento para solucionar un problema concreto que surja en las comprobaciones de CRAN, ya sea para un envío entrante o para un paquete que ya está en CRAN.

Al ejecutar R CMD check para un envío CRAN, debe solucionar cualquier problema que aparezca:

  • Debe corregir todos los “ERRORES” y “ADVERTENCIAS”. CRAN no aceptará un paquete que contenga errores o advertencias.

  • Eliminar tantas NOTAS como sea posible. Cada “NOTA” requiere supervisión humana, lo que crea fricciones tanto para usted como para CRAN. Si hay notas que no cree que sean importantes, casi siempre es más fácil arreglarlas (incluso si la solución es un poco complicada) que persuadir a CRAN de que están bien. Consulte nuestra guía solo en línea sobre R CMD check para obtener detalles sobre cómo solucionar problemas individuales.

  • Si no puede eliminar una NOTA, inclúyala en cran-comments.md y explique por qué cree que es falsa. Analizaremos este archivo con más detalle en Sección 22.6.

    Tenga en cuenta que siempre habrá una “NOTA” cuando envíe su paquete por primera vez. Esto le recuerda a CRAN que se trata de un envío nuevo y que necesitarán realizar algunas comprobaciones adicionales. No puede eliminar esta “NOTA”, así que simplemente mencione en “cran-comments.md” que este es su primer envío.

22.4.1 CRAN consulta sabores y servicios relacionados

CRAN ejecuta R CMD check en todos los paquetes contribuidos al momento del envío y de forma regular, en múltiples plataformas o lo que ellos llaman “sabores”. Puede ver los tipos de cheques actuales de CRAN aquí: https://cran.r-project.org/web/checks/check_flavors.html. Hay varias combinaciones de:

  • Sistema operativo y CPU: Windows, macOS (x86_64, arm64), Linux (varias distribuciones)
  • Versión R: r-devel, r-release, r-oldrel
  • Compiladores C, C++, FORTRAN
  • Configuración regional, en el sentido de la variable de entorno LC_CTYPE (se trata de qué lenguaje humano está en uso y codificación de caracteres)

Es casi seguro que los tipos de verificación de CRAN incluyen plataformas distintas a su(s) entorno(s) de desarrollo preferido, por lo que eventualmente necesitará hacer un esfuerzo explícito para verificar y, tal vez, solucionar problemas de su paquete en estos otros tipos.

No sería práctico que los desarrolladores de paquetes individuales mantuvieran personalmente todas estas plataformas de prueba. En lugar de eso, recurrimos a varios recursos mantenidos por la comunidad y por CRAN para esto. Aquí hay una selección, en orden de cuán centrales son para nuestras prácticas actuales:

  • GitHub Actions (GHA) es nuestro medio principal para probar paquetes en múltiples versiones, como se describe en Sección 20.2.1.

  • Constructor de R-hub (R-hub). Este es un servicio respaldado por R Consortium donde los desarrolladores de paquetes pueden enviar su paquete para verificaciones que repliquen varios tipos de verificación CRAN.

    Puede utilizar R-hub a través de una interfaz web (https://builder.r-hub.io) o, como recomendamos, a través del paquete Rhub R.

    rhub::check_for_cran() es una buena opción para un paquete CRAN típico y es moralmente similar al flujo de trabajo de GHA configurado por usethis::use_github_action("check-standard"). Sin embargo, a diferencia de GHA, R-hub actualmente no cubre macOS, sólo Windows y Linux.

    Rhub también le ayuda a acceder a algunos de los tipos de cheques más exóticos y ofrece controles especializados relevantes para paquetes con código compilado, como rhub::check_with_sanitizers().

  • El generador de macOS es un servicio mantenido por el personal de CRAN que crea los archivos binarios de macOS para los paquetes de CRAN. Esta es una adición relativamente nueva a la lista y verifica paquetes con “la misma configuración y paquetes disponibles que la máquina de compilación CRAN M1”.

    Puede enviar su paquete usando la interfaz web (https://mac.r-project.org/macbuilder/submit.html) o con devtools::check_mac_release().

22.5 Comprobaciones de dependencia inversa

Este elemento inofensivo de la lista de verificación puede representar en realidad una cantidad considerable de esfuerzo. En un nivel alto, la verificación de sus dependencias inversas (“revdeps”) se divide en:

  • Forme una lista de sus dependencias inversas. Estos son paquetes CRAN que enumeran su paquete en sus campos Depends, Imports, Suggests o LinkingTo.

  • Ejecute R CMD check en cada uno.

  • Asegúrese de no haber roto el paquete de otra persona con los cambios planificados en su paquete.

Cada uno de estos pasos puede requerir mucho trabajo y juicio. Por lo tanto, si no tiene dependencias inversas, debería alegrarse de poder omitir este paso. Si solo tiene un par de dependencias inversas, probablemente pueda hacerlo “a mano”, es decir, descargar el código fuente de cada paquete y ejecutar R CMD check.

Aquí explicamos formas de realizar comprobaciones de dependencia inversa a escala, que es el problema al que nos enfrentamos. Algunos de los paquetes mantenidos por nuestro equipo tienen miles de dependencias inversas e incluso algunos de los paquetes de nivel inferior tienen cientos. Tenemos que abordar esto de forma automatizada y esta sección será de gran utilidad para otros mantenedores en el mismo barco.

Todas nuestras herramientas de dependencia inversa se concentran en el paquete revdepcheck (https://revdepcheck.r-lib.org/). Tenga en cuenta que, al menos en el momento de escribir este artículo, el paquete revdepcheck no está en CRAN. Puedes instalarlo desde Github a través de devtools::install_github("r-lib/revdepcheck") o pak::pak("r-lib/revdepcheck").

Haga esto cuando esté listo para realizar comprobaciones de revdep por primera vez:

usethis::use_revdep()

Esto realiza una configuración única en los archivos .gitignore y .Rbuildignore de su paquete. La comprobación de Revdep creará algunas carpetas bastante grandes debajo de revdep/, por lo que definitivamente querrás configurar estos archivos ignorados. También verá este recordatorio para realizar verificaciones de revdep de esta manera, como sugiere el elemento de la lista de verificación:

revdepcheck::revdep_check(num_workers = 4)

Esto ejecuta ⁠R CMD check⁠ en todas sus dependencias inversas, con nuestra recomendación de utilizar 4 trabajadores paralelos para acelerar las cosas. La salida se parece a esto:

> revdepcheck::revdep_check(num_workers = 4)
── INIT ───────────────────────────────────── Computing revdeps ──
── INSTALL ───────────────────────────────────────── 2 versions ──
Installing CRAN version of cellranger
also installing the dependencies 'cli', 'glue', 'utf8', 'fansi', 'lifecycle', 'magrittr', 'pillar', 'pkgconfig', 'rlang', 'vctrs', 'rematch', 'tibble'

Installing DEV version of cellranger
Installing 13 packages: rlang, lifecycle, glue, cli, vctrs, utf8, fansi, pkgconfig, pillar, magrittr, tibble, rematch2, rematch
── CHECK ─────────────────────────────────────────── 8 packages ──
✔ AOV1R 0.1.0                     ── E: 0     | W: 0     | N: 0
✔ mschart 0.4.0                   ── E: 0     | W: 0     | N: 0
✔ googlesheets4 1.0.1             ── E: 0     | W: 0     | N: 1
✔ readODS 1.8.0                   ── E: 0     | W: 0     | N: 0
✔ readxl 1.4.2                    ── E: 0     | W: 0     | N: 0
✔ readxlsb 0.1.6                  ── E: 0     | W: 0     | N: 0
✔ unpivotr 0.6.3                  ── E: 0     | W: 0     | N: 0
✔ tidyxl 1.0.8                    ── E: 0     | W: 0     | N: 0                  
OK: 8                                                                                 
BROKEN: 0
Total time: 6 min
── REPORT ────────────────────────────────────────────────────────
Writing summary to 'revdep/README.md'
Writing problems to 'revdep/problems.md'
Writing failures to 'revdep/failures.md'
Writing CRAN report to 'revdep/cran.md'

Para minimizar los falsos positivos, revdep_check() ejecuta ⁠R CMD check⁠ dos veces por revdep: una vez con la versión publicada de su paquete actualmente en CRAN y otra vez con la versión de desarrollo local, es decir, con su versión candidata. ¿Por qué dos cheques? Porque a veces el revdep ya está fallando en la R CMD check y sería incorrecto culpar a la versión planificada por la falla. revdep_check() informa los paquetes que no se pueden verificar y, lo más importante, aquellos en los que hay los llamados “cambios a peor”, es decir, donde su versión candidata está asociada con nuevos problemas. Tenga en cuenta también que revdep_check() siempre funciona con una biblioteca de paquetes temporal e independiente, es decir, no modificará su biblioteca de usuario o sistema predeterminada.

equipo tidyverse

De hecho, utilizamos una función diferente para nuestras comprobaciones de dependencia inversa: revdepcheck::cloud_check(). Esto ejecuta las comprobaciones en la nube, masivamente en paralelo, lo que hace posible ejecutar comprobaciones de revdep para paquetes como testthat (con >10,000 revdeps) en solo unas pocas horas.

cloud_check() ha cambiado las reglas del juego para nosotros, permitiéndonos ejecutar comprobaciones revdep con más frecuencia. Por ejemplo, incluso hacemos esto ahora cuando evaluamos el impacto de un posible cambio en un paquete (Sección 21.4), en lugar de hacerlo justo antes de un lanzamiento.

Al momento de escribir este artículo, cloud_check() solo está disponible para los mantenedores de paquetes en Posit, pero esperamos ofrecer este servicio a la comunidad R en general en el futuro.

Además de algunos mensajes interactivos, los resultados de la verificación revdep se escriben en la carpeta revdep/:

  • revdep/README.md: Este es un resumen de alto nivel dirigido a mantenedores. El nombre del archivo y el formato Markdown son muy intencionados para crear una buena página de inicio para la carpeta revdep/ en GitHub.
  • revdep/problems.md: enumera los revdeps que parecen estar rotos por su versión candidata.
  • revdep/failures.md: enumera los revdep que no se pudieron verificar, generalmente debido a un error de instalación, ya sea del propio revdep o de una de sus dependencias.
  • revdep/cran.md: Este es un resumen de alto nivel dirigido a CRAN. Debes copiar y pegar esto en cran-comments.md (Sección 22.6).
  • Otros archivos y carpetas, como checks.noindex, data.sqlite y library.noindex. Estos son para uso interno de revdepcheck y no los discutiremos más.

La forma más sencilla de tener una idea de estos diferentes archivos es consultar los últimos resultados de revdep para algunos paquetes tidyverse, como dplyr o tidyr.

Los resultados de la verificación revdep (local, en la nube o CRAN) no son perfectos, porque no es una tarea sencilla. Hay varias razones por las que un resultado puede faltar, ser incorrecto o contradictorio en diferentes ejecuciones.

  • Falsos positivos: a veces revdepcheck informa que un paquete se ha roto, pero en realidad todo está bien (o, al menos, no peor que antes). Esto ocurre más comúnmente debido a pruebas inestables que fallan aleatoriamente (Sección 15.4.1), como las solicitudes HTTP. Esto también puede suceder porque la instancia se queda sin espacio en disco u otros recursos, por lo que la primera verificación con la versión CRAN tiene éxito y la segunda verificación con la versión dev falla. A veces es obvio que el problema no está relacionado con su paquete.

  • Falsos negativos: a veces se ha roto un paquete, pero no lo detectas. Para nosotros, esto suele suceder cuando cloud_check() no puede verificar un revdep porque no se puede instalar, generalmente debido a que falta un requisito del sistema (por ejemplo, Java). Estos se informan por separado como “no se pudo probar”, pero aún se incluyen en problems.md, porque aún podría tratarse de una rotura directa causada por su paquete. Por ejemplo, si elimina una función exportada que utiliza otro paquete, la instalación fallará.

En general, estas diferencias son menos preocupantes ahora que las propias comprobaciones de revdep de CRAN están bien automatizadas, por lo que las nuevas fallas normalmente no involucran a un humano.

22.5.1 Revdeps y cambios importantes

Si la verificación revdep revela roturas, debe examinar cada falla y determinar si se trata de:

  • Un falso positivo.

  • Un cambio continuo, es decir, una falla causada por el uso no autorizado de su paquete.

  • Un error en tu paquete que necesitas corregir.

  • Un cambio radical deliberado.

Si su actualización romperá otro paquete (independientemente del motivo), debe informar al mantenedor, para que él lo escuche primero de usted, en lugar de CRAN. La mejor manera de hacerlo es con un parche que actualice su paquete para que funcione bien con el suyo, tal vez en forma de solicitud de extracción. Esto puede suponer una cantidad decente de trabajo y ciertamente no es factible para todos los mantenedores. Pero resolver algunos de ellos puede ser una buena manera de enfrentar el dolor que causa el cambio radical y reconsiderar si los beneficios superan los costos. En la mayoría de los casos, es probable que un cambio que afecte a los revdeps también rompa el código menos visible que se encuentra fuera de los paquetes CRAN, como scripts, informes y aplicaciones Shiny.

Si decide continuar, funciones como revdepcheck::revdep_maintainers() y revdepcheck::revdep_email() pueden ayudarle a notificar a los mantenedores de revdep en masa. Asegúrese de que el correo electrónico incluya un enlace a la documentación que describa los cambios importantes más comunes y cómo solucionarlos. Debe informar a los mantenedores cuándo planea enviar su versión a CRAN (recomendamos avisar con al menos dos semanas de anticipación), para que puedan enviar su versión actualizada antes de eso. Cuando llegue la fecha de lanzamiento, vuelva a ejecutar sus comprobaciones para ver cuántos problemas se han resuelto. Explique cualquier falla restante en cran-comments.md como se demuestra en Sección 22.6. Los dos casos más comunes son que no puede verificar un paquete porque no puede instalarlo localmente o un cambio legítimo en la API que el mantenedor aún no ha abordado. Siempre que haya avisado con suficiente antelación, CRAN aceptará su actualización, incluso si daña otros paquetes.

equipo tidyverse

Últimamente, el equipo de tidyverse está tratando de cumplir con los mantenedores de revdep a más de la mitad del camino en términos de lidiar con cambios importantes. Por ejemplo, en el problema de GitHub tidyverse/dplyr#6262, los mantenedores de dplyr rastrearon cientos de solicitudes de extracción en el período previo al lanzamiento de dplyr v1. .1.0. A medida que se crean los RP, también es útil agregar enlaces a ellos. A medida que los mantenedores de revdep fusionan los RP, se pueden marcar como resueltos. Si algunos RP todavía están en proceso cuando llega la fecha de envío anunciada, la situación se puede resumir en cran-comments.md, como fue el caso de dplyr v1.1.0.

22.6 Actualizar comentarios para CRAN

Usamos el archivo cran-comments.md para registrar comentarios sobre un envío, principalmente solo los resultados de R CMD check y controles revdep. Si está realizando un cambio específico a solicitud de CRAN, posiblemente dentro de una fecha límite, también tendría sentido mencionarlo. Nos gusta realizar un seguimiento de este archivo en Git, para poder ver cómo cambia con el tiempo. También debería aparecer en .Rbuildignore, ya que no debería aparecer en su paquete. Cuando esté listo para enviar, devtools::submit_cran() (Sección 22.7) incorpora el contenido de cran-comments.md cuando carga su envío.

El público objetivo de estos comentarios es el personal de CRAN, aunque no hay garantía de que lean los comentarios (o cuando en el proceso de envío los lean). Por ejemplo, si su paquete rompe otros paquetes, probablemente recibirá un correo electrónico automático al respecto, incluso si lo ha explicado en los comentarios. A veces, un humano de CRAN lee los comentarios, queda satisfecho y acepta su paquete de todos modos, sin ninguna otra acción por su parte. En otras ocasiones, su paquete puede quedarse atascado en la cola hasta que copie cran-comments.md y lo pegue en un intercambio de correo electrónico para avanzar. En cualquier caso, vale la pena mantener estos comentarios en su propio archivo controlado por versión.

Aquí hay un cran-comments.md bastante típico de una versión reciente de forcats. Tenga en cuenta que los resultados de la R CMD check son limpios, es decir, no hay nada que deba explicarse o justificarse, y hay un resumen conciso del proceso revdep.

## R CMD check results

0 errors | 0 warnings | 0 notes

## revdepcheck results

We checked 231 reverse dependencies (228 from CRAN + 3 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package.

We saw 2 new problems:

* epikit
* stevemisc

Both maintainers were notified on Jan 12 (~2 week ago) and supplied with patches.

We failed to check 3 packages

* genekitr     (NA)
* OlinkAnalyze (NA)
* SCpubr       (NA)

Este diseño está diseñado para que sea fácil de leer y fácil de comparar con los resultados de la R CMD check vistos por los mantenedores de CRAN. Incluye dos secciones:

  1. Verificar resultados: Siempre afirmamos que no hubo errores ni advertencias (¡y nos aseguramos de que sea cierto!). Idealmente también podemos decir que no hubo notas. Pero si no, las NOTES se presentan en una lista con viñetas. Para cada NOTA, incluimos el mensaje de R CMD check y una breve descripción de por qué creemos que está bien.

    A continuación se explica cómo se explica una NOTA para el paquete de datos nycflights13:

    ## R CMD check results
    
    0 errors | 0 warnings | 1 note
    
    * Checking installed package size:
      installed size is  6.9Mb
      sub-directories of 1Mb or more:
        data   6.9Mb
    
      This is a data package that will be rarely updated.
  2. Dependencias inversas: si hay revdeps, aquí es donde pegamos el contenido de revdep/cran.md (Sección 22.5). Si no hay revdeps, le recomendamos que mantenga esta sección, pero diga algo como: “Actualmente no hay dependencias posteriores para este paquete”.

22.7 El proceso de envío

Cuando esté realmente listo para enviar, es hora de aumentar el número de versión en DESCRIPCIÓN. Este elemento de la lista de verificación reflejará el tipo de lanzamiento declarado al inicio de este proceso (parche, menor o mayor), en la llamada inicial a use_release_issue().

Le recomendamos que envíe su paquete a CRAN llamando a devtools::submit_cran(). Esta función de conveniencia resume algunos pasos:

  • Crea el paquete (Sección 3.3) con pkgbuild::build(manual = TRUE), que finalmente llama a R CMD build.

  • Publica el archivo *.tar.gz resultante en el formulario de envío oficial de CRAN (https://cran.r-project.org/submit.html), completando su nombre y correo electrónico desde DESCRIPCIÓN y sus comentarios de envío. de cran-comments.md.

  • Confirma que el envío fue exitoso y le recuerda que revise su correo electrónico para ver el enlace de confirmación.

  • Escribe los detalles del envío en un archivo local CRAN-SUBMISSION, que registra la versión del paquete, SHA y la hora del envío. Esta información la utiliza más adelante usethis::use_github_release() para crear una versión de GitHub una vez que su paquete haya sido aceptado. CRAN-SUBMISSION se agregará a .Rbuildignore. Generalmente no ignoramos este archivo, pero tampoco lo confirmamos. Es una nota efímera que existe durante el intervalo entre la presentación y (con suerte) la aceptación.

Después de una carga exitosa, debería recibir un correo electrónico de CRAN en unos minutos. Este correo electrónico le notifica a usted, como mantenedor, del envío y proporciona un enlace de confirmación. Parte de lo que esto hace es confirmar que la dirección de correo electrónico del mantenedor es correcta. En el enlace de confirmación, deberá volver a confirmar que ha seguido las políticas de CRAN y que desea enviar el paquete. Si no completa este paso, ¡su paquete en realidad no se envía a CRAN!

Una vez que su paquete ingresa al sistema de CRAN, se verifica automáticamente en Windows y Linux, probablemente con las versiones lanzadas y de desarrollo de R. Recibirá otro correo electrónico con enlaces a los resultados de estas comprobaciones, normalmente en cuestión de horas. Una presentación inicial (Sección 22.2) recibirá un escrutinio adicional por parte del personal de CRAN. El proceso está potencialmente completamente automatizado cuando se actualiza un paquete que ya está en CRAN. Si la actualización de un paquete pasa sus comprobaciones iniciales, CRAN ejecutará comprobaciones de dependencia inversa.

22.8 Modos de fallo

Hay al menos tres formas de que falle el envío de CRAN:

  • No pasa R CMD check. Este es un resultado automatizado.

  • La revisión humana determina que el paquete infringe las políticas de CRAN. Esto se aplica principalmente a los envíos iniciales, pero a veces el personal de CRAN decide participar en una revisión ad hoc de actualizaciones de paquetes existentes que no superan las comprobaciones automáticas.

  • Las comprobaciones de dependencia inversa sugieren que hay “cambios a peor”. Este es un resultado automatizado.

Los fracasos son frustrantes y la retroalimentación puede ser cortante y francamente insultante. Siéntase cómodo sabiendo que esta es una experiencia ampliamente compartida en toda la comunidad R. Nos pasa habitualmente. No se apresure a responder, especialmente si se siente a la defensiva.

Espere hasta que pueda centrar su atención en los problemas técnicos que se han planteado. Lea atentamente los resultados de las comprobaciones o los correos electrónicos e investigue los hallazgos. A menos que crea firmemente que se merece la discusión, no responda el correo electrónico. En cambio:

  • Solucione los problemas identificados y realice los cambios recomendados. Vuelva a ejecutar devtools::check() en cualquier plataforma relevante para asegurarse de no introducir accidentalmente ningún problema nuevo.

  • Aumente la versión de parche de su paquete. Sí, esto significa que puede haber lagunas en los números de versión publicada. Esto no es gran cosa.

  • Agregue una sección “Resubmission” en la parte superior de cran-comments.md. Esto debería identificar claramente que el paquete es un reenvío y enumerar los cambios que realizó.

    ## Resubmission
    This is a resubmission. In this version I have:
    
    * Converted the DESCRIPTION title to title case.
    
    * More clearly identified the copyright holders in the DESCRIPTION
      and LICENSE files.
  • Si es necesario, actualice las secciones de resultados de verificación y revisión.

  • Ejecute devtools::submit_cran() para volver a enviar el paquete.

Si su análisis indica que el error inicial fue un falso positivo, responda al correo electrónico de CRAN con una explicación concisa. Para nosotros, este escenario surge principalmente con respecto a los controles de revdep. Es extremadamente raro que veamos fallas en las ejecuciones iniciales de R CMD check de CRAN y, cuando sucede, a menudo es legítima. Por otro lado, para paquetes con una gran cantidad de revdeps, es inevitable que un subconjunto de estos paquetes tenga algunas pruebas inestables o ejemplos frágiles. Por lo tanto, es bastante común ver fallas de revdep que no tienen nada que ver con la actualización del paquete propuesta. En este caso, lo adecuado es enviar un correo electrónico de respuesta a CRAN explicando por qué cree que se trata de falsos positivos.

22.9 Celebrando el éxito

Ahora pasamos a la sección más feliz de la lista de verificación.

CRAN le notificará por correo electrónico una vez que su paquete sea aceptado. Aquí es cuando enviamos por primera vez a GitHub con el nuevo número de versión, es decir, esperamos hasta que esté seguro de que esta versión realmente se lanzará en CRAN. A continuación, creamos una versión de GitHub correspondiente a esta versión de CRAN, usando usethis::use_github_release(). Una versión de GitHub es básicamente una etiqueta de Git glorificada. El único aspecto de las versiones de GitHub que aprovechamos regularmente son las notas de la versión. usethis::use_github_release() crea notas de la versión a partir de las viñetas NEWS relevantes para la versión actual. Tenga en cuenta que usethis::use_github_release() depende crucialmente del archivo CRAN-SUBMISSION que fue escrito por devtools::submit_cran(): así es como sabe qué SHA etiquetar. Después de la creación exitosa de la versión de GitHub, use_github_release() elimina este archivo temporal.

Ahora nos preparamos para la próxima versión incrementando el número de versión una vez más, esta vez a una versión de desarrollo usando usethis::use_dev_version(). Tiene sentido enviar inmediatamente este estado a GitHub para que, por ejemplo, cualquier rama nueva o solicitud de extracción tenga claramente una versión de desarrollo como base.

Una vez que CRAN acepta el paquete, se crean archivos binarios para macOS y Windows. También se verificará en el panel de tipos de verificación CRAN. Estos procesos se desarrollan a lo largo de unos días, después de la aceptación, y a veces descubren errores que no fueron detectados por las comprobaciones entrantes menos exhaustivas. Es una buena idea visitar la página de inicio de CRAN de su paquete unos días después del lanzamiento y asegurarse de que todo parezca estar bien. Figura 22.1 resalta dónde están vinculados estos resultados desde una página de inicio de CRAN.

Captura de pantalla de la página de inicio de CRAN para usar esto, con el enlace a los resultados de la verificación CRAN resaltados con un cuadro.
Figura 22.1: Enlace a los resultados de la verificación CRAN.

Si hay un problema, prepare una versión de parche para solucionarlo y envíelo utilizando el mismo proceso que antes. Si esto significa que va a realizar un segundo envío menos de una semana después del anterior, explique la situación en cran-comments.md. Lograr que un paquete se establezca en CRAN puede llevar un par de rondas, aunque la orientación de este capítulo tiene como objetivo maximizar las posibilidades de éxito en el primer intento. Las versiones futuras, iniciadas por usted, deben tener un intervalo de al menos uno o dos meses, de acuerdo con la política de CRAN.

Una vez que los binarios de su paquete estén creados y hayan pasado las comprobaciones de los distintos tipos de CRAN, es hora de la parte divertida: dar a conocer su paquete. Esto adopta diferentes formas, según el tipo de liberación. Si este es su lanzamiento inicial (o, al menos, el primer lanzamiento para el que realmente desea atraer usuarios), es especialmente importante correr la voz. Nadie utilizará su nuevo y útil paquete si no sabe que existe. Hay varios lugares para anunciar su paquete, como Twitter, Mastodon, LinkedIn, comunidades de Slack, etc. Asegúrese de utilizar etiquetas relevantes, como el hashtag #rstats. Si tienes un blog, es una gran idea escribir una publicación sobre tu lanzamiento.

Al presentar un paquete, la sensación debería ser bastante similar a escribir su README o una viñeta de “Introducción”. Asegúrese de describir lo que hace el paquete, para que las personas que no lo hayan usado antes puedan entender por qué debería importarles. Para los paquetes existentes, tendemos a escribir publicaciones de blog para versiones menores y principales, pero no para una versión de parche. En todos los casos, encontramos que estas publicaciones de blog son más efectivas cuando incluyen muchos ejemplos, es decir, “muestre, no cuente”. Para actualizaciones de paquetes, recuerde que la existencia de un archivo completo NEWS lo libera de la necesidad de enumerar hasta el último cambio en la publicación de su blog. En su lugar, puede centrarse en los cambios más importantes y vincular a las notas de la versión completas, para aquellos que quieran conocer los detalles sangrientos.

Si escribe un blog sobre su paquete, es bueno capturarlo como otra documentación más en su sitio web de pkgdown. Un sitio típico de pkgdown tiene un elemento de “News” en la barra de navegación superior, que enlaza con un “Changelog” que se crea a partir de NEWS.md. Este menú desplegable es un lugar común para insertar enlaces a cualquier publicación de blog sobre el paquete. Puedes lograr esto teniendo YAML como este en tu archivo de configuración _pkgdown.yml:

news:
  releases:
  - text: "Renaming the default branch (usethis >= 2.1.2)"
    href: https://www.tidyverse.org/blog/2021/10/renaming-default-branch/
  - text: "usethis 2.0.0"
    href: https://www.tidyverse.org/blog/2020/12/usethis-2-0-0/
  - text: "usethis 1.6.0"
    href: https://www.tidyverse.org/blog/2020/04/usethis-1-6-0/

¡Felicidades! ¡Has lanzado tu primer paquete a CRAN y has llegado al final del libro!


  1. La publicación del blog de Fowler “FrequencyReducesDifficulty” es una excelente lectura sobre este tema, https://martinfowler.com/bliki/FrequencyReducesDifficulty.html.↩︎

  2. Durante muchos años, existió, en cambio, una cuenta de Twitter de CRAN Policy Watch. Pero gracias a los nuevos límites de acceso a la API para ese “cadáver podrido de una plataforma”, la cuenta de Twitter ya no puede funcionar.↩︎