| Title: | Deploy File Changes Across Multiple 'GitHub' Repositories |
|---|---|
| Description: | Deploy file changes across multiple 'GitHub' repositories using the 'GitHub' 'Web API' <https://docs.github.com/en/rest>. Allows synchronizing common files, Continuous Integration ('CI') workflows, or configurations across many repositories with a single command. |
| Authors: | James Joseph Balamuta [aut, cre] (ORCID: <https://orcid.org/0000-0003-2826-8458>) |
| Maintainer: | James Joseph Balamuta <[email protected]> |
| License: | AGPL (>= 3) |
| Version: | 0.1.0 |
| Built: | 2026-05-25 09:15:37 UTC |
| Source: | https://github.com/coatless-rpkg/multideploy |
This function fetches a file from a GitHub repository and returns its content and SHA. If the file cannot be retrieved, it returns NULL and optionally displays a warning message.
file_content(repo, path, ref = NULL)file_content(repo, path, ref = NULL)
repo |
Character string specifying the full name of the repository (format: "owner/repo") |
path |
Character string specifying the path to the file within the repository |
ref |
Character string specifying the branch name, tag, or commit SHA. Default is NULL (uses default branch). |
When successful, returns a list with two elements:
Character string containing the decoded file content
Character string with the file's blob SHA for use in update operations
When the file cannot be retrieved (e.g., does not exist or no access), returns NULL.
# Get content from default branch file_info <- file_content("username/repository", "path/to/file.R") if (!is.null(file_info)) { # Access the content and SHA content <- file_info$content sha <- file_info$sha } # Get content from specific branch file_info <- file_content("username/repository", "path/to/file.R", ref = "develop") # Suppress warnings file_info <- file_content("username/repository", "path/to/file.R")# Get content from default branch file_info <- file_content("username/repository", "path/to/file.R") if (!is.null(file_info)) { # Access the content and SHA content <- file_info$content sha <- file_info$sha } # Get content from specific branch file_info <- file_content("username/repository", "path/to/file.R", ref = "develop") # Suppress warnings file_info <- file_content("username/repository", "path/to/file.R")
This function deploys a local file to multiple GitHub repositories. It can create new files or update existing ones, and provides detailed status reporting for each operation.
file_deploy( source_file, target_path, repos, commit_message = NULL, branch = NULL, create_if_missing = TRUE, dry_run = FALSE, quiet = FALSE )file_deploy( source_file, target_path, repos, commit_message = NULL, branch = NULL, create_if_missing = TRUE, dry_run = FALSE, quiet = FALSE )
source_file |
Character string specifying the local file path to deploy |
target_path |
Character string specifying the path in the repositories where the file should be placed |
repos |
Data frame of repositories as returned by |
commit_message |
Character string with the commit message. Default automatically generates a message. |
branch |
Character string specifying the branch name. Default is NULL (uses default branch). |
create_if_missing |
Logical indicating whether to create the file if it doesn't exist. Default is TRUE. |
dry_run |
Logical indicating whether to only simulate the changes without making actual commits. Default is FALSE. |
quiet |
Logical; if TRUE, suppresses progress and status messages. Default is FALSE. |
Returns a data.frame with class "file_deploy_result" containing the following columns:
Character, the full repository name (owner/repo)
Character, indicating the operation result with one of these values: "created", "updated", "unchanged", "skipped", "error", "would_create", "would_update"
Character, a description of the action taken or error encountered
print.file_deploy_result() for a formatted summary of deployment results.
# Get list of repositories repositories <- repos("my-organization") # Deploy a workflow file to all repositories results <- file_deploy( source_file = "local/path/to/workflow.yml", target_path = ".github/workflows/ci.yml", repos = repositories ) # Filter to see only successfully updated repositories updated <- results[results$status == "updated", ] # Check for any errors errors <- results[results$status == "error", ]# Get list of repositories repositories <- repos("my-organization") # Deploy a workflow file to all repositories results <- file_deploy( source_file = "local/path/to/workflow.yml", target_path = ".github/workflows/ci.yml", repos = repositories ) # Filter to see only successfully updated repositories updated <- results[results$status == "updated", ] # Check for any errors errors <- results[results$status == "error", ]
This function builds a mapping between local files and their target paths in repositories, supporting both individual file mapping and bulk directory processing.
file_mapping( ..., dir = NULL, pattern = NULL, target_prefix = "", preserve_structure = FALSE, quiet = FALSE )file_mapping( ..., dir = NULL, pattern = NULL, target_prefix = "", preserve_structure = FALSE, quiet = FALSE )
... |
Named arguments where names are local file paths and values are repository paths |
dir |
Character string specifying a directory to search for files. Default is NULL. |
pattern |
Character string with a regular expression pattern to match files in dir. Default is NULL. |
target_prefix |
Character string to prefix to all target paths. Default is "". |
preserve_structure |
Logical indicating whether to preserve directory structure in target. Default is FALSE. |
quiet |
Logical; if TRUE, suppresses information messages. Default is FALSE. |
The dir argument requires a valid directory path currently on the local filesystem.
This directory is scanned for files matching the pattern regular expression,
and each file is mapped to a target path in repositories. If the directory is
not found, an error is thrown.
Returns an object of class "file_mapping" (which is just a marked up "list") containing:
A named list where each entry maps a local file path (name) to a target repository path (value)
Each key is the full path to a local file
Each value is the corresponding path where the file should be placed in repositories
print.file_mapping() to display the mapping in a formatted way.
# Map individual files with explicit source-to-target paths mapping <- file_mapping( "local/path/ci.yml" = ".github/workflows/ci.yml", "local/path/lint.R" = ".lintr" ) # Automatically map all R files from a directory to backup/R2/ workflow_mapping <- file_mapping( dir = system.file(package = "multideploy"), pattern = "\\.R$", target_prefix = "backup/R2/" ) # Preserve directory structure when mapping files template_mapping <- file_mapping( dir = system.file(package = "multideploy"), preserve_structure = TRUE ) # Combine explicit mappings with directory-based mappings combined_mapping <- file_mapping( "specific/file.R" = "R/functions.R", dir = system.file(package = "multideploy"), target_prefix = ".github/" )# Map individual files with explicit source-to-target paths mapping <- file_mapping( "local/path/ci.yml" = ".github/workflows/ci.yml", "local/path/lint.R" = ".lintr" ) # Automatically map all R files from a directory to backup/R2/ workflow_mapping <- file_mapping( dir = system.file(package = "multideploy"), pattern = "\\.R$", target_prefix = "backup/R2/" ) # Preserve directory structure when mapping files template_mapping <- file_mapping( dir = system.file(package = "multideploy"), preserve_structure = TRUE ) # Combine explicit mappings with directory-based mappings combined_mapping <- file_mapping( "specific/file.R" = "R/functions.R", dir = system.file(package = "multideploy"), target_prefix = ".github/" )
This function creates a new file or updates an existing file in a GitHub repository. For updating existing files, the SHA of the current file must be provided.
file_update( repo, path, content, message, branch = NULL, sha = NULL, quiet = FALSE )file_update( repo, path, content, message, branch = NULL, sha = NULL, quiet = FALSE )
repo |
Character string specifying the full name of the repository (format: "owner/repo") |
path |
Character string specifying the path to the file within the repository |
content |
Character string with the new content of the file |
message |
Character string with the commit message |
branch |
Character string specifying the branch name. Default is NULL (uses default branch). |
sha |
Character string with the blob SHA of the file being replaced. Required for updating existing files; omit for creating new files. Default is NULL. |
quiet |
Logical; if TRUE, suppresses progress and status messages. Default is FALSE. |
When successful, returns a list containing the GitHub API response with details about the commit,
including:
Information about the updated file
Details about the created commit
When the operation fails (e.g., permission issues, invalid SHA), returns NULL.
# Create a new file result <- file_update( repo = "username/repository", path = "path/to/new_file.R", content = "# New R script\n\nprint('Hello world')", message = "Add new script file" ) # Check if operation was successful if (!is.null(result)) { # Access commit information commit_sha <- result$commit$sha } # Update an existing file (requires SHA) file_info <- file_content("username/repository", "path/to/existing_file.R") if (!is.null(file_info)) { result <- file_update( repo = "username/repository", path = "path/to/existing_file.R", content = "# Updated content\n\nprint('Hello updated world')", message = "Update file content", sha = file_info$sha ) }# Create a new file result <- file_update( repo = "username/repository", path = "path/to/new_file.R", content = "# New R script\n\nprint('Hello world')", message = "Add new script file" ) # Check if operation was successful if (!is.null(result)) { # Access commit information commit_sha <- result$commit$sha } # Update an existing file (requires SHA) file_info <- file_content("username/repository", "path/to/existing_file.R") if (!is.null(file_info)) { result <- file_update( repo = "username/repository", path = "path/to/existing_file.R", content = "# Updated content\n\nprint('Hello updated world')", message = "Update file content", sha = file_info$sha ) }
This function retrieves all organizations associated with the currently authenticated GitHub user, with options to control pagination.
orgs(per_page = 100, max_pages = 5, quiet = FALSE)orgs(per_page = 100, max_pages = 5, quiet = FALSE)
per_page |
Number of organizations to return per page. Default is 100. |
max_pages |
Maximum number of pages to retrieve. Default is 5. |
quiet |
Logical; if TRUE, suppresses progress and status messages. Default is FALSE. |
Returns a data.frame of organizations with the following columns:
Character, the organization's username/login name
Character, the API URL for the organization
The data.frame is ordered as returned by the GitHub API (typically alphabetically).
# Get all organizations for the authenticated user my_orgs <- orgs() # Retrieve silently without progress messages my_orgs <- orgs(quiet = TRUE) # Extract just the organization names org_names <- orgs()$login# Get all organizations for the authenticated user my_orgs <- orgs() # Retrieve silently without progress messages my_orgs <- orgs(quiet = TRUE) # Extract just the organization names org_names <- orgs()$login
This function creates pull requests across multiple GitHub repositories, applying the same set of file changes to each repository. It can create new branches as needed, add or update files, and then open pull requests.
pr_create( repos, branch_name, base_branch = NULL, title, body, create_branch = TRUE, file_mapping, dry_run = FALSE, quiet = FALSE )pr_create( repos, branch_name, base_branch = NULL, title, body, create_branch = TRUE, file_mapping, dry_run = FALSE, quiet = FALSE )
repos |
Data frame of repositories as returned by |
branch_name |
Character string with the name of the branch to create for the changes |
base_branch |
Character string with the name of the base branch. Default is NULL (uses default branch). |
title |
Character string with the PR title |
body |
Character string with the PR description |
create_branch |
Logical indicating whether to create the branch if it doesn't exist. Default is TRUE. |
file_mapping |
List mapping local file paths to repository paths, as created by |
dry_run |
Logical indicating whether to only simulate the changes. Default is FALSE. |
quiet |
Logical; if TRUE, suppresses progress and status messages. Default is FALSE. |
Returns a data.frame with class "pr_create_result" containing the following columns:
Character, the full repository name (owner/repo)
Character, the URL of the created pull request, or NA if no PR was created
Character, indicating the operation result: "created", "would_create", "skipped", or "error"
Character, a description of the action taken or error encountered
print.pr_create_result() to display the results in a formatted way.
# Get repositories and create file mapping repositories <- repos("my-organization") mapping <- file_mapping( "local/path/file1.R" = ".github/workflows/ci.yml", "local/path/file2.R" = "R/utils.R" ) # Create pull requests in all repositories results <- pr_create( repos = repositories, branch_name = "feature-branch", title = "Update CI workflow", body = "Standardizing CI workflow across repositories", file_mapping = mapping ) # Simulate without making actual changes dry_run_results <- pr_create( repos = repositories, branch_name = "feature-branch", title = "Update documentation", body = "Updating documentation with new examples", file_mapping = mapping, dry_run = TRUE ) # Only create PRs in repositories where the branch already exists existing_branch_results <- pr_create( repos = repositories, branch_name = "existing-branch", title = "Fix existing branch", body = "Apply fixes to existing branch", file_mapping = mapping, create_branch = FALSE )# Get repositories and create file mapping repositories <- repos("my-organization") mapping <- file_mapping( "local/path/file1.R" = ".github/workflows/ci.yml", "local/path/file2.R" = "R/utils.R" ) # Create pull requests in all repositories results <- pr_create( repos = repositories, branch_name = "feature-branch", title = "Update CI workflow", body = "Standardizing CI workflow across repositories", file_mapping = mapping ) # Simulate without making actual changes dry_run_results <- pr_create( repos = repositories, branch_name = "feature-branch", title = "Update documentation", body = "Updating documentation with new examples", file_mapping = mapping, dry_run = TRUE ) # Only create PRs in repositories where the branch already exists existing_branch_results <- pr_create( repos = repositories, branch_name = "existing-branch", title = "Fix existing branch", body = "Apply fixes to existing branch", file_mapping = mapping, create_branch = FALSE )
"file_deploy_result" objectsThis method provides a formatted summary of file deployment results, showing counts by status and details for any errors encountered.
## S3 method for class 'file_deploy_result' print(x, ...)## S3 method for class 'file_deploy_result' print(x, ...)
x |
An object of class |
... |
Additional arguments passed to other print methods (not used) |
Invisibly returns the original input data frame unchanged.
Displays a formatted summary of deployment results to the console.
# Get list of repositories repositories <- repos("my-organization") # Deploy files results <- file_deploy("local/file.R", "remote/file.R", repositories) # Explicitly print the summary print(results)# Get list of repositories repositories <- repos("my-organization") # Deploy files results <- file_deploy("local/file.R", "remote/file.R", repositories) # Explicitly print the summary print(results)
This method provides a formatted display of file mappings, showing the relationship between local files and their target repository paths with visual indicators for file existence.
## S3 method for class 'file_mapping' print(x, max_files = 20, ...)## S3 method for class 'file_mapping' print(x, max_files = 20, ...)
x |
An object of class |
max_files |
Maximum number of files to display. Default is 20. |
... |
Additional arguments passed to other print methods (not used) |
Invisibly returns the original file_mapping object unchanged, allowing for
chained operations.
Displays a formatted representation of the mapping to the console, including:
Total count of mapped files
Visual indicators showing which local files exist (checkmark) or are missing (x)
Source-to-target mapping for each file (limited by max_files)
# Create and display a mapping mapping <- file_mapping( "R/functions.R" = "R/utils.R", dir = system.file(package = "multideploy") ) # The mapping is automatically printed when not assigned # Control how many files are displayed mapping <- file_mapping(dir = system.file(package = "multideploy")) print(mapping, max_files = 5) # Show only first 5 mappings# Create and display a mapping mapping <- file_mapping( "R/functions.R" = "R/utils.R", dir = system.file(package = "multideploy") ) # The mapping is automatically printed when not assigned # Control how many files are displayed mapping <- file_mapping(dir = system.file(package = "multideploy")) print(mapping, max_files = 5) # Show only first 5 mappings
This method provides a formatted summary of pull request creation results, showing counts by status and details for created PRs and any errors encountered.
## S3 method for class 'pr_create_result' print(x, ...)## S3 method for class 'pr_create_result' print(x, ...)
x |
An object of class "pr_create_result" as returned by |
... |
Additional arguments passed to other print methods (not used) |
Invisibly returns the original input data frame (x) unchanged, allowing for chained operations. The function's primary purpose is displaying a formatted summary to the console, including:
Counts of PRs by status (created, would_create, skipped, error)
List of successfully created PRs with clickable URLs
Details about any errors encountered during the process
# Create PRs results <- pr_create( repos = repos("my-organization"), branch_name = "feature-branch", title = "Update configuration", body = "Standardize configuration across repos", file_mapping = file_mapping("config.yml" = ".github/config.yml") ) print(results) # Explicitly print the summary# Create PRs results <- pr_create( repos = repos("my-organization"), branch_name = "feature-branch", title = "Update configuration", body = "Standardize configuration across repos", file_mapping = file_mapping("config.yml" = ".github/config.yml") ) print(results) # Explicitly print the summary
This function fetches repository information from GitHub for a specified user or organization, with options to filter and limit the results.
repos( owner, type = "owner", per_page = 100, max_pages = 10, filter_regex = NULL, quiet = FALSE )repos( owner, type = "owner", per_page = 100, max_pages = 10, filter_regex = NULL, quiet = FALSE )
owner |
Character string specifying the GitHub username or organization name |
type |
Character string specifying the type of repositories to list: "all", "owner", "public", "private", or "member". Default is "owner". |
per_page |
Number of repositories to return per page. Default is 100. |
max_pages |
Maximum number of pages to retrieve. Default is 10. |
filter_regex |
Optional regular expression to filter repositories by name |
quiet |
Logical; if TRUE, suppresses progress and status messages. Default is FALSE. |
Returns a data.frame of repositories with the following columns:
Character, repository name without owner prefix
Character, complete repository identifier (owner/repo)
Character, the name of the default branch (e.g., "main" or "master")
Logical, TRUE if repository is private, FALSE if public
# Get all repositories owned by a user user_repos <- repos("username") # Get only public repositories for an organization org_public_repos <- repos("orgname", type = "public") # Filter repositories by name pattern api_repos <- repos("orgname", filter_regex = "^api-") # Limit the number of fetched repositories limited_repos <- repos("large-org", per_page = 50, max_pages = 2)# Get all repositories owned by a user user_repos <- repos("username") # Get only public repositories for an organization org_public_repos <- repos("orgname", type = "public") # Filter repositories by name pattern api_repos <- repos("orgname", filter_regex = "^api-") # Limit the number of fetched repositories limited_repos <- repos("large-org", per_page = 50, max_pages = 2)