Skip to contents

Introduction

The multideploy package provides a streamlined way to deploy file changes across multiple GitHub repositories. Whether you’re managing standardized CI/CD configurations, common utility scripts, code style definitions, or any other files that should be consistent across repositories, multideploy helps automate this process.

This vignette will guide you through the main functionality of the package with practical examples.

Setup and Authentication

First, load the multideploy package:

Before using multideploy, you need to authenticate with GitHub. The package uses the gh package for authentication, which looks for a GitHub Personal Access Token (PAT) in the GITHUB_PAT or GITHUB_TOKEN environment variables. This token can be set directly within the R script via:

# Set GitHub PAT (or better, use .Renviron)
Sys.setenv(GITHUB_PAT = askpass::askpass("What is your GitHub Personal Access Token (PAT) ?"))

For regular use, it’s recommended to add your PAT to the git credential system through the gitcreds package:

gitcreds::gitcreds_set()

Alternatively, you can set the PAT directly in your .Renviron file by running:

file.edit("~/.Renviron")

Then, type:

GITHUB_PAT=your_github_pat_here

Your PAT needs appropriate permissions to access and modify repositories. At a minimum, you’ll need:

  • repo scope for accessing private repositories
  • workflow scope if you’re modifying GitHub Actions workflows

Managing Repositories

Listing Repositories

The repos() function allows you to list repositories for a user or organization:

# List repositories for a user
user_repos <- repos("username")

# List repositories for an organization
org_repos <- repos("orgname", type = "public")

# Filter repositories by name pattern
api_repos <- repos("orgname", filter_regex = "^api-")

# View the repositories
head(api_repos)

Listing Organizations

If you’re a member of multiple organizations, you can list them with:

my_orgs <- orgs()
print(my_orgs)

Working with Files

Getting File Content

You can retrieve the content of a file from a GitHub repository:

# Get content of a file
workflow_file <- file_content("username/repo", ".github/workflows/ci.yml")

# View the content
cat(workflow_file$content)

Creating or Updating Files

To create or update a file in a repository:

# Update a file
result <- file_update(
  repo = "username/repo",
  path = ".github/workflows/ci.yml",
  content = "updated workflow content...",
  message = "Update CI workflow"
)

Deploying Files Across Repositories

The core functionality of multideploy is deploying files across multiple repositories. This can be done in two ways:

Direct File Deployment

Deploy a single file to multiple repositories:

# Get repositories
repos <- repos("orgname", filter_regex = "^api-")

# Deploy a file to all repositories
results <- file_deploy(
  source_file = "templates/ci.yml",
  target_path = ".github/workflows/ci.yml",
  repos = repos,
  commit_message = "Standardize CI workflow"
)

# View deployment results
print(results)

Creating Pull Requests

For changes that require review, you can create pull requests:

# Create a mapping of files to deploy
mapping <- file_mapping(
  "templates/ci.yml" = ".github/workflows/ci.yml",
  "templates/lint.R" = ".lintr",
  "templates/codeowners" = ".github/CODEOWNERS"
)

# Create pull requests with these changes
pr_results <- pr_create(
  repos = repos,
  branch_name = "feature/standardize-configs",
  title = "Standardize repository configurations",
  body = "This PR updates CI workflows, linting settings, and CODEOWNERS file to match organization standards.",
  file_mapping = mapping
)

# View PR creation results
print(pr_results)

Advanced Use Cases

Deploying Files with Directory Structure

You can deploy all files from a directory while preserving their structure:

# Create mapping from a directory
workflow_mapping <- file_mapping(
  dir = "templates/workflows",
  pattern = "\\.ya?ml$",
  target_prefix = ".github/workflows/",
  preserve_structure = TRUE
)

# Use this mapping to create PRs
pr_create(
  repos = repos,
  branch_name = "feature/update-workflows",
  title = "Update all workflow files",
  body = "Standardize all GitHub Actions workflow files",
  file_mapping = workflow_mapping
)

Dry Run Mode

Before making actual changes, you can preview them using dry run mode:

# Preview file deployment without making changes
dry_results <- file_deploy(
  source_file = "templates/ci.yml",
  target_path = ".github/workflows/ci.yml",
  repos = repos,
  dry_run = TRUE
)

# View what would happen
print(dry_results)

Filtering and Targeting Repositories

You can combine repository filtering with deployment to target specific subsets of repositories:

# Get all organization repositories
all_repos <- repos("orgname")

# Filter to only Java repositories
r_repos <- all_repos[grepl("r", all_repos$name), ]

# Deploy R-specific configuration
file_deploy(
  source_file = "templates/R/.Rbuildignore",
  target_path = ".Rbuildignore",
  repos = r_repos
)

# Filter to only Python repositories
python_repos <- all_repos[grepl("python", all_repos$name), ]

# Deploy Python-specific configuration
file_deploy(
  source_file = "templates/python/pylintrc",
  target_path = ".pylintrc",
  repos = python_repos
)

Recommendations

If you’re deploying files across multiple repositories, we recommend taking into consideration the following:

  1. Start with dry runs: Always use dry_run = TRUE first to preview changes.

  2. Use meaningful commit messages: Include context about why the change is being made.

  3. Consider PR approach for significant changes: Use pr_create() instead of direct commits for changes that might need review.

  4. Store templates in version control: Keep your template files in their own repository.

  5. Create a deployment script: For regular deployments, create an R script that can be run repeatedly.

Deployment Script Example

Regarding the last recommendation, you can create a deployment script that automates the process of updating files across multiple repositories. Here’s an example script that updates CI/CD workflows and deploys configuration files to all repositories in an organization:

library(multideploy)

# Get repositories
api_repos <- repos("my-organization", filter_regex = "^api-")
service_repos <- repos("my-organization", filter_regex = "^service-")
all_repos <- rbind(api_repos, service_repos)

# Create file mappings
workflow_mapping <- file_mapping(
  dir = "templates/workflows",
  pattern = "\\.ya?ml$",
  target_prefix = ".github/workflows/",
  preserve_structure = TRUE
)

config_mapping <- file_mapping(
  "templates/.lintr" = ".lintr",
  "templates/.editorconfig" = ".editorconfig",
  "templates/CONTRIBUTING.md" = "CONTRIBUTING.md"
)

# Create PRs for workflow changes
pr_create(
  repos = all_repos,
  branch_name = "chore/update-workflows",
  title = "Update CI/CD workflows",
  body = "Update workflows to organization standards",
  file_mapping = workflow_mapping,
  dry_run = FALSE
)

If you want to deploy the files directly without creating pull requests, you can use the following snippet to directly deploy the configuration files:

# Directly deploy config files
for (local_file in names(config_mapping)) {
  target_path <- config_mapping[[local_file]]
  
  file_deploy(
    source_file = local_file,
    target_path = target_path,
    repos = all_repos,
    commit_message = paste("Update", basename(target_path), "to organization standards"),
    dry_run = FALSE
  )
}

Fin

The multideploy package streamlines the process of maintaining consistent files across multiple GitHub repositories. By automating deployment, you can ensure standardization while saving significant time and effort.