Skip to main content

gitops-replacer

License: MIT Python 3.10+ PyPI version PyPI downloads

A lightweight CLI tool that automates value updates in GitOps repositories using marker comments. Replace values across multiple GitHub repositories with a single command, enabling automated deployment workflows.

Features

  • Marker-based Approach: Uses # gitops-replacer: <name> comments to locate values
  • Format Preservation: No YAML parsing - comments, quotes, and formatting are preserved
  • Multiple Dependencies: Update different values in the same file via unique markers
  • Flexible Modes: Dry-run for validation, apply mode for commits
  • CI/CD Integration: Built-in CI mode with GITHUB_REF pattern matching
  • Multiple Repositories: Update values across any number of repos and files
  • Configuration Formats: JSON (default) and YAML support
  • Performance Optimized: Response caching eliminates duplicate API calls
  • Robust HTTP: Automatic retries, timeouts, and error handling

Requirements

  • Python 3.10+
  • A GitHub/GitHub Enterprise token with content read/write access

Installation

# Install from PyPI
pip install gitops-replacer

# Verify installation
gitops-replacer --help

From source

# Clone repository
git clone https://github.com/slauger/gitops-replacer.git
cd gitops-replacer

# Install in development mode
pip install -e .

# Or run directly
python -m gitops_replacer --help

Quick Start

  1. Add marker comments to your target files (see Marker Format)
  2. Create a configuration file (default: gitops-replacer.json)
  3. Run a dry-run:
    gitops-replacer "1.2.3"
    
  4. Apply changes (commit to target repos):
    gitops-replacer --apply "1.2.3"
    

Marker Format

Add a comment above the line you want to update:

dependencies:
  # gitops-replacer: my-app
  - name: my-app
    version: "0.0.0-e0f72bb"
    repository: oci://registry.example.com/charts

  # gitops-replacer: another-chart
  - name: another-chart
    version: "1.0.0"
    repository: oci://registry.example.com/charts

The tool will:

  1. Find the line with # gitops-replacer: <depName>
  2. Replace the value on the next line (preserving key, quotes, and formatting)

Examples

Chart.yaml (Helm dependency version):

dependencies:
  # gitops-replacer: my-app
  - name: my-app
    version: "0.0.0-e0f72bb"
    repository: oci://registry.example.com/charts

values.yaml (image tag):

# gitops-replacer: my-app-image
image: registry.example.com/myorg/my-app:1.2.3

Note: Only YAML files are supported (JSON has no comments). GitOps manifests are typically YAML.

CLI

usage: gitops-replacer [-h] [--config <file>] [--apply] [--ci]
                        [--name <string>] [--email <string>]
                        [--message <string>] [--api <string>]
                        [--verbose]
                        <string>
  • --config Path to the configuration file (default: gitops-replacer.json). JSON recommended.
  • --apply Apply changes (commit). Without this flag the tool runs in dry-run.
  • --ci CI mode: validates GITHUB_REF against when/except regex patterns from config.
  • --name Commit author name (default: env GIT_COMMIT_NAME or Replacer Bot).
  • --email Commit author email (default: env GIT_COMMIT_EMAIL or replacer-bot@localhost.localdomain).
  • --message Commit message template (default: fix: update {} to {}). First {} is depName, second is value.
  • --api GitHub API URL (default: env GITHUB_API_URL or https://api.github.com).
  • --verbose Print file contents and desired state (use with care in CI logs).
  • Positional: value - the new value to set at the marked location.

Environment

  • GITHUB_TOKEN (required) – token with access to read/write repository contents.
  • GITHUB_REF (required when --ci) – the current ref string, e.g., refs/heads/main. Falls back to GIT_REF for backwards compatibility.

Recommended token scopes:

  • Public repos only: public_repo
  • Private repos: repo
  • GitHub Enterprise: equivalent content permissions

Configuration

Default format is JSON. YAML (.yaml/.yml) is supported as well.

JSON schema (per entry)

{
  "gitops-replacer": [
    {
      "repository": "acme/gitops",
      "branch": "main",
      "file": "apps/my-app/Chart.yaml",
      "depName": "my-app",
      "when": "^refs/heads/main$"
    }
  ]
}

Fields

Field Description
repository Target repo on GitHub (ORG/REPO format)
branch Target branch
file Target file path relative to repo root
depName Dependency name (must match marker in file)
when Regex that must match GITHUB_REF when --ci is enabled (optional)
except Regex that must not match GITHUB_REF when --ci is enabled (optional)

The tool uses re.match (anchored at the string start). Use ^...$ in your patterns if you require a full match.

Examples

JSON (default)

{
  "gitops-replacer": [
    {
      "repository": "acme/gitops",
      "branch": "main",
      "file": "apps/my-app/Chart.yaml",
      "depName": "my-app",
      "when": "^refs/heads/(main|release/.*)$"
    },
    {
      "repository": "acme/gitops",
      "branch": "develop",
      "file": "apps/my-app-dev/Chart.yaml",
      "depName": "my-app",
      "except": "^refs/heads/legacy/"
    }
  ]
}

YAML (alternative)

gitops-replacer:
  - repository: acme/gitops
    branch: main
    file: apps/my-app/Chart.yaml
    depName: my-app
    when: '^refs/heads/(main|release/.*)$'
  - repository: acme/gitops
    branch: develop
    file: apps/my-app-dev/Chart.yaml
    depName: my-app
    except: '^refs/heads/legacy/'

How it works

  1. Validation: Checks CLI arguments, environment variables, and configuration file
  2. Precheck Phase: Validates access to all target repositories/files (caches responses)
  3. Replace Phase: Downloads files (reuses cached data), finds marker comments, replaces values
  4. Commit Phase: If --apply is set and changes detected, commits via GitHub Contents API
  5. Exit Codes: Returns 0 on success, non-zero on failures

Why Marker-based?

Traditional approaches parse YAML, modify the data structure, and serialize back. This often breaks:

  • Comments are lost
  • Quote styles change ("1.0" becomes '1.0' or 1.0)
  • Key ordering may change
  • Multi-line strings get reformatted

The marker-based approach works on raw text:

  • Explicit: Only marked lines are modified
  • Safe: No risk of unintended changes
  • Preserving: Comments, quotes, and formatting stay intact

Exit Codes

  • 0 success (no changes or committed changes)
  • 1 validation or API error

Use Cases

Automated Deployment Pipeline

Update chart version when a new release is built:

# In your CI/CD pipeline after publishing a chart
gitops-replacer --ci --apply "0.1.0-abc123"

Multi-Environment Updates

Use CI mode to update different environments based on branch:

{
  "gitops-replacer": [
    {
      "repository": "myorg/gitops",
      "branch": "main",
      "file": "apps/production/Chart.yaml",
      "depName": "myapp",
      "when": "^refs/heads/main$"
    },
    {
      "repository": "myorg/gitops",
      "branch": "main",
      "file": "apps/staging/Chart.yaml",
      "depName": "myapp",
      "when": "^refs/heads/(main|develop)$"
    }
  ]
}

Troubleshooting

Common Issues

401 Unauthorized

  • Verify GITHUB_TOKEN is set correctly
  • Check token has repo or public_repo scope
  • For GitHub Enterprise, confirm token has access to the organization

404 Not Found

  • Verify repository, branch, and file paths in config
  • Check branch name spelling (case-sensitive)
  • Ensure file exists at the specified path

No marker found

  • Confirm the marker comment exists in the target file
  • Check depName in config matches the marker exactly
  • Marker format: # gitops-replacer: <depName>

No changes detected

  • The current value already matches the new value
  • Use --verbose to see file contents

Debug Mode

Run with --verbose to see:

  • Full API URLs being called
  • Complete file contents before replacement
  • Desired file contents after replacement

Warning: Verbose mode may expose sensitive data in logs.

Contributing

Contributions are welcome! Please ensure:

  • Code follows existing style and patterns
  • Changes are tested with both dry-run and apply modes
  • Documentation is updated for new features

License

This project is licensed under the MIT License - see the LICENSE file for details.

Metadata

Release files for gitops-replacer 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gitops-replacer 1.0.0
File Size Uploaded Provenance
gitops_replacer-1.0.0.tar.gz 13.1 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for gitops-replacer 1.0.0
File Interpreter ABI Platform
gitops_replacer-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 23.3 kB

Release files / gitops_replacer-1.0.0.tar.gz

Download URL gitops_replacer-1.0.0.tar.gz
Size 13.1 kB
Tags Source
SHA-256 checksum
How to use checksums
181a6d730289acb88fe18faa86317a50682a6797e91e6e64b54716d3f6ff49c8
BLAKE2b-256 checksum
How to use checksums
b3507478f84f3829d7e196e53a0d04d4d21506afe1081f0062c43d205da4b0d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release files / gitops_replacer-1.0.0-py3-none-any.whl

Download URL gitops_replacer-1.0.0-py3-none-any.whl
Size 10.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1b79226dec12410c0ace1100b09c55ff131ca26dd37660592c25bd581e432b09
BLAKE2b-256 checksum
How to use checksums
df458cc7c556ffec4a7f4b00169e0785a46864a1549f9961dcc3a8fbdfbea280
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Security for gitops-replacer 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for gitops_replacer-1.0.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page