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
107 changes: 60 additions & 47 deletions cmd/importDir.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ type ValidationError struct {
Message string
}

type ImportFailuresError struct {
FailedCount int
TotalFiles int
}

func (e ImportError) Error() string {
return fmt.Sprintf("failed to import %s: %v", e.File, e.Err)
}
Expand All @@ -95,6 +100,10 @@ func (e ValidationError) Error() string {
return e.Message
}

func (e ImportFailuresError) Error() string {
return fmt.Sprintf("%d/%d files failed to import", e.FailedCount, e.TotalFiles)
}

func NewImportDirCommand(globalClientOpts *connectors.ClientOptions) *cobra.Command {
var (
recursive bool
Expand All @@ -115,13 +124,8 @@ func NewImportDirCommand(globalClientOpts *connectors.ClientOptions) *cobra.Comm
microcks import-dir ./api-specs --recursive
microcks import-dir ./api-specs --pattern "*.yaml"
microcks import-dir ./api-specs --recursive --pattern "openapi.*"`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
fmt.Println("import-dir command requires a directory path")
cmd.HelpFunc()(cmd, args)
os.Exit(1)
}

Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
dirPath := args[0]

config.InsecureTLS = globalClientOpts.InsecureTLS
Expand All @@ -130,13 +134,11 @@ func NewImportDirCommand(globalClientOpts *connectors.ClientOptions) *cobra.Comm

localConfig, err := config.ReadLocalConfig(globalClientOpts.ConfigPath)
if err != nil {
fmt.Println(err)
return
return err
}

if localConfig == nil {
fmt.Println("Please login to perform operation...")
return
return fmt.Errorf("please login to perform operation")
}

if globalClientOpts.Context == "" {
Expand All @@ -146,8 +148,7 @@ func NewImportDirCommand(globalClientOpts *connectors.ClientOptions) *cobra.Comm
// Create client
mc, err := connectors.NewClient(*globalClientOpts)
if err != nil {
fmt.Printf("error %v", err)
return
return fmt.Errorf("error creating Microcks client: %w", err)
}

// Set up business logic dependencies
Expand All @@ -161,42 +162,11 @@ func NewImportDirCommand(globalClientOpts *connectors.ClientOptions) *cobra.Comm
// Execute business logic
result, err := ImportDirectory(mc, fs, dirPath, importConfig)
if err != nil {
if validationErr, ok := err.(*ValidationError); ok {
fmt.Println(validationErr.Message)
return
}
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}

// Display results
if verbose {
fmt.Printf("Found %d specification files to import...\n", result.TotalFiles)
for i, file := range result.SuccessFiles {
fmt.Printf("[%d/%d] ✓ Imported: %s\n", i+1, result.TotalFiles, file)
}
for i, file := range result.FailedFiles {
errorMsg := "Unknown error"
if i < len(result.Errors) {
errorMsg = result.Errors[i]
}
fmt.Printf("✗ Failed: %s - %s\n", file, errorMsg)
}
} else {
fmt.Println("\nImport results:")
for _, file := range result.SuccessFiles {
fmt.Printf("✓ Imported: %s\n", file)
}
for i, file := range result.FailedFiles {
errorMsg := "Unknown error"
if i < len(result.Errors) {
errorMsg = result.Errors[i]
}
fmt.Printf("✗ Failed: %s - %s\n", file, errorMsg)
}
return err
}

fmt.Printf("\nImport completed: %d/%d files imported successfully\n", result.SuccessCount, result.TotalFiles)
printImportResults(result, verbose)
return importResultError(result)
},
}

Expand All @@ -207,6 +177,49 @@ func NewImportDirCommand(globalClientOpts *connectors.ClientOptions) *cobra.Comm
return importDirCmd
}

func printImportResults(result ImportResult, verbose bool) {
if verbose {
fmt.Printf("Found %d specification files to import...\n", result.TotalFiles)
for i, file := range result.SuccessFiles {
fmt.Printf("[%d/%d] ✓ Imported: %s\n", i+1, result.TotalFiles, file)
}
for i, file := range result.FailedFiles {
fmt.Printf("✗ Failed: %s - %s\n", file, importErrorMessage(result, i))
}
} else {
fmt.Println("\nImport results:")
for _, file := range result.SuccessFiles {
fmt.Printf("✓ Imported: %s\n", file)
}
for i, file := range result.FailedFiles {
fmt.Printf("✗ Failed: %s - %s\n", file, importErrorMessage(result, i))
}
}

if result.FailedCount > 0 {
fmt.Printf("\nSome imports failed: %d/%d files imported successfully (%d failed)\n", result.SuccessCount, result.TotalFiles, result.FailedCount)
return
}
fmt.Printf("\nImport completed: %d/%d files imported successfully\n", result.SuccessCount, result.TotalFiles)
}

func importErrorMessage(result ImportResult, index int) string {
if index < len(result.Errors) {
return result.Errors[index]
}
return "Unknown error"
}

func importResultError(result ImportResult) error {
if result.FailedCount == 0 {
return nil
}
return &ImportFailuresError{
FailedCount: result.FailedCount,
TotalFiles: result.TotalFiles,
}
}

func ImportDirectory(client MicrocksClient, fs FileSystem, dirPath string, config ImportConfig) (ImportResult, error) {
if err := validateDirectory(fs, dirPath); err != nil {
return ImportResult{}, err
Expand Down
101 changes: 101 additions & 0 deletions cmd/importDir_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package cmd

import (
"bytes"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -399,6 +400,106 @@ func TestImportResult(t *testing.T) {
assert.Len(t, result.Errors, 2)
}

func TestImportResultError(t *testing.T) {
tests := []struct {
name string
result ImportResult
expectError bool
}{
{
name: "no error when all files import successfully",
result: ImportResult{
TotalFiles: 2,
SuccessCount: 2,
FailedCount: 0,
},
expectError: false,
},
{
name: "error when one or more files fail to import",
result: ImportResult{
TotalFiles: 2,
SuccessCount: 1,
FailedCount: 1,
},
expectError: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := importResultError(tt.result)

if tt.expectError {
assert.Error(t, err)
assert.IsType(t, &ImportFailuresError{}, err)
return
}
assert.NoError(t, err)
})
}
}

func TestPrintImportResults(t *testing.T) {
tests := []struct {
name string
result ImportResult
expected string
}{
{
name: "success summary",
result: ImportResult{
TotalFiles: 1,
SuccessCount: 1,
SuccessFiles: []string{"/test/openapi.yaml"},
},
expected: "Import completed: 1/1 files imported successfully",
},
{
name: "failure summary",
result: ImportResult{
TotalFiles: 2,
SuccessCount: 1,
FailedCount: 1,
SuccessFiles: []string{"/test/openapi.yaml"},
FailedFiles: []string{"/test/postman.json"},
Errors: []string{"error importing /test/postman.json: upload failed"},
},
expected: "Some imports failed: 1/2 files imported successfully (1 failed)",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
output := captureStdout(t, func() {
printImportResults(tt.result, false)
})

assert.Contains(t, output, tt.expected)
})
}
}

func captureStdout(t *testing.T, fn func()) string {
t.Helper()

oldStdout := os.Stdout
readPipe, writePipe, err := os.Pipe()
require.NoError(t, err)

os.Stdout = writePipe
fn()
require.NoError(t, writePipe.Close())
os.Stdout = oldStdout

var buf bytes.Buffer
_, err = buf.ReadFrom(readPipe)
require.NoError(t, err)
require.NoError(t, readPipe.Close())

return buf.String()
}

// Benchmark tests for performance
func BenchmarkImportDirectory(b *testing.B) {
// Create a mock with many files
Expand Down