diff --git a/README.md b/README.md index f275143..deee63d 100644 --- a/README.md +++ b/README.md @@ -233,7 +233,7 @@ Flags: --owner string GitHub owner that hosts the curated services (default "grycap") --path string subdirectory inside the repository that contains the services --ref string Git reference (branch, tag, or commit) to query (default "main") - -n, --name string override the OSCAR service name during deployment + -n, --name string override the OSCAR service and primary bucket names during deployment --repo string GitHub repository that hosts the curated services (default "oscar-hub") Global Flags: diff --git a/cmd/apply.go b/cmd/apply.go index ebf1c80..118928f 100644 --- a/cmd/apply.go +++ b/cmd/apply.go @@ -194,19 +194,19 @@ func overrideServiceName(svc *types.Service, newName string) { if override == "" { return } - original := strings.TrimSpace(svc.Name) - if original == "" { - svc.Name = override - return - } - if original == override { - return + originalName := strings.TrimSpace(svc.Name) + primaryBucket := primaryBucketName(svc) + oldBucket := originalName + if primaryBucket != "" { + oldBucket = primaryBucket } - renameStoragePaths(&svc.Input, original, override) - renameStoragePaths(&svc.Output, original, override) - if svc.Mount.Path != "" { - svc.Mount.Path = replacePathBucket(svc.Mount.Path, original, override) + if strings.TrimSpace(oldBucket) != "" && !strings.EqualFold(oldBucket, override) { + renameStoragePaths(&svc.Input, oldBucket, override) + renameStoragePaths(&svc.Output, oldBucket, override) + if svc.Mount.Path != "" { + svc.Mount.Path = replacePathBucket(svc.Mount.Path, oldBucket, override) + } } svc.Name = override @@ -258,3 +258,36 @@ func replacePathBucket(path, oldName, newName string) string { } return builder } + +func primaryBucketName(svc *types.Service) string { + if svc == nil { + return "" + } + for _, cfg := range svc.Output { + if bucket := bucketFromPath(cfg.Path); bucket != "" { + return bucket + } + } + for _, cfg := range svc.Input { + if bucket := bucketFromPath(cfg.Path); bucket != "" { + return bucket + } + } + if bucket := bucketFromPath(svc.Mount.Path); bucket != "" { + return bucket + } + return "" +} + +func bucketFromPath(path string) string { + if strings.TrimSpace(path) == "" { + return "" + } + trimmed := strings.Trim(path, " ") + trimmed = strings.Trim(trimmed, "/") + if trimmed == "" { + return "" + } + parts := strings.SplitN(trimmed, "/", 2) + return parts[0] +} diff --git a/cmd/apply_test.go b/cmd/apply_test.go index d80c0f2..c39df7e 100644 --- a/cmd/apply_test.go +++ b/cmd/apply_test.go @@ -36,6 +36,36 @@ func TestOverrideServiceNameUpdatesPaths(t *testing.T) { } } +func TestOverrideServiceNameUpdatesPathsWhenBucketDiffersFromServiceName(t *testing.T) { + svc := &types.Service{ + Name: "demo", + Input: []types.StorageIOConfig{ + {Path: "workflow/in"}, + {Path: "other/in"}, + }, + Output: []types.StorageIOConfig{{Path: "workflow"}}, + Mount: types.StorageIOConfig{Path: "workflow/mount"}, + } + + overrideServiceName(svc, "demo-new") + + if svc.Name != "demo-new" { + t.Fatalf("expected service name demo-new, got %s", svc.Name) + } + if got := svc.Input[0].Path; got != "demo-new/in" { + t.Fatalf("expected first input path demo-new/in, got %s", got) + } + if got := svc.Input[1].Path; got != "other/in" { + t.Fatalf("unexpected path rewrite: %s", got) + } + if got := svc.Output[0].Path; got != "demo-new" { + t.Fatalf("expected output path demo-new, got %s", got) + } + if got := svc.Mount.Path; got != "demo-new/mount" { + t.Fatalf("expected mount path demo-new/mount, got %s", got) + } +} + func TestReplacePathBucket(t *testing.T) { cases := []struct { name string diff --git a/cmd/hub_deploy.go b/cmd/hub_deploy.go index f5bcc7e..73dbf48 100644 --- a/cmd/hub_deploy.go +++ b/cmd/hub_deploy.go @@ -82,7 +82,7 @@ func hubDeployFunc(cmd *cobra.Command, args []string, opts *hubDeployOptions) er } if opts.name != "" { - serviceDef.Name = opts.name + overrideServiceName(serviceDef, opts.name) } action := "Creating" @@ -128,7 +128,7 @@ func makeHubDeployCmd() *cobra.Command { cmd.Flags().StringVar(&opts.rootPath, "path", opts.rootPath, "subdirectory inside the repository that contains the services") cmd.Flags().StringVar(&opts.ref, "ref", opts.ref, "Git reference (branch, tag, or commit) to query") cmd.Flags().StringVar(&opts.apiBase, "api-base", "", "override the GitHub API base URL") - cmd.Flags().StringVarP(&opts.name, "name", "n", "", "override the OSCAR service name during deployment") + cmd.Flags().StringVarP(&opts.name, "name", "n", "", "override the OSCAR service and primary bucket names during deployment") cmd.Flags().StringVar(&opts.localPath, "local-path", "", "use a local directory containing the RO-Crate metadata instead of fetching it from GitHub") cmd.Flags().StringP("cluster", "c", "", "set the cluster") diff --git a/cmd/hub_deploy_test.go b/cmd/hub_deploy_test.go index 273183c..f9a022c 100644 --- a/cmd/hub_deploy_test.go +++ b/cmd/hub_deploy_test.go @@ -25,6 +25,15 @@ functions: name: Cowsay image: ghcr.io/demo/cowsay:latest script: script.sh + input: + - storage_provider: minio.default + path: cowsay/in + output: + - storage_provider: minio.default + path: cowsay + mount: + storage_provider: minio.default + path: cowsay/mount ` scriptContent = "#!/bin/bash\necho moo\n" ) @@ -98,6 +107,21 @@ default: test if applied.Name != override { t.Fatalf("expected service name %s, got %s", override, applied.Name) } + if len(applied.Input) != 1 { + t.Fatalf("expected 1 input entry, got %d", len(applied.Input)) + } + if got := applied.Input[0].Path; got != "alt-cowsay/in" { + t.Fatalf("expected input path alt-cowsay/in, got %s", got) + } + if len(applied.Output) != 1 { + t.Fatalf("expected 1 output entry, got %d", len(applied.Output)) + } + if got := applied.Output[0].Path; got != "alt-cowsay" { + t.Fatalf("expected output path alt-cowsay, got %s", got) + } + if got := applied.Mount.Path; got != "alt-cowsay/mount" { + t.Fatalf("expected mount path alt-cowsay/mount, got %s", got) + } if applied.Script != scriptContent { t.Fatalf("expected script content %q, got %q", scriptContent, applied.Script) }