├── .gitignore ├── main.go ├── renovate.json ├── scripts ├── install_version.sh ├── check_version.sh └── install.sh ├── cmd ├── root_test.go └── root.go ├── plugin.yaml ├── go.mod ├── .goreleaser.yml ├── .github └── workflows │ ├── go.yml │ └── release.yml ├── LICENSE ├── testdata └── values.yaml ├── go.sum └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | helm-schema-gen -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/knechtionscoding/helm-schema-gen/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /scripts/install_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ## this script must be called ONLY 4 | ## from the root of this project 5 | 6 | ## this script installs a the 7 | ## version of the plugin mentioned 8 | ## in the plugin.yaml 9 | 10 | ./scripts/install.sh "0.0.10" 11 | -------------------------------------------------------------------------------- /cmd/root_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "path/filepath" 5 | "testing" 6 | ) 7 | 8 | func BenchmarkRootCommandExecution(b *testing.B) { 9 | for i := 0; i < b.N; i++ { 10 | rootCmd.RunE(nil, []string{filepath.Join("..", "testdata", "values.yaml")}) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /plugin.yaml: -------------------------------------------------------------------------------- 1 | name: "schema-gen" 2 | version: "0.0.10" 3 | usage: "generate json schema for values yaml" 4 | description: "generate json schema for values yaml" 5 | command: "$HELM_PLUGIN_DIR/bin/helm-schema-gen" 6 | hooks: 7 | install: "cd $HELM_PLUGIN_DIR; scripts/install_version.sh" 8 | update: "cd $HELM_PLUGIN_DIR; scripts/install_version.sh" 9 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/knechtionscoding/helm-schema-gen 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/karuppiah7890/go-jsonschema-generator v0.0.0-20191229070329-082ad3307d9e 7 | github.com/spf13/cobra v1.8.0 8 | gopkg.in/yaml.v2 v2.4.0 9 | ) 10 | 11 | require ( 12 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 13 | github.com/spf13/pflag v1.0.5 // indirect 14 | ) 15 | 16 | replace gopkg.in/yaml.v2 => gopkg.in/yaml.v2 v2.4.0 17 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | builds: 2 | - env: 3 | - CGO_ENABLED=0 4 | goos: 5 | - linux 6 | - darwin 7 | - windows 8 | goarch: 9 | - arm64 10 | - amd64 11 | - arm 12 | archives: 13 | - replacements: 14 | darwin: Darwin 15 | linux: Linux 16 | windows: Windows 17 | 386: i386 18 | amd64: x86_64 19 | arm64: arm64 20 | format_overrides: 21 | - goos: windows 22 | format: zip 23 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a golang project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go 3 | 4 | name: Go 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Set up Go 20 | uses: actions/setup-go@v5 21 | with: 22 | go-version: '1.20' 23 | 24 | - name: Build 25 | run: go build -v ./... 26 | 27 | - name: Test 28 | run: go test -v ./... 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: goreleaser 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | goreleaser: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v4 14 | with: 15 | fetch-depth: 0 16 | - name: Check plugin and script version 17 | uses: mikefarah/yq@v4.43.1 18 | with: 19 | cmd: ./scripts/check_version.sh plugin.yaml scripts/install_version.sh ${{ github.ref }} 20 | - name: Set up Go 21 | uses: actions/setup-go@v5 22 | with: 23 | go-version: 1.19 24 | - name: Run GoReleaser 25 | uses: goreleaser/goreleaser-action@v5 26 | with: 27 | version: latest 28 | args: release --clean 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | -------------------------------------------------------------------------------- /scripts/check_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Checks plugin.yaml version and also the install version script version 4 | 5 | set -e 6 | 7 | plugin_yaml=$1 8 | # example: refs/tags/0.0.1 9 | install_version_script=$2 10 | refTag=$3 11 | expected_version=$(echo $refTag | cut -d "/" -f 3) 12 | 13 | if [ -z $expected_version ]; 14 | then 15 | echo "git tag value is empty" 16 | exit 1 17 | fi 18 | 19 | if [ ! -e $plugin_yaml ]; 20 | then 21 | echo "File $plugin_yaml does not exist!" 22 | exit 1 23 | fi 24 | 25 | plugin_version=$(yq read $plugin_yaml version) 26 | 27 | if [ "$plugin_version" != "$expected_version" ]; 28 | then 29 | echo "Plugin version $plugin_version is not the expected version $expected_version" 30 | exit 1 31 | fi 32 | 33 | if [ ! -e $install_version_script ]; 34 | then 35 | echo "File $install_version_script does not exist!" 36 | exit 1 37 | fi 38 | 39 | set +e 40 | 41 | grep -q -F $expected_version $install_version_script 42 | wrong_version=$? 43 | 44 | set -e 45 | 46 | if [ $wrong_version != 0 ]; 47 | then 48 | echo "$install_version_script does not have the right version" 49 | exit 1 50 | fi 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2021 Karuppiah Natarajan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | 8 | "github.com/karuppiah7890/go-jsonschema-generator" 9 | "github.com/spf13/cobra" 10 | "gopkg.in/yaml.v2" 11 | ) 12 | 13 | // rootCmd represents the base command when called without any subcommands 14 | var rootCmd = &cobra.Command{ 15 | Use: "helm schema-gen ", 16 | SilenceUsage: true, 17 | SilenceErrors: true, 18 | Short: "Helm plugin to generate json schema for values yaml", 19 | Long: `Helm plugin to generate json schema for values yaml 20 | 21 | Examples: 22 | $ helm schema-gen values.yaml # generate schema json 23 | `, 24 | RunE: func(cmd *cobra.Command, args []string) error { 25 | if len(args) == 0 { 26 | return fmt.Errorf("pass one values yaml file") 27 | } 28 | if len(args) != 1 { 29 | return fmt.Errorf("schema can be generated only for one values yaml at once") 30 | } 31 | 32 | valuesFilePath := args[0] 33 | values := make(map[string]interface{}) 34 | valuesFileData, err := ioutil.ReadFile(valuesFilePath) 35 | if err != nil { 36 | return fmt.Errorf("error when reading file '%s': %v", valuesFilePath, err) 37 | } 38 | err = yaml.Unmarshal(valuesFileData, &values) 39 | s := &jsonschema.Document{} 40 | s.ReadDeep(&values) 41 | fmt.Println(s) 42 | 43 | return nil 44 | }, 45 | } 46 | 47 | // Execute executes the root command 48 | func Execute() { 49 | if err := rootCmd.Execute(); err != nil { 50 | fmt.Println(err) 51 | os.Exit(1) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /testdata/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for dummy. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 1 6 | 7 | image: 8 | repository: nginx 9 | pullPolicy: IfNotPresent 10 | # Overrides the image tag whose default is the chart appVersion. 11 | tag: "" 12 | 13 | imagePullSecrets: [] 14 | nameOverride: "" 15 | fullnameOverride: "" 16 | 17 | serviceAccount: 18 | # Specifies whether a service account should be created 19 | create: true 20 | # Annotations to add to the service account 21 | annotations: {} 22 | # The name of the service account to use. 23 | # If not set and create is true, a name is generated using the fullname template 24 | name: "" 25 | 26 | podAnnotations: {} 27 | 28 | podSecurityContext: {} 29 | # fsGroup: 2000 30 | 31 | securityContext: {} 32 | # capabilities: 33 | # drop: 34 | # - ALL 35 | # readOnlyRootFilesystem: true 36 | # runAsNonRoot: true 37 | # runAsUser: 1000 38 | 39 | service: 40 | type: ClusterIP 41 | port: 80 42 | 43 | ingress: 44 | enabled: false 45 | annotations: {} 46 | # kubernetes.io/ingress.class: nginx 47 | # kubernetes.io/tls-acme: "true" 48 | hosts: 49 | - host: chart-example.local 50 | paths: [] 51 | tls: [] 52 | # - secretName: chart-example-tls 53 | # hosts: 54 | # - chart-example.local 55 | 56 | resources: {} 57 | # We usually recommend not to specify default resources and to leave this as a conscious 58 | # choice for the user. This also increases chances charts run on environments with little 59 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 60 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 61 | # limits: 62 | # cpu: 100m 63 | # memory: 128Mi 64 | # requests: 65 | # cpu: 100m 66 | # memory: 128Mi 67 | 68 | autoscaling: 69 | enabled: false 70 | minReplicas: 1 71 | maxReplicas: 100 72 | targetCPUUtilizationPercentage: 80 73 | # targetMemoryUtilizationPercentage: 80 74 | 75 | nodeSelector: {} 76 | 77 | tolerations: [] 78 | 79 | affinity: {} 80 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 3 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 4 | github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 5 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 6 | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 7 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 8 | github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 9 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 11 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 12 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 13 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 14 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 15 | github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 16 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 17 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 18 | github.com/karuppiah7890/go-jsonschema-generator v0.0.0-20191229070329-082ad3307d9e h1:jPRoHoZaEunUNhxRoob4kBzXCpIyanE1bX3eCqfeIFo= 19 | github.com/karuppiah7890/go-jsonschema-generator v0.0.0-20191229070329-082ad3307d9e/go.mod h1:SltxBi57U2RnGZlEO3kSfuVQ8gdHdgSEcJFQ5zOnqqk= 20 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 21 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 22 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 23 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 24 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 25 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 26 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 27 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 28 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 29 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 30 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 31 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 32 | github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= 33 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 34 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 35 | github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= 36 | github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= 37 | github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= 38 | github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= 39 | github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= 40 | github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= 41 | github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= 42 | github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= 43 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 44 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 45 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 46 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 47 | github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 48 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 49 | github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= 50 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 51 | golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 52 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a h1:1n5lsVfiQW3yfsRGu98756EH1YthsFqr/5mxHduZW2A= 53 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 54 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 55 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 56 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 57 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 58 | gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= 59 | gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 60 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 61 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 62 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # helm schema gen plugin 2 | 3 | ![](https://github.com/KnechtionsCoding/helm-schema-gen/workflows/goreleaser/badge.svg) 4 | 5 | So that you don't have to write values.schema.json by hand from scratch for your Helm 3 charts 6 | 7 | [Helm](https://helm.sh) plugin to generate [JSON Schema for values yaml](https://helm.sh/docs/topics/charts/#schema-files) 8 | 9 | ## Code stuff 10 | 11 | Nothing fancy about the code, all the heavy lifting is done by: 12 | 13 | - [go-jsonschema-generator](https://github.com/KnechtionsCoding/go-jsonschema-generator) - for generating JSON schema. It's a fork of [this](https://github.com/mcuadros/go-jsonschema-generator). Thanks to [@mcuadros](https://github.com/mcuadros) 14 | - [go-yaml](https://github.com/go-yaml/yaml/) - for YAML parsing 15 | - [cobra](https://github.com/spf13/cobra) - for CLI stuff 16 | - [The Go stdlib](https://golang.org/pkg/) - for everything else 17 | 18 | ## Install 19 | 20 | The plugin works with both Helm v2 and v3 versions as it's agnostic to the Helm 21 | binary version 22 | 23 | ``` 24 | $ helm plugin install https://github.com/KnechtionsCoding/helm-schema-gen.git 25 | KnechtionsCoding/helm-schema-gen info checking GitHub for tag '0.0.4' 26 | KnechtionsCoding/helm-schema-gen info found version: 0.0.4 for 0.0.4/Darwin/x86_64 27 | KnechtionsCoding/helm-schema-gen info installed ./bin/helm-schema-gen 28 | Installed plugin: schema-gen 29 | ``` 30 | 31 | But note that the schema feature is present only in Helm v3 charts, so Helm 32 | chart still has to be v3, meaning - based on the Helm chart v3 spec. And the 33 | schema validation is only done in Helm v3. Read more in the 34 | [Schema Files](https://helm.sh/docs/topics/charts/#schema-files) section of the 35 | Helm official docs. 36 | 37 | ## Usage 38 | 39 | The plugin works with both Helm v2 and v3 versions 40 | 41 | Let's take a sample `values.yaml` like the below 42 | 43 | ``` 44 | replicaCount: 1 45 | 46 | image: 47 | repository: nginx 48 | pullPolicy: IfNotPresent 49 | 50 | imagePullSecrets: [] 51 | nameOverride: "" 52 | fullnameOverride: "" 53 | 54 | serviceAccount: 55 | # Specifies whether a service account should be created 56 | create: true 57 | # The name of the service account to use. 58 | # If not set and create is true, a name is generated using the fullname template 59 | name: 60 | 61 | podSecurityContext: {} 62 | # fsGroup: 2000 63 | 64 | securityContext: {} 65 | # capabilities: 66 | # drop: 67 | # - ALL 68 | # readOnlyRootFilesystem: true 69 | # runAsNonRoot: true 70 | # runAsUser: 1000 71 | 72 | service: 73 | type: ClusterIP 74 | port: 80 75 | 76 | ingress: 77 | enabled: false 78 | annotations: {} 79 | # kubernetes.io/ingress.class: nginx 80 | # kubernetes.io/tls-acme: "true" 81 | hosts: 82 | - host: chart-example.local 83 | paths: [] 84 | tls: [] 85 | # - secretName: chart-example-tls 86 | # hosts: 87 | # - chart-example.local 88 | 89 | resources: {} 90 | # We usually recommend not to specify default resources and to leave this as a conscious 91 | # choice for the user. This also increases chances charts run on environments with little 92 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 93 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 94 | # limits: 95 | # cpu: 100m 96 | # memory: 128Mi 97 | # requests: 98 | # cpu: 100m 99 | # memory: 128Mi 100 | 101 | nodeSelector: {} 102 | 103 | tolerations: [] 104 | 105 | affinity: {} 106 | ``` 107 | 108 | Now if you use the plugin and pass the `values.yaml` to it, you will 109 | get the JSON Schema for the `values.yaml` 110 | 111 | ``` 112 | $ helm schema-gen values.yaml 113 | { 114 | "$schema": "http://json-schema.org/schema#", 115 | "type": "object", 116 | "properties": { 117 | "affinity": { 118 | "type": "object" 119 | }, 120 | "fullnameOverride": { 121 | "type": "string" 122 | }, 123 | "image": { 124 | "type": "object", 125 | "properties": { 126 | "pullPolicy": { 127 | "type": "string" 128 | }, 129 | "repository": { 130 | "type": "string" 131 | } 132 | } 133 | }, 134 | "imagePullSecrets": { 135 | "type": "array" 136 | }, 137 | "ingress": { 138 | "type": "object", 139 | "properties": { 140 | "annotations": { 141 | "type": "object" 142 | }, 143 | "enabled": { 144 | "type": "boolean" 145 | }, 146 | "hosts": { 147 | "type": "array", 148 | "items": { 149 | "type": "object", 150 | "properties": { 151 | "host": { 152 | "type": "string" 153 | }, 154 | "paths": { 155 | "type": "array" 156 | } 157 | } 158 | } 159 | }, 160 | "tls": { 161 | "type": "array" 162 | } 163 | } 164 | }, 165 | "nameOverride": { 166 | "type": "string" 167 | }, 168 | "nodeSelector": { 169 | "type": "object" 170 | }, 171 | "podSecurityContext": { 172 | "type": "object" 173 | }, 174 | "replicaCount": { 175 | "type": "integer" 176 | }, 177 | "resources": { 178 | "type": "object" 179 | }, 180 | "securityContext": { 181 | "type": "object" 182 | }, 183 | "service": { 184 | "type": "object", 185 | "properties": { 186 | "port": { 187 | "type": "integer" 188 | }, 189 | "type": { 190 | "type": "string" 191 | } 192 | } 193 | }, 194 | "serviceAccount": { 195 | "type": "object", 196 | "properties": { 197 | "create": { 198 | "type": "boolean" 199 | }, 200 | "name": { 201 | "type": "null" 202 | } 203 | } 204 | }, 205 | "tolerations": { 206 | "type": "array" 207 | } 208 | } 209 | } 210 | ``` 211 | 212 | You can save it to a file like this 213 | 214 | ``` 215 | helm schema-gen values.yaml > values.schema.json 216 | ``` 217 | 218 | ## Issues? Feature Requests? Proposals? Feedback? 219 | 220 | Put them all in [GitHub issues](https://github.com/KnechtionsCoding/helm-schema-gen/issues) 221 | -------------------------------------------------------------------------------- /scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | # Code generated by godownloader on 2020-12-23T14:59:45Z. DO NOT EDIT. 4 | # 5 | 6 | usage() { 7 | this=$1 8 | cat </dev/null 137 | } 138 | echoerr() { 139 | echo "$@" 1>&2 140 | } 141 | log_prefix() { 142 | echo "$0" 143 | } 144 | _logp=6 145 | log_set_priority() { 146 | _logp="$1" 147 | } 148 | log_priority() { 149 | if test -z "$1"; then 150 | echo "$_logp" 151 | return 152 | fi 153 | [ "$1" -le "$_logp" ] 154 | } 155 | log_tag() { 156 | case $1 in 157 | 0) echo "emerg" ;; 158 | 1) echo "alert" ;; 159 | 2) echo "crit" ;; 160 | 3) echo "err" ;; 161 | 4) echo "warning" ;; 162 | 5) echo "notice" ;; 163 | 6) echo "info" ;; 164 | 7) echo "debug" ;; 165 | *) echo "$1" ;; 166 | esac 167 | } 168 | log_debug() { 169 | log_priority 7 || return 0 170 | echoerr "$(log_prefix)" "$(log_tag 7)" "$@" 171 | } 172 | log_info() { 173 | log_priority 6 || return 0 174 | echoerr "$(log_prefix)" "$(log_tag 6)" "$@" 175 | } 176 | log_err() { 177 | log_priority 3 || return 0 178 | echoerr "$(log_prefix)" "$(log_tag 3)" "$@" 179 | } 180 | log_crit() { 181 | log_priority 2 || return 0 182 | echoerr "$(log_prefix)" "$(log_tag 2)" "$@" 183 | } 184 | uname_os() { 185 | os=$(uname -s | tr '[:upper:]' '[:lower:]') 186 | case "$os" in 187 | cygwin_nt*) os="windows" ;; 188 | mingw*) os="windows" ;; 189 | msys_nt*) os="windows" ;; 190 | esac 191 | echo "$os" 192 | } 193 | uname_arch() { 194 | arch=$(uname -m) 195 | case $arch in 196 | x86_64) arch="amd64" ;; 197 | x86) arch="386" ;; 198 | i686) arch="386" ;; 199 | i386) arch="386" ;; 200 | aarch64) arch="arm64" ;; 201 | armv5*) arch="armv5" ;; 202 | armv6*) arch="armv6" ;; 203 | armv7*) arch="armv7" ;; 204 | esac 205 | echo ${arch} 206 | } 207 | uname_os_check() { 208 | os=$(uname_os) 209 | case "$os" in 210 | darwin) return 0 ;; 211 | dragonfly) return 0 ;; 212 | freebsd) return 0 ;; 213 | linux) return 0 ;; 214 | android) return 0 ;; 215 | nacl) return 0 ;; 216 | netbsd) return 0 ;; 217 | openbsd) return 0 ;; 218 | plan9) return 0 ;; 219 | solaris) return 0 ;; 220 | windows) return 0 ;; 221 | esac 222 | log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib" 223 | return 1 224 | } 225 | uname_arch_check() { 226 | arch=$(uname_arch) 227 | case "$arch" in 228 | 386) return 0 ;; 229 | amd64) return 0 ;; 230 | arm64) return 0 ;; 231 | armv5) return 0 ;; 232 | armv6) return 0 ;; 233 | armv7) return 0 ;; 234 | ppc64) return 0 ;; 235 | ppc64le) return 0 ;; 236 | mips) return 0 ;; 237 | mipsle) return 0 ;; 238 | mips64) return 0 ;; 239 | mips64le) return 0 ;; 240 | s390x) return 0 ;; 241 | amd64p32) return 0 ;; 242 | esac 243 | log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib" 244 | return 1 245 | } 246 | untar() { 247 | tarball=$1 248 | case "${tarball}" in 249 | *.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;; 250 | *.tar) tar --no-same-owner -xf "${tarball}" ;; 251 | *.zip) unzip "${tarball}" ;; 252 | *) 253 | log_err "untar unknown archive format for ${tarball}" 254 | return 1 255 | ;; 256 | esac 257 | } 258 | http_download_curl() { 259 | local_file=$1 260 | source_url=$2 261 | header=$3 262 | if [ -z "$header" ]; then 263 | code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url") 264 | else 265 | code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url") 266 | fi 267 | if [ "$code" != "200" ]; then 268 | log_debug "http_download_curl received HTTP status $code" 269 | return 1 270 | fi 271 | return 0 272 | } 273 | http_download_wget() { 274 | local_file=$1 275 | source_url=$2 276 | header=$3 277 | if [ -z "$header" ]; then 278 | wget -q -O "$local_file" "$source_url" 279 | else 280 | wget -q --header "$header" -O "$local_file" "$source_url" 281 | fi 282 | } 283 | http_download() { 284 | log_debug "http_download $2" 285 | if is_command curl; then 286 | http_download_curl "$@" 287 | return 288 | elif is_command wget; then 289 | http_download_wget "$@" 290 | return 291 | fi 292 | log_crit "http_download unable to find wget or curl" 293 | return 1 294 | } 295 | http_copy() { 296 | tmp=$(mktemp) 297 | http_download "${tmp}" "$1" "$2" || return 1 298 | body=$(cat "$tmp") 299 | rm -f "${tmp}" 300 | echo "$body" 301 | } 302 | github_release() { 303 | owner_repo=$1 304 | version=$2 305 | test -z "$version" && version="latest" 306 | giturl="https://github.com/${owner_repo}/releases/${version}" 307 | json=$(http_copy "$giturl" "Accept:application/json") 308 | test -z "$json" && return 1 309 | version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//') 310 | test -z "$version" && return 1 311 | echo "$version" 312 | } 313 | hash_sha256() { 314 | TARGET=${1:-/dev/stdin} 315 | if is_command gsha256sum; then 316 | hash=$(gsha256sum "$TARGET") || return 1 317 | echo "$hash" | cut -d ' ' -f 1 318 | elif is_command sha256sum; then 319 | hash=$(sha256sum "$TARGET") || return 1 320 | echo "$hash" | cut -d ' ' -f 1 321 | elif is_command shasum; then 322 | hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1 323 | echo "$hash" | cut -d ' ' -f 1 324 | elif is_command openssl; then 325 | hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1 326 | echo "$hash" | cut -d ' ' -f a 327 | else 328 | log_crit "hash_sha256 unable to find command to compute sha-256 hash" 329 | return 1 330 | fi 331 | } 332 | hash_sha256_verify() { 333 | TARGET=$1 334 | checksums=$2 335 | if [ -z "$checksums" ]; then 336 | log_err "hash_sha256_verify checksum file not specified in arg2" 337 | return 1 338 | fi 339 | BASENAME=${TARGET##*/} 340 | want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1) 341 | if [ -z "$want" ]; then 342 | log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'" 343 | return 1 344 | fi 345 | got=$(hash_sha256 "$TARGET") 346 | if [ "$want" != "$got" ]; then 347 | log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got" 348 | return 1 349 | fi 350 | } 351 | cat /dev/null <