Help us shape the future of Go! Take the 2026 Go Developer Survey

argo-diff

module
v0.0.0-...-e5aad21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2026 License: Apache-2.0

README

Argo-Diff

An application written in go that provides Pull Request comments for changes to Kubernetes manifests when those manifests are delivered via ArgoCD:

Example argo-diff comment showing a container image change

Contents

Overview

Argo-diff is designed to receive webhook notifications from GitHub for pull_request and issue_comment events. When events are received, it uses the ArgoCD CLI to identify the ArgoCD application(s) that are configured with the pull request's repository as a source and to generate a diff of those applications against the live state.

Argo-diff will comment on the associated pull request with markdown displaying the diffs for the applications with potential changes.

Argo-diff will not run when the base branch of the pull request (the branch it will be merged into) is not the target revision for the Argo application. (eg: your Argo application targets production, but your PR is to be merged into dev.)

Why argo-diff?

There are multiple ways to produce diff previews of proposed manifest changes to ArgoCD applications in GitHub Pull Requests, but they often require per-repository configuration. Because argo-diff is triggered by GitHub event notifications, and because argo-diff auto-discovers ArgoCD applications configured in the source code repository, no configuration is needed when repositories and/or ArgoCD applications are added and removed.

Argo-diff natively supports ArgoCD's manifest-generate-paths annotation. This annotation is useful for monorepos that contain the manifests for many ArgoCD applications. For applications with it set, ArgoCD will only attempt to produce diffs for the applications whose manifest-generate-paths match the pull request's files changed (which is fetched via the GitHub API).

Argo-diff supports multi-source ArgoCD applications, including helm applications whose Application specs are managed by ArgoCD. This means if, in source control, you have a pull request that updates the chart version in the Application spec of a helm application, argo-diff will produce a diff of the affected application.

Argo-diff can also be quickly deployed via GitHub Actions.

Example argo-diff Comments

You can view example comments generated by argo-diff in PRs opened in this repo:

Those comments are generated by a Github actions workflow that performs an end-to-end test of new builds.

The first comment demonstrates generic manifest changes, including a cascading app-of-apps change (meta) that triggers downstream changes to a child application (helm-deployment).

The second comment shows the UX when the proposed manifests generate an error (broken-deployment).

Deploying as a Webhook receiver

Deploying argo-diff as a long-running webhook receiver takes five steps: grant it access to the GitHub API, create a read-only ArgoCD user, generate a shared webhook secret, deploy it to Kubernetes, and point GitHub webhooks at it.

1. Grant access to the GitHub API

Access can be granted either via a Personal Access Token (good for small environments or a proof of concept) or a GitHub App.

Option A — Personal Access Token (PAT)

  • It is recommended to create a separate GitHub account in your organization specifically for argo-diff.
  • argo-diff looks for the PAT in the GITHUB_TOKEN or GITHUB_PERSONAL_ACCESS_TOKEN env var.
  • The PAT's permissions should match the GitHub App permissions listed below.

Option B — GitHub App

Create a new application in your organization under Developer Settings:

  • Name can be anything, e.g. argo-diff. argo-diff identifies its own PR comments using the App's slug (the URL-friendly form of the name GitHub derives automatically), not the display name, so any name works.
  • Homepage URL can be the base URL of your ArgoCD instance or of your webhook URL.
  • Callback URL and Setup URL should be empty.
  • Webhooks should not be active.
  • Permissions:
    • Administration: Read-only
    • Commit statuses: Read and write
    • Metadata: Read-only
    • Pull requests: Read and write
  • Where can this GitHub App be installed? → Only on this account
  • After creating the App, note the App ID, then generate a new Private Key (this downloads a .pem file locally).
  • Install the App to your organization. The installation settings URL looks like /organizations/<ORG_NAME>/settings/installations/<INSTALLATION_ID> — note the installation id from it.
  • argo-diff reads the App configuration from the GITHUB_APP_ID, GITHUB_APP_INSTALLATION_ID, and GITHUB_APP_PRIVATE_KEY env vars (the last being the contents of the .pem file above).
2. Create an ArgoCD user

Create a user in your ArgoCD instance with read-only access to all applications.

  • If you installed ArgoCD from its Helm chart, add an argo-diff user via the chart's values:
    configs:
      cm:
        accounts.argodiff: apiKey
        accounts.argodiff.enabled: "true"
    
  • In policy.csv: g, argodiff, role:ci and p, role:ci, applications, get, *, allow. (This may not be needed if users in your ArgoCD installation default to the role:readonly role.)
  • This user doesn't need a password but does need an API token, which an admin can generate via the UI or CLI. Use the generated token as the value of ARGOCD_AUTH_TOKEN.
3. Generate a webhook secret

Generate a webhook secret that is shared by both the argo-diff deployment and the GitHub webhook configuration.

4. Deploy to Kubernetes
  • Recommended: use the Helm chart in charts/argo-diff/:
    helm install my-release oci://ghcr.io/vince-riv/chart/argo-diff
    
    To run an argocd CLI version other than the one baked into the argo-diff image, set the chart's argocdCli.image.tag value — see charts/argo-diff/README.md.
  • Alternatively, use the example manifests in docs/k8s/ to deploy argo-diff to the argocd namespace of your cluster. You'll need to add an Ingress or IngressRoute so GitHub can reach the /webhook endpoint on the argo-diff Service.
5. Configure GitHub webhooks

Configure organization-level (or repository-level) webhook notifications to argo-diff. The Payload URL should map to the ingress configured in your cluster, and the secret should be the webhook secret generated above. Enable these event types:

  • Issue comments — lets a comment of argo diff (customizable via ARGO_DIFF_REFRESH_COMMENT_KEYWORDS) re-trigger argo-diff on the pull request.
  • Pull requests

Note: argo-diff only supports pull request events. Push events to branches are ignored.

After the webhook is activated, argo-diff should receive and verify the ping event, confirming connectivity from GitHub to argo-diff.

GitHub Actions

argo-diff can also run as a GitHub Action. This requires that your ArgoCD instance be reachable from the GitHub Actions runner — either ArgoCD is publicly available (and you accept the associated risks) or you use self-hosted runners within your environment.

The upside is that neither a GitHub account nor a GitHub App needs to be provisioned; you only need an ArgoCD user for argo-diff:

  • Create a read-only ArgoCD user as described in step 2 above.
  • Save its API token to the repository's Actions secrets and pass it to the argocd_auth_token input.

The downside is that GitHub workflows are typically managed on a repo-by-repo basis, and performance is a little slower than the deployed version.

Here's an example workflow snippet, assuming a self-hosted runner and that an ArgoCD auth token has been added to the repository's secrets:

---

on:
  pull_request:
    branches: [main]
    # `edited` covers stacked PRs: GitHub retargets them when their parent merges (see note below)
    types: [opened, synchronize, reopened, edited]

permissions:
  pull-requests: write

jobs:
  argo-diff:
    runs-on: [self-hosted]  # remove when running on GitHub's public runners and ArgoCD is publicly available
    name: Argo Diff
    # run on every edit that changed the base branch, and skip title/body edits
    if: github.event.action != 'edited' || github.event.changes.base.ref.from != ''
    steps:
      - name: ArgoCD Diff
        id: argo-diff
        uses: vince-riv/argo-diff@v3  # or pin an exact release, e.g. @2.10.0
        with:
          argocd_auth_token: ${{ secrets.ARGOCD_AUTH_TOKEN }}
          argocd_server: argocd-server.argocd.svc.cluster.local:80  # argocd.domain.example when publicly available via https
          argocd_server_insecure: true                              # typically false when publicly available via https
          argocd_server_plaintext: true                             # typically false when publicly available via https
          argocd_ui_base_url: https://argocd.domain.example
          argocd_grpc_web: true
          github_token: ${{ secrets.GITHUB_TOKEN }}
          log_level: trace
          repo_default_ref: main

Stacked pull requests: when a pull request's base branch merges, GitHub retargets the pull requests stacked on top of it. That retarget arrives as a pull_request event with the edited action, not synchronize, so a workflow on the default activity types never runs on a stacked pull request — its earlier events were filtered out by branches: [main] while the base was still a feature branch. Listening to edited closes that gap. Keep the if condition alongside it: GitHub also sends edited for title and body edits, and it populates changes.base.ref.from only when the base branch itself changed. argo-diff itself does not filter on the action type under GitHub Actions, and it reads the pull request's current head and base from the API on every run, so the run triggered by the retarget diffs against the new base.

Note: the deployed webhook service also handles this case. It acts on the opened and synchronize actions, and on edited when the payload's changes.base.ref.from field is set — the same signal used above — so a stacked pull request's retarget triggers a run there too, with no extra webhook configuration needed. An ordinary title or body edit still sends edited but leaves that field empty, so it is ignored as before. If a retarget is ever missed, comment argo diff on the pull request to trigger a run by hand.

Note: Releases were previously published under an actions-vX.Y.Z tag prefix (with a floating actions-vX major tag). As of 3.0.0, the actions-* tags are deprecated and will not be maintained.

Configuration

When deployed as a web service, argo-diff accepts all configuration options via environment variables. When used via GitHub Actions, the relevant options are accepted via inputs. The following table describes the accepted environment variables and their respective GitHub Actions inputs.

Important: ARGO_DIFF_SCM_PROVIDERS selects the source control providers (default: github), and each one listed needs valid credentials. For GitHub, either the GITHUB_APP_* variables must be set, or GITHUB_TOKEN / GITHUB_PERSONAL_ACCESS_TOKEN must be set. For GitLab, GITLAB_TOKEN must be set. To use GitLab, set ARGO_DIFF_SCM_PROVIDERS to gitlab, or github,gitlab for both.

Many of these variables have a typed Helm values key (config.*, logLevel, secret.*) — see charts/argo-diff/README.md. Any variable without a typed key — including ones not listed here — can still be set through the chart's deployment.env / deployment.envFrom passthrough values.

Environment Variable Input Name Required Default Description
APP_ENV N/A no Set to dev during local development.
ARGOCD_AUTH_TOKEN argocd_auth_token yes Bearer token for ArgoCD (value passed to --auth-token).
ARGOCD_APP_DIFF_OPTS argocd_app_diff_opts no Extra flags appended to every argocd app diff command, and only that command, after argo-diff's own flags. Split like a shell would, so quote a value that contains spaces. Example: --server-side-diff-concurrency=1, which stops large server-side diffs from running all their batches at once. argo-diff fails at startup if it contains an app diff flag it sets itself (--revision, --revisions, --source-positions, --source-names, --app-namespace/-N, --server-side-diff), a flag that changes the exit code (--exit-code, --diff-exit-code), a flag that diffs against something other than the PR revision (--local, --local-repo-root, --server-side-generate, --local-include), a global flag argo-diff sets from its own variables (--server, --auth-token, --insecure, --plaintext, --grpc-web, --grpc-web-root-path), or --header/-H (argo-diff logs these flags, so put headers in ARGOCD_OPTS). It also fails at startup on a word that is not a flag and does not follow one, or a bare --: the CLI would take it as a second application name. Write flags as --flag=value.
ARGOCD_APP_DIFF_SERVER_SIDE_DIFF argocd_app_server_side_diff no Set --server-side-diff for argocd app diff (true/false).
ARGOCD_CLI_CMD_NAME N/A no argocd Overrides the argocd CLI command name (e.g., to use a specific argocd version); accepts either a bare command name on PATH or an absolute path to the binary. Discovering app-of-apps children of an Application that lives outside ArgoCD's own namespace (most commonly argocd) requires CLI version >= 3.5.0.
ARGOCD_GRPC_WEB argocd_grpc_web no false Set --grpc-web flag for argocd cli (true/false).
ARGOCD_GRPC_WEB_ROOT_PATH argocd_grpc_web_root_path no Value for --grpc-web-root-path for argocd cli.
ARGOCD_OPTS argocd_opts no Additional flags for argocd cli. The argocd CLI reads it only for global flags (eg: --header, --grpc-web); use ARGOCD_APP_DIFF_OPTS for argocd app diff flags.
ARGOCD_SERVER_ADDR argocd_server yes ArgoCD server name (value passed to --server).
ARGOCD_SERVER_INSECURE argocd_server_insecure no false Set --insecure flag for argocd cli (true/false).
ARGOCD_SERVER_PLAINTEXT argocd_server_plaintext no false Set --plaintext flag for argocd cli (true/false).
ARGOCD_UI_BASE_URL argocd_ui_base_url no Base URL of ArgoCD UI (usually the server name prefixed with https://).
ARGO_DIFF_BYPASS_CONNECTIVITY_CHECKS N/A no Comma-separated list of startup connectivity checks to skip: github, gitlab, argocd, true/all for every one, or false/none (default, skips nothing). Useful when GITHUB_TOKEN holds a GitHub App installation token, which can't call GET /user (a per-PR CI invocation minting its own token, eg: from Jenkins, is the common case — GitHub Actions mode doesn't need this, it already skips the check); for that case, bypass github specifically rather than true/all. Bypassing github also makes argo-diff match its own prior PR comments by marker only, the same as it does under GitHub Actions — so two instances sharing an empty ARGO_DIFF_CONTEXT_STR on one PR will overwrite each other's comments. Bypassing gitlab does the same for GitLab merge request notes. Bypassing argocd skips reachability and the minimum ArgoCD version check (client and server must be 2.12.0+), so it also silently drops that guard.
ARGO_DIFF_COMMENT_COLLAPSE comment_collapse no expanded Whether the collapsible sections in a PR comment start open. expanded (default) always starts them open; collapsed always starts them folded; auto folds ignorable resource diffs and keeps everything else open. With ARGO_DIFF_COMMENT_COLLAPSE_IGNORABLE=false, auto instead keeps a small comment fully expanded, folds an application's own block once the comment covers more than ARGO_DIFF_COMMENT_COLLAPSE_APP_COUNT applications, and folds an application's individual resource (diff) blocks once that application has more than ARGO_DIFF_COMMENT_COLLAPSE_RESOURCE_COUNT changed resources.
ARGO_DIFF_COMMENT_COLLAPSE_APP_COUNT comment_collapse_app_count no 3 In auto collapse mode with ARGO_DIFF_COMMENT_COLLAPSE_IGNORABLE=false (it has no effect otherwise), the application count above which each application's own block starts folded. Must be positive; a non-positive value warns and falls back to the default.
ARGO_DIFF_COMMENT_COLLAPSE_RESOURCE_COUNT comment_collapse_resource_count no 5 In auto collapse mode with ARGO_DIFF_COMMENT_COLLAPSE_IGNORABLE=false (it has no effect otherwise), the count of changed resources within an application above which that application's individual resource (diff) blocks start folded — not the application's own block, which is governed by ARGO_DIFF_COMMENT_COLLAPSE_APP_COUNT. Must be positive; a non-positive value warns and falls back to the default.
ARGO_DIFF_COMMENT_COLLAPSE_IGNORABLE comment_collapse_ignorable no true In auto collapse mode, fold resource diffs whose every changed line matches an ignorable regex, and ignore the two count thresholds. false brings the count thresholds back. Case-insensitive; any other value warns and means true. No effect outside auto mode. See Folding ignorable diffs.
ARGO_DIFF_COMMENT_COLLAPSE_IGNORABLE_REGEXES comment_collapse_ignorable_regexes no built-in defaults Newline-separated RE2 regexes. A changed diff line is ignorable if it matches one. A value replaces the defaults; [] means no global regexes. See Folding ignorable diffs.
ARGO_DIFF_COMMENT_COLLAPSE_IGNORABLE_EXCLUDE_KINDS comment_collapse_ignorable_exclude_kinds no argoproj.io/* Comma- or newline-separated group/Kind, group/* or Kind (core group) entries that never fold. A value replaces the default; [] excludes nothing.
ARGO_DIFF_COMMENT_INDEX_COUNT comment_index_count no 2 When to render the summary index — a table of every application with its change count, sync status and health — above the diffs. -1 always renders it, 0 never does, and any other number is the count of applications at which it starts rendering.
ARGO_DIFF_COMMENT_MAX_CHARS comment_max_chars no 262144 Maximum size of a single PR comment, in bytes; argo-diff splits its output across more comments to stay under it. The default is the provider's own limit and cannot be raised: 262144 on GitHub, 1048576 (1 MiB) on GitLab. Lower it for a GitHub Enterprise instance with a smaller cap. The operator preamble and argo-diff's HTML marker count against this.
ARGO_DIFF_COMMENT_NOTICE comment_notice no Advisory text rendered as a note at the top of the PR comment — a deprecation warning, say, or a caveat about this environment. Separate several notices with |. Rendered distinctly from argo-diff's own warnings and errors.
ARGO_DIFF_COMMENT_PREAMBLE comment_preamble no String/markdown prefixed to comments. Keep to 150 chars or less.
ARGO_DIFF_CONTEXT_STR context_str no Unique identifier of the argo-diff instance. Use when deploying multiple instances (eg: one per cluster); a brief cluster nickname is recommended.
ARGO_DIFF_DISABLE_NON_GITHUB_REPO_MATCH N/A no false Set to true to disable matching ArgoCD application sources on non-github.com git hosts (GitHub Enterprise, AWS CodeConnections, GitLab, mirrors, etc.) by owner/repo path suffix; matching on github.com URLs is unaffected. (Strictly: matching stays on for the hosts of the change's own source control provider: github.com for GitHub pull requests, the host of GITLAB_BASE_URL for GitLab merge requests.) With both GitHub and GitLab enabled, set this to true if you mirror repositories under the same owner/repo path on both hosts; otherwise a change on one host also matches applications sourced from the mirror.
ARGO_DIFF_MAX_WORKERS max_workers no 4 Max number of ArgoCD applications diffed concurrently (capped at 32). Raising this speeds up runs that match many applications, at the cost of more concurrent load on the ArgoCD repo-server; pair a higher value with a longer ARGO_DIFF_TIMEOUT if the repo-server is slow under that load.
ARGO_DIFF_REFRESH_COMMENT_KEYWORDS N/A no argo diff,argo-diff Comma-separated list of PR comments (case-insensitive, trimmed) that re-trigger argo-diff, replacing the default keywords. Each keyword also matches with a trailing ARGO_DIFF_CONTEXT_STR suffix (eg: argo diff prod). Only takes effect when deployed as a webhook service — GitHub Actions mode doesn't process issue_comment events.
ARGO_DIFF_REQUIRE_APP_MATCH N/A no false Set to true to check for a matching ArgoCD application before posting anything to GitHub, and stay completely silent (no commit status, no comment) when nothing matches, instead of posting a pending status up front followed by an unconditional success. Mainly useful when deployed as a webhook server installed org-wide: without it, every PR in every repo the GitHub App can see gets an argo-diff commit status, even repos ArgoCD doesn't track, which tends to confuse people. The match check itself is cheap (one argocd app list call plus local filtering, no argocd app diff calls), but it does mean one extra argocd app list call on PRs that do match, and it skips clearing a stale prior comment if a later push makes a previously-matching PR stop matching. Has no effect in GitHub Actions mode — it skips commit statuses already and only runs in repos the action was added to, so there is no chatter to suppress; argo-diff logs a warning if the flag is set there.
ARGO_DIFF_SCM_PROVIDERS N/A no github Comma-separated list of the source control providers argo-diff runs for: github, gitlab (eg: gitlab, or github,gitlab for both). Case-insensitive. Each provider listed needs its credentials; a provider not listed is ignored even when its credentials are set. An unknown name stops argo-diff at startup.
ARGO_DIFF_TIMEOUT timeout no 3m How long argo-diff may spend generating diffs for a single event, as a Go duration (eg: 5m, 90s); a bare integer is treated as seconds. Raise this when a change matches many ArgoCD applications, since each one costs a round trip to the argocd server. Reporting results to GitHub gets up to 30 seconds on top of this, so a run can take that much longer than the value set here. Any applications left undiffed when the time runs out are named in a warning in the PR comment, and the run is failed — a failed step under GitHub Actions (commit statuses are skipped there), or a failure commit status when deployed as a service.
COMMENT_LINE_MAX_CHARS comment_line_max_chars no 175 Individual lines in argo-diff PR comments longer than this are truncated.
GITHUB_APP_ID N/A no GitHub Application Id (see deployment instructions).
GITHUB_APP_INSTALLATION_ID N/A no GitHub Application Installation Id (see deployment instructions).
GITHUB_APP_PRIVATE_KEY N/A no GitHub Application Private Key (see deployment instructions).
GITHUB_PERSONAL_ACCESS_TOKEN N/A no Bearer token for GitHub API calls; same as GITHUB_TOKEN.
GITHUB_TOKEN github_token yes for GHA Bearer token for GitHub API calls (in a GitHub Actions workflow, usually secrets.GITHUB_TOKEN). Required in GitHub Actions.
GITHUB_WEBHOOK_SECRET N/A yes for deployed Shared secret for GitHub webhook validation. Required when deployed.
GITLAB_BASE_URL N/A no https://gitlab.com URL of the GitLab instance, eg: https://gitlab.example.com. Falls back to CI_SERVER_URL, then gitlab.com.
GITLAB_CA_FILE N/A no Path to a PEM bundle of extra CA certificates to trust for a self-managed GitLab instance. Falls back to CI_SERVER_TLS_CA_FILE.
GITLAB_TOKEN N/A yes for GitLab GitLab access token (personal, project or group access token with api scope). Required when ARGO_DIFF_SCM_PROVIDERS lists gitlab. CI_JOB_TOKEN cannot be used: it cannot write merge request notes. GitLab support is in progress: today it works with -f event files only (see Running locally).
LOG_LEVEL log_level no info Log level of argo-diff.
REPO_DEFAULT_REF repo_default_ref no Default branch of the repository (eg: main). Only needed in GitHub Actions when HEAD is specified as the target revision in the ArgoCD application source.

Note: When running via GitHub Actions, argo-diff uses the following environment variables set by GitHub: GITHUB_ACTIONS, GITHUB_BASE_REF, GITHUB_EVENT_NAME, GITHUB_HEAD_REF, GITHUB_REF, and GITHUB_REPOSITORY. Do not set these yourself.

Folding ignorable diffs

Behavior change: ARGO_DIFF_COMMENT_COLLAPSE_IGNORABLE defaults to true, so operators who already set ARGO_DIFF_COMMENT_COLLAPSE=auto see different folding: ignorable resources fold, everything else stays open, and ARGO_DIFF_COMMENT_COLLAPSE_APP_COUNT / ARGO_DIFF_COMMENT_COLLAPSE_RESOURCE_COUNT stop having an effect. Set ARGO_DIFF_COMMENT_COLLAPSE_IGNORABLE=false to keep the old auto behavior. The default mode (expanded) is unchanged.

In auto mode, argo-diff folds every resource diff in which every changed line matches a regex, and keeps all other diffs open. The main use case is a Helm chart bump, where most resources change only the chart and app version labels. A folded diff keeps its full text one click away, and shows 🔕 ignorable in its summary. The comment also says how many resources started folded.

Is it on?

ARGO_DIFF_COMMENT_COLLAPSE ARGO_DIFF_COMMENT_COLLAPSE_IGNORABLE Result
expanded (default), empty, unknown, or collapsed any Off. Output does not change.
auto true (default) On. Ignorable resources fold. An application folds only when all its resources are ignorable. The _APP_COUNT and _RESOURCE_COUNT thresholds have no effect.
auto false Off. auto uses the _APP_COUNT and _RESOURCE_COUNT thresholds.

How do I opt an application in or out? Annotate the ArgoCD Application that argo-diff diffs. All three annotations work only when the feature is on globally; none can turn it on.

Global regexes Application annotations What folds in this application
defaults or a custom list none Resources that match the global regexes
defaults or a custom list collapse-ignorable-regexes Resources that match the global regexes plus the application regexes
[] none Nothing (the application is not opted in)
[] collapse-ignorable-regexes Resources that match the application regexes (opt-in)
any collapse-ignorable: "false" Nothing (opt-out; wins over everything else)

In every row, excluded kinds never fold, unless collapse-ignorable-include-kinds names them.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  annotations:
    # "false" opts this application out. "true" is the default
    argo-diff.vince-riv.io/collapse-ignorable: "true"
    # newline-separated RE2 regexes, added to the global list
    argo-diff.vince-riv.io/collapse-ignorable-regexes: |
      ^\s*image:\s+registry\.example\.com/
    # lifts global exclusions for this application: group/Kind, group/* or Kind, comma or newline separated
    argo-diff.vince-riv.io/collapse-ignorable-include-kinds: argoproj.io/Application

The annotations belong on the Application being diffed. For an argoproj.io/Application resource inside an app-of-apps diff, that is the parent Application, not the child. argo-diff reads the live Application, so an annotation that a pull request adds or changes takes effect only after that Application syncs. An invalid annotation entry never fails a run: argo-diff skips it, logs a warning, and adds a note to that application's block.

What folds?

  • A changed line is a line of the unified diff that starts with + or -. The --- and +++ file headers, context lines and @@ lines do not count.
  • argo-diff removes one leading +/- and keeps the indentation. A resource is ignorable when it is not excluded, has at least one changed line, and every changed line matches at least one regex.
  • Matching is an unanchored RE2 search on the diff text. Anchor your regexes with ^ and $.
  • A resource with no changed lines never folds.

Default regexes (used when ARGO_DIFF_COMMENT_COLLAPSE_IGNORABLE_REGEXES is unset or empty):

^\s*app\.kubernetes\.io/version:\s
^\s*(helm\.sh/)?chart:\s+["']?[A-Za-z0-9][-A-Za-z0-9_.]*-v?\d+\.\d+\.\d+[-+A-Za-z0-9_.]*["']?\s*$
^\s*controller-gen\.kubebuilder\.io/version:\s+["']?v?\d+\.\d+\.\d+[-+A-Za-z0-9_.]*["']?\s*$

They match the app version label, the helm.sh/chart label (and the legacy chart label, which needs a <name>-<semver> value), and the CRD controller-gen version annotation. They deliberately do not match image tags or checksum/* annotations, so a chart bump that changes an image stays visible. A value of this variable replaces the defaults: copy the list above and extend it. Separate regexes with newlines, because regexes often contain , and |. Blank lines and lines that start with # are skipped; to match a literal leading #, write \# or [#]. Each list holds at most 32 entries of at most 1024 bytes. An invalid regex is skipped with a warning and a note in the comment. If every entry is invalid, the list is empty; it does not fall back to the defaults.

Warning: a regex that is too greedy can fold a diff that a reviewer needs to see. Keep regexes narrow and anchored. Choosing them is the operator's responsibility.

Excluded kinds. Some resources must stay visible even when every changed line matches, because they change what the cluster runs or who can do what. ARGO_DIFF_COMMENT_COLLAPSE_IGNORABLE_EXCLUDE_KINDS lists them. The default is argoproj.io/* (Application, ApplicationSet, AppProject, ...). Entries:

  • group/Kind: one kind, for example rbac.authorization.k8s.io/ClusterRole
  • group/*: every kind in a group
  • Kind or /Kind: a kind in the core group, for example Secret

Matching is exact on the group and case-insensitive. * as a group is not supported, and neither is a bare group such as argoproj.io (use argoproj.io/*). To also keep every ClusterRole visible: ARGO_DIFF_COMMENT_COLLAPSE_IGNORABLE_EXCLUDE_KINDS=argoproj.io/*,rbac.authorization.k8s.io/ClusterRole. The exclusion covers only a resource's own group: the CustomResourceDefinition that defines an argoproj.io kind belongs to apiextensions.k8s.io. An application lifts exclusions for itself with collapse-ignorable-include-kinds.

The [] value. An unset or empty variable means "use the defaults". To say "none", set the variable to exactly []. With ARGO_DIFF_COMMENT_COLLAPSE_IGNORABLE_REGEXES=[], only applications that carry the collapse-ignorable-regexes annotation fold anything. That is the way to opt in per application only.

Running locally

Set the environment variables used by argo-diff and then execute go run cmd/main.go.

For example, you can place these in a file called .env.sh:

GITHUB_PERSONAL_ACCESS_TOKEN='github_pat_XXXX'
ARGOCD_AUTH_TOKEN='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
ARGOCD_SERVER_ADDR='argocd.your.domain:443'
ARGOCD_UI_BASE_URL='https://argocd.your.domain'
APP_ENV='dev'

Then source it and start the server:

$ set -o allexport ; . .env.sh ; set +o allexport
$ go run cmd/main.go

Or run it once to process a manually crafted event file:

$ set -o allexport ; . .env.sh ; set +o allexport
$ go run cmd/main.go -f path/to/event_info.json

Note: argo-diff shells out to the argocd CLI, so a compatible argocd binary must be on your PATH (override the command name, or point at an absolute path, with ARGOCD_CLI_CMD_NAME).

Craft a local file with event data

When running locally, the easiest way to trigger argo-diff is to create a JSON file that can be unmarshalled into an EventInfo struct (defined in internal/webhook/process.go):

{
    "provider": "github",
    "ignore": false,
    "owner": "GITHUB_ORG_NAME",
    "repo": "REPOSITORY_NAME",
    "default_ref": "main",
    "commit_sha": "LONG_SHA_OF_COMMIT",
    "pr": 123,
    "change_ref": "BRANCH_NAME_OF_PR",
    "base_ref": "main"
}

Description of those fields:

  • provider: the source control provider, github or gitlab; optional, defaults to github
  • ignore: tells argo-diff to ignore the event
  • owner: GitHub organization name, or the GitLab namespace path, which may hold nested groups (eg: group/subgroup)
  • repo: GitHub repository name, or the GitLab project name
  • default_ref: the default branch of the repository
  • commit_sha: the sha that triggered the event — should be HEAD of the branch of the PR if you want it to comment
  • pr: pull request number (duh), or the merge request IID on GitLab (the !123 number)
  • change_ref: the source branch of the PR (the feature branch)
  • base_ref: the branch to which the PR is getting merged
  • refresh: optional; when true, argo-diff reads commit_sha, change_ref and base_ref from the PR/MR itself

This JSON file can be passed to argo-diff via the -f argument or posted to the /dev HTTP endpoint.

For a GitLab merge request, set ARGO_DIFF_SCM_PROVIDERS=gitlab (or github,gitlab), set GITLAB_TOKEN (and GITLAB_BASE_URL for a self-managed instance), and name the provider. For the project https://gitlab.com/group/subgroup/project:

{
    "provider": "gitlab",
    "owner": "group/subgroup",
    "repo": "project",
    "default_ref": "main",
    "pr": 42,
    "refresh": true
}

"refresh": true makes argo-diff read the head commit and branches from the merge request, so commit_sha, change_ref and base_ref can be left out.

Testing HTTP endpoints locally

To simulate GitHub webhook requests, copy the webhook request headers and payload to temp/curl-headers.txt and temp/curl-payload.json, then use the post-local.sh script to ship them to the local server.

There is also a /dev endpoint that is enabled when APP_ENV=dev. It is handled by devHandler() in internal/server/http_server.go; it bypasses webhook signature validation and triggers argo-diff for the posted event.

When APP_ENV is dev, argo-diff will comment but will not set commit status checks.

Development Notes

This was originally developed by @vrivellino as a way to learn Go. Its functionality replicates that of an internal tool written by smart people at a previous job.

Directories

Path Synopsis
cmd
webhook-parse command
Command webhook-parse reads one raw HTTP webhook request from stdin, parses it with a provider's scm.WebhookHandler, and prints the result as JSON to stdout.
Command webhook-parse reads one raw HTTP webhook request from stdin, parses it with a provider's scm.WebhookHandler, and prints the result as JSON to stdout.
internal
config
Package config holds cross-package operator configuration that more than one internal package needs to read — starting with the connectivity-check bypass.
Package config holds cross-package operator configuration that more than one internal package needs to read — starting with the connectivity-check bypass.
gitlab
Package gitlab is the GitLab provider: Provider implements scm.Provider on top of the GitLab REST API (gitlab.com/gitlab-org/api/client-go).
Package gitlab is the GitLab provider: Provider implements scm.Provider on top of the GitLab REST API (gitlab.com/gitlab-org/api/client-go).
ignorable
Package ignorable decides which resource diffs are "ignorable": diffs whose every changed line matches a configured regex, such as a Helm chart bump that only touches version labels.
Package ignorable decides which resource diffs are "ignorable": diffs whose every changed line matches a configured regex, such as a Helm chart bump that only touches version labels.
scm
Package scm holds the source-control-provider abstraction: the neutral types every provider (GitHub today) speaks in, so the rest of argo-diff does not depend on any one provider's API types.
Package scm holds the source-control-provider abstraction: the neutral types every provider (GitHub today) speaks in, so the rest of argo-diff does not depend on any one provider's API types.
shellquote
Shellquote provides utilities for joining/splitting strings using sh's word-splitting rules.
Shellquote provides utilities for joining/splitting strings using sh's word-splitting rules.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL