this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 113 lines 5.3 kB view raw
1#!/usr/bin/env zx 2$.verbose = true 3/* Stolen from https://raw.githubusercontent.com/onedr0p/home-ops/main/.github/scripts/helmReleaseDiff.mjs */ 4 5 6/** 7 * * helmReleaseDiff.mjs 8 * * Runs `helm template` with your Helm values and then runs `dyff` across Flux HelmRelease manifests 9 * @param --current-release The source Flux HelmRelease to compare against the target 10 * @param --incoming-release The target Flux HelmRelease to compare against the source 11 * @param --kubernetes-dir The directory containing your Flux manifests including the HelmRepository manifests 12 * * Limitations: 13 * * Does not work with multiple HelmRelease maninfests in the same YAML document 14 */ 15const CurrentRelease = argv['current-release'] 16const IncomingRelease = argv['incoming-release'] 17const KubernetesDir = argv['kubernetes-dir'] 18 19const dyff = await which('dyff') 20const helm = await which('helm') 21const kustomize = await which('kustomize') 22 23async function helmRelease(releaseFile) { 24 const helmRelease = await fs.readFile(releaseFile, 'utf8') 25 const doc = YAML.parseAllDocuments(helmRelease).map((item) => item.toJS()) 26 const release = doc.filter((item) => 27 item.apiVersion === 'helm.toolkit.fluxcd.io/v2beta1' 28 && item.kind === 'HelmRelease' 29 ) 30 return release[0] 31} 32 33async function helmRepositoryUrl(kubernetesDir, releaseName) { 34 const files = await globby([`${kubernetesDir}/**/*.yaml`]) 35 for await (const file of files) { 36 const contents = await fs.readFile(file, 'utf8') 37 const doc = YAML.parseAllDocuments(contents).map((item) => item.toJS()) 38 if ('apiVersion' in doc[0] && doc[0].apiVersion === 'source.toolkit.fluxcd.io/v1beta2' 39 && 'kind' in doc[0] && doc[0].kind === 'HelmRepository' 40 && 'metadata' in doc[0] && 'name' in doc[0].metadata && doc[0].metadata.name === releaseName) 41 { 42 return doc[0].spec.url 43 } 44 } 45} 46 47async function kustomizeBuild(releaseBaseDir, releaseName) { 48 const build = await $`${kustomize} build --load-restrictor=LoadRestrictionsNone ${releaseBaseDir}` 49 const docs = YAML.parseAllDocuments(build.stdout).map((item) => item.toJS()) 50 const release = docs.filter((item) => 51 item.apiVersion === 'helm.toolkit.fluxcd.io/v2beta1' 52 && item.kind === 'HelmRelease' 53 && item.metadata.name === releaseName 54 ) 55 return release[0] 56} 57 58async function helmRepoAdd (registryName, registryUrl) { 59 await $`${helm} repo add ${registryName} ${registryUrl}` 60} 61 62async function helmTemplate (releaseName, registryName, chartName, chartVersion, chartValues) { 63 const values = new YAML.Document() 64 values.contents = chartValues 65 const valuesFile = await $`mktemp` 66 await fs.writeFile(valuesFile.stdout.trim(), values.toString()) 67 68 const manifestsFile = await $`mktemp` 69 const manifests = await $`${helm} template --kube-version 1.24.8 --release-name ${releaseName} --include-crds=false ${registryName}/${chartName} --version ${chartVersion} --values ${valuesFile.stdout.trim()}` 70 71 // Remove docs that are CustomResourceDefinition and keys which contain generated fields 72 let documents = YAML.parseAllDocuments(manifests.stdout.trim()) 73 documents = documents.filter(doc => doc.get('kind') !== 'CustomResourceDefinition') 74 documents.forEach(doc => { 75 const del = (path) => doc.hasIn(path) ? doc.deleteIn(path) : false 76 del(['metadata', 'labels']) 77 del(['spec', 'template', 'metadata', 'annotations']) 78 del(['spec', 'template', 'metadata', 'labels']) 79 }) 80 81 await fs.writeFile(manifestsFile.stdout.trim(), documents.map(doc => doc.toString({directives: true})).join('\n')) 82 return manifestsFile.stdout.trim() 83} 84 85// Generate current template from Helm values 86const currentRelease = await helmRelease(CurrentRelease) 87const currentBuild = await kustomizeBuild(path.dirname(CurrentRelease), currentRelease.metadata.name) 88const currentRepositoryUrl = await helmRepositoryUrl(KubernetesDir, currentBuild.spec.chart.spec.sourceRef.name) 89await helmRepoAdd(currentBuild.spec.chart.spec.sourceRef.name, currentRepositoryUrl) 90const currentManifests = await helmTemplate( 91 currentBuild.metadata.name, 92 currentBuild.spec.chart.spec.sourceRef.name, 93 currentBuild.spec.chart.spec.chart, 94 currentBuild.spec.chart.spec.version, 95 currentBuild.spec.values 96) 97 98// Generate incoming template from Helm values 99const incomingRelease = await helmRelease(IncomingRelease) 100const incomingBuild = await kustomizeBuild(path.dirname(IncomingRelease), incomingRelease.metadata.name) 101const incomingRepositoryUrl = await helmRepositoryUrl(KubernetesDir, incomingBuild.spec.chart.spec.sourceRef.name) 102await helmRepoAdd(incomingBuild.spec.chart.spec.sourceRef.name, incomingRepositoryUrl) 103const incomingManifests = await helmTemplate( 104 incomingBuild.metadata.name, 105 incomingBuild.spec.chart.spec.sourceRef.name, 106 incomingBuild.spec.chart.spec.chart, 107 incomingBuild.spec.chart.spec.version, 108 incomingBuild.spec.values 109) 110 111// Print diff using dyff 112const diff = await $`${dyff} --color=off --truecolor=off between --omit-header --ignore-order-changes --detect-kubernetes=true --output=human ${currentManifests} ${incomingManifests}` 113echo(diff.stdout.trim())