From 12909ec2756aa04f77cad5a5bf3a112e0a3aa139 Mon Sep 17 00:00:00 2001 From: Timo Behrendt Date: Wed, 29 Apr 2026 17:16:51 +0200 Subject: [PATCH 1/8] ci(renovate): modernize config --- renovate.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/renovate.json b/renovate.json index 9e28a36..f275018 100644 --- a/renovate.json +++ b/renovate.json @@ -1,7 +1,4 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "local>t.behrendt/renovate-configs:common", - "local>t.behrendt/renovate-configs:action" - ] + "extends": ["local>t.behrendt/renovate-configs:action"] } -- 2.52.0 From d03c9283b1c1bc077c4c452c1901ba46e6da6a2e Mon Sep 17 00:00:00 2001 From: Timo Behrendt Date: Wed, 29 Apr 2026 17:17:11 +0200 Subject: [PATCH 2/8] remove custom branch and secrets, also rename some things --- .gitea/workflows/cd.yaml | 79 ++-------------------------------------- 1 file changed, 3 insertions(+), 76 deletions(-) diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/cd.yaml index 40c3ba2..0533e21 100644 --- a/.gitea/workflows/cd.yaml +++ b/.gitea/workflows/cd.yaml @@ -3,36 +3,21 @@ name: Deploy on: workflow_call: inputs: - # Optional: Override the default k8s directory path k8s_dir: - description: "Path to Kubernetes manifests directory" + description: "Override the default k8s directory path (k8s/)" required: false default: "k8s/" type: string - # Optional: Override the default helmfile path helmfile_path: - description: "Path to helmfile.yaml" + description: "Override the default helmfile path (hemfile.yaml)" required: false default: "helmfile.yaml" type: string - # Optional: Skip Helm deployment even if helmfile exists skip_helm_deployment: description: "Skip Helm deployment even if helmfile.yaml exists" required: false default: false type: boolean - # Optional: Custom secrets to create (JSON array of secret objects) - custom_secrets: - description: "JSON array of secrets to create. Each secret should have: name, type, data" - required: false - default: "[]" - type: string - # Optional: Branch to deploy from - deploy_branch: - description: "Branch to deploy from" - required: false - default: "main" - type: string jobs: detect-service-type: @@ -69,8 +54,6 @@ jobs: if: needs.detect-service-type.outputs.has_k8s == 'true' steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - ref: ${{ inputs.deploy_branch }} - uses: ./.gitea/actions/extract-namespace-from-repo-name id: namespace with: @@ -80,29 +63,6 @@ jobs: with: method: kubeconfig kubeconfig: ${{ secrets.KUBECONFIG }} - - name: Create custom secrets - id: create-secrets - run: | - # Parse custom secrets from input - SECRETS='${{ inputs.custom_secrets }}' - if [ "$SECRETS" != "[]" ]; then - echo "Creating custom secrets..." - echo "$SECRETS" | jq -c '.[]' | while read -r secret; do - SECRET_NAME=$(echo "$secret" | jq -r '.name') - SECRET_TYPE=$(echo "$secret" | jq -r '.type // "generic"') - SECRET_DATA=$(echo "$secret" | jq -r '.data') - - echo "Creating secret: $SECRET_NAME (type: $SECRET_TYPE)" - - # Create the secret using kubectl - echo "$SECRET_DATA" | kubectl create secret $SECRET_TYPE $SECRET_NAME \ - --from-literal=secret.json="$SECRET_DATA" \ - --namespace=${{ steps.namespace.outputs.namespace }} \ - --dry-run=client -o yaml | kubectl apply -f - - done - else - echo "No custom secrets to create" - fi - name: Deploy Kubernetes manifests uses: azure/k8s-deploy@c7ebd0d5f39477a23f1b5dea0f52e6db04adf28e # v6.0.0 with: @@ -120,8 +80,6 @@ jobs: inputs.skip_helm_deployment != 'true' steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - ref: ${{ inputs.deploy_branch }} - uses: ./.gitea/actions/extract-namespace-from-repo-name id: namespace with: @@ -132,29 +90,6 @@ jobs: with: method: kubeconfig kubeconfig: ${{ secrets.KUBECONFIG }} - - name: Create custom secrets - id: create-secrets - run: | - # Parse custom secrets from input - SECRETS='${{ inputs.custom_secrets }}' - if [ "$SECRETS" != "[]" ]; then - echo "Creating custom secrets..." - echo "$SECRETS" | jq -c '.[]' | while read -r secret; do - SECRET_NAME=$(echo "$secret" | jq -r '.name') - SECRET_TYPE=$(echo "$secret" | jq -r '.type // "generic"') - SECRET_DATA=$(echo "$secret" | jq -r '.data') - - echo "Creating secret: $SECRET_NAME (type: $SECRET_TYPE)" - - # Create the secret using kubectl - echo "$SECRET_DATA" | kubectl create secret $SECRET_TYPE $SECRET_NAME \ - --from-literal=secret.json="$SECRET_DATA" \ - --namespace=${{ steps.namespace.outputs.namespace }} \ - --dry-run=client -o yaml | kubectl apply -f - - done - else - echo "No custom secrets to create" - fi - name: Deploy Helm uses: helmfile/helmfile-action@02671705b1dda1dc4b0a4ddd4f9f1ea8f4568c6f # v2.4.3 with: @@ -163,7 +98,7 @@ jobs: # Summary job that always runs to show what was deployed deployment-summary: runs-on: ubuntu-latest - needs: [ detect-service-type, deploy-k8s, deploy-helm ] + needs: [detect-service-type, deploy-k8s, deploy-helm] if: always() steps: - name: Deployment Summary @@ -187,11 +122,3 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY echo "**Service Type**: ${{ needs.detect-service-type.outputs.has_helmfile == 'true' && 'Helm + Kubernetes' || 'Kubernetes Only' }}" >> $GITHUB_STEP_SUMMARY - - # Show custom secrets info - SECRETS='${{ inputs.custom_secrets }}' - if [ "$SECRETS" != "[]" ]; then - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Custom Secrets Created**: $(echo "$SECRETS" | jq length)" >> $GITHUB_STEP_SUMMARY - echo "$SECRETS" | jq -r '.[] | "- " + .name + " (" + (.type // "generic") + ")"' >> $GITHUB_STEP_SUMMARY - fi -- 2.52.0 From feb33eb0dcd3673caec3eb97f2a94aee9b2f7746 Mon Sep 17 00:00:00 2001 From: Timo Behrendt Date: Wed, 29 Apr 2026 17:19:46 +0200 Subject: [PATCH 3/8] feat: add restic backup secret --- .gitea/workflows/cd.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/cd.yaml index 0533e21..902bf3f 100644 --- a/.gitea/workflows/cd.yaml +++ b/.gitea/workflows/cd.yaml @@ -18,6 +18,11 @@ on: required: false default: false type: boolean + skip_shared_secrets_deployment: + description: "Skip shared secrets deployment (e.g. restic backup secret)" + required: false + default: false + type: boolean jobs: detect-service-type: @@ -48,6 +53,26 @@ jobs: echo "No k8s directory found at ${{ inputs.k8s_dir }}" fi + deploy-shared-secrets: + runs-on: ubuntu-latest + needs: detect-service-type + if: inputs.skip_shared_secrets_deployment != 'true' + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Set restic backup secret + uses: azure/k8s-create-secret@6e0ba8047235646753f2a3a3b359b4d0006ff218 # v5.0.1 + with: + namespace: ${{ steps.namespace.outputs.namespace }} + secret-name: backupsidecar-secret + secret-type: generic + data: | + { + "restic_password": "${{ secrets.RESTIC_PASSWORD }}", + "restic_rest_username": "${{ secrets.RESTIC_REST_USERNAME }}", + "restic_rest_password": "${{ secrets.RESTIC_REST_PASSWORD }}", + "gotify_token": "${{ secrets.GOTIFY_TOKEN }}" + } + deploy-k8s: runs-on: ubuntu-latest needs: detect-service-type -- 2.52.0 From e01287d52cdacc7edd4865b84846d2ab268ed3bd Mon Sep 17 00:00:00 2001 From: Timo Behrendt Date: Wed, 29 Apr 2026 17:24:23 +0200 Subject: [PATCH 4/8] pass env args to helm --- .gitea/workflows/cd.yaml | 6 ++++++ .gitea/workflows/ci.yaml | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/cd.yaml index 902bf3f..101b677 100644 --- a/.gitea/workflows/cd.yaml +++ b/.gitea/workflows/cd.yaml @@ -23,6 +23,11 @@ on: required: false default: false type: boolean + helmfile_env: + description: "Optional JSON object string of environment variables for Helmfile" + required: false + default: "{}" + type: string jobs: detect-service-type: @@ -119,6 +124,7 @@ jobs: uses: helmfile/helmfile-action@02671705b1dda1dc4b0a4ddd4f9f1ea8f4568c6f # v2.4.3 with: helmfile-args: apply + env: ${{ fromJSON(inputs.helmfile_env) }} # Summary job that always runs to show what was deployed deployment-summary: diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 42a249f..3513ddc 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -18,6 +18,11 @@ on: required: false default: false type: boolean + helmfile_env: + description: "Optional JSON object string of environment variables for Helmfile" + required: false + default: "{}" + type: string jobs: detect-service-type: @@ -93,11 +98,12 @@ jobs: uses: helmfile/helmfile-action@02671705b1dda1dc4b0a4ddd4f9f1ea8f4568c6f # v2.4.3 with: helmfile-args: diff + env: ${{ fromJSON(inputs.helmfile_env) }} # Summary job that always runs to show what was validated ci-summary: runs-on: ubuntu-latest - needs: [ detect-service-type, validate-k8s, validate-helm ] + needs: [detect-service-type, validate-k8s, validate-helm] if: always() steps: - name: CI Summary -- 2.52.0 From c40148a3e1f36106a930ffb8343582fb4a836cce Mon Sep 17 00:00:00 2001 From: Timo Behrendt Date: Wed, 29 Apr 2026 18:20:50 +0200 Subject: [PATCH 5/8] feat: add new namespace extraction --- .gitea/workflows/cd.yaml | 4 ++-- .gitea/workflows/ci.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/cd.yaml index 101b677..fb4518c 100644 --- a/.gitea/workflows/cd.yaml +++ b/.gitea/workflows/cd.yaml @@ -84,7 +84,7 @@ jobs: if: needs.detect-service-type.outputs.has_k8s == 'true' steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: ./.gitea/actions/extract-namespace-from-repo-name + - uses: https://gitea.t000-n.de/t.behrendt/k_deploy_actions/.gitea/actions/extract-namespace-from-repo-name@0.0.1 id: namespace with: repo: ${{ github.repository }} @@ -110,7 +110,7 @@ jobs: inputs.skip_helm_deployment != 'true' steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: ./.gitea/actions/extract-namespace-from-repo-name + - uses: https://gitea.t000-n.de/t.behrendt/k_deploy_actions/.gitea/actions/extract-namespace-from-repo-name@0.0.1 id: namespace with: repo: ${{ github.repository }} diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 3513ddc..c9316e2 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -59,7 +59,7 @@ jobs: if: needs.detect-service-type.outputs.has_k8s == 'true' steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: ./.gitea/actions/extract-namespace-from-repo-name + - uses: https://gitea.t000-n.de/t.behrendt/k_deploy_actions/.gitea/actions/extract-namespace-from-repo-name@0.0.1 id: namespace with: repo: ${{ github.repository }} @@ -84,7 +84,7 @@ jobs: inputs.skip_helm_validation != 'true' steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: ./.gitea/actions/extract-namespace-from-repo-name + - uses: https://gitea.t000-n.de/t.behrendt/k_deploy_actions/.gitea/actions/extract-namespace-from-repo-name@0.0.1 id: namespace with: repo: ${{ github.repository }} -- 2.52.0 From c306e1db1af765fade2e90a9c2ee0833e69b4acf Mon Sep 17 00:00:00 2001 From: Timo Behrendt Date: Wed, 29 Apr 2026 18:36:38 +0200 Subject: [PATCH 6/8] externalize summary --- .gitea/actions/ci-summary/action.yaml | 41 ++++++++++++++++ .gitea/actions/deployment-summary/action.yaml | 41 ++++++++++++++++ .../action.yaml | 19 ------- .../action.yaml | 19 ------- .gitea/workflows/{cd.yaml => deploy.yaml} | 49 ++++++++++++------- .gitea/workflows/{ci.yaml => validate.yaml} | 49 ++++++++++++------- 6 files changed, 144 insertions(+), 74 deletions(-) create mode 100644 .gitea/actions/ci-summary/action.yaml create mode 100644 .gitea/actions/deployment-summary/action.yaml delete mode 100644 .gitea/actions/extract-chart-name-from-repo-name/action.yaml delete mode 100644 .gitea/actions/extract-namespace-from-repo-name/action.yaml rename .gitea/workflows/{cd.yaml => deploy.yaml} (76%) rename .gitea/workflows/{ci.yaml => validate.yaml} (71%) diff --git a/.gitea/actions/ci-summary/action.yaml b/.gitea/actions/ci-summary/action.yaml new file mode 100644 index 0000000..c9a71fc --- /dev/null +++ b/.gitea/actions/ci-summary/action.yaml @@ -0,0 +1,41 @@ +name: "CI Summary" +description: "Writes CI validation summary to GITHUB_STEP_SUMMARY" +inputs: + has_k8s: + description: "Whether Kubernetes manifests were detected" + required: true + has_helmfile: + description: "Whether helmfile.yaml was detected" + required: true + skip_helm_validation: + description: "Whether Helm validation is manually disabled" + required: true +runs: + using: "composite" + steps: + - shell: bash + run: | + echo "## CI Validation Summary" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + + if [ "${{ inputs.has_k8s }}" = "true" ]; then + echo "✅ **Kubernetes validation**: Completed" >> "$GITHUB_STEP_SUMMARY" + else + echo "❌ **Kubernetes validation**: Skipped (no k8s/ directory found)" >> "$GITHUB_STEP_SUMMARY" + fi + + if [ "${{ inputs.has_helmfile }}" = "true" ] && [ "${{ inputs.skip_helm_validation }}" != "true" ]; then + echo "✅ **Helm validation**: Completed" >> "$GITHUB_STEP_SUMMARY" + elif [ "${{ inputs.has_helmfile }}" = "true" ] && [ "${{ inputs.skip_helm_validation }}" = "true" ]; then + echo "⏭️ **Helm validation**: Skipped (manually disabled)" >> "$GITHUB_STEP_SUMMARY" + else + echo "⏭️ **Helm validation**: Skipped (no helmfile.yaml found)" >> "$GITHUB_STEP_SUMMARY" + fi + + echo "" >> "$GITHUB_STEP_SUMMARY" + if [ "${{ inputs.has_helmfile }}" = "true" ]; then + service_type="Helm + Kubernetes" + else + service_type="Kubernetes Only" + fi + echo "**Service Type**: ${service_type}" >> "$GITHUB_STEP_SUMMARY" diff --git a/.gitea/actions/deployment-summary/action.yaml b/.gitea/actions/deployment-summary/action.yaml new file mode 100644 index 0000000..00647f3 --- /dev/null +++ b/.gitea/actions/deployment-summary/action.yaml @@ -0,0 +1,41 @@ +name: "Deployment Summary" +description: "Writes deployment summary to GITHUB_STEP_SUMMARY" +inputs: + has_k8s: + description: "Whether Kubernetes manifests were detected" + required: true + has_helmfile: + description: "Whether helmfile.yaml was detected" + required: true + skip_helm_deployment: + description: "Whether Helm deployment is manually disabled" + required: true +runs: + using: "composite" + steps: + - shell: bash + run: | + echo "## Deployment Summary" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + + if [ "${{ inputs.has_k8s }}" = "true" ]; then + echo "✅ **Kubernetes deployment**: Completed" >> "$GITHUB_STEP_SUMMARY" + else + echo "❌ **Kubernetes deployment**: Skipped (no k8s/ directory found)" >> "$GITHUB_STEP_SUMMARY" + fi + + if [ "${{ inputs.has_helmfile }}" = "true" ] && [ "${{ inputs.skip_helm_deployment }}" != "true" ]; then + echo "✅ **Helm deployment**: Completed" >> "$GITHUB_STEP_SUMMARY" + elif [ "${{ inputs.has_helmfile }}" = "true" ] && [ "${{ inputs.skip_helm_deployment }}" = "true" ]; then + echo "⏭️ **Helm deployment**: Skipped (manually disabled)" >> "$GITHUB_STEP_SUMMARY" + else + echo "⏭️ **Helm deployment**: Skipped (no helmfile.yaml found)" >> "$GITHUB_STEP_SUMMARY" + fi + + echo "" >> "$GITHUB_STEP_SUMMARY" + if [ "${{ inputs.has_helmfile }}" = "true" ]; then + service_type="Helm + Kubernetes" + else + service_type="Kubernetes Only" + fi + echo "**Service Type**: ${service_type}" >> "$GITHUB_STEP_SUMMARY" diff --git a/.gitea/actions/extract-chart-name-from-repo-name/action.yaml b/.gitea/actions/extract-chart-name-from-repo-name/action.yaml deleted file mode 100644 index 7e72d80..0000000 --- a/.gitea/actions/extract-chart-name-from-repo-name/action.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: Extract chart name from repo name -description: Extracts the chart name from the repo name, based on the convention of helm- -inputs: - repo: - description: The full repository name (e.g., "helm-my-chart") - required: true -outputs: - chart-name: - description: The extracted chart name - value: ${{ steps.extract.outputs.suffix }} -runs: - using: "composite" - steps: - - id: extract - shell: bash - run: | - full_repo="${{ inputs.repo }}" - suffix="${full_repo##*helm-}" - echo "suffix=$suffix" >> $GITHUB_OUTPUT diff --git a/.gitea/actions/extract-namespace-from-repo-name/action.yaml b/.gitea/actions/extract-namespace-from-repo-name/action.yaml deleted file mode 100644 index d8a639e..0000000 --- a/.gitea/actions/extract-namespace-from-repo-name/action.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: "Extract namespace from repo name" -description: "Extracts the namespace name from the repo name, based on the convention of k_" -inputs: - repo: - description: 'The repo name, get it from "github.repository"' - required: true -outputs: - namespace: - description: "The namespace name" - value: ${{ steps.extract.outputs.suffix }} -runs: - using: "composite" - steps: - - id: extract - shell: bash - run: | - full_repo="${{ inputs.repo }}" - suffix="${full_repo##*k_}" - echo "suffix=$suffix" >> $GITHUB_OUTPUT diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/deploy.yaml similarity index 76% rename from .gitea/workflows/cd.yaml rename to .gitea/workflows/deploy.yaml index fb4518c..becfeff 100644 --- a/.gitea/workflows/cd.yaml +++ b/.gitea/workflows/deploy.yaml @@ -28,6 +28,19 @@ on: required: false default: "{}" type: string + outputs: + has_k8s: + description: "Whether Kubernetes manifests were detected" + value: ${{ jobs.summary-data.outputs.has_k8s }} + has_helmfile: + description: "Whether helmfile.yaml was detected" + value: ${{ jobs.summary-data.outputs.has_helmfile }} + skip_helm_deployment: + description: "Whether Helm deployment was manually skipped" + value: ${{ jobs.summary-data.outputs.skip_helm_deployment }} + service_type: + description: "Service type inferred from repository contents" + value: ${{ jobs.summary-data.outputs.service_type }} jobs: detect-service-type: @@ -126,30 +139,30 @@ jobs: helmfile-args: apply env: ${{ fromJSON(inputs.helmfile_env) }} - # Summary job that always runs to show what was deployed - deployment-summary: + summary-data: runs-on: ubuntu-latest needs: [detect-service-type, deploy-k8s, deploy-helm] if: always() + outputs: + has_k8s: ${{ steps.export.outputs.has_k8s }} + has_helmfile: ${{ steps.export.outputs.has_helmfile }} + skip_helm_deployment: ${{ steps.export.outputs.skip_helm_deployment }} + service_type: ${{ steps.export.outputs.service_type }} steps: - - name: Deployment Summary + - name: Export summary data + id: export run: | - echo "## Deployment Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + has_k8s="${{ needs.detect-service-type.outputs.has_k8s }}" + has_helmfile="${{ needs.detect-service-type.outputs.has_helmfile }}" + skip_helm_deployment="${{ inputs.skip_helm_deployment }}" - if [ "${{ needs.detect-service-type.outputs.has_k8s }}" == "true" ]; then - echo "✅ **Kubernetes deployment**: Completed" >> $GITHUB_STEP_SUMMARY + if [ "$has_helmfile" = "true" ]; then + service_type="Helm + Kubernetes" else - echo "❌ **Kubernetes deployment**: Skipped (no k8s/ directory found)" >> $GITHUB_STEP_SUMMARY + service_type="Kubernetes Only" fi - if [ "${{ needs.detect-service-type.outputs.has_helmfile }}" == "true" ] && [ "${{ inputs.skip_helm_deployment }}" != "true" ]; then - echo "✅ **Helm deployment**: Completed" >> $GITHUB_STEP_SUMMARY - elif [ "${{ needs.detect-service-type.outputs.has_helmfile }}" == "true" ] && [ "${{ inputs.skip_helm_deployment }}" == "true" ]; then - echo "⏭️ **Helm deployment**: Skipped (manually disabled)" >> $GITHUB_STEP_SUMMARY - else - echo "⏭️ **Helm deployment**: Skipped (no helmfile.yaml found)" >> $GITHUB_STEP_SUMMARY - fi - - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Service Type**: ${{ needs.detect-service-type.outputs.has_helmfile == 'true' && 'Helm + Kubernetes' || 'Kubernetes Only' }}" >> $GITHUB_STEP_SUMMARY + echo "has_k8s=$has_k8s" >> "$GITHUB_OUTPUT" + echo "has_helmfile=$has_helmfile" >> "$GITHUB_OUTPUT" + echo "skip_helm_deployment=$skip_helm_deployment" >> "$GITHUB_OUTPUT" + echo "service_type=$service_type" >> "$GITHUB_OUTPUT" diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/validate.yaml similarity index 71% rename from .gitea/workflows/ci.yaml rename to .gitea/workflows/validate.yaml index c9316e2..e36f680 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/validate.yaml @@ -23,6 +23,19 @@ on: required: false default: "{}" type: string + outputs: + has_k8s: + description: "Whether Kubernetes manifests were detected" + value: ${{ jobs.summary-data.outputs.has_k8s }} + has_helmfile: + description: "Whether helmfile.yaml was detected" + value: ${{ jobs.summary-data.outputs.has_helmfile }} + skip_helm_validation: + description: "Whether Helm validation was manually skipped" + value: ${{ jobs.summary-data.outputs.skip_helm_validation }} + service_type: + description: "Service type inferred from repository contents" + value: ${{ jobs.summary-data.outputs.service_type }} jobs: detect-service-type: @@ -100,30 +113,30 @@ jobs: helmfile-args: diff env: ${{ fromJSON(inputs.helmfile_env) }} - # Summary job that always runs to show what was validated - ci-summary: + summary-data: runs-on: ubuntu-latest needs: [detect-service-type, validate-k8s, validate-helm] if: always() + outputs: + has_k8s: ${{ steps.export.outputs.has_k8s }} + has_helmfile: ${{ steps.export.outputs.has_helmfile }} + skip_helm_validation: ${{ steps.export.outputs.skip_helm_validation }} + service_type: ${{ steps.export.outputs.service_type }} steps: - - name: CI Summary + - name: Export summary data + id: export run: | - echo "## CI Validation Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + has_k8s="${{ needs.detect-service-type.outputs.has_k8s }}" + has_helmfile="${{ needs.detect-service-type.outputs.has_helmfile }}" + skip_helm_validation="${{ inputs.skip_helm_validation }}" - if [ "${{ needs.detect-service-type.outputs.has_k8s }}" == "true" ]; then - echo "✅ **Kubernetes validation**: Completed" >> $GITHUB_STEP_SUMMARY + if [ "$has_helmfile" = "true" ]; then + service_type="Helm + Kubernetes" else - echo "❌ **Kubernetes validation**: Skipped (no k8s/ directory found)" >> $GITHUB_STEP_SUMMARY + service_type="Kubernetes Only" fi - if [ "${{ needs.detect-service-type.outputs.has_helmfile }}" == "true" ] && [ "${{ inputs.skip_helm_validation }}" != "true" ]; then - echo "✅ **Helm validation**: Completed" >> $GITHUB_STEP_SUMMARY - elif [ "${{ needs.detect-service-type.outputs.has_helmfile }}" == "true" ] && [ "${{ inputs.skip_helm_validation }}" == "true" ]; then - echo "⏭️ **Helm validation**: Skipped (manually disabled)" >> $GITHUB_STEP_SUMMARY - else - echo "⏭️ **Helm validation**: Skipped (no helmfile.yaml found)" >> $GITHUB_STEP_SUMMARY - fi - - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Service Type**: ${{ needs.detect-service-type.outputs.has_helmfile == 'true' && 'Helm + Kubernetes' || 'Kubernetes Only' }}" >> $GITHUB_STEP_SUMMARY + echo "has_k8s=$has_k8s" >> "$GITHUB_OUTPUT" + echo "has_helmfile=$has_helmfile" >> "$GITHUB_OUTPUT" + echo "skip_helm_validation=$skip_helm_validation" >> "$GITHUB_OUTPUT" + echo "service_type=$service_type" >> "$GITHUB_OUTPUT" -- 2.52.0 From 1c260643573d4b978ac281d7dc1f5991afb4ce68 Mon Sep 17 00:00:00 2001 From: Timo Behrendt Date: Wed, 29 Apr 2026 19:39:22 +0200 Subject: [PATCH 7/8] merge summary back in --- .gitea/actions/ci-summary/action.yaml | 41 ---------------- .gitea/actions/deployment-summary/action.yaml | 41 ---------------- .gitea/workflows/deploy.yaml | 49 +++++++------------ .gitea/workflows/validate.yaml | 49 +++++++------------ 4 files changed, 36 insertions(+), 144 deletions(-) delete mode 100644 .gitea/actions/ci-summary/action.yaml delete mode 100644 .gitea/actions/deployment-summary/action.yaml diff --git a/.gitea/actions/ci-summary/action.yaml b/.gitea/actions/ci-summary/action.yaml deleted file mode 100644 index c9a71fc..0000000 --- a/.gitea/actions/ci-summary/action.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: "CI Summary" -description: "Writes CI validation summary to GITHUB_STEP_SUMMARY" -inputs: - has_k8s: - description: "Whether Kubernetes manifests were detected" - required: true - has_helmfile: - description: "Whether helmfile.yaml was detected" - required: true - skip_helm_validation: - description: "Whether Helm validation is manually disabled" - required: true -runs: - using: "composite" - steps: - - shell: bash - run: | - echo "## CI Validation Summary" >> "$GITHUB_STEP_SUMMARY" - echo "" >> "$GITHUB_STEP_SUMMARY" - - if [ "${{ inputs.has_k8s }}" = "true" ]; then - echo "✅ **Kubernetes validation**: Completed" >> "$GITHUB_STEP_SUMMARY" - else - echo "❌ **Kubernetes validation**: Skipped (no k8s/ directory found)" >> "$GITHUB_STEP_SUMMARY" - fi - - if [ "${{ inputs.has_helmfile }}" = "true" ] && [ "${{ inputs.skip_helm_validation }}" != "true" ]; then - echo "✅ **Helm validation**: Completed" >> "$GITHUB_STEP_SUMMARY" - elif [ "${{ inputs.has_helmfile }}" = "true" ] && [ "${{ inputs.skip_helm_validation }}" = "true" ]; then - echo "⏭️ **Helm validation**: Skipped (manually disabled)" >> "$GITHUB_STEP_SUMMARY" - else - echo "⏭️ **Helm validation**: Skipped (no helmfile.yaml found)" >> "$GITHUB_STEP_SUMMARY" - fi - - echo "" >> "$GITHUB_STEP_SUMMARY" - if [ "${{ inputs.has_helmfile }}" = "true" ]; then - service_type="Helm + Kubernetes" - else - service_type="Kubernetes Only" - fi - echo "**Service Type**: ${service_type}" >> "$GITHUB_STEP_SUMMARY" diff --git a/.gitea/actions/deployment-summary/action.yaml b/.gitea/actions/deployment-summary/action.yaml deleted file mode 100644 index 00647f3..0000000 --- a/.gitea/actions/deployment-summary/action.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: "Deployment Summary" -description: "Writes deployment summary to GITHUB_STEP_SUMMARY" -inputs: - has_k8s: - description: "Whether Kubernetes manifests were detected" - required: true - has_helmfile: - description: "Whether helmfile.yaml was detected" - required: true - skip_helm_deployment: - description: "Whether Helm deployment is manually disabled" - required: true -runs: - using: "composite" - steps: - - shell: bash - run: | - echo "## Deployment Summary" >> "$GITHUB_STEP_SUMMARY" - echo "" >> "$GITHUB_STEP_SUMMARY" - - if [ "${{ inputs.has_k8s }}" = "true" ]; then - echo "✅ **Kubernetes deployment**: Completed" >> "$GITHUB_STEP_SUMMARY" - else - echo "❌ **Kubernetes deployment**: Skipped (no k8s/ directory found)" >> "$GITHUB_STEP_SUMMARY" - fi - - if [ "${{ inputs.has_helmfile }}" = "true" ] && [ "${{ inputs.skip_helm_deployment }}" != "true" ]; then - echo "✅ **Helm deployment**: Completed" >> "$GITHUB_STEP_SUMMARY" - elif [ "${{ inputs.has_helmfile }}" = "true" ] && [ "${{ inputs.skip_helm_deployment }}" = "true" ]; then - echo "⏭️ **Helm deployment**: Skipped (manually disabled)" >> "$GITHUB_STEP_SUMMARY" - else - echo "⏭️ **Helm deployment**: Skipped (no helmfile.yaml found)" >> "$GITHUB_STEP_SUMMARY" - fi - - echo "" >> "$GITHUB_STEP_SUMMARY" - if [ "${{ inputs.has_helmfile }}" = "true" ]; then - service_type="Helm + Kubernetes" - else - service_type="Kubernetes Only" - fi - echo "**Service Type**: ${service_type}" >> "$GITHUB_STEP_SUMMARY" diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml index becfeff..fb4518c 100644 --- a/.gitea/workflows/deploy.yaml +++ b/.gitea/workflows/deploy.yaml @@ -28,19 +28,6 @@ on: required: false default: "{}" type: string - outputs: - has_k8s: - description: "Whether Kubernetes manifests were detected" - value: ${{ jobs.summary-data.outputs.has_k8s }} - has_helmfile: - description: "Whether helmfile.yaml was detected" - value: ${{ jobs.summary-data.outputs.has_helmfile }} - skip_helm_deployment: - description: "Whether Helm deployment was manually skipped" - value: ${{ jobs.summary-data.outputs.skip_helm_deployment }} - service_type: - description: "Service type inferred from repository contents" - value: ${{ jobs.summary-data.outputs.service_type }} jobs: detect-service-type: @@ -139,30 +126,30 @@ jobs: helmfile-args: apply env: ${{ fromJSON(inputs.helmfile_env) }} - summary-data: + # Summary job that always runs to show what was deployed + deployment-summary: runs-on: ubuntu-latest needs: [detect-service-type, deploy-k8s, deploy-helm] if: always() - outputs: - has_k8s: ${{ steps.export.outputs.has_k8s }} - has_helmfile: ${{ steps.export.outputs.has_helmfile }} - skip_helm_deployment: ${{ steps.export.outputs.skip_helm_deployment }} - service_type: ${{ steps.export.outputs.service_type }} steps: - - name: Export summary data - id: export + - name: Deployment Summary run: | - has_k8s="${{ needs.detect-service-type.outputs.has_k8s }}" - has_helmfile="${{ needs.detect-service-type.outputs.has_helmfile }}" - skip_helm_deployment="${{ inputs.skip_helm_deployment }}" + echo "## Deployment Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY - if [ "$has_helmfile" = "true" ]; then - service_type="Helm + Kubernetes" + if [ "${{ needs.detect-service-type.outputs.has_k8s }}" == "true" ]; then + echo "✅ **Kubernetes deployment**: Completed" >> $GITHUB_STEP_SUMMARY else - service_type="Kubernetes Only" + echo "❌ **Kubernetes deployment**: Skipped (no k8s/ directory found)" >> $GITHUB_STEP_SUMMARY fi - echo "has_k8s=$has_k8s" >> "$GITHUB_OUTPUT" - echo "has_helmfile=$has_helmfile" >> "$GITHUB_OUTPUT" - echo "skip_helm_deployment=$skip_helm_deployment" >> "$GITHUB_OUTPUT" - echo "service_type=$service_type" >> "$GITHUB_OUTPUT" + if [ "${{ needs.detect-service-type.outputs.has_helmfile }}" == "true" ] && [ "${{ inputs.skip_helm_deployment }}" != "true" ]; then + echo "✅ **Helm deployment**: Completed" >> $GITHUB_STEP_SUMMARY + elif [ "${{ needs.detect-service-type.outputs.has_helmfile }}" == "true" ] && [ "${{ inputs.skip_helm_deployment }}" == "true" ]; then + echo "⏭️ **Helm deployment**: Skipped (manually disabled)" >> $GITHUB_STEP_SUMMARY + else + echo "⏭️ **Helm deployment**: Skipped (no helmfile.yaml found)" >> $GITHUB_STEP_SUMMARY + fi + + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Service Type**: ${{ needs.detect-service-type.outputs.has_helmfile == 'true' && 'Helm + Kubernetes' || 'Kubernetes Only' }}" >> $GITHUB_STEP_SUMMARY diff --git a/.gitea/workflows/validate.yaml b/.gitea/workflows/validate.yaml index e36f680..c9316e2 100644 --- a/.gitea/workflows/validate.yaml +++ b/.gitea/workflows/validate.yaml @@ -23,19 +23,6 @@ on: required: false default: "{}" type: string - outputs: - has_k8s: - description: "Whether Kubernetes manifests were detected" - value: ${{ jobs.summary-data.outputs.has_k8s }} - has_helmfile: - description: "Whether helmfile.yaml was detected" - value: ${{ jobs.summary-data.outputs.has_helmfile }} - skip_helm_validation: - description: "Whether Helm validation was manually skipped" - value: ${{ jobs.summary-data.outputs.skip_helm_validation }} - service_type: - description: "Service type inferred from repository contents" - value: ${{ jobs.summary-data.outputs.service_type }} jobs: detect-service-type: @@ -113,30 +100,30 @@ jobs: helmfile-args: diff env: ${{ fromJSON(inputs.helmfile_env) }} - summary-data: + # Summary job that always runs to show what was validated + ci-summary: runs-on: ubuntu-latest needs: [detect-service-type, validate-k8s, validate-helm] if: always() - outputs: - has_k8s: ${{ steps.export.outputs.has_k8s }} - has_helmfile: ${{ steps.export.outputs.has_helmfile }} - skip_helm_validation: ${{ steps.export.outputs.skip_helm_validation }} - service_type: ${{ steps.export.outputs.service_type }} steps: - - name: Export summary data - id: export + - name: CI Summary run: | - has_k8s="${{ needs.detect-service-type.outputs.has_k8s }}" - has_helmfile="${{ needs.detect-service-type.outputs.has_helmfile }}" - skip_helm_validation="${{ inputs.skip_helm_validation }}" + echo "## CI Validation Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY - if [ "$has_helmfile" = "true" ]; then - service_type="Helm + Kubernetes" + if [ "${{ needs.detect-service-type.outputs.has_k8s }}" == "true" ]; then + echo "✅ **Kubernetes validation**: Completed" >> $GITHUB_STEP_SUMMARY else - service_type="Kubernetes Only" + echo "❌ **Kubernetes validation**: Skipped (no k8s/ directory found)" >> $GITHUB_STEP_SUMMARY fi - echo "has_k8s=$has_k8s" >> "$GITHUB_OUTPUT" - echo "has_helmfile=$has_helmfile" >> "$GITHUB_OUTPUT" - echo "skip_helm_validation=$skip_helm_validation" >> "$GITHUB_OUTPUT" - echo "service_type=$service_type" >> "$GITHUB_OUTPUT" + if [ "${{ needs.detect-service-type.outputs.has_helmfile }}" == "true" ] && [ "${{ inputs.skip_helm_validation }}" != "true" ]; then + echo "✅ **Helm validation**: Completed" >> $GITHUB_STEP_SUMMARY + elif [ "${{ needs.detect-service-type.outputs.has_helmfile }}" == "true" ] && [ "${{ inputs.skip_helm_validation }}" == "true" ]; then + echo "⏭️ **Helm validation**: Skipped (manually disabled)" >> $GITHUB_STEP_SUMMARY + else + echo "⏭️ **Helm validation**: Skipped (no helmfile.yaml found)" >> $GITHUB_STEP_SUMMARY + fi + + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Service Type**: ${{ needs.detect-service-type.outputs.has_helmfile == 'true' && 'Helm + Kubernetes' || 'Kubernetes Only' }}" >> $GITHUB_STEP_SUMMARY -- 2.52.0 From 33ef2a2d12cd609390152977965e5592cc6285a6 Mon Sep 17 00:00:00 2001 From: Timo Behrendt Date: Wed, 29 Apr 2026 19:44:03 +0200 Subject: [PATCH 8/8] docs: finish docs --- README.md | 156 +++++++++++++----------------------------------------- 1 file changed, 38 insertions(+), 118 deletions(-) diff --git a/README.md b/README.md index 1395b3e..5cd0e4a 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,75 @@ -> [!WARNING] -> Repo is currently not in use and not tested. -> We are waiting for proper shared workflow UI support in gitea. Otherwise errors are hard to identify. -> Follow https://github.com/go-gitea/gitea/issues/24604 +# Reusable CI/CD Workflows for k\_ Services -# Reusable CI Workflow for Kubernetes Services - -This directory contains a reusable CI workflow that automatically detects and validates your Kubernetes services, whether they use Helm + Kubernetes or just Kubernetes manifests. +This repository contains reusable CI and CD workflows that automatically detect Kubernetes service type (Kubernetes-only vs Helm + Kubernetes) and execute the relevant steps. ## Features -- **Automatic Detection**: Automatically detects if your service uses Helm (helmfile.yaml) or just Kubernetes manifests -- **Conditional Validation**: Only runs Helm validation when helmfile.yaml exists -- **Flexible Paths**: Configurable paths for k8s directory and helmfile -- **Comprehensive Validation**: Validates both Kubernetes manifests and Helm charts -- **CI Summary**: Provides a clear summary of what was validated +- **Reusable CI and CD**: Separate reusable workflows for validation and deployment +- **Automatic Detection**: Detects whether `helmfile.yaml` exists and whether `k8s/` exists +- **Conditional Execution**: Runs Helm steps only when applicable +- **Flexible Inputs**: Supports custom `k8s_dir` and `helmfile_path` ## Usage -### Basic Usage (Recommended) +### Basic CI Usage -Simply call the workflow without any parameters - it will automatically detect your service type: +Call the reusable CI workflow: ```yaml jobs: ci: - uses: ./.gitea/workflows/ci.yaml + uses: https://gitea.t000-n.de/t.behrendt/k_deploy_workflows/.gitea/workflows/ci.yaml@main + secrets: inherit ``` -### Advanced Usage with Custom Paths +### Basic CD Usage -If your service uses non-standard directory names: +Call the reusable CD workflow: + +```yaml +jobs: + deploy: + uses: https://gitea.t000-n.de/t.behrendt/k_deploy_workflows/.gitea/workflows/cd.yaml@main + secrets: inherit +``` + +### Advanced Usage with Custom Paths and Flags ```yaml jobs: ci: - uses: ./.gitea/workflows/ci.yaml + uses: https://gitea.t000-n.de/t.behrendt/k_deploy_workflows/.gitea/workflows/ci.yaml@main with: k8s_dir: "kubernetes/" helmfile_path: "helm/helmfile.yaml" -``` - -### Force Skip Helm Validation - -If you want to skip Helm validation even when helmfile.yaml exists: - -```yaml -jobs: - ci: - uses: ./.gitea/workflows/ci.yaml - with: skip_helm_validation: true + secrets: inherit ``` -## Input Parameters +## Inputs + +### CI (`.gitea/workflows/ci.yaml`) | Parameter | Description | Default | Required | | ---------------------- | -------------------------------------------- | --------------- | -------- | | `k8s_dir` | Path to Kubernetes manifests directory | `k8s/` | No | | `helmfile_path` | Path to helmfile.yaml | `helmfile.yaml` | No | | `skip_helm_validation` | Skip Helm validation even if helmfile exists | `false` | No | +| `helmfile_env` | JSON object string passed as env to helmfile | `{}` | No | + +### CD (`.gitea/workflows/cd.yaml`) + +| Parameter | Description | Default | Required | +| -------------------------------- | -------------------------------------------- | --------------- | -------- | +| `k8s_dir` | Path to Kubernetes manifests directory | `k8s/` | No | +| `helmfile_path` | Path to helmfile.yaml | `helmfile.yaml` | No | +| `skip_helm_deployment` | Skip Helm deployment even if helmfile exists | `false` | No | +| `skip_shared_secrets_deployment` | Skip shared secrets deployment | `false` | No | +| `helmfile_env` | JSON object string passed as env to helmfile | `{}` | No | ## Directory Structure Requirements -### For Kubernetes-only services: - -``` -your-service/ -├── k8s/ -│ ├── deployment.yaml -│ ├── service.yaml -│ └── ... -└── .gitea/workflows/your-workflow.yaml -``` - -### For Helm + Kubernetes services: +### Full example structure (Helm + Kubernetes): ``` your-service/ @@ -84,79 +80,3 @@ your-service/ ├── helmfile.yaml └── .gitea/workflows/your-workflow.yaml ``` - -## What Gets Validated - -### Always (if k8s/ directory exists): - -- Kubernetes manifest validation using `kubectl --dry-run` -- Namespace extraction from repository name -- Basic Kubernetes syntax and schema validation - -### Conditionally (if helmfile.yaml exists and Helm validation not skipped): - -- Helm chart validation using `helmfile diff` -- Kubernetes manifests in Helm context -- Helm-specific configurations and values - -## Example Workflows - -See `example-usage.yaml` for complete examples of how to use this workflow in different scenarios. - -## Available Actions - -### Extract Chart Name from Repository Name - -The `extract-chart-name-from-repo-name` action extracts the chart name from repository names following the `helm-` convention. - -#### Usage - -```yaml -- name: Extract chart name - uses: ./.gitea/actions/extract-chart-name-from-repo-name - with: - repo: ${{ github.repository_name }} # e.g., "helm-my-service" -``` - -#### Inputs - -| Parameter | Description | Required | -| --------- | ------------------------------------------------ | -------- | -| `repo` | The full repository name (e.g., "helm-my-chart") | Yes | - -#### Outputs - -| Output | Description | -| ------------ | ---------------------------------------------------------------- | -| `chart-name` | The extracted chart name (e.g., "my-chart" from "helm-my-chart") | - -#### Example - -For a repository named `helm-user-service`, this action will extract `user-service` as the chart name. - -## Dependencies - -This workflow requires: - -- `./.gitea/actions/extract-namespace-from-repo-name` action -- `./.gitea/actions/extract-chart-name-from-repo-name` action -- `KUBECONFIG` secret configured in your repository -- Access to your Kubernetes cluster - -## Troubleshooting - -### Helm validation skipped unexpectedly - -- Check if `helmfile.yaml` exists in the expected location -- Verify the `skip_helm_validation` parameter is not set to `true` -- Ensure the file path is correct if using custom paths - -### Kubernetes validation skipped - -- Verify the `k8s/` directory (or custom path) exists -- Check the directory contains valid Kubernetes manifests - -### Permission issues - -- Ensure the `KUBECONFIG` secret is properly configured -- Verify the workflow has access to your Kubernetes cluster -- 2.52.0