Merge branch 'main' into update-strategy-feature
This commit is contained in:
commit
32afe9de42
|
|
@ -0,0 +1,234 @@
|
|||
# Copilot Instructions for Helmfile
|
||||
|
||||
## Repository Overview
|
||||
|
||||
Helmfile is a tool for deploying Helm charts that manages Kubernetes deployments as code. It provides templating, environment management, and GitOps workflows for Helm chart deployments.
|
||||
|
||||
Helmfile is a declarative tool. In Helmfile, all elements of the desired state for deployments must be included in the `helmfile.yaml` config file and any associated files. Only operational matters can be provided dynamically, via command-line flags and environment variables.
|
||||
|
||||
**Key Details:**
|
||||
- **Language:** Go 1.24.2+
|
||||
- **Type:** CLI tool / Kubernetes deployment management
|
||||
- **Size:** Large codebase (~229MB binary, 200+ dependencies)
|
||||
- **Runtime:** Requires Helm 3.x as external dependency
|
||||
- **Target Platform:** Linux/macOS/Windows, Kubernetes clusters
|
||||
|
||||
## Build and Validation Commands
|
||||
|
||||
### Essential Setup
|
||||
Helmfile requires Helm 3.x and Kustomize 5.x as runtime dependencies:
|
||||
```bash
|
||||
# Check for Helm dependency (REQUIRED)
|
||||
helm version # Must show version 3.x
|
||||
|
||||
# Initialize Helm plugins after helmfile installation
|
||||
./helmfile init # Installs required helm-diff plugin
|
||||
|
||||
# Alternative: Force install without prompts
|
||||
./helmfile init --force
|
||||
```
|
||||
|
||||
### Build Process
|
||||
```bash
|
||||
# Standard build (takes 2-3 minutes due to many dependencies)
|
||||
make build
|
||||
|
||||
# Alternative direct build
|
||||
go build -o helmfile .
|
||||
|
||||
# Build with test tools (required for integration tests, ~1 minute)
|
||||
make build-test-tools # Creates diff-yamls and downloads dyff
|
||||
|
||||
# Cross-platform builds
|
||||
make cross
|
||||
```
|
||||
|
||||
**Build Timing:** First build downloads 200+ Go packages and takes 2-3 minutes. Subsequent builds are faster due to module cache. Test tools build is faster (~1 minute).
|
||||
|
||||
### Validation Pipeline
|
||||
Run in this exact order to match CI requirements:
|
||||
|
||||
```bash
|
||||
# 1. Code formatting and linting
|
||||
make check # Run go vet (required - always works)
|
||||
# Note: make fmt requires gci tool (go install github.com/daixiang0/gci@latest)
|
||||
|
||||
# 2. Unit tests (fast, ~30 seconds)
|
||||
go test -v ./pkg/... -race -p=1
|
||||
|
||||
# 3. Integration tests (requires Kubernetes - see Environment Setup)
|
||||
make integration # Takes 5-10 minutes, needs minikube/k8s cluster
|
||||
|
||||
# 4. E2E tests (optional, needs expect package)
|
||||
sudo apt-get install expect # On Ubuntu/Debian
|
||||
bash test/e2e/helmfile-init/init_linux.sh
|
||||
```
|
||||
|
||||
### Linting Configuration
|
||||
Uses golangci-lint with configuration in `.golangci.yaml`. Install via:
|
||||
```bash
|
||||
# For local development
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.1.6
|
||||
golangci-lint run
|
||||
```
|
||||
|
||||
**Critical Lint Rules:** staticcheck, errcheck, revive, unused. Fix lint errors before committing.
|
||||
|
||||
## Environment Setup Requirements
|
||||
|
||||
### Dependencies for Development
|
||||
```bash
|
||||
# Required for building/testing
|
||||
go version # Must be 1.24.2+
|
||||
helm version # Must be 3.x
|
||||
kubectl version # For K8s integration
|
||||
|
||||
# Required for integration tests
|
||||
minikube start # Or other K8s cluster
|
||||
kustomize version # v5.2.1+ for some tests
|
||||
```
|
||||
|
||||
### Integration Test Environment
|
||||
Integration tests require a running Kubernetes cluster:
|
||||
|
||||
```bash
|
||||
# Using minikube (recommended for CI)
|
||||
minikube start
|
||||
export KUBECONFIG=$(minikube kubeconfig-path)
|
||||
|
||||
# Using kind (alternative)
|
||||
kind create cluster --name helmfile-test
|
||||
|
||||
# Verify cluster access
|
||||
kubectl cluster-info
|
||||
```
|
||||
|
||||
**Timing:** Integration tests take 5-10 minutes and may fail due to timing issues in resource-constrained environments.
|
||||
|
||||
## Project Architecture and Layout
|
||||
|
||||
### Core Directory Structure
|
||||
```
|
||||
/
|
||||
├── main.go # Entry point - CLI initialization and signal handling
|
||||
├── cmd/ # CLI commands (apply, diff, sync, template, etc.)
|
||||
│ ├── root.go # Main cobra command setup and global flags
|
||||
│ ├── apply.go # helmfile apply command
|
||||
│ ├── diff.go # helmfile diff command
|
||||
│ └── ... # Other subcommands
|
||||
├── pkg/ # Core library packages
|
||||
│ ├── app/ # Main application logic and execution
|
||||
│ ├── state/ # Helmfile state management and chart dependencies
|
||||
│ ├── helmexec/ # Helm execution and command wrapper
|
||||
│ ├── tmpl/ # Go template processing and functions
|
||||
│ ├── environment/ # Environment and values management
|
||||
│ └── ... # Other core packages
|
||||
├── test/ # Test suites
|
||||
│ ├── integration/ # Integration tests with real K8s clusters
|
||||
│ ├── e2e/ # End-to-end user workflow tests
|
||||
│ └── advanced/ # Advanced feature tests
|
||||
├── docs/ # Documentation (mkdocs format)
|
||||
├── examples/ # Example helmfile configurations
|
||||
└── .github/workflows/ # CI/CD pipeline definitions
|
||||
```
|
||||
|
||||
### Key Source Files
|
||||
- **main.go:** Signal handling, CLI execution entry point
|
||||
- **cmd/root.go:** Global CLI configuration, error handling, logging setup
|
||||
- **pkg/app/app.go:** Main application orchestration, state management
|
||||
- **pkg/state/state.go:** Helmfile state parsing, release management
|
||||
- **pkg/helmexec/exec.go:** Helm command execution, version detection
|
||||
|
||||
### Configuration Files
|
||||
- **go.mod/go.sum:** Go dependencies (many cloud providers, k8s libraries)
|
||||
- **.golangci.yaml:** Linting rules and settings
|
||||
- **Makefile:** Build targets and development workflows
|
||||
- **mkdocs.yml:** Documentation generation configuration
|
||||
- **.github/workflows/ci.yaml:** Complete CI pipeline definition
|
||||
|
||||
## Continuous Integration Pipeline
|
||||
|
||||
### GitHub Actions Workflow (`.github/workflows/ci.yaml`)
|
||||
1. **Lint Job:** golangci-lint with custom configuration (~5 minutes)
|
||||
2. **Test Job:** Unit tests + binary build (~10 minutes)
|
||||
3. **Integration Job:** Tests with multiple Helm/Kustomize versions (~15-20 minutes each)
|
||||
4. **E2E Job:** User workflow validation (~5 minutes)
|
||||
|
||||
**Matrix Testing:** CI tests against multiple Helm versions (3.17.x, 3.18.x) and Kustomize versions (5.2.x, 5.4.x).
|
||||
|
||||
### Pre-commit Validation Steps
|
||||
Always run these locally before pushing:
|
||||
```bash
|
||||
make check # Format and vet (required)
|
||||
go test ./pkg/... # Unit tests
|
||||
make build # Verify build works
|
||||
# Note: make fmt requires gci tool: go install github.com/daixiang0/gci@latest
|
||||
```
|
||||
|
||||
### Common CI Failure Causes
|
||||
- **Linting errors:** Run `golangci-lint run` locally first
|
||||
- **Integration test timeouts:** K8s cluster setup timing issues
|
||||
- **Version compatibility:** Ensure Go 1.24.2+ and Helm 3.x
|
||||
- **Race conditions:** Some tests are sensitive to parallel execution
|
||||
|
||||
## Development Gotchas and Known Issues
|
||||
|
||||
### Build Issues
|
||||
- **Long initial build time:** First `make build` downloads 200+ packages (~2-3 minutes)
|
||||
- **Memory usage:** Large binary size due to embedded dependencies
|
||||
- **Git tags:** Build may show version warnings if not on tagged commit
|
||||
- **Tool dependencies:** `make fmt` requires `gci` tool installation
|
||||
|
||||
### Testing Issues
|
||||
- **Integration tests require K8s:** Will fail without cluster access
|
||||
- **Test isolation:** Use `-p=1` flag to avoid race conditions
|
||||
- **Minikube timing:** May need to wait for cluster ready state
|
||||
- **Plugin dependencies:** Tests need helm-diff and helm-secrets plugins
|
||||
|
||||
### Runtime Requirements
|
||||
- **Helm dependency:** Always required at runtime, not just build time (available in CI)
|
||||
- **kubectl access:** Most operations need valid kubeconfig
|
||||
- **Plugin management:** `helmfile init` must be run after installation
|
||||
|
||||
### Common Error Patterns
|
||||
```bash
|
||||
# Missing Helm
|
||||
"helm: command not found" → Install Helm first
|
||||
|
||||
# Plugin missing
|
||||
"Error: plugin 'diff' not found" → Run helmfile init
|
||||
|
||||
# K8s access
|
||||
"connection refused" → Check kubectl cluster-info
|
||||
|
||||
# Permission errors
|
||||
"permission denied" → Check kubeconfig and cluster access
|
||||
|
||||
# Missing tools
|
||||
"gci: No such file or directory" → go install github.com/daixiang0/gci@latest
|
||||
```
|
||||
|
||||
## Working with the Codebase
|
||||
|
||||
### Making Changes
|
||||
- **Follow Helmfile design**: Helmfile is a declarative deployment tool. Anything that is part of the desired state of the deployments needs to be managed by Helmfile configs. Only operational knowledge that affects "how" to apply the desired state needs to be runtime options, like command-like flags and environment variables.
|
||||
- **Small, focused changes:** Each PR should address single concern
|
||||
- **Test coverage:** Add unit tests for new pkg/ functionality
|
||||
- **Integration tests:** Update test-cases/ for new CLI features
|
||||
- **Documentation:** Update docs/ for user-facing changes
|
||||
|
||||
### Key Packages to Understand
|
||||
- **pkg/app:** Main business logic, start here for feature changes
|
||||
- **pkg/state:** Helmfile parsing and release orchestration
|
||||
- **cmd/:** CLI interface changes and new subcommands
|
||||
- **pkg/helmexec:** Helm integration and command execution
|
||||
|
||||
### Architecture Patterns
|
||||
- **Dependency injection:** App uses interfaces for testability
|
||||
- **State management:** Immutable state objects, functional transforms
|
||||
- **Error handling:** Custom error types with exit codes
|
||||
- **Plugin system:** Extensible via Helm plugins and Go templates
|
||||
|
||||
---
|
||||
|
||||
**Trust these instructions:** This information is validated against the current codebase. Only search for additional details if these instructions are incomplete or found to be incorrect for your specific task.
|
||||
|
|
@ -13,8 +13,8 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: false
|
||||
|
|
@ -25,10 +25,10 @@ jobs:
|
|||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
- name: Build
|
||||
|
|
@ -54,12 +54,12 @@ jobs:
|
|||
# Helm maintains the latest minor version only and therefore each Helmfile version supports 2 Helm minor versions.
|
||||
# That's why we cover only 2 Helm minor versions in this matrix.
|
||||
# See https://github.com/helmfile/helmfile/pull/286#issuecomment-1250161182 for more context.
|
||||
- helm-version: v3.17.4
|
||||
- helm-version: v3.18.6
|
||||
kustomize-version: v5.2.1
|
||||
plugin-secrets-version: 4.6.5
|
||||
plugin-diff-version: 3.11.0
|
||||
extra-helmfile-flags: ''
|
||||
- helm-version: v3.17.4
|
||||
- helm-version: v3.18.6
|
||||
kustomize-version: v5.4.3
|
||||
# We assume that the helm-secrets plugin is supposed to
|
||||
# work with the two most recent helm minor versions.
|
||||
|
|
@ -67,32 +67,32 @@ jobs:
|
|||
# we will mark this combination as failable,
|
||||
# and instruct users to upgrade helm and helm-secrets at once.
|
||||
plugin-secrets-version: 4.6.5
|
||||
plugin-diff-version: 3.12.3
|
||||
plugin-diff-version: 3.12.5
|
||||
extra-helmfile-flags: ''
|
||||
- helm-version: v3.18.4
|
||||
- helm-version: v3.19.0
|
||||
kustomize-version: v5.2.1
|
||||
plugin-secrets-version: 4.6.5
|
||||
plugin-diff-version: 3.11.0
|
||||
extra-helmfile-flags: ''
|
||||
- helm-version: v3.18.4
|
||||
- helm-version: v3.19.0
|
||||
kustomize-version: v5.4.3
|
||||
plugin-secrets-version: 4.6.5
|
||||
plugin-diff-version: 3.12.3
|
||||
plugin-diff-version: 3.12.5
|
||||
extra-helmfile-flags: ''
|
||||
# In case you need to test some optional helmfile features,
|
||||
# enable it via extra-helmfile-flags below.
|
||||
- helm-version: v3.18.4
|
||||
- helm-version: v3.19.0
|
||||
kustomize-version: v5.4.3
|
||||
plugin-secrets-version: 4.6.5
|
||||
plugin-diff-version: 3.12.3
|
||||
plugin-diff-version: 3.12.5
|
||||
extra-helmfile-flags: '--enable-live-output'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: built-binaries-${{ github.run_id }}
|
||||
- name: install semver
|
||||
|
|
@ -109,6 +109,8 @@ jobs:
|
|||
run: make -C .github/workflows helm vault sops kustomize
|
||||
- name: Start minikube
|
||||
uses: medyagh/setup-minikube@latest
|
||||
with:
|
||||
kubernetes-version: v1.33.1
|
||||
- name: Execute integration tests
|
||||
run: make integration
|
||||
env:
|
||||
|
|
@ -122,10 +124,10 @@ jobs:
|
|||
needs: tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: built-binaries-${{ github.run_id }}
|
||||
- name: Extract tar to get built binaries
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ jobs:
|
|||
suffix: "-ubuntu"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
|
|
|||
|
|
@ -22,12 +22,14 @@ jobs:
|
|||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
- name: check disk usage
|
||||
run: df -h
|
||||
- uses: goreleaser/goreleaser-action@v6
|
||||
with:
|
||||
version: latest
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ ENV HELM_CONFIG_HOME="${HELM_CONFIG_HOME}"
|
|||
ARG HELM_DATA_HOME="${HOME}/.local/share/helm"
|
||||
ENV HELM_DATA_HOME="${HELM_DATA_HOME}"
|
||||
|
||||
ARG HELM_VERSION="v3.18.4"
|
||||
ARG HELM_VERSION="v3.19.0"
|
||||
ENV HELM_VERSION="${HELM_VERSION}"
|
||||
ARG HELM_LOCATION="https://get.helm.sh"
|
||||
ARG HELM_FILENAME="helm-${HELM_VERSION}-${TARGETOS}-${TARGETARCH}.tar.gz"
|
||||
|
|
@ -38,8 +38,8 @@ RUN set -x && \
|
|||
curl --retry 5 --retry-connrefused -LO "${HELM_LOCATION}/${HELM_FILENAME}" && \
|
||||
echo Verifying ${HELM_FILENAME}... && \
|
||||
case ${TARGETPLATFORM} in \
|
||||
"linux/amd64") HELM_SHA256="f8180838c23d7c7d797b208861fecb591d9ce1690d8704ed1e4cb8e2add966c1" ;; \
|
||||
"linux/arm64") HELM_SHA256="c0a45e67eef0c7416a8a8c9e9d5d2d30d70e4f4d3f7bea5de28241fffa8f3b89" ;; \
|
||||
"linux/amd64") HELM_SHA256="a7f81ce08007091b86d8bd696eb4d86b8d0f2e1b9f6c714be62f82f96a594496" ;; \
|
||||
"linux/arm64") HELM_SHA256="440cf7add0aee27ebc93fada965523c1dc2e0ab340d4348da2215737fc0d76ad" ;; \
|
||||
esac && \
|
||||
echo "${HELM_SHA256} ${HELM_FILENAME}" | sha256sum -c && \
|
||||
echo Extracting ${HELM_FILENAME}... && \
|
||||
|
|
@ -93,7 +93,7 @@ RUN set -x && \
|
|||
[ "$(age --version)" = "${AGE_VERSION}" ] && \
|
||||
[ "$(age-keygen --version)" = "${AGE_VERSION}" ]
|
||||
|
||||
RUN helm plugin install https://github.com/databus23/helm-diff --version v3.12.3 && \
|
||||
RUN helm plugin install https://github.com/databus23/helm-diff --version v3.13.0 && \
|
||||
helm plugin install https://github.com/jkroepke/helm-secrets --version v4.6.5 && \
|
||||
helm plugin install https://github.com/hypnoglow/helm-s3.git --version v0.16.3 && \
|
||||
helm plugin install https://github.com/aslafy-z/helm-git.git --version v1.3.0 && \
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ ENV HELM_CONFIG_HOME="${HELM_CONFIG_HOME}"
|
|||
ARG HELM_DATA_HOME="${HOME}/.local/share/helm"
|
||||
ENV HELM_DATA_HOME="${HELM_DATA_HOME}"
|
||||
|
||||
ARG HELM_VERSION="v3.18.4"
|
||||
ARG HELM_VERSION="v3.19.0"
|
||||
ENV HELM_VERSION="${HELM_VERSION}"
|
||||
ARG HELM_LOCATION="https://get.helm.sh"
|
||||
ARG HELM_FILENAME="helm-${HELM_VERSION}-${TARGETOS}-${TARGETARCH}.tar.gz"
|
||||
|
|
@ -43,8 +43,8 @@ RUN set -x && \
|
|||
curl --retry 5 --retry-connrefused -LO "${HELM_LOCATION}/${HELM_FILENAME}" && \
|
||||
echo Verifying ${HELM_FILENAME}... && \
|
||||
case ${TARGETPLATFORM} in \
|
||||
"linux/amd64") HELM_SHA256="f8180838c23d7c7d797b208861fecb591d9ce1690d8704ed1e4cb8e2add966c1" ;; \
|
||||
"linux/arm64") HELM_SHA256="c0a45e67eef0c7416a8a8c9e9d5d2d30d70e4f4d3f7bea5de28241fffa8f3b89" ;; \
|
||||
"linux/amd64") HELM_SHA256="a7f81ce08007091b86d8bd696eb4d86b8d0f2e1b9f6c714be62f82f96a594496" ;; \
|
||||
"linux/arm64") HELM_SHA256="440cf7add0aee27ebc93fada965523c1dc2e0ab340d4348da2215737fc0d76ad" ;; \
|
||||
esac && \
|
||||
echo "${HELM_SHA256} ${HELM_FILENAME}" | sha256sum -c && \
|
||||
echo Extracting ${HELM_FILENAME}... && \
|
||||
|
|
@ -99,7 +99,7 @@ RUN set -x && \
|
|||
[ "$(age --version)" = "${AGE_VERSION}" ] && \
|
||||
[ "$(age-keygen --version)" = "${AGE_VERSION}" ]
|
||||
|
||||
RUN helm plugin install https://github.com/databus23/helm-diff --version v3.12.3 && \
|
||||
RUN helm plugin install https://github.com/databus23/helm-diff --version v3.13.0 && \
|
||||
helm plugin install https://github.com/jkroepke/helm-secrets --version v4.6.5 && \
|
||||
helm plugin install https://github.com/hypnoglow/helm-s3.git --version v0.16.3 && \
|
||||
helm plugin install https://github.com/aslafy-z/helm-git.git --version v1.3.0 && \
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ RUN make static-${TARGETOS}-${TARGETARCH}
|
|||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
FROM ubuntu:24.10
|
||||
FROM ubuntu:24.04
|
||||
|
||||
LABEL org.opencontainers.image.source=https://github.com/helmfile/helmfile
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ ENV HELM_CONFIG_HOME="${HELM_CONFIG_HOME}"
|
|||
ARG HELM_DATA_HOME="${HOME}/.local/share/helm"
|
||||
ENV HELM_DATA_HOME="${HELM_DATA_HOME}"
|
||||
|
||||
ARG HELM_VERSION="v3.18.4"
|
||||
ARG HELM_VERSION="v3.19.0"
|
||||
ENV HELM_VERSION="${HELM_VERSION}"
|
||||
ARG HELM_LOCATION="https://get.helm.sh"
|
||||
ARG HELM_FILENAME="helm-${HELM_VERSION}-${TARGETOS}-${TARGETARCH}.tar.gz"
|
||||
|
|
@ -43,8 +43,8 @@ RUN set -x && \
|
|||
curl --retry 5 --retry-connrefused -LO "${HELM_LOCATION}/${HELM_FILENAME}" && \
|
||||
echo Verifying ${HELM_FILENAME}... && \
|
||||
case ${TARGETPLATFORM} in \
|
||||
"linux/amd64") HELM_SHA256="f8180838c23d7c7d797b208861fecb591d9ce1690d8704ed1e4cb8e2add966c1" ;; \
|
||||
"linux/arm64") HELM_SHA256="c0a45e67eef0c7416a8a8c9e9d5d2d30d70e4f4d3f7bea5de28241fffa8f3b89" ;; \
|
||||
"linux/amd64") HELM_SHA256="a7f81ce08007091b86d8bd696eb4d86b8d0f2e1b9f6c714be62f82f96a594496" ;; \
|
||||
"linux/arm64") HELM_SHA256="440cf7add0aee27ebc93fada965523c1dc2e0ab340d4348da2215737fc0d76ad" ;; \
|
||||
esac && \
|
||||
echo "${HELM_SHA256} ${HELM_FILENAME}" | sha256sum -c && \
|
||||
echo Extracting ${HELM_FILENAME}... && \
|
||||
|
|
@ -99,7 +99,7 @@ RUN set -x && \
|
|||
[ "$(age --version)" = "${AGE_VERSION}" ] && \
|
||||
[ "$(age-keygen --version)" = "${AGE_VERSION}" ]
|
||||
|
||||
RUN helm plugin install https://github.com/databus23/helm-diff --version v3.12.3 && \
|
||||
RUN helm plugin install https://github.com/databus23/helm-diff --version v3.13.0 && \
|
||||
helm plugin install https://github.com/jkroepke/helm-secrets --version v4.6.5 && \
|
||||
helm plugin install https://github.com/hypnoglow/helm-s3.git --version v0.16.3 && \
|
||||
helm plugin install https://github.com/aslafy-z/helm-git.git --version v1.3.0 && \
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ Helmfile is a declarative spec for deploying helm charts. It lets you...
|
|||
* Apply CI/CD to configuration changes.
|
||||
* Periodically sync to avoid skew in environments.
|
||||
|
||||
To avoid upgrades for each iteration of `helm`, the `helmfile` executable delegates to `helm` - as a result, `helm` must be installed.
|
||||
To avoid upgrades for each iteration of `helm`, the `helmfile` executable delegates to `helm` - as a result, the following must be installed
|
||||
- [helm](https://helm.sh/docs/intro/install/)
|
||||
- [helm-diff](https://github.com/databus23/helm-diff)
|
||||
|
||||
## Highlights
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ func NewRootCmd(globalConfig *config.GlobalOptions) (*cobra.Command, error) {
|
|||
// Set the global options for the root command.
|
||||
setGlobalOptionsForRootCmd(flags, globalConfig)
|
||||
|
||||
flags.ParseErrorsWhitelist.UnknownFlags = true
|
||||
flags.ParseErrorsAllowlist.UnknownFlags = true
|
||||
|
||||
globalImpl := config.NewGlobalImpl(globalConfig)
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ func NewSyncCmd(globalCfg *config.GlobalImpl) *cobra.Command {
|
|||
f.BoolVar(&syncOptions.SyncReleaseLabels, "sync-release-labels", false, "sync release labels to the target release")
|
||||
f.BoolVar(&syncOptions.Wait, "wait", false, `Override helmDefaults.wait setting "helm upgrade --install --wait"`)
|
||||
f.BoolVar(&syncOptions.WaitForJobs, "wait-for-jobs", false, `Override helmDefaults.waitForJobs setting "helm upgrade --install --wait-for-jobs"`)
|
||||
f.IntVar(&syncOptions.Timeout, "timeout", 0, `Override helmDefaults.timeout setting "helm upgrade --install --timeout" (default 0, which means no timeout)`)
|
||||
f.BoolVar(&syncOptions.ReuseValues, "reuse-values", false, `Override helmDefaults.reuseValues "helm upgrade --install --reuse-values"`)
|
||||
f.BoolVar(&syncOptions.ResetValues, "reset-values", false, `Override helmDefaults.reuseValues "helm upgrade --install --reset-values"`)
|
||||
f.StringVar(&syncOptions.PostRenderer, "post-renderer", "", `pass --post-renderer to "helm template" or "helm upgrade --install"`)
|
||||
|
|
|
|||
|
|
@ -194,8 +194,9 @@ helmDefaults:
|
|||
skipSchemaValidation: false
|
||||
# wait for k8s resources via --wait. (default false)
|
||||
wait: true
|
||||
# if set and --wait enabled, will retry any failed check on resource state subject to the specified number of retries (default 0)
|
||||
waitRetries: 3
|
||||
# DEPRECATED: waitRetries is no longer supported as the --wait-retries flag was removed from Helm.
|
||||
# This configuration is ignored and preserved only for backward compatibility.
|
||||
# waitRetries: 3
|
||||
# if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout (default false, Implemented in Helm3.5)
|
||||
waitForJobs: true
|
||||
# time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks, and waits on pod/pvc/svc/deployment readiness) (default 300)
|
||||
|
|
@ -318,7 +319,8 @@ releases:
|
|||
# --skip-schema-validation flag to helm 'install', 'upgrade' and 'lint', starts with helm 3.16.0 (default false)
|
||||
skipSchemaValidation: false
|
||||
wait: true
|
||||
waitRetries: 3
|
||||
# DEPRECATED: waitRetries is no longer supported - see documentation above
|
||||
# waitRetries: 3
|
||||
waitForJobs: true
|
||||
timeout: 60
|
||||
recreatePods: true
|
||||
|
|
@ -649,6 +651,8 @@ Flags:
|
|||
Use "helmfile [command] --help" for more information about a command.
|
||||
```
|
||||
|
||||
**Note:** Each command has its own specific flags. Use `helmfile [command] --help` to see command-specific options. For example, `helmfile sync --help` shows operational flags like `--timeout`, `--wait`, and `--wait-for-jobs`.
|
||||
|
||||
### init
|
||||
|
||||
The `helmfile init` sub-command checks the dependencies required for helmfile operation, such as `helm`, `helm diff plugin`, `helm secrets plugin`, `helm helm-git plugin`, `helm s3 plugin`. When it does not exist or the version is too low, it can be installed automatically.
|
||||
|
|
@ -664,6 +668,25 @@ The `helmfile sync` sub-command sync your cluster state as described in your `he
|
|||
Under the covers, Helmfile executes `helm upgrade --install` for each `release` declared in the manifest, by optionally decrypting [secrets](#secrets) to be consumed as helm chart values. It also updates specified chart repositories and updates the
|
||||
dependencies of any referenced local charts.
|
||||
|
||||
#### Common sync flags
|
||||
|
||||
* `--timeout SECONDS` - Override the default timeout for all releases in this sync operation. This takes precedence over `helmDefaults.timeout` and per-release `timeout` settings.
|
||||
* `--wait` - Override the default wait behavior for all releases
|
||||
* `--wait-for-jobs` - Override the default wait-for-jobs behavior for all releases
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
# Override timeout for all releases to 10 minutes
|
||||
helmfile sync --timeout 600
|
||||
|
||||
# Combine timeout with wait flags
|
||||
helmfile sync --timeout 900 --wait --wait-for-jobs
|
||||
|
||||
# Target specific releases with custom timeout
|
||||
helmfile sync --selector tier=backend --timeout 1200
|
||||
```
|
||||
|
||||
For Helm 2.9+ you can use a username and password to authenticate to a remote repository.
|
||||
|
||||
### deps
|
||||
|
|
|
|||
225
go.mod
225
go.mod
|
|
@ -1,6 +1,6 @@
|
|||
module github.com/helmfile/helmfile
|
||||
|
||||
go 1.24.2
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.2
|
||||
|
|
@ -11,32 +11,32 @@ require (
|
|||
github.com/golang/mock v1.6.0
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/gosuri/uitable v0.0.4
|
||||
github.com/hashicorp/go-getter v1.7.8
|
||||
github.com/hashicorp/go-getter v1.8.1
|
||||
github.com/hashicorp/hcl/v2 v2.24.0
|
||||
github.com/helmfile/chartify v0.24.6
|
||||
github.com/helmfile/vals v0.41.3
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spf13/pflag v1.0.7
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/helmfile/chartify v0.25.0
|
||||
github.com/helmfile/vals v0.42.1
|
||||
github.com/spf13/cobra v1.10.1
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/tatsushid/go-prettytable v0.0.0-20141013043238-ed2d14c29939
|
||||
github.com/tj/assert v0.0.3
|
||||
github.com/variantdev/dag v1.1.0
|
||||
github.com/zclconf/go-cty v1.16.3
|
||||
github.com/zclconf/go-cty v1.17.0
|
||||
github.com/zclconf/go-cty-yaml v1.1.0
|
||||
go.szostok.io/version v1.2.0
|
||||
go.uber.org/zap v1.27.0
|
||||
go.yaml.in/yaml/v2 v2.4.2
|
||||
go.yaml.in/yaml/v2 v2.4.3
|
||||
go.yaml.in/yaml/v3 v3.0.4
|
||||
golang.org/x/sync v0.16.0
|
||||
golang.org/x/term v0.33.0
|
||||
helm.sh/helm/v3 v3.18.4
|
||||
k8s.io/apimachinery v0.33.3
|
||||
golang.org/x/sync v0.17.0
|
||||
golang.org/x/term v0.35.0
|
||||
helm.sh/helm/v3 v3.19.0
|
||||
k8s.io/apimachinery v0.34.1
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.116.0 // indirect
|
||||
cloud.google.com/go/iam v1.2.2 // indirect
|
||||
cloud.google.com/go/storage v1.50.0 // indirect
|
||||
cloud.google.com/go v0.121.6 // indirect
|
||||
cloud.google.com/go/iam v1.5.2 // indirect
|
||||
cloud.google.com/go/storage v1.56.1 // indirect
|
||||
filippo.io/age v1.2.1 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect
|
||||
|
|
@ -51,24 +51,24 @@ require (
|
|||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/fatih/color v1.18.0
|
||||
github.com/fujiwara/tfstate-lookup v1.6.0 // indirect
|
||||
github.com/fujiwara/tfstate-lookup v1.7.0 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
|
||||
github.com/goware/prefixer v0.0.0-20160118172347-395022866408 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||
github.com/hashicorp/go-slug v0.16.3 // indirect
|
||||
github.com/hashicorp/go-slug v0.16.4 // indirect
|
||||
github.com/hashicorp/go-sockaddr v1.0.7 // indirect
|
||||
github.com/hashicorp/go-tfe v1.56.0 // indirect
|
||||
github.com/hashicorp/go-tfe v1.84.0 // indirect
|
||||
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
||||
github.com/hashicorp/hcl v1.0.1-vault-7 // indirect
|
||||
github.com/hashicorp/jsonapi v1.3.1 // indirect
|
||||
github.com/hashicorp/jsonapi v1.4.3-0.20250220162346-81a76b606f3e // indirect
|
||||
github.com/hashicorp/vault/api v1.20.0 // indirect
|
||||
github.com/huandu/xstrings v1.5.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
|
|
@ -76,11 +76,10 @@ require (
|
|||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
|
|
@ -91,114 +90,116 @@ require (
|
|||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/cast v1.7.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.15 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
golang.org/x/time v0.9.0 // indirect
|
||||
google.golang.org/api v0.215.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
|
||||
google.golang.org/grpc v1.68.1 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
golang.org/x/sys v0.36.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
google.golang.org/api v0.248.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/grpc v1.74.2 // indirect
|
||||
google.golang.org/protobuf v1.36.7 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
al.essio.dev/pkg/shellescape v1.5.1 // indirect
|
||||
cel.dev/expr v0.19.1 // indirect
|
||||
cloud.google.com/go/auth v0.13.0 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
||||
cloud.google.com/go/kms v1.20.5 // indirect
|
||||
cloud.google.com/go/longrunning v0.6.2 // indirect
|
||||
cloud.google.com/go/monitoring v1.21.2 // indirect
|
||||
cloud.google.com/go/secretmanager v1.14.3 // indirect
|
||||
al.essio.dev/pkg/shellescape v1.6.0 // indirect
|
||||
cel.dev/expr v0.24.0 // indirect
|
||||
cloud.google.com/go/auth v0.16.5 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.8.0 // indirect
|
||||
cloud.google.com/go/kms v1.22.0 // indirect
|
||||
cloud.google.com/go/longrunning v0.6.7 // indirect
|
||||
cloud.google.com/go/monitoring v1.24.2 // indirect
|
||||
cloud.google.com/go/secretmanager v1.15.0 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/1Password/connect-sdk-go v1.5.3 // indirect
|
||||
github.com/1password/onepassword-sdk-go v0.3.1 // indirect
|
||||
github.com/AlecAivazis/survey/v2 v2.3.6 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.3.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.11.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.4.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
|
||||
github.com/DopplerHQ/cli v0.5.11-0.20230908185655-7aef4713e1a4 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Masterminds/squirrel v1.5.4 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.3 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.2.0 // indirect
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/antchfx/jsonquery v1.3.6 // indirect
|
||||
github.com/antchfx/xpath v1.3.4 // indirect
|
||||
github.com/antchfx/xpath v1.3.5 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/atotto/clipboard v0.1.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.38.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.68 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.72 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.37.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.79.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.38.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.80.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.39.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.64.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 // indirect
|
||||
github.com/aws/smithy-go v1.22.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.20 // indirect
|
||||
github.com/aws/smithy-go v1.23.0 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect
|
||||
github.com/containerd/containerd v1.7.27 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
|
||||
github.com/containerd/containerd v1.7.28 // indirect
|
||||
github.com/containerd/errdefs v0.3.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/platforms v0.2.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
github.com/cyberark/conjur-api-go v0.13.1 // indirect
|
||||
github.com/cyberark/conjur-api-go v0.13.3 // indirect
|
||||
github.com/danieljoos/wincred v1.2.2 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/dylibso/observe-sdk/go v0.0.0-20240819160327-2d926c5d788a // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.13.1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||
github.com/extism/go-sdk v1.7.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/getsops/gopgagent v0.0.0-20240527072608-0c14999532fe // indirect
|
||||
github.com/getsops/sops/v3 v3.9.2 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/getsops/gopgagent v0.0.0-20241224165529-7044f28e491e // indirect
|
||||
github.com/getsops/sops/v3 v3.10.2 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/analysis v0.23.0 // indirect
|
||||
github.com/go-openapi/errors v0.22.1 // indirect
|
||||
github.com/go-openapi/errors v0.22.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/loads v0.22.0 // indirect
|
||||
|
|
@ -211,20 +212,21 @@ require (
|
|||
github.com/goccy/go-yaml v1.17.1 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/gnostic-models v0.6.9 // indirect
|
||||
github.com/google/gnostic-models v0.7.0 // indirect
|
||||
github.com/google/go-jsonnet v0.20.0 // indirect
|
||||
github.com/google/s2a-go v0.1.8 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
|
||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||
github.com/hashicorp/hcp-sdk-go v0.151.0 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/hashicorp/hcp-sdk-go v0.155.0 // indirect
|
||||
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f // indirect
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20240805132620-81f5be970eca // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.6 // indirect
|
||||
|
|
@ -244,7 +246,7 @@ require (
|
|||
github.com/moby/spdystream v0.5.0 // indirect
|
||||
github.com/moby/term v0.5.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/muesli/termenv v0.15.1 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
|
|
@ -261,6 +263,7 @@ require (
|
|||
github.com/rubenv/sql-migrate v1.8.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
|
||||
github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834 // indirect
|
||||
github.com/tetratelabs/wazero v1.9.0 // indirect
|
||||
github.com/tidwall/gjson v1.18.0 // indirect
|
||||
|
|
@ -272,42 +275,44 @@ require (
|
|||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
github.com/yandex-cloud/go-genproto v0.19.0 // indirect
|
||||
github.com/yandex-cloud/go-sdk v0.15.0 // indirect
|
||||
github.com/zalando/go-keyring v0.2.6 // indirect
|
||||
github.com/zeebo/errs v1.4.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.14.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.29.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
|
||||
go.opentelemetry.io/otel v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.33.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.36.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.39.0 // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a // indirect
|
||||
golang.org/x/crypto v0.41.0 // indirect
|
||||
golang.org/x/mod v0.26.0 // indirect
|
||||
golang.org/x/tools v0.35.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/gookit/color.v1 v1.1.6 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.33.2 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.33.2 // indirect
|
||||
k8s.io/cli-runtime v0.33.2 // indirect
|
||||
k8s.io/client-go v0.33.2 // indirect
|
||||
k8s.io/component-base v0.33.2 // indirect
|
||||
k8s.io/api v0.34.0 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.34.0 // indirect
|
||||
k8s.io/cli-runtime v0.34.0 // indirect
|
||||
k8s.io/client-go v0.34.0 // indirect
|
||||
k8s.io/component-base v0.34.0 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||
k8s.io/kubectl v0.33.2 // indirect
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect
|
||||
k8s.io/kubectl v0.34.0 // indirect
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
|
||||
oras.land/oras-go/v2 v2.6.0 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.19.0 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.19.0 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.20.1 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.20.1 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -784,7 +784,7 @@ func createHelmKey(bin, kubectx string) helmKey {
|
|||
//
|
||||
// This is currently used for running all the helm commands for reconciling releases. But this may change in the future
|
||||
// once we enable each release to have its own helm binary/version.
|
||||
func (a *App) getHelm(st *state.HelmState) helmexec.Interface {
|
||||
func (a *App) getHelm(st *state.HelmState) (helmexec.Interface, error) {
|
||||
a.helmsMutex.Lock()
|
||||
defer a.helmsMutex.Unlock()
|
||||
|
||||
|
|
@ -799,14 +799,18 @@ func (a *App) getHelm(st *state.HelmState) helmexec.Interface {
|
|||
key := createHelmKey(bin, kubectx)
|
||||
|
||||
if _, ok := a.helms[key]; !ok {
|
||||
a.helms[key] = helmexec.New(bin, helmexec.HelmExecOptions{EnableLiveOutput: a.EnableLiveOutput, DisableForceUpdate: a.DisableForceUpdate}, a.Logger, kubeconfig, kubectx, &helmexec.ShellRunner{
|
||||
exec, err := helmexec.New(bin, helmexec.HelmExecOptions{EnableLiveOutput: a.EnableLiveOutput, DisableForceUpdate: a.DisableForceUpdate}, a.Logger, kubeconfig, kubectx, &helmexec.ShellRunner{
|
||||
Logger: a.Logger,
|
||||
Ctx: a.ctx,
|
||||
StripArgsValuesOnExitError: a.StripArgsValuesOnExitError,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a.helms[key] = exec
|
||||
}
|
||||
|
||||
return a.helms[key]
|
||||
return a.helms[key], nil
|
||||
}
|
||||
|
||||
func (a *App) visitStates(fileOrDir string, defOpts LoadOpts, converge func(*state.HelmState) (bool, []error)) error {
|
||||
|
|
@ -958,7 +962,10 @@ var (
|
|||
func (a *App) ForEachState(do func(*Run) (bool, []error), includeTransitiveNeeds bool, o ...LoadOption) error {
|
||||
ctx := NewContext()
|
||||
err := a.visitStatesWithSelectorsAndRemoteSupport(a.FileOrDir, func(st *state.HelmState) (bool, []error) {
|
||||
helm := a.getHelm(st)
|
||||
helm, err := a.getHelm(st)
|
||||
if err != nil {
|
||||
return false, []error{err}
|
||||
}
|
||||
|
||||
run, err := NewRun(st, helm, ctx)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -2583,9 +2583,12 @@ func (mock *mockRunner) Execute(cmd string, args []string, env map[string]string
|
|||
return []byte{}, nil
|
||||
}
|
||||
|
||||
func MockExecer(logger *zap.SugaredLogger, kubeContext string) helmexec.Interface {
|
||||
execer := helmexec.New("helm", helmexec.HelmExecOptions{}, logger, "", kubeContext, &mockRunner{})
|
||||
return execer
|
||||
func MockExecer(logger *zap.SugaredLogger, kubeContext string) (helmexec.Interface, error) {
|
||||
execer, err := helmexec.New("helm", helmexec.HelmExecOptions{}, logger, "", kubeContext, &mockRunner{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return execer, nil
|
||||
}
|
||||
|
||||
// mocking helmexec.Interface
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ type desiredStateLoader struct {
|
|||
chart string
|
||||
fs *filesystem.FileSystem
|
||||
|
||||
getHelm func(*state.HelmState) helmexec.Interface
|
||||
getHelm func(*state.HelmState) (helmexec.Interface, error)
|
||||
|
||||
remote *remote.Remote
|
||||
logger *zap.SugaredLogger
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
HelmRequiredVersion = "v3.17.4"
|
||||
HelmDiffRecommendedVersion = "v3.12.3"
|
||||
HelmRecommendedVersion = "v3.18.4"
|
||||
HelmRequiredVersion = "v3.18.6"
|
||||
HelmDiffRecommendedVersion = "v3.13.0"
|
||||
HelmRecommendedVersion = "v3.19.0"
|
||||
HelmSecretsRecommendedVersion = "v4.6.5"
|
||||
HelmGitRecommendedVersion = "v1.3.0"
|
||||
HelmS3RecommendedVersion = "v0.16.3"
|
||||
|
|
@ -163,7 +163,10 @@ func (h *HelmfileInit) WhetherContinue(ask string) error {
|
|||
|
||||
func (h *HelmfileInit) CheckHelmPlugins() error {
|
||||
settings := cli.New()
|
||||
helm := helmexec.New(h.helmBinary, helmexec.HelmExecOptions{}, h.logger, "", "", h.runner)
|
||||
helm, err := helmexec.New(h.helmBinary, helmexec.HelmExecOptions{}, h.logger, "", "", h.runner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range helmPlugins {
|
||||
pluginVersion, err := helmexec.GetPluginVersion(p.name, settings.PluginsDirectory)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ type SyncOptions struct {
|
|||
WaitRetries int
|
||||
// WaitForJobs is the wait for jobs flag
|
||||
WaitForJobs bool
|
||||
// Timeout is the timeout flag in seconds
|
||||
Timeout int
|
||||
// ReuseValues is true if the helm command should reuse the values
|
||||
ReuseValues bool
|
||||
// ResetValues is true if helm command should reset values to charts' default
|
||||
|
|
@ -124,6 +126,11 @@ func (t *SyncImpl) WaitForJobs() bool {
|
|||
return t.SyncOptions.WaitForJobs
|
||||
}
|
||||
|
||||
// Timeout returns the timeout
|
||||
func (t *SyncImpl) Timeout() int {
|
||||
return t.SyncOptions.Timeout
|
||||
}
|
||||
|
||||
// ReuseValues returns the ReuseValues.
|
||||
func (t *SyncImpl) ReuseValues() bool {
|
||||
if !t.ResetValues() {
|
||||
|
|
|
|||
|
|
@ -69,7 +69,13 @@ func parseHelmVersion(versionStr string) (*semver.Version, error) {
|
|||
return nil, fmt.Errorf("empty helm version")
|
||||
}
|
||||
|
||||
v, err := chartify.FindSemVerInfo(versionStr)
|
||||
// Check if version string starts with "v", if not add it
|
||||
processedVersion := strings.TrimSpace(versionStr)
|
||||
if !strings.HasPrefix(processedVersion, "v") {
|
||||
processedVersion = "v" + processedVersion
|
||||
}
|
||||
|
||||
v, err := chartify.FindSemVerInfo(processedVersion)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error find helm srmver version '%s': %w", versionStr, err)
|
||||
|
|
@ -116,11 +122,10 @@ func redactedURL(chart string) string {
|
|||
}
|
||||
|
||||
// New for running helm commands
|
||||
func New(helmBinary string, options HelmExecOptions, logger *zap.SugaredLogger, kubeconfig string, kubeContext string, runner Runner) *execer {
|
||||
// TODO: proper error handling
|
||||
func New(helmBinary string, options HelmExecOptions, logger *zap.SugaredLogger, kubeconfig string, kubeContext string, runner Runner) (*execer, error) {
|
||||
version, err := GetHelmVersion(helmBinary, runner)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if version.Prerelease() != "" {
|
||||
|
|
@ -137,7 +142,7 @@ func New(helmBinary string, options HelmExecOptions, logger *zap.SugaredLogger,
|
|||
kubeContext: kubeContext,
|
||||
runner: runner,
|
||||
decryptedSecrets: make(map[string]*decryptedSecret),
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (helm *execer) SetExtraArgs(args ...string) {
|
||||
|
|
|
|||
|
|
@ -36,16 +36,22 @@ func (mock *mockRunner) Execute(cmd string, args []string, env map[string]string
|
|||
return mock.output, mock.err
|
||||
}
|
||||
|
||||
func MockExecer(logger *zap.SugaredLogger, kubeconfig, kubeContext string) *execer {
|
||||
execer := New("helm", HelmExecOptions{}, logger, kubeconfig, kubeContext, &mockRunner{})
|
||||
return execer
|
||||
func MockExecer(logger *zap.SugaredLogger, kubeconfig, kubeContext string) (*execer, error) {
|
||||
execer, err := New("helm", HelmExecOptions{}, logger, kubeconfig, kubeContext, &mockRunner{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return execer, nil
|
||||
}
|
||||
|
||||
// Test methods
|
||||
|
||||
func TestNewHelmExec(t *testing.T) {
|
||||
buffer := bytes.NewBufferString("something")
|
||||
helm := MockExecer(NewLogger(buffer, "debug"), "config", "dev")
|
||||
helm, err := MockExecer(NewLogger(buffer, "debug"), "config", "dev")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if helm.kubeContext != "dev" {
|
||||
t.Error("helmexec.New() - kubeContext")
|
||||
}
|
||||
|
|
@ -58,7 +64,10 @@ func TestNewHelmExec(t *testing.T) {
|
|||
}
|
||||
|
||||
func Test_SetExtraArgs(t *testing.T) {
|
||||
helm := MockExecer(NewLogger(os.Stdout, "info"), "config", "dev")
|
||||
helm, err := MockExecer(NewLogger(os.Stdout, "info"), "config", "dev")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
helm.SetExtraArgs()
|
||||
if len(helm.extra) != 0 {
|
||||
t.Error("helmexec.SetExtraArgs() - passing no arguments should not change extra field")
|
||||
|
|
@ -74,7 +83,10 @@ func Test_SetExtraArgs(t *testing.T) {
|
|||
}
|
||||
|
||||
func Test_SetHelmBinary(t *testing.T) {
|
||||
helm := MockExecer(NewLogger(os.Stdout, "info"), "config", "dev")
|
||||
helm, err := MockExecer(NewLogger(os.Stdout, "info"), "config", "dev")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if helm.helmBinary != "helm" {
|
||||
t.Error("helmexec.command - default command is not helm")
|
||||
}
|
||||
|
|
@ -85,7 +97,10 @@ func Test_SetHelmBinary(t *testing.T) {
|
|||
}
|
||||
|
||||
func Test_SetEnableLiveOutput(t *testing.T) {
|
||||
helm := MockExecer(NewLogger(os.Stdout, "info"), "config", "dev")
|
||||
helm, err := MockExecer(NewLogger(os.Stdout, "info"), "config", "dev")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if helm.options.EnableLiveOutput {
|
||||
t.Error("helmexec.options.EnableLiveOutput should not be enabled by default")
|
||||
}
|
||||
|
|
@ -96,7 +111,10 @@ func Test_SetEnableLiveOutput(t *testing.T) {
|
|||
}
|
||||
|
||||
func Test_SetDisableForceUpdate(t *testing.T) {
|
||||
helm := MockExecer(NewLogger(os.Stdout, "info"), "config", "dev")
|
||||
helm, err := MockExecer(NewLogger(os.Stdout, "info"), "config", "dev")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if helm.options.DisableForceUpdate {
|
||||
t.Error("helmexec.options.ForceUpdate should not be enabled by default")
|
||||
}
|
||||
|
|
@ -155,11 +173,14 @@ exec: helm --kubeconfig config --kube-context dev repo add myRepo https://repo.e
|
|||
func Test_AddRepo(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Test case with certfile and keyfile
|
||||
buffer.Reset()
|
||||
err := helm.AddRepo("myRepo", "https://repo.example.com/", "", "cert.pem", "key.pem", "", "", "", false, false)
|
||||
err = helm.AddRepo("myRepo", "https://repo.example.com/", "", "cert.pem", "key.pem", "", "", "", false, false)
|
||||
expected := `Adding repo myRepo https://repo.example.com/
|
||||
exec: helm --kubeconfig config --kube-context dev repo add myRepo https://repo.example.com/ --cert-file cert.pem --key-file key.pem
|
||||
`
|
||||
|
|
@ -292,8 +313,11 @@ exec: helm --kubeconfig config --kube-context dev repo add myRepo https://repo.e
|
|||
func Test_UpdateRepo(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
err := helm.UpdateRepo()
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.UpdateRepo()
|
||||
expected := `Updating repo
|
||||
exec: helm --kubeconfig config --kube-context dev repo update
|
||||
`
|
||||
|
|
@ -346,8 +370,11 @@ exec: helm --kubeconfig config --kube-context dev registry login repo.example.co
|
|||
func Test_SyncRelease(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
err := helm.SyncRelease(HelmContext{}, "release", "chart", "default", "--timeout 10", "--wait", "--wait-for-jobs")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.SyncRelease(HelmContext{}, "release", "chart", "default", "--timeout 10", "--wait", "--wait-for-jobs")
|
||||
expected := `Upgrading release=release, chart=chart, namespace=default
|
||||
exec: helm --kubeconfig config --kube-context dev upgrade --install release chart --timeout 10 --wait --wait-for-jobs --history-max 0
|
||||
`
|
||||
|
|
@ -386,8 +413,11 @@ exec: helm --kubeconfig config --kube-context dev upgrade --install release http
|
|||
func Test_UpdateDeps(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
err := helm.UpdateDeps("./chart/foo")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.UpdateDeps("./chart/foo")
|
||||
expected := `Updating dependency ./chart/foo
|
||||
exec: helm --kubeconfig config --kube-context dev dependency update ./chart/foo
|
||||
`
|
||||
|
|
@ -416,8 +446,11 @@ func Test_BuildDeps(t *testing.T) {
|
|||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm3Runner := mockRunner{output: []byte("v3.2.4+ge29ce2a")}
|
||||
helm := New("helm", HelmExecOptions{}, logger, "config", "dev", &helm3Runner)
|
||||
err := helm.BuildDeps("foo", "./chart/foo", []string{"--skip-refresh"}...)
|
||||
helm, err := New("helm", HelmExecOptions{}, logger, "config", "dev", &helm3Runner)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.BuildDeps("foo", "./chart/foo", []string{"--skip-refresh"}...)
|
||||
expected := `Building dependency release=foo, chart=./chart/foo
|
||||
exec: helm --kubeconfig config --kube-context dev dependency build ./chart/foo --skip-refresh
|
||||
v3.2.4+ge29ce2a
|
||||
|
|
@ -458,7 +491,10 @@ v3.2.4+ge29ce2a
|
|||
|
||||
buffer.Reset()
|
||||
helm2Runner := mockRunner{output: []byte("Client: v2.16.1+ge13bc94")}
|
||||
helm = New("helm", HelmExecOptions{}, logger, "config", "dev", &helm2Runner)
|
||||
helm, err = New("helm", HelmExecOptions{}, logger, "config", "dev", &helm2Runner)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.BuildDeps("foo", "./chart/foo")
|
||||
expected = `Building dependency release=foo, chart=./chart/foo
|
||||
exec: helm --kubeconfig config --kube-context dev dependency build ./chart/foo
|
||||
|
|
@ -484,14 +520,17 @@ func Test_DecryptSecret(t *testing.T) {
|
|||
}()
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
tmpFilePath := "path/to/temp/file"
|
||||
helm.writeTempFile = func(content []byte) (string, error) {
|
||||
return tmpFilePath, nil
|
||||
}
|
||||
|
||||
_, err := helm.DecryptSecret(HelmContext{}, "secretName")
|
||||
_, err = helm.DecryptSecret(HelmContext{}, "secretName")
|
||||
if err != nil {
|
||||
t.Errorf("Error: %v", err)
|
||||
}
|
||||
|
|
@ -533,7 +572,10 @@ func Test_DecryptSecretWithGotmpl(t *testing.T) {
|
|||
}()
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
tmpFilePath := "path/to/temp/file"
|
||||
helm.writeTempFile = func(content []byte) (string, error) {
|
||||
|
|
@ -541,7 +583,7 @@ func Test_DecryptSecretWithGotmpl(t *testing.T) {
|
|||
}
|
||||
|
||||
secretName := "secretName.yaml.gotmpl"
|
||||
_, err := helm.DecryptSecret(HelmContext{}, secretName)
|
||||
_, err = helm.DecryptSecret(HelmContext{}, secretName)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %v", err)
|
||||
}
|
||||
|
|
@ -566,8 +608,11 @@ Decrypted %s/secretName.yaml.gotmpl into %s
|
|||
func Test_DiffRelease(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
err := helm.DiffRelease(HelmContext{}, "release", "chart", "default", false, "--timeout 10", "--wait", "--wait-for-jobs")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.DiffRelease(HelmContext{}, "release", "chart", "default", false, "--timeout 10", "--wait", "--wait-for-jobs")
|
||||
expected := `Comparing release=release, chart=chart, namespace=default
|
||||
|
||||
exec: helm --kubeconfig config --kube-context dev diff upgrade --allow-unreleased release chart --timeout 10 --wait --wait-for-jobs
|
||||
|
|
@ -609,8 +654,11 @@ exec: helm --kubeconfig config --kube-context dev diff upgrade --allow-unrelease
|
|||
func Test_DeleteRelease(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
err := helm.DeleteRelease(HelmContext{}, "release")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.DeleteRelease(HelmContext{}, "release")
|
||||
expected := `Deleting release
|
||||
exec: helm --kubeconfig config --kube-context dev delete release
|
||||
`
|
||||
|
|
@ -624,8 +672,11 @@ exec: helm --kubeconfig config --kube-context dev delete release
|
|||
func Test_DeleteRelease_Flags(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
err := helm.DeleteRelease(HelmContext{}, "release", "--purge")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.DeleteRelease(HelmContext{}, "release", "--purge")
|
||||
expected := `Deleting release
|
||||
exec: helm --kubeconfig config --kube-context dev delete release --purge
|
||||
`
|
||||
|
|
@ -640,8 +691,11 @@ exec: helm --kubeconfig config --kube-context dev delete release --purge
|
|||
func Test_TestRelease(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
err := helm.TestRelease(HelmContext{}, "release")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.TestRelease(HelmContext{}, "release")
|
||||
expected := `Testing release
|
||||
exec: helm --kubeconfig config --kube-context dev test release
|
||||
`
|
||||
|
|
@ -655,8 +709,11 @@ exec: helm --kubeconfig config --kube-context dev test release
|
|||
func Test_TestRelease_Flags(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
err := helm.TestRelease(HelmContext{}, "release", "--cleanup", "--timeout", "60")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.TestRelease(HelmContext{}, "release", "--cleanup", "--timeout", "60")
|
||||
expected := `Testing release
|
||||
exec: helm --kubeconfig config --kube-context dev test release --cleanup --timeout 60
|
||||
`
|
||||
|
|
@ -671,8 +728,11 @@ exec: helm --kubeconfig config --kube-context dev test release --cleanup --timeo
|
|||
func Test_ReleaseStatus(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
err := helm.ReleaseStatus(HelmContext{}, "myRelease")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.ReleaseStatus(HelmContext{}, "myRelease")
|
||||
expected := `Getting status myRelease
|
||||
exec: helm --kubeconfig config --kube-context dev status myRelease
|
||||
`
|
||||
|
|
@ -687,9 +747,12 @@ exec: helm --kubeconfig config --kube-context dev status myRelease
|
|||
func Test_exec(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "", "")
|
||||
helm, err := MockExecer(logger, "", "")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
env := map[string]string{}
|
||||
_, err := helm.exec([]string{"version"}, env, nil)
|
||||
_, err = helm.exec([]string{"version"}, env, nil)
|
||||
expected := `exec: helm version
|
||||
`
|
||||
if err != nil {
|
||||
|
|
@ -699,14 +762,20 @@ func Test_exec(t *testing.T) {
|
|||
t.Errorf("helmexec.exec()\nactual = %v\nexpect = %v", buffer.String(), expected)
|
||||
}
|
||||
|
||||
helm = MockExecer(logger, "config", "dev")
|
||||
helm, err = MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
ret, _ := helm.exec([]string{"diff"}, env, nil)
|
||||
if len(ret) != 0 {
|
||||
t.Error("helmexec.exec() - expected empty return value")
|
||||
}
|
||||
|
||||
buffer.Reset()
|
||||
helm = MockExecer(logger, "config", "dev")
|
||||
helm, err = MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
_, err = helm.exec([]string{"diff", "release", "chart", "--timeout 10", "--wait", "--wait-for-jobs"}, env, nil)
|
||||
expected = `exec: helm --kubeconfig config --kube-context dev diff release chart --timeout 10 --wait --wait-for-jobs
|
||||
`
|
||||
|
|
@ -741,7 +810,10 @@ func Test_exec(t *testing.T) {
|
|||
}
|
||||
|
||||
buffer.Reset()
|
||||
helm = MockExecer(logger, "", "")
|
||||
helm, err = MockExecer(logger, "", "")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
helm.SetHelmBinary("overwritten")
|
||||
_, err = helm.exec([]string{"version"}, env, nil)
|
||||
expected = `exec: overwritten version
|
||||
|
|
@ -757,8 +829,11 @@ func Test_exec(t *testing.T) {
|
|||
func Test_Lint(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
err := helm.Lint("release", "path/to/chart", "--values", "file.yml")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.Lint("release", "path/to/chart", "--values", "file.yml")
|
||||
expected := `Linting release=release, chart=path/to/chart
|
||||
exec: helm --kubeconfig config --kube-context dev lint path/to/chart --values file.yml
|
||||
`
|
||||
|
|
@ -773,8 +848,11 @@ exec: helm --kubeconfig config --kube-context dev lint path/to/chart --values fi
|
|||
func Test_Fetch(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
err := helm.Fetch("chart", "--version", "1.2.3", "--untar", "--untardir", "/tmp/dir")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.Fetch("chart", "--version", "1.2.3", "--untar", "--untardir", "/tmp/dir")
|
||||
expected := `Fetching chart
|
||||
exec: helm --kubeconfig config --kube-context dev fetch chart --version 1.2.3 --untar --untardir /tmp/dir
|
||||
`
|
||||
|
|
@ -848,8 +926,11 @@ exec: helm --kubeconfig config --kube-context dev pull oci://repo/helm-charts --
|
|||
tt := tests[i]
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
buffer.Reset()
|
||||
helm := New(tt.helmBin, HelmExecOptions{}, logger, "config", "dev", &mockRunner{output: []byte(tt.helmVersion)})
|
||||
err := helm.ChartPull(tt.chartName, tt.chartPath, tt.chartFlags...)
|
||||
helm, err := New(tt.helmBin, HelmExecOptions{}, logger, "config", "dev", &mockRunner{output: []byte(tt.helmVersion)})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.ChartPull(tt.chartName, tt.chartPath, tt.chartFlags...)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
@ -922,8 +1003,11 @@ func Test_LogLevels(t *testing.T) {
|
|||
for logLevel, expected := range logLevelTests {
|
||||
buffer.Reset()
|
||||
logger := NewLogger(&buffer, logLevel)
|
||||
helm := MockExecer(logger, "", "")
|
||||
err := helm.AddRepo("myRepo", "https://repo.example.com/", "", "", "", "example_user", "example_password", "", false, false)
|
||||
helm, err := MockExecer(logger, "", "")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.AddRepo("myRepo", "https://repo.example.com/", "", "", "", "example_user", "example_password", "", false, false)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
@ -951,8 +1035,11 @@ func Test_mergeEnv(t *testing.T) {
|
|||
func Test_Template(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "config", "dev")
|
||||
err := helm.TemplateRelease("release", "path/to/chart", "--values", "file.yml")
|
||||
helm, err := MockExecer(logger, "config", "dev")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
err = helm.TemplateRelease("release", "path/to/chart", "--values", "file.yml")
|
||||
expected := `Templating release=release, chart=path/to/chart
|
||||
exec: helm --kubeconfig config --kube-context dev template release path/to/chart --values file.yml
|
||||
`
|
||||
|
|
@ -978,13 +1065,19 @@ exec: helm --kubeconfig config --kube-context dev template release https://examp
|
|||
|
||||
func Test_IsHelm3(t *testing.T) {
|
||||
helm2Runner := mockRunner{output: []byte("Client: v2.16.0+ge13bc94\n")}
|
||||
helm := New("helm", HelmExecOptions{}, NewLogger(os.Stdout, "info"), "", "dev", &helm2Runner)
|
||||
helm, err := New("helm", HelmExecOptions{}, NewLogger(os.Stdout, "info"), "", "dev", &helm2Runner)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if helm.IsHelm3() {
|
||||
t.Error("helmexec.IsHelm3() - Detected Helm 3 with Helm 2 version")
|
||||
}
|
||||
|
||||
helm3Runner := mockRunner{output: []byte("v3.0.0+ge29ce2a\n")}
|
||||
helm = New("helm", HelmExecOptions{}, NewLogger(os.Stdout, "info"), "", "dev", &helm3Runner)
|
||||
helm, err = New("helm", HelmExecOptions{}, NewLogger(os.Stdout, "info"), "", "dev", &helm3Runner)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if !helm.IsHelm3() {
|
||||
t.Error("helmexec.IsHelm3() - Failed to detect Helm 3")
|
||||
}
|
||||
|
|
@ -1012,14 +1105,20 @@ func Test_GetPluginVersion(t *testing.T) {
|
|||
|
||||
func Test_GetVersion(t *testing.T) {
|
||||
helm2Runner := mockRunner{output: []byte("Client: v2.16.1+ge13bc94\n")}
|
||||
helm := New("helm", HelmExecOptions{}, NewLogger(os.Stdout, "info"), "", "dev", &helm2Runner)
|
||||
helm, err := New("helm", HelmExecOptions{}, NewLogger(os.Stdout, "info"), "", "dev", &helm2Runner)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
ver := helm.GetVersion()
|
||||
if ver.Major != 2 || ver.Minor != 16 || ver.Patch != 1 {
|
||||
t.Errorf("helmexec.GetVersion - did not detect correct Helm2 version; it was: %+v", ver)
|
||||
}
|
||||
|
||||
helm3Runner := mockRunner{output: []byte("v3.2.4+ge29ce2a\n")}
|
||||
helm = New("helm", HelmExecOptions{}, NewLogger(os.Stdout, "info"), "", "dev", &helm3Runner)
|
||||
helm, err = New("helm", HelmExecOptions{}, NewLogger(os.Stdout, "info"), "", "dev", &helm3Runner)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
ver = helm.GetVersion()
|
||||
if ver.Major != 3 || ver.Minor != 2 || ver.Patch != 4 {
|
||||
t.Errorf("helmexec.GetVersion - did not detect correct Helm3 version; it was: %+v", ver)
|
||||
|
|
@ -1028,7 +1127,10 @@ func Test_GetVersion(t *testing.T) {
|
|||
|
||||
func Test_IsVersionAtLeast(t *testing.T) {
|
||||
helm2Runner := mockRunner{output: []byte("Client: v2.16.1+ge13bc94\n")}
|
||||
helm := New("helm", HelmExecOptions{}, NewLogger(os.Stdout, "info"), "", "dev", &helm2Runner)
|
||||
helm, err := New("helm", HelmExecOptions{}, NewLogger(os.Stdout, "info"), "", "dev", &helm2Runner)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if !helm.IsVersionAtLeast("2.1.0") {
|
||||
t.Error("helmexec.IsVersionAtLeast - 2.16.1 not atleast 2.1")
|
||||
}
|
||||
|
|
@ -1140,6 +1242,24 @@ func TestParseHelmVersion(t *testing.T) {
|
|||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "version without v prefix",
|
||||
version: "3.2.4",
|
||||
want: semver.MustParse("v3.2.4"),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "version without v prefix with build info",
|
||||
version: "3.2.4+ge29ce2a",
|
||||
want: semver.MustParse("v3.2.4+ge29ce2a"),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "version without v prefix with spaces",
|
||||
version: " 3.2.4 ",
|
||||
want: semver.MustParse("v3.2.4"),
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ func Output(ctx context.Context, c *exec.Cmd, stripArgsValuesOnExitError bool, l
|
|||
exitStatus := waitStatus.ExitStatus()
|
||||
err = newExitError(c.Path, c.Args, exitStatus, ee, stderr.String(), combined.String(), stripArgsValuesOnExitError)
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected error: %v", err))
|
||||
err = fmt.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ type StateCreator struct {
|
|||
|
||||
LoadFile func(inheritedEnv, overrodeEnv *environment.Environment, baseDir, file string, evaluateBases bool) (*HelmState, error)
|
||||
|
||||
getHelm func(*HelmState) helmexec.Interface
|
||||
getHelm func(*HelmState) (helmexec.Interface, error)
|
||||
|
||||
overrideHelmBinary string
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ type StateCreator struct {
|
|||
lockFile string
|
||||
}
|
||||
|
||||
func NewCreator(logger *zap.SugaredLogger, fs *filesystem.FileSystem, valsRuntime vals.Evaluator, getHelm func(*HelmState) helmexec.Interface, overrideHelmBinary string, overrideKustomizeBinary string, remote *remote.Remote, enableLiveOutput bool, lockFile string) *StateCreator {
|
||||
func NewCreator(logger *zap.SugaredLogger, fs *filesystem.FileSystem, valsRuntime vals.Evaluator, getHelm func(*HelmState) (helmexec.Interface, error), overrideHelmBinary string, overrideKustomizeBinary string, remote *remote.Remote, enableLiveOutput bool, lockFile string) *StateCreator {
|
||||
return &StateCreator{
|
||||
logger: logger,
|
||||
|
||||
|
|
@ -352,7 +352,10 @@ func (c *StateCreator) loadEnvValues(st *HelmState, name string, failOnMissingEn
|
|||
func (c *StateCreator) scatterGatherEnvSecretFiles(st *HelmState, envSecretFiles []string, envVals map[string]any, keepFileExtensions []string) ([]string, error) {
|
||||
var errs []error
|
||||
var decryptedFilesKeeper []string
|
||||
helm := c.getHelm(st)
|
||||
helm, err := c.getHelm(st)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
inputs := envSecretFiles
|
||||
inputsSize := len(inputs)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/helmfile/helmfile/pkg/exectest"
|
||||
"github.com/helmfile/helmfile/pkg/helmexec"
|
||||
)
|
||||
|
||||
func TestIsReleaseInstalled_HandlesConnectionError(t *testing.T) {
|
||||
logger := zap.NewNop().Sugar()
|
||||
|
||||
state := &HelmState{
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
// Create a custom helm mock that fails on List operations
|
||||
helm := &CustomFailingHelm{
|
||||
Helm: &exectest.Helm{
|
||||
DiffMutex: &sync.Mutex{},
|
||||
ChartsMutex: &sync.Mutex{},
|
||||
ReleasesMutex: &sync.Mutex{},
|
||||
Helm3: true,
|
||||
},
|
||||
}
|
||||
|
||||
release := ReleaseSpec{
|
||||
Name: "test-release",
|
||||
Chart: "test/chart",
|
||||
Namespace: "default",
|
||||
}
|
||||
|
||||
// This should return an error due to connection failure
|
||||
_, err := state.isReleaseInstalled(helmexec.HelmContext{}, helm, release)
|
||||
|
||||
// Verify that error was propagated
|
||||
if err == nil {
|
||||
t.Fatalf("expected isReleaseInstalled to return error when Kubernetes is unreachable, but got no error")
|
||||
}
|
||||
|
||||
if err.Error() == "" {
|
||||
t.Fatalf("expected isReleaseInstalled to return meaningful error when Kubernetes is unreachable, but got empty error")
|
||||
}
|
||||
|
||||
// Check if the error contains the expected message
|
||||
expectedMsg := "Kubernetes cluster unreachable"
|
||||
if err.Error() != expectedMsg && !strings.Contains(err.Error(), "Kubernetes cluster unreachable") {
|
||||
t.Fatalf("expected error to contain 'Kubernetes cluster unreachable', but got: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// CustomFailingHelm wraps exectest.Helm and overrides List to simulate failures
|
||||
type CustomFailingHelm struct {
|
||||
*exectest.Helm
|
||||
}
|
||||
|
||||
func (h *CustomFailingHelm) List(context helmexec.HelmContext, filter string, flags ...string) (string, error) {
|
||||
return "", errors.New("Kubernetes cluster unreachable: Get \"http://localhost:8080/version\": dial tcp [::1]:8080: connect: connection refused")
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/helmfile/chartify"
|
||||
|
|
@ -158,31 +157,17 @@ func (st *HelmState) appendWaitForJobsFlags(flags []string, release *ReleaseSpec
|
|||
return flags
|
||||
}
|
||||
|
||||
func (st *HelmState) appendWaitFlags(flags []string, helm helmexec.Interface, release *ReleaseSpec, ops *SyncOpts) []string {
|
||||
var hasWait bool
|
||||
func (st *HelmState) appendWaitFlags(flags []string, release *ReleaseSpec, ops *SyncOpts) []string {
|
||||
switch {
|
||||
case release.Wait != nil && *release.Wait:
|
||||
hasWait = true
|
||||
flags = append(flags, "--wait")
|
||||
case ops != nil && ops.Wait:
|
||||
hasWait = true
|
||||
flags = append(flags, "--wait")
|
||||
case release.Wait == nil && st.HelmDefaults.Wait:
|
||||
hasWait = true
|
||||
flags = append(flags, "--wait")
|
||||
}
|
||||
// see https://github.com/helm/helm/releases/tag/v3.15.0
|
||||
// https://github.com/helm/helm/commit/fc74964
|
||||
if hasWait && helm.IsVersionAtLeast("3.15.0") {
|
||||
switch {
|
||||
case release.WaitRetries != nil && *release.WaitRetries > 0:
|
||||
flags = append(flags, "--wait-retries", strconv.Itoa(*release.WaitRetries))
|
||||
case ops != nil && ops.WaitRetries > 0:
|
||||
flags = append(flags, "--wait-retries", strconv.Itoa(ops.WaitRetries))
|
||||
case release.WaitRetries == nil && st.HelmDefaults.WaitRetries > 0:
|
||||
flags = append(flags, "--wait-retries", strconv.Itoa(st.HelmDefaults.WaitRetries))
|
||||
}
|
||||
}
|
||||
// Note: --wait-retries flag has been removed from Helm and is no longer supported
|
||||
// WaitRetries configuration is preserved for backward compatibility but ignored
|
||||
return flags
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ func TestAppendWaitFlags(t *testing.T) {
|
|||
name string
|
||||
release *ReleaseSpec
|
||||
syncOpts *SyncOpts
|
||||
helm helmexec.Interface
|
||||
helmSpec HelmSpec
|
||||
expected []string
|
||||
}{
|
||||
|
|
@ -85,7 +84,6 @@ func TestAppendWaitFlags(t *testing.T) {
|
|||
name: "release wait",
|
||||
release: &ReleaseSpec{Wait: &[]bool{true}[0]},
|
||||
syncOpts: nil,
|
||||
helm: testutil.NewVersionHelmExec("3.11.0"),
|
||||
helmSpec: HelmSpec{},
|
||||
expected: []string{"--wait"},
|
||||
},
|
||||
|
|
@ -93,7 +91,6 @@ func TestAppendWaitFlags(t *testing.T) {
|
|||
name: "cli flags wait",
|
||||
release: &ReleaseSpec{},
|
||||
syncOpts: &SyncOpts{Wait: true},
|
||||
helm: testutil.NewVersionHelmExec("3.11.0"),
|
||||
helmSpec: HelmSpec{},
|
||||
expected: []string{"--wait"},
|
||||
},
|
||||
|
|
@ -101,7 +98,6 @@ func TestAppendWaitFlags(t *testing.T) {
|
|||
name: "helm defaults wait",
|
||||
release: &ReleaseSpec{},
|
||||
syncOpts: nil,
|
||||
helm: testutil.NewVersionHelmExec("3.11.0"),
|
||||
helmSpec: HelmSpec{Wait: true},
|
||||
expected: []string{"--wait"},
|
||||
},
|
||||
|
|
@ -109,7 +105,6 @@ func TestAppendWaitFlags(t *testing.T) {
|
|||
name: "release wait false",
|
||||
release: &ReleaseSpec{Wait: &[]bool{false}[0]},
|
||||
syncOpts: nil,
|
||||
helm: testutil.NewVersionHelmExec("3.11.0"),
|
||||
helmSpec: HelmSpec{Wait: true},
|
||||
expected: []string{},
|
||||
},
|
||||
|
|
@ -117,7 +112,6 @@ func TestAppendWaitFlags(t *testing.T) {
|
|||
name: "cli flags wait false",
|
||||
release: &ReleaseSpec{},
|
||||
syncOpts: &SyncOpts{},
|
||||
helm: testutil.NewVersionHelmExec("3.11.0"),
|
||||
helmSpec: HelmSpec{Wait: true},
|
||||
expected: []string{"--wait"},
|
||||
},
|
||||
|
|
@ -125,66 +119,58 @@ func TestAppendWaitFlags(t *testing.T) {
|
|||
name: "helm defaults wait false",
|
||||
release: &ReleaseSpec{},
|
||||
syncOpts: nil,
|
||||
helm: testutil.NewVersionHelmExec("3.11.0"),
|
||||
helmSpec: HelmSpec{Wait: false},
|
||||
expected: []string{},
|
||||
},
|
||||
// --wait-retries
|
||||
// --wait-retries flag has been removed from Helm
|
||||
{
|
||||
name: "release wait and retry unsupported",
|
||||
release: &ReleaseSpec{Wait: &[]bool{true}[0], WaitRetries: &[]int{1}[0]},
|
||||
syncOpts: nil,
|
||||
helm: testutil.NewVersionHelmExec("3.11.0"),
|
||||
helmSpec: HelmSpec{},
|
||||
expected: []string{"--wait"},
|
||||
},
|
||||
{
|
||||
name: "release wait and retry supported",
|
||||
name: "release wait and retry - retries ignored",
|
||||
release: &ReleaseSpec{Wait: &[]bool{true}[0], WaitRetries: &[]int{1}[0]},
|
||||
syncOpts: nil,
|
||||
helm: testutil.NewVersionHelmExec("3.15.0"),
|
||||
helmSpec: HelmSpec{},
|
||||
expected: []string{"--wait", "--wait-retries", "1"},
|
||||
expected: []string{"--wait"},
|
||||
},
|
||||
{
|
||||
name: "no wait retry",
|
||||
release: &ReleaseSpec{WaitRetries: &[]int{1}[0]},
|
||||
syncOpts: nil,
|
||||
helm: testutil.NewVersionHelmExec("3.15.0"),
|
||||
helmSpec: HelmSpec{},
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "cli flags wait and retry",
|
||||
name: "cli flags wait and retry - retries ignored",
|
||||
release: &ReleaseSpec{},
|
||||
syncOpts: &SyncOpts{Wait: true, WaitRetries: 2},
|
||||
helm: testutil.NewVersionHelmExec("3.15.0"),
|
||||
helmSpec: HelmSpec{},
|
||||
expected: []string{"--wait", "--wait-retries", "2"},
|
||||
expected: []string{"--wait"},
|
||||
},
|
||||
{
|
||||
name: "helm defaults wait retry",
|
||||
name: "helm defaults wait retry - retries ignored",
|
||||
release: &ReleaseSpec{},
|
||||
syncOpts: nil,
|
||||
helm: testutil.NewVersionHelmExec("3.15.0"),
|
||||
helmSpec: HelmSpec{Wait: true, WaitRetries: 3},
|
||||
expected: []string{"--wait", "--wait-retries", "3"},
|
||||
expected: []string{"--wait"},
|
||||
},
|
||||
{
|
||||
name: "release wait default retries",
|
||||
name: "release wait default retries - retries ignored",
|
||||
release: &ReleaseSpec{Wait: &[]bool{true}[0]},
|
||||
syncOpts: nil,
|
||||
helm: testutil.NewVersionHelmExec("3.15.0"),
|
||||
helmSpec: HelmSpec{WaitRetries: 4},
|
||||
expected: []string{"--wait", "--wait-retries", "4"},
|
||||
expected: []string{"--wait"},
|
||||
},
|
||||
{
|
||||
name: "release retries default wait",
|
||||
name: "release retries default wait - retries ignored",
|
||||
release: &ReleaseSpec{WaitRetries: &[]int{5}[0]},
|
||||
syncOpts: nil,
|
||||
helm: testutil.NewVersionHelmExec("3.15.0"),
|
||||
helmSpec: HelmSpec{Wait: true},
|
||||
expected: []string{"--wait", "--wait-retries", "5"},
|
||||
expected: []string{"--wait"},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -192,7 +178,7 @@ func TestAppendWaitFlags(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
st := &HelmState{}
|
||||
st.HelmDefaults = tt.helmSpec
|
||||
got := st.appendWaitFlags([]string{}, tt.helm, tt.release, tt.syncOpts)
|
||||
got := st.appendWaitFlags([]string{}, tt.release, tt.syncOpts)
|
||||
require.Equalf(t, tt.expected, got, "appendWaitFlags() = %v, want %v", got, tt.expected)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ type HelmSpec struct {
|
|||
// Wait, if set to true, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful
|
||||
Wait bool `yaml:"wait"`
|
||||
// WaitRetries, if set and --wait enabled, will retry any failed check on resource state, except if HTTP status code < 500 is received, subject to the specified number of retries
|
||||
// DEPRECATED: This field is ignored as the --wait-retries flag was removed from Helm. Preserved for backward compatibility.
|
||||
WaitRetries int `yaml:"waitRetries"`
|
||||
// WaitForJobs, if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout
|
||||
WaitForJobs bool `yaml:"waitForJobs"`
|
||||
|
|
@ -267,6 +268,7 @@ type ReleaseSpec struct {
|
|||
// Wait, if set to true, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful
|
||||
Wait *bool `yaml:"wait,omitempty"`
|
||||
// WaitRetries, if set and --wait enabled, will retry any failed check on resource state, except if HTTP status code < 500 is received, subject to the specified number of retries
|
||||
// DEPRECATED: This field is ignored as the --wait-retries flag was removed from Helm. Preserved for backward compatibility.
|
||||
WaitRetries *int `yaml:"waitRetries,omitempty"`
|
||||
// WaitForJobs, if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout
|
||||
WaitForJobs *bool `yaml:"waitForJobs,omitempty"`
|
||||
|
|
@ -813,6 +815,7 @@ type SyncOpts struct {
|
|||
Wait bool
|
||||
WaitRetries int
|
||||
WaitForJobs bool
|
||||
Timeout int
|
||||
SyncReleaseLabels bool
|
||||
ReuseValues bool
|
||||
ResetValues bool
|
||||
|
|
@ -1269,6 +1272,19 @@ func (st *HelmState) GetRepositoryAndNameFromChartName(chartName string) (*Repos
|
|||
return nil, chartName
|
||||
}
|
||||
|
||||
var mutexMap sync.Map
|
||||
|
||||
// retrieves or creates a sync.Mutex for a given name
|
||||
func (st *HelmState) getNamedMutex(name string) *sync.Mutex {
|
||||
mu, ok := mutexMap.Load(name)
|
||||
if ok {
|
||||
return mu.(*sync.Mutex)
|
||||
}
|
||||
newMu := &sync.Mutex{}
|
||||
actualMu, _ := mutexMap.LoadOrStore(name, newMu)
|
||||
return actualMu.(*sync.Mutex)
|
||||
}
|
||||
|
||||
type PrepareChartKey struct {
|
||||
Namespace, Name, KubeContext string
|
||||
}
|
||||
|
|
@ -1347,7 +1363,7 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
|
|||
chartFetchedByGoGetter := chartPath != chartName
|
||||
|
||||
if !chartFetchedByGoGetter {
|
||||
ociChartPath, err := st.getOCIChart(release, dir, helm, opts.OutputDirTemplate)
|
||||
ociChartPath, err := st.getOCIChart(release, dir, helm, opts)
|
||||
if err != nil {
|
||||
results <- &chartPrepareResult{err: fmt.Errorf("release %q: %w", release.Name, err)}
|
||||
|
||||
|
|
@ -1967,7 +1983,7 @@ func (st *HelmState) prepareDiffReleases(helm helmexec.Interface, additionalValu
|
|||
mu := &sync.RWMutex{}
|
||||
installedReleases := map[string]bool{}
|
||||
|
||||
isInstalled := func(r *ReleaseSpec) bool {
|
||||
isInstalled := func(r *ReleaseSpec) (bool, error) {
|
||||
id := ReleaseToID(r)
|
||||
|
||||
mu.RLock()
|
||||
|
|
@ -1975,19 +1991,19 @@ func (st *HelmState) prepareDiffReleases(helm helmexec.Interface, additionalValu
|
|||
mu.RUnlock()
|
||||
|
||||
if ok {
|
||||
return v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
v, err := st.isReleaseInstalled(st.createHelmContext(r, 0), helm, *r)
|
||||
if err != nil {
|
||||
st.logger.Warnf("confirming if the release is already installed or not: %v", err)
|
||||
} else {
|
||||
mu.Lock()
|
||||
installedReleases[id] = v
|
||||
mu.Unlock()
|
||||
return false, err
|
||||
}
|
||||
|
||||
return v
|
||||
mu.Lock()
|
||||
installedReleases[id] = v
|
||||
mu.Unlock()
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
releases := []*ReleaseSpec{}
|
||||
|
|
@ -2032,12 +2048,25 @@ func (st *HelmState) prepareDiffReleases(helm helmexec.Interface, additionalValu
|
|||
suppressDiff = true
|
||||
}
|
||||
|
||||
if opt.SkipDiffOnInstall && !isInstalled(release) {
|
||||
results <- diffPrepareResult{release: release, upgradeDueToSkippedDiff: true, suppressDiff: suppressDiff}
|
||||
continue
|
||||
if opt.SkipDiffOnInstall {
|
||||
installed, err := isInstalled(release)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else if !installed {
|
||||
results <- diffPrepareResult{release: release, upgradeDueToSkippedDiff: true, suppressDiff: suppressDiff}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
disableValidation := release.DisableValidationOnInstall != nil && *release.DisableValidationOnInstall && !isInstalled(release)
|
||||
var disableValidation bool
|
||||
if release.DisableValidationOnInstall != nil && *release.DisableValidationOnInstall {
|
||||
installed, err := isInstalled(release)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
disableValidation = !installed
|
||||
}
|
||||
}
|
||||
|
||||
// TODO We need a long-term fix for this :)
|
||||
// See https://github.com/roboll/helmfile/issues/737
|
||||
|
|
@ -2352,7 +2381,7 @@ func (st *HelmState) TestReleases(helm helmexec.Interface, cleanup bool, timeout
|
|||
}
|
||||
|
||||
if timeout == EmptyTimeout {
|
||||
flags = append(flags, st.timeoutFlags(&release)...)
|
||||
flags = append(flags, st.timeoutFlags(&release, nil)...)
|
||||
} else {
|
||||
duration := strconv.Itoa(timeout)
|
||||
duration += "s"
|
||||
|
|
@ -2779,6 +2808,14 @@ func (st *HelmState) appendKeyringFlags(flags []string, release *ReleaseSpec) []
|
|||
return flags
|
||||
}
|
||||
|
||||
// appendEnableDNSFlags append the helm command-line flag for DNS resolution
|
||||
func (st *HelmState) appendEnableDNSFlags(flags []string, release *ReleaseSpec) []string {
|
||||
if release.EnableDNS != nil && *release.EnableDNS || release.EnableDNS == nil && st.HelmDefaults.EnableDNS {
|
||||
flags = append(flags, "--enable-dns")
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
func (st *HelmState) kubeConnectionFlags(release *ReleaseSpec) []string {
|
||||
flags := []string{}
|
||||
if release.KubeContext != "" {
|
||||
|
|
@ -2832,13 +2869,16 @@ func (st *HelmState) needsInsecureSkipTLSVerify(release *ReleaseSpec, repo *Repo
|
|||
return relSkipTLSVerify || st.HelmDefaults.InsecureSkipTLSVerify || repoSkipTLSVerify
|
||||
}
|
||||
|
||||
func (st *HelmState) timeoutFlags(release *ReleaseSpec) []string {
|
||||
func (st *HelmState) timeoutFlags(release *ReleaseSpec, ops *SyncOpts) []string {
|
||||
var flags []string
|
||||
|
||||
timeout := st.HelmDefaults.Timeout
|
||||
if release.Timeout != nil {
|
||||
timeout = *release.Timeout
|
||||
}
|
||||
if ops != nil && ops.Timeout > 0 {
|
||||
timeout = ops.Timeout
|
||||
}
|
||||
if timeout != 0 {
|
||||
duration := strconv.Itoa(timeout)
|
||||
duration += "s"
|
||||
|
|
@ -2851,11 +2891,9 @@ func (st *HelmState) timeoutFlags(release *ReleaseSpec) []string {
|
|||
func (st *HelmState) flagsForUpgrade(helm helmexec.Interface, release *ReleaseSpec, workerIndex int, opt *SyncOpts) ([]string, []string, error) {
|
||||
var flags []string
|
||||
flags = st.appendChartVersionFlags(flags, release)
|
||||
if release.EnableDNS != nil && *release.EnableDNS || release.EnableDNS == nil && st.HelmDefaults.EnableDNS {
|
||||
flags = append(flags, "--enable-dns")
|
||||
}
|
||||
flags = st.appendEnableDNSFlags(flags, release)
|
||||
|
||||
flags = st.appendWaitFlags(flags, helm, release, opt)
|
||||
flags = st.appendWaitFlags(flags, release, opt)
|
||||
flags = st.appendWaitForJobsFlags(flags, release, opt)
|
||||
|
||||
// non-OCI chart should be verified here
|
||||
|
|
@ -2864,7 +2902,7 @@ func (st *HelmState) flagsForUpgrade(helm helmexec.Interface, release *ReleaseSp
|
|||
flags = st.appendKeyringFlags(flags, release)
|
||||
}
|
||||
|
||||
flags = append(flags, st.timeoutFlags(release)...)
|
||||
flags = append(flags, st.timeoutFlags(release, opt)...)
|
||||
|
||||
if release.Force != nil && *release.Force || release.Force == nil && st.HelmDefaults.Force {
|
||||
flags = append(flags, "--force")
|
||||
|
|
@ -2978,6 +3016,7 @@ func (st *HelmState) flagsForDiff(helm helmexec.Interface, release *ReleaseSpec,
|
|||
settings := cli.New()
|
||||
var flags []string
|
||||
flags = st.appendChartVersionFlags(flags, release)
|
||||
flags = st.appendEnableDNSFlags(flags, release)
|
||||
|
||||
disableOpenAPIValidation := false
|
||||
if release.DisableOpenAPIValidation != nil {
|
||||
|
|
@ -3291,7 +3330,7 @@ func (st *HelmState) ExpandedHelmfiles() ([]SubHelmfileSpec, error) {
|
|||
}
|
||||
if len(matches) == 0 {
|
||||
err := fmt.Errorf("no matches for path: %s", hf.Path)
|
||||
if *st.MissingFileHandler == "Error" {
|
||||
if *st.getMissingFileHandler() == "Error" {
|
||||
return nil, err
|
||||
}
|
||||
st.logger.Warnf("no matches for path: %s", hf.Path)
|
||||
|
|
@ -3379,6 +3418,19 @@ func (st *HelmState) getReleaseMissingFileHandler(release *ReleaseSpec) *string
|
|||
}
|
||||
}
|
||||
|
||||
// getMissingFileHandler returns the first non-nil MissingFileHandler in the following order:
|
||||
// - st.MissingFileHandler
|
||||
// - "Error"
|
||||
func (st *HelmState) getMissingFileHandler() *string {
|
||||
defaultMissingFileHandler := "Error"
|
||||
switch {
|
||||
case st.MissingFileHandler != nil:
|
||||
return st.MissingFileHandler
|
||||
default:
|
||||
return &defaultMissingFileHandler
|
||||
}
|
||||
}
|
||||
|
||||
func (st *HelmState) generateTemporaryReleaseValuesFiles(release *ReleaseSpec, values []any) ([]string, error) {
|
||||
generatedFiles := []string{}
|
||||
|
||||
|
|
@ -4091,7 +4143,10 @@ func (st *HelmState) Reverse() {
|
|||
}
|
||||
}
|
||||
|
||||
func (st *HelmState) getOCIChart(release *ReleaseSpec, tempDir string, helm helmexec.Interface, outputDirTemplate string) (*string, error) {
|
||||
var downloadedOCICharts = make(map[string]bool)
|
||||
var downloadedOCIMutex sync.RWMutex
|
||||
|
||||
func (st *HelmState) getOCIChart(release *ReleaseSpec, tempDir string, helm helmexec.Interface, opts ChartPrepareOptions) (*string, error) {
|
||||
qualifiedChartName, chartName, chartVersion, err := st.getOCIQualifiedChartName(release, helm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -4101,7 +4156,34 @@ func (st *HelmState) getOCIChart(release *ReleaseSpec, tempDir string, helm helm
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
chartPath, _ := st.getOCIChartPath(tempDir, release, chartName, chartVersion, outputDirTemplate)
|
||||
if opts.OutputDirTemplate == "" {
|
||||
tempDir = remote.CacheDir()
|
||||
}
|
||||
|
||||
chartPath, _ := st.getOCIChartPath(tempDir, release, chartName, chartVersion, opts.OutputDirTemplate)
|
||||
|
||||
mu := st.getNamedMutex(chartPath)
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
_, err = os.Stat(tempDir)
|
||||
if err != nil {
|
||||
err = os.MkdirAll(tempDir, 0755)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
downloadedOCIMutex.RLock()
|
||||
alreadyDownloadedFlag := downloadedOCICharts[chartPath]
|
||||
downloadedOCIMutex.RUnlock()
|
||||
|
||||
if !opts.SkipDeps && !opts.SkipRefresh && !alreadyDownloadedFlag {
|
||||
err = os.RemoveAll(chartPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if st.fs.DirectoryExistsAt(chartPath) {
|
||||
st.logger.Debugf("chart already exists at %s", chartPath)
|
||||
|
|
@ -4128,6 +4210,10 @@ func (st *HelmState) getOCIChart(release *ReleaseSpec, tempDir string, helm helm
|
|||
return nil, err
|
||||
}
|
||||
|
||||
downloadedOCIMutex.Lock()
|
||||
downloadedOCICharts[chartPath] = true
|
||||
downloadedOCIMutex.Unlock()
|
||||
|
||||
chartPath = filepath.Dir(fullChartPath)
|
||||
|
||||
return &chartPath, nil
|
||||
|
|
@ -4194,15 +4280,15 @@ func (st *HelmState) getOCIChartPath(tempDir string, release *ReleaseSpec, chart
|
|||
|
||||
pathElems := []string{tempDir}
|
||||
|
||||
if release.Namespace != "" {
|
||||
pathElems = append(pathElems, release.Namespace)
|
||||
}
|
||||
|
||||
if release.KubeContext != "" {
|
||||
pathElems = append(pathElems, release.KubeContext)
|
||||
}
|
||||
|
||||
pathElems = append(pathElems, release.Name, chartName, safeVersionPath(chartVersion))
|
||||
replacer := strings.NewReplacer(
|
||||
":", "_",
|
||||
"//", "_",
|
||||
".", "_",
|
||||
"&", "_",
|
||||
)
|
||||
qName := strings.Split(replacer.Replace(release.Chart), "/")
|
||||
|
||||
pathElems = append(pathElems, qName...)
|
||||
pathElems = append(pathElems, safeVersionPath(chartVersion))
|
||||
return filepath.Join(pathElems...), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ func TestHelmState_flagsForUpgrade(t *testing.T) {
|
|||
version *semver.Version
|
||||
defaults HelmSpec
|
||||
release *ReleaseSpec
|
||||
syncOpts *SyncOpts
|
||||
want []string
|
||||
wantErr string
|
||||
}{
|
||||
|
|
@ -455,6 +456,27 @@ func TestHelmState_flagsForUpgrade(t *testing.T) {
|
|||
"--namespace", "test-namespace",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "timeout-from-cli-flag",
|
||||
defaults: HelmSpec{
|
||||
Timeout: 123,
|
||||
},
|
||||
release: &ReleaseSpec{
|
||||
Chart: "test/chart",
|
||||
Version: "0.1",
|
||||
Timeout: some(456),
|
||||
Name: "test-charts",
|
||||
Namespace: "test-namespace",
|
||||
},
|
||||
syncOpts: &SyncOpts{
|
||||
Timeout: 789,
|
||||
},
|
||||
want: []string{
|
||||
"--version", "0.1",
|
||||
"--timeout", "789s",
|
||||
"--namespace", "test-namespace",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "atomic",
|
||||
defaults: HelmSpec{
|
||||
|
|
@ -737,7 +759,7 @@ func TestHelmState_flagsForUpgrade(t *testing.T) {
|
|||
Version: tt.version,
|
||||
}
|
||||
|
||||
args, _, err := state.flagsForUpgrade(helm, tt.release, 0, nil)
|
||||
args, _, err := state.flagsForUpgrade(helm, tt.release, 0, tt.syncOpts)
|
||||
if err != nil && tt.wantErr == "" {
|
||||
t.Errorf("unexpected error flagsForUpgrade: %v", err)
|
||||
}
|
||||
|
|
@ -1942,14 +1964,19 @@ func TestHelmState_DiffReleases(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestHelmState_DiffFlags(t *testing.T) {
|
||||
enable := true
|
||||
disable := false
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
defaults HelmSpec
|
||||
releases []ReleaseSpec
|
||||
helm *exectest.Helm
|
||||
wantDiffFlags []string
|
||||
}{
|
||||
{
|
||||
name: "release with api version and kubeversion",
|
||||
name: "release with api version and kubeversion",
|
||||
defaults: HelmSpec{},
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseName",
|
||||
|
|
@ -1962,7 +1989,8 @@ func TestHelmState_DiffFlags(t *testing.T) {
|
|||
wantDiffFlags: []string{"--api-versions", "helmfile.test/v1", "--api-versions", "helmfile.test/v2", "--kube-version", "1.21"},
|
||||
},
|
||||
{
|
||||
name: "release with kubeversion and plain http which is ignored",
|
||||
name: "release with kubeversion and plain http which is ignored",
|
||||
defaults: HelmSpec{},
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseName",
|
||||
|
|
@ -1974,13 +2002,52 @@ func TestHelmState_DiffFlags(t *testing.T) {
|
|||
helm: &exectest.Helm{},
|
||||
wantDiffFlags: []string{"--kube-version", "1.21"},
|
||||
},
|
||||
{
|
||||
name: "release with enable-dns",
|
||||
defaults: HelmSpec{EnableDNS: false},
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseName",
|
||||
Chart: "foo",
|
||||
EnableDNS: &enable,
|
||||
},
|
||||
},
|
||||
helm: &exectest.Helm{},
|
||||
wantDiffFlags: []string{"--enable-dns"},
|
||||
},
|
||||
{
|
||||
name: "release with disable-dns override",
|
||||
defaults: HelmSpec{EnableDNS: true},
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseName",
|
||||
Chart: "foo",
|
||||
EnableDNS: &disable,
|
||||
},
|
||||
},
|
||||
helm: &exectest.Helm{},
|
||||
wantDiffFlags: nil,
|
||||
},
|
||||
{
|
||||
name: "release with enable-dns from default",
|
||||
defaults: HelmSpec{EnableDNS: true},
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseName",
|
||||
Chart: "foo",
|
||||
},
|
||||
},
|
||||
helm: &exectest.Helm{},
|
||||
wantDiffFlags: []string{"--enable-dns"},
|
||||
},
|
||||
}
|
||||
for i := range tests {
|
||||
tt := tests[i]
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
state := &HelmState{
|
||||
ReleaseSetSpec: ReleaseSetSpec{
|
||||
Releases: tt.releases,
|
||||
Releases: tt.releases,
|
||||
HelmDefaults: tt.defaults,
|
||||
},
|
||||
logger: logger,
|
||||
valsRuntime: valsRuntime,
|
||||
|
|
|
|||
|
|
@ -30,12 +30,6 @@ var (
|
|||
helmShortVersionRegex = regexp.MustCompile(`v\d+\.\d+\.\d+\+[a-z0-9]+`)
|
||||
)
|
||||
|
||||
type ociChart struct {
|
||||
name string
|
||||
version string
|
||||
digest string
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
LocalDockerRegistry struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
|
|
@ -166,8 +160,6 @@ func testHelmfileTemplateWithBuildCommand(t *testing.T, GoYamlV3 bool) {
|
|||
}
|
||||
})
|
||||
|
||||
// ociCharts holds a list of chart name, version and digest distributed by local oci registry.
|
||||
ociCharts := []ociChart{}
|
||||
// If localDockerRegistry.enabled is set to `true`,
|
||||
// run the docker registry v2 and push the test charts to the registry
|
||||
// so that it can be accessed by helm and helmfile as a oci registry based chart repository.
|
||||
|
|
@ -201,16 +193,9 @@ func testHelmfileTemplateWithBuildCommand(t *testing.T, GoYamlV3 bool) {
|
|||
if !c.IsDir() {
|
||||
t.Fatalf("%s is not a directory", c)
|
||||
}
|
||||
chartName, chartVersion := execHelmShowChart(t, chartPath)
|
||||
tgzFile := execHelmPackage(t, chartPath)
|
||||
chartDigest, err := execHelmPush(t, tgzFile, fmt.Sprintf("oci://localhost:%d/myrepo", hostPort))
|
||||
_, err := execHelmPush(t, tgzFile, fmt.Sprintf("oci://localhost:%d/myrepo", hostPort))
|
||||
require.NoError(t, err, "Unable to run helm push to local registry: %v", err)
|
||||
|
||||
ociCharts = append(ociCharts, ociChart{
|
||||
name: chartName,
|
||||
version: chartVersion,
|
||||
digest: chartDigest,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +206,7 @@ func testHelmfileTemplateWithBuildCommand(t *testing.T, GoYamlV3 bool) {
|
|||
helmfileCacheHome := filepath.Join(tmpDir, "helmfile_cache")
|
||||
// HELM_CONFIG_HOME contains the registry auth file (registry.json) and the index of all the repos added via helm-repo-add (repositories.yaml).
|
||||
helmConfigHome := filepath.Join(tmpDir, "helm_config")
|
||||
t.Logf("Using HELM_CACHE_HOME=%s, HELMFILE_CACHE_HOME=%s, HELM_CONFIG_HOME=%s", helmCacheHome, helmfileCacheHome, helmConfigHome)
|
||||
t.Logf("Using HELM_CACHE_HOME=%s, HELMFILE_CACHE_HOME=%s, HELM_CONFIG_HOME=%s, WD=%s", helmCacheHome, helmfileCacheHome, helmConfigHome, wd)
|
||||
|
||||
inputFile := filepath.Join(testdataDir, name, "input.yaml.gotmpl")
|
||||
outputFile := ""
|
||||
|
|
@ -230,6 +215,7 @@ func testHelmfileTemplateWithBuildCommand(t *testing.T, GoYamlV3 bool) {
|
|||
} else {
|
||||
outputFile = filepath.Join(testdataDir, name, "gopkg.in-yaml.v2-output.yaml")
|
||||
}
|
||||
expectedOutputFile := filepath.Join(testdataDir, name, "output.yaml")
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
|
@ -262,15 +248,8 @@ func testHelmfileTemplateWithBuildCommand(t *testing.T, GoYamlV3 bool) {
|
|||
gotStr = chartGitFullPathRegex.ReplaceAllString(gotStr, `chart=$$GoGetterPath`)
|
||||
// Replace helm version with $HelmVersion
|
||||
gotStr = helmShortVersionRegex.ReplaceAllString(gotStr, `$$HelmVersion`)
|
||||
// Replace all occurrences of HELMFILE_CACHE_HOME with /home/runner/.cache/helmfile
|
||||
// for stable test result
|
||||
gotStr = strings.ReplaceAll(gotStr, helmfileCacheHome, "/home/runner/.cache/helmfile")
|
||||
|
||||
// OCI based helm charts are pulled and exported under temporary directory.
|
||||
// We are not sure the exact name of the temporary directory generated by helmfile,
|
||||
// so redact its base directory name with $TMP.
|
||||
if config.LocalDockerRegistry.Enabled {
|
||||
var releaseName, chartPath string
|
||||
sc := bufio.NewScanner(strings.NewReader(gotStr))
|
||||
for sc.Scan() {
|
||||
if !strings.HasPrefix(sc.Text(), "Templating ") {
|
||||
|
|
@ -281,28 +260,20 @@ func testHelmfileTemplateWithBuildCommand(t *testing.T, GoYamlV3 bool) {
|
|||
if len(releaseChartParts) != 2 {
|
||||
t.Fatal("Found unexpected log output of templating oci based helm chart, want=\"Templating release=<release_name>, chart=<chart_name>\"")
|
||||
}
|
||||
releaseNamePart, chartPathPart := releaseChartParts[0], releaseChartParts[1]
|
||||
releaseName = strings.TrimPrefix(releaseNamePart, "release=")
|
||||
chartPath = chartPathPart
|
||||
}
|
||||
for _, ociChart := range ociCharts {
|
||||
chartPathWithoutTempDirBase := fmt.Sprintf("/%s/%s/%s/%s", releaseName, ociChart.name, ociChart.version, ociChart.name)
|
||||
var chartPathBase string
|
||||
if strings.HasSuffix(chartPath, chartPathWithoutTempDirBase) {
|
||||
chartPathBase = strings.TrimSuffix(chartPath, chartPathWithoutTempDirBase)
|
||||
}
|
||||
if len(chartPathBase) != 0 {
|
||||
gotStr = strings.ReplaceAll(gotStr, chartPathBase, "chart=$TMP")
|
||||
}
|
||||
gotStr = strings.ReplaceAll(gotStr, fmt.Sprintf("Digest: %s", ociChart.digest), "Digest: $DIGEST")
|
||||
}
|
||||
}
|
||||
|
||||
gotStr = strings.ReplaceAll(gotStr, helmfileCacheHome, "$HELMFILE_CACHE_HOME")
|
||||
gotStr = strings.ReplaceAll(gotStr, wd, "__workingdir__")
|
||||
|
||||
if stat, _ := os.Stat(outputFile); stat != nil {
|
||||
want, err := os.ReadFile(outputFile)
|
||||
wantStr := strings.ReplaceAll(string(want), "__workingdir__", wd)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wantStr, gotStr)
|
||||
require.Equal(t, string(want), gotStr)
|
||||
} else if stat, _ := os.Stat(expectedOutputFile); stat != nil {
|
||||
want, err := os.ReadFile(expectedOutputFile)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, string(want), gotStr)
|
||||
} else {
|
||||
// To update the test golden image(output.yaml), just remove it and rerun this test.
|
||||
// We automatically capture the output to `output.yaml` in the test case directory
|
||||
|
|
@ -325,23 +296,6 @@ func execDocker(t *testing.T, args ...string) {
|
|||
}
|
||||
}
|
||||
|
||||
func execHelmShowChart(t *testing.T, localChart string) (string, string) {
|
||||
t.Helper()
|
||||
|
||||
name, version := "", ""
|
||||
out := execHelm(t, "show", "chart", localChart)
|
||||
sc := bufio.NewScanner(strings.NewReader(out))
|
||||
for sc.Scan() {
|
||||
if strings.HasPrefix(sc.Text(), "name:") {
|
||||
name = strings.TrimPrefix(sc.Text(), "name: ")
|
||||
}
|
||||
if strings.HasPrefix(sc.Text(), "version:") {
|
||||
version = strings.TrimPrefix(sc.Text(), "version: ")
|
||||
}
|
||||
}
|
||||
return name, version
|
||||
}
|
||||
|
||||
func execHelmPackage(t *testing.T, localChart string) string {
|
||||
t.Helper()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Pulling localhost:5001/myrepo/raw:0.1.0
|
||||
Templating release=foo, chart=$TMP/foo/raw/0.1.0/raw
|
||||
Templating release=foo, chart=$HELMFILE_CACHE_HOME/myrepo/raw/0.1.0/raw
|
||||
---
|
||||
# Source: raw/templates/resources.yaml
|
||||
apiVersion: v1
|
||||
|
|
|
|||
6
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_direct/config.yaml
vendored
Normal file
6
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_direct/config.yaml
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
localDockerRegistry:
|
||||
enabled: true
|
||||
port: 5001
|
||||
chartifyTempDir: temp2
|
||||
helmfileArgs:
|
||||
- template
|
||||
22
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_direct/input.yaml.gotmpl
vendored
Normal file
22
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_direct/input.yaml.gotmpl
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
releases:
|
||||
- name: foo
|
||||
chart: oci://localhost:5001/myrepo/raw
|
||||
version: 0.1.0
|
||||
values: &oci_chart_pull_direct
|
||||
- templates:
|
||||
- |
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{`{{ .Release.Name }}`}}
|
||||
namespace: {{`{{ .Release.Namespace }}`}}
|
||||
annotations:
|
||||
chart-version: {{`{{ .Chart.Version }}`}}
|
||||
data:
|
||||
values: {{`{{ .Release.Name }}`}}
|
||||
|
||||
- name: bar
|
||||
chart: oci://localhost:5001/myrepo/raw
|
||||
version: 0.1.0
|
||||
namespace: ns2
|
||||
values: *oci_chart_pull_direct
|
||||
27
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_direct/output.yaml
vendored
Normal file
27
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_direct/output.yaml
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
Pulling localhost:5001/myrepo/raw:0.1.0
|
||||
Templating release=foo, chart=$HELMFILE_CACHE_HOME/oci__localhost_5001/myrepo/raw/0.1.0/raw
|
||||
---
|
||||
# Source: raw/templates/resources.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: default
|
||||
annotations:
|
||||
chart-version: 0.1.0
|
||||
data:
|
||||
values: foo
|
||||
|
||||
Templating release=bar, chart=$HELMFILE_CACHE_HOME/oci__localhost_5001/myrepo/raw/0.1.0/raw
|
||||
---
|
||||
# Source: raw/templates/resources.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: bar
|
||||
namespace: ns2
|
||||
annotations:
|
||||
chart-version: 0.1.0
|
||||
data:
|
||||
values: bar
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# Templating two versions of the same chart with only one pulling of each version
|
||||
localDockerRegistry:
|
||||
enabled: true
|
||||
port: 5001
|
||||
chartifyTempDir: temp3
|
||||
helmfileArgs:
|
||||
# Prevent releases from racing and randomizing the log
|
||||
- --concurrency=1
|
||||
- template
|
||||
43
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_once/input.yaml.gotmpl
vendored
Normal file
43
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_once/input.yaml.gotmpl
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
repositories:
|
||||
- name: myrepo
|
||||
url: localhost:5001/myrepo
|
||||
oci: true
|
||||
|
||||
releases:
|
||||
- name: foo
|
||||
chart: myrepo/raw
|
||||
version: 0.1.0
|
||||
values: &oci_chart_pull_once_values
|
||||
- templates:
|
||||
- |
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{`{{ .Release.Name }}`}}
|
||||
namespace: {{`{{ .Release.Namespace }}`}}
|
||||
annotations:
|
||||
chart-version: {{`{{ .Chart.Version }}`}}
|
||||
data:
|
||||
values: {{`{{ .Release.Name }}`}}
|
||||
|
||||
- name: bar
|
||||
chart: myrepo/raw
|
||||
version: 0.1.0
|
||||
values: *oci_chart_pull_once_values
|
||||
|
||||
- name: release-no-default-ns
|
||||
chart: myrepo/raw
|
||||
version: 0.1.0
|
||||
namespace: no-default
|
||||
values: *oci_chart_pull_once_values
|
||||
|
||||
- name: second-version-of-chart
|
||||
chart: myrepo/raw
|
||||
version: 0.0.1
|
||||
namespace: foobar
|
||||
values: *oci_chart_pull_once_values
|
||||
|
||||
- name: first-release-version-of-chart
|
||||
chart: myrepo/raw
|
||||
version: 0.1.0
|
||||
values: *oci_chart_pull_once_values
|
||||
67
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_once/output.yaml
vendored
Normal file
67
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_once/output.yaml
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
Pulling localhost:5001/myrepo/raw:0.1.0
|
||||
Pulling localhost:5001/myrepo/raw:0.0.1
|
||||
Templating release=foo, chart=$HELMFILE_CACHE_HOME/myrepo/raw/0.1.0/raw
|
||||
---
|
||||
# Source: raw/templates/resources.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: default
|
||||
annotations:
|
||||
chart-version: 0.1.0
|
||||
data:
|
||||
values: foo
|
||||
|
||||
Templating release=bar, chart=$HELMFILE_CACHE_HOME/myrepo/raw/0.1.0/raw
|
||||
---
|
||||
# Source: raw/templates/resources.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: bar
|
||||
namespace: default
|
||||
annotations:
|
||||
chart-version: 0.1.0
|
||||
data:
|
||||
values: bar
|
||||
|
||||
Templating release=release-no-default-ns, chart=$HELMFILE_CACHE_HOME/myrepo/raw/0.1.0/raw
|
||||
---
|
||||
# Source: raw/templates/resources.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: release-no-default-ns
|
||||
namespace: no-default
|
||||
annotations:
|
||||
chart-version: 0.1.0
|
||||
data:
|
||||
values: release-no-default-ns
|
||||
|
||||
Templating release=second-version-of-chart, chart=$HELMFILE_CACHE_HOME/myrepo/raw/0.0.1/raw
|
||||
---
|
||||
# Source: raw/templates/resources.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: second-version-of-chart
|
||||
namespace: foobar
|
||||
annotations:
|
||||
chart-version: 0.0.1
|
||||
data:
|
||||
values: second-version-of-chart
|
||||
|
||||
Templating release=first-release-version-of-chart, chart=$HELMFILE_CACHE_HOME/myrepo/raw/0.1.0/raw
|
||||
---
|
||||
# Source: raw/templates/resources.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: first-release-version-of-chart
|
||||
namespace: default
|
||||
annotations:
|
||||
chart-version: 0.1.0
|
||||
data:
|
||||
values: first-release-version-of-chart
|
||||
|
||||
7
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_once2/config.yaml
vendored
Normal file
7
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_once2/config.yaml
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Templating few releases with the same chart\version and only one pulling
|
||||
localDockerRegistry:
|
||||
enabled: true
|
||||
port: 5001
|
||||
chartifyTempDir: temp3
|
||||
helmfileArgs:
|
||||
- template
|
||||
23
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_once2/input.yaml.gotmpl
vendored
Normal file
23
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_once2/input.yaml.gotmpl
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
repositories:
|
||||
- name: myrepo
|
||||
url: localhost:5001/myrepo
|
||||
oci: true
|
||||
|
||||
releases:
|
||||
{{- range $i := until 5 }}
|
||||
- name: release-{{ $i }}
|
||||
chart: myrepo/raw
|
||||
version: 0.1.0
|
||||
values:
|
||||
- templates:
|
||||
- |
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{`{{ .Release.Name }}`}}
|
||||
namespace: {{`{{ .Release.Namespace }}`}}
|
||||
annotations:
|
||||
chart-version: {{`{{ .Chart.Version }}`}}
|
||||
data:
|
||||
values: {{`{{ .Release.Name }}`}}
|
||||
{{- end }}
|
||||
66
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_once2/output.yaml
vendored
Normal file
66
test/e2e/template/helmfile/testdata/snapshot/oci_chart_pull_once2/output.yaml
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
Pulling localhost:5001/myrepo/raw:0.1.0
|
||||
Templating release=release-0, chart=$HELMFILE_CACHE_HOME/myrepo/raw/0.1.0/raw
|
||||
---
|
||||
# Source: raw/templates/resources.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: release-0
|
||||
namespace: default
|
||||
annotations:
|
||||
chart-version: 0.1.0
|
||||
data:
|
||||
values: release-0
|
||||
|
||||
Templating release=release-1, chart=$HELMFILE_CACHE_HOME/myrepo/raw/0.1.0/raw
|
||||
---
|
||||
# Source: raw/templates/resources.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: release-1
|
||||
namespace: default
|
||||
annotations:
|
||||
chart-version: 0.1.0
|
||||
data:
|
||||
values: release-1
|
||||
|
||||
Templating release=release-2, chart=$HELMFILE_CACHE_HOME/myrepo/raw/0.1.0/raw
|
||||
---
|
||||
# Source: raw/templates/resources.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: release-2
|
||||
namespace: default
|
||||
annotations:
|
||||
chart-version: 0.1.0
|
||||
data:
|
||||
values: release-2
|
||||
|
||||
Templating release=release-3, chart=$HELMFILE_CACHE_HOME/myrepo/raw/0.1.0/raw
|
||||
---
|
||||
# Source: raw/templates/resources.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: release-3
|
||||
namespace: default
|
||||
annotations:
|
||||
chart-version: 0.1.0
|
||||
data:
|
||||
values: release-3
|
||||
|
||||
Templating release=release-4, chart=$HELMFILE_CACHE_HOME/myrepo/raw/0.1.0/raw
|
||||
---
|
||||
# Source: raw/templates/resources.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: release-4
|
||||
namespace: default
|
||||
annotations:
|
||||
chart-version: 0.1.0
|
||||
data:
|
||||
values: release-4
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ export HELM_DATA_HOME="${helm_dir}/data"
|
|||
export HELM_HOME="${HELM_DATA_HOME}"
|
||||
export HELM_PLUGINS="${HELM_DATA_HOME}/plugins"
|
||||
export HELM_CONFIG_HOME="${helm_dir}/config"
|
||||
HELM_DIFF_VERSION="${HELM_DIFF_VERSION:-3.12.3}"
|
||||
HELM_DIFF_VERSION="${HELM_DIFF_VERSION:-3.12.5}"
|
||||
HELM_GIT_VERSION="${HELM_GIT_VERSION:-1.3.0}"
|
||||
HELM_SECRETS_VERSION="${HELM_SECRETS_VERSION:-3.15.0}"
|
||||
export GNUPGHOME="${PWD}/${dir}/.gnupg"
|
||||
|
|
|
|||
Loading…
Reference in New Issue