Skip to content
Open
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
43 changes: 39 additions & 4 deletions cmd/harbor/root/project/member/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ package member

import (
"fmt"
"strings"

"github.com/goharbor/go-client/pkg/sdk/v2.0/models"
"github.com/sirupsen/logrus"

"github.com/goharbor/harbor-cli/pkg/api"
"github.com/goharbor/harbor-cli/pkg/prompt"
Expand All @@ -28,6 +28,37 @@ import (
"github.com/spf13/cobra"
)

// roleFlagAliases maps every accepted spelling of --role to a canonical
// Harbor role ID. Keys are pre-normalized (lowercase, separators stripped).
var roleFlagAliases = map[string]int{
"projectadmin": 1, "admin": 1,
"developer": 2,
"guest": 3,
"maintainer": 4,
"limitedguest": 5,
}

// resolveRoleFlags collapses --role and --roleid into one canonical Harbor
// role ID (1..5). (0, nil) means "no role specified" — the interactive view
// will prompt for one.
func resolveRoleFlags(roleName string, roleID int) (int, error) {
if roleName != "" {
key := strings.ToLower(strings.NewReplacer("_", "", " ", "", "-", "").Replace(roleName))
matched, ok := roleFlagAliases[key]
if !ok {
return 0, fmt.Errorf("invalid --role %q (expected one of: Project_Admin, Developer, Guest, Maintainer, Limited_Guest)", roleName)
}
if roleID != 0 && roleID != matched {
return 0, fmt.Errorf("--role %q (id %d) conflicts with --roleid %d", roleName, matched, roleID)
}
roleID = matched
}
if roleID != 0 && (roleID < 1 || roleID > 5) {
return 0, fmt.Errorf("invalid --roleid %d (must be 1=Admin, 2=Developer, 3=Guest, 4=Maintainer, 5=LimitedGuest)", roleID)
}
return roleID, nil
}

func CreateMemberCommand() *cobra.Command {
var opts create.CreateView
opts.MemberUser = &models.UserEntity{} // Initialize MemberUser
Expand Down Expand Up @@ -59,9 +90,14 @@ func CreateMemberCommand() *cobra.Command {
}
}

opts.RoleID, err = resolveRoleFlags(opts.RoleName, opts.RoleID)
if err != nil {
return err
}

sysInfo, err := api.GetSystemInfo()
if err != nil {
fmt.Println("could not access server info")
return fmt.Errorf("could not access server info: %v", utils.ParseHarborErrorMsg(err))
}

createView := &create.CreateView{
Expand All @@ -81,15 +117,14 @@ func CreateMemberCommand() *cobra.Command {
},
}

// check if role and member is valid
if opts.RoleID != 0 && opts.MemberUser.Username != "" {
err = api.CreateMember(*createView)
} else {
err = createMemberView(createView)
}

if err != nil {
logrus.Errorf("failed to create user: %v", err)
return fmt.Errorf("failed to create member: %v", utils.ParseHarborErrorMsg(err))
}

fmt.Printf("successfully added user %s to project %s\n", createView.MemberUser.Username, opts.ProjectName)
Expand Down
1 change: 1 addition & 0 deletions pkg/api/instance_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/goharbor/go-client/pkg/sdk/v2.0/models"
"github.com/goharbor/harbor-cli/pkg/utils"
"github.com/goharbor/harbor-cli/pkg/views/instance/create"
log "github.com/sirupsen/logrus"
)

func CreateInstance(opts create.CreateView) error {
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/member_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func CreateMember(opts create.CreateView) error {
ctx, &member.CreateProjectMemberParams{
XIsResourceName: &opts.XIsResourceID,
ProjectMember: &models.ProjectMember{
RoleID: int64(opts.RoleID + 1),
RoleID: int64(opts.RoleID),
MemberUser: opts.MemberUser,
MemberGroup: opts.MemberGroup,
},
Expand Down
6 changes: 3 additions & 3 deletions pkg/api/registry_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ func GetRegistryResponse(registryId int64) (*models.Registry, error) {
return nil, err
}
if response.Payload.ID == 0 {
return nil, err
return nil, fmt.Errorf("registry %d not found", registryId)
}

return response.GetPayload(), err
return response.GetPayload(), nil
}

func UpdateRegistry(updateView *models.Registry, projectID int64) error {
Expand Down Expand Up @@ -187,5 +187,5 @@ func GetRegistryIdByName(registryName string) (int64, error) {
}
}

return 0, err
return 0, fmt.Errorf("registry %q not found", registryName)
}
2 changes: 1 addition & 1 deletion pkg/api/user_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func GetUsersIdByName(userName string) (int64, error) {
}
}

return 0, err
return 0, fmt.Errorf("user %q not found", userName)
}

func ResetPassword(userId int64, opts reset.PasswordChangeView) error {
Expand Down
12 changes: 8 additions & 4 deletions pkg/views/member/create/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,14 @@ var RoleOptions = map[string]int{
}

func CreateMemberView(createView *CreateView) {
roleOptions := []string{"Project Admin", "Developer", "Guest", "Maintainer", "Limited Guest"}
var roleSelectOptions []huh.Option[int]
for id, name := range roleOptions {
roleSelectOptions = append(roleSelectOptions, huh.NewOption(name, id))
// Bind labels directly to canonical Harbor role IDs so the form and
// the --role/--roleid flags share one representation.
roleSelectOptions := []huh.Option[int]{
huh.NewOption("Project Admin", RoleOptions["Admin"]),
huh.NewOption("Developer", RoleOptions["Developer"]),
huh.NewOption("Guest", RoleOptions["Guest"]),
huh.NewOption("Maintainer", RoleOptions["Maintainer"]),
huh.NewOption("Limited Guest", RoleOptions["LimitedGuest"]),
}

groupOptions := []string{"None", "LDAP group", "HTTP group", "OIDC group"}
Expand Down