Community-maintained chart that deploys pr-generator — an automated pull request daemon for GitHub and Bitbucket Cloud, designed for ArgoCD Image Updater and GitOps workflows.
$ helm repo add helm-pr-generator https://devops-ia.github.io/helm-pr-generator $ helm repo update $ helm install pr-generator helm-pr-generator/pr-generator \ --set config.providers.github.owner=my-org \ --set config.providers.github.repo=my-repo \ --set config.providers.github.appId="123456" \ --set secrets.github.privateKey="$(cat github-app.pem)"
Features
Production-ready defaults with security hardening, flexible multi-provider support, annotation-based ArgoCD discovery, and built-in Prometheus observability.
Supports GitHub App (PEM key) and Personal Access Token auth. Switch per provider with authMethod.
Full Bitbucket Cloud support via access token. Run GitHub and Bitbucket providers side by side.
Declare multiple named provider instances — different GitHub orgs, multiple Bitbucket workspaces — all in one deployment.
Non-root user, read-only filesystem, dropped capabilities, automountServiceAccountToken: false, and dedicated ServiceAccount.
Pod annotation checksum/config triggers a rolling restart whenever config.* values change. No manual rollout needed.
PodDisruptionBudget protects against involuntary eviction. Liveness, readiness, and startup probes are all configurable.
Chart-managed inline secrets or existingSecret for External Secrets Operator and Vault integration.
Enable config.dryRun: true to simulate PR creation without touching any repository. Safe to test in production clusters.
Designed to pair with ArgoCD Image Updater. Watches branches created by the updater and opens PRs automatically.
Each ArgoCD Application declares its own PR rules via annotations. Three modes: config_only, annotations_only, hybrid.
Built-in /metrics endpoint with counters, histograms, and gauges. Pod annotations and ServiceMonitor included.
Usage
Helm must be installed. Once set up, add this repository and install the chart.
# Add the repository $ helm repo add helm-pr-generator https://devops-ia.github.io/helm-pr-generator $ helm repo update # Install with GitHub App authentication $ helm install pr-generator helm-pr-generator/pr-generator \ --namespace pr-generator --create-namespace \ --set config.providers.github.owner=my-org \ --set config.providers.github.repo=my-repo \ --set config.providers.github.appId="123456" \ --set config.providers.github.installationId="78901234" \ --set secrets.github.privateKey="$(cat github-app.pem)"
$ helm install pr-generator helm-pr-generator/pr-generator \ --namespace pr-generator --create-namespace \ --set config.providers.github.authMethod=pat \ --set config.providers.github.owner=my-org \ --set config.providers.github.repo=my-repo \ --set secrets.github.token="ghp_xxxx"
$ helm repo update $ helm upgrade pr-generator helm-pr-generator/pr-generator
ArgoCD Image Updater
pr-generator is designed to close the loop when ArgoCD Image Updater pushes a commit to a new branch. Configure it to watch that branch pattern and open the PR automatically.
config: scanFrequency: 300 providers: github: enabled: true owner: my-org repo: my-app appId: "123456" installationId: "78901234" rules: - pattern: "argocd-image-updater-.*-dev-.*" # regex matching Image Updater branches destinations: github: develop - pattern: "argocd-image-updater-.*-pro-.*" destinations: github: main secrets: github: existingSecret: github-app-secret # key: private-key.pem
config.dryRun: true first to verify branch matching before enabling live PR creation.
The daemon logs which branches matched each rule on every scan cycle.
ArgoCD annotation discovery
Let each ArgoCD Application declare its own PR rules via annotations — no central
config.rules change needed when onboarding a new application. Mirrors the model used by ArgoCD Image Updater.
annotationDiscovery: enabled: true mode: hybrid # config_only | annotations_only | hybrid annotationPrefix: "pr-generator.io"
apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: my-app namespace: argocd annotations: pr-generator.io/enabled: "true" pr-generator.io/pattern: "argocd-image-updater-.*-dev-.*" pr-generator.io/destination.github: "develop" pr-generator.io/destination.bitbucket: "dev"
ClusterRole and
ClusterRoleBinding granting the chart ServiceAccount get/list on
applications.argoproj.io cluster-wide. Requires serviceAccount.create: true.
Observability
Built-in /metrics endpoint (Prometheus format) on the health port (8080).
Enabled by default — no extra configuration required for basic scraping.
| Metric | Type | Description |
|---|---|---|
pr_generator_prs_created_total | Counter | PRs successfully created, labelled by provider and destination |
pr_generator_prs_skipped_total | Counter | PRs skipped because one already exists |
pr_generator_prs_failed_total | Counter | PR creation failures, labelled by error type |
pr_generator_scan_cycles_total | Counter | Completed scan cycles by result (success / partial / error) |
pr_generator_scan_duration_seconds | Histogram | Wall-clock duration of each scan cycle |
pr_generator_rules_active | Gauge | Active scan rules at end of last cycle |
pr_generator_annotation_rules_discovered | Gauge | Rules discovered from ArgoCD Application annotations |
pr_generator_provider_errors_total | Counter | Provider-level errors by provider and error type |
pr_generator_up | Gauge | 1 after first successful scan cycle, 0 on startup |
$ kubectl port-forward svc/pr-generator 8080:8080 -n pr-generator $ curl -s http://localhost:8080/metrics | grep pr_generator
metrics: enabled: true serviceMonitor: enabled: true # requires Prometheus Operator CRDs interval: 30s scrapeTimeout: 10s labels: release: kube-prometheus-stack # must match serviceMonitorSelector
Configuration
Common values to get started. Full reference at values.yaml.
| Parameter | Description | Default |
|---|---|---|
config.scanFrequency |
Seconds between branch scan cycles. | 300 |
config.dryRun |
Simulate PR creation without modifying repositories. | false |
config.providers.github.enabled |
Enable the GitHub provider instance. | false |
config.providers.github.authMethod |
app (GitHub App PEM) or pat (Personal Access Token). |
"app" |
config.providers.github.owner |
GitHub org or user that owns the repository. | "" |
config.providers.github.repo |
Repository name (without org prefix). | "" |
config.providers.github.appId |
GitHub App ID (string). Required when authMethod: app. |
"" |
config.rules |
List of rules: pattern (regex) + destinations map of provider-key → branch. Can be empty when annotationDiscovery.mode: annotations_only. |
[] |
secrets.github.existingSecret |
Name of an existing Secret with the GitHub credential key. Shared by all GitHub providers. | "" |
secrets.bitbucket.existingSecret |
Name of an existing Secret with the Bitbucket credential key. Shared by all Bitbucket providers. | "" |
annotationDiscovery.enabled |
Read ArgoCD Application CRs to derive scan rules. Creates ClusterRole + ClusterRoleBinding automatically. | false |
annotationDiscovery.mode |
config_only, annotations_only, or hybrid. |
"hybrid" |
metrics.enabled |
Expose /metrics (Prometheus format) on the health port. Adds pod scrape annotations. |
true |
metrics.serviceMonitor.enabled |
Create a Prometheus Operator ServiceMonitor. Requires Operator CRDs installed. |
false |
serviceAccount.create |
Create a dedicated ServiceAccount with automountServiceAccountToken: false. |
true |
podDisruptionBudget.enabled |
Create a PodDisruptionBudget to protect against involuntary eviction. | false |
resources |
Pod resource requests and limits. | {} |
image.tag |
Image tag. Defaults to chart appVersion when empty. |
"" |
Troubleshooting
Most issues come down to auth configuration or branch pattern matching.
Check the daemon logs first:
kubectl logs -n pr-generator deploy/pr-generator -f
Common causes:
config.dryRun is true — PRs are simulated but not created.enabled: false).Two separate issues:
privateKeyKey (default: privateKey). The PEM must be the complete RSA key including header/footer lines.installationId must be the numeric ID shown on the GitHub App installation settings page, not the App ID.kubectl get secret <github-secret> -o jsonpath='{.data.privateKey}' | base64 -d | head -1
# should print: -----BEGIN RSA PRIVATE KEY-----
Each provider of the same type must use a unique tokenEnv value. If two Bitbucket providers share the same env var name, the daemon raises a ValueError at startup to prevent silent credential overwrite.
config:
providers:
bitbucket:
tokenEnv: BITBUCKET_TOKEN # provider 1
bitbucket-org2:
type: bitbucket
tokenEnv: BITBUCKET_ORG2_TOKEN # must be different
The values.schema.json requires appId and installationId to be strings. When using --set on the CLI, Helm auto-parses numeric values as integers. Use quotes:
helm install ... --set config.providers.github.appId="123456" # ^ ^ # quoted string
Or use a values file where YAML quotes are explicit.