diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d05f99f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,86 @@ +name: CI + +on: + pull_request: + branches: [main] + push: + branches: [main] + +permissions: + contents: read + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + DEVSPACE_VERSION: v6.3.15 + HELM_VERSION: v3.18.3 + YQ_VERSION: v4.45.4 + +jobs: + pre-commit: + name: Pre-commit + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Set up Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: "3.x" + + - name: Install Helm unittest tooling + run: | + set -euo pipefail + mkdir -p "${RUNNER_TEMP}/bin" + echo "${RUNNER_TEMP}/bin" >> "${GITHUB_PATH}" + + curl -fsSL "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz" \ + | tar -xz -C "${RUNNER_TEMP}" + mv "${RUNNER_TEMP}/linux-amd64/helm" "${RUNNER_TEMP}/bin/helm" + + helm plugin install https://github.com/helm-unittest/helm-unittest + + - name: Run pre-commit hooks + run: | + python -m pip install --upgrade pip + python -m pip install pre-commit==4.6.0 + pre-commit run --all-files --show-diff-on-failure + + devspace: + name: DevSpace config + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Install DevSpace tooling + run: | + set -euo pipefail + mkdir -p "${RUNNER_TEMP}/bin" + echo "${RUNNER_TEMP}/bin" >> "${GITHUB_PATH}" + + curl -fsSL -o "${RUNNER_TEMP}/bin/yq" \ + "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64" + chmod +x "${RUNNER_TEMP}/bin/yq" + + curl -fsSL -o "${RUNNER_TEMP}/bin/devspace" \ + "https://github.com/loft-sh/devspace/releases/download/${DEVSPACE_VERSION}/devspace-linux-amd64" + chmod +x "${RUNNER_TEMP}/bin/devspace" + + - name: Validate DevSpace config + run: devspace print --skip-info --disable-profile-activation >/tmp/devspace.yaml + + actionlint: + name: GitHub Actions lint + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Set up Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version-file: go.mod + + - name: Lint workflows + run: go run github.com/rhysd/actionlint/cmd/actionlint@latest diff --git a/.github/workflows/smoke.yaml b/.github/workflows/smoke.yaml index 82eb234..3964012 100644 --- a/.github/workflows/smoke.yaml +++ b/.github/workflows/smoke.yaml @@ -11,22 +11,63 @@ on: - reopened - labeled +permissions: + contents: read + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + jobs: smoke: - if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'smoke') + name: Smoke runs-on: ubuntu-latest timeout-minutes: 90 steps: - name: Check out repository - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: go.mod + - name: Decide whether smoke is required + id: smoke + run: | + set -euo pipefail + + run_smoke=false + reason="pull request has no smoke label or smoke-related file changes" + smoke_path_re='^(devspace\.yaml|Makefile|go\.mod|go\.sum|' + smoke_path_re+='\.github/workflows/smoke\.yaml|charts/|helm-values/|' + smoke_path_re+='manifests/|scripts/|tests/e2e/|tests/install/)' + + if [ "${{ github.event_name }}" != "pull_request" ]; then + run_smoke=true + reason="${{ github.event_name }} event" + elif [ "${{ contains(github.event.pull_request.labels.*.name, 'smoke') }}" = "true" ]; then + run_smoke=true + reason="pull request has smoke label" + else + changed_files="$(git diff --name-only "origin/${{ github.base_ref }}"...HEAD)" + while IFS= read -r path; do + if [[ "${path}" =~ ${smoke_path_re} ]]; then + run_smoke=true + reason="smoke-related file changed: ${path}" + break + fi + done <<< "${changed_files}" + fi + + echo "run=${run_smoke}" >> "${GITHUB_OUTPUT}" + echo "reason=${reason}" >> "${GITHUB_OUTPUT}" + echo "I: ${reason}" + - name: Install smoke tooling + if: steps.smoke.outputs.run == 'true' run: | set -euo pipefail sudo apt-get update @@ -35,20 +76,30 @@ jobs: mkdir -p "${RUNNER_TEMP}/bin" echo "${RUNNER_TEMP}/bin" >> "${GITHUB_PATH}" - curl -fsSL -o "${RUNNER_TEMP}/bin/kind" "https://kind.sigs.k8s.io/dl/v0.29.0/kind-linux-amd64" + curl -fsSL -o "${RUNNER_TEMP}/bin/kind" \ + "https://kind.sigs.k8s.io/dl/v0.29.0/kind-linux-amd64" chmod +x "${RUNNER_TEMP}/bin/kind" - curl -fsSL -o "${RUNNER_TEMP}/bin/kubectl" "https://dl.k8s.io/release/v1.33.2/bin/linux/amd64/kubectl" + curl -fsSL -o "${RUNNER_TEMP}/bin/kubectl" \ + "https://dl.k8s.io/release/v1.33.2/bin/linux/amd64/kubectl" chmod +x "${RUNNER_TEMP}/bin/kubectl" curl -fsSL "https://get.helm.sh/helm-v3.18.3-linux-amd64.tar.gz" | tar -xz -C "${RUNNER_TEMP}" mv "${RUNNER_TEMP}/linux-amd64/helm" "${RUNNER_TEMP}/bin/helm" - curl -fsSL -o "${RUNNER_TEMP}/bin/yq" "https://github.com/mikefarah/yq/releases/download/v4.45.4/yq_linux_amd64" + curl -fsSL -o "${RUNNER_TEMP}/bin/yq" \ + "https://github.com/mikefarah/yq/releases/download/v4.45.4/yq_linux_amd64" chmod +x "${RUNNER_TEMP}/bin/yq" - curl -fsSL -o "${RUNNER_TEMP}/bin/devspace" "https://github.com/loft-sh/devspace/releases/download/v6.3.15/devspace-linux-amd64" + curl -fsSL -o "${RUNNER_TEMP}/bin/devspace" \ + "https://github.com/loft-sh/devspace/releases/download/v6.3.15/devspace-linux-amd64" chmod +x "${RUNNER_TEMP}/bin/devspace" - name: Run smoke + if: steps.smoke.outputs.run == 'true' run: make smoke + + - name: Skip smoke + if: steps.smoke.outputs.run != 'true' + run: | + echo "I: ${{ steps.smoke.outputs.reason }}" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4897895..828e4f8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: rev: v1.35.1 hooks: - id: yamllint - args: ['-d', '{extends: relaxed, rules: {line-length: {max: 120}}}'] + args: ['-c', '.yamllint.yaml'] exclude: 'templates/.*\.yaml$|.*\.jinja$' - repo: local diff --git a/.yamllint.yaml b/.yamllint.yaml index 7b35421..d62937b 100644 --- a/.yamllint.yaml +++ b/.yamllint.yaml @@ -15,4 +15,5 @@ ignore: | charts/*/charts/ charts/*/Chart.lock charts/*.tgz + manifests/grafana-dashboards-*.yaml .devspace/ diff --git a/Makefile b/Makefile index b8b9f2d..95ff2e0 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help install-precommit setup-dev lint test test-install test-e2e smoke clean +.PHONY: help install-precommit setup-dev lint lint-actions lint-devspace test test-install test-e2e smoke clean verify help: ## Display this help message @echo "Available targets:" @@ -33,6 +33,14 @@ lint: ## Run all linting checks @echo "Running pre-commit on all files..." pre-commit run --all-files +lint-actions: ## Lint GitHub Actions workflows + @echo "Running actionlint..." + go run github.com/rhysd/actionlint/cmd/actionlint@latest + +lint-devspace: ## Validate DevSpace config syntax and substitution + @echo "Validating DevSpace config..." + devspace print --skip-info --disable-profile-activation >/tmp/devspace-starter-pack-devspace.yaml + lint-yaml: ## Run YAML linting only @echo "Running yamllint..." yamllint . @@ -72,6 +80,8 @@ format: ## Auto-format files where possible @echo "Auto-formatting files..." pre-commit run --all-files || true -check: lint test ## Run all checks (lint + test) +verify: lint lint-actions lint-devspace test ## Run CI-equivalent local validation without a cluster + +check: verify ## Run all checks .DEFAULT_GOAL := help diff --git a/devspace.yaml b/devspace.yaml index 3a3a7a0..311c2ee 100644 --- a/devspace.yaml +++ b/devspace.yaml @@ -670,7 +670,8 @@ commands: trap 'rm -f "${CERTFILE}"' EXIT echo >&2 "I: Extracting Root CA certificate..." - kubectl get secret -n istio-ingress cluster-root-ca-secret -o jsonpath='{.data.tls\.crt}' | base64 -d > "${CERTFILE}" + kubectl get secret -n istio-ingress cluster-root-ca-secret \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > "${CERTFILE}" if [ ! -s "${CERTFILE}" ]; then echo >&2 "E: Failed to extract certificate or certificate is empty" exit 1 @@ -692,7 +693,8 @@ commands: trap 'rm -f "${CERTFILE}"' EXIT echo >&2 "I: Extracting Root CA certificate..." - kubectl get secret -n istio-ingress cluster-root-ca-secret -o jsonpath='{.data.tls\.crt}' | base64 -d > "${CERTFILE}" + kubectl get secret -n istio-ingress cluster-root-ca-secret \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > "${CERTFILE}" if [ ! -s "${CERTFILE}" ]; then echo >&2 "E: Failed to extract certificate or certificate is empty" exit 1 diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..7d822a7 --- /dev/null +++ b/renovate.json @@ -0,0 +1,58 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ], + "postUpdateOptions": [ + "gomodTidy" + ], + "packageRules": [ + { + "description": "Automerge Renovate version bumps after required CI passes", + "matchManagers": [ + "gomod", + "github-actions", + "pre-commit" + ], + "matchUpdateTypes": [ + "minor", + "patch" + ], + "automerge": true, + "automergeType": "pr", + "automergeStrategy": "rebase", + "platformAutomerge": true + }, + { + "matchManagers": [ + "gomod" + ], + "enabled": true + }, + { + "matchManagers": [ + "github-actions" + ], + "enabled": true + }, + { + "matchManagers": [ + "pre-commit" + ], + "enabled": true + }, + { + "description": "Avoid unmergeable Go indirect major bumps that go mod tidy reverses", + "matchManagers": [ + "gomod" + ], + "matchDepTypes": [ + "indirect" + ], + "matchUpdateTypes": [ + "major" + ], + "enabled": false + } + ] +}