Skip to content

Commit

Permalink
feat: support release unlock command
Browse files Browse the repository at this point in the history
  • Loading branch information
liu-hm19 committed Jun 28, 2024
1 parent 55e7e7a commit 2eadd91
Show file tree
Hide file tree
Showing 7 changed files with 403 additions and 1 deletion.
7 changes: 7 additions & 0 deletions pkg/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"kusionstack.io/kusion/pkg/cmd/mod"
"kusionstack.io/kusion/pkg/cmd/preview"
"kusionstack.io/kusion/pkg/cmd/project"
rel "kusionstack.io/kusion/pkg/cmd/release"
"kusionstack.io/kusion/pkg/cmd/stack"
"kusionstack.io/kusion/pkg/cmd/version"
"kusionstack.io/kusion/pkg/cmd/workspace"
Expand Down Expand Up @@ -128,6 +129,12 @@ Find more information at: https://www.kusionstack.io`),
mod.NewCmdMod(o.IOStreams),
},
},
{
Message: "Release Management Commands:",
Commands: []*cobra.Command{
rel.NewCmdRel(o.IOStreams),
},
},
}
groups.Add(rootCmd)

Expand Down
29 changes: 29 additions & 0 deletions pkg/cmd/release/release.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package rel

import (
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericiooptions"
"k8s.io/kubectl/pkg/util/templates"
cmdutil "kusionstack.io/kusion/pkg/cmd/util"
"kusionstack.io/kusion/pkg/util/i18n"
)

var relLong = i18n.T(`
Commands for managing Kusion release files.
These commands help you manage the lifecycle of Kusion release files. `)

// NewCmdRel returns an initialized Command instance for 'release' sub command.
func NewCmdRel(streams genericiooptions.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "release",
DisableFlagsInUseLine: true,
Short: "Manage Kusion release files",
Long: templates.LongDesc(relLong),
Run: cmdutil.DefaultSubCommandRun(streams.ErrOut),
}

cmd.AddCommand(NewCmdUnlock(streams))

return cmd
}
17 changes: 17 additions & 0 deletions pkg/cmd/release/release_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package rel

import (
"testing"

"github.com/stretchr/testify/assert"
"k8s.io/cli-runtime/pkg/genericiooptions"
)

func TestNewCmdRel(t *testing.T) {
t.Run("successfully get release help", func(t *testing.T) {
streams, _, _, _ := genericiooptions.NewTestIOStreams()

cmd := NewCmdRel(streams)
assert.NotNil(t, cmd)
})
}
143 changes: 143 additions & 0 deletions pkg/cmd/release/unlock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package rel

import (
"fmt"

"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericiooptions"
"k8s.io/kubectl/pkg/util/templates"
v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1"
"kusionstack.io/kusion/pkg/cmd/meta"
cmdutil "kusionstack.io/kusion/pkg/cmd/util"
"kusionstack.io/kusion/pkg/engine/release"
"kusionstack.io/kusion/pkg/util/i18n"
)

var (
unlockShort = i18n.T("Unlock the latest release file of the current stack")

unlockLong = i18n.T(`
Unlock the latest release file of the current stack.
The phase of the latest release file of the current stack in the current or a specified workspace
will be set to 'failed' if it was in the stages of 'generating', 'previewing', 'applying' or 'destroying'.
Please note that using the 'kusion release unlock' command may cause unexpected concurrent read-write
issues with release files, so please use it with caution.
`)

unlockExample = i18n.T(`# Unlock the latest release file of the current stack in the current workspace.
kusion release unlock
# Unlock the latest release file of the current stack in a specified workspace.
kusion release unlock --workspace=dev
`)
)

// UnlockFlags reflects the information that CLI is gathering via flags,
// which will be converted into UnlockOptions.
type UnlockFlags struct {
MetaFlags *meta.MetaFlags
}

// UnlockOptions defines the configuration parameters for the `kusion release unlock` command.
type UnlockOptions struct {
*meta.MetaOptions
}

// NewUnlockFlags returns a default UnlockFlags.
func NewUnlockFlags(streams genericiooptions.IOStreams) *UnlockFlags {
return &UnlockFlags{
MetaFlags: meta.NewMetaFlags(),
}
}

// NewCmdUnlock creates the `kusion release unlock` command.
func NewCmdUnlock(streams genericiooptions.IOStreams) *cobra.Command {
flags := NewUnlockFlags(streams)

cmd := &cobra.Command{
Use: "unlock",
Short: unlockShort,
Long: templates.LongDesc(unlockLong),
Example: templates.Examples(unlockExample),
RunE: func(cmd *cobra.Command, args []string) (err error) {
o, err := flags.ToOptions()
defer cmdutil.RecoverErr(&err)
cmdutil.CheckErr(err)
cmdutil.CheckErr(o.Validate(cmd, args))
cmdutil.CheckErr(o.Run())

return
},
}

flags.AddFlags(cmd)

return cmd
}

// AddFlags registers flags for the CLI.
func (f *UnlockFlags) AddFlags(cmd *cobra.Command) {
f.MetaFlags.AddFlags(cmd)
}

// ToOptions converts from CLI inputs to runtime inputs.
func (f *UnlockFlags) ToOptions() (*UnlockOptions, error) {
metaOpts, err := f.MetaFlags.ToOptions()
if err != nil {
return nil, err
}

o := &UnlockOptions{
MetaOptions: metaOpts,
}

return o, nil
}

// Validate verifies if UnlockOptions are valid and without conflicts.
func (o *UnlockOptions) Validate(cmd *cobra.Command, args []string) error {
if len(args) != 0 {
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
}

return nil
}

// Run executes the `kusion release unlock` command.
func (o *UnlockOptions) Run() error {
// Get the storage backend of the release.
storage, err := o.Backend.ReleaseStorage(o.RefProject.Name, o.RefWorkspace.Name)
if err != nil {
return err
}

// Get the latest release.
r, err := release.GetLatestRelease(storage)
if err != nil {
return err
}
if r == nil {
fmt.Printf("No release file found for project: %s, workspace: %s\n",
o.RefProject.Name, o.RefWorkspace.Name)
return nil
}

// Update the phase to 'failed', if it was not succeeded or failed.
if r.Phase != v1.ReleasePhaseSucceeded && r.Phase != v1.ReleasePhaseFailed {
r.Phase = v1.ReleasePhaseFailed

if err := storage.Update(r); err != nil {
return err
}

fmt.Printf("Successfully update release phase to Failed, project: %s, workspace: %s, revision: %d\n",
r.Project, r.Workspace, r.Revision)

return nil
}

fmt.Printf("No need to update the release phase, current phase: %s\n", r.Phase)
return nil
}
Loading

0 comments on commit 2eadd91

Please sign in to comment.