Skip to content

abstrask/flux-helm-diff

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

Flux Helm chart diff action

A composite GitHub Action for use with PR workflows in repos with Flux Helm manifests.

It extracts the repo URL, chart name and version and values, and renders the supplied list of templates before and after PR, and produce a diff report in markdown format.

It makes it easy to determine the effect on the rendered Kubernetes manifests, e.g. when bumping chart version or changing the supplied Helm values.

Combine with these awesome projects for maximum workflow smoothness:

Table of Contents

Dependencies

Requires Helm and yq. Both can be installed using Arkade if needed.

Inputs

Outputs

  • diff_markdown: Markdown report with per-Helm file changes, to be passed to mshick/add-pr-comment
  • any_failed: Will be set to 1 if the helm command fails on any of the files

In diff_markdown the output for each file will either be:

  • That of the diff command
  • "No changes"
  • Error message produced by Helm command if failed

Usage

TL;DR

- id: helm_diff
  name: Flux Helm diff
  uses: abstrask/flux-helm-diff@main
  with:
    helm_files: ${{ steps.changed_files_helm.outputs.all_changed_files }}

Full Example

Run on pull requests:

name: Run Helm diff
on:
  - pull_request_target

Filter on changed Helm files (under infrastructure/base/):

jobs:
  path_filter:
    name: Filter Helm templates
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: read # fix "Resource not accessible by integration" error
    outputs:
      helm: ${{ steps.filter.outputs.helm }}
    steps:
      - id: checkout_head
        uses: actions/checkout@v4
        with:
          ref: ${{ github.head_ref }}

      - uses: dorny/paths-filter@v3
        id: filter
        with:
          filters: |
            helm:
              - 'infrastructure/base/*/helm.yaml'

Run diff job only if any Helm files were changed:

  helm_diff:
    name: Diff changed Helm templates
    needs: path_filter
    if: ${{ needs.path_filter.outputs.helm == 'true' }}
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write

Install helm and yq:

    steps:
      - id: dependencies
        name: Install dependencies
        uses: alexellis/arkade-get@master
        with:
          helm: latest
          yq: latest

Checkout base and head:

      - id: checkout_base
        uses: actions/checkout@v4
        with:
          ref: ${{ github.base_ref }}
          path: base

      - id: checkout_head
        uses: actions/checkout@v4
        with:
          ref: ${{ github.head_ref }}
          path: head

Produce list of changed Helm files:

      - name: Get changed Helm files
        id: changed_files_helm
        uses: tj-actions/changed-files@v44
        with:
          files: |
            infrastructure/base/*/helm.yaml

Render templates and generate diff report:

      - id: helm_diff
        name: Helm diff
        uses: abstrask/actions-playground@main
        with:
          helm_files: ${{ steps.changed_files_helm.outputs.all_changed_files }}

Add diff report as comment to PR:

      - id: pr_comment
        name: Add PR comment
        uses: mshick/add-pr-comment@v2
        if: contains(fromJSON('["pull_request_target"]'), github.event_name)
        with:
          message-id: diff
          refresh-message-position: true
          message: |
            ${{ steps.helm_diff.outputs.diff_markdown }}

Optionally, cause check to fail, if any Helm file failed to render:

      - id: fail_job
        name: Diff failed?
        uses: actions/github-script@v7
        if: ${{ steps.helm_diff.outputs.any_failed == 1 }}
        with:
          script: |
            core.setFailed('Failed to run diff')

See example-workflow.yaml for coherent example.

Simulating Capabilities

When installing, Helm can access the Kubernetes version and available Kubernetes APIs and versions, through "Built-in Objects".

This enable charts to deploy custom resources, or tweak properties as needed, based on the features introduced in specific Kubernetes versions, or APIs offered in the cluster.

For example, starting with argo-workflows chart 0.41.0, the ServiceMonitor resource doesn't even get deployed, if .Capabilities.APIVersions.Has doesn't contain monitoring.coreos.com/v1.

By default, Helm will use the Kubernetes version included in the tool, and the built-in API versions in this version. These are printed in the beginning of the logs of the GitHub Action for clarity.

If needed, the Kubernetes version used for templating can be overriden, and additional API versions can be specified in the helm.yaml file in the form of a small commented YAML document. The comments has to be the last in the file and must have the document start --- marker above. Example:

---
# flux-helm-diff:
#   kube-version: 1.30
#   api-versions:
#   - myapi/v0
#   - monitoring.coreos.com/v1

You can verify that the APIs are read correctly from the log output of the "Helm diff" step of the action:

Processing file "infrastructure/base/argo-workflows/helm.yaml"
(...)
head simulate Kube version: 1.30
head API versions:          myapi/v0,monitoring.coreos.com/v1
(...)

Example Output/PR comment

infrastructure/base/dcgm-exporter/helm.yaml

No changes

infrastructure/base/nvidia-device-plugin/helm.yaml

(abbreviated)

+# Source: nvidia-device-plugin/templates/daemonset-device-plugin.yml
 apiVersion: apps/v1
 kind: DaemonSet
 metadata:
   labels:
     app.kubernetes.io/instance: nvidia-device-plugin
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/name: nvidia-device-plugin
-    app.kubernetes.io/version: 0.14.5
-    helm.sh/chart: nvidia-device-plugin-0.14.5
+    app.kubernetes.io/version: 0.15.0
+    helm.sh/chart: nvidia-device-plugin-0.15.0
   name: nvidia-device-plugin
   namespace: nvidia-device-plugin
 spec:
   selector:
     matchLabels:
@@ -19,15 +75,42 @@
       annotations: {}
       labels:
         app.kubernetes.io/instance: nvidia-device-plugin
         app.kubernetes.io/name: nvidia-device-plugin
     spec:
+      affinity:
+        nodeAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            nodeSelectorTerms:
+              - matchExpressions:
+                  - key: feature.node.kubernetes.io/pci-10de.present
+                    operator: In
+                    values:
+                      - "true"
+              - matchExpressions:
+                  - key: feature.node.kubernetes.io/cpu-model.vendor_id
+                    operator: In
+                    values:
+                      - NVIDIA
+              - matchExpressions:
+                  - key: nvidia.com/gpu.present
+                    operator: In
+                    values:
+                      - "true"
       containers:
-        - env:
+        - command:
+            - nvidia-device-plugin
+          env:
+            - name: MPS_ROOT
+              value: /run/nvidia/mps
             - name: NVIDIA_MIG_MONITOR_DEVICES
               value: all
-          image: nvcr.io/nvidia/k8s-device-plugin:v0.14.5
+            - name: NVIDIA_VISIBLE_DEVICES
+              value: all
+            - name: NVIDIA_DRIVER_CAPABILITIES
+              value: compute,utility
+          image: nvcr.io/nvidia/k8s-device-plugin:v0.15.0
           imagePullPolicy: IfNotPresent
           name: nvidia-device-plugin-ctr
           resources:
             limits:
               memory: 64Mi

(abbreviated)

Testing

helm_files=($(find ./test/head -type f -name 'helm.yaml' | sed "s|^./test/head/||" | sort))
GITHUB_OUTPUT=debug.out HELM_FILES="${helm_files[@]}" TEST=1 ./flux-helm-diff.sh; cat debug.out

Testing files

Name Scenario tested Expected output
argo-workflows Read API from comment in helm file (otherwise ServiceMonitor resource is not rendered) Diff shows change to ServiceMonitor, instead of being removed
dcgm-exporter Chart added in head that doesn't exist in base Diff shows entire rendered template as added
metaflow Very non-standard way of publishing charts (not sure if should be supported) TBD
metrics-server Old Kube Version simulated in base, using Helm's default in head PodDisruptionBudget changes API version from policy/v1beta1 to policy/v1
nvidia-device-plugin HelmRepository (using https), minor chart version bump Diff (with potentially breaking nodeAffinity)
podinfo Unknown repository type (HelmTypoRepository) Unrecognised repo type
weave-gitops-helm2oci Repository type changed from HelmRepository (type oci) to OCIRepository No changes
weave-gitops-helmrepo HelmRepository with type oci Diff
weave-gitops-ocirepo OCIRepository Diff

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages