diff --git a/.ci/gpg/create-keyring.sh b/.ci/gpg/create-keyring.sh new file mode 100755 index 00000000..7837e313 --- /dev/null +++ b/.ci/gpg/create-keyring.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" + +# Modified from https://blogs.itemis.com/en/secure-your-travis-ci-releases-part-2-signature-with-openpgp + +function err_exit() { + echo "ERROR: ${1:-"Unknown Error"} Exiting." 1>&2 + exit 1 +} + +declare -r GPG_HOME="${DIR}/keyring" +declare -r SECRING_AUTO="${GPG_HOME}/secring.auto" +declare -r PUBRING_AUTO="${GPG_HOME}/pubring.auto" + +mkdir -p "$GPG_HOME" +cp "${DIR}"/*.auto* "${GPG_HOME}" + +echo -e "\nDecrypting secret key..." +{ + # $GPG_PASSWORD is taken from the script's env (injected by CI). + echo $GPG_PASSWORD | gpg --decrypt \ + --pinentry-mode loopback --batch \ + --passphrase-fd 0 \ + --output "${SECRING_AUTO}" \ + "${SECRING_AUTO}".gpg ; \ +} || { err_exit "Failed to decrypt secret key." ; } +echo "Success!" + +echo -e "\nImporting keys..." +{ gpg --home "${GPG_HOME}" --import "${PUBRING_AUTO}" ; } || { err_exit "Could not import public key into gpg." ; } +{ gpg --home "${GPG_HOME}" --import "${SECRING_AUTO}" ; } || { err_exit "Could not import secret key into gpg." ; } +echo "Success!" diff --git a/.ci/gpg/pubring.auto b/.ci/gpg/pubring.auto new file mode 100644 index 00000000..41fa49fa --- /dev/null +++ b/.ci/gpg/pubring.auto @@ -0,0 +1,64 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBF+clTQBEADMHVz8qS+dcYC0qxlSNe4Yipbr/BtVuWGJay26OAbS4K7sjzs3 +XP+RhjUsJGOnPXn+N/zM6wVNczV7MrdfWNK1UAWBPVC4HjD/ysj/m5lMv/j0RNym +W6VNdSgV4YWyQHn6eD279gT4p6GAVvQj0eXnWtX7eA0SaITi6dMNqw8QcTOBxzFI +PXw+4MDJJKDAammtNKgj6LtmYc3o9d8aqbwtPfj3Vvi5d3SWfMx8a+2aSDkVcsva +bloGUBXYWFzO11T4OYvUYXgQdaKHyT+ZWGCpDsnQV/KqG5S456jmV+Qp+98vwe8k +XhXhlkjauhbvVR0uGAv0RJ4NZPSmWpie6f7ApQ3XTg3+ZvsrTvi3STCkOKA8/CLm +/xRhAF/aFZSOLlgzyAxr45j0PRjzX3XJfPePkV1D1cFso3JGDT5Y2oku8bNqYTof +fV/vw6jxylSNKApn1VyViwZ0+aE9kjMHXytKWWLK+woxrFOG74nGcI+xBOAOHvSU +GRh5EVXydbyMxqEpq2Su+rHlzfzgPh+hORNQgrag+qdbTVMimCoD+datX4854Hkb +nah+mq7RtI0k5Nn+ENm4ufbHEKiNb56qFTNgMkquG5vxpA6NOlZ0QfKUxiDU08+g +Pix7+TY7lzNhGipD7QjqfuJJr+1k3p/GrIpoHlU8/8FvlNYBDG3oMUvxNwARAQAB +tDJPcGVyYXRvciBTREsgKHJlbGVhc2UpIDxjbmNmLW9wZXJhdG9yLXNka0BjbmNm +LmlvPokCVAQTAQgAPhYhBDsvFIHRRiOAgLNGuwUpluKiC1x+BQJfnJU0AhsBBQkD +w7iABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEAUpluKiC1x+P5IQAJXpQMA1 +kIr6S2N9A4TE6z+dhN0g3oPdZqOYwlKpX32H4nLdv219Ns1mwBHUfTFmcbUuQLwH +1TjF7cVya/tUoyh/P7bBBOy/vC0NvvaOuhRXxeJJD7Q8neuXyCpIoCW8x2Eq47ut +21AL79ZrzZEBpavJ80S2uNTx7HGKYug491OKkEWO3Y+FOmTV38WsN+lpM+atn1LP +gWkEhWaxwkfLrYUgZ/lDBAIhPZ7n3gYptmTQdCzlp4dSEwJXesV35aMWfJOM848M +fVJFyFcMNo6ww0tHD+7btrGc4fHSJC/dKZcYVoiSHmpuAqRBXHWMxKPfijgwWQs5 +6JjxCWt4bwouF0D2uE6SD/MYsxN05yZL6OGfzzQES5Ilt0DS3QRLktN8PdeuS+WN +jLVo7/Q2SUGZcANm+5/ul7Qwj9JeFSK3VloLKY0YFEbnyTHw2TU4oDqyffUWTn+h +Pt34Wy+OWRM+2ykxFP1VklgCN07ESRSZOTN6iUzqets50rKpY3okNiZeMPcblxQo +uQ5/NFmYV/de87JuSmOKXB2yy/xdr7oxkbw9uYZmBEvw4etxH2yyzVxr0BJ4r0DW +5DlSxOeHaNa7aUVQnlK+Xf27Pj1XyYvV6G7NWEZYZQ/pclO0rhFH21ZiGo3DHgSo +cAGv6SWU01nELYYHTn3QFdmdjxmbqjSC0t+EuQINBF+clhYBEACj1YQhSMK8kp1W +oDL5As2yFlljmdkXTrYtMBLjLnkUaKoxIEGbrB/aeyph9PC84iKGLrHGC6rNBdVq +2mnGyJCXKKeJLovJnopz3+2bTOnypaOdk1QhovFw8CXRMVhjRehDe9PWQYXk2aL7 +sPvtLl5clw2iULdjxs2KfBGwSlEV6eXjGCFUGfIvMEQ/gjbTIiUtkhqaMCsEuyrB +aliNNfuBYsmnP5pHvn7yI/kMiNB8d0LmI8PCb+zdzZVbu9mID8P0Eyy6imbfwzIt +f21OP78lvGBVGzd2mH/EYyBswHEUblqBcb9maTz2Yy85dTFXKWU7n+OjKCCYpOK7 +SVffQFdR2ylUtv2JvLOCR/gH1Z0ac8ZF2DEI9C+owsVS9dqMk9l4p3cNeQzgRshN +qhO9eP9qGZ1LIgEKOeyLm5TgUcPLnq49vS4/eCo+p+Qa1FcGEs+b6rqIxSzyxNxs +v2lRmUQ/A3BToV321De2zfr51u1rJJVpYIEvbMPRyiciZzkDu/D5Z5fR1nytoFcR +t3osFILI0lilvzpSzxlHmnM480JADiTlKGz6YTnYG2mrZCFOxrmAsA/yDO4v41Ii +7O7z0cJO3l3mZ1fbqqAqqyHU0EGcxYOAmfM8azSrxj0MOM2jfGDMPWg3g3SXTXIl +6qyWOVUWfP4+QBsHrByHTSpGCgyTWwARAQABiQRyBBgBCAAmFiEEOy8UgdFGI4CA +s0a7BSmW4qILXH4FAl+clhYCGwIFCQPDuIACQAkQBSmW4qILXH7BdCAEGQEIAB0W +IQSGE9uHpbqCXvP9Dr4qhZ0Iv5iG2wUCX5yWFgAKCRAqhZ0Iv5iG2x3cD/9KqFC6 +gbhzNpIvZ2yrri1l1SIrB+PKvCeZSOYDlxDJ3YgAu/3+d7EwOovP8IuEb340R8w0 +onsdYDHCHODCgda+Pu/WvWxx5/wSObyd0kHPM55RLx5C5UHPdlt+yKJ0QwiMPF8g +AqVDXkc2XIghBID4ykP0V5re9ug87hVd2EYnrkMDa6N+lXtlvzptFTjBJVdu3reM +pLwHqS/GAmxhgwF6kVPxZRHcMIKLweLN2JgGd2aFaIQBj+O43XROhL5or+F/E60w +c4ZTUp/a8aRxJRrzlHgNFBbV6oknzwTQRaB1CD0YXjFZL2k5rEEfvyfXguCTDyZT +jJjYvCO0MDxL/KI9fyJpcU+entGod83Ne893XXCS2SmaTY3LvQ+v/e99trh4m7St +oOQ8xm6b10sI6TbhbgPOYgtTPLxw3BldTrU5Hphz+suPrcHybKn357l7bf9yYTfK +tsrAKPVOMNF7QEdR3UldqoGzkTo55l4omvMS93tWSG+w47W7QIAQjwTlqDyjYVg3 +2l8XlfDtcR0k+Y6ObguEMUwtsikK+FvqVS5ZCPIyvv4kMCIazMlEWocsfvrINjQ4 +II2W+oQv5vJmOyY30tPELq35taH9oOMjtY3KWZVmPzw6+DGRTA2RDR+7qm2v3lgl +i49Nzi/iSBvDeVZxSBHRRjH/OL7TKWN+WwC2I4wYD/4iox1+WcKPsI+77HaULvsP +qa+bXnKbZidrsqSejbPnLg3M9an2gDo0d62QxrnJLl9OhuhObXP/bzCjrcMkg9hY +BAHaTXbRtVlSKpXYEyuwO6HYQ7WyHlY9y9srHIvcWuBrpI9Kgd28rkT4QZB5WJD/ +Cgj4ksJAe+TsSmccdw3zG3OWWVs4HujQnWnh+NbBE7cyYqZaByKiDjL3vKP+0Zfj +M/TF8nnY7zqgSljQxScbW7//U3GiB9DKg1r9TEMzmSTDugwv7u2kM/iZPjq+dvUs +KqKuyX23WDKRLyzusDqIWKsRrkd+g1vBfxSUhWwxtwzyy1rL/tNcXGBuLOxjUit9 +LhdowjFRG93Tswac/Q8VGPEB5XjBgRNlW9vSYgw+5wTHf01UBWgEWtFhl6SJnD6u +AjnMBtduqXBXmncTA6Gz5XB1h7xM32pLncWJGHfixXiJcOgGqW+Lv1Y3eaPqCFOm +4yfYDfBL+UN8Y7sR3WrVy1R6Ut/8bf4sD/i1UyBNKSzeN5sBpi7KgA6yY7PpVIN7 +H7V1QN41Bw9vAG5WXCO8vmY0GoCMQAKM5p04mMuBr6nswy1W94q6uuINwq6q1ycf +YQJyoKhXifPhdicwDMYeuW7aP7WnPIb3VwdtlEyD+ycBsak0Jsq/+yrov3pXgrdL +dlF2O4uTr4frwKRl28eGEQ== +=ebPb +-----END PGP PUBLIC KEY BLOCK----- diff --git a/.ci/gpg/secring.auto.gpg b/.ci/gpg/secring.auto.gpg new file mode 100644 index 00000000..29f151e6 Binary files /dev/null and b/.ci/gpg/secring.auto.gpg differ diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index cb4d1126..920ccfd5 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -19,12 +19,11 @@ jobs: with: fetch-depth: 0 - - name: Import GPG Key - id: import_gpg - uses: crazy-max/ghaction-import-gpg@v3 - with: - gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} - passphrase: ${{ secrets.GPG_PASSPHRASE }} + - name: gpg init + if: github.event_name != 'pull_request' + run: .ci/gpg/create-keyring.sh + env: + GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }} - name: Install Go uses: actions/setup-go@v2 @@ -42,6 +41,9 @@ jobs: GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} docker: + # TODO(fabianvf): skip pushing images for now, reenable once we're + # working on migrating the official helm plugin here + if: ${{ false }} name: Docker runs-on: ubuntu-latest steps: @@ -54,7 +56,7 @@ jobs: - name: Prepare id: prep run: | - IMG=quay.io/joelanford/helm-operator + IMG=quay.io/operator-framework/helm-operator if [[ $GITHUB_REF == refs/tags/* ]]; then TAG=${GITHUB_REF#refs/tags/} MAJOR_MINOR=${TAG%.*} diff --git a/.goreleaser.yml b/.goreleaser.yml index 4be14687..83e0100a 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -3,7 +3,7 @@ env: - CGO_ENABLED=0 - GO111MODULE=on - GOPROXY=https://proxy.golang.org|direct - - VERSION_PKG=github.com/joelanford/helm-operator/internal/version + - VERSION_PKG=github.com/operator-framework/helm-operator-plugins/internal/version # Hooks to run before any build is run. before: @@ -48,5 +48,6 @@ checksum: name_template: "checksums.txt" signs: - - artifacts: checksum - args: ["--batch", "-u", "{{ .Env.GPG_FINGERPRINT }}", "--output", "${signature}", "--detach-sign", "${artifact}"] + - signature: "${artifact}.asc" + artifacts: checksum + args: ["--home", ".ci/gpg/keyring", "-u", "A20B5C7E", "--output", "${signature}", "--detach-sign", "${artifact}"] diff --git a/Makefile b/Makefile index 6ef236ad..ad3173e2 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ lint: fetch golangci-lint 1.35.2 && golangci-lint run .PHONY: release -release: GORELEASER_ARGS ?= --snapshot --rm-dist +release: GORELEASER_ARGS ?= --snapshot --rm-dist --skip-sign release: fetch goreleaser 0.156.2 && goreleaser $(GORELEASER_ARGS) diff --git a/README.md b/README.md index 0a8e4ac0..4f100fd5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # helm-operator -[![Build Status](https://github.com/joelanford/helm-operator/workflows/CI/badge.svg?branch=master) -[![Coverage Status](https://coveralls.io/repos/github/joelanford/helm-operator/badge.svg?branch=master)](https://coveralls.io/github/joelanford/helm-operator?branch=master) +[![Build Status](https://github.com/operator-framework/helm-operator-plugins/workflows/CI/badge.svg?branch=master) +[![Coverage Status](https://coveralls.io/repos/github/operator-framework/helm-operator-plugins/badge.svg?branch=master)](https://coveralls.io/github/operator-framework/helm-operator-plugins?branch=master) Experimental refactoring of the operator-framework's helm operator diff --git a/example/Dockerfile b/example/Dockerfile index f40ecc85..eee9e50a 100644 --- a/example/Dockerfile +++ b/example/Dockerfile @@ -1,4 +1,4 @@ -FROM quay.io/joelanford/helm-operator:main +FROM quay.io/operator-framework/helm-operator-plugins:main ENV HOME=/opt/helm COPY watches.yaml ${HOME}/watches.yaml diff --git a/go.mod b/go.mod index cd56b77d..cc89d13e 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/joelanford/helm-operator +module github.com/operator-framework/helm-operator-plugins go 1.16 @@ -8,16 +8,14 @@ require ( github.com/go-logr/logr v0.3.0 github.com/iancoleman/strcase v0.1.2 github.com/kr/text v0.1.0 - github.com/onsi/ginkgo v1.14.1 - github.com/onsi/gomega v1.10.2 + github.com/onsi/ginkgo v1.15.0 + github.com/onsi/gomega v1.10.5 github.com/operator-framework/operator-lib v0.3.0 github.com/prometheus/client_golang v1.7.1 github.com/sirupsen/logrus v1.7.0 - github.com/spf13/afero v1.2.2 github.com/spf13/cobra v1.1.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.6.1 - golang.org/x/tools v0.0.0-20200616195046-dc31b401abb5 gomodules.xyz/jsonpatch/v2 v2.1.0 helm.sh/helm/v3 v3.5.0 k8s.io/api v0.20.4 @@ -27,7 +25,7 @@ require ( k8s.io/client-go v0.20.4 k8s.io/kubectl v0.20.4 sigs.k8s.io/controller-runtime v0.8.2 - sigs.k8s.io/kubebuilder/v3 v3.0.0-beta.0 + sigs.k8s.io/kubebuilder/v3 v3.1.0 sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index dd2754e6..fb322c1b 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,5 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -24,6 +25,7 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= @@ -52,6 +54,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= @@ -70,6 +74,7 @@ github.com/Microsoft/hcsshim v0.8.7 h1:ptnOoufxGSzauVTsdE+wMYnCWA301PdoN4xg5oRdZ github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= @@ -84,11 +89,13 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -131,6 +138,7 @@ github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3k github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= @@ -141,6 +149,11 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY= +github.com/cloudflare/cfssl v1.5.0 h1:vFJDAvQgFSRbCn9zg8KpSrrEZrBAQ4KO5oNK7SXEyb0= +github.com/cloudflare/cfssl v1.5.0/go.mod h1:sPPkBS5L8l8sRc/IOO1jG51Xb34u+TYhL6P//JdODMQ= +github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4= +github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s= @@ -176,6 +189,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -211,6 +225,7 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustmop/soup v1.1.2-0.20190516214245-38228baa104e/go.mod h1:CgNC6SGbT+Xb8wGGvzilttZL1mc5sQ/5KkcxsZttMIk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= @@ -241,12 +256,15 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwLGgOgnE+rdPuvX9DxCqaHwKy7i/ko= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -295,12 +313,14 @@ github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nA github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= -github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= @@ -310,6 +330,7 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -320,6 +341,8 @@ github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6 github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/gobuffalo/flect v0.2.2 h1:PAVD7sp0KOdfswjAw9BpLCU9hXo7wFSzgpQ+zNeks/A= github.com/gobuffalo/flect v0.2.2/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= +github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI= +github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= github.com/gobuffalo/logger v1.0.1 h1:ZEgyRGgAm4ZAhAO45YXMs5Fp+bzGLESFewzAVBMKuTg= github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4= @@ -372,6 +395,8 @@ github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA// github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= +github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -462,9 +487,11 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= @@ -482,6 +509,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= +github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -493,12 +522,14 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= @@ -516,6 +547,8 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno= +github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= @@ -530,6 +563,7 @@ github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.12.0 h1:u/x3mp++qUxvYfulZ4HKOvVO0JWhk7HtE8lWhbGz/Do= github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -562,8 +596,12 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -576,6 +614,7 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= @@ -589,19 +628,19 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4= +github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= +github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -628,6 +667,7 @@ github.com/operator-framework/operator-lib v0.3.0 h1:eGJv0k7dEHIT9vfArWPo6U4eVur github.com/operator-framework/operator-lib v0.3.0/go.mod h1:LTp5UQd8ivq4MXqm/W/XHulHQ0RRoZXsAj73sNMAQxc= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu//Vk= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= @@ -682,6 +722,7 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -699,11 +740,14 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -724,7 +768,6 @@ github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= @@ -744,8 +787,10 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3 github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -761,7 +806,12 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= +github.com/weppos/publicsuffix-go v0.13.0 h1:0Tu1uzLBd1jPn4k6OnMmOPZH/l/9bj9kUOMMkoRs6Gg= +github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= @@ -770,8 +820,11 @@ github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= @@ -780,6 +833,13 @@ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1 github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= +github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= +github.com/zmap/zcrypto v0.0.0-20200513165325-16679db567ff/go.mod h1:TxpejqcVKQjQaVVmMGfzx5HnmFMdIU+vLtaCyPBfGI4= +github.com/zmap/zcrypto v0.0.0-20200911161511-43ff0ea04f21 h1:PIpcdSOg3pMdFJUBg5yR9xxcj5rm/SGAyaWT/wK6Kco= +github.com/zmap/zcrypto v0.0.0-20200911161511-43ff0ea04f21/go.mod h1:TxpejqcVKQjQaVVmMGfzx5HnmFMdIU+vLtaCyPBfGI4= +github.com/zmap/zlint/v2 v2.2.1 h1:b2kI/ToXX16h2wjV2c6Da65eT6aTMtkLHKetXuM9EtI= +github.com/zmap/zlint/v2 v2.2.1/go.mod h1:ixPWsdq8qLxYRpNUTbcKig3R7WgmspsHGLhCCs6rFAM= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= @@ -796,6 +856,8 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.starlark.net v0.0.0-20190528202925-30ae18b8564f/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -830,12 +892,14 @@ golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200124225646-8b5121be2f68/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI= +golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -869,6 +933,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -903,8 +968,11 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -916,8 +984,9 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -948,6 +1017,7 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -967,8 +1037,9 @@ golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1030,11 +1101,11 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200616195046-dc31b401abb5 h1:UaoXseXAWUJUcuJ2E2oczJdLxAJXL0lOmVaBl7kuk+I= golang.org/x/tools v0.0.0-20200616195046-dc31b401abb5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1140,6 +1211,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1253,11 +1325,15 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyz sigs.k8s.io/controller-runtime v0.7.0/go.mod h1:pJ3YBrJiAqMAZKi6UVGuE98ZrroV1p+pIhoHsMm9wdU= sigs.k8s.io/controller-runtime v0.8.2 h1:SBWmI0b3uzMIUD/BIXWNegrCeZmPJ503pOtwxY0LPHM= sigs.k8s.io/controller-runtime v0.8.2/go.mod h1:U/l+DUopBc1ecfRZ5aviA9JDmGFQKvLf5YkZNx2e0sU= +sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= +sigs.k8s.io/controller-tools v0.4.1 h1:VkuV0MxlRPmRu5iTgBZU4UxUX2LiR99n3sdQGRxZF4w= sigs.k8s.io/controller-tools v0.4.1/go.mod h1:G9rHdZMVlBDocIxGkK3jHLWqcTMNvveypYJwrvYKjWU= -sigs.k8s.io/kubebuilder/v3 v3.0.0-beta.0 h1:TXXv53toWFNR1EGU8bFfE+XaSuzzbBA/nlDRz2FbimY= -sigs.k8s.io/kubebuilder/v3 v3.0.0-beta.0/go.mod h1:b1WkCy5t/3VSRBCffSfPV1WbH+f45ls69d4ic37sW6w= +sigs.k8s.io/kubebuilder/v3 v3.1.0 h1:LPgQQcKtVwqJ19gRboBYJHRG9a/wDeP3fXO7czTKVwE= +sigs.k8s.io/kubebuilder/v3 v3.1.0/go.mod h1:kWdZWaDD6/+IEU+fX9OH6yD8XjEHBvgfcd8WjjJ9qDo= sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= +sigs.k8s.io/kustomize/kyaml v0.10.10 h1:caAxDDkaXZp+0kDsZVik4leFJV8LCy09PdVqpaoNeF4= +sigs.k8s.io/kustomize/kyaml v0.10.10/go.mod h1:K9yg1k/HB/6xNOf5VH3LhTo1DK9/5ykSZO5uIv+Y/1k= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= diff --git a/internal/cmd/run/cmd.go b/internal/cmd/run/cmd.go index 84ccee95..98fea18e 100644 --- a/internal/cmd/run/cmd.go +++ b/internal/cmd/run/cmd.go @@ -31,12 +31,12 @@ import ( zapl "sigs.k8s.io/controller-runtime/pkg/log/zap" crmetrics "sigs.k8s.io/controller-runtime/pkg/metrics" - "github.com/joelanford/helm-operator/internal/metrics" - "github.com/joelanford/helm-operator/internal/version" - "github.com/joelanford/helm-operator/pkg/annotation" - "github.com/joelanford/helm-operator/pkg/manager" - "github.com/joelanford/helm-operator/pkg/reconciler" - "github.com/joelanford/helm-operator/pkg/watches" + "github.com/operator-framework/helm-operator-plugins/internal/metrics" + "github.com/operator-framework/helm-operator-plugins/internal/version" + "github.com/operator-framework/helm-operator-plugins/pkg/annotation" + "github.com/operator-framework/helm-operator-plugins/pkg/manager" + "github.com/operator-framework/helm-operator-plugins/pkg/reconciler" + "github.com/operator-framework/helm-operator-plugins/pkg/watches" ) func NewCmd() *cobra.Command { diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 7c6761aa..51f92bad 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -17,7 +17,7 @@ package metrics import ( "github.com/prometheus/client_golang/prometheus" - helmVersion "github.com/joelanford/helm-operator/internal/version" + helmVersion "github.com/operator-framework/helm-operator-plugins/internal/version" ) const ( diff --git a/internal/version/version.go b/internal/version/version.go index a5e3e434..17fdd9de 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -26,7 +26,7 @@ import ( const ( Unknown = "unknown" - modulePath = "github.com/joelanford/helm-operator" + modulePath = "github.com/operator-framework/helm-operator-plugins" ) var ( diff --git a/main.go b/main.go index 8f8008b2..3b6f5362 100644 --- a/main.go +++ b/main.go @@ -25,9 +25,9 @@ import ( "sigs.k8s.io/kubebuilder/v3/pkg/cli" config "sigs.k8s.io/kubebuilder/v3/pkg/config/v3" - "github.com/joelanford/helm-operator/internal/cmd/run" - "github.com/joelanford/helm-operator/internal/version" - pluginv1 "github.com/joelanford/helm-operator/pkg/plugins/v1" + "github.com/operator-framework/helm-operator-plugins/internal/cmd/run" + "github.com/operator-framework/helm-operator-plugins/internal/version" + pluginv1 "github.com/operator-framework/helm-operator-plugins/pkg/plugins/v1" ) func main() { diff --git a/pkg/annotation/annotation.go b/pkg/annotation/annotation.go index 7a42b1f2..4cf7ac43 100644 --- a/pkg/annotation/annotation.go +++ b/pkg/annotation/annotation.go @@ -45,7 +45,7 @@ import ( "helm.sh/helm/v3/pkg/action" - helmclient "github.com/joelanford/helm-operator/pkg/client" + helmclient "github.com/operator-framework/helm-operator-plugins/pkg/client" ) var ( diff --git a/pkg/client/actionclient.go b/pkg/client/actionclient.go index e6315fef..9706c81d 100644 --- a/pkg/client/actionclient.go +++ b/pkg/client/actionclient.go @@ -44,8 +44,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/yaml" - "github.com/joelanford/helm-operator/pkg/internal/sdk/controllerutil" - "github.com/joelanford/helm-operator/pkg/manifestutil" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/sdk/controllerutil" + "github.com/operator-framework/helm-operator-plugins/pkg/manifestutil" ) type ActionClientGetter interface { diff --git a/pkg/client/actionclient_test.go b/pkg/client/actionclient_test.go index 4be1d0f0..dc2803b7 100644 --- a/pkg/client/actionclient_test.go +++ b/pkg/client/actionclient_test.go @@ -43,7 +43,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/apiutil" "sigs.k8s.io/yaml" - "github.com/joelanford/helm-operator/pkg/internal/testutil" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/testutil" ) const mockTestDesc = "Test Description" diff --git a/pkg/client/actionconfig_test.go b/pkg/client/actionconfig_test.go index bf6b7b06..df7c5745 100644 --- a/pkg/client/actionconfig_test.go +++ b/pkg/client/actionconfig_test.go @@ -22,7 +22,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/apiutil" - "github.com/joelanford/helm-operator/pkg/internal/testutil" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/testutil" ) var _ = Describe("ActionConfig", func() { diff --git a/pkg/client/client_suite_test.go b/pkg/client/client_suite_test.go index 17d2fd19..bf21aaec 100644 --- a/pkg/client/client_suite_test.go +++ b/pkg/client/client_suite_test.go @@ -28,7 +28,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - "github.com/joelanford/helm-operator/pkg/internal/testutil" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/testutil" ) func TestClient(t *testing.T) { diff --git a/pkg/hook/hook_test.go b/pkg/hook/hook_test.go index 4b185249..eb81a7d7 100644 --- a/pkg/hook/hook_test.go +++ b/pkg/hook/hook_test.go @@ -24,7 +24,7 @@ import ( "helm.sh/helm/v3/pkg/release" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - . "github.com/joelanford/helm-operator/pkg/hook" + . "github.com/operator-framework/helm-operator-plugins/pkg/hook" ) var _ = Describe("Hook", func() { diff --git a/pkg/internal/sdk/controllerutil/controllerutil_test.go b/pkg/internal/sdk/controllerutil/controllerutil_test.go index 8bebcc58..6ad13f38 100644 --- a/pkg/internal/sdk/controllerutil/controllerutil_test.go +++ b/pkg/internal/sdk/controllerutil/controllerutil_test.go @@ -31,7 +31,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - . "github.com/joelanford/helm-operator/pkg/internal/sdk/controllerutil" + . "github.com/operator-framework/helm-operator-plugins/pkg/internal/sdk/controllerutil" ) var _ = Describe("Controllerutil", func() { diff --git a/pkg/manager/delegatingclient_test.go b/pkg/manager/delegatingclient_test.go index f4fbc530..559c2148 100644 --- a/pkg/manager/delegatingclient_test.go +++ b/pkg/manager/delegatingclient_test.go @@ -32,7 +32,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" - . "github.com/joelanford/helm-operator/pkg/manager" + . "github.com/operator-framework/helm-operator-plugins/pkg/manager" ) var _ = Describe("NewCachingClientBuilder", func() { diff --git a/pkg/manager/namespace_test.go b/pkg/manager/namespace_test.go index 980f4ce8..f413e23a 100644 --- a/pkg/manager/namespace_test.go +++ b/pkg/manager/namespace_test.go @@ -34,7 +34,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" - . "github.com/joelanford/helm-operator/pkg/manager" + . "github.com/operator-framework/helm-operator-plugins/pkg/manager" ) var _ = Describe("ConfigureWatchNamespaces", func() { diff --git a/pkg/manifestutil/resourcepolicykeep_test.go b/pkg/manifestutil/resourcepolicykeep_test.go index 7a078a27..93a07e32 100644 --- a/pkg/manifestutil/resourcepolicykeep_test.go +++ b/pkg/manifestutil/resourcepolicykeep_test.go @@ -23,7 +23,7 @@ import ( . "github.com/onsi/gomega" "helm.sh/helm/v3/pkg/kube" - "github.com/joelanford/helm-operator/pkg/manifestutil" + "github.com/operator-framework/helm-operator-plugins/pkg/manifestutil" ) var _ = Describe("HasResourcePolicyKeep", func() { diff --git a/pkg/plugins/internal/kubebuilder/cmdutil/cmdutil.go b/pkg/plugins/internal/kubebuilder/cmdutil/cmdutil.go deleted file mode 100644 index aa3e7f4a..00000000 --- a/pkg/plugins/internal/kubebuilder/cmdutil/cmdutil.go +++ /dev/null @@ -1,60 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package cmdutil - -// Scaffolder interface creates files to set up a controller manager -type Scaffolder interface { - // Scaffold performs the scaffolding - Scaffold() error -} - -// RunOptions represent the types used to implement the different commands -type RunOptions interface { - // - Step 1: verify that the command can be run (e.g., go version, project version, arguments, ...) - Validate() error - // - Step 2: create the Scaffolder instance - GetScaffolder() (Scaffolder, error) - // - Step 3: call the Scaffold method of the Scaffolder instance. Doesn't need any method - // - Step 4: finish the command execution - PostScaffold() error -} - -// Run executes a command -func Run(options RunOptions) error { - // Step 1: validate - if err := options.Validate(); err != nil { - return err - } - - // Step 2: get scaffolder - scaffolder, err := options.GetScaffolder() - if err != nil { - return err - } - // Step 3: scaffold - if scaffolder != nil { - if err := scaffolder.Scaffold(); err != nil { - return err - } - } - // Step 4: finish - if err := options.PostScaffold(); err != nil { - return err - } - - return nil -} diff --git a/pkg/plugins/internal/kubebuilder/filesystem/errors.go b/pkg/plugins/internal/kubebuilder/filesystem/errors.go deleted file mode 100644 index 7f605d32..00000000 --- a/pkg/plugins/internal/kubebuilder/filesystem/errors.go +++ /dev/null @@ -1,173 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "errors" - "fmt" -) - -// This file contains the errors returned by the file system wrapper -// They are not exported as they should not be created outside of this package -// Exported functions are provided to check which kind of error was returned - -// fileExistsError is returned if it could not be checked if the file exists -type fileExistsError struct { - path string - err error -} - -// Error implements error interface -func (e fileExistsError) Error() string { - return fmt.Sprintf("failed to check if %s exists: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e fileExistsError) Unwrap() error { - return e.err -} - -// IsFileExistsError checks if the returned error is because the file could not be checked for existence -func IsFileExistsError(err error) bool { - return errors.As(err, &fileExistsError{}) -} - -// openFileError is returned if the file could not be opened -type openFileError struct { - path string - err error -} - -// Error implements error interface -func (e openFileError) Error() string { - return fmt.Sprintf("failed to open %s: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e openFileError) Unwrap() error { - return e.err -} - -// IsOpenFileError checks if the returned error is because the file could not be opened -func IsOpenFileError(err error) bool { - return errors.As(err, &openFileError{}) -} - -// createDirectoryError is returned if the directory could not be created -type createDirectoryError struct { - path string - err error -} - -// Error implements error interface -func (e createDirectoryError) Error() string { - return fmt.Sprintf("failed to create directory for %s: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e createDirectoryError) Unwrap() error { - return e.err -} - -// IsCreateDirectoryError checks if the returned error is because the directory could not be created -func IsCreateDirectoryError(err error) bool { - return errors.As(err, &createDirectoryError{}) -} - -// createFileError is returned if the file could not be created -type createFileError struct { - path string - err error -} - -// Error implements error interface -func (e createFileError) Error() string { - return fmt.Sprintf("failed to create %s: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e createFileError) Unwrap() error { - return e.err -} - -// IsCreateFileError checks if the returned error is because the file could not be created -func IsCreateFileError(err error) bool { - return errors.As(err, &createFileError{}) -} - -// readFileError is returned if the file could not be read -type readFileError struct { - path string - err error -} - -// Error implements error interface -func (e readFileError) Error() string { - return fmt.Sprintf("failed to read from %s: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e readFileError) Unwrap() error { - return e.err -} - -// IsReadFileError checks if the returned error is because the file could not be read -func IsReadFileError(err error) bool { - return errors.As(err, &readFileError{}) -} - -// writeFileError is returned if the file could not be written -type writeFileError struct { - path string - err error -} - -// Error implements error interface -func (e writeFileError) Error() string { - return fmt.Sprintf("failed to write to %s: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e writeFileError) Unwrap() error { - return e.err -} - -// IsWriteFileError checks if the returned error is because the file could not be written to -func IsWriteFileError(err error) bool { - return errors.As(err, &writeFileError{}) -} - -// closeFileError is returned if the file could not be created -type closeFileError struct { - path string - err error -} - -// Error implements error interface -func (e closeFileError) Error() string { - return fmt.Sprintf("failed to close %s: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e closeFileError) Unwrap() error { - return e.err -} - -// IsCloseFileError checks if the returned error is because the file could not be closed -func IsCloseFileError(err error) bool { - return errors.As(err, &closeFileError{}) -} diff --git a/pkg/plugins/internal/kubebuilder/filesystem/errors_test.go b/pkg/plugins/internal/kubebuilder/filesystem/errors_test.go deleted file mode 100644 index 090101fa..00000000 --- a/pkg/plugins/internal/kubebuilder/filesystem/errors_test.go +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "errors" - "path/filepath" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/ginkgo/extensions/table" - . "github.com/onsi/gomega" -) - -var _ = Describe("Errors", func() { - var ( - path = filepath.Join("path", "to", "file") - err = errors.New("test error") - fileExistsErr = fileExistsError{path, err} - openFileErr = openFileError{path, err} - createDirectoryErr = createDirectoryError{path, err} - createFileErr = createFileError{path, err} - readFileErr = readFileError{path, err} - writeFileErr = writeFileError{path, err} - closeFileErr = closeFileError{path, err} - ) - - DescribeTable("IsXxxxError should return true for themselves and false for the rest", - func(f func(error) bool, itself error, rest ...error) { - Expect(f(itself)).To(BeTrue()) - for _, err := range rest { - Expect(f(err)).To(BeFalse()) - } - }, - Entry("file exists", IsFileExistsError, fileExistsErr, - openFileErr, createDirectoryErr, createFileErr, readFileErr, writeFileErr, closeFileErr), - Entry("open file", IsOpenFileError, openFileErr, - fileExistsErr, createDirectoryErr, createFileErr, readFileErr, writeFileErr, closeFileErr), - Entry("create directory", IsCreateDirectoryError, createDirectoryErr, - fileExistsErr, openFileErr, createFileErr, readFileErr, writeFileErr, closeFileErr), - Entry("create file", IsCreateFileError, createFileErr, - fileExistsErr, openFileErr, createDirectoryErr, readFileErr, writeFileErr, closeFileErr), - Entry("read file", IsReadFileError, readFileErr, - fileExistsErr, openFileErr, createDirectoryErr, createFileErr, writeFileErr, closeFileErr), - Entry("write file", IsWriteFileError, writeFileErr, - fileExistsErr, openFileErr, createDirectoryErr, createFileErr, readFileErr, closeFileErr), - Entry("close file", IsCloseFileError, closeFileErr, - fileExistsErr, openFileErr, createDirectoryErr, createFileErr, readFileErr, writeFileErr), - ) - - DescribeTable("should contain the wrapped error and error message", - func(err error) { - Expect(err).To(MatchError(err)) - Expect(err.Error()).To(ContainSubstring(err.Error())) - }, - Entry("file exists", fileExistsErr), - Entry("open file", openFileErr), - Entry("create directory", createDirectoryErr), - Entry("create file", createFileErr), - Entry("read file", readFileErr), - Entry("write file", writeFileErr), - Entry("close file", closeFileErr), - ) -}) diff --git a/pkg/plugins/internal/kubebuilder/filesystem/filesystem.go b/pkg/plugins/internal/kubebuilder/filesystem/filesystem.go deleted file mode 100644 index e7e362c5..00000000 --- a/pkg/plugins/internal/kubebuilder/filesystem/filesystem.go +++ /dev/null @@ -1,181 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "io" - "os" - "path/filepath" - - "github.com/spf13/afero" -) - -const ( - createOrUpdate = os.O_WRONLY | os.O_CREATE | os.O_TRUNC - - defaultDirectoryPermission os.FileMode = 0700 - defaultFilePermission os.FileMode = 0600 -) - -// FileSystem is an IO wrapper to create files -type FileSystem interface { - // Exists checks if the file exists - Exists(path string) (bool, error) - - // Open opens the file and returns a self-closing io.Reader. - Open(path string) (io.ReadCloser, error) - - // Create creates the directory and file and returns a self-closing - // io.Writer pointing to that file. If the file exists, it truncates it. - Create(path string) (io.Writer, error) -} - -// fileSystem implements FileSystem -type fileSystem struct { - fs afero.Fs - dirPerm os.FileMode - filePerm os.FileMode - fileMode int -} - -// New returns a new FileSystem -func New(options ...Options) FileSystem { - // Default values - fs := fileSystem{ - fs: afero.NewOsFs(), - dirPerm: defaultDirectoryPermission, - filePerm: defaultFilePermission, - fileMode: createOrUpdate, - } - - // Apply options - for _, option := range options { - option(&fs) - } - - return fs -} - -// Options configure FileSystem -type Options func(system *fileSystem) - -// DirectoryPermissions makes FileSystem.Create use the provided directory -// permissions -func DirectoryPermissions(dirPerm os.FileMode) Options { - return func(fs *fileSystem) { - fs.dirPerm = dirPerm - } -} - -// FilePermissions makes FileSystem.Create use the provided file permissions -func FilePermissions(filePerm os.FileMode) Options { - return func(fs *fileSystem) { - fs.filePerm = filePerm - } -} - -// Exists implements FileSystem.Exists -func (fs fileSystem) Exists(path string) (bool, error) { - exists, err := afero.Exists(fs.fs, path) - if err != nil { - return exists, fileExistsError{path, err} - } - - return exists, nil -} - -// Open implements FileSystem.Open -func (fs fileSystem) Open(path string) (io.ReadCloser, error) { - rc, err := fs.fs.Open(path) - if err != nil { - return nil, openFileError{path, err} - } - - return &readFile{path, rc}, nil -} - -// Create implements FileSystem.Create -func (fs fileSystem) Create(path string) (io.Writer, error) { - // Create the directory if needed - if err := fs.fs.MkdirAll(filepath.Dir(path), fs.dirPerm); err != nil { - return nil, createDirectoryError{path, err} - } - - // Create or truncate the file - wc, err := fs.fs.OpenFile(path, fs.fileMode, fs.filePerm) - if err != nil { - return nil, createFileError{path, err} - } - - return &writeFile{path, wc}, nil -} - -var _ io.ReadCloser = &readFile{} - -// readFile implements io.Reader -type readFile struct { - path string - io.ReadCloser -} - -// Read implements io.Reader.ReadCloser -func (f *readFile) Read(content []byte) (n int, err error) { - // Read the content - n, err = f.ReadCloser.Read(content) - // EOF is a special case error that we can't wrap - if err == io.EOF { - return - } - if err != nil { - return n, readFileError{f.path, err} - } - - return n, nil -} - -// Close implements io.Reader.ReadCloser -func (f *readFile) Close() error { - if err := f.ReadCloser.Close(); err != nil { - return closeFileError{f.path, err} - } - - return nil -} - -// writeFile implements io.Writer -type writeFile struct { - path string - io.WriteCloser -} - -// Write implements io.Writer.Write -func (f *writeFile) Write(content []byte) (n int, err error) { - // Close the file when we end writing - defer func() { - if closeErr := f.Close(); err == nil && closeErr != nil { - err = closeFileError{f.path, err} - } - }() - - // Write the content - n, err = f.WriteCloser.Write(content) - if err != nil { - return n, writeFileError{f.path, err} - } - - return n, nil -} diff --git a/pkg/plugins/internal/kubebuilder/filesystem/filesystem_suite_test.go b/pkg/plugins/internal/kubebuilder/filesystem/filesystem_suite_test.go deleted file mode 100644 index 47302470..00000000 --- a/pkg/plugins/internal/kubebuilder/filesystem/filesystem_suite_test.go +++ /dev/null @@ -1,29 +0,0 @@ -/* -Copyright 2021 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func TestScaffold(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Filesystem suite") -} diff --git a/pkg/plugins/internal/kubebuilder/filesystem/filesystem_test.go b/pkg/plugins/internal/kubebuilder/filesystem/filesystem_test.go deleted file mode 100644 index 6a3d216f..00000000 --- a/pkg/plugins/internal/kubebuilder/filesystem/filesystem_test.go +++ /dev/null @@ -1,150 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "os" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("FileSystem", func() { - Describe("New", func() { - const ( - dirPerm os.FileMode = 0777 - filePerm os.FileMode = 0666 - ) - - var ( - fsi FileSystem - fs fileSystem - ok bool - ) - - Context("when using no options", func() { - BeforeEach(func() { - fsi = New() - fs, ok = fsi.(fileSystem) - }) - - It("should be a fileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should not have a nil fs", func() { - Expect(fs.fs).NotTo(BeNil()) - }) - - It("should use default directory permission", func() { - Expect(fs.dirPerm).To(Equal(defaultDirectoryPermission)) - }) - - It("should use default file permission", func() { - Expect(fs.filePerm).To(Equal(defaultFilePermission)) - }) - - It("should use default file mode", func() { - Expect(fs.fileMode).To(Equal(createOrUpdate)) - }) - }) - - Context("when using directory permission option", func() { - BeforeEach(func() { - fsi = New(DirectoryPermissions(dirPerm)) - fs, ok = fsi.(fileSystem) - }) - - It("should be a fileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should not have a nil fs", func() { - Expect(fs.fs).NotTo(BeNil()) - }) - - It("should use provided directory permission", func() { - Expect(fs.dirPerm).To(Equal(dirPerm)) - }) - - It("should use default file permission", func() { - Expect(fs.filePerm).To(Equal(defaultFilePermission)) - }) - - It("should use default file mode", func() { - Expect(fs.fileMode).To(Equal(createOrUpdate)) - }) - }) - - Context("when using file permission option", func() { - BeforeEach(func() { - fsi = New(FilePermissions(filePerm)) - fs, ok = fsi.(fileSystem) - }) - - It("should be a fileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should not have a nil fs", func() { - Expect(fs.fs).NotTo(BeNil()) - }) - - It("should use default directory permission", func() { - Expect(fs.dirPerm).To(Equal(defaultDirectoryPermission)) - }) - - It("should use provided file permission", func() { - Expect(fs.filePerm).To(Equal(filePerm)) - }) - - It("should use default file mode", func() { - Expect(fs.fileMode).To(Equal(createOrUpdate)) - }) - }) - - Context("when using both directory and file permission options", func() { - BeforeEach(func() { - fsi = New(DirectoryPermissions(dirPerm), FilePermissions(filePerm)) - fs, ok = fsi.(fileSystem) - }) - - It("should be a fileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should not have a nil fs", func() { - Expect(fs.fs).NotTo(BeNil()) - }) - - It("should use provided directory permission", func() { - Expect(fs.dirPerm).To(Equal(dirPerm)) - }) - - It("should use provided file permission", func() { - Expect(fs.filePerm).To(Equal(filePerm)) - }) - - It("should use default file mode", func() { - Expect(fs.fileMode).To(Equal(createOrUpdate)) - }) - }) - }) - - // NOTE: FileSystem.Exists, FileSystem.Open, FileSystem.Open().Read, FileSystem.Create and FileSystem.Create().Write - // are hard to test in unitary tests as they deal with actual files -}) diff --git a/pkg/plugins/internal/kubebuilder/filesystem/mock.go b/pkg/plugins/internal/kubebuilder/filesystem/mock.go deleted file mode 100644 index b7d213c1..00000000 --- a/pkg/plugins/internal/kubebuilder/filesystem/mock.go +++ /dev/null @@ -1,217 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "bytes" - "io" -) - -// mockFileSystem implements FileSystem -type mockFileSystem struct { - path string - exists func(path string) bool - existsError error - openFileError error - createDirError error - createFileError error - input *bytes.Buffer - readFileError error - output *bytes.Buffer - writeFileError error - closeFileError error -} - -// NewMock returns a new FileSystem -func NewMock(options ...MockOptions) FileSystem { - // Default values - fs := mockFileSystem{ - exists: func(_ string) bool { return false }, - output: new(bytes.Buffer), - } - - // Apply options - for _, option := range options { - option(&fs) - } - - return fs -} - -// MockOptions configure FileSystem -type MockOptions func(system *mockFileSystem) - -// MockPath ensures that the file created with this scaffold is at path -func MockPath(path string) MockOptions { - return func(fs *mockFileSystem) { - fs.path = path - } -} - -// MockExists makes FileSystem.Exists use the provided function to check if the file exists -func MockExists(exists func(path string) bool) MockOptions { - return func(fs *mockFileSystem) { - fs.exists = exists - } -} - -// MockExistsError makes FileSystem.Exists return err -func MockExistsError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.existsError = err - } -} - -// MockOpenFileError makes FileSystem.Open return err -func MockOpenFileError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.openFileError = err - } -} - -// MockCreateDirError makes FileSystem.Create return err -func MockCreateDirError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.createDirError = err - } -} - -// MockCreateFileError makes FileSystem.Create return err -func MockCreateFileError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.createFileError = err - } -} - -// MockInput provides a buffer where the content will be read from -func MockInput(input *bytes.Buffer) MockOptions { - return func(fs *mockFileSystem) { - fs.input = input - } -} - -// MockReadFileError makes the Read method (of the io.Reader returned by FileSystem.Open) return err -func MockReadFileError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.readFileError = err - } -} - -// MockOutput provides a buffer where the content will be written -func MockOutput(output *bytes.Buffer) MockOptions { - return func(fs *mockFileSystem) { - fs.output = output - } -} - -// MockWriteFileError makes the Write method (of the io.Writer returned by FileSystem.Create) return err -func MockWriteFileError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.writeFileError = err - } -} - -// MockCloseFileError makes the Write method (of the io.Writer returned by FileSystem.Create) return err -func MockCloseFileError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.closeFileError = err - } -} - -// Exists implements FileSystem.Exists -func (fs mockFileSystem) Exists(path string) (bool, error) { - if fs.existsError != nil { - return false, fileExistsError{path, fs.existsError} - } - - return fs.exists(path), nil -} - -// Open implements FileSystem.Open -func (fs mockFileSystem) Open(path string) (io.ReadCloser, error) { - if fs.openFileError != nil { - return nil, openFileError{path, fs.openFileError} - } - - if fs.input == nil { - fs.input = bytes.NewBufferString("Hello world!") - } - - return &mockReadFile{path, fs.input, fs.readFileError, fs.closeFileError}, nil -} - -// Create implements FileSystem.Create -func (fs mockFileSystem) Create(path string) (io.Writer, error) { - if fs.createDirError != nil { - return nil, createDirectoryError{path, fs.createDirError} - } - - if fs.createFileError != nil { - return nil, createFileError{path, fs.createFileError} - } - - return &mockWriteFile{path, fs.output, fs.writeFileError, fs.closeFileError}, nil -} - -// mockReadFile implements io.Reader mocking a readFile for tests -type mockReadFile struct { - path string - input *bytes.Buffer - readFileError error - closeFileError error -} - -// Read implements io.Reader.ReadCloser -func (f *mockReadFile) Read(content []byte) (n int, err error) { - if f.readFileError != nil { - return 0, readFileError{path: f.path, err: f.readFileError} - } - - return f.input.Read(content) -} - -// Read implements io.Reader.ReadCloser -func (f *mockReadFile) Close() error { - if f.closeFileError != nil { - return closeFileError{path: f.path, err: f.closeFileError} - } - - return nil -} - -// mockWriteFile implements io.Writer mocking a writeFile for tests -type mockWriteFile struct { - path string - content *bytes.Buffer - writeFileError error - closeFileError error -} - -// Write implements io.Writer.Write -func (f *mockWriteFile) Write(content []byte) (n int, err error) { - defer func() { - if err == nil && f.closeFileError != nil { - err = closeFileError{f.path, f.closeFileError} - } - }() - - if f.writeFileError != nil { - return 0, writeFileError{f.path, f.writeFileError} - } - - return f.content.Write(content) -} diff --git a/pkg/plugins/internal/kubebuilder/filesystem/mock_test.go b/pkg/plugins/internal/kubebuilder/filesystem/mock_test.go deleted file mode 100644 index e9e7d58c..00000000 --- a/pkg/plugins/internal/kubebuilder/filesystem/mock_test.go +++ /dev/null @@ -1,448 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "bytes" - "errors" - "path/filepath" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -//nolint:dupl -var _ = Describe("MockFileSystem", func() { - var ( - fsi FileSystem - fs mockFileSystem - ok bool - options []MockOptions - testErr = errors.New("test error") - ) - - JustBeforeEach(func() { - fsi = NewMock(options...) - fs, ok = fsi.(mockFileSystem) - }) - - Context("when using no options", func() { - BeforeEach(func() { - options = make([]MockOptions, 0) - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - Context("when using MockPath", func() { - var filePath = filepath.Join("path", "to", "file") - - BeforeEach(func() { - options = []MockOptions{MockPath(filePath)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should save the provided path", func() { - Expect(fs.path).To(Equal(filePath)) - }) - }) - - Context("when using MockExists", func() { - BeforeEach(func() { - options = []MockOptions{MockExists(func(_ string) bool { return true })} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeTrue()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - Context("when using MockExistsError", func() { - BeforeEach(func() { - options = []MockOptions{MockExistsError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should error when calling Exists", func() { - _, err := fsi.Exists("") - Expect(err).To(MatchError(testErr)) - Expect(IsFileExistsError(err)).To(BeTrue()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - Context("when using MockOpenFileError", func() { - BeforeEach(func() { - options = []MockOptions{MockOpenFileError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should error when calling Open", func() { - _, err := fsi.Open("") - Expect(err).To(MatchError(testErr)) - Expect(IsOpenFileError(err)).To(BeTrue()) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - Context("when using MockCreateDirError", func() { - BeforeEach(func() { - options = []MockOptions{MockCreateDirError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should error when calling Create", func() { - _, err := fsi.Create("") - Expect(err).To(MatchError(testErr)) - Expect(IsCreateDirectoryError(err)).To(BeTrue()) - }) - }) - - Context("when using MockCreateFileError", func() { - BeforeEach(func() { - options = []MockOptions{MockCreateFileError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should error when calling Create", func() { - _, err := fsi.Create("") - Expect(err).To(MatchError(testErr)) - Expect(IsCreateFileError(err)).To(BeTrue()) - }) - }) - - Context("when using MockInput", func() { - var ( - input *bytes.Buffer - fileContent = []byte("Hello world!") - ) - - BeforeEach(func() { - input = bytes.NewBufferString("Hello world!") - options = []MockOptions{MockInput(input)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files and the content to be accessible", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - output := make([]byte, len(fileContent)) - n, err := f.Read(output) - Expect(err).NotTo(HaveOccurred()) - Expect(n).To(Equal(len(fileContent))) - Expect(output).To(Equal(fileContent)) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - Context("when using MockReadFileError", func() { - BeforeEach(func() { - options = []MockOptions{MockReadFileError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should error when calling Open().Read", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - output := make([]byte, 0) - _, err = f.Read(output) - Expect(err).To(MatchError(testErr)) - Expect(IsReadFileError(err)).To(BeTrue()) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - Context("when using MockOutput", func() { - var ( - output bytes.Buffer - fileContent = []byte("Hello world!") - ) - - BeforeEach(func() { - options = []MockOptions{MockOutput(&output)} - output.Reset() - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should create writable files and the content should be accesible", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - n, err := f.Write(fileContent) - Expect(err).NotTo(HaveOccurred()) - Expect(n).To(Equal(len(fileContent))) - Expect(output.Bytes()).To(Equal(fileContent)) - }) - }) - - Context("when using MockWriteFileError", func() { - BeforeEach(func() { - options = []MockOptions{MockWriteFileError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should error when calling Create().Write", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).To(MatchError(testErr)) - Expect(IsWriteFileError(err)).To(BeTrue()) - }) - }) - - Context("when using MockCloseFileError", func() { - BeforeEach(func() { - options = []MockOptions{MockCloseFileError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should error when calling Open().Close", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - err = f.Close() - Expect(err).To(MatchError(testErr)) - Expect(IsCloseFileError(err)).To(BeTrue()) - }) - - It("should error when calling Create().Write", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).To(MatchError(testErr)) - Expect(IsCloseFileError(err)).To(BeTrue()) - }) - }) -}) diff --git a/pkg/plugins/internal/kubebuilder/machinery/errors.go b/pkg/plugins/internal/kubebuilder/machinery/errors.go deleted file mode 100644 index faba57a1..00000000 --- a/pkg/plugins/internal/kubebuilder/machinery/errors.go +++ /dev/null @@ -1,74 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package machinery - -import ( - "errors" - "fmt" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -// This file contains the errors returned by the scaffolding machinery -// They are not exported as they should not be created outside of this package -// Exported functions are provided to check which kind of error was returned - -// fileAlreadyExistsError is returned if the file is expected not to exist but it does -type fileAlreadyExistsError struct { - path string -} - -// Error implements error interface -func (e fileAlreadyExistsError) Error() string { - return fmt.Sprintf("failed to create %s: file already exists", e.path) -} - -// IsFileAlreadyExistsError checks if the returned error is because the file already existed when expected not to -func IsFileAlreadyExistsError(err error) bool { - return errors.As(err, &fileAlreadyExistsError{}) -} - -// modelAlreadyExistsError is returned if the file is expected not to exist but a previous model does -type modelAlreadyExistsError struct { - path string -} - -// Error implements error interface -func (e modelAlreadyExistsError) Error() string { - return fmt.Sprintf("failed to create %s: model already exists", e.path) -} - -// IsModelAlreadyExistsError checks if the returned error is because the model already existed when expected not to -func IsModelAlreadyExistsError(err error) bool { - return errors.As(err, &modelAlreadyExistsError{}) -} - -// unknownIfExistsActionError is returned if the if-exists-action is unknown -type unknownIfExistsActionError struct { - path string - ifExistsAction file.IfExistsAction -} - -// Error implements error interface -func (e unknownIfExistsActionError) Error() string { - return fmt.Sprintf("unknown behavior if file exists (%d) for %s", e.ifExistsAction, e.path) -} - -// IsUnknownIfExistsActionError checks if the returned error is because the if-exists-action is unknown -func IsUnknownIfExistsActionError(err error) bool { - return errors.As(err, &unknownIfExistsActionError{}) -} diff --git a/pkg/plugins/internal/kubebuilder/machinery/errors_test.go b/pkg/plugins/internal/kubebuilder/machinery/errors_test.go deleted file mode 100644 index 3d6b8ce1..00000000 --- a/pkg/plugins/internal/kubebuilder/machinery/errors_test.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package machinery - -import ( - "errors" - "path/filepath" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/ginkgo/extensions/table" - . "github.com/onsi/gomega" -) - -var _ = Describe("Errors", func() { - var ( - path = filepath.Join("path", "to", "file") - err = errors.New("test error") - fileAlreadyExistsErr = fileAlreadyExistsError{path} - modelAlreadyExistsErr = modelAlreadyExistsError{path} - unknownIfExistsActionErr = unknownIfExistsActionError{path, -1} - ) - - DescribeTable("IsXxxxError should return true for themselves and false for the rest", - func(f func(error) bool, itself error, rest ...error) { - Expect(f(itself)).To(BeTrue()) - for _, err := range rest { - Expect(f(err)).To(BeFalse()) - } - }, - Entry("file exists", IsFileAlreadyExistsError, fileAlreadyExistsErr, - err, modelAlreadyExistsErr, unknownIfExistsActionErr), - Entry("model exists", IsModelAlreadyExistsError, modelAlreadyExistsErr, - err, fileAlreadyExistsErr, unknownIfExistsActionErr), - Entry("unknown if exists action", IsUnknownIfExistsActionError, unknownIfExistsActionErr, - err, fileAlreadyExistsErr, modelAlreadyExistsErr), - ) - - DescribeTable("should contain the wrapped error and error message", - func(err error) { - Expect(err).To(MatchError(err)) - Expect(err.Error()).To(ContainSubstring(err.Error())) - }, - ) - - // NOTE: the following test increases coverage - It("should print a descriptive error message", func() { - Expect(fileAlreadyExistsErr.Error()).To(ContainSubstring("file already exists")) - Expect(modelAlreadyExistsErr.Error()).To(ContainSubstring("model already exists")) - Expect(unknownIfExistsActionErr.Error()).To(ContainSubstring("unknown behavior if file exists")) - }) -}) diff --git a/pkg/plugins/internal/kubebuilder/machinery/machinery_suite_test.go b/pkg/plugins/internal/kubebuilder/machinery/machinery_suite_test.go deleted file mode 100644 index becbe2ed..00000000 --- a/pkg/plugins/internal/kubebuilder/machinery/machinery_suite_test.go +++ /dev/null @@ -1,29 +0,0 @@ -/* -Copyright 2021 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package machinery - -import ( - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func TestMachinery(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Machinery suite") -} diff --git a/pkg/plugins/internal/kubebuilder/machinery/scaffold.go b/pkg/plugins/internal/kubebuilder/machinery/scaffold.go deleted file mode 100644 index 05ea32c5..00000000 --- a/pkg/plugins/internal/kubebuilder/machinery/scaffold.go +++ /dev/null @@ -1,389 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package machinery - -import ( - "bufio" - "bytes" - "fmt" - "io/ioutil" - "path/filepath" - "strings" - "text/template" - - "golang.org/x/tools/imports" - "sigs.k8s.io/kubebuilder/v3/pkg/model" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" - - "github.com/joelanford/helm-operator/pkg/plugins/internal/kubebuilder/filesystem" -) - -var options = imports.Options{ - Comments: true, - TabIndent: true, - TabWidth: 8, - FormatOnly: true, -} - -// Scaffold uses templates to scaffold new files -type Scaffold interface { - // Execute writes to disk the provided files - Execute(*model.Universe, ...file.Builder) error -} - -// scaffold implements Scaffold interface -type scaffold struct { - // plugins is the list of plugins we should allow to transform our generated scaffolding - plugins []model.Plugin - - // fs allows to mock the file system for tests - fs filesystem.FileSystem -} - -// NewScaffold returns a new Scaffold with the provided plugins -func NewScaffold(plugins ...model.Plugin) Scaffold { - return &scaffold{ - plugins: plugins, - fs: filesystem.New(), - } -} - -// Execute implements Scaffold.Execute -func (s *scaffold) Execute(universe *model.Universe, files ...file.Builder) error { - // Initialize the universe files - universe.Files = make(map[string]*file.File, len(files)) - - // Set the repo as the local prefix so that it knows how to group imports - if universe.Config != nil { - imports.LocalPrefix = universe.Config.GetRepository() - } - - for _, f := range files { - // Inject common fields - universe.InjectInto(f) - - // Validate file builders - if reqValFile, requiresValidation := f.(file.RequiresValidation); requiresValidation { - if err := reqValFile.Validate(); err != nil { - return file.NewValidateError(err) - } - } - - // Build models for Template builders - if t, isTemplate := f.(file.Template); isTemplate { - if err := s.buildFileModel(t, universe.Files); err != nil { - return err - } - } - - // Build models for Inserter builders - if i, isInserter := f.(file.Inserter); isInserter { - if err := s.updateFileModel(i, universe.Files); err != nil { - return err - } - } - } - - // Execute plugins - for _, plugin := range s.plugins { - if err := plugin.Pipe(universe); err != nil { - return model.NewPluginError(err) - } - } - - // Persist the files to disk - for _, f := range universe.Files { - if err := s.writeFile(f); err != nil { - return err - } - } - - return nil -} - -// buildFileModel scaffolds a single file -func (scaffold) buildFileModel(t file.Template, models map[string]*file.File) error { - // Set the template default values - err := t.SetTemplateDefaults() - if err != nil { - return file.NewSetTemplateDefaultsError(err) - } - - // Handle already existing models - if _, found := models[t.GetPath()]; found { - switch t.GetIfExistsAction() { - case file.Skip: - return nil - case file.Error: - return modelAlreadyExistsError{t.GetPath()} - case file.Overwrite: - default: - return unknownIfExistsActionError{t.GetPath(), t.GetIfExistsAction()} - } - } - - m := &file.File{ - Path: t.GetPath(), - IfExistsAction: t.GetIfExistsAction(), - } - - b, err := doTemplate(t) - if err != nil { - return err - } - m.Contents = string(b) - - models[m.Path] = m - return nil -} - -// doTemplate executes the template for a file using the input -func doTemplate(t file.Template) ([]byte, error) { - temp, err := newTemplate(t).Parse(t.GetBody()) - if err != nil { - return nil, err - } - - out := &bytes.Buffer{} - err = temp.Execute(out, t) - if err != nil { - return nil, err - } - b := out.Bytes() - - // TODO(adirio): move go-formatting to write step - // gofmt the imports - if filepath.Ext(t.GetPath()) == ".go" { - b, err = imports.Process(t.GetPath(), b, &options) - if err != nil { - return nil, err - } - } - - return b, nil -} - -// newTemplate a new template with common functions -func newTemplate(t file.Template) *template.Template { - fm := file.DefaultFuncMap() - useFM, ok := t.(file.UseCustomFuncMap) - if ok { - fm = useFM.GetFuncMap() - } - return template.New(fmt.Sprintf("%T", t)).Funcs(fm) -} - -// updateFileModel updates a single file -func (s scaffold) updateFileModel(i file.Inserter, models map[string]*file.File) error { - m, err := s.loadPreviousModel(i, models) - if err != nil { - return err - } - - // Get valid code fragments - codeFragments := getValidCodeFragments(i) - - // Remove code fragments that already were applied - err = filterExistingValues(m.Contents, codeFragments) - if err != nil { - return err - } - - // If no code fragment to insert, we are done - if len(codeFragments) == 0 { - return nil - } - - content, err := insertStrings(m.Contents, codeFragments) - if err != nil { - return err - } - - // TODO(adirio): move go-formatting to write step - formattedContent := content - if ext := filepath.Ext(i.GetPath()); ext == ".go" { - formattedContent, err = imports.Process(i.GetPath(), content, nil) - if err != nil { - return err - } - } - - m.Contents = string(formattedContent) - m.IfExistsAction = file.Overwrite - models[m.Path] = m - return nil -} - -// loadPreviousModel gets the previous model from the models map or the actual file -func (s scaffold) loadPreviousModel(i file.Inserter, models map[string]*file.File) (*file.File, error) { - // Lets see if we already have a model for this file - if m, found := models[i.GetPath()]; found { - // Check if there is already an scaffolded file - exists, err := s.fs.Exists(i.GetPath()) - if err != nil { - return nil, err - } - - // If there is a model but no scaffolded file we return the model - if !exists { - return m, nil - } - - // If both a model and a file are found, check which has preference - switch m.IfExistsAction { - case file.Skip: - // File has preference - fromFile, err := s.loadModelFromFile(i.GetPath()) - if err != nil { - return m, nil - } - return fromFile, nil - case file.Error: - // Writing will result in an error, so we can return error now - return nil, fileAlreadyExistsError{i.GetPath()} - case file.Overwrite: - // Model has preference - return m, nil - default: - return nil, unknownIfExistsActionError{i.GetPath(), m.IfExistsAction} - } - } - - // There was no model - return s.loadModelFromFile(i.GetPath()) -} - -// loadModelFromFile gets the previous model from the actual file -func (s scaffold) loadModelFromFile(path string) (f *file.File, err error) { - reader, err := s.fs.Open(path) - if err != nil { - return - } - defer func() { - closeErr := reader.Close() - if err == nil { - err = closeErr - } - }() - - content, err := ioutil.ReadAll(reader) - if err != nil { - return - } - - f = &file.File{Path: path, Contents: string(content)} - return -} - -// getValidCodeFragments obtains the code fragments from a file.Inserter -func getValidCodeFragments(i file.Inserter) file.CodeFragmentsMap { - // Get the code fragments - codeFragments := i.GetCodeFragments() - - // Validate the code fragments - validMarkers := i.GetMarkers() - for marker := range codeFragments { - valid := false - for _, validMarker := range validMarkers { - if marker == validMarker { - valid = true - break - } - } - if !valid { - delete(codeFragments, marker) - } - } - - return codeFragments -} - -// filterExistingValues removes the single-line values that already exists -// TODO: Add support for multi-line duplicate values -func filterExistingValues(content string, codeFragmentsMap file.CodeFragmentsMap) error { - scanner := bufio.NewScanner(strings.NewReader(content)) - for scanner.Scan() { - line := scanner.Text() - for marker, codeFragments := range codeFragmentsMap { - for i, codeFragment := range codeFragments { - if strings.TrimSpace(line) == strings.TrimSpace(codeFragment) { - codeFragmentsMap[marker] = append(codeFragments[:i], codeFragments[i+1:]...) - } - } - if len(codeFragmentsMap[marker]) == 0 { - delete(codeFragmentsMap, marker) - } - } - } - if err := scanner.Err(); err != nil { - return err - } - return nil -} - -func insertStrings(content string, codeFragmentsMap file.CodeFragmentsMap) ([]byte, error) { - out := new(bytes.Buffer) - - scanner := bufio.NewScanner(strings.NewReader(content)) - for scanner.Scan() { - line := scanner.Text() - - for marker, codeFragments := range codeFragmentsMap { - if marker.EqualsLine(line) { - for _, codeFragment := range codeFragments { - _, _ = out.WriteString(codeFragment) // bytes.Buffer.WriteString always returns nil errors - } - } - } - - _, _ = out.WriteString(line + "\n") // bytes.Buffer.WriteString always returns nil errors - } - if err := scanner.Err(); err != nil { - return nil, err - } - - return out.Bytes(), nil -} - -func (s scaffold) writeFile(f *file.File) error { - // Check if the file to write already exists - exists, err := s.fs.Exists(f.Path) - if err != nil { - return err - } - if exists { - switch f.IfExistsAction { - case file.Overwrite: - // By not returning, the file is written as if it didn't exist - case file.Skip: - // By returning nil, the file is not written but the process will carry on - return nil - case file.Error: - // By returning an error, the file is not written and the process will fail - return fileAlreadyExistsError{f.Path} - } - } - - writer, err := s.fs.Create(f.Path) - if err != nil { - return err - } - - _, err = writer.Write([]byte(f.Contents)) - - return err -} diff --git a/pkg/plugins/internal/kubebuilder/machinery/scaffold_test.go b/pkg/plugins/internal/kubebuilder/machinery/scaffold_test.go deleted file mode 100644 index ffed12a7..00000000 --- a/pkg/plugins/internal/kubebuilder/machinery/scaffold_test.go +++ /dev/null @@ -1,554 +0,0 @@ -/* -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package machinery - -import ( - "bytes" - "errors" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/ginkgo/extensions/table" - . "github.com/onsi/gomega" - "sigs.k8s.io/kubebuilder/v3/pkg/model" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" - - "github.com/joelanford/helm-operator/pkg/plugins/internal/kubebuilder/filesystem" -) - -var _ = Describe("Scaffold", func() { - Describe("NewScaffold", func() { - var ( - si Scaffold - s *scaffold - ok bool - ) - - Context("when using no plugins", func() { - BeforeEach(func() { - si = NewScaffold() - s, ok = si.(*scaffold) - }) - - It("should be a scaffold instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should not have a nil fs", func() { - Expect(s.fs).NotTo(BeNil()) - }) - - It("should not have any plugin", func() { - Expect(len(s.plugins)).To(Equal(0)) - }) - }) - - Context("when using one plugin", func() { - BeforeEach(func() { - si = NewScaffold(fakePlugin{}) - s, ok = si.(*scaffold) - }) - - It("should be a scaffold instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should not have a nil fs", func() { - Expect(s.fs).NotTo(BeNil()) - }) - - It("should have one plugin", func() { - Expect(len(s.plugins)).To(Equal(1)) - }) - }) - - Context("when using several plugins", func() { - BeforeEach(func() { - si = NewScaffold(fakePlugin{}, fakePlugin{}, fakePlugin{}) - s, ok = si.(*scaffold) - }) - - It("should be a scaffold instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should not have a nil fs", func() { - Expect(s.fs).NotTo(BeNil()) - }) - - It("should have several plugins", func() { - Expect(len(s.plugins)).To(Equal(3)) - }) - }) - }) - - Describe("Scaffold.Execute", func() { - const fileContent = "Hello world!" - - var ( - output bytes.Buffer - testErr = errors.New("error text") - ) - - BeforeEach(func() { - output.Reset() - }) - - DescribeTable("successes", - func(expected string, files ...file.Builder) { - s := &scaffold{ - fs: filesystem.NewMock( - filesystem.MockOutput(&output), - ), - } - - Expect(s.Execute(model.NewUniverse(), files...)).To(Succeed()) - Expect(output.String()).To(Equal(expected)) - }, - Entry("should write the file", - fileContent, - fakeTemplate{body: fileContent}, - ), - Entry("should skip optional models if already have one", - fileContent, - fakeTemplate{body: fileContent}, - fakeTemplate{}, - ), - Entry("should overwrite required models if already have one", - fileContent, - fakeTemplate{}, - fakeTemplate{fakeBuilder: fakeBuilder{ifExistsAction: file.Overwrite}, body: fileContent}, - ), - Entry("should format a go file", - "package file\n", - fakeTemplate{fakeBuilder: fakeBuilder{path: "file.go"}, body: "package file"}, - ), - ) - - DescribeTable("file builders related errors", - func(f func(error) bool, files ...file.Builder) { - s := &scaffold{fs: filesystem.NewMock()} - - Expect(f(s.Execute(model.NewUniverse(), files...))).To(BeTrue()) - }, - Entry("should fail if unable to validate a file builder", - file.IsValidateError, - fakeRequiresValidation{validateErr: testErr}, - ), - Entry("should fail if unable to set default values for a template", - file.IsSetTemplateDefaultsError, - fakeTemplate{err: testErr}, - ), - Entry("should fail if an unexpected previous model is found", - IsModelAlreadyExistsError, - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename"}}, - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename", ifExistsAction: file.Error}}, - ), - Entry("should fail if behavior if file exists is not defined", - IsUnknownIfExistsActionError, - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename"}}, - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename", ifExistsAction: -1}}, - ), - ) - - // Following errors are unwrapped, so we need to check for substrings - DescribeTable("template related errors", - func(errMsg string, files ...file.Builder) { - s := &scaffold{fs: filesystem.NewMock()} - - err := s.Execute(model.NewUniverse(), files...) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring(errMsg)) - }, - Entry("should fail if a template is broken", - "template: ", - fakeTemplate{body: "{{ .Field }"}, - ), - Entry("should fail if a template params aren't provided", - "template: ", - fakeTemplate{body: "{{ .Field }}"}, - ), - Entry("should fail if unable to format a go file", - "expected 'package', found ", - fakeTemplate{fakeBuilder: fakeBuilder{path: "file.go"}, body: fileContent}, - ), - ) - - DescribeTable("insert strings", - func(input, expected string, files ...file.Builder) { - s := &scaffold{ - fs: filesystem.NewMock( - filesystem.MockInput(bytes.NewBufferString(input)), - filesystem.MockOutput(&output), - filesystem.MockExists(func(_ string) bool { return len(input) != 0 }), - ), - } - - Expect(s.Execute(model.NewUniverse(), files...)).To(Succeed()) - Expect(output.String()).To(Equal(expected)) - }, - Entry("should insert lines for go files", - ` -//+kubebuilder:scaffold:- -`, - ` -1 -2 -//+kubebuilder:scaffold:- -`, - fakeInserter{codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {"1\n", "2\n"}}, - }, - ), - Entry("should insert lines for yaml files", - ` -#+kubebuilder:scaffold:- -`, - ` -1 -2 -#+kubebuilder:scaffold:- -`, - fakeInserter{codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.yaml", "-"): {"1\n", "2\n"}}, - }, - ), - Entry("should use models if there is no file", - "", - ` -1 -2 -//+kubebuilder:scaffold:- -`, - fakeTemplate{fakeBuilder: fakeBuilder{ifExistsAction: file.Overwrite}, body: ` -//+kubebuilder:scaffold:- -`}, - fakeInserter{codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {"1\n", "2\n"}}, - }, - ), - Entry("should use required models over files", - fileContent, - ` -1 -2 -//+kubebuilder:scaffold:- -`, - fakeTemplate{fakeBuilder: fakeBuilder{ifExistsAction: file.Overwrite}, body: ` -//+kubebuilder:scaffold:- -`}, - fakeInserter{codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {"1\n", "2\n"}}, - }, - ), - Entry("should use files over optional models", - ` -//+kubebuilder:scaffold:- -`, - ` -1 -2 -//+kubebuilder:scaffold:- -`, - fakeTemplate{body: fileContent}, - fakeInserter{ - codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {"1\n", "2\n"}, - }, - }, - ), - Entry("should filter invalid markers", - ` -//+kubebuilder:scaffold:- -//+kubebuilder:scaffold:* -`, - ` -1 -2 -//+kubebuilder:scaffold:- -//+kubebuilder:scaffold:* -`, - fakeInserter{ - markers: []file.Marker{file.NewMarkerFor("file.go", "-")}, - codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {"1\n", "2\n"}, - file.NewMarkerFor("file.go", "*"): {"3\n", "4\n"}, - }, - }, - ), - Entry("should filter already existing one-line code fragments", - ` -1 -//+kubebuilder:scaffold:- -3 -4 -//+kubebuilder:scaffold:* -`, - ` -1 -2 -//+kubebuilder:scaffold:- -3 -4 -//+kubebuilder:scaffold:* -`, - fakeInserter{ - codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {"1\n", "2\n"}, - file.NewMarkerFor("file.go", "*"): {"3\n", "4\n"}, - }, - }, - ), - Entry("should not insert anything if no code fragment", - "", // input is provided through a template as mock fs doesn't copy it to the output buffer if no-op - ` -//+kubebuilder:scaffold:- -`, - fakeTemplate{body: ` -//+kubebuilder:scaffold:- -`}, - fakeInserter{ - codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {}, - }, - }, - ), - ) - - DescribeTable("insert strings related errors", - func(f func(error) bool, files ...file.Builder) { - s := &scaffold{ - fs: filesystem.NewMock( - filesystem.MockExists(func(_ string) bool { return true }), - ), - } - - err := s.Execute(model.NewUniverse(), files...) - Expect(err).To(HaveOccurred()) - Expect(f(err)).To(BeTrue()) - }, - Entry("should fail if inserting into a model that fails when a file exists and it does exist", - IsFileAlreadyExistsError, - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename", ifExistsAction: file.Error}}, - fakeInserter{fakeBuilder: fakeBuilder{path: "filename"}}, - ), - Entry("should fail if inserting into a model with unknown behavior if the file exists and it does exist", - IsUnknownIfExistsActionError, - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename", ifExistsAction: -1}}, - fakeInserter{fakeBuilder: fakeBuilder{path: "filename"}}, - ), - ) - - It("should fail if a plugin fails", func() { - s := &scaffold{ - fs: filesystem.NewMock(), - plugins: []model.Plugin{fakePlugin{err: testErr}}, - } - - err := s.Execute( - model.NewUniverse(), - fakeTemplate{}, - ) - Expect(err).To(MatchError(testErr)) - Expect(model.IsPluginError(err)).To(BeTrue()) - }) - - Context("write when the file already exists", func() { - var s Scaffold - - BeforeEach(func() { - s = &scaffold{ - fs: filesystem.NewMock( - filesystem.MockExists(func(_ string) bool { return true }), - filesystem.MockOutput(&output), - ), - } - }) - - It("should skip the file by default", func() { - Expect(s.Execute( - model.NewUniverse(), - fakeTemplate{body: fileContent}, - )).To(Succeed()) - Expect(output.String()).To(BeEmpty()) - }) - - It("should write the file if configured to do so", func() { - Expect(s.Execute( - model.NewUniverse(), - fakeTemplate{fakeBuilder: fakeBuilder{ifExistsAction: file.Overwrite}, body: fileContent}, - )).To(Succeed()) - Expect(output.String()).To(Equal(fileContent)) - }) - - It("should error if configured to do so", func() { - err := s.Execute( - model.NewUniverse(), - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename", ifExistsAction: file.Error}, body: fileContent}, - ) - Expect(err).To(HaveOccurred()) - Expect(IsFileAlreadyExistsError(err)).To(BeTrue()) - Expect(output.String()).To(BeEmpty()) - }) - }) - - DescribeTable("filesystem errors", - func( - mockErrorF func(error) filesystem.MockOptions, - checkErrorF func(error) bool, - files ...file.Builder, - ) { - s := &scaffold{ - fs: filesystem.NewMock( - mockErrorF(testErr), - ), - } - - err := s.Execute(model.NewUniverse(), files...) - Expect(err).To(HaveOccurred()) - Expect(checkErrorF(err)).To(BeTrue()) - }, - Entry("should fail if fs.Exists failed (at file writing)", - filesystem.MockExistsError, filesystem.IsFileExistsError, - fakeTemplate{}, - ), - Entry("should fail if fs.Exists failed (at model updating)", - filesystem.MockExistsError, filesystem.IsFileExistsError, - fakeTemplate{}, - fakeInserter{}, - ), - Entry("should fail if fs.Open was unable to open the file", - filesystem.MockOpenFileError, filesystem.IsOpenFileError, - fakeInserter{}, - ), - Entry("should fail if fs.Open().Read was unable to read the file", - filesystem.MockReadFileError, filesystem.IsReadFileError, - fakeInserter{}, - ), - Entry("should fail if fs.Open().Close was unable to close the file", - filesystem.MockCloseFileError, filesystem.IsCloseFileError, - fakeInserter{}, - ), - Entry("should fail if fs.Create was unable to create the directory", - filesystem.MockCreateDirError, filesystem.IsCreateDirectoryError, - fakeTemplate{}, - ), - Entry("should fail if fs.Create was unable to create the file", - filesystem.MockCreateFileError, filesystem.IsCreateFileError, - fakeTemplate{}, - ), - Entry("should fail if fs.Create().Write was unable to write the file", - filesystem.MockWriteFileError, filesystem.IsWriteFileError, - fakeTemplate{}, - ), - Entry("should fail if fs.Create().Write was unable to close the file", - filesystem.MockCloseFileError, filesystem.IsCloseFileError, - fakeTemplate{}, - ), - ) - }) -}) - -var _ model.Plugin = fakePlugin{} - -// fakePlugin is used to mock a model.Plugin in order to test Scaffold -type fakePlugin struct { - err error -} - -// Pipe implements model.Plugin -func (f fakePlugin) Pipe(_ *model.Universe) error { - return f.err -} - -var _ file.Builder = fakeBuilder{} - -// fakeBuilder is used to mock a file.Builder -type fakeBuilder struct { - path string - ifExistsAction file.IfExistsAction -} - -// GetPath implements file.Builder -func (f fakeBuilder) GetPath() string { - return f.path -} - -// GetIfExistsAction implements file.Builder -func (f fakeBuilder) GetIfExistsAction() file.IfExistsAction { - return f.ifExistsAction -} - -var _ file.RequiresValidation = fakeRequiresValidation{} - -// fakeRequiresValidation is used to mock a file.RequiresValidation in order to test Scaffold -type fakeRequiresValidation struct { - fakeBuilder - - validateErr error -} - -// Validate implements file.RequiresValidation -func (f fakeRequiresValidation) Validate() error { - return f.validateErr -} - -var _ file.Template = fakeTemplate{} - -// fakeTemplate is used to mock a file.File in order to test Scaffold -type fakeTemplate struct { - fakeBuilder - - body string - err error -} - -// GetBody implements file.Template -func (f fakeTemplate) GetBody() string { - return f.body -} - -// SetTemplateDefaults implements file.Template -func (f fakeTemplate) SetTemplateDefaults() error { - if f.err != nil { - return f.err - } - - return nil -} - -type fakeInserter struct { - fakeBuilder - - markers []file.Marker - codeFragments file.CodeFragmentsMap -} - -// GetMarkers implements file.UpdatableTemplate -func (f fakeInserter) GetMarkers() []file.Marker { - if f.markers != nil { - return f.markers - } - - markers := make([]file.Marker, 0, len(f.codeFragments)) - for marker := range f.codeFragments { - markers = append(markers, marker) - } - return markers -} - -// GetCodeFragments implements file.UpdatableTemplate -func (f fakeInserter) GetCodeFragments() file.CodeFragmentsMap { - return f.codeFragments -} diff --git a/pkg/plugins/util/cleanup.go b/pkg/plugins/util/cleanup.go new file mode 100644 index 00000000..bfc4f2e5 --- /dev/null +++ b/pkg/plugins/util/cleanup.go @@ -0,0 +1,137 @@ +// Copyright 2021 The Operator-SDK Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package util + +import ( + "bytes" + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + log "github.com/sirupsen/logrus" +) + +// RemoveKustomizeCRDManifests removes items in config/crd relating to CRD conversion webhooks. +func RemoveKustomizeCRDManifests() error { + + pathsToRemove := []string{ + filepath.Join("config", "crd", "kustomizeconfig.yaml"), + } + configPatchesDir := filepath.Join("config", "crd", "patches") + webhookPatchMatches, err := filepath.Glob(filepath.Join(configPatchesDir, "webhook_in_*.yaml")) + if err != nil { + return err + } + pathsToRemove = append(pathsToRemove, webhookPatchMatches...) + cainjectionPatchMatches, err := filepath.Glob(filepath.Join(configPatchesDir, "cainjection_in_*.yaml")) + if err != nil { + return err + } + pathsToRemove = append(pathsToRemove, cainjectionPatchMatches...) + for _, p := range pathsToRemove { + if err := os.RemoveAll(p); err != nil { + return err + } + } + children, err := ioutil.ReadDir(configPatchesDir) + if err == nil && len(children) == 0 { + if err := os.RemoveAll(configPatchesDir); err != nil { + return err + } + } + return nil +} + +// UpdateKustomizationsCreateAPI updates certain parts of or removes entire kustomization.yaml files +// that are either not used by certain CreateAPI plugins or are created by preceding CreateAPI plugins. +func UpdateKustomizationsCreateAPI() error { + + crdKFile := filepath.Join("config", "crd", "kustomization.yaml") + if crdKBytes, err := ioutil.ReadFile(crdKFile); err != nil && !errors.Is(err, os.ErrNotExist) { + log.Debugf("Error reading kustomization for substitution: %v", err) + } else if err == nil { + if bytes.Contains(crdKBytes, []byte("[WEBHOOK]")) || bytes.Contains(crdKBytes, []byte("[CERTMANAGER]")) { + if err := os.RemoveAll(crdKFile); err != nil { + log.Debugf("Error removing file prior to scaffold: %v", err) + } + } + } + + return nil +} + +// UpdateKustomizationsInit updates certain parts of or removes entire kustomization.yaml files +// that are either not used by certain Init plugins or are created by preceding Init plugins. +func UpdateKustomizationsInit() error { + + defaultKFile := filepath.Join("config", "default", "kustomization.yaml") + if err := ReplaceInFile(defaultKFile, + ` +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- ../webhook +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. +#- ../certmanager`, ""); err != nil { + return fmt.Errorf("remove %s resources: %v", defaultKFile, err) + } + + if err := ReplaceInFile(defaultKFile, + ` +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- manager_webhook_patch.yaml + +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. +# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. +# 'CERTMANAGER' needs to be enabled to use ca injection +#- webhookcainjection_patch.yaml + +# the following config is for teaching kustomize how to do var substitution +vars: +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. +#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR +# objref: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert # this name should match the one in certificate.yaml +# fieldref: +# fieldpath: metadata.namespace +#- name: CERTIFICATE_NAME +# objref: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert # this name should match the one in certificate.yaml +#- name: SERVICE_NAMESPACE # namespace of the service +# objref: +# kind: Service +# version: v1 +# name: webhook-service +# fieldref: +# fieldpath: metadata.namespace +#- name: SERVICE_NAME +# objref: +# kind: Service +# version: v1 +# name: webhook-service +`, ""); err != nil { + return fmt.Errorf("remove %s patch and vars blocks: %v", defaultKFile, err) + } + + return nil +} diff --git a/pkg/plugins/util/utils.go b/pkg/plugins/util/utils.go new file mode 100644 index 00000000..0a9aa3aa --- /dev/null +++ b/pkg/plugins/util/utils.go @@ -0,0 +1,81 @@ +// Copyright 2020 The Operator-SDK Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// todo(camilamacedo86): push this helpers to kubbuilder + +package util + +import ( + "errors" + "io/ioutil" + "os" + "regexp" + "strings" +) + +func ReplaceInFile(path, old, new string) error { + info, err := os.Stat(path) + if err != nil { + return err + } + b, err := ioutil.ReadFile(path) + if err != nil { + return err + } + if !strings.Contains(string(b), old) { + return errors.New("unable to find the content to be replaced") + } + s := strings.Replace(string(b), old, new, -1) + err = ioutil.WriteFile(path, []byte(s), info.Mode()) + if err != nil { + return err + } + return nil +} + +func ReplaceRegexInFile(path, match, replace string) error { + matcher, err := regexp.Compile(match) + if err != nil { + return err + } + info, err := os.Stat(path) + if err != nil { + return err + } + b, err := ioutil.ReadFile(path) + if err != nil { + return err + } + s := matcher.ReplaceAllString(string(b), replace) + if s == string(b) { + return errors.New("unable to find the content to be replaced") + } + err = ioutil.WriteFile(path, []byte(s), info.Mode()) + if err != nil { + return err + } + return nil +} + +// InsertCode searches target content in the file and insert `toInsert` after the target. +func InsertCode(filename, target, code string) error { + contents, err := ioutil.ReadFile(filename) + if err != nil { + return err + } + idx := strings.Index(string(contents), target) + out := string(contents[:idx+len(target)]) + code + string(contents[idx+len(target):]) + // false positive + // nolint:gosec + return ioutil.WriteFile(filename, []byte(out), 0644) +} diff --git a/pkg/plugins/v1/api.go b/pkg/plugins/v1/api.go index 0473f7cb..2f72cede 100644 --- a/pkg/plugins/v1/api.go +++ b/pkg/plugins/v1/api.go @@ -15,137 +15,204 @@ package v1 import ( + "errors" "fmt" "strings" + "github.com/iancoleman/strcase" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/util" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/v1/chartutil" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/v1/scaffolds" "github.com/spf13/pflag" + "helm.sh/helm/v3/pkg/chart" "sigs.k8s.io/kubebuilder/v3/pkg/config" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" + "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" "sigs.k8s.io/kubebuilder/v3/pkg/plugin" + pluginutil "sigs.k8s.io/kubebuilder/v3/pkg/plugin/util" +) + +const ( + crdVersionFlag = "crd-version" + helmChartFlag = "helm-chart" + helmChartRepoFlag = "helm-chart-repo" + helmChartVersionFlag = "helm-chart-version" - "github.com/joelanford/helm-operator/pkg/plugins/internal/kubebuilder/cmdutil" - "github.com/joelanford/helm-operator/pkg/plugins/v1/chartutil" - "github.com/joelanford/helm-operator/pkg/plugins/v1/scaffolds" + defaultCrdVersion = "v1" + + // defaultGroup is the Kubernetes CRD API Group used for fetched charts when the --group flag is not specified + defaultGroup = "charts" + // defaultVersion is the Kubernetes CRD API Version used for fetched charts when the --version flag is not specified + defaultVersion = "v1alpha1" ) -type createAPISubcommand struct { - config config.Config - createOptions chartutil.CreateOptions +type createAPIOptions struct { + // CRDVersion is the version of the `apiextensions.k8s.io` API which will be used to generate the CRD. + CRDVersion string + + chartOptions chartutil.Options } -var ( - _ plugin.CreateAPISubcommand = &createAPISubcommand{} - _ cmdutil.RunOptions = &createAPISubcommand{} -) +// UpdateResource updates the base resource with the information obtained from the flags +func (opts createAPIOptions) UpdateResource(res *resource.Resource) { + res.API = &resource.API{ + CRDVersion: opts.CRDVersion, + Namespaced: true, + } + + // Ensure that Path is empty and Controller false + res.Path = "" + res.Controller = false +} -// UpdateContext define plugin context -func (p createAPISubcommand) UpdateContext(ctx *plugin.Context) { - ctx.Description = `Scaffold a Kubernetes API that is backed by a Helm chart. +var _ plugin.CreateAPISubcommand = &createAPISubcommand{} + +type createAPISubcommand struct { + config config.Config + resource *resource.Resource + chart *chart.Chart + options createAPIOptions +} + +func (p *createAPISubcommand) UpdateMetadata(cliMeta plugin.CLIMetadata, subcmdMeta *plugin.SubcommandMetadata) { + subcmdMeta.Description = `Scaffold a Kubernetes API that is backed by a Helm chart. ` - ctx.Examples = fmt.Sprintf(` $ %s create api \ + subcmdMeta.Examples = fmt.Sprintf(` $ %s create api \ --group=apps --version=v1alpha1 \ --kind=AppService - $ %s create api \ + $ %[1]s create api \ --group=apps --version=v1alpha1 \ --kind=AppService \ --helm-chart=myrepo/app - $ %s create api \ + $ %[1]s create api \ --helm-chart=myrepo/app - $ %s create api \ + $ %[1]s create api \ --helm-chart=myrepo/app \ --helm-chart-version=1.2.3 - $ %s create api \ + $ %[1]s create api \ --helm-chart=app \ --helm-chart-repo=https://charts.mycompany.com/ - $ %s create api \ + $ %[1]s create api \ --helm-chart=app \ --helm-chart-repo=https://charts.mycompany.com/ \ --helm-chart-version=1.2.3 - $ %s create api \ + $ %[1]s create api \ --helm-chart=/path/to/local/chart-directories/app/ - $ %s create api \ + $ %[1]s create api \ --helm-chart=/path/to/local/chart-archives/app-1.2.3.tgz -`, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ) +`, cliMeta.CommandName) } -const ( - groupFlag = "group" - versionFlag = "version" - kindFlag = "kind" - helmChartFlag = "helm-chart" - helmChartRepoFlag = "helm-chart-repo" - helmChartVersionFlag = "helm-chart-version" - crdVersionFlag = "crd-version" - - crdVersionV1 = "v1" -) - // BindFlags will set the flags for the plugin func (p *createAPISubcommand) BindFlags(fs *pflag.FlagSet) { - p.createOptions = chartutil.CreateOptions{} fs.SortFlags = false - fs.StringVar(&p.createOptions.GVK.Group, groupFlag, "", "resource group") - fs.StringVar(&p.createOptions.GVK.Version, versionFlag, "", "resource version") - fs.StringVar(&p.createOptions.GVK.Kind, kindFlag, "", "resource kind") - - fs.StringVar(&p.createOptions.Chart, helmChartFlag, "", "helm chart") - fs.StringVar(&p.createOptions.Repo, helmChartRepoFlag, "", "helm chart repository") - fs.StringVar(&p.createOptions.Version, helmChartVersionFlag, "", "helm chart version (default: latest)") + fs.StringVar(&p.options.chartOptions.Chart, helmChartFlag, "", "helm chart") + fs.StringVar(&p.options.chartOptions.Repo, helmChartRepoFlag, "", "helm chart repository") + fs.StringVar(&p.options.chartOptions.Version, helmChartVersionFlag, "", "helm chart version (default: latest)") - fs.StringVar(&p.createOptions.CRDVersion, crdVersionFlag, crdVersionV1, "crd version to generate") + fs.StringVar(&p.options.CRDVersion, crdVersionFlag, defaultCrdVersion, "crd version to generate") } -// InjectConfig will inject the PROJECT file/config in the plugin -func (p *createAPISubcommand) InjectConfig(c config.Config) { +func (p *createAPISubcommand) InjectConfig(c config.Config) error { p.config = c -} -// Run will call the plugin actions according to the definitions done in RunOptions interface -func (p *createAPISubcommand) Run() error { - return cmdutil.Run(p) + return nil } -// Validate perform the required validations for this plugin -func (p *createAPISubcommand) Validate() error { - if len(strings.TrimSpace(p.createOptions.Chart)) == 0 { - if len(strings.TrimSpace(p.createOptions.Repo)) != 0 { +func (p *createAPISubcommand) InjectResource(res *resource.Resource) error { + p.resource = res + + // The following checks and the chart creation would be a better fit for PreScaffold method + // but, as having a chart sets some default values for the resource's GVK, we need to do it here. + var err error + if len(strings.TrimSpace(p.options.chartOptions.Chart)) == 0 { + // Chart repo and version can only be provided if chart was provided. + if len(strings.TrimSpace(p.options.chartOptions.Repo)) != 0 { return fmt.Errorf("value of --%s can only be used with --%s", helmChartRepoFlag, helmChartFlag) - } else if len(p.createOptions.Version) != 0 { + } + if len(p.options.chartOptions.Version) != 0 { return fmt.Errorf("value of --%s can only be used with --%s", helmChartVersionFlag, helmChartFlag) } - r := p.createOptions.Resource() - r.Domain = p.config.GetDomain() - if err := r.Validate(); err != nil { + // Kind is required if no chart was provided as it is used for the chart name. + // While the resource validation will detect this, the error yielded would not + // mention the option of providing the chart flag. Additionally, by checking it + // here we can create the new chart before resource validation. + if len(p.resource.Kind) == 0 { + return fmt.Errorf("either --%s or --%s need to be provided", kindFlag, helmChartFlag) + } + + p.chart, err = chartutil.NewChart(strings.ToLower(p.resource.Kind)) + if err != nil { return err } + } else { + p.chart, err = chartutil.LoadChart(p.options.chartOptions) + if err != nil { + return err + } + + // In case we loaded a chart and some resource flags were not set we will set defaults. + if p.resource.Group == "" { + p.resource.Group = defaultGroup + } + if p.resource.Version == "" { + p.resource.Version = defaultVersion + } + if p.resource.Kind == "" { + p.resource.Kind = strcase.ToCamel(p.chart.Name()) + if p.resource.Plural == "" { + p.resource.Plural = resource.RegularPlural(p.resource.Kind) + } + } + } + + p.options.UpdateResource(p.resource) + + if err := p.resource.Validate(); err != nil { + return err + } + + // Check that resource doesn't have the API scaffolded + if res, err := p.config.GetResource(p.resource.GVK); err == nil && res.HasAPI() { + return errors.New("the API resource already exists") + } + + // Check that the provided group can be added to the project + if !p.config.IsMultiGroup() && p.config.ResourcesLength() != 0 && !p.config.HasGroup(p.resource.Group) { + return fmt.Errorf("multiple groups are not allowed by default, to enable multi-group set 'multigroup: true' in your PROJECT file") + } + + // Selected CRD version must match existing CRD versions. + if pluginutil.HasDifferentCRDVersion(p.config, p.resource.API.CRDVersion) { + return fmt.Errorf("only one CRD version can be used for all resources, cannot add %q", p.resource.API.CRDVersion) } return nil } -// GetScaffolder returns cmdutil.Scaffolder which will be executed due the RunOptions interface implementation -func (p *createAPISubcommand) GetScaffolder() (cmdutil.Scaffolder, error) { - return scaffolds.NewAPIScaffolder(p.config, p.createOptions), nil -} +func (p *createAPISubcommand) Scaffold(fs machinery.Filesystem) error { + if err := util.RemoveKustomizeCRDManifests(); err != nil { + return fmt.Errorf("error removing kustomization CRD manifests: %v", err) + } + if err := util.UpdateKustomizationsCreateAPI(); err != nil { + return fmt.Errorf("error updating kustomization.yaml files: %v", err) + } + + scaffolder := scaffolds.NewAPIScaffolder(p.config, *p.resource, p.chart) + scaffolder.InjectFS(fs) + if err := scaffolder.Scaffold(); err != nil { + return err + } + // NOTE: previous step fetches the dependencies of the chart.Chart, so reloading may be needed if used afterwards -// PostScaffold runs all actions that should be executed after the default plugin scaffold -func (p *createAPISubcommand) PostScaffold() error { return nil } diff --git a/pkg/plugins/v1/chartutil/chart.go b/pkg/plugins/v1/chartutil/chart.go index 835e1add..0e7d88ed 100644 --- a/pkg/plugins/v1/chartutil/chart.go +++ b/pkg/plugins/v1/chartutil/chart.go @@ -20,9 +20,7 @@ import ( "io/ioutil" "os" "path/filepath" - "strings" - "github.com/iancoleman/strcase" log "github.com/sirupsen/logrus" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" @@ -31,30 +29,16 @@ import ( "helm.sh/helm/v3/pkg/downloader" "helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v3/pkg/repo" - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" ) const ( - - // HelmChartsDir is the relative directory within an SDK project where Helm - // charts are stored. - HelmChartsDir string = "helm-charts" - - // DefaultGroup is the Kubernetes CRD API Group used for fetched - // charts when the --group flag is not specified - DefaultGroup string = "charts" - - // DefaultVersion is the Kubernetes CRD API Version used for fetched - // charts when the --version flag is not specified - DefaultVersion string = "v1alpha1" + // HelmChartsDir is the relative directory within a SDK project where Helm charts are stored. + HelmChartsDir = "helm-charts" ) -// CreateOptions is used to configure how a Helm chart is scaffolded +// Options is used to configure how a Helm chart is scaffolded // for a new Helm operator project. -type CreateOptions struct { - GVK schema.GroupVersionKind - +type Options struct { // Chart is a chart reference for a local or remote chart. Chart string @@ -63,51 +47,41 @@ type CreateOptions struct { // Version is the version of the chart to fetch. Version string - - // CRDVersion is the version of the `apiextensions.k8s.io` API which will be used to generate the CRD. - CRDVersion string } -func (opts CreateOptions) Resource() resource.Resource { - return resource.Resource{ - API: &resource.API{ - Namespaced: true, - CRDVersion: opts.CRDVersion, - }, - GVK: resource.GVK{ - Group: opts.GVK.Group, - Version: opts.GVK.Version, - Kind: opts.GVK.Kind, - }, - Plural: resource.RegularPlural(opts.GVK.Kind), +// NewChart creates a new helm chart for the project from helm's default template. +// It returns a chart.Chart that references the newly created chart or an error. +func NewChart(name string) (*chart.Chart, error) { + tmpDir, err := ioutil.TempDir("", "osdk-helm-chart") + if err != nil { + return nil, err } + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + log.Errorf("Failed to remove temporary directory %s: %v", tmpDir, err) + } + }() + + // Create a new chart + chartPath, err := chartutil.Create(name, tmpDir) + if err != nil { + return nil, err + } + + return loader.Load(chartPath) } -// CreateChart scaffolds a new helm chart for the project rooted in projectDir -// based on the passed opts. -// -// It returns a scaffold.Resource that can be used by the caller to create -// other related files. opts.ResourceAPIVersion and opts.ResourceKind are -// used to create the resource and must be specified if opts.Chart is empty. -// -// If opts.Chart is not empty, opts.ResourceAPIVersion and opts.Kind can be -// left unset: opts.ResourceAPIVersion defaults to "charts.helm.k8s.io/v1alpha1" -// and opts.ResourceKind is deduced from the specified opts.Chart. -// -// CreateChart also returns a chart.Chart that references the newly created -// chart. -// -// If opts.Chart is empty, CreateChart scaffolds the default chart from helm's -// default template. +// LoadChart creates a new helm chart for the project based on the passed opts. +// It returns a chart.Chart that references the newly created chart or an error. // -// If opts.Chart is a local file, CreateChart verifies that it is a valid helm -// chart archive and unpacks it into the project's helm charts directory. +// If opts.Chart is a local file, it verifies that it is a valid helm chart +// archive and returns its chart.Chart representation. // -// If opts.Chart is a local directory, CreateChart verifies that it is a valid -// helm chart directory and copies it into the project's helm charts directory. +// If opts.Chart is a local directory, it verifies that it is a valid helm chart +// directory and returns its chart.Chart representation. // -// For any other value of opts.Chart, CreateChart attempts to fetch the helm chart -// from a remote repository. +// For any other value of opts.Chart, it attempts to fetch the helm chart from a +// remote repository. // // If opts.Repo is not specified, the following chart reference formats are supported: // @@ -122,113 +96,35 @@ func (opts CreateOptions) Resource() resource.Resource { // - : Fetch the helm chart named chartName in the helm chart repository // specified by opts.Repo // -// If opts.Version is not set, CreateChart will fetch the latest available version of -// the helm chart. Otherwise, CreateChart will fetch the specified version. +// If opts.Version is not set, it will fetch the latest available version of the helm +// chart. Otherwise, it will fetch the specified version. // opts.Version is not used when opts.Chart itself refers to a specific version, for // example when it is a local path or a URL. -// -// CreateChart returns an error if an error occurs creating the scaffold.Resource or -// creating the chart. -func CreateChart(projectDir string, opts CreateOptions) (*resource.Resource, *chart.Chart, error) { - chartsDir := filepath.Join(projectDir, HelmChartsDir) - err := os.MkdirAll(chartsDir, 0755) +func LoadChart(opts Options) (*chart.Chart, error) { + tmpDir, err := ioutil.TempDir("", "osdk-helm-chart") if err != nil { - return nil, nil, fmt.Errorf("failed to create helm-charts directory: %v", err) + return nil, err } + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + log.Errorf("Failed to remove temporary directory %s: %v", tmpDir, err) + } + }() - var ( - r *resource.Resource - c *chart.Chart - ) + chartPath := opts.Chart - // If we don't have a helm chart reference, scaffold the default chart - // from Helm's default template. Otherwise, fetch it. - if len(opts.Chart) == 0 { - r, c, err = scaffoldChart(chartsDir, opts) - if err != nil { - return nil, nil, fmt.Errorf("failed to scaffold default chart: %v", err) - } - } else { - r, c, err = fetchChart(chartsDir, opts) + // If it is a remote chart, download it to a temp dir first + if _, err := os.Stat(opts.Chart); err != nil { + chartPath, err = downloadChart(tmpDir, opts) if err != nil { - return nil, nil, fmt.Errorf("failed to fetch chart: %v", err) + return nil, err } } - relChartPath := filepath.Join(HelmChartsDir, c.Name()) - absChartPath := filepath.Join(projectDir, relChartPath) - if err := fetchChartDependencies(absChartPath); err != nil { - return nil, nil, fmt.Errorf("failed to fetch chart dependencies: %v", err) - } - - // Reload chart in case dependencies changed - c, err = loader.Load(absChartPath) - if err != nil { - return nil, nil, fmt.Errorf("failed to load chart: %v", err) - } - - fmt.Printf("Created %s\n", relChartPath) - return r, c, nil -} - -func scaffoldChart(destDir string, opts CreateOptions) (*resource.Resource, *chart.Chart, error) { - r := opts.Resource() - chartPath, err := chartutil.Create(strings.ToLower(r.Kind), destDir) - if err != nil { - return nil, nil, err - } - - chart, err := loader.Load(chartPath) - if err != nil { - return nil, nil, err - } - return &r, chart, nil -} - -func fetchChart(destDir string, opts CreateOptions) (*resource.Resource, *chart.Chart, error) { - var ( - chart *chart.Chart - err error - ) - - if _, err = os.Stat(opts.Chart); err == nil { - chart, err = createChartFromDisk(destDir, opts.Chart) - } else { - chart, err = createChartFromRemote(destDir, opts) - } - if err != nil { - return nil, nil, err - } - - chartName := chart.Name() - if len(opts.GVK.Group) == 0 { - opts.GVK.Group = DefaultGroup - } - if len(opts.GVK.Version) == 0 { - opts.GVK.Version = DefaultVersion - } - if len(opts.GVK.Kind) == 0 { - opts.GVK.Kind = strcase.ToCamel(chartName) - } - - r := opts.Resource() - return &r, chart, nil -} - -func createChartFromDisk(destDir, source string) (*chart.Chart, error) { - chart, err := loader.Load(source) - if err != nil { - return nil, err - } - - // Save it into our project's helm-charts directory. - if err := chartutil.SaveDir(chart, destDir); err != nil { - return nil, err - } - return chart, nil + return loader.Load(chartPath) } -func createChartFromRemote(destDir string, opts CreateOptions) (*chart.Chart, error) { +func downloadChart(destDir string, opts Options) (string, error) { settings := cli.New() getters := getter.All(settings) c := downloader.ChartDownloader{ @@ -241,27 +137,46 @@ func createChartFromRemote(destDir string, opts CreateOptions) (*chart.Chart, er if opts.Repo != "" { chartURL, err := repo.FindChartInRepoURL(opts.Repo, opts.Chart, opts.Version, "", "", "", getters) if err != nil { - return nil, err + return "", err } opts.Chart = chartURL } - tmpDir, err := ioutil.TempDir("", "osdk-helm-chart") + chartArchive, _, err := c.DownloadTo(opts.Chart, opts.Version, destDir) if err != nil { - return nil, err + return "", err } - defer func() { - if err := os.RemoveAll(tmpDir); err != nil { - log.Errorf("Failed to remove temporary directory %s: %s", tmpDir, err) - } - }() - chartArchive, _, err := c.DownloadTo(opts.Chart, opts.Version, tmpDir) + return chartArchive, nil +} + +// ScaffoldChart scaffolds the provided chart.Chart to a known directory relative to projectDir +// +// It also fetches the dependencies and reloads the chart.Chart +// +// It returns the reloaded chart, the relative path, or an error. +func ScaffoldChart(chrt *chart.Chart, projectDir string) (*chart.Chart, string, error) { + chartsPath := filepath.Join(projectDir, HelmChartsDir) + + // Save it into our project's helm-charts directory. + if err := chartutil.SaveDir(chrt, chartsPath); err != nil { + return chrt, "", err + } + + chartPath := filepath.Join(chartsPath, chrt.Name()) + + // Fetch dependencies + if err := fetchChartDependencies(chartPath); err != nil { + return chrt, "", fmt.Errorf("failed to fetch chart dependencies: %w", err) + } + + // Reload chart in case dependencies changed + chrt, err := loader.Load(chartPath) if err != nil { - return nil, err + return chrt, "", fmt.Errorf("failed to reload chart: %w", err) } - return createChartFromDisk(destDir, chartArchive) + return chrt, filepath.Join(HelmChartsDir, chrt.Name()), nil } func fetchChartDependencies(chartPath string) error { diff --git a/pkg/plugins/v1/chartutil/chart_test.go b/pkg/plugins/v1/chartutil/chart_test.go index 8a64879b..62692b8e 100644 --- a/pkg/plugins/v1/chartutil/chart_test.go +++ b/pkg/plugins/v1/chartutil/chart_test.go @@ -18,18 +18,17 @@ import ( "fmt" "os" "path/filepath" + "strings" "testing" "github.com/stretchr/testify/assert" - "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/repo/repotest" - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" - "github.com/joelanford/helm-operator/pkg/plugins/v1/chartutil" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/v1/chartutil" ) -func TestCreateChart(t *testing.T) { +func TestChart(t *testing.T) { srv, err := repotest.NewTempServerWithCleanup(t, "testdata/*.tgz") if err != nil { t.Fatalf("Failed to create new temp server: %s", err) @@ -45,11 +44,8 @@ func TestCreateChart(t *testing.T) { latestVersion = "1.2.3" previousVersion = "1.2.0" nonExistentVersion = "0.0.1" - customGroup = "example.com" - customVersion = "v1" customKind = "MyApp" customExpectName = "myapp" - expectDerivedKind = "TestChart" ) testCases := []createChartTestCase{ @@ -57,10 +53,6 @@ func TestCreateChart(t *testing.T) { name: "from scaffold no apiVersion", expectErr: true, }, - { - name: "from scaffold no kind", - expectErr: true, - }, { name: "version without helm chart", helmChartVersion: latestVersion, @@ -78,54 +70,32 @@ func TestCreateChart(t *testing.T) { expectErr: true, }, { - name: "from scaffold with apiVersion and kind", - group: customGroup, - version: customVersion, + name: "from scaffold with kind", kind: customKind, - crdVersion: "v1beta1", - expectResource: mustNewResource(customGroup, customVersion, customKind, "v1beta1"), expectChartName: customExpectName, expectChartVersion: "0.1.0", }, { name: "from directory", helmChart: filepath.Join(".", "testdata", chartName), - crdVersion: "v1beta1", - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind, "v1beta1"), expectChartName: chartName, expectChartVersion: latestVersion, }, { name: "from archive", helmChart: filepath.Join(".", "testdata", fmt.Sprintf("%s-%s.tgz", chartName, latestVersion)), - crdVersion: "v1beta1", - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind, "v1beta1"), expectChartName: chartName, expectChartVersion: latestVersion, }, { name: "from url", helmChart: fmt.Sprintf("%s/%s-%s.tgz", srv.URL(), chartName, latestVersion), - crdVersion: "v1beta1", - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind, "v1beta1"), expectChartName: chartName, expectChartVersion: latestVersion, }, { name: "from repo and name implicit latest", helmChart: "test/" + chartName, - crdVersion: "v1beta1", - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind, "v1beta1"), - expectChartName: chartName, - expectChartVersion: latestVersion, - }, - { - name: "from repo and name implicit latest with apiVersion", - helmChart: "test/" + chartName, - group: customGroup, - version: customVersion, - crdVersion: "v1beta1", - expectResource: mustNewResource(customGroup, customVersion, expectDerivedKind, "v1beta1"), expectChartName: chartName, expectChartVersion: latestVersion, }, @@ -133,19 +103,6 @@ func TestCreateChart(t *testing.T) { name: "from repo and name implicit latest with kind", helmChart: "test/" + chartName, kind: customKind, - crdVersion: "v1", - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, customKind, "v1"), - expectChartName: chartName, - expectChartVersion: latestVersion, - }, - { - name: "from repo and name implicit latest with apiVersion and kind", - helmChart: "test/" + chartName, - group: customGroup, - version: customVersion, - kind: customKind, - crdVersion: "v1", - expectResource: mustNewResource(customGroup, customVersion, customKind, "v1"), expectChartName: chartName, expectChartVersion: latestVersion, }, @@ -153,8 +110,6 @@ func TestCreateChart(t *testing.T) { name: "from repo and name explicit latest", helmChart: "test/" + chartName, helmChartVersion: latestVersion, - crdVersion: "v1", - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind, "v1"), expectChartName: chartName, expectChartVersion: latestVersion, }, @@ -162,8 +117,6 @@ func TestCreateChart(t *testing.T) { name: "from repo and name explicit previous", helmChart: "test/" + chartName, helmChartVersion: previousVersion, - crdVersion: "v1", - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind, "v1"), expectChartName: chartName, expectChartVersion: previousVersion, }, @@ -171,8 +124,6 @@ func TestCreateChart(t *testing.T) { name: "from name and repo url implicit latest", helmChart: chartName, helmChartRepo: srv.URL(), - crdVersion: "v1", - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind, "v1"), expectChartName: chartName, expectChartVersion: latestVersion, }, @@ -181,8 +132,6 @@ func TestCreateChart(t *testing.T) { helmChart: chartName, helmChartRepo: srv.URL(), helmChartVersion: latestVersion, - crdVersion: "v1", - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind, "v1"), expectChartName: chartName, expectChartVersion: latestVersion, }, @@ -191,8 +140,6 @@ func TestCreateChart(t *testing.T) { helmChart: chartName, helmChartRepo: srv.URL(), helmChartVersion: previousVersion, - crdVersion: "v1", - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind, "v1"), expectChartName: chartName, expectChartVersion: previousVersion, }, @@ -208,36 +155,16 @@ func TestCreateChart(t *testing.T) { type createChartTestCase struct { name string - group string - version string kind string - crdVersion string helmChart string helmChartVersion string helmChartRepo string - expectResource *resource.Resource expectChartName string expectChartVersion string expectErr bool } -func mustNewResource(group, version, kind string, crdVersion string) *resource.Resource { - r := &resource.Resource{ - API: &resource.API{ - Namespaced: true, - CRDVersion: crdVersion, - }, - GVK: resource.GVK{ - Group: group, - Version: version, - Kind: kind, - }, - Plural: resource.RegularPlural(kind), - } - return r -} - func runTestCase(t *testing.T, testDir string, tc createChartTestCase) { outputDir := filepath.Join(testDir, "output") assert.NoError(t, os.Mkdir(outputDir, 0755)) @@ -252,18 +179,21 @@ func runTestCase(t *testing.T, testDir string, tc createChartTestCase) { defer os.Unsetenv("HELM_REPOSITORY_CONFIG") defer os.Unsetenv("HELM_REPOSITORY_CACHE") - opts := chartutil.CreateOptions{ - GVK: schema.GroupVersionKind{ - Group: tc.group, - Version: tc.version, - Kind: tc.kind, - }, - CRDVersion: tc.crdVersion, - Chart: tc.helmChart, - Version: tc.helmChartVersion, - Repo: tc.helmChartRepo, + var ( + chrt *chart.Chart + err error + ) + if tc.helmChart != "" { + opts := chartutil.Options{ + Chart: tc.helmChart, + Version: tc.helmChartVersion, + Repo: tc.helmChartRepo, + } + chrt, err = chartutil.LoadChart(opts) + } else { + chrt, err = chartutil.NewChart(strings.ToLower(tc.kind)) } - resource, chrt, err := chartutil.CreateChart(outputDir, opts) + if tc.expectErr { assert.Error(t, err) return @@ -272,14 +202,10 @@ func runTestCase(t *testing.T, testDir string, tc createChartTestCase) { if !assert.NoError(t, err) { return } - assert.Equal(t, tc.expectResource, resource) assert.Equal(t, tc.expectChartName, chrt.Name()) assert.Equal(t, tc.expectChartVersion, chrt.Metadata.Version) - loadedChart, err := loader.Load(filepath.Join(outputDir, chartutil.HelmChartsDir, chrt.Name())) - if err != nil { - t.Fatalf("Could not load chart from expected location: %s", err) - } - - assert.Equal(t, loadedChart, chrt) + _, chartPath, err := chartutil.ScaffoldChart(chrt, outputDir) + assert.NoError(t, err) + assert.Equal(t, filepath.Join(chartutil.HelmChartsDir, tc.expectChartName), chartPath) } diff --git a/pkg/plugins/v1/init.go b/pkg/plugins/v1/init.go index 6e1d91d7..e84edf53 100644 --- a/pkg/plugins/v1/init.go +++ b/pkg/plugins/v1/init.go @@ -16,42 +16,41 @@ package v1 import ( "fmt" - "os" "path/filepath" - "strings" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/util" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/v1/scaffolds" "github.com/spf13/pflag" - "k8s.io/apimachinery/pkg/util/validation" "sigs.k8s.io/kubebuilder/v3/pkg/config" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "sigs.k8s.io/kubebuilder/v3/pkg/plugin" +) - "github.com/joelanford/helm-operator/pkg/plugins/internal/kubebuilder/cmdutil" - "github.com/joelanford/helm-operator/pkg/plugins/v1/chartutil" - "github.com/joelanford/helm-operator/pkg/plugins/v1/scaffolds" +const ( + groupFlag = "group" + versionFlag = "version" + kindFlag = "kind" ) type initSubcommand struct { - config config.Config - apiPlugin createAPISubcommand - - domain string - projectName string + apiSubcommand createAPISubcommand - // If true, run the `create api` plugin. - doCreateAPI bool + config config.Config // For help text. commandName string + + // Flags + group string + version string + kind string } -var ( - _ plugin.InitSubcommand = &initSubcommand{} - _ cmdutil.RunOptions = &initSubcommand{} -) +var _ plugin.InitSubcommand = &initSubcommand{} // UpdateContext define plugin context -func (p *initSubcommand) UpdateContext(ctx *plugin.Context) { - ctx.Description = `Initialize a new Helm-based operator project. +func (p *initSubcommand) UpdateMetadata(cliMeta plugin.CLIMetadata, subcmdMeta *plugin.SubcommandMetadata) { + subcmdMeta.Description = `Initialize a new Helm-based operator project. Writes the following files: - a helm-charts directory with the chart(s) to build releases from @@ -62,7 +61,7 @@ Writes the following files: - a Patch file for customizing image for manager manifests - a Patch file for enabling prometheus metrics ` - ctx.Examples = fmt.Sprintf(` $ %[1]s init --plugins=%[2]s \ + subcmdMeta.Examples = fmt.Sprintf(` $ %[1]s init --plugins=%[2]s \ --domain=example.com \ --group=apps \ --version=v1alpha1 \ @@ -109,90 +108,85 @@ Writes the following files: $ %[1]s init --plugins=%[2]s \ --domain=example.com \ --helm-chart=/path/to/local/chart-archives/app-1.2.3.tgz -`, - ctx.CommandName, pluginKey, - ) +`, cliMeta.CommandName, pluginKey) - p.commandName = ctx.CommandName + p.commandName = cliMeta.CommandName } -// BindFlags will set the flags for the plugin func (p *initSubcommand) BindFlags(fs *pflag.FlagSet) { fs.SortFlags = false - fs.StringVar(&p.domain, "domain", "my.domain", "domain for groups") - fs.StringVar(&p.projectName, "project-name", "", "name of this project, the default being directory name") - p.apiPlugin.BindFlags(fs) + fs.StringVar(&p.group, groupFlag, "", "resource Group") + fs.StringVar(&p.version, versionFlag, "", "resource Version") + fs.StringVar(&p.kind, kindFlag, "", "resource Kind") + p.apiSubcommand.BindFlags(fs) } -// InjectConfig will inject the PROJECT file/config in the plugin -func (p *initSubcommand) InjectConfig(c config.Config) { - // v3 project configs get a 'layout' value. - _ = c.SetLayout(pluginKey) +func (p *initSubcommand) InjectConfig(c config.Config) error { p.config = c - p.apiPlugin.config = p.config + return nil } -// Run will call the plugin actions -func (p *initSubcommand) Run() error { - return cmdutil.Run(p) +func (p *initSubcommand) Scaffold(fs machinery.Filesystem) error { + if err := addInitCustomizations(p.config.GetProjectName()); err != nil { + return fmt.Errorf("error updating init manifests: %s", err) + } + + scaffolder := scaffolds.NewInitScaffolder(p.config) + scaffolder.InjectFS(fs) + return scaffolder.Scaffold() } -// Validate perform the required validations for this plugin -func (p *initSubcommand) Validate() error { - // Set values in the config - if err := p.config.SetProjectName(p.projectName); err != nil { +// addInitCustomizations will perform the required customizations for this plugin on the common base +func addInitCustomizations(projectName string) error { + managerFile := filepath.Join("config", "manager", "manager.yaml") + + // todo: we ought to use afero instead. Replace this methods to insert/update + // by https://github.com/kubernetes-sigs/kubebuilder/pull/2119 + + // Add leader election arg in config/manager/manager.yaml and in config/default/manager_auth_proxy_patch.yaml + err := util.InsertCode(managerFile, + "--leader-elect", + fmt.Sprintf("\n - --leader-election-id=%s", projectName)) + if err != nil { return err } - if err := p.config.SetDomain(p.domain); err != nil { + err = util.InsertCode(filepath.Join("config", "default", "manager_auth_proxy_patch.yaml"), + "- \"--leader-elect\"", + fmt.Sprintf("\n - \"--leader-election-id=%s\"", projectName)) + if err != nil { return err } - // Check if the project name is a valid k8s namespace (DNS 1123 label). - if p.config.GetProjectName() == "" { - dir, err := os.Getwd() - if err != nil { - return fmt.Errorf("error getting current directory: %v", err) - } - if err = p.config.SetProjectName(strings.ToLower(filepath.Base(dir))); err != nil { - return err - } + // Increase the default memory required. + err = util.ReplaceInFile(managerFile, "memory: 30Mi", "memory: 90Mi") + if err != nil { + return err } - - if err := validation.IsDNS1123Label(p.config.GetProjectName()); err != nil { - return fmt.Errorf("project name (%s) is invalid: %v", p.config.GetProjectName(), err) + err = util.ReplaceInFile(managerFile, "memory: 20Mi", "memory: 60Mi") + if err != nil { + return err } - defaultOpts := chartutil.CreateOptions{CRDVersion: "v1"} - if !p.apiPlugin.createOptions.GVK.Empty() || p.apiPlugin.createOptions != defaultOpts { - p.doCreateAPI = true - return p.apiPlugin.Validate() + // Remove the webhook option for the componentConfig since webhooks are not supported by helm + err = util.ReplaceInFile(filepath.Join("config", "manager", "controller_manager_config.yaml"), + "webhook:\n port: 9443", "") + if err != nil { + return err } - return nil -} - -// GetScaffolder returns cmdutil.Scaffolder which will be executed due the RunOptions interface implementation -func (p *initSubcommand) GetScaffolder() (cmdutil.Scaffolder, error) { - var ( - apiScaffolder cmdutil.Scaffolder - err error - ) - if p.doCreateAPI { - apiScaffolder, err = p.apiPlugin.GetScaffolder() - if err != nil { - return nil, err - } + // Remove the call to the command as manager. Helm has not been exposing this entrypoint + // todo: provide the manager entrypoint for helm and then remove it + const command = `command: + - /manager + ` + err = util.ReplaceInFile(managerFile, command, "") + if err != nil { + return err } - return scaffolds.NewInitScaffolder(p.config, apiScaffolder), nil -} - -// PostScaffold will run the required actions after the default plugin scaffold -func (p *initSubcommand) PostScaffold() error { - if p.doCreateAPI { - return p.apiPlugin.PostScaffold() + if err := util.UpdateKustomizationsInit(); err != nil { + return fmt.Errorf("error updating kustomization.yaml files: %v", err) } - fmt.Printf("Next: define a resource with:\n$ %s create api\n", p.commandName) return nil } diff --git a/pkg/plugins/v1/scaffolds/api.go b/pkg/plugins/v1/scaffolds/api.go index 18efcf83..084f56a0 100644 --- a/pkg/plugins/v1/scaffolds/api.go +++ b/pkg/plugins/v1/scaffolds/api.go @@ -18,89 +18,84 @@ limitations under the License. package scaffolds import ( - "errors" "fmt" "os" - "path/filepath" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/v1/chartutil" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/v1/scaffolds/internal/templates" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/v1/scaffolds/internal/templates/config/crd" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/v1/scaffolds/internal/templates/config/rbac" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/v1/scaffolds/internal/templates/config/samples" + "helm.sh/helm/v3/pkg/chart" "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/model" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" - - "github.com/joelanford/helm-operator/pkg/plugins/internal/kubebuilder/cmdutil" - "github.com/joelanford/helm-operator/pkg/plugins/internal/kubebuilder/machinery" - "github.com/joelanford/helm-operator/pkg/plugins/v1/chartutil" - "github.com/joelanford/helm-operator/pkg/plugins/v1/scaffolds/internal/templates" - "github.com/joelanford/helm-operator/pkg/plugins/v1/scaffolds/internal/templates/config/crd" - "github.com/joelanford/helm-operator/pkg/plugins/v1/scaffolds/internal/templates/config/rbac" - "github.com/joelanford/helm-operator/pkg/plugins/v1/scaffolds/internal/templates/config/samples" + "sigs.k8s.io/kubebuilder/v3/pkg/plugins" ) -var _ cmdutil.Scaffolder = &apiScaffolder{} +var _ plugins.Scaffolder = &apiScaffolder{} // apiScaffolder contains configuration for generating scaffolding for Go type // representing the API and controller that implements the behavior for the API. type apiScaffolder struct { - config config.Config - opts chartutil.CreateOptions + fs machinery.Filesystem + + config config.Config + resource resource.Resource + chrt *chart.Chart } -// NewAPIScaffolder returns a new Scaffolder for API/controller creation operations -func NewAPIScaffolder(config config.Config, opts chartutil.CreateOptions) cmdutil.Scaffolder { +// NewAPIScaffolder returns a new plugins.Scaffolder for API/controller creation operations +func NewAPIScaffolder(cfg config.Config, res resource.Resource, chrt *chart.Chart) plugins.Scaffolder { return &apiScaffolder{ - config: config, - opts: opts, + config: cfg, + resource: res, + chrt: chrt, } } -// Scaffold implements Scaffolder -func (s *apiScaffolder) Scaffold() error { - return s.scaffold() +// InjectFS implements plugins.Scaffolder +func (s *apiScaffolder) InjectFS(fs machinery.Filesystem) { + s.fs = fs } -func (s *apiScaffolder) newUniverse(r *resource.Resource) *model.Universe { - return model.NewUniverse( - model.WithConfig(s.config), - model.WithResource(r), - ) -} +// Scaffold implements plugins.Scaffolder +func (s *apiScaffolder) Scaffold() error { + if err := s.config.UpdateResource(s.resource); err != nil { + return err + } -func (s *apiScaffolder) scaffold() error { + // Get current directory projectDir, err := os.Getwd() if err != nil { return err } - r, chrt, err := chartutil.CreateChart(projectDir, s.opts) + + // Save the loaded chart.Chart + var chartPath string + s.chrt, chartPath, err = chartutil.ScaffoldChart(s.chrt, projectDir) if err != nil { return err } - r.Domain = s.config.GetDomain() - - // Check that resource doesn't exist - if s.config.HasResource(r.GVK) { - return errors.New("the API resource already exists") - } - // Check that the provided group can be added to the project - if !s.config.IsMultiGroup() && s.config.ResourcesLength() != 0 && !s.config.HasGroup(r.Group) { - return errors.New("multiple groups are not allowed by default, to enable multi-group set 'multigroup: true' in your PROJECT file") - } - - if err := s.config.UpdateResource(*r); err != nil { - return fmt.Errorf("error updating resource in PROJECT file: %v", err) - } + fmt.Printf("Created %s\n", chartPath) + + // Initialize the machinery.Scaffold that will write the files to disk + scaffold := machinery.NewScaffold(s.fs, + // NOTE: kubebuilder's default permissions are only for root users + machinery.WithDirectoryPermissions(0755), + machinery.WithFilePermissions(0644), + machinery.WithConfig(s.config), + machinery.WithResource(&s.resource), + ) - chartPath := filepath.Join(chartutil.HelmChartsDir, chrt.Metadata.Name) - if err := machinery.NewScaffold().Execute( - s.newUniverse(r), + if err := scaffold.Execute( &templates.WatchesUpdater{ChartPath: chartPath}, - &crd.CRD{CRDVersion: s.opts.CRDVersion}, + &crd.CRD{}, &crd.Kustomization{}, - &rbac.CRDEditorRole{}, - &rbac.CRDViewerRole{}, - &rbac.ManagerRoleUpdater{Chart: chrt}, - &samples.CRDSample{ChartPath: chartPath, Chart: chrt}, + &rbac.ManagerRoleUpdater{Chart: s.chrt}, + &samples.CustomResource{ChartPath: chartPath, Chart: s.chrt}, ); err != nil { - return fmt.Errorf("error scaffolding APIs: %v", err) + return fmt.Errorf("error scaffolding APIs: %w", err) } return nil diff --git a/pkg/plugins/v1/scaffolds/init.go b/pkg/plugins/v1/scaffolds/init.go index 821236fc..2d5d295e 100644 --- a/pkg/plugins/v1/scaffolds/init.go +++ b/pkg/plugins/v1/scaffolds/init.go @@ -21,17 +21,13 @@ import ( "os" "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/model" - - "github.com/joelanford/helm-operator/internal/version" - "github.com/joelanford/helm-operator/pkg/plugins/internal/kubebuilder/cmdutil" - "github.com/joelanford/helm-operator/pkg/plugins/internal/kubebuilder/machinery" - "github.com/joelanford/helm-operator/pkg/plugins/v1/chartutil" - "github.com/joelanford/helm-operator/pkg/plugins/v1/scaffolds/internal/templates" - "github.com/joelanford/helm-operator/pkg/plugins/v1/scaffolds/internal/templates/config/kdefault" - "github.com/joelanford/helm-operator/pkg/plugins/v1/scaffolds/internal/templates/config/manager" - "github.com/joelanford/helm-operator/pkg/plugins/v1/scaffolds/internal/templates/config/prometheus" - "github.com/joelanford/helm-operator/pkg/plugins/v1/scaffolds/internal/templates/config/rbac" + "sigs.k8s.io/kubebuilder/v3/pkg/plugins" + + "github.com/operator-framework/helm-operator-plugins/internal/version" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/v1/chartutil" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/v1/scaffolds/internal/templates" + "github.com/operator-framework/helm-operator-plugins/pkg/plugins/v1/scaffolds/internal/templates/config/rbac" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) const ( @@ -43,44 +39,40 @@ const ( // helmOperatorVersion is set to the version of helm-operator at compile-time. var helmOperatorVersion = mustGetScaffoldVersion() -var _ cmdutil.Scaffolder = &initScaffolder{} +var _ plugins.Scaffolder = &initScaffolder{} type initScaffolder struct { - config config.Config - apiScaffolder cmdutil.Scaffolder + fs machinery.Filesystem + + config config.Config } -// NewInitScaffolder returns a new Scaffolder for project initialization operations -func NewInitScaffolder(config config.Config, apiScaffolder cmdutil.Scaffolder) cmdutil.Scaffolder { +// NewInitScaffolder returns a new plugins.Scaffolder for project initialization operations +func NewInitScaffolder(config config.Config) plugins.Scaffolder { return &initScaffolder{ - config: config, - apiScaffolder: apiScaffolder, + config: config, } } -func (s *initScaffolder) newUniverse() *model.Universe { - return model.NewUniverse( - model.WithConfig(s.config), - ) +// InjectFS implements plugins.Scaffolder +func (s *initScaffolder) InjectFS(fs machinery.Filesystem) { + s.fs = fs } // Scaffold implements Scaffolder func (s *initScaffolder) Scaffold() error { - if err := s.scaffold(); err != nil { - return err - } - if s.apiScaffolder != nil { - return s.apiScaffolder.Scaffold() - } - return nil -} + // Initialize the machinery.Scaffold that will write the files to disk + scaffold := machinery.NewScaffold(s.fs, + // NOTE: kubebuilder's default permissions are only for root users + machinery.WithDirectoryPermissions(0755), + machinery.WithFilePermissions(0644), + machinery.WithConfig(s.config), + ) -func (s *initScaffolder) scaffold() error { if err := os.MkdirAll(chartutil.HelmChartsDir, 0755); err != nil { return err } - return machinery.NewScaffold().Execute( - s.newUniverse(), + return scaffold.Execute( &templates.Dockerfile{ HelmOperatorVersion: helmOperatorVersion, }, @@ -91,21 +83,7 @@ func (s *initScaffolder) scaffold() error { HelmOperatorVersion: helmOperatorVersion, }, &templates.Watches{}, - &rbac.AuthProxyRole{}, - &rbac.AuthProxyRoleBinding{}, - &rbac.AuthProxyService{}, - &rbac.ClientClusterRole{}, - &rbac.Kustomization{}, - &rbac.LeaderElectionRole{}, - &rbac.LeaderElectionRoleBinding{}, &rbac.ManagerRole{}, - &rbac.ManagerRoleBinding{}, - &manager.Kustomization{}, - &manager.Manager{Image: imageName}, - &prometheus.Kustomization{}, - &prometheus.ServiceMonitor{}, - &kdefault.AuthProxyPatch{}, - &kdefault.Kustomization{}, ) } diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/crd/crd.go b/pkg/plugins/v1/scaffolds/internal/templates/config/crd/crd.go index 842a1ae0..85f81da3 100644 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/crd/crd.go +++ b/pkg/plugins/v1/scaffolds/internal/templates/config/crd/crd.go @@ -15,47 +15,40 @@ package crd import ( - "errors" "fmt" "path/filepath" "github.com/kr/text" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &CRD{} +var _ machinery.Template = &CRD{} // CRD scaffolds a manifest for CRD sample. type CRD struct { - file.TemplateMixin - file.ResourceMixin - - CRDVersion string + machinery.TemplateMixin + machinery.ResourceMixin } -// SetTemplateDefaults implements input.Template +// SetTemplateDefaults implements machinery.Template func (f *CRD) SetTemplateDefaults() error { if f.Path == "" { f.Path = filepath.Join("config", "crd", "bases", fmt.Sprintf("%s_%%[plural].yaml", f.Resource.QualifiedGroup())) } f.Path = f.Resource.Replacer().Replace(f.Path) - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error - if f.CRDVersion == "" { - f.CRDVersion = "v1" - } else if f.CRDVersion != "v1" && f.CRDVersion != "v1beta1" { - return errors.New("the CRD version value must be either 'v1' or 'v1beta1'") - } f.TemplateBody = fmt.Sprintf(crdTemplate, text.Indent(openAPIV3SchemaTemplate, " "), text.Indent(openAPIV3SchemaTemplate, " "), ) + return nil } const crdTemplate = `--- -apiVersion: apiextensions.k8s.io/{{ .CRDVersion }} +apiVersion: apiextensions.k8s.io/{{ .Resource.API.CRDVersion }} kind: CustomResourceDefinition metadata: name: {{ .Resource.Plural }}.{{ .Resource.QualifiedGroup }} @@ -67,7 +60,7 @@ spec: plural: {{ .Resource.Plural }} singular: {{ .Resource.Kind | lower }} scope: Namespaced -{{- if eq .CRDVersion "v1beta1" }} +{{- if eq .Resource.API.CRDVersion "v1beta1" }} subresources: status: {} validation: @@ -75,13 +68,13 @@ spec: {{- end }} versions: - name: {{ .Resource.Version }} -{{- if eq .CRDVersion "v1" }} +{{- if eq .Resource.API.CRDVersion "v1" }} schema: %s {{- end }} served: true storage: true -{{- if eq .CRDVersion "v1" }} +{{- if eq .Resource.API.CRDVersion "v1" }} subresources: status: {} {{- end }} diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/crd/kustomization.go b/pkg/plugins/v1/scaffolds/internal/templates/config/crd/kustomization.go index 7c0cc71d..871c00e1 100644 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/crd/kustomization.go +++ b/pkg/plugins/v1/scaffolds/internal/templates/config/crd/kustomization.go @@ -21,28 +21,27 @@ import ( "fmt" "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Kustomization{} -var _ file.Inserter = &Kustomization{} +var ( + _ machinery.Template = &Kustomization{} + _ machinery.Inserter = &Kustomization{} +) // Kustomization scaffolds the kustomization file in manager folder. type Kustomization struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } -// SetTemplateDefaults implements file.Template +// SetTemplateDefaults implements machinery.Template func (f *Kustomization) SetTemplateDefaults() error { if f.Path == "" { f.Path = filepath.Join("config", "crd", "kustomization.yaml") } - f.Path = f.Resource.Replacer().Replace(f.Path) - f.TemplateBody = fmt.Sprintf(kustomizationTemplate, - file.NewMarkerFor(f.Path, resourceMarker), - ) + f.TemplateBody = fmt.Sprintf(kustomizationTemplate, machinery.NewMarkerFor(f.Path, resourceMarker)) return nil } @@ -51,10 +50,10 @@ const ( resourceMarker = "crdkustomizeresource" ) -// GetMarkers implements file.Inserter -func (f *Kustomization) GetMarkers() []file.Marker { - return []file.Marker{ - file.NewMarkerFor(f.Path, resourceMarker), +// GetMarkers implements machinery.Inserter +func (f *Kustomization) GetMarkers() []machinery.Marker { + return []machinery.Marker{ + machinery.NewMarkerFor(f.Path, resourceMarker), } } @@ -63,20 +62,14 @@ const ( ` ) -// GetCodeFragments implements file.Inserter -func (f *Kustomization) GetCodeFragments() file.CodeFragmentsMap { - fragments := make(file.CodeFragmentsMap, 3) - - // Generate resource code fragments - res := make([]string, 0) - res = append(res, fmt.Sprintf(resourceCodeFragment, f.Resource.QualifiedGroup(), f.Resource.Plural)) - - // Only store code fragments in the map if the slices are non-empty - if len(res) != 0 { - fragments[file.NewMarkerFor(f.Path, resourceMarker)] = res +// GetCodeFragments implements machinery.Inserter +func (f *Kustomization) GetCodeFragments() machinery.CodeFragmentsMap { + return machinery.CodeFragmentsMap{ + // Generate resource code fragments + machinery.NewMarkerFor(f.Path, resourceMarker): []string{ + fmt.Sprintf(resourceCodeFragment, f.Resource.QualifiedGroup(), f.Resource.Plural), + }, } - - return fragments } var kustomizationTemplate = `# This kustomization.yaml is not intended to be run by itself, diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/kdefault/auth_proxy_patch.go b/pkg/plugins/v1/scaffolds/internal/templates/config/kdefault/auth_proxy_patch.go deleted file mode 100644 index 5c3a1086..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/kdefault/auth_proxy_patch.go +++ /dev/null @@ -1,74 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. -Modifications copyright 2020 The Operator-SDK Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package kdefault - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &AuthProxyPatch{} - -// AuthProxyPatch scaffolds the patch file for enabling -// prometheus metrics for manager Pod. -type AuthProxyPatch struct { - file.TemplateMixin - file.ProjectNameMixin -} - -// SetTemplateDefaults implements input.Template -func (f *AuthProxyPatch) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "default", "manager_auth_proxy_patch.yaml") - } - - f.TemplateBody = kustomizeAuthProxyPatchTemplate - - f.IfExistsAction = file.Error - - return nil -} - -const kustomizeAuthProxyPatchTemplate = `# This patch inject a sidecar container which is a HTTP proxy for the -# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. -apiVersion: apps/v1 -kind: Deployment -metadata: - name: controller-manager - namespace: system -spec: - template: - spec: - containers: - - name: kube-rbac-proxy - image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8080/" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - - name: manager - args: - - "--metrics-addr=127.0.0.1:8080" - - "--enable-leader-election" - - "--leader-election-id={{ .ProjectName }}" -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/kdefault/kustomization.go b/pkg/plugins/v1/scaffolds/internal/templates/config/kdefault/kustomization.go deleted file mode 100644 index a5745e7c..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/kdefault/kustomization.go +++ /dev/null @@ -1,73 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. -Modifications copyright 2020 The Operator-SDK Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package kdefault - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &Kustomization{} - -// Kustomization scaffolds the Kustomization file for the default overlay -type Kustomization struct { - file.TemplateMixin - file.ProjectNameMixin -} - -// SetTemplateDefaults implements input.Template -func (f *Kustomization) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "default", "kustomization.yaml") - } - - f.TemplateBody = kustomizeTemplate - - f.IfExistsAction = file.Error - - return nil -} - -const kustomizeTemplate = `# Adds namespace to all resources. -namespace: {{ .ProjectName }}-system - -# Value of this field is prepended to the -# names of all resources, e.g. a deployment named -# "wordpress" becomes "alices-wordpress". -# Note that it should also match with the prefix (text before '-') of the namespace -# field above. -namePrefix: {{ .ProjectName }}- - -# Labels to add to all resources and selectors. -#commonLabels: -# someName: someValue - -bases: -- ../crd -- ../rbac -- ../manager -# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. -#- ../prometheus - -patchesStrategicMerge: - # Protect the /metrics endpoint by putting it behind auth. - # If you want your controller-manager to expose the /metrics - # endpoint w/o any authn/z, please comment the following line. -- manager_auth_proxy_patch.yaml -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/manager/kustomization.go b/pkg/plugins/v1/scaffolds/internal/templates/config/manager/kustomization.go deleted file mode 100644 index 93dcfafa..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/manager/kustomization.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package manager - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &Kustomization{} - -// Kustomization scaffolds the Kustomization file in manager folder. -type Kustomization struct { - file.TemplateMixin -} - -// SetTemplateDefaults implements input.Template -func (f *Kustomization) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "manager", "kustomization.yaml") - } - - f.TemplateBody = kustomizeManagerTemplate - - f.IfExistsAction = file.Error - - return nil -} - -const kustomizeManagerTemplate = `resources: -- manager.yaml -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/manager/manager.go b/pkg/plugins/v1/scaffolds/internal/templates/config/manager/manager.go deleted file mode 100644 index 6c59d16f..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/manager/manager.go +++ /dev/null @@ -1,98 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. -Modifications copyright 2020 The Operator-SDK Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package manager - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &Manager{} - -// Manager scaffolds yaml config for the manager. -type Manager struct { - file.TemplateMixin - file.ProjectNameMixin - - // Image is controller manager image name - Image string -} - -// SetTemplateDefaults implements input.Template -func (f *Manager) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "manager", "manager.yaml") - } - - f.TemplateBody = managerTemplate - - return nil -} - -const managerTemplate = `apiVersion: v1 -kind: Namespace -metadata: - labels: - control-plane: controller-manager - name: system ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: controller-manager - namespace: system - labels: - control-plane: controller-manager -spec: - selector: - matchLabels: - control-plane: controller-manager - replicas: 1 - template: - metadata: - labels: - control-plane: controller-manager - spec: - containers: - - image: {{ .Image }} - args: - - "--enable-leader-election" - - "--leader-election-id={{ .ProjectName }}" - name: manager - livenessProbe: - httpGet: - path: /healthz - port: 8081 - initialDelaySeconds: 15 - periodSeconds: 20 - readinessProbe: - httpGet: - path: /readyz - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 10 - resources: - limits: - cpu: 100m - memory: 90Mi - requests: - cpu: 100m - memory: 60Mi - terminationGracePeriodSeconds: 10 -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/prometheus/kustomization.go b/pkg/plugins/v1/scaffolds/internal/templates/config/prometheus/kustomization.go deleted file mode 100644 index a794eea1..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/prometheus/kustomization.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package prometheus - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &Kustomization{} - -// Kustomization scaffolds the kustomizaiton in the prometheus folder -type Kustomization struct { - file.TemplateMixin -} - -// SetTemplateDefaults implements input.Template -func (f *Kustomization) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "prometheus", "kustomization.yaml") - } - - f.TemplateBody = kustomizationTemplate - - return nil -} - -const kustomizationTemplate = `resources: -- monitor.yaml -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/prometheus/monitor.go b/pkg/plugins/v1/scaffolds/internal/templates/config/prometheus/monitor.go deleted file mode 100644 index d092c6b8..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/prometheus/monitor.go +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package prometheus - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &ServiceMonitor{} - -// ServiceMonitor scaffolds an issuer CR and a certificate CR -type ServiceMonitor struct { - file.TemplateMixin -} - -// SetTemplateDefaults implements input.Template -func (f *ServiceMonitor) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "prometheus", "monitor.yaml") - } - - f.TemplateBody = serviceMonitorTemplate - - return nil -} - -const serviceMonitorTemplate = ` -# Prometheus Monitor Service (Metrics) -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - labels: - control-plane: controller-manager - name: controller-manager-metrics-monitor - namespace: system -spec: - endpoints: - - path: /metrics - port: https - selector: - matchLabels: - control-plane: controller-manager -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role.go b/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role.go deleted file mode 100644 index 2fb69db5..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role.go +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package rbac - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &AuthProxyRole{} - -// AuthProxyRole scaffolds the config/rbac/auth_proxy_role.yaml file -type AuthProxyRole struct { - file.TemplateMixin -} - -// SetTemplateDefaults implements input.Template -func (f *AuthProxyRole) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "rbac", "auth_proxy_role.yaml") - } - - f.TemplateBody = proxyRoleTemplate - - return nil -} - -const proxyRoleTemplate = `apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: proxy-role -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role_binding.go b/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role_binding.go deleted file mode 100644 index 5c52caec..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role_binding.go +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package rbac - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &AuthProxyRoleBinding{} - -// AuthProxyRoleBinding scaffolds the config/rbac/auth_proxy_role_binding_rbac.yaml file -type AuthProxyRoleBinding struct { - file.TemplateMixin -} - -// SetTemplateDefaults implements input.Template -func (f *AuthProxyRoleBinding) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "rbac", "auth_proxy_role_binding.yaml") - } - - f.TemplateBody = proxyRoleBindinggTemplate - - return nil -} - -const proxyRoleBindinggTemplate = `apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: proxy-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: proxy-role -subjects: -- kind: ServiceAccount - name: default - namespace: system -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/auth_proxy_service.go b/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/auth_proxy_service.go deleted file mode 100644 index 25a0a52a..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/auth_proxy_service.go +++ /dev/null @@ -1,57 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package rbac - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &AuthProxyService{} - -// AuthProxyService scaffolds the config/rbac/auth_proxy_service.yaml file -type AuthProxyService struct { - file.TemplateMixin -} - -// SetTemplateDefaults implements input.Template -func (f *AuthProxyService) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "rbac", "auth_proxy_service.yaml") - } - - f.TemplateBody = authProxyServiceTemplate - - return nil -} - -const authProxyServiceTemplate = `apiVersion: v1 -kind: Service -metadata: - labels: - control-plane: controller-manager - name: controller-manager-metrics-service - namespace: system -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - control-plane: controller-manager -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/client_cluster_role.go b/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/client_cluster_role.go deleted file mode 100644 index 6553210c..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/client_cluster_role.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package rbac - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &ClientClusterRole{} - -// ClientClusterRole scaffolds the config/rbac/client_clusterrole.yaml file -type ClientClusterRole struct { - file.TemplateMixin -} - -// SetTemplateDefaults implements input.Template -func (f *ClientClusterRole) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "rbac", "auth_proxy_client_clusterrole.yaml") - } - - f.TemplateBody = clientClusterRoleTemplate - - return nil -} - -const clientClusterRoleTemplate = `apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: metrics-reader -rules: -- nonResourceURLs: ["/metrics"] - verbs: ["get"] -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go b/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go deleted file mode 100644 index 44b02767..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package rbac - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &CRDEditorRole{} - -// CRDEditorRole scaffolds the config/rbac/_editor_role.yaml -type CRDEditorRole struct { - file.TemplateMixin - file.ResourceMixin -} - -// SetTemplateDefaults implements input.Template -func (f *CRDEditorRole) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "rbac", "%[kind]_editor_role.yaml") - } - f.Path = f.Resource.Replacer().Replace(f.Path) - - f.TemplateBody = crdRoleEditorTemplate - - return nil -} - -const crdRoleEditorTemplate = `# permissions for end users to edit {{ .Resource.Plural }}. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ lower .Resource.Kind }}-editor-role -rules: -- apiGroups: - - {{ .Resource.QualifiedGroup }} - resources: - - {{ .Resource.Plural }} - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - {{ .Resource.QualifiedGroup }} - resources: - - {{ .Resource.Plural }}/status - verbs: - - get -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go b/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go deleted file mode 100644 index 3dee9614..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package rbac - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &CRDViewerRole{} - -// CRDViewerRole scaffolds the config/rbac/_viewer_role.yaml -type CRDViewerRole struct { - file.TemplateMixin - file.ResourceMixin -} - -// SetTemplateDefaults implements input.Template -func (f *CRDViewerRole) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "rbac", "%[kind]_viewer_role.yaml") - } - f.Path = f.Resource.Replacer().Replace(f.Path) - - f.TemplateBody = crdRoleViewerTemplate - - return nil -} - -const crdRoleViewerTemplate = `# permissions for end users to view {{ .Resource.Plural }}. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ lower .Resource.Kind }}-viewer-role -rules: -- apiGroups: - - {{ .Resource.QualifiedGroup }} - resources: - - {{ .Resource.Plural }} - verbs: - - get - - list - - watch -- apiGroups: - - {{ .Resource.QualifiedGroup }} - resources: - - {{ .Resource.Plural }}/status - verbs: - - get -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/kustomization.go b/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/kustomization.go deleted file mode 100644 index 74c3ef6e..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/kustomization.go +++ /dev/null @@ -1,57 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package rbac - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &Kustomization{} - -// Kustomization scaffolds the Kustomization file in rbac folder. -type Kustomization struct { - file.TemplateMixin -} - -// SetTemplateDefaults implements input.Template -func (f *Kustomization) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "rbac", "kustomization.yaml") - } - - f.TemplateBody = kustomizeRBACTemplate - - f.IfExistsAction = file.Error - - return nil -} - -const kustomizeRBACTemplate = `resources: -- role.yaml -- role_binding.yaml -- leader_election_role.yaml -- leader_election_role_binding.yaml -# Comment the following 4 lines if you want to disable -# the auth proxy (https://github.com/brancz/kube-rbac-proxy) -# which protects your /metrics endpoint. -- auth_proxy_service.yaml -- auth_proxy_role.yaml -- auth_proxy_role_binding.yaml -- auth_proxy_client_clusterrole.yaml -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/leader_election_role.go b/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/leader_election_role.go deleted file mode 100644 index f029a428..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/leader_election_role.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package rbac - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &LeaderElectionRole{} - -// LeaderElectionRole scaffolds the config/rbac/leader_election_role.yaml file -type LeaderElectionRole struct { - file.TemplateMixin -} - -// SetTemplateDefaults implements input.Template -func (f *LeaderElectionRole) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "rbac", "leader_election_role.yaml") - } - - f.TemplateBody = leaderElectionRoleTemplate - - return nil -} - -const leaderElectionRoleTemplate = `# permissions to do leader election. -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: leader-election-role -rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/leader_election_role_binding.go b/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/leader_election_role_binding.go deleted file mode 100644 index 994c3179..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/leader_election_role_binding.go +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package rbac - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &LeaderElectionRoleBinding{} - -// LeaderElectionRoleBinding scaffolds the config/rbac/leader_election_role_binding.yaml file -type LeaderElectionRoleBinding struct { - file.TemplateMixin -} - -// SetTemplateDefaults implements input.Template -func (f *LeaderElectionRoleBinding) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "rbac", "leader_election_role_binding.yaml") - } - - f.TemplateBody = leaderElectionRoleBindingTemplate - - return nil -} - -const leaderElectionRoleBindingTemplate = `apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: leader-election-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: leader-election-role -subjects: -- kind: ServiceAccount - name: default - namespace: system -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/manager_role.go b/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/manager_role.go index 8472ff19..e5140183 100644 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/manager_role.go +++ b/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/manager_role.go @@ -32,36 +32,34 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/discovery" crconfig "sigs.k8s.io/controller-runtime/pkg/client/config" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "sigs.k8s.io/yaml" ) -var _ file.Template = &ManagerRole{} +var _ machinery.Template = &ManagerRole{} var defaultRoleFile = filepath.Join("config", "rbac", "role.yaml") // ManagerRole scaffolds the role.yaml file type ManagerRole struct { - file.TemplateMixin + machinery.TemplateMixin } -// SetTemplateDefaults implements input.Template +// SetTemplateDefaults implements machinery.Template func (f *ManagerRole) SetTemplateDefaults() error { if f.Path == "" { f.Path = defaultRoleFile } - f.TemplateBody = fmt.Sprintf(roleTemplate, - file.NewMarkerFor(f.Path, rulesMarker), - ) + f.TemplateBody = fmt.Sprintf(roleTemplate, machinery.NewMarkerFor(f.Path, rulesMarker)) + return nil } -var _ file.Inserter = &ManagerRoleUpdater{} +var _ machinery.Inserter = &ManagerRoleUpdater{} type ManagerRoleUpdater struct { - file.TemplateMixin - file.ResourceMixin + machinery.ResourceMixin Chart *chart.Chart SkipDefaultRules bool @@ -72,22 +70,22 @@ func (*ManagerRoleUpdater) GetPath() string { return defaultRoleFile } -func (*ManagerRoleUpdater) GetIfExistsAction() file.IfExistsAction { - return file.Overwrite +func (*ManagerRoleUpdater) GetIfExistsAction() machinery.IfExistsAction { + return machinery.OverwriteFile } const ( rulesMarker = "rules" ) -func (f *ManagerRoleUpdater) GetMarkers() []file.Marker { - return []file.Marker{ - file.NewMarkerFor(defaultRoleFile, rulesMarker), +func (f *ManagerRoleUpdater) GetMarkers() []machinery.Marker { + return []machinery.Marker{ + machinery.NewMarkerFor(defaultRoleFile, rulesMarker), } } -func (f *ManagerRoleUpdater) GetCodeFragments() file.CodeFragmentsMap { - fragments := make(file.CodeFragmentsMap, 1) +func (f *ManagerRoleUpdater) GetCodeFragments() machinery.CodeFragmentsMap { + fragments := make(machinery.CodeFragmentsMap, 1) // If resource is not being provided we are creating the file, not updating it if f.Resource == nil { @@ -113,7 +111,7 @@ func (f *ManagerRoleUpdater) GetCodeFragments() file.CodeFragmentsMap { rules := []string{buf.String()} if len(rules) != 0 { - fragments[file.NewMarkerFor(defaultRoleFile, rulesMarker)] = rules + fragments[machinery.NewMarkerFor(defaultRoleFile, rulesMarker)] = rules } return fragments } diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/manager_role_binding.go b/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/manager_role_binding.go deleted file mode 100644 index 544f4656..00000000 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/rbac/manager_role_binding.go +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package rbac - -import ( - "path/filepath" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -var _ file.Template = &ManagerRoleBinding{} - -// ManagerRoleBinding scaffolds the config/rbac/role_binding.yaml file -type ManagerRoleBinding struct { - file.TemplateMixin -} - -// SetTemplateDefaults implements input.Template -func (f *ManagerRoleBinding) SetTemplateDefaults() error { - if f.Path == "" { - f.Path = filepath.Join("config", "rbac", "role_binding.yaml") - } - - f.TemplateBody = managerBindingTemplate - - return nil -} - -const managerBindingTemplate = `apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: manager-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: manager-role -subjects: -- kind: ServiceAccount - name: default - namespace: system -` diff --git a/pkg/plugins/v1/scaffolds/internal/templates/config/samples/crd_sample.go b/pkg/plugins/v1/scaffolds/internal/templates/config/samples/crd_sample.go index b33681fb..ec757433 100644 --- a/pkg/plugins/v1/scaffolds/internal/templates/config/samples/crd_sample.go +++ b/pkg/plugins/v1/scaffolds/internal/templates/config/samples/crd_sample.go @@ -24,31 +24,33 @@ import ( "text/template" "helm.sh/helm/v3/pkg/chart" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "sigs.k8s.io/yaml" ) -var _ file.Template = &CRDSample{} -var _ file.UseCustomFuncMap = &CRDSample{} +var ( + _ machinery.Template = &CustomResource{} + _ machinery.UseCustomFuncMap = &CustomResource{} +) -// CRDSample scaffolds a manifest for CRD sample. -type CRDSample struct { - file.TemplateMixin - file.ResourceMixin +// CustomResource scaffolds a custom resource sample manifest. +type CustomResource struct { + machinery.TemplateMixin + machinery.ResourceMixin ChartPath string Chart *chart.Chart Spec string } -// SetTemplateDefaults implements input.Template -func (f *CRDSample) SetTemplateDefaults() error { +// SetTemplateDefaults implements machinery.Template +func (f *CustomResource) SetTemplateDefaults() error { if f.Path == "" { f.Path = filepath.Join("config", "samples", "%[group]_%[version]_%[kind].yaml") } f.Path = f.Resource.Replacer().Replace(f.Path) - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.OverwriteFile if len(f.Spec) == 0 { f.Spec = defaultSpecTemplate @@ -65,7 +67,7 @@ func (f *CRDSample) SetTemplateDefaults() error { } } - f.TemplateBody = crdSampleTemplate + f.TemplateBody = customResourceTemplate return nil } @@ -74,9 +76,9 @@ func indent(spaces int, v string) string { return pad + strings.Replace(v, "\n", "\n"+pad, -1) } -// GetFuncMap implements file.UseCustomFuncMap -func (f *CRDSample) GetFuncMap() template.FuncMap { - fm := file.DefaultFuncMap() +// GetFuncMap implements machinery.UseCustomFuncMap +func (f *CustomResource) GetFuncMap() template.FuncMap { + fm := machinery.DefaultFuncMap() fm["indent"] = indent return fm } @@ -84,7 +86,7 @@ func (f *CRDSample) GetFuncMap() template.FuncMap { const defaultSpecTemplate = `foo: bar ` -const crdSampleTemplate = `apiVersion: {{ .Resource.QualifiedGroup }}/{{ .Resource.Version }} +const customResourceTemplate = `apiVersion: {{ .Resource.QualifiedGroup }}/{{ .Resource.Version }} kind: {{ .Resource.Kind }} metadata: name: {{ lower .Resource.Kind }}-sample diff --git a/pkg/plugins/v1/scaffolds/internal/templates/dockerfile.go b/pkg/plugins/v1/scaffolds/internal/templates/dockerfile.go index 0803e936..55c04a62 100644 --- a/pkg/plugins/v1/scaffolds/internal/templates/dockerfile.go +++ b/pkg/plugins/v1/scaffolds/internal/templates/dockerfile.go @@ -17,20 +17,20 @@ package templates import ( "errors" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Dockerfile{} +var _ machinery.Template = &Dockerfile{} // Dockerfile scaffolds a Dockerfile for building a main type Dockerfile struct { - file.TemplateMixin + machinery.TemplateMixin - // HelmOperatorVersion is the version of the Dockerfile's base image. + // HelmOperatorVersion is the version of the Dockerfile base image. HelmOperatorVersion string } -// SetTemplateDefaults implements input.Template +// SetTemplateDefaults implements machinery.Template func (f *Dockerfile) SetTemplateDefaults() error { if f.Path == "" { f.Path = "Dockerfile" @@ -46,7 +46,7 @@ func (f *Dockerfile) SetTemplateDefaults() error { } const dockerfileTemplate = `# Build the manager binary -FROM quay.io/joelanford/helm-operator:{{.HelmOperatorVersion}} +FROM quay.io/operator-framework/helm-operator:{{.HelmOperatorVersion}} ENV HOME=/opt/helm COPY watches.yaml ${HOME}/watches.yaml diff --git a/pkg/plugins/v1/scaffolds/internal/templates/gitignore.go b/pkg/plugins/v1/scaffolds/internal/templates/gitignore.go index 64cc86d9..0d7290b5 100644 --- a/pkg/plugins/v1/scaffolds/internal/templates/gitignore.go +++ b/pkg/plugins/v1/scaffolds/internal/templates/gitignore.go @@ -18,17 +18,17 @@ limitations under the License. package templates import ( - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &GitIgnore{} +var _ machinery.Template = &GitIgnore{} // GitIgnore scaffolds the .gitignore file type GitIgnore struct { - file.TemplateMixin + machinery.TemplateMixin } -// SetTemplateDefaults implements input.Template +// SetTemplateDefaults implements machinery.Template func (f *GitIgnore) SetTemplateDefaults() error { if f.Path == "" { f.Path = ".gitignore" diff --git a/pkg/plugins/v1/scaffolds/internal/templates/makefile.go b/pkg/plugins/v1/scaffolds/internal/templates/makefile.go index a38f8a6e..814b2816 100644 --- a/pkg/plugins/v1/scaffolds/internal/templates/makefile.go +++ b/pkg/plugins/v1/scaffolds/internal/templates/makefile.go @@ -20,14 +20,14 @@ package templates import ( "errors" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Makefile{} +var _ machinery.Template = &Makefile{} // Makefile scaffolds the Makefile type Makefile struct { - file.TemplateMixin + machinery.TemplateMixin // Image is controller manager image name Image string @@ -39,7 +39,7 @@ type Makefile struct { HelmOperatorVersion string } -// SetTemplateDefaults implements input.Template +// SetTemplateDefaults implements machinery.Template func (f *Makefile) SetTemplateDefaults() error { if f.Path == "" { f.Path = "Makefile" @@ -47,7 +47,7 @@ func (f *Makefile) SetTemplateDefaults() error { f.TemplateBody = makefileTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error if f.Image == "" { f.Image = "controller:latest" @@ -70,42 +70,54 @@ IMG ?= {{ .Image }} all: docker-build -# Run against the configured Kubernetes cluster in ~/.kube/config -run: helm-operator +##@ General + +# The help target prints out all targets with their descriptions organized +# beneath their categories. The categories are represented by '##@' and the +# target descriptions by '##'. The awk commands is responsible for reading the +# entire set of makefiles included in this invocation, looking for lines of the +# file as xyz: ## something, and then pretty-format the target and help. Then, +# if there's a line with ##@ something, that gets pretty-printed as a category. +# More info on the usage of ANSI control characters for terminal formatting: +# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters +# More info on the awk command: +# http://linuxcommand.org/lc3_adv_awk.php + +help: ## Display this help. + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +##@ Build + +run: helm-operator ## Run against the configured Kubernetes cluster in ~/.kube/config $(HELM_OPERATOR) run -# Install CRDs into a cluster -install: kustomize +docker-build: ## Build docker image with the manager. + docker build -t ${IMG} . + +docker-push: ## Push docker image with the manager. + docker push ${IMG} + +##@ Deployment + +install: kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. $(KUSTOMIZE) build config/crd | kubectl apply -f - -# Uninstall CRDs from a cluster -uninstall: kustomize +uninstall: kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. $(KUSTOMIZE) build config/crd | kubectl delete -f - -# Deploy controller in the configured Kubernetes cluster in ~/.kube/config -deploy: kustomize +deploy: kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} $(KUSTOMIZE) build config/default | kubectl apply -f - -# Undeploy controller in the configured Kubernetes cluster in ~/.kube/config -undeploy: kustomize +undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. $(KUSTOMIZE) build config/default | kubectl delete -f - -# Build the docker image -docker-build: - docker build -t ${IMG} . - -# Push the docker image -docker-push: - docker push ${IMG} - OS := $(shell uname -s | tr '[:upper:]' '[:lower:]') ARCH := $(shell uname -m | sed 's/x86_64/amd64/') -# Download kustomize locally if necessary, preferring the $(pwd)/bin path over global if both exist. .PHONY: kustomize KUSTOMIZE = $(shell pwd)/bin/kustomize -kustomize: +kustomize: ## Download kustomize locally if necessary. ifeq (,$(wildcard $(KUSTOMIZE))) ifeq (,$(shell which kustomize 2>/dev/null)) @{ \ @@ -119,10 +131,9 @@ KUSTOMIZE = $(shell which kustomize) endif endif -# Download helm-operator locally if necessary, preferring the $(pwd)/bin path over global if both exist. .PHONY: helm-operator HELM_OPERATOR = $(shell pwd)/bin/helm-operator -helm-operator: +helm-operator: ## Download helm-operator locally if necessary, preferring the $(pwd)/bin path over global if both exist. ifeq (,$(wildcard $(HELM_OPERATOR))) ifeq (,$(shell which helm-operator 2>/dev/null)) @{ \ diff --git a/pkg/plugins/v1/scaffolds/internal/templates/watches.go b/pkg/plugins/v1/scaffolds/internal/templates/watches.go index 5269ae1f..2297cc03 100644 --- a/pkg/plugins/v1/scaffolds/internal/templates/watches.go +++ b/pkg/plugins/v1/scaffolds/internal/templates/watches.go @@ -17,35 +17,34 @@ package templates import ( "fmt" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Watches{} +var _ machinery.Template = &Watches{} const defaultWatchesFile = "watches.yaml" // Watches scaffolds the watches.yaml file type Watches struct { - file.TemplateMixin + machinery.TemplateMixin } -// SetTemplateDefaults implements input.Template +// SetTemplateDefaults implements machinery.Template func (f *Watches) SetTemplateDefaults() error { if f.Path == "" { f.Path = defaultWatchesFile } f.TemplateBody = fmt.Sprintf(watchesTemplate, - file.NewMarkerFor(f.Path, watchMarker), + machinery.NewMarkerFor(f.Path, watchMarker), ) return nil } -var _ file.Inserter = &WatchesUpdater{} +var _ machinery.Inserter = &WatchesUpdater{} type WatchesUpdater struct { - file.TemplateMixin - file.ResourceMixin + machinery.ResourceMixin ChartPath string } @@ -54,22 +53,22 @@ func (*WatchesUpdater) GetPath() string { return defaultWatchesFile } -func (*WatchesUpdater) GetIfExistsAction() file.IfExistsAction { - return file.Overwrite +func (*WatchesUpdater) GetIfExistsAction() machinery.IfExistsAction { + return machinery.OverwriteFile } const ( watchMarker = "watch" ) -func (f *WatchesUpdater) GetMarkers() []file.Marker { - return []file.Marker{ - file.NewMarkerFor(defaultWatchesFile, watchMarker), +func (f *WatchesUpdater) GetMarkers() []machinery.Marker { + return []machinery.Marker{ + machinery.NewMarkerFor(defaultWatchesFile, watchMarker), } } -func (f *WatchesUpdater) GetCodeFragments() file.CodeFragmentsMap { - fragments := make(file.CodeFragmentsMap, 1) +func (f *WatchesUpdater) GetCodeFragments() machinery.CodeFragmentsMap { + fragments := make(machinery.CodeFragmentsMap, 1) // If resource is not being provided we are creating the file, not updating it if f.Resource == nil { @@ -82,7 +81,7 @@ func (f *WatchesUpdater) GetCodeFragments() file.CodeFragmentsMap { fmt.Sprintf(watchFragment, f.Resource.QualifiedGroup(), f.Resource.Version, f.Resource.Kind, f.ChartPath)) if len(watches) != 0 { - fragments[file.NewMarkerFor(defaultWatchesFile, watchMarker)] = watches + fragments[machinery.NewMarkerFor(defaultWatchesFile, watchMarker)] = watches } return fragments } diff --git a/pkg/reconciler/internal/conditions/conditions.go b/pkg/reconciler/internal/conditions/conditions.go index 892aee36..1148e125 100644 --- a/pkg/reconciler/internal/conditions/conditions.go +++ b/pkg/reconciler/internal/conditions/conditions.go @@ -21,7 +21,7 @@ import ( corev1 "k8s.io/api/core/v1" - "github.com/joelanford/helm-operator/pkg/internal/sdk/status" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/sdk/status" ) const ( diff --git a/pkg/reconciler/internal/conditions/conditions_test.go b/pkg/reconciler/internal/conditions/conditions_test.go index 93aba549..f9dea6f6 100644 --- a/pkg/reconciler/internal/conditions/conditions_test.go +++ b/pkg/reconciler/internal/conditions/conditions_test.go @@ -23,8 +23,8 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" - "github.com/joelanford/helm-operator/pkg/internal/sdk/status" - . "github.com/joelanford/helm-operator/pkg/reconciler/internal/conditions" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/sdk/status" + . "github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/conditions" ) var _ = Describe("Conditions", func() { diff --git a/pkg/reconciler/internal/fake/actionclient.go b/pkg/reconciler/internal/fake/actionclient.go index 410c4deb..92b7da63 100644 --- a/pkg/reconciler/internal/fake/actionclient.go +++ b/pkg/reconciler/internal/fake/actionclient.go @@ -23,7 +23,7 @@ import ( "helm.sh/helm/v3/pkg/release" crclient "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/joelanford/helm-operator/pkg/client" + "github.com/operator-framework/helm-operator-plugins/pkg/client" ) func NewActionClientGetter(actionClient client.ActionInterface, orErr error) client.ActionClientGetter { diff --git a/pkg/reconciler/internal/hook/hook.go b/pkg/reconciler/internal/hook/hook.go index 82997399..f76ac796 100644 --- a/pkg/reconciler/internal/hook/hook.go +++ b/pkg/reconciler/internal/hook/hook.go @@ -31,10 +31,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/source" "sigs.k8s.io/yaml" - "github.com/joelanford/helm-operator/pkg/hook" - "github.com/joelanford/helm-operator/pkg/internal/sdk/controllerutil" - "github.com/joelanford/helm-operator/pkg/internal/sdk/predicate" - "github.com/joelanford/helm-operator/pkg/manifestutil" + "github.com/operator-framework/helm-operator-plugins/pkg/hook" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/sdk/controllerutil" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/sdk/predicate" + "github.com/operator-framework/helm-operator-plugins/pkg/manifestutil" ) func NewDependentResourceWatcher(c controller.Controller, rm meta.RESTMapper) hook.PostHook { diff --git a/pkg/reconciler/internal/hook/hook_test.go b/pkg/reconciler/internal/hook/hook_test.go index 6861e1ca..b31e9ddb 100644 --- a/pkg/reconciler/internal/hook/hook_test.go +++ b/pkg/reconciler/internal/hook/hook_test.go @@ -29,9 +29,9 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/controller-runtime/pkg/handler" - "github.com/joelanford/helm-operator/pkg/hook" - "github.com/joelanford/helm-operator/pkg/internal/sdk/fake" - internalhook "github.com/joelanford/helm-operator/pkg/reconciler/internal/hook" + "github.com/operator-framework/helm-operator-plugins/pkg/hook" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/sdk/fake" + internalhook "github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/hook" ) var _ = Describe("Hook", func() { diff --git a/pkg/reconciler/internal/updater/updater.go b/pkg/reconciler/internal/updater/updater.go index 590b5beb..28c06857 100644 --- a/pkg/reconciler/internal/updater/updater.go +++ b/pkg/reconciler/internal/updater/updater.go @@ -26,8 +26,8 @@ import ( "k8s.io/client-go/util/retry" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/joelanford/helm-operator/pkg/internal/sdk/controllerutil" - "github.com/joelanford/helm-operator/pkg/internal/sdk/status" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/sdk/controllerutil" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/sdk/status" ) func New(client client.Client) Updater { diff --git a/pkg/reconciler/internal/updater/updater_test.go b/pkg/reconciler/internal/updater/updater_test.go index 7df9d304..978a1540 100644 --- a/pkg/reconciler/internal/updater/updater_test.go +++ b/pkg/reconciler/internal/updater/updater_test.go @@ -29,7 +29,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - "github.com/joelanford/helm-operator/pkg/reconciler/internal/conditions" + "github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/conditions" ) const testFinalizer = "testFinalizer" diff --git a/pkg/reconciler/internal/values/values.go b/pkg/reconciler/internal/values/values.go index 5eef1b3f..dd6e51fd 100644 --- a/pkg/reconciler/internal/values/values.go +++ b/pkg/reconciler/internal/values/values.go @@ -24,7 +24,7 @@ import ( "helm.sh/helm/v3/pkg/strvals" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "github.com/joelanford/helm-operator/pkg/values" + "github.com/operator-framework/helm-operator-plugins/pkg/values" ) type Values struct { diff --git a/pkg/reconciler/internal/values/values_test.go b/pkg/reconciler/internal/values/values_test.go index ba99614a..d9c2d049 100644 --- a/pkg/reconciler/internal/values/values_test.go +++ b/pkg/reconciler/internal/values/values_test.go @@ -22,7 +22,7 @@ import ( "helm.sh/helm/v3/pkg/chartutil" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - . "github.com/joelanford/helm-operator/pkg/reconciler/internal/values" + . "github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/values" ) var _ = Describe("Values", func() { diff --git a/pkg/reconciler/reconciler.go b/pkg/reconciler/reconciler.go index abecaa9d..11872bf2 100644 --- a/pkg/reconciler/reconciler.go +++ b/pkg/reconciler/reconciler.go @@ -44,15 +44,15 @@ import ( "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/source" - "github.com/joelanford/helm-operator/pkg/annotation" - helmclient "github.com/joelanford/helm-operator/pkg/client" - "github.com/joelanford/helm-operator/pkg/hook" - "github.com/joelanford/helm-operator/pkg/internal/sdk/controllerutil" - "github.com/joelanford/helm-operator/pkg/reconciler/internal/conditions" - internalhook "github.com/joelanford/helm-operator/pkg/reconciler/internal/hook" - "github.com/joelanford/helm-operator/pkg/reconciler/internal/updater" - internalvalues "github.com/joelanford/helm-operator/pkg/reconciler/internal/values" - "github.com/joelanford/helm-operator/pkg/values" + "github.com/operator-framework/helm-operator-plugins/pkg/annotation" + helmclient "github.com/operator-framework/helm-operator-plugins/pkg/client" + "github.com/operator-framework/helm-operator-plugins/pkg/hook" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/sdk/controllerutil" + "github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/conditions" + internalhook "github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/hook" + "github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/updater" + internalvalues "github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/values" + "github.com/operator-framework/helm-operator-plugins/pkg/values" ) const uninstallFinalizer = "uninstall-helm-release" diff --git a/pkg/reconciler/reconciler_suite_test.go b/pkg/reconciler/reconciler_suite_test.go index 84cdf061..e1f9a013 100644 --- a/pkg/reconciler/reconciler_suite_test.go +++ b/pkg/reconciler/reconciler_suite_test.go @@ -28,7 +28,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - "github.com/joelanford/helm-operator/pkg/internal/testutil" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/testutil" ) func TestReconciler(t *testing.T) { diff --git a/pkg/reconciler/reconciler_test.go b/pkg/reconciler/reconciler_test.go index 96768e26..4a8fe368 100644 --- a/pkg/reconciler/reconciler_test.go +++ b/pkg/reconciler/reconciler_test.go @@ -49,15 +49,15 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/yaml" - "github.com/joelanford/helm-operator/pkg/annotation" - helmclient "github.com/joelanford/helm-operator/pkg/client" - "github.com/joelanford/helm-operator/pkg/hook" - "github.com/joelanford/helm-operator/pkg/internal/sdk/controllerutil" - "github.com/joelanford/helm-operator/pkg/internal/sdk/status" - "github.com/joelanford/helm-operator/pkg/internal/testutil" - "github.com/joelanford/helm-operator/pkg/reconciler/internal/conditions" - helmfake "github.com/joelanford/helm-operator/pkg/reconciler/internal/fake" - "github.com/joelanford/helm-operator/pkg/values" + "github.com/operator-framework/helm-operator-plugins/pkg/annotation" + helmclient "github.com/operator-framework/helm-operator-plugins/pkg/client" + "github.com/operator-framework/helm-operator-plugins/pkg/hook" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/sdk/controllerutil" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/sdk/status" + "github.com/operator-framework/helm-operator-plugins/pkg/internal/testutil" + "github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/conditions" + helmfake "github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/fake" + "github.com/operator-framework/helm-operator-plugins/pkg/values" ) var _ = Describe("Reconciler", func() {