Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add project display name support #76

Merged
merged 3 commits into from
Feb 6, 2024
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
9 changes: 6 additions & 3 deletions create/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

type projectCmd struct {
Name string `arg:"" default:"" help:"Name of the project. A random name is generated if omitted."`
DisplayName string `default:"" help:"Display Name of the project."`
Wait bool `default:"true" help:"Wait until the project was fully created."`
WaitTimeout time.Duration `default:"10m" help:"Duration to wait for project getting ready. Only relevant if wait is set."`
}
Expand All @@ -27,7 +28,7 @@ func (proj *projectCmd) Run(ctx context.Context, client *api.Client) error {
return err
}

p := newProject(proj.Name, cfg.Organization)
p := newProject(proj.Name, cfg.Organization, proj.DisplayName)
fmt.Printf("Creating new project %s for organization %s\n", p.Name, cfg.Organization)
c := newCreator(client, p, strings.ToLower(management.ProjectKind))
ctx, cancel := context.WithTimeout(ctx, proj.WaitTimeout)
Expand All @@ -47,7 +48,7 @@ func (proj *projectCmd) Run(ctx context.Context, client *api.Client) error {
})
}

func newProject(name, project string) *management.Project {
func newProject(name, project, displayName string) *management.Project {
return &management.Project{
ObjectMeta: metav1.ObjectMeta{
Name: getName(name),
Expand All @@ -57,6 +58,8 @@ func newProject(name, project string) *management.Project {
Kind: management.ProjectKind,
APIVersion: management.SchemeGroupVersion.String(),
},
Spec: management.ProjectSpec{},
Spec: management.ProjectSpec{
DisplayName: displayName,
},
}
}
1 change: 1 addition & 0 deletions create/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func TestProjects(t *testing.T) {

cmd := projectCmd{
Name: projectName,
DisplayName: "Some Display Name",
Wait: false,
WaitTimeout: time.Second,
}
Expand Down
9 changes: 7 additions & 2 deletions get/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

management "github.com/ninech/apis/management/v1alpha1"
"github.com/ninech/nctl/api"
"github.com/ninech/nctl/api/util"
"github.com/ninech/nctl/internal/format"
)

Expand Down Expand Up @@ -60,11 +61,15 @@ func printProject(projects []management.Project, get Cmd, out io.Writer, header
// for projects
if header {
get.AllProjects = false
get.writeHeader(w, "NAME")
get.writeHeader(w, "NAME", "DISPLAY NAME")
}

for _, proj := range projects {
get.writeTabRow(w, "", proj.Name)
displayName := proj.Spec.DisplayName
if len(displayName) == 0 {
displayName = util.NoneText
}
get.writeTabRow(w, "", proj.Name, displayName)
}

return w.Flush()
Expand Down
36 changes: 23 additions & 13 deletions get/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,38 @@ func TestProject(t *testing.T) {

for name, testCase := range map[string]struct {
projects []client.Object
displayNames []string
name string
outputFormat output
allProjects bool
output string
}{
"projects exist, full format": {
projects: test.Projects(organization, "dev", "staging", "prod"),
displayNames: []string{"Development", "", "Production"},
outputFormat: full,
output: `NAME
dev
prod
staging
output: `NAME DISPLAY NAME
dev Development
prod Production
staging <none>
`,
},
"projects exist, no header format": {
projects: test.Projects(organization, "dev", "staging", "prod"),
outputFormat: noHeader,
output: `dev
prod
staging
output: `dev <none>
prod <none>
staging <none>
`,
},
"projects exist and allProjects is set": {
projects: test.Projects(organization, "dev", "staging", "prod"),
outputFormat: full,
allProjects: true,
output: `NAME
dev
prod
staging
output: `NAME DISPLAY NAME
dev <none>
prod <none>
staging <none>
`,
},
"no projects exist": {
Expand All @@ -69,8 +71,8 @@ staging
projects: test.Projects(organization, "dev", "staging"),
name: "dev",
outputFormat: full,
output: `NAME
dev
output: `NAME DISPLAY NAME
dev <none>
`,
},
"specific project requested, but does not exist": {
Expand Down Expand Up @@ -99,6 +101,14 @@ dev
t.Fatal(err)
}

projects := testCase.projects
for i, proj := range projects {
if len(projects) != len(testCase.displayNames) {
break
}
proj.(*management.Project).Spec.DisplayName = testCase.displayNames[i]
}

client := fake.NewClientBuilder().
WithScheme(scheme).
WithIndex(&management.Project{}, "metadata.name", func(o client.Object) []string {
Expand Down
53 changes: 53 additions & 0 deletions update/project.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package update

import (
"context"
"fmt"

"github.com/crossplane/crossplane-runtime/pkg/resource"
management "github.com/ninech/apis/management/v1alpha1"
"github.com/ninech/nctl/api"
"github.com/ninech/nctl/auth"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type projectCmd struct {
Name string `arg:"" default:"" help:"Name of the project to update."`
DisplayName *string `default:"" help:"Display Name of the project."`
}

func (cmd *projectCmd) Run(ctx context.Context, client *api.Client) error {
cfg, err := auth.ReadConfig(client.KubeconfigPath, client.KubeconfigContext)
if err != nil {
if auth.IsConfigNotFoundError(err) {
return auth.ReloginNeeded(err)
}
return err
}

project := &management.Project{
ObjectMeta: metav1.ObjectMeta{
Name: cmd.Name,
Namespace: cfg.Organization,
},
}

upd := newUpdater(client, project, management.ProjectKind, func(current resource.Managed) error {
project, ok := current.(*management.Project)
if !ok {
return fmt.Errorf("resource is of type %T, expected %T", current, management.Project{})
}

cmd.applyUpdates(project)

return nil
})

return upd.Update(ctx)
}

func (cmd *projectCmd) applyUpdates(project *management.Project) {
if cmd.DisplayName != nil {
project.Spec.DisplayName = *cmd.DisplayName
}
}
81 changes: 81 additions & 0 deletions update/project_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package update

import (
"context"
"os"
"testing"

management "github.com/ninech/apis/management/v1alpha1"
"github.com/ninech/nctl/api"
"github.com/ninech/nctl/internal/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
)

func TestProject(t *testing.T) {
const (
projectName = "some-project"
organization = "org"
)
existingProject := &management.Project{
ObjectMeta: metav1.ObjectMeta{
Name: projectName,
Namespace: organization,
},
Spec: management.ProjectSpec{},
}

cases := map[string]struct {
orig *management.Project
project string
cmd projectCmd
checkProject func(t *testing.T, cmd projectCmd, orig, updated *management.Project)
}{
"all fields update": {
orig: existingProject,
project: projectName,
cmd: projectCmd{
Name: projectName,
DisplayName: ptr.To("some display name"),
},
checkProject: func(t *testing.T, cmd projectCmd, orig, updated *management.Project) {
assert.Equal(t, *cmd.DisplayName, updated.Spec.DisplayName)
},
},
}

for name, tc := range cases {
tc := tc

t.Run(name, func(t *testing.T) {
apiClient, err := test.SetupClient(tc.orig)
if err != nil {
t.Fatal(err)
}
apiClient.Project = tc.project

ctx := context.Background()

// we create a kubeconfig which does not contain a nctl config
// extension
kubeconfig, err := test.CreateTestKubeconfig(apiClient, organization)
require.NoError(t, err)
defer os.Remove(kubeconfig)

if err := tc.cmd.Run(ctx, apiClient); err != nil {
t.Fatal(err)
}

updated := &management.Project{}
if err := apiClient.Get(ctx, api.ObjectName(tc.orig), updated); err != nil {
t.Fatal(err)
}

if tc.checkProject != nil {
tc.checkProject(t, tc.cmd, tc.orig, updated)
}
})
}
}
3 changes: 2 additions & 1 deletion update/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
type Cmd struct {
Application applicationCmd `cmd:"" group:"deplo.io" name:"application" aliases:"app" help:"Update an existing deplo.io Application. (Beta - requires access)"`
Config configCmd `cmd:"" group:"deplo.io" name:"config" help:"Update an existing deplo.io Project Configuration. (Beta - requires access)"`
Project projectCmd `cmd:"" group:"management.nine.ch" name:"project" help:"Update an existing Project"`
}

type updater struct {
Expand All @@ -27,7 +28,7 @@ func newUpdater(client *api.Client, mg resource.Managed, kind string, f updateFu
}

func (u *updater) Update(ctx context.Context) error {
if err := u.client.Get(ctx, u.client.Name(u.mg.GetName()), u.mg); err != nil {
if err := u.client.Get(ctx, api.ObjectName(u.mg), u.mg); err != nil {
return err
}

Expand Down
Loading