7 Commits

Author SHA1 Message Date
justin0u0
013b6bc252 fix(kubectx): use the env variable for kubectl (#438) 2025-01-22 09:07:57 -08:00
Antoine
0bcd0d5dd5 fix some ci enhancement (#435)
* fix(release): customize goreleaser config file, by adding json schema and fixing configuration version

* fix(go): rename invalid comment format

* fix(ci): made release workflow work again

replace goreleaser --rm-dist flag by --clean
increment go version for release pipeline
fetch previous tags use by goreleaser
give release workflow content write permissions to publish release
2025-01-07 12:25:01 -08:00
Suleiman Dibirov
561793c356 chore: upgrade Go version to 1.22 (#425) 2024-07-10 14:25:37 -07:00
Suleiman Dibirov
b5daf2cef7 feat(kubens): added force flag to switch namespaces even if it doesn'… (#416)
* feat(kubens): added force flag to switch namespaces even if it doesn't exist

* Merged lines

* fixed README.md and flags.go

* updated flags.go, flags_test.go
2024-07-09 21:38:40 -07:00
pullmerge
4997a261dc Fix some comments (#418) 2024-04-15 09:31:07 -07:00
Marcos Alano
8fb8c9f2f2 Add support to publish Snaps using goreleaser (#353)
Closes #351.
2023-12-25 00:28:51 -08:00
Nabil
11c19c0fb7 Add Scoop command (#396) 2023-08-04 15:04:50 -07:00
16 changed files with 136 additions and 30 deletions

View File

@@ -25,7 +25,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: '1.20'
go-version: '1.22'
- id: go-cache-paths
run: |
echo "::set-output name=go-build::$(go env GOCACHE)"
@@ -50,7 +50,7 @@ jobs:
uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: release --snapshot --skip-publish --rm-dist
args: release --snapshot --skip publish,snapcraft --clean
- name: Setup BATS framework
run: sudo npm install -g bats
- name: kubectx (Go) integration tests

View File

@@ -19,19 +19,29 @@ on:
- 'v*.*.*'
jobs:
goreleaser:
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
- run: git fetch --tags
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: '1.20'
go-version: '1.22'
- name: Install Snapcraft
uses: samuelmeuli/action-snapcraft@v1
- name: Setup Snapcraft
run: |
# https://github.com/goreleaser/goreleaser/issues/1715
mkdir -p $HOME/.cache/snapcraft/download
mkdir -p $HOME/.cache/snapcraft/stage-packages
- name: GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: release --rm-dist
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update new version for plugin 'ctx' in krew-index
@@ -42,3 +52,7 @@ jobs:
uses: rajatjindal/krew-release-bot@v0.0.38
with:
krew_template_file: .krew/ns.yaml
- name: Publish Snaps to the Snap Store (stable channel)
run: for snap in $(ls dist/*.snap); do snapcraft upload --release=stable $snap; done
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_TOKEN }}

View File

@@ -1,3 +1,5 @@
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,6 +16,8 @@
# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
version: 2
before:
hooks:
- go mod download
@@ -98,3 +102,20 @@ release:
extra_files:
- glob: ./kubens
- glob: ./kubectx
snapcrafts:
- id: kubectx
name: kubectx
summary: 'kubectx + kubens: Power tools for kubectl'
description: |
kubectx is a tool to switch between contexts (clusters) on kubectl faster.
kubens is a tool to switch between Kubernetes namespaces (and configure them for kubectl) easily.
grade: stable
confinement: classic
base: core20
apps:
kubectx:
command: kubectx
completer: completion/kubectx.bash
kubens:
command: kubens
completer: completion/kubens.bash

View File

@@ -46,6 +46,15 @@ Active namespace is "kube-system".
$ kubens -
Context "test" set.
Active namespace is "default".
# change the active namespace even if it doesn't exist
$ kubens not-found-namespace --force
Context "test" set.
Active namespace is "not-found-namespace".
---
$ kubens not-found-namespace -f
Context "test" set.
Active namespace is "not-found-namespace".
```
If you have [`fzf`](https://github.com/junegunn/fzf) installed, you can also
@@ -77,6 +86,7 @@ this new Go implementation by downloading the binaries from the [**Releases page
- [with apt (Debian)](#apt-debian)
- [with pacman (Arch Linux)](#pacman-arch-linux)
- [with Chocolatey (Windows)](#windows-installation-using-chocolatey)
- [Windows Installation (using Scoop)](#windows-installation-using-scoop)
- [with winget (Windows)](#windows-installation-using-winget)
- [manually (macOS & Linux)](#manual-installation-macos-and-linux)
@@ -148,6 +158,14 @@ Available as packages on [Chocolatey](https://chocolatey.org/why-chocolatey)
choco install kubens kubectx
```
### Windows Installation (using Scoop)
Available as packages on [Scoop](https://scoop.sh/)
```pwsh
scoop bucket add main
scoop install main/kubens main/kubectx
```
### Windows Installation (using winget)
Available as packages on [winget](https://learn.microsoft.com/en-us/windows/package-manager/)

View File

@@ -31,7 +31,7 @@ type DeleteOp struct {
// deleteContexts deletes context entries one by one.
func (op DeleteOp) Run(_, stderr io.Writer) error {
for _, ctx := range op.Contexts {
// TODO inefficency here. we open/write/close the same file many times.
// TODO inefficiency here. we open/write/close the same file many times.
deletedName, wasActiveContext, err := deleteContext(ctx)
if err != nil {
return errors.Wrapf(err, "error deleting context \"%s\"", deletedName)

View File

@@ -11,7 +11,7 @@ var (
version = "v0.0.0+unknown" // populated by goreleaser
)
// VersionOps describes printing version string.
// VersionOp describes printing version string.
type VersionOp struct{}
func (_ VersionOp) Run(stdout, _ io.Writer) error {

View File

@@ -18,6 +18,7 @@ import (
"fmt"
"io"
"os"
"slices"
"strings"
"github.com/ahmetb/kubectx/internal/cmdutil"
@@ -33,28 +34,51 @@ func (op UnsupportedOp) Run(_, _ io.Writer) error {
// parseArgs looks at flags (excl. executable name, i.e. argv[0])
// and decides which operation should be taken.
func parseArgs(argv []string) Op {
if len(argv) == 0 {
n := len(argv)
if n == 0 {
if cmdutil.IsInteractiveMode(os.Stdout) {
return InteractiveSwitchOp{SelfCmd: os.Args[0]}
}
return ListOp{}
}
if len(argv) == 1 {
if n == 1 {
v := argv[0]
if v == "--help" || v == "-h" {
switch v {
case "--help", "-h":
return HelpOp{}
}
if v == "--version" || v == "-V" {
case "--version", "-V":
return VersionOp{}
}
if v == "--current" || v == "-c" {
case "--current", "-c":
return CurrentOp{}
default:
return getSwitchOp(v, false)
}
if strings.HasPrefix(v, "-") && v != "-" {
return UnsupportedOp{Err: fmt.Errorf("unsupported option '%s'", v)}
} else if n == 2 {
// {namespace} -f|--force
name := argv[0]
force := slices.Contains([]string{"-f", "--force"}, argv[1])
if !force {
if !slices.Contains([]string{"-f", "--force"}, argv[0]) {
return UnsupportedOp{Err: fmt.Errorf("unsupported arguments %q", argv)}
}
// -f|--force {namespace}
force = true
name = argv[1]
}
return SwitchOp{Target: argv[0]}
return getSwitchOp(name, force)
}
return UnsupportedOp{Err: fmt.Errorf("too many arguments")}
}
func getSwitchOp(v string, force bool) Op {
if strings.HasPrefix(v, "-") && v != "-" {
return UnsupportedOp{Err: fmt.Errorf("unsupported option %q", v)}
}
return SwitchOp{Target: v, Force: force}
}

View File

@@ -48,12 +48,30 @@ func Test_parseArgs_new(t *testing.T) {
{name: "switch by name",
args: []string{"foo"},
want: SwitchOp{Target: "foo"}},
{name: "switch by name force short flag",
args: []string{"foo", "-f"},
want: SwitchOp{Target: "foo", Force: true}},
{name: "switch by name force long flag",
args: []string{"foo", "--force"},
want: SwitchOp{Target: "foo", Force: true}},
{name: "switch by name force short flag before name",
args: []string{"-f", "foo"},
want: SwitchOp{Target: "foo", Force: true}},
{name: "switch by name force long flag before name",
args: []string{"--force", "foo"},
want: SwitchOp{Target: "foo", Force: true}},
{name: "switch by name unknown arguments",
args: []string{"foo", "-x"},
want: UnsupportedOp{Err: fmt.Errorf("unsupported arguments %q", []string{"foo", "-x"})}},
{name: "switch by name unknown arguments",
args: []string{"-x", "foo"},
want: UnsupportedOp{Err: fmt.Errorf("unsupported arguments %q", []string{"-x", "foo"})}},
{name: "switch by swap",
args: []string{"-"},
want: SwitchOp{Target: "-"}},
{name: "unrecognized flag",
args: []string{"-x"},
want: UnsupportedOp{Err: fmt.Errorf("unsupported option '-x'")}},
want: UnsupportedOp{Err: fmt.Errorf("unsupported option %q", "-x")}},
{name: "too many args",
args: []string{"a", "b", "c"},
want: UnsupportedOp{Err: fmt.Errorf("too many arguments")}},

View File

@@ -65,7 +65,7 @@ func (op InteractiveSwitchOp) Run(_, stderr io.Writer) error {
if choice == "" {
return errors.New("you did not choose any of the options")
}
name, err := switchNamespace(kc, choice)
name, err := switchNamespace(kc, choice, false)
if err != nil {
return errors.Wrap(err, "failed to switch namespace")
}

View File

@@ -35,6 +35,7 @@ func printUsage(out io.Writer) error {
help := `USAGE:
%PROG% : list the namespaces in the current context
%PROG% <NAME> : change the active namespace of current context
%PROG% <NAME> --force/-f : force change the active namespace of current context (even if it doesn't exist)
%PROG% - : switch to the previous namespace in this context
%PROG% -c, --current : show the current namespace
%PROG% -h,--help : show this message

View File

@@ -29,6 +29,7 @@ import (
type SwitchOp struct {
Target string // '-' for back and forth, or NAME
Force bool // force switch even if the namespace doesn't exist
}
func (s SwitchOp) Run(_, stderr io.Writer) error {
@@ -38,7 +39,7 @@ func (s SwitchOp) Run(_, stderr io.Writer) error {
return errors.Wrap(err, "kubeconfig error")
}
toNS, err := switchNamespace(kc, s.Target)
toNS, err := switchNamespace(kc, s.Target, s.Force)
if err != nil {
return err
}
@@ -46,7 +47,7 @@ func (s SwitchOp) Run(_, stderr io.Writer) error {
return err
}
func switchNamespace(kc *kubeconfig.Kubeconfig, ns string) (string, error) {
func switchNamespace(kc *kubeconfig.Kubeconfig, ns string, force bool) (string, error) {
ctx := kc.GetCurrentContext()
if ctx == "" {
return "", errors.New("current-context is not set")
@@ -69,12 +70,14 @@ func switchNamespace(kc *kubeconfig.Kubeconfig, ns string) (string, error) {
ns = prev
}
ok, err := namespaceExists(kc, ns)
if err != nil {
return "", errors.Wrap(err, "failed to query if namespace exists (is cluster accessible?)")
}
if !ok {
return "", errors.Errorf("no namespace exists with name \"%s\"", ns)
if !force {
ok, err := namespaceExists(kc, ns)
if err != nil {
return "", errors.Wrap(err, "failed to query if namespace exists (is cluster accessible?)")
}
if !ok {
return "", errors.Errorf("no namespace exists with name \"%s\"", ns)
}
}
if err := kc.SetNamespace(ctx, ns); err != nil {

View File

@@ -11,7 +11,7 @@ var (
version = "v0.0.0+unknown" // populated by goreleaser
)
// VersionOps describes printing version string.
// VersionOp describes printing version string.
type VersionOp struct{}
func (_ VersionOp) Run(stdout, _ io.Writer) error {

2
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/ahmetb/kubectx
go 1.20
go 1.22
require (
facette.io/natsort v0.0.0-20181210072756-2cd4dd1e2dcb

7
go.sum
View File

@@ -67,6 +67,7 @@ github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -124,6 +125,7 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -146,6 +148,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -166,7 +169,9 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk=
github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -174,6 +179,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
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/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
@@ -369,6 +375,7 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -19,7 +19,7 @@ const (
// interactive context selection when fzf is installed.
EnvFZFIgnore = "KUBECTX_IGNORE_FZF"
// EnvForceColor describes the environment variable to disable color usage
// EnvNoColor describes the environment variable to disable color usage
// when printing current context in a list.
EnvNoColor = `NO_COLOR`

View File

@@ -227,7 +227,7 @@ main() {
# we don't call current_context here for two reasons:
# - it does not fail when current-context property is not set
# - it does not return a trailing newline
kubectl config current-context
$KUBECTL config current-context
elif [[ "${1}" == '-u' || "${1}" == '--unset' ]]; then
unset_context
elif [[ "${1}" == '-h' || "${1}" == '--help' ]]; then