Merge branch 'main' into cache-index-file

pull/12167/head
Yarden Shoham 7 months ago
commit d9c9fd8796

@ -1,7 +1,24 @@
version: 2 version: 2
updates: updates:
- # Keep dev-v3 branch dependencies up to date, while Helm v3 is within support
package-ecosystem: "gomod"
target-branch: "dev-v3"
directory: "/"
schedule:
interval: "daily"
groups:
k8s.io:
patterns:
- "k8s.io/api"
- "k8s.io/apiextensions-apiserver"
- "k8s.io/apimachinery"
- "k8s.io/apiserver"
- "k8s.io/cli-runtime"
- "k8s.io/client-go"
- "k8s.io/kubectl"
- package-ecosystem: "gomod" - package-ecosystem: "gomod"
target-branch: "main"
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
@ -16,6 +33,7 @@ updates:
- "k8s.io/client-go" - "k8s.io/client-go"
- "k8s.io/kubectl" - "k8s.io/kubectl"
- package-ecosystem: "github-actions" - package-ecosystem: "github-actions"
target-branch: "main"
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"

@ -3,10 +3,12 @@ on:
push: push:
branches: branches:
- "main" - "main"
- "dev-v3"
- "release-**" - "release-**"
pull_request: pull_request:
branches: branches:
- main - "main"
- "dev-v3"
permissions: permissions:
contents: read contents: read
@ -16,11 +18,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout source code - name: Checkout source code
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Setup Go - name: Setup Go
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # pin@5.0.2 uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # pin@5.3.0
with: with:
go-version: '1.22.7' go-version: '1.23'
check-latest: true
- name: Test source headers are present - name: Test source headers are present
run: make test-source-headers run: make test-source-headers
- name: Run unit tests - name: Run unit tests

@ -13,10 +13,14 @@ name: "CodeQL"
on: on:
push: push:
branches: [ main ] branches:
- main
- dev-v3
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ main ] branches:
- main
- dev-v3
schedule: schedule:
- cron: '29 6 * * 6' - cron: '29 6 * * 6'
@ -39,7 +43,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL

@ -13,13 +13,14 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Setup Go - name: Setup Go
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # pin@5.0.2 uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # pin@5.3.0
with: with:
go-version: "1.22.7" go-version: '1.23'
check-latest: true
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 #pin@6.1.0 uses: golangci/golangci-lint-action@051d91933864810ecd5e2ea2cfd98f6a5bca5347 #pin@6.3.2
with: with:
version: v1.58 version: v1.62

@ -6,16 +6,19 @@ on:
schedule: schedule:
- cron: "0 0 * * *" - cron: "0 0 * * *"
permissions: read-all
jobs: jobs:
govulncheck: govulncheck:
name: govulncheck name: govulncheck
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Setup Go - name: Setup Go
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # pin@5.0.2 uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # pin@5.3.0
with: with:
go-version: '1.22.7' go-version: '1.23'
check-latest: true
- name: govulncheck - name: govulncheck
uses: golang/govulncheck-action@dd0578b371c987f96d1185abb54344b44352bd58 # pin@1.0.3 uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # pin@1.0.4
with: with:
go-package: ./... go-package: ./...

@ -7,6 +7,8 @@ on:
branches: branches:
- main - main
permissions: read-all
# Note the only differences between release and canary-release jobs are: # Note the only differences between release and canary-release jobs are:
# - only canary passes --overwrite flag # - only canary passes --overwrite flag
# - the VERSION make variable passed to 'make dist checksum' is expected to # - the VERSION make variable passed to 'make dist checksum' is expected to
@ -15,17 +17,17 @@ on:
jobs: jobs:
release: release:
if: startsWith(github.ref, 'refs/tags/v') if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest runs-on: ubuntu-latest-16-cores
steps: steps:
- name: Checkout source code - name: Checkout source code
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # pin@5.0.2 uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # pin@5.3.0
with: with:
go-version: '1.22.7' go-version: '1.23'
- name: Run unit tests - name: Run unit tests
run: make test-coverage run: make test-coverage
@ -72,16 +74,17 @@ jobs:
connection_string: ${{ secrets.AZURE_STORAGE_CONNECTION_STRING }} connection_string: ${{ secrets.AZURE_STORAGE_CONNECTION_STRING }}
canary-release: canary-release:
runs-on: ubuntu-latest runs-on: ubuntu-latest-16-cores
if: github.ref == 'refs/heads/main' if: github.ref == 'refs/heads/main'
steps: steps:
- name: Checkout source code - name: Checkout source code
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4.1.7 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
- name: Setup Go - name: Setup Go
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # pin@5.0.2 uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # pin@5.3.0
with: with:
go-version: '1.22.7' go-version: '1.23'
check-latest: true
- name: Run unit tests - name: Run unit tests
run: make test-coverage run: make test-coverage

@ -28,7 +28,7 @@ jobs:
steps: steps:
- name: "Checkout code" - name: "Checkout code"
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
persist-credentials: false persist-credentials: false
@ -55,7 +55,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab. # format to the repository Actions tab.
- name: "Upload artifact" - name: "Upload artifact"
uses: actions/upload-artifact@97a0fba1372883ab732affbe8f94b823f91727db # v3.pre.node20 uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with: with:
name: SARIF file name: SARIF file
path: results.sarif path: results.sarif

@ -9,7 +9,7 @@ jobs:
stale: stale:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@87c2b794b9b47a9bec68ae03c01aeb572ffebdb1 # v3.0.14 - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue has been marked as stale because it has been open for 90 days with no activity. This thread will be automatically closed in 30 days if no further activity occurs.' stale-issue-message: 'This issue has been marked as stale because it has been open for 90 days with no activity. This thread will be automatically closed in 30 days if no further activity occurs.'

1
.gitignore vendored

@ -12,3 +12,4 @@ bin/
vendor/ vendor/
# Ignores charts pulled for dependency build tests # Ignores charts pulled for dependency build tests
cmd/helm/testdata/testcharts/issue-7233/charts/* cmd/helm/testdata/testcharts/issue-7233/charts/*
.pre-commit-config.yaml

@ -20,6 +20,26 @@ linters-settings:
gofmt: gofmt:
simplify: true simplify: true
goimports: goimports:
local-prefixes: helm.sh/helm/v3 local-prefixes: helm.sh/helm/v4
dupl: dupl:
threshold: 400 threshold: 400
issues:
exclude-rules:
# Helm, and the Go source code itself, sometimes uses these names outside their built-in
# functions. As the Go source code has re-used these names it's ok for Helm to do the same.
# Linting will look for redefinition of built-in id's but we opt-in to the ones we choose to use.
- linters:
- revive
text: "redefines-builtin-id: redefinition of the built-in function append"
- linters:
- revive
text: "redefines-builtin-id: redefinition of the built-in function clear"
- linters:
- revive
text: "redefines-builtin-id: redefinition of the built-in function max"
- linters:
- revive
text: "redefines-builtin-id: redefinition of the built-in function min"
- linters:
- revive
text: "redefines-builtin-id: redefinition of the built-in function new"

@ -6,14 +6,20 @@
# Organizations Using Helm # Organizations Using Helm
- [IBM](https://www.ibm.com) - [IBM](https://www.ibm.com)
- [InfoCert](https://www.infocert.it/)
- [Intercept](https://Intercept.cloud)
- [Microsoft](https://microsoft.com) - [Microsoft](https://microsoft.com)
- [Octopus Deploy](https://octopus.com/)
- [New Relic](https://www.newrelic.com) - [New Relic](https://www.newrelic.com)
- [Octopus Deploy](https://octopus.com/)
- [Omnistrate](https://omnistrate.com)
- [Oracle](www.oracle.com)
- [Percona](https://www.percona.com)
- [Qovery](https://www.qovery.com/) - [Qovery](https://www.qovery.com/)
- [Samsung SDS](https://www.samsungsds.com/) - [Samsung SDS](https://www.samsungsds.com/)
- [Softonic](https://hello.softonic.com/) - [Softonic](https://hello.softonic.com/)
- [SyncTune](https://mb-consulting.dev)
- [Syself](https://syself.com) - [Syself](https://syself.com)
- [Ville de Montreal](https://montreal.ca) - [Ville de Montreal](https://montreal.ca)
- [Intercept](https://Intercept.cloud)
_This file is part of the CNCF official documentation for projects._ _This file is part of the CNCF official documentation for projects._

@ -11,6 +11,10 @@ vulnerability_, please email a report to
[cncf-helm-security@lists.cncf.io](mailto:cncf-helm-security@lists.cncf.io). This will give us a [cncf-helm-security@lists.cncf.io](mailto:cncf-helm-security@lists.cncf.io). This will give us a
chance to try to fix the issue before it is exploited in the wild. chance to try to fix the issue before it is exploited in the wild.
## Helm v3 and v4
Helm v4 is currently under development on the `main` branch. During the development of Helm v4 and for some time after its released, Helm v3 will continue to be supported and developed on the `dev-v3` branch. Helm v3 will continue to get bug fixes and updates for new Kubernetes releases. Helm v4 is where new features and major changes will happen. For features to be backported to Helm v3, an exception will be needed. Bugs should first be fixed on Helm v4 and then backported to Helm v3.
## Sign Your Work ## Sign Your Work
The sign-off is a simple line at the end of the explanation for a commit. All commits need to be The sign-off is a simple line at the end of the explanation for a commit. All commits need to be
@ -274,7 +278,7 @@ Like any good open source project, we use Pull Requests (PRs) to track code chan
#### Documentation PRs #### Documentation PRs
Documentation PRs should be made on the docs repo: <https://github.com/helm/helm-www>. Keeping Helm's documentation up to date is highly desirable, and it is recommend all user facing changes. Accurate and helpful documentation is critical for effectively communicating Helm's behavior to a wide audience. Documentation PRs should be made on the docs repo: <https://github.com/helm/helm-www>. Keeping Helm's documentation up to date is highly desirable, and is recommended for all user facing changes. Accurate and helpful documentation is critical for effectively communicating Helm's behavior to a wide audience.
Small, ad-hoc changes/PRs to Helm which introduce user facing changes, which would benefit from documentation changes, should apply the `docs needed` label. Larger changes associated with a HIP should track docs via that HIP. The `docs needed` label doesn't block PRs, and maintainers/PR reviewers should apply discretion judging in whether the `docs needed` label should be applied. Small, ad-hoc changes/PRs to Helm which introduce user facing changes, which would benefit from documentation changes, should apply the `docs needed` label. Larger changes associated with a HIP should track docs via that HIP. The `docs needed` label doesn't block PRs, and maintainers/PR reviewers should apply discretion judging in whether the `docs needed` label should be applied.

21
KEYS

@ -1037,3 +1037,24 @@ nk38BkgHg3LHjCbCNEVkSK2TMT69A58iwpY9WUQlphsiz4WBpafSPbv/jSlsm7uK
TNWtbFGBRpJyEg== TNWtbFGBRpJyEg==
=w141 =w141
-----END PGP PUBLIC KEY BLOCK----- -----END PGP PUBLIC KEY BLOCK-----
pub ed25519 2024-07-09 [SC]
7FEC81FACC7FFB2A010ADD13C2D40F4D8196E874
uid [ultimate] Robert Sirchia (I like turtles.) <rsirchia@outlook.com>
sig 3 C2D40F4D8196E874 2024-07-09 [self-signature]
sub cv25519 2024-07-09 [E]
sig C2D40F4D8196E874 2024-07-09 [self-signature]
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEZo2C6xYJKwYBBAHaRw8BAQdA8kCWaI+FlCabcTw8EVeiMkokyWDalgl/Inbn
ACcGN1e0N1JvYmVydCBTaXJjaGlhIChJIGxpa2UgdHVydGxlcy4pIDxyc2lyY2hp
YUBvdXRsb29rLmNvbT6IkwQTFgoAOxYhBH/sgfrMf/sqAQrdE8LUD02Bluh0BQJm
jYLrAhsDBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEMLUD02Bluh0dyYA
/i7RB6m3MXNA8ei7GD8uQVpLfCRgEFsqSS/AzAOu8NGhAQCbw1kWL3AUll7KKtiQ
UE96nhCk+HnkQeVkWYS+MZ1tALg4BGaNgusSCisGAQQBl1UBBQEBB0CCA6Au4krL
YinQq9aAs29fFeRu/ye3PqQuz5jZ2r1ScAMBCAeIeAQYFgoAIBYhBH/sgfrMf/sq
AQrdE8LUD02Bluh0BQJmjYLrAhsMAAoJEMLUD02Bluh0KH4BAMSwEIGkoQl10LN3
K6V08VpFmniENmCDHshXYq0gGiTDAP9FsXl2UtmFU5xuYxH4fRKIxgmxJRAFMWI8
u3Rdu/s+DQ==
=smBO
-----END PGP PUBLIC KEY BLOCK-----

@ -44,7 +44,7 @@ BINARY_VERSION ?= ${GIT_TAG}
# Only set Version if building a tag or VERSION is set # Only set Version if building a tag or VERSION is set
ifneq ($(BINARY_VERSION),) ifneq ($(BINARY_VERSION),)
LDFLAGS += -X helm.sh/helm/v3/internal/version.version=${BINARY_VERSION} LDFLAGS += -X helm.sh/helm/v4/internal/version.version=${BINARY_VERSION}
endif endif
VERSION_METADATA = unreleased VERSION_METADATA = unreleased
@ -53,9 +53,9 @@ ifneq ($(GIT_TAG),)
VERSION_METADATA = VERSION_METADATA =
endif endif
LDFLAGS += -X helm.sh/helm/v3/internal/version.metadata=${VERSION_METADATA} LDFLAGS += -X helm.sh/helm/v4/internal/version.metadata=${VERSION_METADATA}
LDFLAGS += -X helm.sh/helm/v3/internal/version.gitCommit=${GIT_COMMIT} LDFLAGS += -X helm.sh/helm/v4/internal/version.gitCommit=${GIT_COMMIT}
LDFLAGS += -X helm.sh/helm/v3/internal/version.gitTreeState=${GIT_DIRTY} LDFLAGS += -X helm.sh/helm/v4/internal/version.gitTreeState=${GIT_DIRTY}
LDFLAGS += $(EXT_LDFLAGS) LDFLAGS += $(EXT_LDFLAGS)
# Define constants based on the client-go version # Define constants based on the client-go version
@ -63,10 +63,10 @@ K8S_MODULES_VER=$(subst ., ,$(subst v,,$(shell go list -f '{{.Version}}' -m k8s.
K8S_MODULES_MAJOR_VER=$(shell echo $$(($(firstword $(K8S_MODULES_VER)) + 1))) K8S_MODULES_MAJOR_VER=$(shell echo $$(($(firstword $(K8S_MODULES_VER)) + 1)))
K8S_MODULES_MINOR_VER=$(word 2,$(K8S_MODULES_VER)) K8S_MODULES_MINOR_VER=$(word 2,$(K8S_MODULES_VER))
LDFLAGS += -X helm.sh/helm/v3/pkg/lint/rules.k8sVersionMajor=$(K8S_MODULES_MAJOR_VER) LDFLAGS += -X helm.sh/helm/v4/pkg/lint/rules.k8sVersionMajor=$(K8S_MODULES_MAJOR_VER)
LDFLAGS += -X helm.sh/helm/v3/pkg/lint/rules.k8sVersionMinor=$(K8S_MODULES_MINOR_VER) LDFLAGS += -X helm.sh/helm/v4/pkg/lint/rules.k8sVersionMinor=$(K8S_MODULES_MINOR_VER)
LDFLAGS += -X helm.sh/helm/v3/pkg/chartutil.k8sVersionMajor=$(K8S_MODULES_MAJOR_VER) LDFLAGS += -X helm.sh/helm/v4/pkg/chartutil.k8sVersionMajor=$(K8S_MODULES_MAJOR_VER)
LDFLAGS += -X helm.sh/helm/v3/pkg/chartutil.k8sVersionMinor=$(K8S_MODULES_MINOR_VER) LDFLAGS += -X helm.sh/helm/v4/pkg/chartutil.k8sVersionMinor=$(K8S_MODULES_MINOR_VER)
.PHONY: all .PHONY: all
all: build all: build
@ -78,7 +78,7 @@ all: build
build: $(BINDIR)/$(BINNAME) build: $(BINDIR)/$(BINNAME)
$(BINDIR)/$(BINNAME): $(SRC) $(BINDIR)/$(BINNAME): $(SRC)
GO111MODULE=on CGO_ENABLED=$(CGO_ENABLED) go build $(GOFLAGS) -trimpath -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o '$(BINDIR)'/$(BINNAME) ./cmd/helm CGO_ENABLED=$(CGO_ENABLED) go build $(GOFLAGS) -trimpath -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o '$(BINDIR)'/$(BINNAME) ./cmd/helm
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# install # install
@ -104,7 +104,16 @@ test: test-unit
test-unit: test-unit:
@echo @echo
@echo "==> Running unit tests <==" @echo "==> Running unit tests <=="
GO111MODULE=on go test $(GOFLAGS) -run $(TESTS) $(PKG) $(TESTFLAGS) go test $(GOFLAGS) -run $(TESTS) $(PKG) $(TESTFLAGS)
@echo
@echo "==> Running unit test(s) with ldflags <=="
# Test to check the deprecation warnings on Kubernetes templates created by `helm create` against the current Kubernetes
# version. Note: The version details are set in var LDFLAGS. To avoid the ldflags impact on other unit tests that are
# based on older versions, this is run separately. When run without the ldflags in the unit test (above) or coverage
# test, it still passes with a false-positive result as the resources shouldnt be deprecated in the older Kubernetes
# version if it only starts failing with the latest.
go test $(GOFLAGS) -run ^TestHelmCreateChart_CheckDeprecatedWarnings$$ ./pkg/lint/ $(TESTFLAGS) -ldflags '$(LDFLAGS)'
.PHONY: test-coverage .PHONY: test-coverage
test-coverage: test-coverage:
@ -142,7 +151,7 @@ coverage:
.PHONY: format .PHONY: format
format: $(GOIMPORTS) format: $(GOIMPORTS)
GO111MODULE=on go list -f '{{.Dir}}' ./... | xargs $(GOIMPORTS) -w -local helm.sh/helm go list -f '{{.Dir}}' ./... | xargs $(GOIMPORTS) -w -local helm.sh/helm
# Generate golden files used in unit tests # Generate golden files used in unit tests
.PHONY: gen-test-golden .PHONY: gen-test-golden
@ -159,10 +168,10 @@ gen-test-golden: test-unit
# without a go.mod file when downloading the following dependencies # without a go.mod file when downloading the following dependencies
$(GOX): $(GOX):
(cd /; GO111MODULE=on go install github.com/mitchellh/gox@v1.0.2-0.20220701044238-9f712387e2d2) (cd /; go install github.com/mitchellh/gox@v1.0.2-0.20220701044238-9f712387e2d2)
$(GOIMPORTS): $(GOIMPORTS):
(cd /; GO111MODULE=on go install golang.org/x/tools/cmd/goimports@latest) (cd /; go install golang.org/x/tools/cmd/goimports@latest)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# release # release
@ -170,7 +179,7 @@ $(GOIMPORTS):
.PHONY: build-cross .PHONY: build-cross
build-cross: LDFLAGS += -extldflags "-static" build-cross: LDFLAGS += -extldflags "-static"
build-cross: $(GOX) build-cross: $(GOX)
GOFLAGS="-trimpath" GO111MODULE=on CGO_ENABLED=0 $(GOX) -parallel=3 -output="_dist/{{.OS}}-{{.Arch}}/$(BINNAME)" -osarch='$(TARGETS)' $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' ./cmd/helm GOFLAGS="-trimpath" CGO_ENABLED=0 $(GOX) -parallel=3 -output="_dist/{{.OS}}-{{.Arch}}/$(BINNAME)" -osarch='$(TARGETS)' $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' ./cmd/helm
.PHONY: dist .PHONY: dist
dist: dist:

@ -1,15 +1,16 @@
maintainers: maintainers:
- gjenkins8
- joejulian - joejulian
- jdolitsky
- marckhouzam - marckhouzam
- mattfarina - mattfarina
- robertsirc
- sabre1041 - sabre1041
- scottrigby - scottrigby
- technosophos - technosophos
triage: triage:
- banjoh
- yxxhero - yxxhero
- zonggen - zonggen
- gjenkins8
- z4ce - z4ce
emeritus: emeritus:
- adamreese - adamreese
@ -17,6 +18,7 @@ emeritus:
- fibonacci1729 - fibonacci1729
- hickeyma - hickeyma
- jascott1 - jascott1
- jdolitsky
- michelleN - michelleN
- migmartri - migmartri
- nebril - nebril

@ -2,7 +2,7 @@
[![Build Status](https://github.com/helm/helm/workflows/release/badge.svg)](https://github.com/helm/helm/actions?workflow=release) [![Build Status](https://github.com/helm/helm/workflows/release/badge.svg)](https://github.com/helm/helm/actions?workflow=release)
[![Go Report Card](https://goreportcard.com/badge/github.com/helm/helm)](https://goreportcard.com/report/github.com/helm/helm) [![Go Report Card](https://goreportcard.com/badge/github.com/helm/helm)](https://goreportcard.com/report/github.com/helm/helm)
[![GoDoc](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/helm.sh/helm/v3) [![GoDoc](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/helm.sh/helm/v4)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3131/badge)](https://bestpractices.coreinfrastructure.org/projects/3131) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3131/badge)](https://bestpractices.coreinfrastructure.org/projects/3131)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/helm/helm/badge)](https://scorecard.dev/viewer/?uri=github.com/helm/helm) [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/helm/helm/badge)](https://scorecard.dev/viewer/?uri=github.com/helm/helm)
@ -29,6 +29,11 @@ Think of it like apt/yum/homebrew for Kubernetes.
- Charts can be stored on disk, or fetched from remote chart repositories - Charts can be stored on disk, or fetched from remote chart repositories
(like Debian or RedHat packages) (like Debian or RedHat packages)
## Helm Development and Stable Versions
Helm v4 is currently under development on the `main` branch. This is unstable and the APIs within the Go SDK and at the command line are changing.
Helm v3 (current stable) is maintained on the `dev-v3` branch. APIs there follow semantic versioning.
## Install ## Install
Binary downloads of the Helm client can be found on [the Releases page](https://github.com/helm/helm/releases/latest). Binary downloads of the Helm client can be found on [the Releases page](https://github.com/helm/helm/releases/latest).
@ -39,8 +44,10 @@ If you want to use a package manager:
- [Homebrew](https://brew.sh/) users can use `brew install helm`. - [Homebrew](https://brew.sh/) users can use `brew install helm`.
- [Chocolatey](https://chocolatey.org/) users can use `choco install kubernetes-helm`. - [Chocolatey](https://chocolatey.org/) users can use `choco install kubernetes-helm`.
- [Winget](https://learn.microsoft.com/en-us/windows/package-manager/) users can use `winget install Helm.Helm`.
- [Scoop](https://scoop.sh/) users can use `scoop install helm`. - [Scoop](https://scoop.sh/) users can use `scoop install helm`.
- [Snapcraft](https://snapcraft.io/) users can use `snap install helm --classic` - [Snapcraft](https://snapcraft.io/) users can use `snap install helm --classic`.
- [Flox](https://flox.dev) users can use `flox install kubernetes-helm`.
To rapidly get Helm up and running, start with the [Quick Start Guide](https://helm.sh/docs/intro/quickstart/). To rapidly get Helm up and running, start with the [Quick Start Guide](https://helm.sh/docs/intro/quickstart/).
@ -55,6 +62,8 @@ Get started with the [Quick Start guide](https://helm.sh/docs/intro/quickstart/)
The [Helm roadmap uses GitHub milestones](https://github.com/helm/helm/milestones) to track the progress of the project. The [Helm roadmap uses GitHub milestones](https://github.com/helm/helm/milestones) to track the progress of the project.
The development of Helm v4 is currently happening on the `main` branch while the development of Helm v3, the stable branch, is happening on the `dev-v3` branch. Changes should be made to the `main` branch prior to being added to the `dev-v3` branch so that all changes are carried along to Helm v4.
## Community, discussion, contribution, and support ## Community, discussion, contribution, and support
You can reach the Helm community and developers via the following channels: You can reach the Helm community and developers via the following channels:

@ -23,7 +23,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
) )
const completionDesc = ` const completionDesc = `

@ -21,8 +21,8 @@ import (
"strings" "strings"
"testing" "testing"
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
) )
// Check if file completion should be performed according to parameter 'shouldBePerformed' // Check if file completion should be performed according to parameter 'shouldBePerformed'

@ -23,10 +23,10 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v4/pkg/chartutil"
"helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v4/pkg/helmpath"
) )
const createDesc = ` const createDesc = `

@ -22,11 +22,11 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v4/internal/test/ensure"
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v4/pkg/chart/loader"
"helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v4/pkg/chartutil"
"helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v4/pkg/helmpath"
) )
func TestCreateCmd(t *testing.T) { func TestCreateCmd(t *testing.T) {

@ -20,9 +20,10 @@ import (
"path/filepath" "path/filepath"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
) )
const dependencyDesc = ` const dependencyDesc = `
@ -93,7 +94,7 @@ func newDependencyCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
cmd.AddCommand(newDependencyListCmd(out)) cmd.AddCommand(newDependencyListCmd(out))
cmd.AddCommand(newDependencyUpdateCmd(cfg, out)) cmd.AddCommand(newDependencyUpdateCmd(cfg, out))
cmd.AddCommand(newDependencyBuildCmd(cfg, out)) cmd.AddCommand(newDependencyBuildCmd(out))
return cmd return cmd
} }
@ -120,3 +121,16 @@ func newDependencyListCmd(out io.Writer) *cobra.Command {
f.UintVar(&client.ColumnWidth, "max-col-width", 80, "maximum column width for output table") f.UintVar(&client.ColumnWidth, "max-col-width", 80, "maximum column width for output table")
return cmd return cmd
} }
func addDependencySubcommandFlags(f *pflag.FlagSet, client *action.Dependency) {
f.BoolVar(&client.Verify, "verify", false, "verify the packages against signatures")
f.StringVar(&client.Keyring, "keyring", defaultKeyring(), "keyring containing public keys")
f.BoolVar(&client.SkipRefresh, "skip-refresh", false, "do not refresh the local repository cache")
f.StringVar(&client.Username, "username", "", "chart repository username where to locate the requested chart")
f.StringVar(&client.Password, "password", "", "chart repository password where to locate the requested chart")
f.StringVar(&client.CertFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVar(&client.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.BoolVar(&client.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download")
f.BoolVar(&client.PlainHTTP, "plain-http", false, "use insecure HTTP connections for the chart download")
f.StringVar(&client.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
}

@ -24,12 +24,12 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/client-go/util/homedir" "k8s.io/client-go/util/homedir"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/cache" "helm.sh/helm/v4/pkg/cache"
"helm.sh/helm/v3/pkg/downloader" "helm.sh/helm/v4/pkg/downloader"
"helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
) )
const dependencyBuildDesc = ` const dependencyBuildDesc = `
@ -43,7 +43,7 @@ If no lock file is found, 'helm dependency build' will mirror the behavior
of 'helm dependency update'. of 'helm dependency update'.
` `
func newDependencyBuildCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func newDependencyBuildCmd(out io.Writer) *cobra.Command {
client := action.NewDependency() client := action.NewDependency()
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -56,6 +56,11 @@ func newDependencyBuildCmd(cfg *action.Configuration, out io.Writer) *cobra.Comm
if len(args) > 0 { if len(args) > 0 {
chartpath = filepath.Clean(args[0]) chartpath = filepath.Clean(args[0])
} }
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
client.InsecureSkipTLSverify, client.PlainHTTP, client.Username, client.Password)
if err != nil {
return fmt.Errorf("missing registry client: %w", err)
}
var c cache.Cache[*repo.IndexFile] = cache.NewConcurrentMapCache[*repo.IndexFile]() var c cache.Cache[*repo.IndexFile] = cache.NewConcurrentMapCache[*repo.IndexFile]()
man := &downloader.Manager{ man := &downloader.Manager{
Out: out, Out: out,
@ -63,7 +68,7 @@ func newDependencyBuildCmd(cfg *action.Configuration, out io.Writer) *cobra.Comm
Keyring: client.Keyring, Keyring: client.Keyring,
SkipUpdate: client.SkipRefresh, SkipUpdate: client.SkipRefresh,
Getters: getter.All(settings), Getters: getter.All(settings),
RegistryClient: cfg.RegistryClient, RegistryClient: registryClient,
RepositoryConfig: settings.RepositoryConfig, RepositoryConfig: settings.RepositoryConfig,
RepositoryCache: settings.RepositoryCache, RepositoryCache: settings.RepositoryCache,
Debug: settings.Debug, Debug: settings.Debug,
@ -72,7 +77,7 @@ func newDependencyBuildCmd(cfg *action.Configuration, out io.Writer) *cobra.Comm
if client.Verify { if client.Verify {
man.Verify = downloader.VerifyIfPossible man.Verify = downloader.VerifyIfPossible
} }
err := man.Build() err = man.Build()
if e, ok := err.(downloader.ErrRepoNotFound); ok { if e, ok := err.(downloader.ErrRepoNotFound); ok {
return fmt.Errorf("%s. Please add the missing repos via 'helm repo add'", e.Error()) return fmt.Errorf("%s. Please add the missing repos via 'helm repo add'", e.Error())
} }
@ -81,9 +86,7 @@ func newDependencyBuildCmd(cfg *action.Configuration, out io.Writer) *cobra.Comm
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&client.Verify, "verify", false, "verify the packages against signatures") addDependencySubcommandFlags(f, client)
f.StringVar(&client.Keyring, "keyring", defaultKeyring(), "keyring containing public keys")
f.BoolVar(&client.SkipRefresh, "skip-refresh", false, "do not refresh the local repository cache")
return cmd return cmd
} }

@ -22,10 +22,10 @@ import (
"strings" "strings"
"testing" "testing"
"helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v4/pkg/chartutil"
"helm.sh/helm/v3/pkg/provenance" "helm.sh/helm/v4/pkg/provenance"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
"helm.sh/helm/v3/pkg/repo/repotest" "helm.sh/helm/v4/pkg/repo/repotest"
) )
func TestDependencyBuildCmd(t *testing.T) { func TestDependencyBuildCmd(t *testing.T) {
@ -58,7 +58,7 @@ func TestDependencyBuildCmd(t *testing.T) {
createTestingChart(t, rootDir, chartname, srv.URL()) createTestingChart(t, rootDir, chartname, srv.URL())
repoFile := filepath.Join(rootDir, "repositories.yaml") repoFile := filepath.Join(rootDir, "repositories.yaml")
cmd := fmt.Sprintf("dependency build '%s' --repository-config %s --repository-cache %s", filepath.Join(rootDir, chartname), repoFile, rootDir) cmd := fmt.Sprintf("dependency build '%s' --repository-config %s --repository-cache %s --plain-http", filepath.Join(rootDir, chartname), repoFile, rootDir)
_, out, err := executeActionCommand(cmd) _, out, err := executeActionCommand(cmd)
// In the first pass, we basically want the same results as an update. // In the first pass, we basically want the same results as an update.
@ -117,7 +117,7 @@ func TestDependencyBuildCmd(t *testing.T) {
t.Errorf("mismatched versions. Expected %q, got %q", "0.1.0", v) t.Errorf("mismatched versions. Expected %q, got %q", "0.1.0", v)
} }
skipRefreshCmd := fmt.Sprintf("dependency build '%s' --skip-refresh --repository-config %s --repository-cache %s", filepath.Join(rootDir, chartname), repoFile, rootDir) skipRefreshCmd := fmt.Sprintf("dependency build '%s' --skip-refresh --repository-config %s --repository-cache %s --plain-http", filepath.Join(rootDir, chartname), repoFile, rootDir)
_, out, err = executeActionCommand(skipRefreshCmd) _, out, err = executeActionCommand(skipRefreshCmd)
// In this pass, we check --skip-refresh option becomes effective. // In this pass, we check --skip-refresh option becomes effective.
@ -134,7 +134,7 @@ func TestDependencyBuildCmd(t *testing.T) {
if err := chartutil.SaveDir(c, dir()); err != nil { if err := chartutil.SaveDir(c, dir()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
cmd = fmt.Sprintf("dependency build '%s' --repository-config %s --repository-cache %s --registry-config %s/config.json", cmd = fmt.Sprintf("dependency build '%s' --repository-config %s --repository-cache %s --registry-config %s/config.json --plain-http",
dir(ociChartName), dir(ociChartName),
dir("repositories.yaml"), dir("repositories.yaml"),
dir(), dir(),

@ -16,17 +16,18 @@ limitations under the License.
package main package main
import ( import (
"fmt"
"io" "io"
"path/filepath" "path/filepath"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/cache" "helm.sh/helm/v4/pkg/cache"
"helm.sh/helm/v3/pkg/downloader" "helm.sh/helm/v4/pkg/downloader"
"helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
) )
const dependencyUpDesc = ` const dependencyUpDesc = `
@ -45,7 +46,7 @@ in the Chart.yaml file, but (b) at the wrong version.
` `
// newDependencyUpdateCmd creates a new dependency update command. // newDependencyUpdateCmd creates a new dependency update command.
func newDependencyUpdateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func newDependencyUpdateCmd(_ *action.Configuration, out io.Writer) *cobra.Command {
client := action.NewDependency() client := action.NewDependency()
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -59,6 +60,11 @@ func newDependencyUpdateCmd(cfg *action.Configuration, out io.Writer) *cobra.Com
if len(args) > 0 { if len(args) > 0 {
chartpath = filepath.Clean(args[0]) chartpath = filepath.Clean(args[0])
} }
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
client.InsecureSkipTLSverify, client.PlainHTTP, client.Username, client.Password)
if err != nil {
return fmt.Errorf("missing registry client: %w", err)
}
// the helm client cli is run as a short-lived process so it's ok to use a simple // the helm client cli is run as a short-lived process so it's ok to use a simple
// implementation for a strictly growing cache // implementation for a strictly growing cache
var c cache.Cache[*repo.IndexFile] = cache.NewConcurrentMapCache[*repo.IndexFile]() var c cache.Cache[*repo.IndexFile] = cache.NewConcurrentMapCache[*repo.IndexFile]()
@ -68,7 +74,7 @@ func newDependencyUpdateCmd(cfg *action.Configuration, out io.Writer) *cobra.Com
Keyring: client.Keyring, Keyring: client.Keyring,
SkipUpdate: client.SkipRefresh, SkipUpdate: client.SkipRefresh,
Getters: getter.All(settings), Getters: getter.All(settings),
RegistryClient: cfg.RegistryClient, RegistryClient: registryClient,
RepositoryConfig: settings.RepositoryConfig, RepositoryConfig: settings.RepositoryConfig,
RepositoryCache: settings.RepositoryCache, RepositoryCache: settings.RepositoryCache,
Debug: settings.Debug, Debug: settings.Debug,
@ -82,9 +88,7 @@ func newDependencyUpdateCmd(cfg *action.Configuration, out io.Writer) *cobra.Com
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&client.Verify, "verify", false, "verify the packages against signatures") addDependencySubcommandFlags(f, client)
f.StringVar(&client.Keyring, "keyring", defaultKeyring(), "keyring containing public keys")
f.BoolVar(&client.SkipRefresh, "skip-refresh", false, "do not refresh the local repository cache")
return cmd return cmd
} }

@ -22,13 +22,13 @@ import (
"strings" "strings"
"testing" "testing"
"helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v4/internal/test/ensure"
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v4/pkg/chartutil"
"helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v4/pkg/helmpath"
"helm.sh/helm/v3/pkg/provenance" "helm.sh/helm/v4/pkg/provenance"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
"helm.sh/helm/v3/pkg/repo/repotest" "helm.sh/helm/v4/pkg/repo/repotest"
) )
func TestDependencyUpdateCmd(t *testing.T) { func TestDependencyUpdateCmd(t *testing.T) {
@ -67,7 +67,7 @@ func TestDependencyUpdateCmd(t *testing.T) {
} }
_, out, err := executeActionCommand( _, out, err := executeActionCommand(
fmt.Sprintf("dependency update '%s' --repository-config %s --repository-cache %s", dir(chartname), dir("repositories.yaml"), dir()), fmt.Sprintf("dependency update '%s' --repository-config %s --repository-cache %s --plain-http", dir(chartname), dir("repositories.yaml"), dir()),
) )
if err != nil { if err != nil {
t.Logf("Output: %s", out) t.Logf("Output: %s", out)
@ -110,7 +110,7 @@ func TestDependencyUpdateCmd(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
_, out, err = executeActionCommand(fmt.Sprintf("dependency update '%s' --repository-config %s --repository-cache %s", dir(chartname), dir("repositories.yaml"), dir())) _, out, err = executeActionCommand(fmt.Sprintf("dependency update '%s' --repository-config %s --repository-cache %s --plain-http", dir(chartname), dir("repositories.yaml"), dir()))
if err != nil { if err != nil {
t.Logf("Output: %s", out) t.Logf("Output: %s", out)
t.Fatal(err) t.Fatal(err)
@ -131,7 +131,7 @@ func TestDependencyUpdateCmd(t *testing.T) {
if err := chartutil.SaveDir(c, dir()); err != nil { if err := chartutil.SaveDir(c, dir()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
cmd := fmt.Sprintf("dependency update '%s' --repository-config %s --repository-cache %s --registry-config %s/config.json", cmd := fmt.Sprintf("dependency update '%s' --repository-config %s --repository-cache %s --registry-config %s/config.json --plain-http",
dir(ociChartName), dir(ociChartName),
dir("repositories.yaml"), dir("repositories.yaml"),
dir(), dir(),
@ -169,7 +169,7 @@ func TestDependencyUpdateCmd_DoNotDeleteOldChartsOnError(t *testing.T) {
} }
createTestingChart(t, dir(), chartname, srv.URL()) createTestingChart(t, dir(), chartname, srv.URL())
_, output, err := executeActionCommand(fmt.Sprintf("dependency update %s --repository-config %s --repository-cache %s", dir(chartname), dir("repositories.yaml"), dir())) _, output, err := executeActionCommand(fmt.Sprintf("dependency update %s --repository-config %s --repository-cache %s --plain-http", dir(chartname), dir("repositories.yaml"), dir()))
if err != nil { if err != nil {
t.Logf("Output: %s", output) t.Logf("Output: %s", output)
t.Fatal(err) t.Fatal(err)
@ -178,7 +178,7 @@ func TestDependencyUpdateCmd_DoNotDeleteOldChartsOnError(t *testing.T) {
// Chart repo is down // Chart repo is down
srv.Stop() srv.Stop()
_, output, err = executeActionCommand(fmt.Sprintf("dependency update %s --repository-config %s --repository-cache %s", dir(chartname), dir("repositories.yaml"), dir())) _, output, err = executeActionCommand(fmt.Sprintf("dependency update %s --repository-config %s --repository-cache %s --plain-http", dir(chartname), dir("repositories.yaml"), dir()))
if err == nil { if err == nil {
t.Logf("Output: %s", output) t.Logf("Output: %s", output)
t.Fatal("Expected error, got nil") t.Fatal("Expected error, got nil")

@ -28,7 +28,7 @@ import (
"golang.org/x/text/cases" "golang.org/x/text/cases"
"golang.org/x/text/language" "golang.org/x/text/language"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
) )
const docsDesc = ` const docsDesc = `

@ -23,7 +23,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
) )
var envHelp = ` var envHelp = `

@ -28,12 +28,12 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"k8s.io/klog/v2" "k8s.io/klog/v2"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"
"helm.sh/helm/v3/pkg/cli/values" "helm.sh/helm/v4/pkg/cli/values"
"helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v4/pkg/helmpath"
"helm.sh/helm/v3/pkg/postrender" "helm.sh/helm/v4/pkg/postrender"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
) )
const ( const (

@ -20,9 +20,9 @@ import (
"fmt" "fmt"
"testing" "testing"
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
helmtime "helm.sh/helm/v3/pkg/time" helmtime "helm.sh/helm/v4/pkg/time"
) )
func outputFlagCompletionTest(t *testing.T, cmdName string) { func outputFlagCompletionTest(t *testing.T, cmdName string) {

@ -21,8 +21,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
) )
var getHelp = ` var getHelp = `

@ -22,9 +22,9 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"
) )
var getAllHelp = ` var getAllHelp = `
@ -58,7 +58,12 @@ func newGetAllCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
} }
return tpl(template, data, out) return tpl(template, data, out)
} }
return output.Table.Write(out, &statusPrinter{res, true, false, false, true, false}) return output.Table.Write(out, &statusPrinter{
release: res,
debug: true,
showMetadata: true,
hideNotes: false,
})
}, },
} }
@ -70,7 +75,6 @@ func newGetAllCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
} }
return nil, cobra.ShellCompDirectiveNoFileComp return nil, cobra.ShellCompDirectiveNoFileComp
}) })
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

@ -19,7 +19,7 @@ package main
import ( import (
"testing" "testing"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
) )
func TestGetCmd(t *testing.T) { func TestGetCmd(t *testing.T) {

@ -23,8 +23,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
) )
const getHooksHelp = ` const getHooksHelp = `

@ -19,7 +19,7 @@ package main
import ( import (
"testing" "testing"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
) )
func TestGetHooks(t *testing.T) { func TestGetHooks(t *testing.T) {

@ -23,8 +23,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
) )
var getManifestHelp = ` var getManifestHelp = `

@ -19,7 +19,7 @@ package main
import ( import (
"testing" "testing"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
) )
func TestGetManifest(t *testing.T) { func TestGetManifest(t *testing.T) {

@ -22,10 +22,11 @@ import (
"log" "log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
k8sLabels "k8s.io/apimachinery/pkg/labels"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"
) )
type metadataWriter struct { type metadataWriter struct {
@ -78,10 +79,13 @@ func (w metadataWriter) WriteTable(out io.Writer) error {
_, _ = fmt.Fprintf(out, "CHART: %v\n", w.metadata.Chart) _, _ = fmt.Fprintf(out, "CHART: %v\n", w.metadata.Chart)
_, _ = fmt.Fprintf(out, "VERSION: %v\n", w.metadata.Version) _, _ = fmt.Fprintf(out, "VERSION: %v\n", w.metadata.Version)
_, _ = fmt.Fprintf(out, "APP_VERSION: %v\n", w.metadata.AppVersion) _, _ = fmt.Fprintf(out, "APP_VERSION: %v\n", w.metadata.AppVersion)
_, _ = fmt.Fprintf(out, "ANNOTATIONS: %v\n", k8sLabels.Set(w.metadata.Annotations).String())
_, _ = fmt.Fprintf(out, "DEPENDENCIES: %v\n", w.metadata.FormattedDepNames())
_, _ = fmt.Fprintf(out, "NAMESPACE: %v\n", w.metadata.Namespace) _, _ = fmt.Fprintf(out, "NAMESPACE: %v\n", w.metadata.Namespace)
_, _ = fmt.Fprintf(out, "REVISION: %v\n", w.metadata.Revision) _, _ = fmt.Fprintf(out, "REVISION: %v\n", w.metadata.Revision)
_, _ = fmt.Fprintf(out, "STATUS: %v\n", w.metadata.Status) _, _ = fmt.Fprintf(out, "STATUS: %v\n", w.metadata.Status)
_, _ = fmt.Fprintf(out, "DEPLOYED_AT: %v\n", w.metadata.DeployedAt) _, _ = fmt.Fprintf(out, "DEPLOYED_AT: %v\n", w.metadata.DeployedAt)
return nil return nil
} }

@ -19,7 +19,7 @@ package main
import ( import (
"testing" "testing"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
) )
func TestGetMetadataCmd(t *testing.T) { func TestGetMetadataCmd(t *testing.T) {

@ -23,8 +23,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
) )
var getNotesHelp = ` var getNotesHelp = `

@ -19,7 +19,7 @@ package main
import ( import (
"testing" "testing"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
) )
func TestGetNotesCmd(t *testing.T) { func TestGetNotesCmd(t *testing.T) {

@ -23,9 +23,9 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"
) )
var getValuesHelp = ` var getValuesHelp = `

@ -19,7 +19,7 @@ package main
import ( import (
"testing" "testing"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
) )
func TestGetValuesCmd(t *testing.T) { func TestGetValuesCmd(t *testing.T) {

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package main // import "helm.sh/helm/v3/cmd/helm" package main // import "helm.sh/helm/v4/cmd/helm"
import ( import (
"fmt" "fmt"
@ -30,12 +30,12 @@ import (
// Import to initialize client auth plugins. // Import to initialize client auth plugins.
_ "k8s.io/client-go/plugin/pkg/client/auth" _ "k8s.io/client-go/plugin/pkg/client/auth"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v4/pkg/cli"
"helm.sh/helm/v3/pkg/kube" "helm.sh/helm/v4/pkg/kube"
kubefake "helm.sh/helm/v3/pkg/kube/fake" kubefake "helm.sh/helm/v4/pkg/kube/fake"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
"helm.sh/helm/v3/pkg/storage/driver" "helm.sh/helm/v4/pkg/storage/driver"
) )
var settings = cli.New() var settings = cli.New()

@ -28,15 +28,15 @@ import (
shellwords "github.com/mattn/go-shellwords" shellwords "github.com/mattn/go-shellwords"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/internal/test" "helm.sh/helm/v4/internal/test"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v4/pkg/chartutil"
"helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v4/pkg/cli"
kubefake "helm.sh/helm/v3/pkg/kube/fake" kubefake "helm.sh/helm/v4/pkg/kube/fake"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
"helm.sh/helm/v3/pkg/storage" "helm.sh/helm/v4/pkg/storage"
"helm.sh/helm/v3/pkg/storage/driver" "helm.sh/helm/v4/pkg/storage/driver"
"helm.sh/helm/v3/pkg/time" "helm.sh/helm/v4/pkg/time"
) )
func testTimestamper() time.Time { return time.Unix(242085845, 0).UTC() } func testTimestamper() time.Time { return time.Unix(242085845, 0).UTC() }

@ -25,13 +25,13 @@ import (
"github.com/gosuri/uitable" "github.com/gosuri/uitable"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
"helm.sh/helm/v3/pkg/releaseutil" "helm.sh/helm/v4/pkg/releaseutil"
helmtime "helm.sh/helm/v3/pkg/time" helmtime "helm.sh/helm/v4/pkg/time"
) )
var historyHelp = ` var historyHelp = `
@ -136,7 +136,7 @@ func getHistory(client *action.History, name string) (releaseHistory, error) {
func getReleaseHistory(rls []*release.Release) (history releaseHistory) { func getReleaseHistory(rls []*release.Release) (history releaseHistory) {
for i := len(rls) - 1; i >= 0; i-- { for i := len(rls) - 1; i >= 0; i-- {
r := rls[i] r := rls[i]
c := formatChartname(r.Chart) c := formatChartName(r.Chart)
s := r.Info.Status.String() s := r.Info.Status.String()
v := r.Version v := r.Version
d := r.Info.Description d := r.Info.Description
@ -159,7 +159,7 @@ func getReleaseHistory(rls []*release.Release) (history releaseHistory) {
return history return history
} }
func formatChartname(c *chart.Chart) string { func formatChartName(c *chart.Chart) string {
if c == nil || c.Metadata == nil { if c == nil || c.Metadata == nil {
// This is an edge case that has happened in prod, though we don't // This is an edge case that has happened in prod, though we don't
// know how: https://github.com/helm/helm/issues/1347 // know how: https://github.com/helm/helm/issues/1347
@ -177,22 +177,15 @@ func formatAppVersion(c *chart.Chart) string {
return c.AppVersion() return c.AppVersion()
} }
func min(x, y int) int {
if x < y {
return x
}
return y
}
func compListRevisions(_ string, cfg *action.Configuration, releaseName string) ([]string, cobra.ShellCompDirective) { func compListRevisions(_ string, cfg *action.Configuration, releaseName string) ([]string, cobra.ShellCompDirective) {
client := action.NewHistory(cfg) client := action.NewHistory(cfg)
var revisions []string var revisions []string
if hist, err := client.Run(releaseName); err == nil { if hist, err := client.Run(releaseName); err == nil {
for _, release := range hist { for _, version := range hist {
appVersion := fmt.Sprintf("App: %s", release.Chart.Metadata.AppVersion) appVersion := fmt.Sprintf("App: %s", version.Chart.Metadata.AppVersion)
chartDesc := fmt.Sprintf("Chart: %s-%s", release.Chart.Metadata.Name, release.Chart.Metadata.Version) chartDesc := fmt.Sprintf("Chart: %s-%s", version.Chart.Metadata.Name, version.Chart.Metadata.Version)
revisions = append(revisions, fmt.Sprintf("%s\t%s, %s", strconv.Itoa(release.Version), appVersion, chartDesc)) revisions = append(revisions, fmt.Sprintf("%s\t%s, %s", strconv.Itoa(version.Version), appVersion, chartDesc))
} }
return revisions, cobra.ShellCompDirectiveNoFileComp return revisions, cobra.ShellCompDirectiveNoFileComp
} }

@ -20,7 +20,7 @@ import (
"fmt" "fmt"
"testing" "testing"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
) )
func TestHistoryCmd(t *testing.T) { func TestHistoryCmd(t *testing.T) {

@ -30,15 +30,15 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v4/pkg/chart/loader"
"helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"
"helm.sh/helm/v3/pkg/cli/values" "helm.sh/helm/v4/pkg/cli/values"
"helm.sh/helm/v3/pkg/downloader" "helm.sh/helm/v4/pkg/downloader"
"helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
) )
const installDesc = ` const installDesc = `
@ -141,7 +141,7 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
}, },
RunE: func(_ *cobra.Command, args []string) error { RunE: func(_ *cobra.Command, args []string) error {
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
client.InsecureSkipTLSverify, client.PlainHTTP) client.InsecureSkipTLSverify, client.PlainHTTP, client.Username, client.Password)
if err != nil { if err != nil {
return fmt.Errorf("missing registry client: %w", err) return fmt.Errorf("missing registry client: %w", err)
} }
@ -158,7 +158,12 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
return errors.Wrap(err, "INSTALLATION FAILED") return errors.Wrap(err, "INSTALLATION FAILED")
} }
return outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false, false, client.HideNotes}) return outfmt.Write(out, &statusPrinter{
release: rel,
debug: settings.Debug,
showMetadata: false,
hideNotes: client.HideNotes,
})
}, },
} }
@ -184,7 +189,7 @@ func addInstallFlags(cmd *cobra.Command, f *pflag.FlagSet, client *action.Instal
f.Lookup("dry-run").NoOptDefVal = "client" f.Lookup("dry-run").NoOptDefVal = "client"
f.BoolVar(&client.Force, "force", false, "force resource updates through a replacement strategy") f.BoolVar(&client.Force, "force", false, "force resource updates through a replacement strategy")
f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during install") f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during install")
f.BoolVar(&client.Replace, "replace", false, "re-use the given name, only if that name is a deleted release which remains in the history. This is unsafe in production") f.BoolVar(&client.Replace, "replace", false, "reuse the given name, only if that name is a deleted release which remains in the history. This is unsafe in production")
f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)")
f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout") f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout")
f.BoolVar(&client.WaitForJobs, "wait-for-jobs", false, "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") f.BoolVar(&client.WaitForJobs, "wait-for-jobs", false, "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")
@ -201,6 +206,7 @@ func addInstallFlags(cmd *cobra.Command, f *pflag.FlagSet, client *action.Instal
f.StringToStringVarP(&client.Labels, "labels", "l", nil, "Labels that would be added to release metadata. Should be divided by comma.") f.StringToStringVarP(&client.Labels, "labels", "l", nil, "Labels that would be added to release metadata. Should be divided by comma.")
f.BoolVar(&client.EnableDNS, "enable-dns", false, "enable DNS lookups when rendering templates") f.BoolVar(&client.EnableDNS, "enable-dns", false, "enable DNS lookups when rendering templates")
f.BoolVar(&client.HideNotes, "hide-notes", false, "if set, do not show notes in install output. Does not affect presence in chart metadata") f.BoolVar(&client.HideNotes, "hide-notes", false, "if set, do not show notes in install output. Does not affect presence in chart metadata")
f.BoolVar(&client.TakeOwnership, "take-ownership", false, "if set, install will ignore the check for helm annotations and take ownership of the existing resources")
addValueOptionsFlags(f, valueOpts) addValueOptionsFlags(f, valueOpts)
addChartPathOptionsFlags(f, &client.ChartPathOptions) addChartPathOptionsFlags(f, &client.ChartPathOptions)
@ -214,7 +220,6 @@ func addInstallFlags(cmd *cobra.Command, f *pflag.FlagSet, client *action.Instal
} }
return compVersionFlag(args[requiredArgs-1], toComplete) return compVersionFlag(args[requiredArgs-1], toComplete)
}) })
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

@ -23,7 +23,7 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"helm.sh/helm/v3/pkg/repo/repotest" "helm.sh/helm/v4/pkg/repo/repotest"
) )
func TestInstall(t *testing.T) { func TestInstall(t *testing.T) {
@ -96,12 +96,18 @@ func TestInstall(t *testing.T) {
golden: "output/install-no-args.txt", golden: "output/install-no-args.txt",
wantError: true, wantError: true,
}, },
// Install, re-use name // Install, reuse name
{ {
name: "install and replace release", name: "install and replace release",
cmd: "install aeneas testdata/testcharts/empty --replace", cmd: "install aeneas testdata/testcharts/empty --replace",
golden: "output/install-and-replace.txt", golden: "output/install-and-replace.txt",
}, },
// Install, take ownership
{
name: "install and replace release",
cmd: "install aeneas-take-ownership testdata/testcharts/empty --take-ownership",
golden: "output/install-and-take-ownership.txt",
},
// Install, with timeout // Install, with timeout
{ {
name: "install with a timeout", name: "install with a timeout",

@ -26,11 +26,11 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v4/pkg/chartutil"
"helm.sh/helm/v3/pkg/cli/values" "helm.sh/helm/v4/pkg/cli/values"
"helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v3/pkg/lint/support" "helm.sh/helm/v4/pkg/lint/support"
) )
var longLintHelp = ` var longLintHelp = `

@ -25,10 +25,10 @@ import (
"github.com/gosuri/uitable" "github.com/gosuri/uitable"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
) )
var listHelp = ` var listHelp = `
@ -156,7 +156,7 @@ func newReleaseListWriter(releases []*release.Release, timeFormat string, noHead
Namespace: r.Namespace, Namespace: r.Namespace,
Revision: strconv.Itoa(r.Version), Revision: strconv.Itoa(r.Version),
Status: r.Info.Status.String(), Status: r.Info.Status.String(),
Chart: formatChartname(r.Chart), Chart: formatChartName(r.Chart),
AppVersion: formatAppVersion(r.Chart), AppVersion: formatAppVersion(r.Chart),
} }

@ -19,9 +19,9 @@ package main
import ( import (
"testing" "testing"
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
"helm.sh/helm/v3/pkg/time" "helm.sh/helm/v4/pkg/time"
) )
func TestListCmd(t *testing.T) { func TestListCmd(t *testing.T) {

@ -31,7 +31,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
"helm.sh/helm/v3/pkg/plugin" "helm.sh/helm/v4/pkg/plugin"
) )
const ( const (
@ -286,7 +286,7 @@ func addPluginCommands(plugin *plugin.Plugin, baseCmd *cobra.Command, cmds *plug
f.BoolP(longs[i], shorts[i], false, "") f.BoolP(longs[i], shorts[i], false, "")
} else { } else {
// Create a long flag with the same name as the short flag. // Create a long flag with the same name as the short flag.
// Not a perfect solution, but its better than ignoring the extra short flags. // Not a perfect solution, but it's better than ignoring the extra short flags.
f.BoolP(shorts[i], shorts[i], false, "") f.BoolP(shorts[i], shorts[i], false, "")
} }
} }

@ -25,12 +25,12 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/cache" "helm.sh/helm/v4/pkg/cache"
"helm.sh/helm/v3/pkg/cli/values" "helm.sh/helm/v4/pkg/cli/values"
"helm.sh/helm/v3/pkg/downloader" "helm.sh/helm/v4/pkg/downloader"
"helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
) )
const packageDesc = ` const packageDesc = `
@ -49,7 +49,7 @@ If '--keyring' is not specified, Helm usually defaults to the public keyring
unless your environment is otherwise configured. unless your environment is otherwise configured.
` `
func newPackageCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func newPackageCmd(out io.Writer) *cobra.Command {
client := action.NewPackage() client := action.NewPackage()
valueOpts := &values.Options{} valueOpts := &values.Options{}
@ -77,6 +77,12 @@ func newPackageCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
return err return err
} }
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
client.InsecureSkipTLSverify, client.PlainHTTP, client.Username, client.Password)
if err != nil {
return fmt.Errorf("missing registry client: %w", err)
}
for i := 0; i < len(args); i++ { for i := 0; i < len(args); i++ {
path, err := filepath.Abs(args[i]) path, err := filepath.Abs(args[i])
if err != nil { if err != nil {
@ -94,7 +100,7 @@ func newPackageCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Keyring: client.Keyring, Keyring: client.Keyring,
Getters: p, Getters: p,
Debug: settings.Debug, Debug: settings.Debug,
RegistryClient: cfg.RegistryClient, RegistryClient: registryClient,
RepositoryConfig: settings.RepositoryConfig, RepositoryConfig: settings.RepositoryConfig,
RepositoryCache: settings.RepositoryCache, RepositoryCache: settings.RepositoryCache,
IndexFileCache: &c, IndexFileCache: &c,
@ -123,6 +129,13 @@ func newPackageCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.StringVar(&client.AppVersion, "app-version", "", "set the appVersion on the chart to this version") f.StringVar(&client.AppVersion, "app-version", "", "set the appVersion on the chart to this version")
f.StringVarP(&client.Destination, "destination", "d", ".", "location to write the chart.") f.StringVarP(&client.Destination, "destination", "d", ".", "location to write the chart.")
f.BoolVarP(&client.DependencyUpdate, "dependency-update", "u", false, `update dependencies from "Chart.yaml" to dir "charts/" before packaging`) f.BoolVarP(&client.DependencyUpdate, "dependency-update", "u", false, `update dependencies from "Chart.yaml" to dir "charts/" before packaging`)
f.StringVar(&client.Username, "username", "", "chart repository username where to locate the requested chart")
f.StringVar(&client.Password, "password", "", "chart repository password where to locate the requested chart")
f.StringVar(&client.CertFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVar(&client.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.BoolVar(&client.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download")
f.BoolVar(&client.PlainHTTP, "plain-http", false, "use insecure HTTP connections for the chart download")
f.StringVar(&client.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
return cmd return cmd
} }

@ -23,8 +23,8 @@ import (
"strings" "strings"
"testing" "testing"
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v4/pkg/chart/loader"
) )
func TestPackage(t *testing.T) { func TestPackage(t *testing.T) {

@ -23,7 +23,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/pkg/plugin" "helm.sh/helm/v4/pkg/plugin"
) )
const pluginHelp = ` const pluginHelp = `
@ -47,19 +47,27 @@ func newPluginCmd(out io.Writer) *cobra.Command {
// runHook will execute a plugin hook. // runHook will execute a plugin hook.
func runHook(p *plugin.Plugin, event string) error { func runHook(p *plugin.Plugin, event string) error {
hook := p.Metadata.Hooks[event] plugin.SetupPluginEnv(settings, p.Metadata.Name, p.Dir)
if hook == "" {
cmds := p.Metadata.PlatformHooks[event]
expandArgs := true
if len(cmds) == 0 && len(p.Metadata.Hooks) > 0 {
cmd := p.Metadata.Hooks[event]
if len(cmd) > 0 {
cmds = []plugin.PlatformCommand{{Command: "sh", Args: []string{"-c", cmd}}}
expandArgs = false
}
}
main, argv, err := plugin.PrepareCommands(cmds, expandArgs, []string{})
if err != nil {
return nil return nil
} }
prog := exec.Command("sh", "-c", hook) prog := exec.Command(main, argv...)
// TODO make this work on windows
// I think its ... ¯\_(ツ)_/¯
// prog := exec.Command("cmd", "/C", p.Metadata.Hooks.Install())
debug("running %s hook: %s", event, prog) debug("running %s hook: %s", event, prog)
plugin.SetupPluginEnv(settings, p.Metadata.Name, p.Dir)
prog.Stdout, prog.Stderr = os.Stdout, os.Stderr prog.Stdout, prog.Stderr = os.Stdout, os.Stderr
if err := prog.Run(); err != nil { if err := prog.Run(); err != nil {
if eerr, ok := err.(*exec.ExitError); ok { if eerr, ok := err.(*exec.ExitError); ok {

@ -22,9 +22,9 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/plugin" "helm.sh/helm/v4/pkg/plugin"
"helm.sh/helm/v3/pkg/plugin/installer" "helm.sh/helm/v4/pkg/plugin/installer"
) )
type pluginInstallOptions struct { type pluginInstallOptions struct {

@ -22,7 +22,7 @@ import (
"github.com/gosuri/uitable" "github.com/gosuri/uitable"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/pkg/plugin" "helm.sh/helm/v4/pkg/plugin"
) )
func newPluginListCmd(out io.Writer) *cobra.Command { func newPluginListCmd(out io.Writer) *cobra.Command {

@ -26,7 +26,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
) )
func TestManuallyProcessArgs(t *testing.T) { func TestManuallyProcessArgs(t *testing.T) {

@ -24,7 +24,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/pkg/plugin" "helm.sh/helm/v4/pkg/plugin"
) )
type pluginUninstallOptions struct { type pluginUninstallOptions struct {
@ -78,7 +78,7 @@ func (o *pluginUninstallOptions) run(out io.Writer) error {
} }
} }
if len(errorPlugins) > 0 { if len(errorPlugins) > 0 {
return errors.Errorf(strings.Join(errorPlugins, "\n")) return errors.New(strings.Join(errorPlugins, "\n"))
} }
return nil return nil
} }

@ -24,8 +24,8 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/pkg/plugin" "helm.sh/helm/v4/pkg/plugin"
"helm.sh/helm/v3/pkg/plugin/installer" "helm.sh/helm/v4/pkg/plugin/installer"
) )
type pluginUpdateOptions struct { type pluginUpdateOptions struct {
@ -81,7 +81,7 @@ func (o *pluginUpdateOptions) run(out io.Writer) error {
} }
} }
if len(errorPlugins) > 0 { if len(errorPlugins) > 0 {
return errors.Errorf(strings.Join(errorPlugins, "\n")) return errors.New(strings.Join(errorPlugins, "\n"))
} }
return nil return nil
} }

@ -23,8 +23,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
) )
const pullDesc = ` const pullDesc = `
@ -43,7 +43,7 @@ result in an error, and the chart will not be saved locally.
` `
func newPullCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func newPullCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client := action.NewPullWithOpts(action.WithConfig(cfg)) client := action.NewPull(action.WithConfig(cfg))
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "pull [chart URL | repo/chartname] [...]", Use: "pull [chart URL | repo/chartname] [...]",
@ -65,7 +65,7 @@ func newPullCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
} }
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
client.InsecureSkipTLSverify, client.PlainHTTP) client.InsecureSkipTLSverify, client.PlainHTTP, client.Username, client.Password)
if err != nil { if err != nil {
return fmt.Errorf("missing registry client: %w", err) return fmt.Errorf("missing registry client: %w", err)
} }

@ -24,7 +24,7 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"helm.sh/helm/v3/pkg/repo/repotest" "helm.sh/helm/v4/pkg/repo/repotest"
) )
func TestPullCmd(t *testing.T) { func TestPullCmd(t *testing.T) {
@ -183,22 +183,27 @@ func TestPullCmd(t *testing.T) {
wantError: true, wantError: true,
}, },
{ {
name: "Fail fetching OCI chart without version specified", name: "Fetching OCI chart without version option specified",
args: fmt.Sprintf("oci://%s/u/ocitestuser/oci-dependent-chart:0.1.0", ociSrv.RegistryURL), args: fmt.Sprintf("oci://%s/u/ocitestuser/oci-dependent-chart:0.1.0", ociSrv.RegistryURL),
wantErrorMsg: "Error: --version flag is explicitly required for OCI registries", expectFile: "./oci-dependent-chart-0.1.0.tgz",
wantError: true,
}, },
{ {
name: "Fail fetching OCI chart without version specified", name: "Fetching OCI chart with version specified",
args: fmt.Sprintf("oci://%s/u/ocitestuser/oci-dependent-chart:0.1.0 --version 0.1.0", ociSrv.RegistryURL), args: fmt.Sprintf("oci://%s/u/ocitestuser/oci-dependent-chart:0.1.0 --version 0.1.0", ociSrv.RegistryURL),
wantError: true, expectFile: "./oci-dependent-chart-0.1.0.tgz",
},
{
name: "Fail fetching OCI chart with version mismatch",
args: fmt.Sprintf("oci://%s/u/ocitestuser/oci-dependent-chart:0.2.0 --version 0.1.0", ociSrv.RegistryURL),
wantErrorMsg: "Error: chart reference and version mismatch: 0.2.0 is not 0.1.0",
wantError: true,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
outdir := srv.Root() outdir := srv.Root()
cmd := fmt.Sprintf("fetch %s -d '%s' --repository-config %s --repository-cache %s --registry-config %s", cmd := fmt.Sprintf("fetch %s -d '%s' --repository-config %s --repository-cache %s --registry-config %s --plain-http",
tt.args, tt.args,
outdir, outdir,
filepath.Join(outdir, "repositories.yaml"), filepath.Join(outdir, "repositories.yaml"),

@ -22,9 +22,9 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/pusher" "helm.sh/helm/v4/pkg/pusher"
) )
const pushDesc = ` const pushDesc = `
@ -40,6 +40,8 @@ type registryPushOptions struct {
caFile string caFile string
insecureSkipTLSverify bool insecureSkipTLSverify bool
plainHTTP bool plainHTTP bool
password string
username string
} }
func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
@ -68,7 +70,10 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
return noMoreArgsComp() return noMoreArgsComp()
}, },
RunE: func(_ *cobra.Command, args []string) error { RunE: func(_ *cobra.Command, args []string) error {
registryClient, err := newRegistryClient(o.certFile, o.keyFile, o.caFile, o.insecureSkipTLSverify, o.plainHTTP) registryClient, err := newRegistryClient(
o.certFile, o.keyFile, o.caFile, o.insecureSkipTLSverify, o.plainHTTP, o.username, o.password,
)
if err != nil { if err != nil {
return fmt.Errorf("missing registry client: %w", err) return fmt.Errorf("missing registry client: %w", err)
} }
@ -96,6 +101,8 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.BoolVar(&o.insecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart upload") f.BoolVar(&o.insecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart upload")
f.BoolVar(&o.plainHTTP, "plain-http", false, "use insecure HTTP connections for the chart upload") f.BoolVar(&o.plainHTTP, "plain-http", false, "use insecure HTTP connections for the chart upload")
f.StringVar(&o.username, "username", "", "chart repository username where to locate the requested chart")
f.StringVar(&o.password, "password", "", "chart repository password where to locate the requested chart")
return cmd return cmd
} }

@ -20,7 +20,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
) )
const registryHelp = ` const registryHelp = `

@ -27,8 +27,8 @@ import (
"github.com/moby/term" "github.com/moby/term"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
) )
const registryLoginDesc = ` const registryLoginDesc = `
@ -43,6 +43,7 @@ type registryLoginOptions struct {
keyFile string keyFile string
caFile string caFile string
insecure bool insecure bool
plainHTTP bool
} }
func newRegistryLoginCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func newRegistryLoginCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
@ -66,7 +67,8 @@ func newRegistryLoginCmd(cfg *action.Configuration, out io.Writer) *cobra.Comman
action.WithCertFile(o.certFile), action.WithCertFile(o.certFile),
action.WithKeyFile(o.keyFile), action.WithKeyFile(o.keyFile),
action.WithCAFile(o.caFile), action.WithCAFile(o.caFile),
action.WithInsecure(o.insecure)) action.WithInsecure(o.insecure),
action.WithPlainHTTPLogin(o.plainHTTP))
}, },
} }
@ -78,6 +80,7 @@ func newRegistryLoginCmd(cfg *action.Configuration, out io.Writer) *cobra.Comman
f.StringVar(&o.certFile, "cert-file", "", "identify registry client using this SSL certificate file") f.StringVar(&o.certFile, "cert-file", "", "identify registry client using this SSL certificate file")
f.StringVar(&o.keyFile, "key-file", "", "identify registry client using this SSL key file") f.StringVar(&o.keyFile, "key-file", "", "identify registry client using this SSL key file")
f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.BoolVar(&o.plainHTTP, "plain-http", false, "use insecure HTTP connections for the chart upload")
return cmd return cmd
} }

@ -21,8 +21,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
) )
const registryLogoutDesc = ` const registryLogoutDesc = `

@ -25,9 +25,9 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"
) )
const releaseTestHelp = ` const releaseTestHelp = `
@ -39,7 +39,7 @@ The tests to be run are defined in the chart that was installed.
func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client := action.NewReleaseTesting(cfg) client := action.NewReleaseTesting(cfg)
var outfmt = output.Table outfmt := output.Table
var outputLogs bool var outputLogs bool
var filter []string var filter []string
@ -72,7 +72,12 @@ func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command
return runErr return runErr
} }
if err := outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false, false, client.HideNotes}); err != nil { if err := outfmt.Write(out, &statusPrinter{
release: rel,
debug: settings.Debug,
showMetadata: false,
hideNotes: client.HideNotes,
}); err != nil {
return err return err
} }

@ -23,7 +23,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
) )
var repoHelm = ` var repoHelm = `

@ -31,9 +31,9 @@ import (
"golang.org/x/term" "golang.org/x/term"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
) )
// Repositories that have been permanently deleted and no longer work // Repositories that have been permanently deleted and no longer work
@ -59,9 +59,6 @@ type repoAddOptions struct {
repoFile string repoFile string
repoCache string repoCache string
// Deprecated, but cannot be removed until Helm 4
deprecatedNoUpdate bool
} }
func newRepoAddCmd(out io.Writer) *cobra.Command { func newRepoAddCmd(out io.Writer) *cobra.Command {
@ -92,7 +89,6 @@ func newRepoAddCmd(out io.Writer) *cobra.Command {
f.StringVar(&o.password, "password", "", "chart repository password") f.StringVar(&o.password, "password", "", "chart repository password")
f.BoolVarP(&o.passwordFromStdinOpt, "password-stdin", "", false, "read chart repository password from stdin") f.BoolVarP(&o.passwordFromStdinOpt, "password-stdin", "", false, "read chart repository password from stdin")
f.BoolVar(&o.forceUpdate, "force-update", false, "replace (overwrite) the repo if it already exists") f.BoolVar(&o.forceUpdate, "force-update", false, "replace (overwrite) the repo if it already exists")
f.BoolVar(&o.deprecatedNoUpdate, "no-update", false, "Ignored. Formerly, it would disabled forced updates. It is deprecated by force-update.")
f.StringVar(&o.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") f.StringVar(&o.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVar(&o.keyFile, "key-file", "", "identify HTTPS client using this SSL key file") f.StringVar(&o.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")

@ -27,10 +27,10 @@ import (
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
"helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v4/pkg/helmpath"
"helm.sh/helm/v3/pkg/helmpath/xdg" "helm.sh/helm/v4/pkg/helmpath/xdg"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
"helm.sh/helm/v3/pkg/repo/repotest" "helm.sh/helm/v4/pkg/repo/repotest"
) )
func TestRepoAddCmd(t *testing.T) { func TestRepoAddCmd(t *testing.T) {
@ -93,11 +93,10 @@ func TestRepoAdd(t *testing.T) {
const testRepoName = "test-name" const testRepoName = "test-name"
o := &repoAddOptions{ o := &repoAddOptions{
name: testRepoName, name: testRepoName,
url: ts.URL(), url: ts.URL(),
forceUpdate: false, forceUpdate: false,
deprecatedNoUpdate: true, repoFile: repoFile,
repoFile: repoFile,
} }
os.Setenv(xdg.CacheHomeEnvVar, rootDir) os.Setenv(xdg.CacheHomeEnvVar, rootDir)
@ -148,11 +147,10 @@ func TestRepoAddCheckLegalName(t *testing.T) {
repoFile := filepath.Join(t.TempDir(), "repositories.yaml") repoFile := filepath.Join(t.TempDir(), "repositories.yaml")
o := &repoAddOptions{ o := &repoAddOptions{
name: testRepoName, name: testRepoName,
url: ts.URL(), url: ts.URL(),
forceUpdate: false, forceUpdate: false,
deprecatedNoUpdate: true, repoFile: repoFile,
repoFile: repoFile,
} }
os.Setenv(xdg.CacheHomeEnvVar, rootDir) os.Setenv(xdg.CacheHomeEnvVar, rootDir)
@ -204,11 +202,10 @@ func repoAddConcurrent(t *testing.T, testName, repoFile string) {
go func(name string) { go func(name string) {
defer wg.Done() defer wg.Done()
o := &repoAddOptions{ o := &repoAddOptions{
name: name, name: name,
url: ts.URL(), url: ts.URL(),
deprecatedNoUpdate: true, forceUpdate: false,
forceUpdate: false, repoFile: repoFile,
repoFile: repoFile,
} }
if err := o.run(io.Discard); err != nil { if err := o.run(io.Discard); err != nil {
t.Error(err) t.Error(err)

@ -24,19 +24,21 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
) )
const repoIndexDesc = ` const repoIndexDesc = `
Read the current directory and generate an index file based on the charts found. Read the current directory, generate an index file based on the charts found
and write the result to 'index.yaml' in the current directory.
This tool is used for creating an 'index.yaml' file for a chart repository. To This tool is used for creating an 'index.yaml' file for a chart repository. To
set an absolute URL to the charts, use '--url' flag. set an absolute URL to the charts, use '--url' flag.
To merge the generated index with an existing index file, use the '--merge' To merge the generated index with an existing index file, use the '--merge'
flag. In this case, the charts found in the current directory will be merged flag. In this case, the charts found in the current directory will be merged
into the existing index, with local charts taking priority over existing charts. into the index passed in with --merge, with local charts taking priority over
existing charts.
` `
type repoIndexOptions struct { type repoIndexOptions struct {

@ -24,7 +24,7 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
) )
func TestRepoIndexCmd(t *testing.T) { func TestRepoIndexCmd(t *testing.T) {
@ -162,9 +162,9 @@ func TestRepoIndexCmd(t *testing.T) {
} }
} }
func linkOrCopy(old, new string) error { func linkOrCopy(source, target string) error {
if err := os.Link(old, new); err != nil { if err := os.Link(source, target); err != nil {
return copyFile(old, new) return copyFile(source, target)
} }
return nil return nil

@ -24,9 +24,9 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
) )
func newRepoListCmd(out io.Writer) *cobra.Command { func newRepoListCmd(out io.Writer) *cobra.Command {

@ -25,9 +25,9 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v4/pkg/helmpath"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
) )
type repoRemoveOptions struct { type repoRemoveOptions struct {

@ -24,9 +24,9 @@ import (
"strings" "strings"
"testing" "testing"
"helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v4/pkg/helmpath"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
"helm.sh/helm/v3/pkg/repo/repotest" "helm.sh/helm/v4/pkg/repo/repotest"
) )
func TestRepoRemove(t *testing.T) { func TestRepoRemove(t *testing.T) {

@ -19,14 +19,15 @@ package main
import ( import (
"fmt" "fmt"
"io" "io"
"slices"
"sync" "sync"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
) )
const updateDesc = ` const updateDesc = `
@ -158,10 +159,5 @@ func checkRequestedRepos(requestedRepos []string, validRepos []*repo.Entry) erro
} }
func isRepoRequested(repoName string, requestedRepos []string) bool { func isRepoRequested(repoName string, requestedRepos []string) bool {
for _, requestedRepo := range requestedRepos { return slices.Contains(requestedRepos, repoName)
if repoName == requestedRepo {
return true
}
}
return false
} }

@ -24,10 +24,10 @@ import (
"strings" "strings"
"testing" "testing"
"helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v4/internal/test/ensure"
"helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
"helm.sh/helm/v3/pkg/repo/repotest" "helm.sh/helm/v4/pkg/repo/repotest"
) )
func TestUpdateCmd(t *testing.T) { func TestUpdateCmd(t *testing.T) {

@ -24,8 +24,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
) )
const rollbackDesc = ` const rollbackDesc = `

@ -21,8 +21,8 @@ import (
"reflect" "reflect"
"testing" "testing"
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
) )
func TestRollbackCmd(t *testing.T) { func TestRollbackCmd(t *testing.T) {

@ -14,13 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package main // import "helm.sh/helm/v3/cmd/helm" package main // import "helm.sh/helm/v4/cmd/helm"
import ( import (
"context" "context"
"fmt" "fmt"
"io" "io"
"log" "log"
"net/http"
"os" "os"
"strings" "strings"
@ -29,9 +30,10 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/internal/tlsutil"
"helm.sh/helm/v3/pkg/registry" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/registry"
"helm.sh/helm/v4/pkg/repo"
) )
var globalUsage = `The Kubernetes package manager var globalUsage = `The Kubernetes package manager
@ -153,7 +155,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
flags.ParseErrorsWhitelist.UnknownFlags = true flags.ParseErrorsWhitelist.UnknownFlags = true
flags.Parse(args) flags.Parse(args)
registryClient, err := newDefaultRegistryClient(false) registryClient, err := newDefaultRegistryClient(false, "", "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -167,7 +169,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
newPullCmd(actionConfig, out), newPullCmd(actionConfig, out),
newShowCmd(actionConfig, out), newShowCmd(actionConfig, out),
newLintCmd(out), newLintCmd(out),
newPackageCmd(actionConfig, out), newPackageCmd(out),
newRepoCmd(out), newRepoCmd(out),
newSearchCmd(out), newSearchCmd(out),
newVerifyCmd(out), newVerifyCmd(out),
@ -201,9 +203,6 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
// Find and add plugins // Find and add plugins
loadPlugins(cmd, out) loadPlugins(cmd, out)
// Check permissions on critical files
checkPerms()
// Check for expired repositories // Check for expired repositories
checkForExpiredRepos(settings.RepositoryConfig) checkForExpiredRepos(settings.RepositoryConfig)
@ -230,7 +229,7 @@ func checkForExpiredRepos(repofile string) {
} }
// parse repo file. // parse repo file.
// Ignore the error because it is okay for a repo file to be unparseable at this // Ignore the error because it is okay for a repo file to be unparsable at this
// stage. Later checks will trap the error and respond accordingly. // stage. Later checks will trap the error and respond accordingly.
repoFile, err := repo.LoadFile(repofile) repoFile, err := repo.LoadFile(repofile)
if err != nil { if err != nil {
@ -258,27 +257,30 @@ func checkForExpiredRepos(repofile string) {
} }
func newRegistryClient(certFile, keyFile, caFile string, insecureSkipTLSverify, plainHTTP bool) (*registry.Client, error) { func newRegistryClient(
certFile, keyFile, caFile string, insecureSkipTLSverify, plainHTTP bool, username, password string,
) (*registry.Client, error) {
if certFile != "" && keyFile != "" || caFile != "" || insecureSkipTLSverify { if certFile != "" && keyFile != "" || caFile != "" || insecureSkipTLSverify {
registryClient, err := newRegistryClientWithTLS(certFile, keyFile, caFile, insecureSkipTLSverify) registryClient, err := newRegistryClientWithTLS(certFile, keyFile, caFile, insecureSkipTLSverify, username, password)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return registryClient, nil return registryClient, nil
} }
registryClient, err := newDefaultRegistryClient(plainHTTP) registryClient, err := newDefaultRegistryClient(plainHTTP, username, password)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return registryClient, nil return registryClient, nil
} }
func newDefaultRegistryClient(plainHTTP bool) (*registry.Client, error) { func newDefaultRegistryClient(plainHTTP bool, username, password string) (*registry.Client, error) {
opts := []registry.ClientOption{ opts := []registry.ClientOption{
registry.ClientOptDebug(settings.Debug), registry.ClientOptDebug(settings.Debug),
registry.ClientOptEnableCache(true), registry.ClientOptEnableCache(true),
registry.ClientOptWriter(os.Stderr), registry.ClientOptWriter(os.Stderr),
registry.ClientOptCredentialsFile(settings.RegistryConfig), registry.ClientOptCredentialsFile(settings.RegistryConfig),
registry.ClientOptBasicAuth(username, password),
} }
if plainHTTP { if plainHTTP {
opts = append(opts, registry.ClientOptPlainHTTP()) opts = append(opts, registry.ClientOptPlainHTTP())
@ -292,10 +294,31 @@ func newDefaultRegistryClient(plainHTTP bool) (*registry.Client, error) {
return registryClient, nil return registryClient, nil
} }
func newRegistryClientWithTLS(certFile, keyFile, caFile string, insecureSkipTLSverify bool) (*registry.Client, error) { func newRegistryClientWithTLS(
certFile, keyFile, caFile string, insecureSkipTLSverify bool, username, password string,
) (*registry.Client, error) {
tlsConf, err := tlsutil.NewTLSConfig(
tlsutil.WithInsecureSkipVerify(insecureSkipTLSverify),
tlsutil.WithCertKeyPairFiles(certFile, keyFile),
tlsutil.WithCAFile(caFile),
)
if err != nil {
return nil, fmt.Errorf("can't create TLS config for client: %w", err)
}
// Create a new registry client // Create a new registry client
registryClient, err := registry.NewRegistryClientWithTLS(os.Stderr, certFile, keyFile, caFile, insecureSkipTLSverify, registryClient, err := registry.NewClient(
settings.RegistryConfig, settings.Debug, registry.ClientOptDebug(settings.Debug),
registry.ClientOptEnableCache(true),
registry.ClientOptWriter(os.Stderr),
registry.ClientOptCredentialsFile(settings.RegistryConfig),
registry.ClientOptHTTPClient(&http.Client{
Transport: &http.Transport{
TLSClientConfig: tlsConf,
},
}),
registry.ClientOptBasicAuth(username, password),
) )
if err != nil { if err != nil {
return nil, err return nil, err

@ -21,9 +21,9 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v4/internal/test/ensure"
"helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v4/pkg/helmpath"
"helm.sh/helm/v3/pkg/helmpath/xdg" "helm.sh/helm/v4/pkg/helmpath/xdg"
) )
func TestRootCmd(t *testing.T) { func TestRootCmd(t *testing.T) {

@ -1,58 +0,0 @@
//go:build !windows
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"os"
"os/user"
"path/filepath"
)
func checkPerms() {
// This function MUST NOT FAIL, as it is just a check for a common permissions problem.
// If for some reason the function hits a stopping condition, it may panic. But only if
// we can be sure that it is panicking because Helm cannot proceed.
kc := settings.KubeConfig
if kc == "" {
kc = os.Getenv("KUBECONFIG")
}
if kc == "" {
u, err := user.Current()
if err != nil {
// No idea where to find KubeConfig, so return silently. Many helm commands
// can proceed happily without a KUBECONFIG, so this is not a fatal error.
return
}
kc = filepath.Join(u.HomeDir, ".kube", "config")
}
fi, err := os.Stat(kc)
if err != nil {
// DO NOT error if no KubeConfig is found. Not all commands require one.
return
}
perm := fi.Mode().Perm()
if perm&0040 > 0 {
warning("Kubernetes configuration file is group-readable. This is insecure. Location: %s", kc)
}
if perm&0004 > 0 {
warning("Kubernetes configuration file is world-readable. This is insecure. Location: %s", kc)
}
}

@ -1,82 +0,0 @@
//go:build !windows
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"bytes"
"io"
"os"
"path/filepath"
"strings"
"testing"
)
func checkPermsStderr() (string, error) {
r, w, err := os.Pipe()
if err != nil {
return "", err
}
stderr := os.Stderr
os.Stderr = w
defer func() {
os.Stderr = stderr
}()
checkPerms()
w.Close()
var text bytes.Buffer
io.Copy(&text, r)
return text.String(), nil
}
func TestCheckPerms(t *testing.T) {
tdir := t.TempDir()
tfile := filepath.Join(tdir, "testconfig")
fh, err := os.OpenFile(tfile, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0440)
if err != nil {
t.Errorf("Failed to create temp file: %s", err)
}
tconfig := settings.KubeConfig
settings.KubeConfig = tfile
defer func() { settings.KubeConfig = tconfig }()
text, err := checkPermsStderr()
if err != nil {
t.Fatalf("could not read from stderr: %s", err)
}
expectPrefix := "WARNING: Kubernetes configuration file is group-readable. This is insecure. Location:"
if !strings.HasPrefix(text, expectPrefix) {
t.Errorf("Expected to get a warning for group perms. Got %q", text)
}
if err := fh.Chmod(0404); err != nil {
t.Errorf("Could not change mode on file: %s", err)
}
text, err = checkPermsStderr()
if err != nil {
t.Fatalf("could not read from stderr: %s", err)
}
expectPrefix = "WARNING: Kubernetes configuration file is world-readable. This is insecure. Location:"
if !strings.HasPrefix(text, expectPrefix) {
t.Errorf("Expected to get a warning for world perms. Got %q", text)
}
}

@ -31,7 +31,7 @@ import (
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
) )
// Result is a search result. // Result is a search result.

@ -20,8 +20,8 @@ import (
"strings" "strings"
"testing" "testing"
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
) )
func TestSortScore(t *testing.T) { func TestSortScore(t *testing.T) {

@ -25,8 +25,8 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/internal/monocular" "helm.sh/helm/v4/internal/monocular"
"helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"
) )
const searchHubDesc = ` const searchHubDesc = `

@ -30,10 +30,10 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/search" "helm.sh/helm/v4/cmd/helm/search"
"helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"
"helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v4/pkg/helmpath"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v4/pkg/repo"
) )
const searchRepoDesc = ` const searchRepoDesc = `
@ -139,7 +139,7 @@ func (o *searchRepoOptions) setupSearchedVersion() {
if o.devel { // search for releases and prereleases (alpha, beta, and release candidate releases). if o.devel { // search for releases and prereleases (alpha, beta, and release candidate releases).
debug("setting version to >0.0.0-0") debug("setting version to >0.0.0-0")
o.version = ">0.0.0-0" o.version = ">0.0.0-0"
} else { // search only for stable releases, prerelease versions will be skip } else { // search only for stable releases, prerelease versions will be skipped
debug("setting version to >0.0.0") debug("setting version to >0.0.0")
o.version = ">0.0.0" o.version = ">0.0.0"
} }

@ -23,8 +23,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
) )
const showDesc = ` const showDesc = `
@ -57,7 +57,7 @@ of the CustomResourceDefinition files
` `
func newShowCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func newShowCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client := action.NewShowWithConfig(action.ShowAll, cfg) client := action.NewShow(action.ShowAll, cfg)
showCommand := &cobra.Command{ showCommand := &cobra.Command{
Use: "show", Use: "show",
@ -226,7 +226,7 @@ func runShow(args []string, client *action.Show) (string, error) {
func addRegistryClient(client *action.Show) error { func addRegistryClient(client *action.Show) error {
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
client.InsecureSkipTLSverify, client.PlainHTTP) client.InsecureSkipTLSverify, client.PlainHTTP, client.Username, client.Password)
if err != nil { if err != nil {
return fmt.Errorf("missing registry client: %w", err) return fmt.Errorf("missing registry client: %w", err)
} }

@ -22,7 +22,7 @@ import (
"strings" "strings"
"testing" "testing"
"helm.sh/helm/v3/pkg/repo/repotest" "helm.sh/helm/v4/pkg/repo/repotest"
) )
func TestShowPreReleaseChart(t *testing.T) { func TestShowPreReleaseChart(t *testing.T) {

@ -28,11 +28,11 @@ import (
"k8s.io/kubectl/pkg/cmd/get" "k8s.io/kubectl/pkg/cmd/get"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v4/pkg/chartutil"
"helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
) )
// NOTE: Keep the list of statuses up-to-date with pkg/release/status.go. // NOTE: Keep the list of statuses up-to-date with pkg/release/status.go.
@ -43,8 +43,8 @@ The status consists of:
- k8s namespace in which the release lives - k8s namespace in which the release lives
- state of the release (can be: unknown, deployed, uninstalled, superseded, failed, uninstalling, pending-install, pending-upgrade or pending-rollback) - state of the release (can be: unknown, deployed, uninstalled, superseded, failed, uninstalling, pending-install, pending-upgrade or pending-rollback)
- revision of the release - revision of the release
- description of the release (can be completion message or error message, need to enable --show-desc) - description of the release (can be completion message or error message)
- list of resources that this release consists of (need to enable --show-resources) - list of resources that this release consists of
- details on last test suite run, if applicable - details on last test suite run, if applicable
- additional notes provided by the chart - additional notes provided by the chart
` `
@ -65,7 +65,6 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
return compListReleases(toComplete, args, cfg) return compListReleases(toComplete, args, cfg)
}, },
RunE: func(_ *cobra.Command, args []string) error { RunE: func(_ *cobra.Command, args []string) error {
// When the output format is a table the resources should be fetched // When the output format is a table the resources should be fetched
// and displayed as a table. When YAML or JSON the resources will be // and displayed as a table. When YAML or JSON the resources will be
// returned. This mirrors the handling in kubectl. // returned. This mirrors the handling in kubectl.
@ -80,7 +79,12 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
// strip chart metadata from the output // strip chart metadata from the output
rel.Chart = nil rel.Chart = nil
return outfmt.Write(out, &statusPrinter{rel, false, client.ShowDescription, client.ShowResources, false, false}) return outfmt.Write(out, &statusPrinter{
release: rel,
debug: false,
showMetadata: false,
hideNotes: false,
})
}, },
} }
@ -94,26 +98,20 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
} }
return nil, cobra.ShellCompDirectiveNoFileComp return nil, cobra.ShellCompDirectiveNoFileComp
}) })
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
bindOutputFlag(cmd, &outfmt) bindOutputFlag(cmd, &outfmt)
f.BoolVar(&client.ShowDescription, "show-desc", false, "if set, display the description message of the named release")
f.BoolVar(&client.ShowResources, "show-resources", false, "if set, display the resources of the named release")
return cmd return cmd
} }
type statusPrinter struct { type statusPrinter struct {
release *release.Release release *release.Release
debug bool debug bool
showDescription bool showMetadata bool
showResources bool hideNotes bool
showMetadata bool
hideNotes bool
} }
func (s statusPrinter) WriteJSON(out io.Writer) error { func (s statusPrinter) WriteJSON(out io.Writer) error {
@ -140,11 +138,9 @@ func (s statusPrinter) WriteTable(out io.Writer) error {
_, _ = fmt.Fprintf(out, "VERSION: %s\n", s.release.Chart.Metadata.Version) _, _ = fmt.Fprintf(out, "VERSION: %s\n", s.release.Chart.Metadata.Version)
_, _ = fmt.Fprintf(out, "APP_VERSION: %s\n", s.release.Chart.Metadata.AppVersion) _, _ = fmt.Fprintf(out, "APP_VERSION: %s\n", s.release.Chart.Metadata.AppVersion)
} }
if s.showDescription { _, _ = fmt.Fprintf(out, "DESCRIPTION: %s\n", s.release.Info.Description)
_, _ = fmt.Fprintf(out, "DESCRIPTION: %s\n", s.release.Info.Description)
}
if s.showResources && s.release.Info.Resources != nil && len(s.release.Info.Resources) > 0 { if len(s.release.Info.Resources) > 0 {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
printFlags := get.NewHumanPrintFlags() printFlags := get.NewHumanPrintFlags()
typePrinter, _ := printFlags.ToPrinter("") typePrinter, _ := printFlags.ToPrinter("")

@ -20,9 +20,9 @@ import (
"testing" "testing"
"time" "time"
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
helmtime "helm.sh/helm/v3/pkg/time" helmtime "helm.sh/helm/v4/pkg/time"
) )
func TestStatusCmd(t *testing.T) { func TestStatusCmd(t *testing.T) {
@ -46,7 +46,7 @@ func TestStatusCmd(t *testing.T) {
}), }),
}, { }, {
name: "get status of a deployed release, with desc", name: "get status of a deployed release, with desc",
cmd: "status --show-desc flummoxed-chickadee", cmd: "status flummoxed-chickadee",
golden: "output/status-with-desc.txt", golden: "output/status-with-desc.txt",
rels: releasesMockWithStatus(&release.Info{ rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed, Status: release.StatusDeployed,
@ -70,7 +70,7 @@ func TestStatusCmd(t *testing.T) {
}), }),
}, { }, {
name: "get status of a deployed release with resources", name: "get status of a deployed release with resources",
cmd: "status --show-resources flummoxed-chickadee", cmd: "status flummoxed-chickadee",
golden: "output/status-with-resources.txt", golden: "output/status-with-resources.txt",
rels: releasesMockWithStatus( rels: releasesMockWithStatus(
&release.Info{ &release.Info{
@ -79,7 +79,7 @@ func TestStatusCmd(t *testing.T) {
), ),
}, { }, {
name: "get status of a deployed release with resources in json", name: "get status of a deployed release with resources in json",
cmd: "status --show-resources flummoxed-chickadee -o json", cmd: "status flummoxed-chickadee -o json",
golden: "output/status-with-resources.json", golden: "output/status-with-resources.json",
rels: releasesMockWithStatus( rels: releasesMockWithStatus(
&release.Info{ &release.Info{

@ -24,18 +24,19 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"regexp" "regexp"
"slices"
"sort" "sort"
"strings" "strings"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v4/pkg/release"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v4/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v4/pkg/chartutil"
"helm.sh/helm/v3/pkg/cli/values" "helm.sh/helm/v4/pkg/cli/values"
"helm.sh/helm/v3/pkg/releaseutil" "helm.sh/helm/v4/pkg/releaseutil"
) )
const templateDesc = ` const templateDesc = `
@ -74,7 +75,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
} }
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
client.InsecureSkipTLSverify, client.PlainHTTP) client.InsecureSkipTLSverify, client.PlainHTTP, client.Username, client.Password)
if err != nil { if err != nil {
return fmt.Errorf("missing registry client: %w", err) return fmt.Errorf("missing registry client: %w", err)
} }
@ -206,12 +207,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
} }
func isTestHook(h *release.Hook) bool { func isTestHook(h *release.Hook) bool {
for _, e := range h.Events { return slices.Contains(h.Events, release.HookTest)
if e == release.HookTest {
return true
}
}
return false
} }
// The following functions (writeToFile, createOrOpenFile, and ensureDirectoryForFile) // The following functions (writeToFile, createOrOpenFile, and ensureDirectoryForFile)
@ -219,7 +215,7 @@ func isTestHook(h *release.Hook) bool {
// bug introduced by #8156. As part of the todo to refactor renderResources // bug introduced by #8156. As part of the todo to refactor renderResources
// this duplicate code should be removed. It is added here so that the API // this duplicate code should be removed. It is added here so that the API
// surface area is as minimally impacted as possible in fixing the issue. // surface area is as minimally impacted as possible in fixing the issue.
func writeToFile(outputDir string, name string, data string, append bool) error { func writeToFile(outputDir string, name string, data string, appendData bool) error {
outfileName := strings.Join([]string{outputDir, name}, string(filepath.Separator)) outfileName := strings.Join([]string{outputDir, name}, string(filepath.Separator))
err := ensureDirectoryForFile(outfileName) err := ensureDirectoryForFile(outfileName)
@ -227,7 +223,7 @@ func writeToFile(outputDir string, name string, data string, append bool) error
return err return err
} }
f, err := createOrOpenFile(outfileName, append) f, err := createOrOpenFile(outfileName, appendData)
if err != nil { if err != nil {
return err return err
} }
@ -244,8 +240,8 @@ func writeToFile(outputDir string, name string, data string, append bool) error
return nil return nil
} }
func createOrOpenFile(filename string, append bool) (*os.File, error) { func createOrOpenFile(filename string, appendData bool) (*os.File, error) {
if append { if appendData {
return os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0600) return os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0600)
} }
return os.Create(filename) return os.Create(filename)

@ -22,6 +22,18 @@ import (
"testing" "testing"
) )
func TestTemplateCmdWithToml(t *testing.T) {
tests := []cmdTestCase{
{
name: "check toToml function rendering",
cmd: fmt.Sprintf("template '%s'", "testdata/testcharts/issue-totoml"),
golden: "output/issue-totoml.txt",
},
}
runTestCmd(t, tests)
}
var chartPath = "testdata/testcharts/subchart" var chartPath = "testdata/testcharts/subchart"
func TestTemplateCmd(t *testing.T) { func TestTemplateCmd(t *testing.T) {

@ -3,6 +3,7 @@ LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default NAMESPACE: default
STATUS: deployed STATUS: deployed
REVISION: 1 REVISION: 1
DESCRIPTION: Install complete
TEST SUITE: None TEST SUITE: None
NOTES: NOTES:
PARENT NOTES PARENT NOTES

@ -3,4 +3,5 @@ LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default NAMESPACE: default
STATUS: deployed STATUS: deployed
REVISION: 1 REVISION: 1
DESCRIPTION: Install complete
TEST SUITE: None TEST SUITE: None

@ -1 +1 @@
{"name":"thomas-guide","chart":"foo","version":"0.1.0-beta.1","appVersion":"1.0","namespace":"default","revision":1,"status":"deployed","deployedAt":"1977-09-02T22:04:05Z"} {"name":"thomas-guide","chart":"foo","version":"0.1.0-beta.1","appVersion":"1.0","annotations":{"category":"web-apps","supported":"true"},"dependencies":[{"name":"cool-plugin","version":"1.0.0","repository":"https://coolplugin.io/charts","condition":"coolPlugin.enabled","enabled":true},{"name":"crds","version":"2.7.1","repository":"","condition":"crds.enabled"}],"namespace":"default","revision":1,"status":"deployed","deployedAt":"1977-09-02T22:04:05Z"}

@ -2,6 +2,8 @@ NAME: thomas-guide
CHART: foo CHART: foo
VERSION: 0.1.0-beta.1 VERSION: 0.1.0-beta.1
APP_VERSION: 1.0 APP_VERSION: 1.0
ANNOTATIONS: category=web-apps,supported=true
DEPENDENCIES: cool-plugin,crds
NAMESPACE: default NAMESPACE: default
REVISION: 1 REVISION: 1
STATUS: deployed STATUS: deployed

@ -1,5 +1,18 @@
annotations:
category: web-apps
supported: "true"
appVersion: "1.0" appVersion: "1.0"
chart: foo chart: foo
dependencies:
- condition: coolPlugin.enabled
enabled: true
name: cool-plugin
repository: https://coolplugin.io/charts
version: 1.0.0
- condition: crds.enabled
name: crds
repository: ""
version: 2.7.1
deployedAt: "1977-09-02T22:04:05Z" deployedAt: "1977-09-02T22:04:05Z"
name: thomas-guide name: thomas-guide
namespace: default namespace: default

@ -6,6 +6,7 @@ REVISION: 1
CHART: foo CHART: foo
VERSION: 0.1.0-beta.1 VERSION: 0.1.0-beta.1
APP_VERSION: 1.0 APP_VERSION: 1.0
DESCRIPTION: Release mock
TEST SUITE: None TEST SUITE: None
USER-SUPPLIED VALUES: USER-SUPPLIED VALUES:
name: value name: value

@ -3,4 +3,5 @@ LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default NAMESPACE: default
STATUS: deployed STATUS: deployed
REVISION: 1 REVISION: 1
DESCRIPTION: Install complete
TEST SUITE: None TEST SUITE: None

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save