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
8 changes: 2 additions & 6 deletions cmd/harbor/root/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package root
import (
"context"
"fmt"
"os"
"strings"

"github.com/goharbor/go-client/pkg/harbor"
Expand All @@ -28,7 +27,6 @@ import (
"github.com/goharbor/harbor-cli/pkg/views/login"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"golang.org/x/term"
)

var (
Expand All @@ -53,13 +51,11 @@ func LoginCommand() *cobra.Command {
}

if passwordStdin {
fmt.Print("Password: ")
passwordBytes, err := term.ReadPassword(int(os.Stdin.Fd())) // #nosec G115 - fd fits in int on all supported platforms
password, err := utils.GetSecretStdin("Password: ")
if err != nil {
return fmt.Errorf("failed to read password from stdin: %v", err)
}
fmt.Println()
Password = string(passwordBytes)
Password = password
}

loginView := login.LoginView{
Expand Down
6 changes: 3 additions & 3 deletions cmd/harbor/root/quota/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,19 @@ func ListQuotaCommand() *cobra.Command {
return fmt.Errorf("page size should be less than or equal to 100")
}

quota, err := api.ListQuota(opts)
quotas, err := api.GetAllQuotas(api.ListQuota, opts)
if err != nil {
return fmt.Errorf("failed to get quota list: %v", err)
}

FormatFlag := viper.GetString("output-format")
if FormatFlag != "" {
err = utils.PrintFormat(quota, FormatFlag)
err = utils.PrintFormat(quotas, FormatFlag)
if err != nil {
return fmt.Errorf("failed to get quota list: %v", err)
}
} else {
list.ListQuotas(quota.Payload)
list.ListQuotas(quotas)
}
return nil
},
Expand Down
10 changes: 5 additions & 5 deletions cmd/harbor/root/replication/executions/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,27 +61,27 @@ func ListCommand() *cobra.Command {
}

log.Debug("Fetching executions...")
executions, err := api.ListReplicationExecutions(rpolicyID, opts)
executions, err := api.GetAllReplicationExecutions(rpolicyID, api.ListReplicationExecutions, opts)
if err != nil {
return fmt.Errorf("failed to get projects list: %v", utils.ParseHarborErrorMsg(err))
}

log.WithField("count", len(executions.Payload)).Debug("Number of executions fetched")
if len(executions.Payload) == 0 {
log.WithField("count", len(executions)).Debug("Number of executions fetched")
if len(executions) == 0 {
fmt.Println("No executions found")
return nil
}

formatFlag := viper.GetString("output-format")
if formatFlag != "" {
log.WithField("output_format", formatFlag).Debug("Output format selected")
err = utils.PrintFormat(executions.Payload, formatFlag)
err = utils.PrintFormat(executions, formatFlag)
if err != nil {
return err
}
} else {
log.Debug("Listing projects using default view")
list.ListExecutions(executions.Payload)
list.ListExecutions(executions)
}
return nil
},
Expand Down
10 changes: 5 additions & 5 deletions cmd/harbor/root/replication/policies/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,27 @@ func ListCommand() *cobra.Command {
}

log.Debug("Fetching policies...")
allPolicies, err := api.ListReplicationPolicies(opts)
allPolicies, err := api.GetAllReplicationPolicies(api.ListReplicationPolicies, opts)
if err != nil {
return fmt.Errorf("failed to get projects list: %v", utils.ParseHarborErrorMsg(err))
}

log.WithField("count", len(allPolicies.Payload)).Debug("Number of policies fetched")
if len(allPolicies.Payload) == 0 {
log.WithField("count", len(allPolicies)).Debug("Number of policies fetched")
if len(allPolicies) == 0 {
fmt.Println("No policies found")
return nil
}

formatFlag := viper.GetString("output-format")
if formatFlag != "" {
log.WithField("output_format", formatFlag).Debug("Output format selected")
err = utils.PrintFormat(allPolicies.Payload, formatFlag)
err = utils.PrintFormat(allPolicies, formatFlag)
if err != nil {
return err
}
} else {
log.Debug("Listing projects using default view")
list.ListPolicies(allPolicies.Payload)
list.ListPolicies(allPolicies)
}
return nil
},
Expand Down
54 changes: 54 additions & 0 deletions pkg/api/quota_handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright Project Harbor 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 api

import (
"testing"

"github.com/goharbor/go-client/pkg/sdk/v2.0/client/quota"
"github.com/goharbor/go-client/pkg/sdk/v2.0/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGetAllQuotasFetchesAllPages(t *testing.T) {
var pages []int64
var pageSizes []int64

quotas, err := GetAllQuotas(
func(opts ListQuotaFlags) (*quota.ListQuotasOK, error) {
pages = append(pages, opts.Page)
pageSizes = append(pageSizes, opts.PageSize)

if opts.Page == 1 {
return &quota.ListQuotasOK{Payload: makeQuotas(100)}, nil
}
return &quota.ListQuotasOK{Payload: makeQuotas(2)}, nil
},
ListQuotaFlags{Page: 8, PageSize: 0},
)

require.NoError(t, err)
assert.Len(t, quotas, 102)
assert.Equal(t, []int64{1, 2}, pages)
assert.Equal(t, []int64{100, 100}, pageSizes)
}

func makeQuotas(count int) []*models.Quota {
quotas := make([]*models.Quota, count)
for i := range quotas {
quotas[i] = &models.Quota{ID: int64(i + 1)}
}
return quotas
}
69 changes: 69 additions & 0 deletions pkg/api/replication_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,40 @@ func ListReplicationPolicies(opts ...ListFlags) (*replication.ListReplicationPol
return response, nil
}

func GetAllReplicationPolicies(
listFunc func(...ListFlags) (*replication.ListReplicationPoliciesOK, error),
opts ListFlags,
) ([]*models.ReplicationPolicy, error) {
var allPolicies []*models.ReplicationPolicy
if opts.PageSize == 0 {
opts.PageSize = 100
opts.Page = 1

for {
policies, err := listFunc(opts)
if err != nil {
return nil, err
}

allPolicies = append(allPolicies, policies.Payload...)

if len(policies.Payload) < int(opts.PageSize) {
break
}

opts.Page++
}
} else {
policies, err := listFunc(opts)
if err != nil {
return nil, err
}
allPolicies = policies.Payload
}

return allPolicies, nil
}

func GetReplicationPolicy(policyID int64) (*replication.GetReplicationPolicyOK, error) {
ctx, client, err := utils.ContextWithClient()
if err != nil {
Expand Down Expand Up @@ -166,6 +200,41 @@ func ListReplicationExecutions(policyID int64, opts ...ListFlags) (*replication.
return response, nil
}

func GetAllReplicationExecutions(
policyID int64,
listFunc func(int64, ...ListFlags) (*replication.ListReplicationExecutionsOK, error),
opts ListFlags,
) ([]*models.ReplicationExecution, error) {
var allExecutions []*models.ReplicationExecution
if opts.PageSize == 0 {
opts.PageSize = 100
opts.Page = 1

for {
executions, err := listFunc(policyID, opts)
if err != nil {
return nil, err
}

allExecutions = append(allExecutions, executions.Payload...)

if len(executions.Payload) < int(opts.PageSize) {
break
}

opts.Page++
}
} else {
executions, err := listFunc(policyID, opts)
if err != nil {
return nil, err
}
allExecutions = executions.Payload
}

return allExecutions, nil
}

func GetReplicationExecution(executionID int64) (*replication.GetReplicationExecutionOK, error) {
ctx, client, err := utils.ContextWithClient()
if err != nil {
Expand Down
90 changes: 90 additions & 0 deletions pkg/api/replication_handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright Project Harbor 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 api

import (
"testing"

"github.com/goharbor/go-client/pkg/sdk/v2.0/client/replication"
"github.com/goharbor/go-client/pkg/sdk/v2.0/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGetAllReplicationPoliciesFetchesAllPages(t *testing.T) {
var pages []int64
var pageSizes []int64

policies, err := GetAllReplicationPolicies(
func(opts ...ListFlags) (*replication.ListReplicationPoliciesOK, error) {
require.Len(t, opts, 1)
pages = append(pages, opts[0].Page)
pageSizes = append(pageSizes, opts[0].PageSize)

if opts[0].Page == 1 {
return &replication.ListReplicationPoliciesOK{Payload: makeReplicationPolicies(100)}, nil
}
return &replication.ListReplicationPoliciesOK{Payload: makeReplicationPolicies(3)}, nil
},
ListFlags{Page: 5, PageSize: 0},
)

require.NoError(t, err)
assert.Len(t, policies, 103)
assert.Equal(t, []int64{1, 2}, pages)
assert.Equal(t, []int64{100, 100}, pageSizes)
}

func TestGetAllReplicationExecutionsFetchesAllPages(t *testing.T) {
var pages []int64
var pageSizes []int64
const policyID int64 = 7

executions, err := GetAllReplicationExecutions(
policyID,
func(gotPolicyID int64, opts ...ListFlags) (*replication.ListReplicationExecutionsOK, error) {
require.Equal(t, policyID, gotPolicyID)
require.Len(t, opts, 1)
pages = append(pages, opts[0].Page)
pageSizes = append(pageSizes, opts[0].PageSize)

if opts[0].Page == 1 {
return &replication.ListReplicationExecutionsOK{Payload: makeReplicationExecutions(100)}, nil
}
return &replication.ListReplicationExecutionsOK{Payload: makeReplicationExecutions(4)}, nil
},
ListFlags{Page: 3, PageSize: 0},
)

require.NoError(t, err)
assert.Len(t, executions, 104)
assert.Equal(t, []int64{1, 2}, pages)
assert.Equal(t, []int64{100, 100}, pageSizes)
}

func makeReplicationPolicies(count int) []*models.ReplicationPolicy {
policies := make([]*models.ReplicationPolicy, count)
for i := range policies {
policies[i] = &models.ReplicationPolicy{ID: int64(i + 1)}
}
return policies
}

func makeReplicationExecutions(count int) []*models.ReplicationExecution {
executions := make([]*models.ReplicationExecution, count)
for i := range executions {
executions[i] = &models.ReplicationExecution{ID: int64(i + 1)}
}
return executions
}
22 changes: 17 additions & 5 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
"regexp"
"strconv"
"strings"
"syscall"

"github.com/charmbracelet/bubbles/table"
"github.com/gocarina/gocsv"
Expand Down Expand Up @@ -187,13 +187,25 @@ func SavePayloadJSON(filename string, payload any) {

// Get Password as Stdin
func GetSecretStdin(prompt string) (string, error) {
fmt.Print(prompt)
bytePassword, err := term.ReadPassword(int(syscall.Stdin))
if term.IsTerminal(int(os.Stdin.Fd())) { // #nosec G115 - fd fits in int on all supported platforms
fmt.Print(prompt)
bytePassword, err := term.ReadPassword(int(os.Stdin.Fd())) // #nosec G115 - fd fits in int on all supported platforms
if err != nil {
return "", err
}
fmt.Println() // move to the next line after input
return trimSecretLineEnding(bytePassword), nil
}

bytePassword, err := io.ReadAll(os.Stdin)
if err != nil {
return "", err
}
fmt.Println() // move to the next line after input
return strings.TrimSpace(string(bytePassword)), nil
return trimSecretLineEnding(bytePassword), nil
}

func trimSecretLineEnding(secret []byte) string {
return strings.TrimRight(string(secret), "\r\n")
}

func ToKebabCase(s string) string {
Expand Down
Loading