From 96f500a0f9fcc12c6e385713b464d1dfde03e445 Mon Sep 17 00:00:00 2001 From: Mauricio Ferrari Date: Thu, 27 Jun 2024 23:37:04 -0400 Subject: [PATCH] Workflow Template Enhancements (#324) Co-authored-by: Vidya Reddy <59590642+Vidya2606@users.noreply.github.com> --- .github/workflows/integration-linux.yml | 72 +++---- cmd/create.go | 24 +-- cmd/create_test.go | 36 ++-- cmd/generate-workflow.go | 19 +- pkg/config/draftconfig.go | 68 +++++- pkg/config/draftconfig_test.go | 204 ++++++++++++++++++ pkg/osutil/osutil.go | 8 +- pkg/osutil/osutil_test.go | 2 +- pkg/prompts/prompts.go | 14 +- pkg/workflows/workflowconfig.go | 49 +++-- pkg/workflows/workflows_test.go | 11 +- .../azure-kubernetes-service-helm.yml | 20 +- template/workflows/helm/draft.yaml | 26 ++- .../azure-kubernetes-service-kustomize.yml | 16 +- template/workflows/kustomize/draft.yaml | 23 +- .../workflows/azure-kubernetes-service.yml | 14 +- template/workflows/manifests/draft.yaml | 23 +- test/gen_integration.sh | 6 +- 18 files changed, 499 insertions(+), 136 deletions(-) create mode 100644 pkg/config/draftconfig_test.go diff --git a/.github/workflows/integration-linux.yml b/.github/workflows/integration-linux.yml index 86c0952c..8d092931 100644 --- a/.github/workflows/integration-linux.yml +++ b/.github/workflows/integration-linux.yml @@ -139,7 +139,7 @@ jobs: curl -m 3 $SERVICEIP:80 kill $tunnelPID - run: | - ./draft -b main -v generate-workflow -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type helm --build-context-path . + ./draft -v generate-workflow -d ./langtest/ --deploy-type helm -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false pwd # Validate generated workflow yaml - name: Install action-validator with asdf @@ -273,7 +273,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -b main -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type kustomize --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type kustomize -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -398,7 +398,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -d ./langtest/ -b main -c someAksCluster -r localhost -g someResourceGroup --container-name testapp --deploy-type manifests --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type manifests -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -577,7 +577,7 @@ jobs: curl -m 3 $SERVICEIP:8080 kill $tunnelPID - run: | - ./draft -b main -v generate-workflow -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type helm --build-context-path . + ./draft -v generate-workflow -d ./langtest/ --deploy-type helm -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false pwd # Validate generated workflow yaml - name: Install action-validator with asdf @@ -711,7 +711,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:8080 kill $tunnelPID - - run: ./draft -v generate-workflow -b main -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type kustomize --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type kustomize -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -836,7 +836,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:8080 kill $tunnelPID - - run: ./draft -v generate-workflow -d ./langtest/ -b main -c someAksCluster -r localhost -g someResourceGroup --container-name testapp --deploy-type manifests --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type manifests -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -1015,7 +1015,7 @@ jobs: curl -m 3 $SERVICEIP:80 kill $tunnelPID - run: | - ./draft -b main -v generate-workflow -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type helm --build-context-path . + ./draft -v generate-workflow -d ./langtest/ --deploy-type helm -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false pwd # Validate generated workflow yaml - name: Install action-validator with asdf @@ -1149,7 +1149,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -b main -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type kustomize --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type kustomize -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -1274,7 +1274,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -d ./langtest/ -b main -c someAksCluster -r localhost -g someResourceGroup --container-name testapp --deploy-type manifests --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type manifests -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -1453,7 +1453,7 @@ jobs: curl -m 3 $SERVICEIP:80 kill $tunnelPID - run: | - ./draft -b main -v generate-workflow -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type helm --build-context-path . + ./draft -v generate-workflow -d ./langtest/ --deploy-type helm -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false pwd # Validate generated workflow yaml - name: Install action-validator with asdf @@ -1587,7 +1587,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -b main -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type kustomize --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type kustomize -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -1712,7 +1712,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -d ./langtest/ -b main -c someAksCluster -r localhost -g someResourceGroup --container-name testapp --deploy-type manifests --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type manifests -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -1891,7 +1891,7 @@ jobs: curl -m 3 $SERVICEIP:80 kill $tunnelPID - run: | - ./draft -b main -v generate-workflow -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type helm --build-context-path . + ./draft -v generate-workflow -d ./langtest/ --deploy-type helm -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false pwd # Validate generated workflow yaml - name: Install action-validator with asdf @@ -2025,7 +2025,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -b main -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type kustomize --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type kustomize -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -2150,7 +2150,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -d ./langtest/ -b main -c someAksCluster -r localhost -g someResourceGroup --container-name testapp --deploy-type manifests --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type manifests -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -2329,7 +2329,7 @@ jobs: curl -m 3 $SERVICEIP:80 kill $tunnelPID - run: | - ./draft -b main -v generate-workflow -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type helm --build-context-path . + ./draft -v generate-workflow -d ./langtest/ --deploy-type helm -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false pwd # Validate generated workflow yaml - name: Install action-validator with asdf @@ -2463,7 +2463,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -b main -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type kustomize --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type kustomize -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -2588,7 +2588,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -d ./langtest/ -b main -c someAksCluster -r localhost -g someResourceGroup --container-name testapp --deploy-type manifests --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type manifests -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -2767,7 +2767,7 @@ jobs: curl -m 3 $SERVICEIP:80 kill $tunnelPID - run: | - ./draft -b main -v generate-workflow -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type helm --build-context-path . + ./draft -v generate-workflow -d ./langtest/ --deploy-type helm -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false pwd # Validate generated workflow yaml - name: Install action-validator with asdf @@ -2901,7 +2901,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -b main -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type kustomize --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type kustomize -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -3026,7 +3026,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -d ./langtest/ -b main -c someAksCluster -r localhost -g someResourceGroup --container-name testapp --deploy-type manifests --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type manifests -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -3205,7 +3205,7 @@ jobs: curl -m 3 $SERVICEIP:80 kill $tunnelPID - run: | - ./draft -b main -v generate-workflow -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type helm --build-context-path . + ./draft -v generate-workflow -d ./langtest/ --deploy-type helm -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false pwd # Validate generated workflow yaml - name: Install action-validator with asdf @@ -3339,7 +3339,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -b main -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type kustomize --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type kustomize -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -3464,7 +3464,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -d ./langtest/ -b main -c someAksCluster -r localhost -g someResourceGroup --container-name testapp --deploy-type manifests --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type manifests -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -3643,7 +3643,7 @@ jobs: curl -m 3 $SERVICEIP:80 kill $tunnelPID - run: | - ./draft -b main -v generate-workflow -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type helm --build-context-path . + ./draft -v generate-workflow -d ./langtest/ --deploy-type helm -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false pwd # Validate generated workflow yaml - name: Install action-validator with asdf @@ -3777,7 +3777,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -b main -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type kustomize --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type kustomize -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -3902,7 +3902,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -d ./langtest/ -b main -c someAksCluster -r localhost -g someResourceGroup --container-name testapp --deploy-type manifests --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type manifests -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -4081,7 +4081,7 @@ jobs: curl -m 3 $SERVICEIP:80 kill $tunnelPID - run: | - ./draft -b main -v generate-workflow -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type helm --build-context-path . + ./draft -v generate-workflow -d ./langtest/ --deploy-type helm -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false pwd # Validate generated workflow yaml - name: Install action-validator with asdf @@ -4215,7 +4215,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -b main -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type kustomize --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type kustomize -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -4340,7 +4340,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -d ./langtest/ -b main -c someAksCluster -r localhost -g someResourceGroup --container-name testapp --deploy-type manifests --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type manifests -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -4519,7 +4519,7 @@ jobs: curl -m 3 $SERVICEIP:80 kill $tunnelPID - run: | - ./draft -b main -v generate-workflow -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type helm --build-context-path . + ./draft -v generate-workflow -d ./langtest/ --deploy-type helm -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false pwd # Validate generated workflow yaml - name: Install action-validator with asdf @@ -4653,7 +4653,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -b main -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type kustomize --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type kustomize -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -4778,7 +4778,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -d ./langtest/ -b main -c someAksCluster -r localhost -g someResourceGroup --container-name testapp --deploy-type manifests --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type manifests -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -4957,7 +4957,7 @@ jobs: curl -m 3 $SERVICEIP:80 kill $tunnelPID - run: | - ./draft -b main -v generate-workflow -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type helm --build-context-path . + ./draft -v generate-workflow -d ./langtest/ --deploy-type helm -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false pwd # Validate generated workflow yaml - name: Install action-validator with asdf @@ -5091,7 +5091,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -b main -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type kustomize --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type kustomize -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -5216,7 +5216,7 @@ jobs: echo 'Curling service IP' curl -m 3 $SERVICEIP:80 kill $tunnelPID - - run: ./draft -v generate-workflow -d ./langtest/ -b main -c someAksCluster -r localhost -g someResourceGroup --container-name testapp --deploy-type manifests --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type manifests -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 diff --git a/cmd/create.go b/cmd/create.go index b0bfd1d0..4f57204f 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -292,7 +292,7 @@ func (cc *createCmd) generateDockerfile(langConfig *config.DraftConfig, lowerLan return err } } else { - inputs, err = validateConfigInputsToPrompts(langConfig.Variables, cc.createConfig.LanguageVariables) + inputs, err = validateConfigInputsToPrompts(langConfig, cc.createConfig.LanguageVariables) if err != nil { return err } @@ -330,7 +330,7 @@ func (cc *createCmd) createDeployment() error { if deployConfig == nil { return errors.New("invalid deployment type") } - customInputs, err = validateConfigInputsToPrompts(deployConfig.Variables, cc.createConfig.DeployVariables) + customInputs, err = validateConfigInputsToPrompts(deployConfig, cc.createConfig.DeployVariables) if err != nil { return err } @@ -464,7 +464,7 @@ func init() { rootCmd.AddCommand(newCreateCmd()) } -func validateConfigInputsToPrompts(required []config.BuilderVar, provided []UserInputs) (map[string]string, error) { +func validateConfigInputsToPrompts(draftConfig *config.DraftConfig, provided []UserInputs) (map[string]string, error) { customInputs := make(map[string]string) // set inputs to provided values @@ -472,23 +472,11 @@ func validateConfigInputsToPrompts(required []config.BuilderVar, provided []User customInputs[variable.Name] = variable.Value } - // fill in missing vars using variable default references - for _, variable := range required { - if customInputs[variable.Name] == "" && variable.Default.ReferenceVar != "" { - log.Debugf("variable %s is empty, using default referenceVar value from %s", variable.Name, variable.Default.ReferenceVar) - customInputs[variable.Name] = customInputs[variable.Default.ReferenceVar] - } - } - - // fill in missing vars using variable default values - for _, variable := range required { - if customInputs[variable.Name] == "" && variable.Default.Value != "" { - log.Debugf("variable %s is empty, using default value %s", variable.Name, variable.Default.Value) - customInputs[variable.Name] = variable.Default.Value - } + if err := draftConfig.ApplyDefaultVariables(customInputs); err != nil { + return nil, fmt.Errorf("validate config inputs to prompts: %w", err) } - for _, variable := range required { + for _, variable := range draftConfig.Variables { value, ok := customInputs[variable.Name] if !ok { return nil, fmt.Errorf("config missing required variable: %s with description: %s", variable.Name, variable.Description) diff --git a/cmd/create_test.go b/cmd/create_test.go index bfcff610..5bdcd4e0 100644 --- a/cmd/create_test.go +++ b/cmd/create_test.go @@ -142,14 +142,16 @@ func TestInitConfig(t *testing.T) { } func TestValidateConfigInputsToPromptsPass(t *testing.T) { - required := []config.BuilderVar{ - { - Name: "REQUIRED_PROVIDED", - }, - { - Name: "REQUIRED_DEFAULTED", - Default: config.BuilderVarDefault{ - Value: "DEFAULT_VALUE", + required := config.DraftConfig{ + Variables: []config.BuilderVar{ + { + Name: "REQUIRED_PROVIDED", + }, + { + Name: "REQUIRED_DEFAULTED", + Default: config.BuilderVarDefault{ + Value: "DEFAULT_VALUE", + }, }, }, } @@ -157,25 +159,27 @@ func TestValidateConfigInputsToPromptsPass(t *testing.T) { {Name: "REQUIRED_PROVIDED", Value: "PROVIDED_VALUE"}, } - vars, err := validateConfigInputsToPrompts(required, provided) + vars, err := validateConfigInputsToPrompts(&required, provided) assert.True(t, err == nil) assert.Equal(t, vars["REQUIRED_DEFAULTED"], "DEFAULT_VALUE") } func TestValidateConfigInputsToPromptsMissing(t *testing.T) { - required := []config.BuilderVar{ - { - Name: "REQUIRED_PROVIDED", - }, - { - Name: "REQUIRED_MISSING", + required := config.DraftConfig{ + Variables: []config.BuilderVar{ + { + Name: "REQUIRED_PROVIDED", + }, + { + Name: "REQUIRED_MISSING", + }, }, } provided := []UserInputs{ {Name: "REQUIRED_PROVIDED"}, } - _, err := validateConfigInputsToPrompts(required, provided) + _, err := validateConfigInputsToPrompts(&required, provided) assert.NotNil(t, err) } diff --git a/cmd/generate-workflow.go b/cmd/generate-workflow.go index 22c75f07..0e73a5f2 100644 --- a/cmd/generate-workflow.go +++ b/cmd/generate-workflow.go @@ -52,15 +52,20 @@ with draft on AKS. This command assumes the 'setup-gh' command has been run prop } f := cmd.Flags() - f.StringVarP(&gwCmd.workflowConfig.AksClusterName, "cluster-name", "c", emptyDefaultFlagValue, "specify the AKS cluster name") - f.StringVarP(&gwCmd.workflowConfig.AcrName, "registry-name", "r", emptyDefaultFlagValue, "specify the Azure container registry name") - f.StringVar(&gwCmd.workflowConfig.ContainerName, "container-name", emptyDefaultFlagValue, "specify the container image name") - f.StringVarP(&gwCmd.workflowConfig.ResourceGroupName, "resource-group", "g", emptyDefaultFlagValue, "specify the Azure resource group of your AKS cluster") f.StringVarP(&gwCmd.dest, "destination", "d", currentDirDefaultFlagValue, "specify the path to the project directory") - f.StringVarP(&gwCmd.workflowConfig.BranchName, "branch", "b", emptyDefaultFlagValue, "specify the Github branch to automatically deploy from") f.StringVar(&gwCmd.deployType, "deploy-type", emptyDefaultFlagValue, "specify the type of deployment") - f.StringArrayVarP(&gwCmd.flagVariables, "variable", "", []string{}, "pass additional variables") + f.StringVarP(&gwCmd.workflowConfig.WorkflowName, "workflow", "w", emptyDefaultFlagValue, "specify the Github workflow name") + f.StringVarP(&gwCmd.workflowConfig.BranchName, "branch", "b", emptyDefaultFlagValue, "specify the Github branch to automatically deploy from") + f.StringVar(&gwCmd.workflowConfig.AcrResourceGroup, "acr-resource-group", emptyDefaultFlagValue, "specify the Azure container registry resource group") + f.StringVarP(&gwCmd.workflowConfig.AcrName, "registry-name", "r", emptyDefaultFlagValue, "specify the Azure container registry name") + f.StringVar(&gwCmd.workflowConfig.ContainerName, "container-name", emptyDefaultFlagValue, "specify the container image name") + f.StringVarP(&gwCmd.workflowConfig.ClusterResourceGroup, "cluster-resource-group", "g", emptyDefaultFlagValue, "specify the Azure resource group of your AKS cluster") + f.StringVarP(&gwCmd.workflowConfig.ClusterName, "cluster-name", "c", emptyDefaultFlagValue, "specify the AKS cluster name") + f.StringVar(&gwCmd.workflowConfig.Dockerfile, "dockerfile", emptyDefaultFlagValue, "specify the path to the Dockerfile") f.StringVarP(&gwCmd.workflowConfig.BuildContextPath, "build-context-path", "x", emptyDefaultFlagValue, "specify the docker build context path") + f.StringVarP(&gwCmd.workflowConfig.Namespace, "namespace", "n", emptyDefaultFlagValue, "specify the Kubernetes namespace") + f.StringVar(&gwCmd.workflowConfig.PrivateCluster, "private-cluster", emptyDefaultFlagValue, "specify if the AKS cluster is private") + f.StringArrayVarP(&gwCmd.flagVariables, "variable", "", []string{}, "pass additional variables") gwCmd.templateWriter = &writers.LocalFSWriter{} return cmd } @@ -109,4 +114,4 @@ func (gwc *generateWorkflowCmd) generateWorkflows(dest string, deployType string maps.Copy(customInputs, flagValuesMap) return workflow.CreateWorkflowFiles(deployType, customInputs, templateWriter) -} \ No newline at end of file +} diff --git a/pkg/config/draftconfig.go b/pkg/config/draftconfig.go index 9950e6b0..6d6a6eb2 100644 --- a/pkg/config/draftconfig.go +++ b/pkg/config/draftconfig.go @@ -2,6 +2,7 @@ package config import ( "errors" + "fmt" log "github.com/sirupsen/logrus" ) @@ -26,6 +27,7 @@ type BuilderVar struct { Description string `yaml:"description"` ExampleValues []string `yaml:"exampleValues"` Type string `yaml:"type"` + Value string `yaml:"value"` } type BuilderVarDefault struct { @@ -67,21 +69,50 @@ func (d *DraftConfig) GetNameOverride(path string) string { } // ApplyDefaultVariables will apply the defaults to variables that are not already set -func (d *DraftConfig) ApplyDefaultVariables(customConfig map[string]string) error { +func (d *DraftConfig) ApplyDefaultVariables(customInputs map[string]string) error { + varIdxMap := VariableIdxMap(d.Variables) + for _, variable := range d.Variables { // handle where variable is not set or is set to an empty string from cli handling - if val, ok := customConfig[variable.Name]; !ok || val == "" { - if variable.Default.Value == "" { - return errors.New("variable " + variable.Name + " has no default value") + if customInputs[variable.Name] == "" { + if variable.Default.ReferenceVar != "" { + defaultVal, err := recurseReferenceVars(d.Variables, d.Variables[varIdxMap[variable.Default.ReferenceVar]], customInputs, varIdxMap, d.Variables[varIdxMap[variable.Default.ReferenceVar]], true) + if err != nil { + return fmt.Errorf("apply default variables: %w", err) + } + log.Infof("Variable %s defaulting to value %s", variable.Name, customInputs[variable.Name]) + customInputs[variable.Name] = defaultVal + } + + if customInputs[variable.Name] == "" { + if variable.Default.Value != "" { + log.Infof("Variable %s defaulting to value %s", variable.Name, variable.Default.Value) + customInputs[variable.Name] = variable.Default.Value + } else { + return fmt.Errorf("variable %s has no default value", variable.Name) + } } - log.Infof("Variable %s defaulting to value %s", variable.Name, variable.Default.Value) - customConfig[variable.Name] = variable.Default.Value } } return nil } +// recurseReferenceVars recursively checks each variable's ReferenceVar if it doesn't have a custom input. If there's no more ReferenceVars, it will return the default value of the last ReferenceVar. +func recurseReferenceVars(variables []BuilderVar, variable BuilderVar, customInputs map[string]string, varIdxMap map[string]int, variableCheck BuilderVar, isFirst bool) (string, error) { + if !isFirst && variable.Name == variableCheck.Name { + return "", errors.New("cyclical reference detected") + } + + if customInputs[variable.Name] != "" { + return customInputs[variable.Name], nil + } else if variable.Default.ReferenceVar != "" { + return recurseReferenceVars(variables, variables[varIdxMap[variable.Default.ReferenceVar]], customInputs, varIdxMap, variableCheck, false) + } + + return variable.Default.Value, nil +} + func VariableIdxMap(variables []BuilderVar) map[string]int { varIdxMap := make(map[string]int) @@ -92,6 +123,31 @@ func VariableIdxMap(variables []BuilderVar) map[string]int { return varIdxMap } +func (d *DraftConfig) VariableMap() (map[string]string, error) { + envArgs := make(map[string]string) + + for _, variable := range d.Variables { + envArgs[variable.Name] = variable.Value + } + + err := d.ApplyDefaultVariables(envArgs) + if err != nil { + return nil, fmt.Errorf("creating variable map: %w", err) + } + + return envArgs, nil +} + +func (d *DraftConfig) VariableIdxMap() map[string]int { + varIdxMap := make(map[string]int) + + for i, variable := range d.Variables { + varIdxMap[variable.Name] = i + } + + return varIdxMap +} + // TemplateVariableRecorder is an interface for recording variables that are used read using draft configs type TemplateVariableRecorder interface { Record(key, value string) diff --git a/pkg/config/draftconfig_test.go b/pkg/config/draftconfig_test.go new file mode 100644 index 00000000..20bd1f2a --- /dev/null +++ b/pkg/config/draftconfig_test.go @@ -0,0 +1,204 @@ +package config + +import ( + "testing" +) + +func TestApplyDefaultVariables(t *testing.T) { + tests := []struct { + testName string + draftConfig DraftConfig + customInputs map[string]string + want map[string]string + wantErrMsg string + }{ + { + testName: "keepAllCustomInputs", + draftConfig: DraftConfig{ + Variables: []BuilderVar{ + { + Name: "var1", + Default: BuilderVarDefault{ + Value: "default-value-1", + }, + }, + { + Name: "var2", + Default: BuilderVarDefault{ + Value: "default-value-2", + }, + }, + }, + }, + customInputs: map[string]string{ + "var1": "custom-value-1", + "var2": "custom-value-2", + }, + want: map[string]string{ + "var1": "custom-value-1", + "var2": "custom-value-2", + }, + }, + { + testName: "applyDefaultToEmptyCustomInputs", + draftConfig: DraftConfig{ + Variables: []BuilderVar{ + { + Name: "var1", + Default: BuilderVarDefault{ + Value: "default-value-1", + }, + }, + { + Name: "var2", + Default: BuilderVarDefault{ + Value: "default-value-2", + }, + }, + }, + }, + customInputs: map[string]string{}, + want: map[string]string{ + "var1": "default-value-1", + "var2": "default-value-2", + }, + }, + { + testName: "applyDefaultToPartialCustomInputs", + draftConfig: DraftConfig{ + Variables: []BuilderVar{ + { + Name: "var1", + Default: BuilderVarDefault{ + Value: "default-value-1", + }, + }, + { + Name: "var2", + Default: BuilderVarDefault{ + Value: "default-value-2", + }, + }, + }, + }, + customInputs: map[string]string{ + "var1": "custom-value-1", + }, + want: map[string]string{ + "var1": "custom-value-1", + "var2": "default-value-2", + }, + }, + { + testName: "variablesHaveNoInputOrDefault", + draftConfig: DraftConfig{ + Variables: []BuilderVar{ + { + Name: "var1", + }, + { + Name: "var2", + }, + }, + }, + customInputs: map[string]string{}, + want: map[string]string{}, + wantErrMsg: "variable var1 has no default value", + }, + { + testName: "getDefaultFromReferenceVarCustomInputs", + draftConfig: DraftConfig{ + Variables: []BuilderVar{ + { + Name: "var1", + Default: BuilderVarDefault{ + ReferenceVar: "var2", + Value: "not-this-value", + }, + }, + { + Name: "var2", + Default: BuilderVarDefault{ + Value: "not-this-value", + }, + }, + }, + }, + customInputs: map[string]string{ + "var2": "this-value", + }, + want: map[string]string{ + "var1": "this-value", + "var2": "this-value", + }, + }, + { + testName: "getDefaultFromReferenceVar", + draftConfig: DraftConfig{ + Variables: []BuilderVar{ + { + Name: "var1", + Default: BuilderVarDefault{ + ReferenceVar: "var2", + Value: "not-this-value", + }, + }, + { + Name: "var2", + Default: BuilderVarDefault{ + ReferenceVar: "var3", + Value: "not-this-value", + }, + }, + { + Name: "var3", + Default: BuilderVarDefault{ + Value: "default-value-3", + }, + }, + }, + }, + customInputs: map[string]string{}, + want: map[string]string{ + "var1": "default-value-3", + "var2": "default-value-3", + "var3": "default-value-3", + }, + }, + { + testName: "cyclicalReferenceVarsDetected", + draftConfig: DraftConfig{ + Variables: []BuilderVar{ + { + Name: "var1", + Default: BuilderVarDefault{ + ReferenceVar: "var2", + }, + }, + { + Name: "var2", + Default: BuilderVarDefault{ + ReferenceVar: "var1", + }, + }, + }, + }, + customInputs: map[string]string{}, + want: map[string]string{}, + wantErrMsg: "apply default variables: cyclical reference detected", + }, + } + for _, tt := range tests { + t.Run(tt.testName, func(t *testing.T) { + if err := tt.draftConfig.ApplyDefaultVariables(tt.customInputs); err != nil && err.Error() != tt.wantErrMsg { + t.Error(err) + } else { + for k, v := range tt.want { + if tt.customInputs[k] != v { + t.Errorf("got: %s, want: %s", tt.customInputs[k], v) + } + } + } + }) + } +} diff --git a/pkg/osutil/osutil.go b/pkg/osutil/osutil.go index eab99aea..7e7ea8d4 100644 --- a/pkg/osutil/osutil.go +++ b/pkg/osutil/osutil.go @@ -107,12 +107,12 @@ func CopyDir( return err } } else { - fileContent, err := replaceTemplateVariables(fileSys, srcPath, customInputs) + fileContent, err := ReplaceTemplateVariables(fileSys, srcPath, customInputs) if err != nil { return err } - if err = checkAllVariablesSubstituted(string(fileContent)); err != nil { + if err = CheckAllVariablesSubstituted(string(fileContent)); err != nil { return fmt.Errorf("error substituting file %s: %w", srcPath, err) } @@ -131,7 +131,7 @@ If any draft variables are found, an error is returned. Draft variables are defined as a string of non-whitespace characters starting with a non-period character wrapped in double curly braces. The non-period first character constraint is used to avoid matching helm template functions. */ -func checkAllVariablesSubstituted(fileContent string) error { +func CheckAllVariablesSubstituted(fileContent string) error { if unsubstitutedVars := draftVariableRegex.FindAllString(fileContent, -1); len(unsubstitutedVars) > 0 { unsubstitutedVarsString := strings.Join(unsubstitutedVars, ", ") return fmt.Errorf("unsubstituted variable: %s", unsubstitutedVarsString) @@ -139,7 +139,7 @@ func checkAllVariablesSubstituted(fileContent string) error { return nil } -func replaceTemplateVariables(fileSys fs.FS, srcPath string, customInputs map[string]string) ([]byte, error) { +func ReplaceTemplateVariables(fileSys fs.FS, srcPath string, customInputs map[string]string) ([]byte, error) { file, err := fs.ReadFile(fileSys, srcPath) if err != nil { return nil, err diff --git a/pkg/osutil/osutil_test.go b/pkg/osutil/osutil_test.go index ed108062..8536a77a 100644 --- a/pkg/osutil/osutil_test.go +++ b/pkg/osutil/osutil_test.go @@ -110,7 +110,7 @@ func TestAllVariablesSubstituted(t *testing.T) { for _, test := range tests { t.Run(test.String, func(t *testing.T) { - err := checkAllVariablesSubstituted(test.String) + err := CheckAllVariablesSubstituted(test.String) didError := err != nil assert.Equal(t, test.ExpectError, didError) }) diff --git a/pkg/prompts/prompts.go b/pkg/prompts/prompts.go index cc8bdf15..d8d47057 100644 --- a/pkg/prompts/prompts.go +++ b/pkg/prompts/prompts.go @@ -20,18 +20,18 @@ const defaultAppName = "my-app" // Function to get current directory name var getCurrentDirNameFunc = getCurrentDirName -func RunPromptsFromConfig(config *config.DraftConfig) (map[string]string, error) { - return RunPromptsFromConfigWithSkips(config, []string{}) +func RunPromptsFromConfig(draftConfig *config.DraftConfig) (map[string]string, error) { + return RunPromptsFromConfigWithSkips(draftConfig, []string{}) } -func RunPromptsFromConfigWithSkips(config *config.DraftConfig, varsToSkip []string) (map[string]string, error) { - return RunPromptsFromConfigWithSkipsIO(config, varsToSkip, nil, nil) +func RunPromptsFromConfigWithSkips(draftConfig *config.DraftConfig, varsToSkip []string) (map[string]string, error) { + return RunPromptsFromConfigWithSkipsIO(draftConfig, varsToSkip, nil, nil) } -// RunPromptsFromConfigWithSkipsIO runs the prompts for the given config +// RunPromptsFromConfigWithSkipsIO runs the prompts for the given draftConfig // skipping any variables in varsToSkip or where the BuilderVar.IsPromptDisabled is true. // If Stdin or Stdout are nil, the default values will be used. -func RunPromptsFromConfigWithSkipsIO(config *config.DraftConfig, varsToSkip []string, Stdin io.ReadCloser, Stdout io.WriteCloser) (map[string]string, error) { +func RunPromptsFromConfigWithSkipsIO(draftConfig *config.DraftConfig, varsToSkip []string, Stdin io.ReadCloser, Stdout io.WriteCloser) (map[string]string, error) { skipMap := make(map[string]interface{}) for _, v := range varsToSkip { skipMap[v] = interface{}(nil) @@ -39,7 +39,7 @@ func RunPromptsFromConfigWithSkipsIO(config *config.DraftConfig, varsToSkip []st inputs := make(map[string]string) - for _, variable := range config.Variables { + for _, variable := range draftConfig.Variables { if val, ok := skipMap[variable.Name]; ok && val != "" { log.Debugf("Skipping prompt for %s", variable.Name) continue diff --git a/pkg/workflows/workflowconfig.go b/pkg/workflows/workflowconfig.go index 0752b941..5aace52e 100644 --- a/pkg/workflows/workflowconfig.go +++ b/pkg/workflows/workflowconfig.go @@ -1,16 +1,33 @@ package workflows type WorkflowConfig struct { - AcrName string - ContainerName string - ResourceGroupName string - AksClusterName string - BranchName string - BuildContextPath string + WorkflowName string + BranchName string + AcrResourceGroup string + AcrName string + ContainerName string + ClusterResourceGroup string + ClusterName string + Dockerfile string + BuildContextPath string + Namespace string + PrivateCluster string } func (config *WorkflowConfig) SetFlagValuesToMap() map[string]string { flagValuesMap := make(map[string]string) + if config.WorkflowName != "" { + flagValuesMap["WORKFLOWNAME"] = config.WorkflowName + } + + if config.BranchName != "" { + flagValuesMap["BRANCHNAME"] = config.BranchName + } + + if config.AcrResourceGroup != "" { + flagValuesMap["ACRRESOURCEGROUP"] = config.AcrResourceGroup + } + if config.AcrName != "" { flagValuesMap["AZURECONTAINERREGISTRY"] = config.AcrName } @@ -19,21 +36,29 @@ func (config *WorkflowConfig) SetFlagValuesToMap() map[string]string { flagValuesMap["CONTAINERNAME"] = config.ContainerName } - if config.ResourceGroupName != "" { - flagValuesMap["RESOURCEGROUP"] = config.ResourceGroupName + if config.ClusterResourceGroup != "" { + flagValuesMap["CLUSTERRESOURCEGROUP"] = config.ClusterResourceGroup } - if config.AksClusterName != "" { - flagValuesMap["CLUSTERNAME"] = config.AksClusterName + if config.ClusterName != "" { + flagValuesMap["CLUSTERNAME"] = config.ClusterName } - if config.BranchName != "" { - flagValuesMap["BRANCHNAME"] = config.BranchName + if config.Dockerfile != "" { + flagValuesMap["DOCKERFILE"] = config.Dockerfile } if config.BuildContextPath != "" { flagValuesMap["BUILDCONTEXTPATH"] = config.BuildContextPath } + if config.Namespace != "" { + flagValuesMap["NAMESPACE"] = config.Namespace + } + + if config.PrivateCluster != "" { + flagValuesMap["PRIVATECLUSTER"] = config.PrivateCluster + } + return flagValuesMap } diff --git a/pkg/workflows/workflows_test.go b/pkg/workflows/workflows_test.go index 4da6eae1..621d55c9 100644 --- a/pkg/workflows/workflows_test.go +++ b/pkg/workflows/workflows_test.go @@ -25,8 +25,8 @@ func TestCreateWorkflows(t *testing.T) { dest := "." deployType := "helm" templatewriter := &writers.LocalFSWriter{} - flagValuesMap := map[string]string{"AZURECONTAINERREGISTRY": "testAcr", "CONTAINERNAME": "testContainer", "RESOURCEGROUP": "testRG", "CLUSTERNAME": "testCluster", "BRANCHNAME": "testBranch", "BUILDCONTEXTPATH": "."} - flagValuesMapNoRoot := map[string]string{"AZURECONTAINERREGISTRY": "testAcr", "CONTAINERNAME": "testContainer", "RESOURCEGROUP": "testRG", "CLUSTERNAME": "testCluster", "BRANCHNAME": "testBranch", "BUILDCONTEXTPATH": "test"} + flagValuesMap := map[string]string{"WORKFLOWNAME": "testWorkflow", "BRANCHNAME": "testBranch", "ACRRESOURCEGROUP": "testAcrRG", "AZURECONTAINERREGISTRY": "testAcr", "CONTAINERNAME": "testContainer", "CLUSTERRESOURCEGROUP": "testClusterRG", "CLUSTERNAME": "testCluster", "DOCKERFILE": "./Dockerfile", "BUILDCONTEXTPATH": ".", "NAMESPACE": "default", "PRIVATECLUSTER": "false"} + flagValuesMapNoRoot := map[string]string{"WORKFLOWNAME": "testWorkflow", "BRANCHNAME": "testBranch", "ACRRESOURCEGROUP": "testAcrRG", "AZURECONTAINERREGISTRY": "testAcr", "CONTAINERNAME": "testContainer", "CLUSTERRESOURCEGROUP": "testClusterRG", "CLUSTERNAME": "testCluster", "DOCKERFILE": "./Dockerfile", "BUILDCONTEXTPATH": "test", "NAMESPACE": "default", "PRIVATECLUSTER": "false"} tests := []struct { name string @@ -63,7 +63,8 @@ func TestCreateWorkflows(t *testing.T) { os.Remove(".overlays") os.Remove(".github") }, - }, { + }, + { name: "manifests", deployType: "manifests", flagValues: flagValuesMap, @@ -236,8 +237,8 @@ func TestPopulateConfigs(t *testing.T) { func TestCreateWorkflowFiles(t *testing.T) { templatewriter := &writers.LocalFSWriter{} - customInputs := map[string]string{"AZURECONTAINERREGISTRY": "testAcr", "CONTAINERNAME": "testContainer", "RESOURCEGROUP": "testRG", "CLUSTERNAME": "testCluster", "BRANCHNAME": "testBranch", "CHARTPATH": "testPath", "CHARTOVERRIDEPATH": "testOverridePath", "BUILDCONTEXTPATH": "."} - customInputsNoRoot := map[string]string{"AZURECONTAINERREGISTRY": "testAcr", "CONTAINERNAME": "testContainer", "RESOURCEGROUP": "testRG", "CLUSTERNAME": "testCluster", "BRANCHNAME": "testBranch", "CHARTPATH": "testPath", "CHARTOVERRIDEPATH": "testOverridePath", "BUILDCONTEXTPATH": "test"} + customInputs := map[string]string{"WORKFLOWNAME": "testWorkflow", "BRANCHNAME": "testBranch", "ACRRESOURCEGROUP": "testAcrRG", "AZURECONTAINERREGISTRY": "testAcr", "CONTAINERNAME": "testContainer", "CLUSTERRESOURCEGROUP": "testClusterRG", "CLUSTERNAME": "testCluster", "DOCKERFILE": "./Dockerfile", "BUILDCONTEXTPATH": ".", "CHARTPATH": "testPath", "CHARTOVERRIDEPATH": "testOverridePath", "CHARTOVERRIDES": "replicas:2", "NAMESPACE": "default", "PRIVATECLUSTER": "false"} + customInputsNoRoot := map[string]string{"WORKFLOWNAME": "testWorkflow", "BRANCHNAME": "testBranch", "ACRRESOURCEGROUP": "testAcrRG", "AZURECONTAINERREGISTRY": "testAcr", "CONTAINERNAME": "testContainer", "CLUSTERRESOURCEGROUP": "testClusterRG", "CLUSTERNAME": "testCluster", "DOCKERFILE": "./Dockerfile", "BUILDCONTEXTPATH": ".", "CHARTPATH": "testPath", "CHARTOVERRIDEPATH": "testOverridePath", "CHARTOVERRIDES": "replicas:2", "NAMESPACE": "default", "PRIVATECLUSTER": "false"} badInputs := map[string]string{} workflowTemplate, err := createMockWorkflowTemplatesFS() diff --git a/template/workflows/helm/.github/workflows/azure-kubernetes-service-helm.yml b/template/workflows/helm/.github/workflows/azure-kubernetes-service-helm.yml index 8b1cf1f8..5952ff4c 100644 --- a/template/workflows/helm/.github/workflows/azure-kubernetes-service-helm.yml +++ b/template/workflows/helm/.github/workflows/azure-kubernetes-service-helm.yml @@ -32,7 +32,7 @@ # For more samples to get started with GitHub Action workflows to deploy to Azure, refer to https://github.com/Azure/actions-workflow-samples # For more options with the actions used below please refer to https://github.com/Azure/login -name: Build and deploy an app to AKS with Helm +name: {{WORKFLOWNAME}} on: push: @@ -40,13 +40,18 @@ on: workflow_dispatch: env: - RESOURCE_GROUP: {{RESOURCEGROUP}} + ACR_RESOURCE_GROUP: {{ACRRESOURCEGROUP}} AZURE_CONTAINER_REGISTRY: {{AZURECONTAINERREGISTRY}} CONTAINER_NAME: {{CONTAINERNAME}} + CLUSTER_RESOURCE_GROUP: {{CLUSTERRESOURCEGROUP}} CLUSTER_NAME: {{CLUSTERNAME}} + DOCKER_FILE: {{DOCKERFILE}} BUILD_CONTEXT_PATH: {{BUILDCONTEXTPATH}} CHART_PATH: {{CHARTPATH}} CHART_OVERRIDE_PATH: {{CHARTOVERRIDEPATH}} + CHART_OVERRIDES: {{CHARTOVERRIDES}} + NAMESPACE: {{NAMESPACE}} + PRIVATE_CLUSTER: {{PRIVATECLUSTER}} jobs: buildImage: @@ -69,7 +74,7 @@ jobs: # Builds and pushes an image up to your Azure Container Registry - name: Build and push image to ACR run: | - az acr build --image ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_NAME }}:${{ github.sha }} --registry ${{ env.AZURE_CONTAINER_REGISTRY }} -g ${{ env.RESOURCE_GROUP }} . + az acr build --image ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_NAME }}:${{ github.sha }} --registry ${{ env.AZURE_CONTAINER_REGISTRY }} -g ${{ env.ACR_RESOURCE_GROUP }} -f ${{ env.DOCKER_FILE }} ${{ env.BUILD_CONTEXT_PATH }} deploy: permissions: actions: read @@ -99,7 +104,7 @@ jobs: - name: Get K8s context uses: azure/aks-set-context@v3 with: - resource-group: ${{ env.RESOURCE_GROUP }} + resource-group: ${{ env.CLUSTER_RESOURCE_GROUP }} cluster-name: ${{ env.CLUSTER_NAME }} admin: 'false' use-kubelogin: 'true' @@ -111,8 +116,7 @@ jobs: renderEngine: "helm" helmChart: ${{ env.CHART_PATH }} overrideFiles: ${{ env.CHART_OVERRIDE_PATH }} - overrides: | - replicas:2 + overrides: ${{ env.CHART_OVERRIDES }} helm-version: "latest" id: bake @@ -123,4 +127,6 @@ jobs: action: deploy manifests: ${{ steps.bake.outputs.manifestsBundle }} images: | - ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_NAME }}:${{ github.sha }} \ No newline at end of file + ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_NAME }}:${{ github.sha }} + namespace: ${{ env.NAMESPACE }} + private-cluster: ${{ env.PRIVATE_CLUSTER }} diff --git a/template/workflows/helm/draft.yaml b/template/workflows/helm/draft.yaml index 259275fd..26c99b89 100644 --- a/template/workflows/helm/draft.yaml +++ b/template/workflows/helm/draft.yaml @@ -1,14 +1,24 @@ variables: + - name: "WORKFLOWNAME" + default: + value: "Build and deploy an app to AKS with Helm" + description: "the name of the workflow" - name: "BRANCHNAME" description: "the Github branch to automatically deploy from" - - name: "RESOURCEGROUP" + - name: "ACRRESOURCEGROUP" description: "the ACR resource group" - name: "AZURECONTAINERREGISTRY" description: "the Azure container registry name" - name: "CONTAINERNAME" description: "the container image name" + - name: "CLUSTERRESOURCEGROUP" + description: "the AKS cluster resource group" - name: "CLUSTERNAME" description: "the AKS cluster name" + - name: "DOCKERFILE" + default: + value: "./Dockerfile" + description: "the path to the Dockerfile" - name: "BUILDCONTEXTPATH" default: value: "." @@ -23,4 +33,18 @@ variables: disablePrompt: true value: "./charts/production.yaml" description: "the path to the Helm chart override file" + - name: "CHARTOVERRIDES" + default: + disablePrompt: true + value: "replicas:2" + description: "the Helm chart overrides" + - name: "NAMESPACE" + default: + value: "default" + description: "the Kubernetes namespace" + - name: "PRIVATECLUSTER" + default: + value: "false" + description: "true if the AKS cluster is private" + type: "bool" \ No newline at end of file diff --git a/template/workflows/kustomize/.github/workflows/azure-kubernetes-service-kustomize.yml b/template/workflows/kustomize/.github/workflows/azure-kubernetes-service-kustomize.yml index 8b49876e..60fbe3e9 100644 --- a/template/workflows/kustomize/.github/workflows/azure-kubernetes-service-kustomize.yml +++ b/template/workflows/kustomize/.github/workflows/azure-kubernetes-service-kustomize.yml @@ -31,7 +31,7 @@ # For more samples to get started with GitHub Action workflows to deploy to Azure, refer to https://github.com/Azure/actions-workflow-samples # For more options with the actions used below please refer to https://github.com/Azure/login -name: Build and deploy an app to AKS with Kustomize +name: {{WORKFLOWNAME}} on: push: @@ -39,12 +39,16 @@ on: workflow_dispatch: env: - RESOURCE_GROUP: {{RESOURCEGROUP}} + ACR_RESOURCE_GROUP: {{ACRRESOURCEGROUP}} AZURE_CONTAINER_REGISTRY: {{AZURECONTAINERREGISTRY}} CONTAINER_NAME: {{CONTAINERNAME}} + CLUSTER_RESOURCE_GROUP: {{CLUSTERRESOURCEGROUP}} CLUSTER_NAME: {{CLUSTERNAME}} KUSTOMIZE_PATH: {{KUSTOMIZEPATH}} + DOCKER_FILE: {{DOCKERFILE}} BUILD_CONTEXT_PATH: {{BUILDCONTEXTPATH}} + NAMESPACE: {{NAMESPACE}} + PRIVATE_CLUSTER: {{PRIVATECLUSTER}} jobs: buildImage: @@ -67,7 +71,7 @@ jobs: # Builds and pushes an image up to your Azure Container Registry - name: Build and push image to ACR run: | - az acr build --image ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_NAME }}:${{ github.sha }} --registry ${{ env.AZURE_CONTAINER_REGISTRY }} -g ${{ env.RESOURCE_GROUP }} . + az acr build --image ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_NAME }}:${{ github.sha }} --registry ${{ env.AZURE_CONTAINER_REGISTRY }} -g ${{ env.ACR_RESOURCE_GROUP }} -f ${{ env.DOCKER_FILE }} ${{ env.BUILD_CONTEXT_PATH }} deploy: permissions: actions: read @@ -97,7 +101,7 @@ jobs: - name: Get K8s context uses: azure/aks-set-context@v3 with: - resource-group: ${{ env.RESOURCE_GROUP }} + resource-group: ${{ env.CLUSTER_RESOURCE_GROUP }} cluster-name: ${{ env.CLUSTER_NAME }} admin: 'false' use-kubelogin: 'true' @@ -118,4 +122,6 @@ jobs: action: deploy manifests: ${{ steps.bake.outputs.manifestsBundle }} images: | - ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_NAME }}:${{ github.sha }} \ No newline at end of file + ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_NAME }}:${{ github.sha }} + namespace: ${{ env.NAMESPACE }} + private-cluster: ${{ env.PRIVATE_CLUSTER }} diff --git a/template/workflows/kustomize/draft.yaml b/template/workflows/kustomize/draft.yaml index 01df153a..b0c8bc93 100644 --- a/template/workflows/kustomize/draft.yaml +++ b/template/workflows/kustomize/draft.yaml @@ -1,12 +1,18 @@ variables: + - name: "WORKFLOWNAME" + default: + value: "Build and deploy an app to AKS with Kustomize" + description: "the name of the workflow" - name: "BRANCHNAME" description: "the Github branch to automatically deploy from" - - name: "RESOURCEGROUP" + - name: "ACRRESOURCEGROUP" description: "the ACR resource group" - name: "AZURECONTAINERREGISTRY" description: "the Azure container registry name" - name: "CONTAINERNAME" description: "the container image name" + - name: "CLUSTERRESOURCEGROUP" + description: "the AKS cluster resource group" - name: "CLUSTERNAME" description: "the AKS cluster name" - name: "KUSTOMIZEPATH" @@ -14,7 +20,20 @@ variables: disablePrompt: true value: "./overlays/production" description: "the path to the Kustomize directory" + - name: "DOCKERFILE" + default: + value: "./Dockerfile" + description: "the path to the Dockerfile" - name: "BUILDCONTEXTPATH" default: value: "." - description: "the path to the Docker build context" \ No newline at end of file + description: "the path to the Docker build context" + - name: "NAMESPACE" + default: + value: "default" + description: "the Kubernetes namespace" + - name: "PRIVATECLUSTER" + default: + value: "false" + description: "true if the AKS cluster is private" + type: "bool" diff --git a/template/workflows/manifests/.github/workflows/azure-kubernetes-service.yml b/template/workflows/manifests/.github/workflows/azure-kubernetes-service.yml index ca1b83cc..9dc76c86 100644 --- a/template/workflows/manifests/.github/workflows/azure-kubernetes-service.yml +++ b/template/workflows/manifests/.github/workflows/azure-kubernetes-service.yml @@ -27,7 +27,7 @@ # For more samples to get started with GitHub Action workflows to deploy to Azure, refer to https://github.com/Azure/actions-workflow-samples # For more options with the actions used below please refer to https://github.com/Azure/login -name: Build and deploy an app to AKS +name: {{WORKFLOWNAME}} on: push: @@ -35,12 +35,16 @@ on: workflow_dispatch: env: - RESOURCE_GROUP: {{RESOURCEGROUP}} + ACR_RESOURCE_GROUP: {{ACRRESOURCEGROUP}} AZURE_CONTAINER_REGISTRY: {{AZURECONTAINERREGISTRY}} CONTAINER_NAME: {{CONTAINERNAME}} + CLUSTER_RESOURCE_GROUP: {{CLUSTERRESOURCEGROUP}} CLUSTER_NAME: {{CLUSTERNAME}} DEPLOYMENT_MANIFEST_PATH: {{DEPLOYMENTMANIFESTPATH}} + DOCKER_FILE: {{DOCKERFILE}} BUILD_CONTEXT_PATH: {{BUILDCONTEXTPATH}} + NAMESPACE: {{NAMESPACE}} + PRIVATE_CLUSTER: {{PRIVATECLUSTER}} jobs: buildImage: @@ -63,7 +67,7 @@ jobs: # Builds and pushes an image up to your Azure Container Registry - name: Build and push image to ACR run: | - az acr build --image ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_NAME }}:${{ github.sha }} --registry ${{ env.AZURE_CONTAINER_REGISTRY }} -g ${{ env.RESOURCE_GROUP }} . + az acr build --image ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_NAME }}:${{ github.sha }} --registry ${{ env.AZURE_CONTAINER_REGISTRY }} -g ${{ env.ACR_RESOURCE_GROUP }} -f ${{ env.DOCKER_FILE }} ${{ env.BUILD_CONTEXT_PATH }} deploy: permissions: actions: read @@ -93,7 +97,7 @@ jobs: - name: Get K8s context uses: azure/aks-set-context@v3 with: - resource-group: ${{ env.RESOURCE_GROUP }} + resource-group: ${{ env.CLUSTER_RESOURCE_GROUP }} cluster-name: ${{ env.CLUSTER_NAME }} admin: 'false' use-kubelogin: 'true' @@ -106,4 +110,6 @@ jobs: manifests: ${{ env.DEPLOYMENT_MANIFEST_PATH }} images: | ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_NAME }}:${{ github.sha }} + namespace: ${{ env.NAMESPACE }} + private-cluster: ${{ env.PRIVATE_CLUSTER }} \ No newline at end of file diff --git a/template/workflows/manifests/draft.yaml b/template/workflows/manifests/draft.yaml index beb109cd..e1edbdad 100644 --- a/template/workflows/manifests/draft.yaml +++ b/template/workflows/manifests/draft.yaml @@ -1,12 +1,18 @@ variables: + - name: "WORKFLOWNAME" + default: + value: "Build and deploy an app to AKS" + description: "the name of the workflow" - name: "BRANCHNAME" description: "the Github branch to automatically deploy from" - - name: "RESOURCEGROUP" + - name: "ACRRESOURCEGROUP" description: "the ACR resource group" - name: "AZURECONTAINERREGISTRY" description: "the Azure container registry name" - name: "CONTAINERNAME" description: "the container image name" + - name: "CLUSTERRESOURCEGROUP" + description: "the AKS cluster resource group" - name: "CLUSTERNAME" description: "the AKS cluster name" - name: "DEPLOYMENTMANIFESTPATH" @@ -14,7 +20,20 @@ variables: disablePrompt: true value: "./manifests" description: "the path to the Kubernetes deployment manifest" + - name: "DOCKERFILE" + default: + value: "./Dockerfile" + description: "the path to the Dockerfile" - name: "BUILDCONTEXTPATH" default: value: "." - description: "the path to the Docker build context" \ No newline at end of file + description: "the path to the Docker build context" + - name: "NAMESPACE" + default: + value: "default" + description: "the Kubernetes namespace" + - name: "PRIVATECLUSTER" + default: + value: "false" + description: "true if the AKS cluster is private" + type: "bool" diff --git a/test/gen_integration.sh b/test/gen_integration.sh index 722f5eb4..24ffb4f8 100755 --- a/test/gen_integration.sh +++ b/test/gen_integration.sh @@ -305,7 +305,7 @@ languageVariables: curl -m 3 \$SERVICEIP:$serviceport kill \$tunnelPID - run: | - ./draft -b main -v generate-workflow -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type helm --build-context-path . + ./draft -v generate-workflow -d ./langtest/ --deploy-type helm -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false pwd # Validate generated workflow yaml - name: Install action-validator with asdf @@ -455,7 +455,7 @@ languageVariables: echo 'Curling service IP' curl -m 3 \$SERVICEIP:$serviceport kill \$tunnelPID - - run: ./draft -v generate-workflow -b main -d ./langtest/ -c someAksCluster -r someRegistry -g someResourceGroup --container-name someContainer --deploy-type kustomize --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type kustomize -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1 @@ -596,7 +596,7 @@ languageVariables: echo 'Curling service IP' curl -m 3 \$SERVICEIP:$serviceport kill \$tunnelPID - - run: ./draft -v generate-workflow -d ./langtest/ -b main -c someAksCluster -r localhost -g someResourceGroup --container-name testapp --deploy-type manifests --build-context-path . + - run: ./draft -v generate-workflow -d ./langtest/ --deploy-type manifests -w someWorkflow -b main --acr-resource-group someAcrResourceGroup -r someRegistry --container-name someContainer -g someClusterResourceGroup -c someAksCluster --dockerfile ./Dockerfile --build-context-path . -n default --private-cluster false # Validate generated workflow yaml - name: Install action-validator with asdf uses: asdf-vm/actions/install@v1