@@ -502,35 +502,52 @@ validate_codecheck_yml_crossref <- function(yml_file = "codecheck.yml",
502502# #' For each person with an ORCID, retrieves their ORCID record and compares
503503# #' the name in the ORCID record with the name in the local codecheck.yml file.
504504# #'
505+ # #' Note: This function requires access to the ORCID API. If you encounter
506+ # #' authentication issues, you can either:
507+ # #' \itemize{
508+ # #' \item Set the \code{ORCID_TOKEN} environment variable with your ORCID token
509+ # #' \item Run \code{rorcid::orcid_auth()} to authenticate interactively
510+ # #' \item Set \code{skip_on_auth_error = TRUE} to skip validation if authentication fails
511+ # #' }
512+ # #'
505513# #' @title Validate codecheck.yml metadata against ORCID
506514# #' @param yml_file Path to the codecheck.yml file (defaults to "./codecheck.yml")
507515# #' @param strict Logical. If \code{TRUE}, throw an error on any mismatch.
508516# #' If \code{FALSE} (default), only issue warnings.
509517# #' @param validate_authors Logical. If \code{TRUE} (default), validate author ORCIDs.
510518# #' @param validate_codecheckers Logical. If \code{TRUE} (default), validate codechecker ORCIDs.
519+ # #' @param skip_on_auth_error Logical. If \code{TRUE}, skip validation when ORCID
520+ # #' authentication fails instead of throwing an error. Default is \code{FALSE},
521+ # #' which requires ORCID authentication. Set to \code{TRUE} to allow the function
522+ # #' to work without ORCID authentication (e.g., CI/CD pipelines, test environments).
511523# #' @return Invisibly returns a list with validation results:
512524# #' \describe{
513525# #' \item{valid}{Logical indicating if all checks passed}
514526# #' \item{issues}{Character vector of any issues found}
527+ # #' \item{skipped}{Logical indicating if validation was skipped due to auth issues}
515528# #' }
516529# #' @author Daniel Nuest
517530# #' @importFrom rorcid orcid_person
518531# #' @export
519532# #' @examples
520533# #' \dontrun{
521- # #' # Validate with warnings only
534+ # #' # Validate with warnings only (requires ORCID authentication)
522535# #' result <- validate_codecheck_yml_orcid()
523536# #'
524537# #' # Validate with strict error checking
525538# #' validate_codecheck_yml_orcid(strict = TRUE)
526539# #'
527540# #' # Validate only codecheckers
528541# #' validate_codecheck_yml_orcid(validate_authors = FALSE)
542+ # #'
543+ # #' # Skip ORCID validation if authentication is not available
544+ # #' validate_codecheck_yml_orcid(skip_on_auth_error = TRUE)
529545# #' }
530546validate_codecheck_yml_orcid <- function (yml_file = " codecheck.yml" ,
531547 strict = FALSE ,
532548 validate_authors = TRUE ,
533- validate_codecheckers = TRUE ) {
549+ validate_codecheckers = TRUE ,
550+ skip_on_auth_error = FALSE ) {
534551
535552 if (! file.exists(yml_file )) {
536553 stop(" codecheck.yml file not found at: " , yml_file )
@@ -540,6 +557,7 @@ validate_codecheck_yml_orcid <- function(yml_file = "codecheck.yml",
540557 local_meta <- yaml :: read_yaml(yml_file )
541558
542559 issues <- character (0 )
560+ validation_skipped <- FALSE
543561
544562 # Helper function to normalize names for comparison
545563 normalize_name <- function (name ) {
@@ -577,7 +595,23 @@ validate_codecheck_yml_orcid <- function(yml_file = "codecheck.yml",
577595
578596 return (NULL )
579597 }, error = function (e ) {
580- warning(" Failed to retrieve ORCID record for " , orcid_id , " : " , e $ message )
598+ error_msg <- conditionMessage(e )
599+
600+ # Check if this is an authentication error
601+ if (grepl(" Unauthorized|401|authentication|token" , error_msg , ignore.case = TRUE )) {
602+ if (skip_on_auth_error ) {
603+ validation_skipped <<- TRUE
604+ message(" \u 2139 ORCID authentication required but not available. Skipping validation for " , orcid_id )
605+ message(" To enable ORCID validation, set ORCID_TOKEN environment variable or run rorcid::orcid_auth()" )
606+ return (" AUTH_ERROR" )
607+ } else {
608+ stop(" ORCID authentication failed for " , orcid_id , " : " , error_msg ,
609+ " \n Set ORCID_TOKEN environment variable or run rorcid::orcid_auth() to authenticate." ,
610+ " \n Or set skip_on_auth_error = TRUE to skip validation when authentication fails." )
611+ }
612+ }
613+
614+ warning(" Failed to retrieve ORCID record for " , orcid_id , " : " , error_msg )
581615 return (NULL )
582616 })
583617 }
@@ -603,6 +637,11 @@ validate_codecheck_yml_orcid <- function(yml_file = "codecheck.yml",
603637 # Query ORCID for name
604638 orcid_name <- get_orcid_name(author $ ORCID )
605639
640+ # Skip this author if authentication failed and we're in skip mode
641+ if (! is.null(orcid_name ) && orcid_name == " AUTH_ERROR" ) {
642+ next
643+ }
644+
606645 if (! is.null(orcid_name )) {
607646 local_name_norm <- normalize_name(author $ name )
608647 orcid_name_norm <- normalize_name(orcid_name )
@@ -670,6 +709,11 @@ validate_codecheck_yml_orcid <- function(yml_file = "codecheck.yml",
670709 # Query ORCID for name
671710 orcid_name <- get_orcid_name(checker $ ORCID )
672711
712+ # Skip this codechecker if authentication failed and we're in skip mode
713+ if (! is.null(orcid_name ) && orcid_name == " AUTH_ERROR" ) {
714+ next
715+ }
716+
673717 if (! is.null(orcid_name )) {
674718 local_name_norm <- normalize_name(checker $ name )
675719 orcid_name_norm <- normalize_name(orcid_name )
@@ -703,7 +747,10 @@ validate_codecheck_yml_orcid <- function(yml_file = "codecheck.yml",
703747 # Final validation result
704748 valid <- length(issues ) == 0
705749
706- if (! valid ) {
750+ if (validation_skipped ) {
751+ message(" \n\u 2139 ORCID validation skipped due to authentication issues" )
752+ message(" Set ORCID_TOKEN environment variable or run rorcid::orcid_auth() to enable ORCID validation" )
753+ } else if (! valid ) {
707754 message(" \n\u 26a0 ORCID validation completed with " , length(issues ), " issue(s)" )
708755 if (strict ) {
709756 stop(" ORCID validation failed with " , length(issues ), " issue(s):\n " ,
@@ -715,7 +762,8 @@ validate_codecheck_yml_orcid <- function(yml_file = "codecheck.yml",
715762
716763 invisible (list (
717764 valid = valid ,
718- issues = issues
765+ issues = issues ,
766+ skipped = validation_skipped
719767 ))
720768}
721769
@@ -733,6 +781,10 @@ validate_codecheck_yml_orcid <- function(yml_file = "codecheck.yml",
733781# #' @param validate_crossref Logical. If \code{TRUE} (default), validate against CrossRef.
734782# #' @param validate_orcid Logical. If \code{TRUE} (default), validate against ORCID.
735783# #' @param check_orcids Logical. If \code{TRUE} (default), validate ORCID identifiers in CrossRef check.
784+ # #' @param skip_on_auth_error Logical. If \code{TRUE}, skip ORCID validation
785+ # #' when authentication fails instead of throwing an error. Default is \code{FALSE},
786+ # #' which requires ORCID authentication. Set to \code{TRUE} to allow the function
787+ # #' to work without ORCID authentication (e.g., CI/CD pipelines, test environments).
736788# #' @return Invisibly returns a list with validation results:
737789# #' \describe{
738790# #' \item{valid}{Logical indicating if all checks passed}
@@ -754,12 +806,16 @@ validate_codecheck_yml_orcid <- function(yml_file = "codecheck.yml",
754806# #'
755807# #' # Validate only ORCID
756808# #' validate_contents_references(validate_crossref = FALSE)
809+ # #'
810+ # #' # Skip ORCID validation if authentication is not available
811+ # #' validate_contents_references(skip_on_auth_error = TRUE)
757812# #' }
758813validate_contents_references <- function (yml_file = " codecheck.yml" ,
759814 strict = FALSE ,
760815 validate_crossref = TRUE ,
761816 validate_orcid = TRUE ,
762- check_orcids = TRUE ) {
817+ check_orcids = TRUE ,
818+ skip_on_auth_error = FALSE ) {
763819
764820 crossref_result <- NULL
765821 orcid_result <- NULL
@@ -790,7 +846,8 @@ validate_contents_references <- function(yml_file = "codecheck.yml",
790846
791847 orcid_result <- validate_codecheck_yml_orcid(
792848 yml_file = yml_file ,
793- strict = FALSE # Don't stop yet
849+ strict = FALSE , # Don't stop yet
850+ skip_on_auth_error = skip_on_auth_error
794851 )
795852
796853 if (! orcid_result $ valid ) {
0 commit comments