Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package kubectl-view-secret for 
openSUSE:Factory checked in at 2024-08-17 12:41:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/kubectl-view-secret (Old)
 and      /work/SRC/openSUSE:Factory/.kubectl-view-secret.new.2698 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "kubectl-view-secret"

Sat Aug 17 12:41:42 2024 rev:4 rq:1194373 version:0.13.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/kubectl-view-secret/kubectl-view-secret.changes  
2024-08-02 17:27:56.398795630 +0200
+++ 
/work/SRC/openSUSE:Factory/.kubectl-view-secret.new.2698/kubectl-view-secret.changes
        2024-08-17 12:42:00.185404657 +0200
@@ -1,0 +2,9 @@
+Fri Aug 16 18:13:25 UTC 2024 - opensuse_buildserv...@ojkastl.de
+
+- Update to version 0.13.0:
+  * Update changelog for v0.13.0 release
+  * Integrate with huh for better interface (#47)
+  * Add instructions for nixpkgs to README (#49)
+  * Add test coverage via codecov.io (#48)
+
+-------------------------------------------------------------------
@@ -4,2 +13,2 @@
-- make kubectl recognize this as a plugin by having an executable with the
-  right name
+- make kubectl recognize this as a plugin by having an executable
+  with the right name

Old:
----
  kubectl-view-secret-0.12.1.obscpio

New:
----
  kubectl-view-secret-0.13.0.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ kubectl-view-secret.spec ++++++
--- /var/tmp/diff_new_pack.YZuwSe/_old  2024-08-17 12:42:00.689425616 +0200
+++ /var/tmp/diff_new_pack.YZuwSe/_new  2024-08-17 12:42:00.693425782 +0200
@@ -23,7 +23,7 @@
 %define executable_name kubectl-view_secret
 
 Name:           kubectl-view-secret
-Version:        0.12.1
+Version:        0.13.0
 Release:        0
 Summary:        Kubernetes CLI plugin to decode Kubernetes secrets
 License:        MIT

++++++ _service ++++++
--- /var/tmp/diff_new_pack.YZuwSe/_old  2024-08-17 12:42:00.721426947 +0200
+++ /var/tmp/diff_new_pack.YZuwSe/_new  2024-08-17 12:42:00.725427113 +0200
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/elsesiy/kubectl-view-secret</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="revision">v0.12.1</param>
+    <param name="revision">v0.13.0</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="changesgenerate">enable</param>
     <param name="versionrewrite-pattern">v(.*)</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.YZuwSe/_old  2024-08-17 12:42:00.745427945 +0200
+++ /var/tmp/diff_new_pack.YZuwSe/_new  2024-08-17 12:42:00.749428111 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/elsesiy/kubectl-view-secret</param>
-              <param 
name="changesrevision">122b2e639fd48b6bd2655957e82c539d83ced5df</param></service></servicedata>
+              <param 
name="changesrevision">9599a2e2e9bf4ecc14d6b4fb52230c10195ecb4e</param></service></servicedata>
 (No newline at EOF)
 

++++++ kubectl-view-secret-0.12.1.obscpio -> kubectl-view-secret-0.13.0.obscpio 
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/.github/workflows/ci.yml 
new/kubectl-view-secret-0.13.0/.github/workflows/ci.yml
--- old/kubectl-view-secret-0.12.1/.github/workflows/ci.yml     2024-08-02 
06:26:00.000000000 +0200
+++ new/kubectl-view-secret-0.13.0/.github/workflows/ci.yml     2024-08-14 
22:05:48.000000000 +0200
@@ -1,15 +1,25 @@
 ---
 name: ci
-on:
-  pull_request:
+on: [push, pull_request]
 jobs:
   ci_job:
     name: test
     runs-on: ubuntu-22.04
-    container:
-      image: golang:1.22
     steps:
       - name: Checkout
         uses: actions/checkout@v4
+      - name: Create kind cluster
+        uses: helm/kind-action@v1
+        with:
+          cluster_name: kvs-test
+          install_only: true
+      - name: Prepare env
+        run: make bootstrap
       - name: Test
         run: make test
+      - name: Generate coverage report
+        run: make test-cov
+      - name: Upload results to Codecov
+        uses: codecov/codecov-action@v4
+        with:
+          token: ${{ secrets.CODECOV_TOKEN }}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/.gitignore 
new/kubectl-view-secret-0.13.0/.gitignore
--- old/kubectl-view-secret-0.12.1/.gitignore   2024-08-02 06:26:00.000000000 
+0200
+++ new/kubectl-view-secret-0.13.0/.gitignore   2024-08-14 22:05:48.000000000 
+0200
@@ -4,4 +4,5 @@
 .idea
 .vscode
 
-kubectl-view-secret
\ No newline at end of file
+kubectl-view-secret
+coverage.txt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/CHANGELOG.md 
new/kubectl-view-secret-0.13.0/CHANGELOG.md
--- old/kubectl-view-secret-0.12.1/CHANGELOG.md 2024-08-02 06:26:00.000000000 
+0200
+++ new/kubectl-view-secret-0.13.0/CHANGELOG.md 2024-08-14 22:05:48.000000000 
+0200
@@ -1,8 +1,18 @@
 # Changelog
 
-## [0.12.1](https://github.com/elsesiy/kubectl-view-secret/tree/0.12.1) 
(2024-08-02)
+## [0.13.0](https://github.com/elsesiy/kubectl-view-secret/tree/0.13.0) 
(2024-08-14)
 
-[Full 
Changelog](https://github.com/elsesiy/kubectl-view-secret/compare/v0.12.0...0.12.1)
+[Full 
Changelog](https://github.com/elsesiy/kubectl-view-secret/compare/v0.12.1...0.13.0)
+
+**Merged pull requests:**
+
+- Add instructions for nixpkgs to README 
[\#49](https://github.com/elsesiy/kubectl-view-secret/pull/49) 
([elsesiy](https://github.com/elsesiy))
+- Add test coverage via codecov.io 
[\#48](https://github.com/elsesiy/kubectl-view-secret/pull/48) 
([elsesiy](https://github.com/elsesiy))
+- Integrate with huh for better interface 
[\#47](https://github.com/elsesiy/kubectl-view-secret/pull/47) 
([elsesiy](https://github.com/elsesiy))
+
+## [v0.12.1](https://github.com/elsesiy/kubectl-view-secret/tree/v0.12.1) 
(2024-08-02)
+
+[Full 
Changelog](https://github.com/elsesiy/kubectl-view-secret/compare/v0.12.0...v0.12.1)
 
 **Closed issues:**
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/Makefile 
new/kubectl-view-secret-0.13.0/Makefile
--- old/kubectl-view-secret-0.12.1/Makefile     2024-08-02 06:26:00.000000000 
+0200
+++ new/kubectl-view-secret-0.13.0/Makefile     2024-08-14 22:05:48.000000000 
+0200
@@ -1,13 +1,22 @@
 SOURCES := $(shell find . -name '*.go')
 BINARY := kubectl-view-secret
+COV_REPORT := "coverage.txt"
 
 build: kubectl-view-secret
 
+bootstrap:
+       ./hack/kind-bootstrap.sh
+
 test: $(SOURCES)
        go test -v -short -race -timeout 30s ./...
 
+test-cov:
+       go test ./... -coverprofile=$(COV_REPORT)
+       go tool cover -html=$(COV_REPORT)
+
 clean:
        @rm -rf $(BINARY)
+       @kind delete cluster --name kvs-test
 
 $(BINARY): $(SOURCES)
        CGO_ENABLED=0 go build -o $(BINARY) -ldflags="-s -w" ./cmd/$(BINARY).go
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/README.md 
new/kubectl-view-secret-0.13.0/README.md
--- old/kubectl-view-secret-0.12.1/README.md    2024-08-02 06:26:00.000000000 
+0200
+++ new/kubectl-view-secret-0.13.0/README.md    2024-08-14 22:05:48.000000000 
+0200
@@ -2,9 +2,12 @@
 
 [![Go Report 
Card](https://goreportcard.com/badge/github.com/elsesiy/kubectl-view-secret)](https://goreportcard.com/report/github.com/elsesiy/kubectl-view-secret)
 
![CI](https://github.com/elsesiy/kubectl-view-secret/actions/workflows/ci.yml/badge.svg)
+[![codecov](https://codecov.io/github/elsesiy/kubectl-view-secret/graph/badge.svg?token=RODJX5GLDB)](https://codecov.io/github/elsesiy/kubectl-view-secret)
 
[![Twitter](https://img.shields.io/badge/twitt...@elsesiy-blue.svg)](http://twitter.com/elsesiy)
 [![GitHub 
release](https://img.shields.io/github/release/elsesiy/kubectl-view-secret.svg)](https://github.com/elsesiy/kubectl-view-secret/releases)
 
+![gif](./media/view-secret.gif)
+
 This plugin allows for easy secret decoding. Useful if you want to see what's 
inside of a secret without always go through the following:
 
 1. `kubectl get secret <secret> -o yaml`
@@ -58,6 +61,13 @@
 
 Contribution by [@jocelynthode](https://github.com/jocelynthode)
 
+#### Nix
+You can install the latest version from Nixpkgs 
([24.05](https://search.nixos.org/packages?channel=24.05&from=0&size=50&sort=relevance&type=packages&query=kubectl-view-secret),
 
[unstable](https://search.nixos.org/packages?channel=unstable&show=kubectl-view-secret&from=0&size=50&sort=relevance&type=packages&query=kubectl-view-secret))
 or try it via a temporary nix-shell:
+
+```
+nix-shell -p kubectl-view-secret
+```
+
 ### Build from source
 
     # Clone this repository (or your fork)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/go.mod 
new/kubectl-view-secret-0.13.0/go.mod
--- old/kubectl-view-secret-0.12.1/go.mod       2024-08-02 06:26:00.000000000 
+0200
+++ new/kubectl-view-secret-0.13.0/go.mod       2024-08-14 22:05:48.000000000 
+0200
@@ -3,12 +3,43 @@
 go 1.22
 
 require (
+       github.com/charmbracelet/bubbletea v0.26.6
+       github.com/charmbracelet/huh v0.5.2
        github.com/goccy/go-json v0.10.3
-       github.com/magiconair/properties v1.8.7
        github.com/spf13/cobra v1.8.1
+       github.com/stretchr/testify v1.9.0
 )
 
 require (
+       github.com/atotto/clipboard v0.1.4 // indirect
+       github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
+       github.com/catppuccin/go v0.2.0 // indirect
+       github.com/charmbracelet/bubbles v0.18.0 // indirect
+       github.com/charmbracelet/lipgloss v0.12.1 // indirect
+       github.com/charmbracelet/x/ansi v0.1.4 // indirect
+       github.com/charmbracelet/x/exp/strings 
v0.0.0-20240806224806-c5da01e9b4d1 // indirect
+       github.com/charmbracelet/x/exp/term v0.0.0-20240725160154-f9f6568126ec 
// indirect
+       github.com/charmbracelet/x/input v0.1.3 // indirect
+       github.com/charmbracelet/x/term v0.1.1 // indirect
+       github.com/charmbracelet/x/windows v0.1.2 // indirect
+       github.com/davecgh/go-spew v1.1.1 // indirect
+       github.com/dustin/go-humanize v1.0.1 // indirect
+       github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // 
indirect
        github.com/inconshreveable/mousetrap v1.1.0 // indirect
+       github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
+       github.com/mattn/go-isatty v0.0.20 // indirect
+       github.com/mattn/go-localereader v0.0.1 // indirect
+       github.com/mattn/go-runewidth v0.0.16 // indirect
+       github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
+       github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
+       github.com/muesli/cancelreader v0.2.2 // indirect
+       github.com/muesli/termenv v0.15.2 // indirect
+       github.com/pmezard/go-difflib v1.0.0 // indirect
+       github.com/rivo/uniseg v0.4.7 // indirect
        github.com/spf13/pflag v1.0.5 // indirect
+       github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
+       golang.org/x/sync v0.8.0 // indirect
+       golang.org/x/sys v0.23.0 // indirect
+       golang.org/x/text v0.17.0 // indirect
+       gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/go.sum 
new/kubectl-view-secret-0.13.0/go.sum
--- old/kubectl-view-secret-0.12.1/go.sum       2024-08-02 06:26:00.000000000 
+0200
+++ new/kubectl-view-secret-0.13.0/go.sum       2024-08-14 22:05:48.000000000 
+0200
@@ -1,19 +1,81 @@
-github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod 
h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/atotto/clipboard v0.1.4 
h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
+github.com/atotto/clipboard v0.1.4/go.mod 
h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1 
h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod 
h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
+github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA=
+github.com/catppuccin/go v0.2.0/go.mod 
h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
+github.com/charmbracelet/bubbles v0.18.0 
h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0=
+github.com/charmbracelet/bubbles v0.18.0/go.mod 
h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw=
+github.com/charmbracelet/bubbletea v0.26.6 
h1:zTCWSuST+3yZYZnVSvbXwKOPRSNZceVeqpzOLN2zq1s=
+github.com/charmbracelet/bubbletea v0.26.6/go.mod 
h1:dz8CWPlfCCGLFbBlTY4N7bjLiyOGDJEnd2Muu7pOWhk=
+github.com/charmbracelet/huh v0.5.2 
h1:ofeNkJ4iaFnzv46Njhx896DzLUe/j0L2QAf8znwzX4c=
+github.com/charmbracelet/huh v0.5.2/go.mod 
h1:Sf7dY0oAn6N/e3sXJFtFX9hdQLrUdO3z7AYollG9bAM=
+github.com/charmbracelet/lipgloss v0.12.1 
h1:/gmzszl+pedQpjCOH+wFkZr/N90Snz40J/NR7A0zQcs=
+github.com/charmbracelet/lipgloss v0.12.1/go.mod 
h1:V2CiwIuhx9S1S1ZlADfOj9HmxeMAORuz5izHb0zGbB8=
+github.com/charmbracelet/x/ansi v0.1.4 
h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM=
+github.com/charmbracelet/x/ansi v0.1.4/go.mod 
h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
+github.com/charmbracelet/x/exp/strings v0.0.0-20240806224806-c5da01e9b4d1 
h1:KuM2G5oWPAd0FlLh+mSl5p6bLVKK52KEmSik5z6UNbE=
+github.com/charmbracelet/x/exp/strings 
v0.0.0-20240806224806-c5da01e9b4d1/go.mod 
h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
+github.com/charmbracelet/x/exp/term v0.0.0-20240725160154-f9f6568126ec 
h1:tg3MAnVjISHLuysTCGGtsjkuoBzPzL9OrWvxs5Rd29I=
+github.com/charmbracelet/x/exp/term v0.0.0-20240725160154-f9f6568126ec/go.mod 
h1:YG0dzr31td4jqC86wFlB8fJGgPwqPgTSa8VC0Hf7u+k=
+github.com/charmbracelet/x/input v0.1.3 
h1:oy4TMhyGQsYs/WWJwu1ELUMFnjiUAXwtDf048fHbCkg=
+github.com/charmbracelet/x/input v0.1.3/go.mod 
h1:1gaCOyw1KI9e2j00j/BBZ4ErzRZqa05w0Ghn83yIhKU=
+github.com/charmbracelet/x/term v0.1.1 
h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI=
+github.com/charmbracelet/x/term v0.1.1/go.mod 
h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw=
+github.com/charmbracelet/x/windows v0.1.2 
h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg=
+github.com/charmbracelet/x/windows v0.1.2/go.mod 
h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ=
 github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod 
h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
-github.com/goccy/go-json v0.10.2 
h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
-github.com/goccy/go-json v0.10.2/go.mod 
h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/davecgh/go-spew v1.1.1 
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dustin/go-humanize v1.0.1 
h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod 
h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
+github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f 
h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
+github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod 
h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
 github.com/goccy/go-json v0.10.3 
h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
 github.com/goccy/go-json v0.10.3/go.mod 
h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 github.com/inconshreveable/mousetrap v1.1.0 
h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 github.com/inconshreveable/mousetrap v1.1.0/go.mod 
h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/magiconair/properties v1.8.7 
h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
-github.com/magiconair/properties v1.8.7/go.mod 
h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/lucasb-eyer/go-colorful v1.2.0 
h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod 
h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/mattn/go-isatty v0.0.20 
h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod 
h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-localereader v0.0.1 
h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
+github.com/mattn/go-localereader v0.0.1/go.mod 
h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
+github.com/mattn/go-runewidth v0.0.16 
h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod 
h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mitchellh/hashstructure/v2 v2.0.2 
h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
+github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod 
h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
+github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 
h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
+github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod 
h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
+github.com/muesli/cancelreader v0.2.2 
h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
+github.com/muesli/cancelreader v0.2.2/go.mod 
h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
+github.com/muesli/termenv v0.15.2 
h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
+github.com/muesli/termenv v0.15.2/go.mod 
h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
+github.com/pmezard/go-difflib v1.0.0 
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rivo/uniseg v0.2.0/go.mod 
h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod 
h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod 
h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
-github.com/spf13/cobra v1.8.0/go.mod 
h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
 github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
 github.com/spf13/cobra v1.8.1/go.mod 
h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod 
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stretchr/testify v1.9.0 
h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod 
h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e 
h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod 
h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
+golang.org/x/exp v0.0.0-20231006140011-7918f672742d 
h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
+golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod 
h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
+golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod 
h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 
h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/hack/kind-bootstrap.sh 
new/kubectl-view-secret-0.13.0/hack/kind-bootstrap.sh
--- old/kubectl-view-secret-0.12.1/hack/kind-bootstrap.sh       1970-01-01 
01:00:00.000000000 +0100
+++ new/kubectl-view-secret-0.13.0/hack/kind-bootstrap.sh       2024-08-14 
22:05:48.000000000 +0200
@@ -0,0 +1,70 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+CLUSTER_NAME="kvs-test"
+
+# Check if kind & kubectl are installed
+which kind &>/dev/null || { echo "failed to find 'kind' binary, please install 
it" && exit 1; }
+which kubectl &>/dev/null || { echo "failed to find 'kubectl' binary, please 
install it" && exit 1; }
+
+# Ensure the cluster exists
+[[ $(kind get clusters) == *$CLUSTER_NAME* ]] || kind create cluster --name 
$CLUSTER_NAME
+
+# Set context in case there are mulitple
+kubectl config set-context kind-${CLUSTER_NAME}
+
+# Seed test secrets
+
+## secret 'test' in namespace 'default' (multiple keys)
+kubectl apply -f - <<EOF
+apiVersion: v1
+data:
+  key1: dmFsdWUxCg==
+  key2: dmFsdWUyCg==
+kind: Secret
+metadata:
+  name: test
+  namespace: default
+type: Opaque
+EOF
+
+## secret 'test2' in namespace 'default' (single key)
+kubectl apply -f - <<EOF
+apiVersion: v1
+data:
+  key1: dmFsdWUx
+kind: Secret
+metadata:
+  name: test2
+  namespace: default
+type: Opaque
+EOF
+
+## 'another' namespace
+kubectl apply -f - <<EOF
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: another
+EOF
+
+## secret 'gopher' in namespace 'another' (single key)
+kubectl apply -f - <<EOF
+apiVersion: v1
+data:
+  foo: YmFy
+kind: Secret
+metadata:
+  name: gopher
+  namespace: another
+type: Opaque
+EOF
+
+## 'empty' namespace
+kubectl apply -f - <<EOF
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: empty
+EOF
Binary files old/kubectl-view-secret-0.12.1/media/view-secret.gif and 
new/kubectl-view-secret-0.13.0/media/view-secret.gif differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/media/view-secret.tape 
new/kubectl-view-secret-0.13.0/media/view-secret.tape
--- old/kubectl-view-secret-0.12.1/media/view-secret.tape       1970-01-01 
01:00:00.000000000 +0100
+++ new/kubectl-view-secret-0.13.0/media/view-secret.tape       2024-08-14 
22:05:48.000000000 +0200
@@ -0,0 +1,88 @@
+Output media/view-secret.gif
+Set Theme "Catppuccin Mocha"
+Set CursorBlink false
+Set Width 1400
+
+Hide
+Type "# Secrets in current namespace"
+Enter 2
+Show
+Sleep 2
+Type "kubectl get secret"
+Enter
+Sleep 2
+Type "clear"
+Enter
+
+Hide
+Type "# Showing all secrets in current namespace with interactive selection"
+Enter 2
+Show
+Sleep 2
+Type "kubectl view-secret"
+Enter
+Sleep 2
+Down
+Sleep 1
+Enter
+Sleep 1
+Type "clear"
+Enter
+
+Hide
+Type "# View 'test' secret in current namespace with interactive selection for 
a single key"
+Enter 2
+Show
+Sleep 2
+Type "kubectl view-secret test"
+Enter
+Sleep 1
+Type "/key2"
+Sleep 1
+Enter
+Sleep 1
+Type "clear"
+Enter
+
+Hide
+Type "# View 'test' secret in current namespace and show all keys"
+Enter 2
+Show
+Sleep 2
+Type "kubectl view-secret test -a"
+Enter
+Sleep 1
+Type "clear"
+Enter
+
+Hide
+Type "# View 'test2' secret in current namespace immediately shows the secret 
contents (only one key exists)"
+Enter 2
+Show
+Sleep 2
+Type "kubectl view-secret test2"
+Enter
+Sleep 1
+Type "clear"
+Enter
+
+Hide
+Type "# Secrets in 'another' namespace"
+Enter 2
+Show
+Sleep 2
+Type "kubectl get secret -n another"
+Enter
+Sleep 2
+Type "clear"
+Enter
+
+Hide
+Type "# View 'gopher' secret in 'another' namespace and silence info about 
single key"
+Enter 2
+Show
+Sleep 2
+Type "kubectl view-secret gopher -n another -q"
+Enter
+
+Sleep 5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/pkg/cmd/types.go 
new/kubectl-view-secret-0.13.0/pkg/cmd/types.go
--- old/kubectl-view-secret-0.12.1/pkg/cmd/types.go     1970-01-01 
01:00:00.000000000 +0100
+++ new/kubectl-view-secret-0.13.0/pkg/cmd/types.go     2024-08-14 
22:05:48.000000000 +0200
@@ -0,0 +1,17 @@
+package cmd
+
+type SecretList struct {
+       Items []Secret `json:"items"`
+}
+
+type Secret struct {
+       Data     SecretData `json:"data"`
+       Metadata Metadata   `json:"metadata"`
+}
+
+type SecretData map[string]string
+
+type Metadata struct {
+       Name      string `json:"name"`
+       Namespace string `json:"namespace"`
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/pkg/cmd/types_test.go 
new/kubectl-view-secret-0.13.0/pkg/cmd/types_test.go
--- old/kubectl-view-secret-0.12.1/pkg/cmd/types_test.go        1970-01-01 
01:00:00.000000000 +0100
+++ new/kubectl-view-secret-0.13.0/pkg/cmd/types_test.go        2024-08-14 
22:05:48.000000000 +0200
@@ -0,0 +1,96 @@
+package cmd
+
+import (
+       "encoding/json"
+       "errors"
+       "reflect"
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+)
+
+var (
+       validSecretJson = `{
+    "apiVersion": "v1",
+    "data": {
+        "key1": "dmFsdWUxCg==",
+        "key2": "dmFsdWUyCg=="
+    },
+    "kind": "Secret",
+    "metadata": {
+        "creationTimestamp": "2024-08-02T21:25:40Z",
+        "name": "test",
+        "namespace": "default",
+        "resourceVersion": "715",
+        "uid": "0027fdc9-5371-4715-a0a8-61f3f78fdd36"
+    },
+    "type": "Opaque"
+}`
+
+       emptySecretJson = `{
+    "apiVersion": "v1",
+    "data": {},
+    "kind": "Secret",
+    "metadata": {
+        "name": "test-empty",
+        "namespace": "default",
+    },
+    "type": "Opaque"
+}`
+)
+
+func TestSerialize(t *testing.T) {
+       tests := map[string]struct {
+               input   string
+               want    Secret
+               wantErr error
+       }{
+               "empty secret": {
+                       input: emptySecretJson,
+                       want: Secret{
+                               Metadata: Metadata{
+                                       Name:      "test",
+                                       Namespace: "default",
+                               },
+                       },
+                       wantErr: errors.New("invalid character '}' looking for 
beginning of object key string"),
+               },
+               "valid secret": {
+                       input: validSecretJson,
+                       want: Secret{
+                               Data: SecretData{
+                                       "key1": "dmFsdWUxCg==",
+                                       "key2": "dmFsdWUyCg==",
+                               },
+                               Metadata: Metadata{
+                                       Name:      "test",
+                                       Namespace: "default",
+                               },
+                       },
+               },
+       }
+
+       for name, tt := range tests {
+               t.Run(name, func(t *testing.T) {
+                       t.Parallel()
+
+                       var got Secret
+                       err := json.Unmarshal([]byte(tt.input), &got)
+                       if err != nil {
+                               if tt.wantErr == nil {
+                                       assert.Fail(t, "unexpected error", err)
+                               } else if err.Error() != tt.wantErr.Error() {
+                                       assert.Equal(t, tt.wantErr, err)
+                               }
+                               return
+                       } else if tt.wantErr != nil {
+                               assert.Fail(t, "expected error, got nil", 
tt.wantErr)
+                               return
+                       }
+
+                       if !reflect.DeepEqual(got, tt.want) {
+                               t.Fatal(err)
+                       }
+               })
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/pkg/cmd/view-secret.go 
new/kubectl-view-secret-0.13.0/pkg/cmd/view-secret.go
--- old/kubectl-view-secret-0.12.1/pkg/cmd/view-secret.go       2024-08-02 
06:26:00.000000000 +0200
+++ new/kubectl-view-secret-0.13.0/pkg/cmd/view-secret.go       2024-08-14 
22:05:48.000000000 +0200
@@ -11,6 +11,8 @@
        "sort"
        "strings"
 
+       tea "github.com/charmbracelet/bubbletea"
+       "github.com/charmbracelet/huh"
        "github.com/goccy/go-json"
        "github.com/spf13/cobra"
 )
@@ -39,19 +41,23 @@
        %[1]s view-secret <secret> -q/--quiet
 `
 
-       singleKeyDescription = "Choosing key: %[1]s"
-       listDescription      = "Multiple sub keys found. Specify another 
argument, one of:"
-       listPrefix           = "->"
+       secretDescription     = "Found %d keys in secret %q. Choose one or 
select 'all' to view."
+       secretListDescription = "Found %d secrets. Choose one."
+       secretListTitle       = "Available Secrets"
+       secretTitle           = "Secret Data"
+       singleKeyDescription  = "Viewing only available key: %[1]s"
 )
 
-// ErrSecretKeyNotFound is thrown if the key doesn't exist in the secret
-var ErrSecretKeyNotFound = errors.New("provided key not found in secret")
+var (
+       // ErrNoSecretFound is thrown when no secret name was provided but we 
didn't find any secrets
+       ErrNoSecretFound = errors.New("no secrets found")
 
-// ErrSecretEmpty is thrown when there's no data in the secret
-var ErrSecretEmpty = errors.New("secret is empty")
+       // ErrSecretEmpty is thrown when there's no data in the secret
+       ErrSecretEmpty = errors.New("secret is empty")
 
-// ErrInsufficientArgs is thrown if arg len <1 or >2
-var ErrInsufficientArgs = fmt.Errorf("\nincorrect number or arguments, see 
--help for usage instructions")
+       // ErrSecretKeyNotFound is thrown if the key doesn't exist in the secret
+       ErrSecretKeyNotFound = errors.New("provided key not found in secret")
+)
 
 // CommandOpts is the struct holding common properties
 type CommandOpts struct {
@@ -71,14 +77,13 @@
        res := &CommandOpts{}
 
        cmd := &cobra.Command{
-               Use:          "view-secret [secret-name] [secret-key]",
-               Short:        "Decode a kubernetes secret by name & key in the 
current context/cluster/namespace",
+               Args:         cobra.RangeArgs(0, 2),
                Example:      fmt.Sprintf(example, "kubectl"),
+               Short:        "Decode a kubernetes secret by name & key in the 
current context/cluster/namespace",
                SilenceUsage: true,
+               Use:          "view-secret [secret-name] [secret-key]",
                RunE: func(c *cobra.Command, args []string) error {
-                       if err := res.Validate(args); err != nil {
-                               return err
-                       }
+                       res.ParseArgs(args)
                        if err := res.Retrieve(c); err != nil {
                                return err
                        }
@@ -100,19 +105,16 @@
        return cmd
 }
 
-// Validate ensures proper command usage
-func (c *CommandOpts) Validate(args []string) error {
+// ParseArgs serializes the user supplied program arguments
+func (c *CommandOpts) ParseArgs(args []string) {
        argLen := len(args)
-       if argLen < 1 || argLen > 2 {
-               return ErrInsufficientArgs
-       }
+       if argLen >= 1 {
+               c.secretName = args[0]
 
-       c.secretName = args[0]
-       if argLen == 2 {
-               c.secretKey = args[1]
+               if argLen == 2 {
+                       c.secretKey = args[1]
+               }
        }
-
-       return nil
 }
 
 // Retrieve reads the kubeconfig and decodes the secret
@@ -124,7 +126,12 @@
        impersonateGroupOverride, _ := cmd.Flags().GetString("as-group")
 
        var res, cmdErr bytes.Buffer
-       commandArgs := []string{"get", "secret", c.secretName, "-o", "json"}
+
+       commandArgs := []string{"get", "secret", "-o", "json"}
+       if c.secretName != "" {
+               commandArgs = []string{"get", "secret", c.secretName, "-o", 
"json"}
+       }
+
        if nsOverride != "" {
                commandArgs = append(commandArgs, "-n", nsOverride)
        }
@@ -154,54 +161,108 @@
                return nil
        }
 
-       var secret map[string]interface{}
-       if err := json.Unmarshal(res.Bytes(), &secret); err != nil {
-               return err
+       var secret Secret
+       if c.secretName == "" {
+               var secretList SecretList
+               if err := json.Unmarshal(res.Bytes(), &secretList); err != nil {
+                       return err
+               }
+
+               // Since we don't query valid namespaces, we'll avoid prompting 
the user to select a secret if we didn't retrieve any secrets
+               if len(secretList.Items) == 0 {
+                       return ErrNoSecretFound
+               }
+
+               opts := []string{}
+               secretMap := map[string]Secret{}
+               for _, v := range secretList.Items {
+                       opts = append(opts, v.Metadata.Name)
+                       secretMap[v.Metadata.Name] = v
+               }
+
+               err := huh.NewForm(
+                       huh.NewGroup(
+                               huh.NewSelect[string]().
+                                       Title(secretListTitle).
+                                       
Description(fmt.Sprintf(secretListDescription, len(secretList.Items))).
+                                       Options(huh.NewOptions(opts...)...).
+                                       Value(&c.secretName),
+                       ),
+               ).WithProgramOptions(tea.WithInput(cmd.InOrStdin()), 
tea.WithOutput(cmd.OutOrStdout())).Run()
+               if err != nil {
+                       return err
+               }
+
+               secret = secretMap[c.secretName]
+       } else {
+               if err := json.Unmarshal(res.Bytes(), &secret); err != nil {
+                       return err
+               }
        }
 
        if c.quiet {
-               return ProcessSecret(os.Stdout, io.Discard, secret, 
c.secretKey, c.decodeAll)
+               return ProcessSecret(cmd.OutOrStdout(), io.Discard, 
cmd.InOrStdin(), secret, c.secretKey, c.decodeAll)
        }
 
-       return ProcessSecret(os.Stdout, os.Stderr, secret, c.secretKey, 
c.decodeAll)
+       return ProcessSecret(cmd.OutOrStdout(), cmd.OutOrStderr(), 
cmd.InOrStdin(), secret, c.secretKey, c.decodeAll)
 }
 
 // ProcessSecret takes the secret and user input to determine the output
-func ProcessSecret(outWriter, errWriter io.Writer, secret 
map[string]interface{}, secretKey string, decodeAll bool) error {
-       data, ok := secret["data"].(map[string]interface{})
-       if !ok {
+func ProcessSecret(outWriter, errWriter io.Writer, inputReader io.Reader, 
secret Secret, secretKey string, decodeAll bool) error {
+       data := secret.Data
+       if len(data) == 0 {
                return ErrSecretEmpty
        }
 
        var keys []string
-       for k := range data {
+       for k := range secret.Data {
                keys = append(keys, k)
        }
        sort.Strings(keys)
 
        if decodeAll {
                for _, k := range keys {
-                       b64d, _ := 
base64.StdEncoding.DecodeString(data[k].(string))
+                       b64d, _ := base64.StdEncoding.DecodeString(data[k])
                        _, _ = fmt.Fprintf(outWriter, "%s='%s'\n", k, 
strings.TrimSpace(string(b64d)))
                }
        } else if len(data) == 1 {
                for k, v := range data {
                        _, _ = fmt.Fprintf(errWriter, 
singleKeyDescription+"\n", k)
-                       b64d, _ := base64.StdEncoding.DecodeString(v.(string))
-                       _, _ = fmt.Fprint(outWriter, string(b64d))
+                       b64d, _ := base64.StdEncoding.DecodeString(v)
+                       _, _ = fmt.Fprintf(outWriter, "%s\n", 
strings.TrimSpace(string(b64d)))
                }
        } else if secretKey != "" {
                if v, ok := data[secretKey]; ok {
-                       b64d, _ := base64.StdEncoding.DecodeString(v.(string))
-                       _, _ = fmt.Fprint(outWriter, string(b64d))
+                       b64d, _ := base64.StdEncoding.DecodeString(v)
+                       _, _ = fmt.Fprintf(outWriter, "%s\n", 
strings.TrimSpace(string(b64d)))
                } else {
                        return ErrSecretKeyNotFound
                }
        } else {
-               _, _ = fmt.Fprintln(errWriter, listDescription)
+               opts := []string{"all"}
                for k := range data {
-                       _, _ = fmt.Fprintf(outWriter, "%s %s\n", listPrefix, k)
+                       opts = append(opts, k)
+               }
+
+               var selection string
+               err := huh.NewForm(
+                       huh.NewGroup(
+                               huh.NewSelect[string]().
+                                       Title(secretTitle).
+                                       
Description(fmt.Sprintf(secretDescription, len(data), secret.Metadata.Name)).
+                                       Options(huh.NewOptions(opts...)...).
+                                       Value(&selection),
+                       ),
+               ).WithProgramOptions(tea.WithInput(inputReader), 
tea.WithOutput(outWriter)).Run()
+               if err != nil {
+                       return err
                }
+
+               if selection == "all" {
+                       decodeAll = true
+               }
+
+               return ProcessSecret(outWriter, errWriter, inputReader, secret, 
selection, decodeAll)
        }
 
        return nil
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kubectl-view-secret-0.12.1/pkg/cmd/view-secret_test.go 
new/kubectl-view-secret-0.13.0/pkg/cmd/view-secret_test.go
--- old/kubectl-view-secret-0.12.1/pkg/cmd/view-secret_test.go  2024-08-02 
06:26:00.000000000 +0200
+++ new/kubectl-view-secret-0.13.0/pkg/cmd/view-secret_test.go  2024-08-14 
22:05:48.000000000 +0200
@@ -1,81 +1,135 @@
 package cmd
 
 import (
-       "bufio"
        "bytes"
+       "errors"
        "fmt"
-       "reflect"
-       "sort"
+       "io"
        "strings"
        "testing"
 
-       "github.com/goccy/go-json"
-       "github.com/magiconair/properties/assert"
+       "github.com/stretchr/testify/assert"
 )
 
-const (
-       testSecret = `
-{
-    "data": {
-               "TEST_CONN_STR": 
"bW9uZ29kYjovL215REJSZWFkZXI6RDFmZmljdWx0UCU0MHNzdzByZEBtb25nb2RiMC5leGFtcGxlLmNvbToyNzAxNy8/YXV0aFNvdXJjZT1hZG1pbg==",
-        "TEST_PASSWORD": "c2VjcmV0Cg==",
-               "TEST_PASSWORD_2": "dmVyeXNlY3JldAo="
-    }
-}
-`
-       testSecretSingle = `
-{
-    "data": {
-        "SINGLE_PASSWORD": "c2VjcmV0Cg=="
-    }
-}
-`
-       testSecretEmpty = "{}"
+var (
+       secret = SecretData{
+               "TEST_CONN_STR":   
"bW9uZ29kYjovL215REJSZWFkZXI6RDFmZmljdWx0UCU0MHNzdzByZEBtb25nb2RiMC5leGFtcGxlLmNvbToyNzAxNy8/YXV0aFNvdXJjZT1hZG1pbg==",
+               "TEST_PASSWORD":   "c2VjcmV0Cg==",
+               "TEST_PASSWORD_2": "dmVyeXNlY3JldAo=",
+       }
+
+       secretSingle = SecretData{
+               "SINGLE_PASSWORD": "c2VjcmV0Cg==",
+       }
+
+       secretEmpty = SecretData{}
 )
 
-func TestValidate(t *testing.T) {
+func TestParseArgs(t *testing.T) {
        opts := CommandOpts{}
        tests := map[string]struct {
-               opts CommandOpts
-               args []string
-               err  error
+               opts     CommandOpts
+               args     []string
+               wantOpts CommandOpts
        }{
-               "args insufficient length": {opts, []string{}, 
ErrInsufficientArgs},
-               "valid args":               {opts, []string{"test", "key"}, 
nil},
+               "one arg":  {opts, []string{"test"}, CommandOpts{secretName: 
"test"}},
+               "two args": {opts, []string{"test", "key"}, 
CommandOpts{secretName: "test", secretKey: "key"}},
        }
 
        for name, test := range tests {
                t.Run(name, func(t *testing.T) {
-                       got := test.opts.Validate(test.args)
-                       want := test.err
-                       if got != want {
-                               t.Errorf("got %v, want %v", got, want)
+                       t.Parallel()
+
+                       test.opts.ParseArgs(test.args)
+                       got := test.opts
+                       if got != test.wantOpts {
+                               t.Errorf("got %v, want %v", got, test.wantOpts)
                        }
                })
        }
 }
 
-func TestProcessSecret(t *testing.T) {
-       var secret, secretSingle, secretEmpty map[string]interface{}
-       _ = json.Unmarshal([]byte(testSecret), &secret)
-       _ = json.Unmarshal([]byte(testSecretSingle), &secretSingle)
-       _ = json.Unmarshal([]byte(testSecretEmpty), &secretEmpty)
+func TestNewCmdViewSecret(t *testing.T) {
+       tests := map[string]struct {
+               args     []string
+               feedkeys string
+               want     string
+               wantErr  error
+       }{
+               "all":                        {args: []string{"test", "--all"}, 
want: `key1='value1'\nkey2='value2'`},
+               "custom ctx":                 {args: []string{"test", 
"--context", "gotest"}},
+               "custom kubecfg":             {args: []string{"test", 
"--kubeconfig", "cfg"}},
+               "custom ns (does not exist)": {args: []string{"test", 
"--namespace", "bob"}, want: `Error from server (NotFound): namespaces "bob" 
not found`},
+               "custom ns (no secret)":      {args: []string{"test", 
"--namespace", "another"}, want: `Error from server (NotFound): secrets "test" 
not found`},
+               "custom ns (valid secret)":   {args: []string{"gopher", 
"--namespace", "another"}, want: `Viewing only available key: foo\nbar`},
+               "impersonate group":          {args: []string{"test", "--as", 
"gopher"}},
+               "impersonate user & group":   {args: []string{"test", "--as", 
"gopher", "--as-group", "golovers"}},
+               // make bootstrap sources 2 test secrets in the default 
namespace, select the first one and print all values
+               "interactive":                       {args: []string{"--all"}, 
feedkeys: "\r", want: `key1='value1'\nkey2='value2'`},
+               "interactive custom ns (no secret)": {args: 
[]string{"--namespace", "empty"}, wantErr: ErrNoSecretFound},
+               "invalid arg count":                 {args: []string{"a", "b", 
"c"}, wantErr: errors.New("accepts between 0 and 2 arg(s), received 3")},
+               "quiet":                             {args: []string{"test2", 
"--quiet"}, want: `value1`},
+               "unknown flag":                      {args: 
[]string{"--version"}, wantErr: errors.New("unknown flag: --version")},
+       }
+
+       for name, tt := range tests {
+               t.Run(name, func(t *testing.T) {
+                       t.Parallel()
+
+                       cmd := NewCmdViewSecret()
+                       outBuf := bytes.NewBufferString("")
+                       readBuf := &strings.Reader{}
+                       if tt.feedkeys != "" {
+                               readBuf = strings.NewReader(tt.feedkeys)
+                       }
 
+                       cmd.SetOut(outBuf)
+                       cmd.SetIn(readBuf)
+                       cmd.SetArgs(tt.args)
+
+                       err := cmd.Execute()
+                       if err != nil {
+                               if tt.wantErr == nil {
+                                       assert.Fail(t, "unexpected error", err)
+                               } else if err.Error() != tt.wantErr.Error() {
+                                       assert.Equal(t, tt.wantErr, err)
+                               }
+                               return
+                       } else if tt.wantErr != nil {
+                               assert.Fail(t, "expected error, got nil", 
tt.wantErr)
+                               return
+                       }
+
+                       _, err = io.ReadAll(outBuf)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+               })
+       }
+}
+
+func TestProcessSecret(t *testing.T) {
        tests := map[string]struct {
-               secretData map[string]interface{}
+               secretData SecretData
                wantStdOut []string
                wantStdErr []string
                secretKey  string
                decodeAll  bool
                err        error
+               feedkeys   string
        }{
                "view-secret <secret>": {
                        secret,
-                       []string{"-> TEST_CONN_STR", "-> TEST_PASSWORD", "-> 
TEST_PASSWORD_2"},
-                       []string{listDescription},
+                       []string{
+                               
"TEST_CONN_STR='mongodb://myDBReader:d1fficultp%40ssw...@mongodb0.example.com:27017/?authSource=admin'",
+                               "TEST_PASSWORD='secret'",
+                               "TEST_PASSWORD_2='verysecret'",
+                       },
+                       []string{},
                        "",
                        false,
                        nil,
+                       "\r", // selects 'all' as it's the default selection
                },
                "view-secret <secret-single-key>": {
                        secretSingle,
@@ -84,8 +138,9 @@
                        "",
                        false,
                        nil,
+                       "",
                },
-               "view-secret test TEST_PASSWORD": {secret, []string{"secret"}, 
nil, "TEST_PASSWORD", false, nil},
+               "view-secret test TEST_PASSWORD": {secret, []string{"secret"}, 
nil, "TEST_PASSWORD", false, nil, ""},
                "view-secret test -a": {
                        secret,
                        []string{
@@ -97,40 +152,42 @@
                        "",
                        true,
                        nil,
+                       "",
                },
-               "view-secret test NONE":      {secret, nil, nil, "NONE", false, 
ErrSecretKeyNotFound},
-               "view-secret <secret-empty>": {secretEmpty, nil, nil, "", 
false, ErrSecretEmpty},
+               "view-secret test NONE":      {secret, nil, nil, "NONE", false, 
ErrSecretKeyNotFound, ""},
+               "view-secret <secret-empty>": {secretEmpty, nil, nil, "", 
false, ErrSecretEmpty, ""},
        }
 
        for name, test := range tests {
                t.Run(name, func(t *testing.T) {
-                       gotStdOut := bytes.Buffer{}
-                       gotStdErr := bytes.Buffer{}
-                       err := ProcessSecret(&gotStdOut, &gotStdErr, 
test.secretData, test.secretKey, test.decodeAll)
+                       t.Parallel()
+
+                       stdOutBuf := bytes.Buffer{}
+                       stdErrBuf := bytes.Buffer{}
+                       readBuf := strings.Reader{}
+
+                       if test.feedkeys != "" {
+                               readBuf = *strings.NewReader(test.feedkeys)
+                       }
+
+                       err := ProcessSecret(&stdOutBuf, &stdErrBuf, &readBuf, 
Secret{Data: test.secretData}, test.secretKey, test.decodeAll)
 
                        if test.err != nil {
                                assert.Equal(t, err, test.err)
                        } else {
-                               var gotStdOutArr, gotStdErrArr []string
-                               scanner := 
bufio.NewScanner(strings.NewReader(gotStdOut.String()))
-                               for scanner.Scan() {
-                                       gotStdOutArr = append(gotStdOutArr, 
scanner.Text())
-                               }
-
-                               scanner = 
bufio.NewScanner(strings.NewReader(gotStdErr.String()))
-                               for scanner.Scan() {
-                                       gotStdErrArr = append(gotStdErrArr, 
scanner.Text())
-                               }
-
-                               sort.Strings(gotStdOutArr)
-                               sort.Strings(gotStdErrArr)
+                               gotStdOut := stdOutBuf.String()
+                               gotStdErr := stdErrBuf.String()
 
-                               if !reflect.DeepEqual(gotStdOutArr, 
test.wantStdOut) {
-                                       t.Errorf("got %v, want %v", 
gotStdOutArr, test.wantStdOut)
+                               for _, s := range test.wantStdOut {
+                                       if !assert.Contains(t, gotStdOut, s) {
+                                               t.Errorf("got %v, want %v", 
gotStdOut, s)
+                                       }
                                }
 
-                               if !reflect.DeepEqual(gotStdErrArr, 
test.wantStdErr) {
-                                       t.Errorf("got %v, want %v", 
gotStdErrArr, test.wantStdErr)
+                               for _, s := range test.wantStdErr {
+                                       if !assert.Contains(t, gotStdErr, s) {
+                                               t.Errorf("got %v, want %v", 
gotStdErr, s)
+                                       }
                                }
                        }
                })

++++++ kubectl-view-secret.obsinfo ++++++
--- /var/tmp/diff_new_pack.YZuwSe/_old  2024-08-17 12:42:00.861432768 +0200
+++ /var/tmp/diff_new_pack.YZuwSe/_new  2024-08-17 12:42:00.865432935 +0200
@@ -1,5 +1,5 @@
 name: kubectl-view-secret
-version: 0.12.1
-mtime: 1722572760
-commit: 122b2e639fd48b6bd2655957e82c539d83ced5df
+version: 0.13.0
+mtime: 1723665948
+commit: 9599a2e2e9bf4ecc14d6b4fb52230c10195ecb4e
 

++++++ vendor.tar.gz ++++++
++++ 302658 lines of diff (skipped)

Reply via email to