Skip to content

joshjohanning/bulk-github-repo-settings-sync-action

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Repository files navigation

Bulk GitHub Repository Settings Sync Action

GitHub release Immutable releases GitHub marketplace CI Publish GitHub Action Coverage

Update repository settings in bulk across multiple GitHub repositories.

Features

  • 🔧 Update pull request merge strategies (squash, merge, rebase)
  • ✅ Configure auto-merge settings
  • 🗑️ Enable automatic branch deletion after merge
  • 🔄 Configure pull request branch update suggestions
  • 📊 Enable default CodeQL code scanning
  • 🔒 Enable or disable immutable releases to prevent release deletion and modification
  • 🏷️ Manage repository topics
  • 🔄 Sync dependabot.yml files across repositories via pull requests
  • 📋 Sync repository rulesets across repositories
  • 📝 Sync pull request templates across repositories via pull requests
  • 📝 Support multiple repository input methods (comma-separated, YAML file, or all org repos)
  • 🔍 Dry-run mode with change preview and intelligent change detection
  • 📋 Per-repository overrides via YAML configuration
  • 📊 Comprehensive logging showing before/after values for all changes

Usage Examples

Basic Usage

- name: Update Repository Settings
  uses: joshjohanning/bulk-github-repo-settings-sync-action@v1
  with:
    github-token: ${{ steps.app-token.outputs.token }}
    repositories: 'owner/repo1,owner/repo2,owner/repo3'
    allow-squash-merge: true
    allow-merge-commit: false
    delete-branch-on-merge: true
    enable-default-code-scanning: true
    immutable-releases: true
    dependabot-yml: './config/dependabot/npm-actions.yml'
    rulesets-file: './config/rulesets/prod-ruleset.json'
    pull-request-template: './config/templates/pull_request_template.md'
    topics: 'javascript,github-actions,automation'
    dry-run: ${{ github.event_name == 'pull_request' }} # dry run if PR

Using YAML Configuration with Overrides

Create a repos.yml file:

repos:
  - repo: owner/repo1
    allow-squash-merge: false # Override global setting
    topics: 'javascript,special-config'
  - repo: owner/repo2 # Uses global defaults
  - repo: owner/repo3
    enable-default-code-scanning: false

Use in workflow:

- name: Update Repository Settings with Overrides
  uses: joshjohanning/bulk-github-repo-settings-sync-action@v1
  with:
    github-token: ${{ steps.app-token.outputs.token }}
    repositories-file: 'repos.yml'
    # Global defaults (overridden per-repo in YAML)
    allow-squash-merge: true
    delete-branch-on-merge: true
    enable-default-code-scanning: true
    topics: 'javascript,github-actions'

Syncing Dependabot Configuration

Sync a dependabot.yml file to .github/dependabot.yml in target repositories via pull requests:

- name: Sync Dependabot Config
  uses: joshjohanning/bulk-github-repo-settings-sync-action@v1
  with:
    github-token: ${{ steps.app-token.outputs.token }}
    repositories-file: 'repos.yml'
    dependabot-yml: './config/dependabot/npm-actions.yml'
    dependabot-pr-title: 'chore: update dependabot.yml'

Or with repo-specific overrides in repos.yml:

repos:
  - repo: owner/repo1
    dependabot-yml: './config/dependabot/npm-actions.yml'
  - repo: owner/repo2
    dependabot-yml: './config/dependabot/python.yml'
  - repo: owner/repo3
    dependabot-yml: './.github/dependabot.yml' # use the same config that this repo is using

Behavior:

  • If .github/dependabot.yml doesn't exist, it creates it and opens a PR
  • If it exists but differs, it updates it via PR
  • If content is identical, no PR is created
  • PRs are created/updated using the GitHub API so commits are verified
  • Updates existing open PRs instead of creating duplicates

Syncing Repository Rulesets

Sync repository rulesets across multiple repositories:

- name: Sync Repository Rulesets
  uses: joshjohanning/bulk-github-repo-settings-sync-action@v1
  with:
    github-token: ${{ steps.app-token.outputs.token }}
    repositories-file: 'repos.yml'
    rulesets-file: './config/rulesets/ci-ruleset.json'

Or with repo-specific overrides in repos.yml:

repos:
  - repo: owner/repo1
    rulesets-file: './config/rulesets/ci-ruleset.json'
  - repo: owner/repo2
    rulesets-file: './config/rulesets/prod-ruleset.json'
  - repo: owner/repo3
    # Skip ruleset sync for this repo

Behavior:

  • Creates the ruleset if it doesn't exist in the repository
  • Updates the ruleset if a ruleset with the same name already exists
  • Ruleset is identified by the name field in the JSON configuration
  • The JSON file should contain a valid ruleset configuration matching the GitHub Rulesets API schema

Example Ruleset JSON (ci-ruleset.json):

{
  "name": "ci",
  "target": "branch",
  "enforcement": "active",
  "bypass_actors": [
    {
      "actor_id": 5,
      "actor_type": "RepositoryRole",
      "bypass_mode": "always"
    }
  ],
  "conditions": {
    "ref_name": {
      "include": ["refs/heads/main"],
      "exclude": []
    }
  },
  "rules": [
    {
      "type": "deletion"
    },
    {
      "type": "required_status_checks",
      "parameters": {
        "required_status_checks": [
          {
            "context": "test",
            "integration_id": 15368
          }
        ]
      }
    },
    {
      "type": "non_fast_forward"
    }
  ]
}

For more information on ruleset configuration, see the GitHub Rulesets documentation.

Syncing Pull Request Templates

Sync a pull request template file to .github/pull_request_template.md in target repositories via pull requests:

- name: Sync Pull Request Template
  uses: joshjohanning/bulk-github-repo-settings-sync-action@v1
  with:
    github-token: ${{ steps.app-token.outputs.token }}
    repositories-file: 'repos.yml'
    pull-request-template: './config/templates/pull_request_template.md'
    pull-request-template-pr-title: 'chore: update pull request template'

Or with repo-specific overrides in repos.yml:

repos:
  - repo: owner/repo1
    pull-request-template: './config/templates/standard-template.md'
  - repo: owner/repo2
    pull-request-template: './config/templates/feature-template.md'
  - repo: owner/repo3
    # Skip pull request template sync for this repo

Behavior:

  • If .github/pull_request_template.md doesn't exist, it creates it and opens a PR
  • If it exists but differs, it updates it via PR
  • If content is identical, no PR is created
  • PRs are created/updated using the GitHub API so commits are verified
  • Updates existing open PRs instead of creating duplicates

For more information on pull request templates, see the GitHub documentation.

Organization-wide Updates

- name: Update All Org Repositories
  uses: joshjohanning/bulk-github-repo-settings-sync-action@v1
  with:
    github-token: ${{ steps.app-token.outputs.token }}
    repositories: 'all'
    owner: 'my-organization'
    allow-squash-merge: true
    delete-branch-on-merge: true

Dry-Run Mode

Preview changes without applying them:

- name: Preview Changes
  uses: joshjohanning/bulk-github-repo-settings-sync-action@v1
  with:
    github-token: ${{ steps.app-token.outputs.token }}
    repositories: 'owner/repo1,owner/repo2'
    allow-squash-merge: true
    dry-run: true
    # dry-run true in PRs, false otherwise example:
    # dry-run: ${{ github.event_name == 'pull_request' }}

Output shows what would change:

🔍 Would update owner/repo1
  📝 Settings changes:
     allow-squash-merge: false → true
     delete-branch-on-merge: false → true
  📦 Would create .github/dependabot.yml via PR

Action Inputs

Input Description Required Default
github-token GitHub token for API access (requires repo scope or GitHub App with repository administration) Yes -
github-api-url GitHub API URL (e.g., https://api.github.com for GitHub.com or https://ghes.domain.com/api/v3 for GHES). Instance URL is auto-derived. No ${{ github.api_url }}
repositories Comma-separated list of repositories (owner/repo) or "all" for all org/user repos No* -
repositories-file Path to YAML file containing repository list No* -
owner Owner (user or organization) name - required when using repositories: "all" No -
allow-squash-merge Allow squash merging pull requests No -
allow-merge-commit Allow merge commits for pull requests No -
allow-rebase-merge Allow rebase merging pull requests No -
allow-auto-merge Allow auto-merge on pull requests No -
delete-branch-on-merge Automatically delete head branches after pull requests are merged No -
allow-update-branch Always suggest updating pull request branches No -
immutable-releases Enable immutable releases to prevent release deletion and modification No -
enable-default-code-scanning Enable default code scanning setup No -
topics Comma-separated list of topics to set on repositories (replaces existing topics) No -
dependabot-yml Path to a dependabot.yml file to sync to .github/dependabot.yml in target repositories No -
dependabot-pr-title Title for pull requests when updating dependabot.yml No chore: update dependabot.yml
rulesets-file Path to a JSON file containing repository ruleset configuration to sync to target repositories No -
pull-request-template Path to a pull request template file to sync to .github/pull_request_template.md in target repositories No -
pull-request-template-pr-title Title for pull requests when updating pull request template No chore: update pull request template
dry-run Preview changes without applying them (logs what would be changed) No false

* Either repositories or repositories-file must be provided

Action Outputs

Output Description
updated-repositories Number of repositories successfully updated
failed-repositories Number of repositories that failed to update
results JSON array of update results for each repository

Authentication

GitHub App (Recommended)

For better security and rate limits, use a GitHub App:

  1. Create a GitHub App with the following permissions:
    • Repository Administration: Read and write (required for updating repository settings and rulesets)
    • Contents: Read and write (required if syncing dependabot.yml)
    • Pull Requests: Read and write (required if syncing dependabot.yml)
  2. Install it to your organization/repositories
  3. Add APP_ID and APP_PRIVATE_KEY as repository secrets
- name: Generate GitHub App Token
  id: app-token
  uses: actions/create-github-app-token@v1
  with:
    app-id: ${{ secrets.APP_ID }}
    private-key: ${{ secrets.APP_PRIVATE_KEY }}
    owner: ${{ github.repository_owner }}

- name: Update Repository Settings
  uses: joshjohanning/bulk-github-repo-settings-sync-action@v1
  with:
    github-token: ${{ steps.app-token.outputs.token }}
    # ... other inputs

Personal Access Token

Alternatively, use a PAT with repo scope:

- name: Update Repository Settings
  uses: joshjohanning/bulk-github-repo-settings-sync-action@v1
  with:
    github-token: ${{ secrets.PAT_TOKEN }}
    # ... other inputs

YAML Configuration

The repositories-file supports both simple lists and per-repository overrides:

Basic Format

repos:
  - owner/repo1
  - owner/repo2
  - owner/repo3

With Per-Repository Overrides

repos:
  - repo: owner/repo1
    allow-squash-merge: false # Override global setting
    topics: 'javascript,custom-topic'
  - repo: owner/repo2 # Uses global defaults
  - repo: owner/repo3
    enable-default-code-scanning: false
    dependabot-yml: './config/dependabot/npm-actions.yml'
    rulesets-file: './config/rulesets/custom-ruleset.json'
    pull-request-template: './config/templates/feature-template.md'

Priority: Repository-specific settings override global defaults from action inputs.

Important Notes

  • Settings not specified will remain unchanged
  • Topics replace all existing repository topics
  • Dependabot.yml syncing creates pull requests for review before merging
  • Dependabot.yml PRs use the GitHub API ensuring verified commits
  • Pull request template syncing creates pull requests for review before merging
  • Pull request templates are synced to .github/pull_request_template.md (standard location)
  • Failed updates are logged as warnings but don't fail the action
  • Access denied repositories are skipped with warnings - ensure your GitHub App has:
    • Repository Administration permissions
    • Is installed on all target repositories
  • CodeQL scanning may not be available for all languages

Contributing

See CONTRIBUTING.md for development setup, testing, and contribution guidelines.

About

⚙️ Bulk configure GitHub repository settings (squash/merge, branch deletion, features) across multiple repos or organizations

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 5