Repository: radius-project/radius

Issue:
Call to `rad bicep publish-extension ` where target exists results in misleading error
### Steps to reproduce

1. Create a yaml file for a bicep extension. A reference file for eg. deploy/manifest/built-in-providers/self-hosted/applications_core.yaml. Pls create different provider/type names. 
2. Run 
```
rad bicep publish-extension -f <path to .yaml file> --target br:<acr registry location>:label
```
3. bicep extension is successfully created.
4. rerun command in 2. above after a possible .yaml file update, we get error: 
```
The extension "br:<acr registry location>:label" already exists. Use --force to overwrite the existing extension.
```
5. Attempting to rerun the above command with additional --force argument results in error :
```
Error: unknown flag: --force
```

### Observed behavior

If a bicep extension is created using 
```
rad bicep-extension ..
```
to an existing target, we see that the user cannot overwrite the existing extension using --force

### Desired behavior

We should either:
1. Incorporate `--force ` flag into the command so that the user has a way to update the extension at an existing target location or 
2. Update the existing error message to ask the user to say delete the existing target and then rerun command.

### Workaround

User is able to push updated extension to target by first deleting the existing target and then rerunning the command.

### rad Version

v0.43.0

### Operating system

M1

### Additional context

_No response_

### Would you like to support us?

- [ ] Yes, I would like to support you

[AB#15217](https://dev.azure.com/azure-octo/e61041b4-555f-47ae-95b2-4f8ab480ea57/_workitems/edit/15217)

Hints from issue comments:
@radius-triage-bot: :wave: @lakshmimsft Thanks for filing this bug report. 

A project maintainer will review this report and get back to you soon. If you'd like immediate help troubleshooting, please visit our [Discord server](https://aka.ms/radius/discord).

_For more information on our triage process please visit our [triage overview](https://github.com/radius-project/radius/blob/main/docs/contributing/triage/triage-process.md)_

Solution patch:
diff --git a/pkg/cli/cmd/bicep/publishextension/publish.go b/pkg/cli/cmd/bicep/publishextension/publish.go
index 91b34a200..f8764ff47 100644
--- a/pkg/cli/cmd/bicep/publishextension/publish.go
+++ b/pkg/cli/cmd/bicep/publishextension/publish.go
@@ -66,6 +66,7 @@ bicep publish-extension ./Example.Provider.yaml --target br:ghcr.io/myregistry/e
 
 	cmd.Flags().StringVar(&runner.Target, "target", "", "The destination path file or OCI registry path. OCI registry paths use the format 'br:HOST/PATH:TAG'.")
 	_ = cmd.MarkFlagRequired("target")
+	cmd.Flags().BoolVar(&runner.Force, "force", false, "Overwrite the target extension if it exists.")
 	return cmd, runner
 }
 
@@ -76,6 +77,7 @@ type Runner struct {
 	ResourceProvider                 *manifest.ResourceProvider
 	ResourceProviderManifestFilePath string
 	Target                           string
+	Force                            bool
 }
 
 // NewRunner creates a new instance of the `rad bicep publish-extension` runner.
@@ -128,7 +130,7 @@ func (r *Runner) Run(ctx context.Context) error {
 		return err
 	}
 
-	err = publishExtension(ctx, temp, r.Target)
+	err = publishExtension(ctx, temp, r.Target, r.Force)
 	if err != nil {
 		return err
 	}
@@ -157,7 +159,7 @@ func generateBicepExtensionIndex(ctx context.Context, inputFilePath string, outp
 	return nil
 }
 
-func publishExtension(ctx context.Context, inputDirectoryPath string, target string) error {
+func publishExtension(ctx context.Context, inputDirectoryPath string, target string, force bool) error {
 	bicepFilePath, err := bicep.GetBicepFilePath()
 	if err != nil {
 		return err
@@ -169,6 +171,11 @@ func publishExtension(ctx context.Context, inputDirectoryPath string, target str
 		filepath.Join(inputDirectoryPath, "index.json"),
 		"--target", target,
 	}
+
+	if force {
+		args = append(args, "--force")
+	}
+
 	cmd := exec.CommandContext(ctx, bicepFilePath, args...)
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr



Test patch:
diff --git a/pkg/cli/cmd/bicep/publishextension/publish_test.go b/pkg/cli/cmd/bicep/publishextension/publish_test.go
index d0cd222d2..b8a3db8ed 100644
--- a/pkg/cli/cmd/bicep/publishextension/publish_test.go
+++ b/pkg/cli/cmd/bicep/publishextension/publish_test.go
@@ -32,6 +32,11 @@ func TestRunner_Validate(t *testing.T) {
 			Input:         []string{"--from-file", "testdata/valid.yaml", "--target", "./output.tgz"},
 			ExpectedValid: true,
 		},
+		{
+			Name:          "Valid with force flag",
+			Input:         []string{"--from-file", "testdata/valid.yaml", "--target", "./output.tgz", "--force"},
+			ExpectedValid: true,
+		},
 		{
 			Name:          "Invalid: invalid manifest",
 			Input:         []string{"--from-file", "testdata/invalid.yaml", "--target", "./output.tgz"},