Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Open sidebar
Ijaz Ahmad
ksonnet
Commits
bd322a52
Unverified
Commit
bd322a52
authored
Apr 07, 2018
by
Bryan Liles
Committed by
GitHub
Apr 07, 2018
Browse files
Merge pull request #424 from bryanl/set-current-environment
Add `ks env current` command
parents
e13aee65
d0b9028b
Changes
33
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
512 additions
and
159 deletions
+512
-159
actions/actions.go
actions/actions.go
+4
-2
actions/apply.go
actions/apply.go
+8
-1
actions/apply_test.go
actions/apply_test.go
+62
-32
actions/current_environment.go
actions/current_environment.go
+40
-0
actions/delete.go
actions/delete.go
+8
-1
actions/delete_test.go
actions/delete_test.go
+56
-26
actions/env_current.go
actions/env_current.go
+78
-0
actions/env_current_test.go
actions/env_current_test.go
+97
-0
actions/env_list.go
actions/env_list.go
+1
-1
actions/env_list_test.go
actions/env_list_test.go
+1
-1
actions/show.go
actions/show.go
+8
-1
actions/show_test.go
actions/show_test.go
+55
-25
actions/validate.go
actions/validate.go
+8
-1
actions/validate_test.go
actions/validate_test.go
+71
-42
cmd/actions.go
cmd/actions.go
+2
-0
cmd/apply.go
cmd/apply.go
+4
-5
cmd/apply_test.go
cmd/apply_test.go
+0
-6
cmd/delete.go
cmd/delete.go
+4
-5
cmd/delete_test.go
cmd/delete_test.go
+0
-6
cmd/env.go
cmd/env.go
+5
-4
No files found.
actions/actions.go
View file @
bd322a52
...
...
@@ -86,6 +86,8 @@ const (
OptionSkipGc
=
"skip-gc"
// OptionSpecFlag is specFlag option. Used for setting k8s spec.
OptionSpecFlag
=
"spec-flag"
// OptionUnset is unset option.
OptionUnset
=
"unset"
// OptionURI is uri option. Used for setting registry URI.
OptionURI
=
"URI"
// OptionValue is value option.
...
...
@@ -97,8 +99,8 @@ const (
const
(
// OutputWide is wide output
OutputWide
=
"wide"
//
EnvList
OutputJSON is JSON output
EnvList
OutputJSON
=
"json"
// OutputJSON is JSON output
OutputJSON
=
"json"
)
var
(
...
...
actions/apply.go
View file @
bd322a52
...
...
@@ -59,7 +59,6 @@ func newApply(m map[string]interface{}, opts ...applyOpt) (*Apply, error) {
componentNames
:
ol
.
loadStringSlice
(
OptionComponentNames
),
create
:
ol
.
loadBool
(
OptionCreate
),
dryRun
:
ol
.
loadBool
(
OptionDryRun
),
envName
:
ol
.
loadString
(
OptionEnvName
),
gcTag
:
ol
.
loadString
(
OptionGcTag
),
skipGc
:
ol
.
loadBool
(
OptionSkipGc
),
...
...
@@ -74,6 +73,10 @@ func newApply(m map[string]interface{}, opts ...applyOpt) (*Apply, error) {
opt
(
a
)
}
if
err
:=
setCurrentEnv
(
a
.
app
,
a
,
ol
);
err
!=
nil
{
return
nil
,
err
}
return
a
,
nil
}
...
...
@@ -91,3 +94,7 @@ func (a *Apply) run() error {
return
a
.
runApplyFn
(
config
)
}
func
(
a
*
Apply
)
setCurrentEnv
(
name
string
)
{
a
.
envName
=
name
}
actions/apply_test.go
View file @
bd322a52
...
...
@@ -26,42 +26,72 @@ import (
)
func
TestApply
(
t
*
testing
.
T
)
{
withApp
(
t
,
func
(
appMock
*
amocks
.
App
)
{
in
:=
map
[
string
]
interface
{}{
OptionApp
:
appMock
,
OptionClientConfig
:
&
client
.
Config
{},
OptionComponentNames
:
[]
string
{},
OptionCreate
:
true
,
OptionDryRun
:
true
,
OptionEnvName
:
"default"
,
OptionGcTag
:
"gc-tag"
,
OptionSkipGc
:
true
,
}
cases
:=
[]
struct
{
name
string
isSetupErr
bool
currentName
string
envName
string
}{
{
name
:
"with a supplied env"
,
envName
:
"default"
,
},
{
name
:
"with a current env"
,
currentName
:
"default"
,
},
{
name
:
"without supplied or current env"
,
isSetupErr
:
true
,
},
}
expected
:=
cluster
.
ApplyConfig
{
App
:
appMock
,
ClientConfig
:
&
client
.
Config
{},
ComponentNames
:
[]
string
{},
Create
:
true
,
DryRun
:
true
,
EnvName
:
"default"
,
GcTag
:
"gc-tag"
,
SkipGc
:
true
,
}
for
_
,
tc
:=
range
cases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
withApp
(
t
,
func
(
appMock
*
amocks
.
App
)
{
appMock
.
On
(
"CurrentEnvironment"
)
.
Return
(
tc
.
currentName
)
runApplyOpt
:=
func
(
a
*
Apply
)
{
a
.
runApplyFn
=
func
(
config
cluster
.
ApplyConfig
,
opts
...
cluster
.
ApplyOpts
)
error
{
assert
.
Equal
(
t
,
expected
,
config
)
return
nil
}
}
in
:=
map
[
string
]
interface
{}{
OptionApp
:
appMock
,
OptionClientConfig
:
&
client
.
Config
{},
OptionComponentNames
:
[]
string
{},
OptionCreate
:
true
,
OptionDryRun
:
true
,
OptionEnvName
:
tc
.
envName
,
OptionGcTag
:
"gc-tag"
,
OptionSkipGc
:
true
,
}
a
,
err
:=
newApply
(
in
,
runApplyOpt
)
require
.
NoError
(
t
,
err
)
expected
:=
cluster
.
ApplyConfig
{
App
:
appMock
,
ClientConfig
:
&
client
.
Config
{},
ComponentNames
:
[]
string
{},
Create
:
true
,
DryRun
:
true
,
EnvName
:
"default"
,
GcTag
:
"gc-tag"
,
SkipGc
:
true
,
}
err
=
a
.
run
()
require
.
NoError
(
t
,
err
)
})
runApplyOpt
:=
func
(
a
*
Apply
)
{
a
.
runApplyFn
=
func
(
config
cluster
.
ApplyConfig
,
opts
...
cluster
.
ApplyOpts
)
error
{
assert
.
Equal
(
t
,
expected
,
config
)
return
nil
}
}
a
,
err
:=
newApply
(
in
,
runApplyOpt
)
if
tc
.
isSetupErr
{
require
.
Error
(
t
,
err
)
return
}
require
.
NoError
(
t
,
err
)
err
=
a
.
run
()
require
.
NoError
(
t
,
err
)
})
})
}
}
func
TestApply_invalid_input
(
t
*
testing
.
T
)
{
...
...
actions/current_environment.go
0 → 100644
View file @
bd322a52
// Copyright 2018 The ksonnet 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
actions
import
"github.com/pkg/errors"
type
environmentMetadata
interface
{
CurrentEnvironment
()
string
}
type
currentEnver
interface
{
setCurrentEnv
(
name
string
)
}
func
setCurrentEnv
(
em
environmentMetadata
,
ce
currentEnver
,
ol
*
optionLoader
)
error
{
envName
:=
ol
.
loadOptionalString
(
OptionEnvName
)
if
envName
==
""
{
envName
=
em
.
CurrentEnvironment
()
}
if
envName
==
""
{
return
errors
.
Errorf
(
"environment is not set; use `env list` to see available environments"
)
}
ce
.
setCurrentEnv
(
envName
)
return
nil
}
actions/delete.go
View file @
bd322a52
...
...
@@ -54,7 +54,6 @@ func newDelete(m map[string]interface{}, opts ...deleteOpt) (*Delete, error) {
app
:
ol
.
loadApp
(),
clientConfig
:
ol
.
loadClientConfig
(),
componentNames
:
ol
.
loadStringSlice
(
OptionComponentNames
),
envName
:
ol
.
loadString
(
OptionEnvName
),
gracePeriod
:
ol
.
loadInt64
(
OptionGracePeriod
),
runDeleteFn
:
cluster
.
RunDelete
,
...
...
@@ -68,6 +67,10 @@ func newDelete(m map[string]interface{}, opts ...deleteOpt) (*Delete, error) {
opt
(
d
)
}
if
err
:=
setCurrentEnv
(
d
.
app
,
d
,
ol
);
err
!=
nil
{
return
nil
,
err
}
return
d
,
nil
}
...
...
@@ -82,3 +85,7 @@ func (d *Delete) run() error {
return
d
.
runDeleteFn
(
config
)
}
func
(
d
*
Delete
)
setCurrentEnv
(
name
string
)
{
d
.
envName
=
name
}
actions/delete_test.go
View file @
bd322a52
...
...
@@ -26,36 +26,66 @@ import (
)
func
TestDelete
(
t
*
testing
.
T
)
{
withApp
(
t
,
func
(
appMock
*
amocks
.
App
)
{
in
:=
map
[
string
]
interface
{}{
OptionApp
:
appMock
,
OptionClientConfig
:
&
client
.
Config
{},
OptionComponentNames
:
[]
string
{},
OptionEnvName
:
"default"
,
OptionGracePeriod
:
int64
(
3
),
}
cases
:=
[]
struct
{
name
string
isSetupErr
bool
currentName
string
envName
string
}{
{
name
:
"with a supplied env"
,
envName
:
"default"
,
},
{
name
:
"with a current env"
,
currentName
:
"default"
,
},
{
name
:
"without supplied or current env"
,
isSetupErr
:
true
,
},
}
expected
:=
cluster
.
DeleteConfig
{
App
:
appMock
,
ClientConfig
:
&
client
.
Config
{},
ComponentNames
:
[]
string
{},
EnvName
:
"default"
,
GracePeriod
:
3
,
}
for
_
,
tc
:=
range
cases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
withApp
(
t
,
func
(
appMock
*
amocks
.
App
)
{
appMock
.
On
(
"CurrentEnvironment"
)
.
Return
(
tc
.
currentName
)
runDeleteOpt
:=
func
(
a
*
Delete
)
{
a
.
runDeleteFn
=
func
(
config
cluster
.
DeleteConfig
,
opts
...
cluster
.
DeleteOpts
)
error
{
assert
.
Equal
(
t
,
expected
,
config
)
return
nil
}
}
in
:=
map
[
string
]
interface
{}{
OptionApp
:
appMock
,
OptionClientConfig
:
&
client
.
Config
{},
OptionComponentNames
:
[]
string
{},
OptionEnvName
:
tc
.
envName
,
OptionGracePeriod
:
int64
(
3
),
}
a
,
err
:=
newDelete
(
in
,
runDeleteOpt
)
require
.
NoError
(
t
,
err
)
expected
:=
cluster
.
DeleteConfig
{
App
:
appMock
,
ClientConfig
:
&
client
.
Config
{},
ComponentNames
:
[]
string
{},
EnvName
:
"default"
,
GracePeriod
:
3
,
}
err
=
a
.
run
()
require
.
NoError
(
t
,
err
)
})
runDeleteOpt
:=
func
(
a
*
Delete
)
{
a
.
runDeleteFn
=
func
(
config
cluster
.
DeleteConfig
,
opts
...
cluster
.
DeleteOpts
)
error
{
assert
.
Equal
(
t
,
expected
,
config
)
return
nil
}
}
a
,
err
:=
newDelete
(
in
,
runDeleteOpt
)
if
tc
.
isSetupErr
{
require
.
Error
(
t
,
err
)
return
}
require
.
NoError
(
t
,
err
)
err
=
a
.
run
()
require
.
NoError
(
t
,
err
)
})
})
}
}
func
TestDelete_invalid_input
(
t
*
testing
.
T
)
{
...
...
actions/env_current.go
0 → 100644
View file @
bd322a52
// Copyright 2018 The ksonnet 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
actions
import
(
"fmt"
"io"
"os"
"github.com/ksonnet/ksonnet/metadata/app"
"github.com/pkg/errors"
)
// RunEnvCurrent runs `env current`.
func
RunEnvCurrent
(
m
map
[
string
]
interface
{})
error
{
a
,
err
:=
newEnvCurrent
(
m
)
if
err
!=
nil
{
return
err
}
return
a
.
run
()
}
// EnvCurrent sets/unsets the current environment
type
EnvCurrent
struct
{
app
app
.
App
envName
string
unset
bool
out
io
.
Writer
}
// RunEnvCurrent runs `env current`
func
newEnvCurrent
(
m
map
[
string
]
interface
{})
(
*
EnvCurrent
,
error
)
{
ol
:=
newOptionLoader
(
m
)
d
:=
&
EnvCurrent
{
app
:
ol
.
loadApp
(),
envName
:
ol
.
loadOptionalString
(
OptionEnvName
),
unset
:
ol
.
loadBool
(
OptionUnset
),
out
:
os
.
Stdout
,
}
if
ol
.
err
!=
nil
{
return
nil
,
ol
.
err
}
return
d
,
nil
}
func
(
e
*
EnvCurrent
)
run
()
error
{
if
e
.
envName
!=
""
&&
e
.
unset
==
true
{
return
errors
.
New
(
"set and unset are exclusive"
)
}
if
e
.
unset
{
return
e
.
app
.
SetCurrentEnvironment
(
""
)
}
else
if
e
.
envName
!=
""
{
return
e
.
app
.
SetCurrentEnvironment
(
e
.
envName
)
}
else
{
fmt
.
Fprintln
(
e
.
out
,
e
.
app
.
CurrentEnvironment
())
return
nil
}
}
actions/env_current_test.go
0 → 100644
View file @
bd322a52
// Copyright 2018 The ksonnet 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
actions
import
(
"bytes"
"testing"
amocks
"github.com/ksonnet/ksonnet/metadata/app/mocks"
"github.com/stretchr/testify/require"
)
func
TestEnvCurrent
(
t
*
testing
.
T
)
{
cases
:=
[]
struct
{
name
string
envName
string
currentName
string
unset
bool
output
string
isErr
bool
}{
{
name
:
"show current environment with no current environment"
,
},
{
name
:
"show current environment with current environment set"
,
currentName
:
"default"
,
output
:
"default"
,
},
{
name
:
"set current"
,
envName
:
"default"
,
},
{
name
:
"unset current"
,
unset
:
true
,
},
{
name
:
"error if set and unset together"
,
unset
:
true
,
envName
:
"default"
,
isErr
:
true
,
},
}
for
_
,
tc
:=
range
cases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
withApp
(
t
,
func
(
appMock
*
amocks
.
App
)
{
appMock
.
On
(
"CurrentEnvironment"
)
.
Return
(
tc
.
currentName
)
appMock
.
On
(
"SetCurrentEnvironment"
,
tc
.
envName
)
.
Return
(
nil
)
in
:=
map
[
string
]
interface
{}{
OptionApp
:
appMock
,
OptionEnvName
:
tc
.
envName
,
OptionUnset
:
tc
.
unset
,
}
a
,
err
:=
newEnvCurrent
(
in
)
require
.
NoError
(
t
,
err
)
var
buf
bytes
.
Buffer
a
.
out
=
&
buf
err
=
a
.
run
()
if
tc
.
isErr
{
require
.
Error
(
t
,
err
)
return
}
require
.
NoError
(
t
,
err
)
})
})
}
}
func
TestEnvCurrent_invalid_input
(
t
*
testing
.
T
)
{
withApp
(
t
,
func
(
appMock
*
amocks
.
App
)
{
in
:=
map
[
string
]
interface
{}{
OptionApp
:
"invalid"
,
}
_
,
err
:=
newEnvCurrent
(
in
)
require
.
Error
(
t
,
err
)
})
}
actions/env_list.go
View file @
bd322a52
...
...
@@ -72,7 +72,7 @@ func (el *EnvList) Run() error {
return
errors
.
Errorf
(
"unknown output format %q"
,
el
.
outputType
)
case
OutputWide
:
return
el
.
outputWide
()
case
EnvList
OutputJSON
:
case
OutputJSON
:
return
el
.
outputJSON
()
}
}
...
...
actions/env_list_test.go
View file @
bd322a52
...
...
@@ -59,7 +59,7 @@ func TestEnvList(t *testing.T) {
},
{
name
:
"json output"
,
outputType
:
EnvList
OutputJSON
,
outputType
:
OutputJSON
,
expectedFile
:
filepath
.
Join
(
"env"
,
"list"
,
"output.json"
),
},
{
...
...
actions/show.go
View file @
bd322a52
...
...
@@ -57,7 +57,6 @@ func newShow(m map[string]interface{}, opts ...showOpt) (*Show, error) {
s
:=
&
Show
{
app
:
ol
.
loadApp
(),
componentNames
:
ol
.
loadStringSlice
(
OptionComponentNames
),
envName
:
ol
.
loadString
(
OptionEnvName
),
format
:
ol
.
loadString
(
OptionFormat
),
out
:
os
.
Stdout
,
...
...
@@ -72,6 +71,10 @@ func newShow(m map[string]interface{}, opts ...showOpt) (*Show, error) {
opt
(
s
)
}
if
err
:=
setCurrentEnv
(
s
.
app
,
s
,
ol
);
err
!=
nil
{
return
nil
,
err
}
return
s
,
nil
}
...
...
@@ -86,3 +89,7 @@ func (s *Show) run() error {
return
s
.
runShowFn
(
config
)
}
func
(
s
*
Show
)
setCurrentEnv
(
name
string
)
{
s
.
envName
=
name
}
actions/show_test.go
View file @
bd322a52
...
...
@@ -26,35 +26,65 @@ import (
)
func
TestShow
(
t
*
testing
.
T
)
{
withApp
(
t
,
func
(
appMock
*
amocks
.
App
)
{
in
:=
map
[
string
]
interface
{}{
OptionApp
:
appMock
,
OptionComponentNames
:
[]
string
{},
OptionEnvName
:
"default"
,
OptionFormat
:
"yaml"
,
}
cases
:=
[]
struct
{
name
string
isSetupErr
bool
currentName
string
envName
string
}{
{
name
:
"with a supplied env"
,
envName
:
"default"
,
},
{
name
:
"with a current env"
,
currentName
:
"default"
,
},
{
name
:
"without supplied or current env"
,
isSetupErr
:
true
,
},
}
expected
:=
cluster
.
ShowConfig
{
App
:
appMock
,
ComponentNames
:
[]
string
{},
EnvName
:
"default"
,
Format
:
"yaml"
,
Out
:
os
.
Stdout
,
}
for
_
,
tc
:=
range
cases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
withApp
(
t
,
func
(
appMock
*
amocks
.
App
)
{
appMock
.
On
(
"CurrentEnvironment"
)
.
Return
(
tc
.
currentName
)
runShowOpt
:=
func
(
a
*
Show
)
{
a
.
runShowFn
=
func
(
config
cluster
.
ShowConfig
,
opts
...
cluster
.
ShowOpts
)
error
{
assert
.
Equal
(
t
,
expected
,
config
)
return
nil
}
}
in
:=
map
[
string
]
interface
{}
{
OptionApp
:
appMock
,
OptionComponentNames
:
[]
string
{},
OptionEnvName
:
tc
.
envName
,
OptionFormat
:
"yaml"
,
}
a
,
err
:=
newShow
(
in
,
runShowOpt
)
require
.
NoError
(
t
,
err
)
expected
:=
cluster
.
ShowConfig
{
App
:
appMock
,
ComponentNames
:
[]
string
{},
EnvName
:
"default"
,
Format
:
"yaml"
,
Out
:
os
.
Stdout
,
}
err
=
a
.
run
()
require
.
NoError
(
t
,
err
)
})
runShowOpt
:=
func
(
a
*
Show
)
{
a
.
runShowFn
=
func
(
config
cluster
.
ShowConfig
,
opts
...
cluster
.
ShowOpts
)
error
{
assert
.
Equal
(
t
,
expected
,
config
)
return
nil
}
}
a
,
err
:=
newShow
(
in
,
runShowOpt
)
if
tc
.
isSetupErr
{
require
.
Error
(
t
,
err
)
return
}
require
.
NoError
(
t
,