cli/azd/pkg/tools/swa/swa.go (110 lines of code) (raw):
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package swa
import (
"context"
"fmt"
"io"
"log"
"os"
"path/filepath"
"strings"
"github.com/azure/azure-dev/cli/azd/pkg/exec"
"github.com/azure/azure-dev/cli/azd/pkg/tools"
)
// swaCliPackage is the npm package (including the version version) we execute with npx to run the SWA CLI.
const swaCliPackage = "@azure/static-web-apps-cli@2.0.5"
var _ tools.ExternalTool = (*Cli)(nil)
func NewCli(commandRunner exec.CommandRunner) *Cli {
return &Cli{
commandRunner: commandRunner,
}
}
type DeployOptions struct {
AppFolderPath string
OutputRelativeFolderPath string
}
type Cli struct {
// commandRunner allows us to stub out the CommandRunner, for testing.
commandRunner exec.CommandRunner
}
func (cli *Cli) Build(ctx context.Context, cwd string, buildProgress io.Writer) error {
fullAppFolderPath := filepath.Join(cwd)
result, err := cli.run(ctx, fullAppFolderPath, buildProgress, "build", "-V")
if err != nil {
return fmt.Errorf("swa build: %w", err)
}
output := result.Stdout
// when swa cli does not find swa-cli.config.json, it shows the message:
// No build options were defined.
// If your app needs a build step, run "swa init" to set your project configuration
// or use option flags to set your build commands and paths.
// Azd used this as an error for the customer and return the full message.
if strings.Contains(output, "No build options were defined") {
return fmt.Errorf("swa build: %s", output)
}
return nil
}
func (cli *Cli) Deploy(
ctx context.Context,
cwd string,
tenantId string,
subscriptionId string,
resourceGroup string,
appName string,
environment string,
deploymentToken string,
options DeployOptions,
) (string, error) {
log.Printf(
"SWA Deploy: TenantId: %s, SubscriptionId: %s, ResourceGroup: %s, ResourceName: %s, Environment: %s",
tenantId,
subscriptionId,
resourceGroup,
appName,
environment,
)
args := []string{"deploy",
"--tenant-id", tenantId,
"--subscription-id", subscriptionId,
"--resource-group", resourceGroup,
"--app-name", appName,
"--env", environment,
"--no-use-keychain",
"--deployment-token", deploymentToken}
if options.AppFolderPath != "" {
args = append(args, "--app-location", options.AppFolderPath)
}
if options.OutputRelativeFolderPath != "" {
args = append(args, "--output-location", options.OutputRelativeFolderPath)
}
res, err := cli.executeCommand(ctx, cwd, args...)
if err != nil {
return "", fmt.Errorf("swa deploy: %w", err)
}
return res.Stdout + res.Stderr, nil
}
func (cli *Cli) CheckInstalled(_ context.Context) error {
return tools.ToolInPath("npx")
}
func (cli *Cli) Name() string {
return "SWA CLI"
}
func (cli *Cli) InstallUrl() string {
return "https://azure.github.io/static-web-apps-cli/docs/use/install"
}
func (cli *Cli) executeCommand(ctx context.Context, cwd string, args ...string) (exec.RunResult, error) {
return cli.run(ctx, cwd, nil, args...)
}
func (cli *Cli) run(ctx context.Context, cwd string, buildProgress io.Writer, args ...string) (exec.RunResult, error) {
runArgs := exec.
NewRunArgs("npx", "-y", swaCliPackage).
AppendParams(args...).
WithCwd(cwd)
if buildProgress != nil {
runArgs = runArgs.WithStdOut(buildProgress).WithStdErr(buildProgress)
}
return cli.commandRunner.Run(ctx, runArgs)
}
const swaConfigFileName = "swa-cli.config.json"
// check if the swa-cli.config.json file exists in the given directory
func ContainsSwaConfig(path string) (bool, error) {
_, err := os.Stat(filepath.Join(path, swaConfigFileName))
if os.IsNotExist(err) {
return false, nil
}
if err != nil {
return false, err
}
return true, nil
}