Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 51 additions & 13 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,29 +72,38 @@ jobs:
run: |
set -e
missing=0
for f in dist/helm-diff-*.tgz; do
# Archives wrap their content in a "diff/" directory: the layout
# every released install/update hook expects (issues #1071, #1076).
# Each platform is published under two names (see .goreleaser.yml):
# the historical "helm-diff-<os>-<arch>.tgz" and the versioned
# "diff-<version>-<os>-<arch>.tgz" installable by helm 4 directly
# from a local tarball.
for f in dist/*.tgz; do
echo "== $f =="
tar tzf "$f"
# Archives are wrapped in a directory named after the archive
# itself (required by helm 4 installs from a tarball, see #1071)
base="$(basename "$f" .tgz)"
for member in "$base/plugin.yaml" "$base/install-binary.sh" "$base/install-binary.ps1"; do
for member in "diff/plugin.yaml" "diff/install-binary.sh" "diff/install-binary.ps1"; do
if ! tar tzf "$f" | grep -q "^${member}$"; then
echo "ERROR: ${member} missing from ${f}"
missing=1
fi
done
# the binary has a .exe suffix on windows archives
if ! tar tzf "$f" | grep -qE "^${base}/bin/diff(\\.exe)?$"; then
echo "ERROR: ${base}/bin/diff missing from ${f}"
if ! tar tzf "$f" | grep -qE "^diff/bin/diff(\\.exe)?$"; then
echo "ERROR: diff/bin/diff missing from ${f}"
missing=1
fi
done
legacy_count="$(find dist -maxdepth 1 -name 'helm-diff-*.tgz' | wc -l)"
versioned_count="$(find dist -maxdepth 1 -name 'diff-*.tgz' | wc -l)"
if [ "$legacy_count" -eq 0 ] || [ "$legacy_count" -ne "$versioned_count" ]; then
echo "ERROR: expected an equal, non-zero number of legacy (helm-diff-*) and versioned (diff-*) archives"
missing=1
fi
if [ "$missing" -ne 0 ]; then
echo "Smoke test failed: required plugin files missing from one or more archives"
exit 1
fi
echo "Smoke test passed: all archives bundle plugin.yaml, install scripts, and binary"
echo "Smoke test passed: all archives bundle plugin.yaml, install scripts, and binary in a diff/ directory"
-
name: Set up Helm
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
Expand All @@ -110,9 +119,9 @@ jobs:
mkdir -p /tmp/archive-test
tar xzf dist/helm-diff-linux-amd64.tgz -C /tmp/archive-test
echo "Extracted archive layout:"
find /tmp/archive-test/helm-diff-linux-amd64 -maxdepth 2 -type f | sort
find /tmp/archive-test/diff -maxdepth 2 -type f | sort

out="$(helm plugin install /tmp/archive-test/helm-diff-linux-amd64 2>&1)"
out="$(helm plugin install /tmp/archive-test/diff 2>&1)"
echo "$out"
# The install hook must find the bundled binary already staged in
# HELM_PLUGIN_DIR and skip the network download.
Expand All @@ -129,17 +138,46 @@ jobs:
uses: azure/setup-helm@v5
with:
version: v4.3.0
-
# Regression test for issue #1076: `helm plugin update` runs the
# *already installed* copy of install-binary.sh, so release tarballs
# must keep the layout every previously released hook expects
# ("$HELM_TMP/diff/bin/diff" after extraction). Simulate updating a
# pre-3.15.14 install (v3.15.13 hook) and a 3.15.14 install by
# running their exact install scripts, in update mode, against the
# archives just built.
name: Legacy update hook regression test (snapshot only)
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
run: |
set -e
archive="$PWD/dist/helm-diff-linux-amd64.tgz"
for hook_version in v3.15.13 v3.15.14; do
echo "== simulating 'helm plugin update' with the $hook_version install hook =="
plugin_dir="$(mktemp -d)/diff"
mkdir -p "$plugin_dir/bin"
git show "${hook_version}:install-binary.sh" > "$plugin_dir/install-binary.sh"
HELM_BIN=helm HELM_PLUGIN_DIR="$plugin_dir" \
HELM_DIFF_BIN_TGZ="$archive" \
sh "$plugin_dir/install-binary.sh" -u
test -x "$plugin_dir/bin/diff"
"$plugin_dir/bin/diff" version
echo "$hook_version hook updated the plugin successfully"
done
echo "Legacy update hook regression test passed"
-
# Regression test for issue #1071: helm 4 must be able to install
# directly from a local tarball (which it verifies by default), so
# archives must be wrapped in a directory named after the tarball.
# directly from a local tarball (which it verifies by default). When
# installing from a local file, helm 4 derives the directory it
# expects inside the archive from the tarball file name
# ("diff-<version>-<os>-<arch>.tgz" -> "diff/"), hence the versioned
# archive names.
name: Helm 4 offline tarball install test (snapshot only)
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
env:
HELM_DATA_HOME: /tmp/helm4-data
run: |
set -e
archive="dist/helm-diff-linux-amd64.tgz"
archive="$(find dist -maxdepth 1 -name 'diff-*-linux-amd64.tgz')"

export GNUPGHOME="$(mktemp -d)"
chmod 700 "$GNUPGHOME"
Expand Down
38 changes: 32 additions & 6 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,45 @@ builds:
- "6"
- "7"

# Archives wrap their content in a "diff/" directory. This is the layout
# every install/update hook released so far expects when it downloads a
# release tarball (it copies "$HELM_TMP/diff/bin/diff"), so it must not be
# changed: wrapping in any other directory breaks `helm plugin update` on
# all pre-existing installs (issue #1076).
#
# Helm 4, when installing from a *local* tarball, derives the directory it
# expects inside the archive from the tarball file name: "<name>-<version>-…"
# must contain "<name>/" (helm strips a trailing version component from the
# name; see stripPluginName in helm's plugin installer). To support that
# flow (issue #1071) each platform is published a second time under a
# versioned name, "diff-<version>-<os>-<arch>.tgz": the historical
# "helm-diff-<os>-<arch>.tgz" name cannot satisfy helm 4 because it carries
# no version component to strip. Both names wrap the identical "diff/"
# layout, and each gets its own ".prov" provenance signature (helm's
# verification matches file names against the checksums in the ".prov").
archives:
- id: default
builds:
- default
- linux-additional
format: tgz
name_template: '{{ .ProjectName }}-{{ if eq .Os "darwin" }}macos{{ else }}{{ .Os }}{{ end }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
# Wrap archives in a directory named after the archive itself
# (e.g. helm-diff-linux-amd64/). Helm 4's plugin installer requires this
# when installing from a local tarball: it derives the expected directory
# from the tarball filename and fails with "plugin.yaml not found in
# expected directory" otherwise (see issue #1071).
wrap_in_directory: true
wrap_in_directory: diff
files:
- README.md
- plugin.yaml
- LICENSE
- install-binary.sh
- install-binary.ps1
# The same archive under a versioned, helm 4-friendly name so it can be
# installed (and provenance-verified) directly from a local tarball.
- id: versioned
builds:
- default
- linux-additional
format: tgz
name_template: 'diff-{{ .Version }}-{{ if eq .Os "darwin" }}macos{{ else }}{{ .Os }}{{ end }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
wrap_in_directory: diff
files:
- README.md
- plugin.yaml
Expand Down
25 changes: 15 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,25 @@ docker-run-release:
-w $(pkg) helm-diff-release make release

# dist-package builds the plugin for a single platform and packs it into
# release/$(1).tgz. The archive content is wrapped in a directory named
# after the archive itself (e.g. helm-diff-linux-amd64/). Helm 4's plugin
# installer requires this when installing directly from a tarball: it
# derives the expected directory from the tarball filename and fails with
# "plugin.yaml not found in expected directory" otherwise (see issue #1071).
# release/helm-diff-$(1).tgz, plus a byte-identical copy named
# release/diff-$(VERSION)-$(1).tgz. Archives wrap their content in a "diff/"
# directory: that is the layout the install/update hooks of all previously
# released versions expect when they download a release tarball, so it must
# not change (issue #1076). The versioned copy exists because helm 4 derives
# the directory it expects inside a locally installed tarball from the
# tarball file name: "diff-<version>-<os>-<arch>.tgz" must contain "diff/"
# (issue #1071); the historical name carries no version to strip, so it
# cannot serve that flow.
# Usage: $(call dist-package,<platform>,<GOOS>,<GOARCH>[,<extra env>])
DIST_PACKAGE_FILES := README.md LICENSE plugin.yaml install-binary.sh install-binary.ps1
define dist-package
mkdir -p build/helm-diff-$(1)/bin
cp $(DIST_PACKAGE_FILES) build/helm-diff-$(1)/
mkdir -p build/diff/bin
cp $(DIST_PACKAGE_FILES) build/diff/
goarch=$(3); bin=diff; [ "$(2)" = "windows" ] && bin=$$bin.exe; \
$(4) GOOS=$(2) GOARCH=$$goarch $(GO) build -o build/helm-diff-$(1)/bin/$$bin -trimpath -ldflags="$(LDFLAGS)"
tar -C build/ -zcvf $(CURDIR)/release/helm-diff-$(1).tgz helm-diff-$(1)/
rm -rf build/helm-diff-$(1)
$(4) GOOS=$(2) GOARCH=$$goarch $(GO) build -o build/diff/bin/$$bin -trimpath -ldflags="$(LDFLAGS)"
tar -C build/ -zcvf $(CURDIR)/release/helm-diff-$(1).tgz diff/
cp $(CURDIR)/release/helm-diff-$(1).tgz $(CURDIR)/release/diff-$(VERSION)-$(1).tgz
rm -rf build/diff

endef

Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ helm plugin install https://github.com/databus23/helm-diff

If installing this in an offline/airgapped environment, download the platform-specific binary archive (e.g., `helm-diff-linux-amd64.tgz` or `helm-diff-windows-amd64.tgz`) from [releases](https://github.com/databus23/helm-diff/releases). Make sure to select the correct `.tgz` file for your operating system and architecture.

The release archives include everything needed to install the plugin (binary, `plugin.yaml`, and the install scripts). Each archive wraps its content in a directory named after the archive itself (e.g. `helm-diff-linux-amd64/`), which is what Helm 4 expects when installing from a tarball.
The release archives include everything needed to install the plugin (binary, `plugin.yaml`, and the install scripts). Each archive wraps its content in a `diff/` directory — the layout the plugin's install scripts have always expected.

The simplest way to install offline is to extract the archive and point `helm plugin install` at the extracted directory:

```
tar xzf helm-diff-linux-amd64.tgz # extracts into a ./helm-diff-linux-amd64 directory
helm plugin install ./helm-diff-linux-amd64
tar xzf helm-diff-linux-amd64.tgz # extracts into a ./diff directory
helm plugin install ./diff
```

The install script detects that the binary is already bundled and skips the GitHub download.
Expand Down Expand Up @@ -65,15 +65,15 @@ gpg --list-keys --with-fingerprint EA17A2A206AFF8CD
helm plugin install https://github.com/databus23/helm-diff/releases/latest/download/helm-diff-linux-amd64.tgz
```

For offline/airgapped environments with Helm 4, transfer the release tarball **together with its `.prov` file** (and keep the original tarball file name — provenance verification matches the file name against the checksums recorded in the `.prov` file) and install directly from the tarball:
For offline/airgapped environments with Helm 4, transfer the release tarball **together with its `.prov` file** and install directly from the tarball. Use the **versioned** asset name (`diff-<version>-<os>-<arch>.tgz`, e.g. `diff-3.15.15-linux-amd64.tgz`): when installing from a local file, Helm 4 derives the directory it expects inside the archive from the tarball file name (`diff-3.15.15-linux-amd64.tgz` → `diff/`), so keep the original file name as well — provenance verification also matches the file name against the checksums recorded in the `.prov` file:

```shell
curl -LO https://github.com/databus23/helm-diff/releases/download/<TAG>/helm-diff-linux-amd64.tgz
curl -LO https://github.com/databus23/helm-diff/releases/download/<TAG>/helm-diff-linux-amd64.tgz.prov
helm plugin install helm-diff-linux-amd64.tgz --keyring <path-to-keyring.gpg>
curl -LO https://github.com/databus23/helm-diff/releases/download/<TAG>/diff-<VERSION>-linux-amd64.tgz
curl -LO https://github.com/databus23/helm-diff/releases/download/<TAG>/diff-<VERSION>-linux-amd64.tgz.prov
helm plugin install diff-<VERSION>-linux-amd64.tgz --keyring <path-to-keyring.gpg>
```

(Replace `<TAG>` with the release you are installing. The direct tarball install requires Helm 4. On Helm 3, extract the archive and install from the extracted directory as described above.)
(Replace `<TAG>`/`<VERSION>` with the release you are installing. The versioned asset is only needed for installs directly from a local tarball; on Helm 3, extract the archive and install from the extracted directory as described above.)

For offline/airgapped environments, download the public key from the maintainer's GitHub profile on a connected machine, transfer it, and import it locally:

Expand Down
18 changes: 10 additions & 8 deletions install-binary.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@ function Install-Plugin {
tar -xzf $ArchiveName -C .
Pop-Location
New-Item -ItemType Directory -Path $Destination -Force
# Release archives wrap their content in a directory named after the
# archive itself (e.g. helm-diff-windows-amd64/bin/diff.exe), as required
# by helm 4 when installing directly from a tarball (issue #1071).
# Archives from earlier releases wrap the content in a
# directory named "diff" instead.
# Release archives wrap their content in a "diff" directory — the layout
# the install/update hooks of every released version expect, so it must not
# change (issue #1076). The 3.15.14 release instead wrapped the content in a
# directory named after the archive itself (e.g. helm-diff-windows-amd64/
# bin/diff.exe), as required by helm 4 when installing directly from a
# tarball (issue #1071); support that layout as well so 3.15.14 tarballs
# keep installing and updating.
$wrapDir = [System.IO.Path]::GetFileNameWithoutExtension($ArchiveName)
$binary = Join-Path $ArchiveDirectory $wrapDir "bin" "diff.exe"
if (-not (Test-Path $binary -PathType Leaf)) {
Expand All @@ -81,9 +83,9 @@ $ErrorActionPreference = "Stop"

$arch = Get-Architecture

# Archives wrap their content in a directory named after the archive
# itself (see Install-Plugin below), so the temporary copy must keep the
# original file name.
# The 3.15.14 release archives wrapped their content in a directory named
# after the archive itself (see Install-Plugin below), so the temporary copy
# of HELM_DIFF_BIN_TGZ must keep its original file name.
$archiveName = "helm-diff-windows-${arch}.tgz"

# If installing (not updating) and the binary is already staged in the
Expand Down
15 changes: 9 additions & 6 deletions install-binary.sh
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,9 @@ rmTempDir() {
# for that binary.
downloadFile() {
# If HELM_DIFF_BIN_TGZ is set, copy the local file instead of downloading.
# Keep its original file name: release archives wrap their content in a
# directory named after the archive (see installFile below).
# Keep its original file name: the 3.15.14 release archives wrapped their
# content in a directory named after the archive, which installFile locates
# via the file name (see below).
if [ -n "$HELM_DIFF_BIN_TGZ" ]; then
echo "Using local package at $HELM_DIFF_BIN_TGZ"
if [ ! -f "$HELM_DIFF_BIN_TGZ" ]; then
Expand Down Expand Up @@ -162,11 +163,13 @@ installFile() {
if [ "${OS}" = "windows" ]; then
bin="$bin.exe"
fi
# Release archives wrap their content in a directory named after the
# Release archives wrap their content in a "diff/" directory — the layout
# the install/update hooks of every released version expect when they
# download a tarball, so it must not change (issue #1076). The 3.15.14
# release instead wrapped the content in a directory named after the
# archive itself (e.g. helm-diff-linux-amd64/bin/diff), as required by
# helm 4 when installing directly from a tarball (issue #1071).
# Archives from earlier releases wrap the content in a directory named
# "diff" instead.
# helm 4 when installing directly from a tarball (issue #1071); support
# that layout as well so 3.15.14 tarballs keep installing and updating.
wrap_dir="$(basename "$PLUGIN_TMP_FILE" .tgz)"
HELM_TMP_BIN="$HELM_TMP/$wrap_dir/bin/$bin"
if [ ! -f "$HELM_TMP_BIN" ] && [ -f "$HELM_TMP/diff/bin/$bin" ]; then
Expand Down
Loading