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
47 changes: 47 additions & 0 deletions cli/src/cmd/app/commands/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Examples:

cmd.Flags().Bool("list", false, "List all available services")
cmd.Flags().Bool("show-connection", false, "Show connection string after adding")
cmd.Flags().Bool("dry-run", false, "Show the azure.yaml service block without modifying the file")

return cmd
}
Expand All @@ -63,12 +64,14 @@ type AddResult struct {
Service string `json:"service"`
Added bool `json:"added"`
Message string `json:"message,omitempty"`
Preview string `json:"preview,omitempty"`
ConnectionStrings map[string]string `json:"connectionStrings,omitempty"`
}

func runAdd(cmd *cobra.Command, args []string) error {
listServices, _ := cmd.Flags().GetBool("list")
showConnection, _ := cmd.Flags().GetBool("show-connection")
dryRun, _ := cmd.Flags().GetBool("dry-run")

// Handle --list flag
if listServices {
Expand Down Expand Up @@ -113,6 +116,28 @@ func runAdd(cmd *cobra.Command, args []string) error {
return nil
}

if dryRun {
preview, previewErr := buildServicePreview(serviceName, def)
if previewErr != nil {
return fmt.Errorf("failed to build service preview: %w", previewErr)
}
if cliout.IsJSON() {
return cliout.PrintJSON(AddResult{
Service: serviceName,
Added: false,
Message: fmt.Sprintf("Would add %s to azure.yaml", def.DisplayName),
Preview: preview,
})
}
cliout.Info("Dry run: would add %s to azure.yaml", def.DisplayName)
cliout.Newline()
fmt.Print(preview)
if !strings.HasSuffix(preview, "\n") {
cliout.Newline()
}
return nil
}

// Add the service to azure.yaml
if err := addServiceToYaml(azureYamlPath, serviceName, def); err != nil {
return fmt.Errorf("failed to add service: %w", err)
Expand Down Expand Up @@ -386,3 +411,25 @@ func buildServiceNode(def *wellknown.ServiceDefinition) *yaml.Node {

return node
}

func buildServicePreview(serviceName string, def *wellknown.ServiceDefinition) (string, error) {
servicesNode := &yaml.Node{
Kind: yaml.MappingNode,
Content: []*yaml.Node{
{Kind: yaml.ScalarNode, Value: serviceName, Tag: "!!str"},
buildServiceNode(def),
},
}
root := &yaml.Node{
Kind: yaml.MappingNode,
Content: []*yaml.Node{
{Kind: yaml.ScalarNode, Value: "services", Tag: "!!str"},
servicesNode,
},
}
out, err := yaml.Marshal(root)
if err != nil {
return "", err
}
return string(out), nil
}
59 changes: 59 additions & 0 deletions cli/src/cmd/app/commands/add_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,62 @@ func TestBuildServiceNode(t *testing.T) {
t.Error("buildServiceNode() did not include environment (postgres has env vars)")
}
}

func TestBuildServicePreview(t *testing.T) {
def := wellknown.Get("redis")
if def == nil {
t.Fatal("redis service not found in wellknown registry")
}

preview, err := buildServicePreview("redis", def)
if err != nil {
t.Fatalf("buildServicePreview() error: %v", err)
}

for _, want := range []string{"services:", "redis:", "image: redis:7-alpine", "6379:6379"} {
if !strings.Contains(preview, want) {
t.Errorf("preview missing %q:\n%s", want, preview)
}
}
}

func TestRunAddDryRunDoesNotModifyAzureYaml(t *testing.T) {
tempDir := t.TempDir()
content := `name: test-app
services:
api:
language: python
project: ./api
`
azureYamlPath := filepath.Join(tempDir, "azure.yaml")
if err := os.WriteFile(azureYamlPath, []byte(content), 0o644); err != nil {
t.Fatalf("failed to create azure.yaml: %v", err)
}

originalWD, err := os.Getwd()
if err != nil {
t.Fatalf("failed to get cwd: %v", err)
}
t.Cleanup(func() {
if chdirErr := os.Chdir(originalWD); chdirErr != nil {
t.Fatalf("failed to restore cwd: %v", chdirErr)
}
})
if err := os.Chdir(tempDir); err != nil {
t.Fatalf("failed to chdir: %v", err)
}

cmd := NewAddCommand()
cmd.SetArgs([]string{"redis", "--dry-run"})
if err := cmd.Execute(); err != nil {
t.Fatalf("add --dry-run failed: %v", err)
}

after, err := os.ReadFile(azureYamlPath)
if err != nil {
t.Fatalf("failed to read azure.yaml: %v", err)
}
if string(after) != content {
t.Fatalf("dry-run modified azure.yaml:\n%s", string(after))
}
}
Loading