Skip to content

Commit

Permalink
ZEA-4010: Implement export template for CLI (#109)
Browse files Browse the repository at this point in the history
#### Description (required)

- **feat(project): Implement project export API**
- **feat(project): Implement project export CLI**

#### Related issues & labels (optional)

- Closes ZEA-4010
- Suggested label: enhancement
  • Loading branch information
Yuanlin Lin authored Sep 7, 2024
2 parents abe3f58 + 0d9b9f6 commit 63a211c
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 1 deletion.
76 changes: 76 additions & 0 deletions internal/cmd/project/export/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package export

import (
"context"
"fmt"

"github.com/spf13/cobra"

"github.com/zeabur/cli/internal/cmdutil"
"github.com/zeabur/cli/internal/util"
)

type Options struct {
ProjectID string
ProjectName string

EnvironmentID string
}

func NewCmdExport(f *cmdutil.Factory) *cobra.Command {
opts := Options{}

cmd := &cobra.Command{
Use: "export",
Short: "Export projects to Template Resource YAML",
RunE: func(cmd *cobra.Command, args []string) error {
return runExport(f, opts)
},
}

util.AddProjectParam(cmd, &opts.ProjectID, &opts.ProjectName)
cmd.Flags().StringVar(&opts.EnvironmentID, "environment", "", "Environment ID to export. If not specified, we export the default environment.")

return cmd
}

// runExport will export the project to a template resource YAML.
func runExport(f *cmdutil.Factory, opts Options) error {
if opts.ProjectID == "" && opts.ProjectName == "" {
return fmt.Errorf("please specify project by --name or --id")
}

if opts.ProjectID == "" && opts.ProjectName != "" {
project, err := util.GetProjectByName(f.Config, f.ApiClient, opts.ProjectName)
if err != nil {
return fmt.Errorf("get project %s failed: %w", opts.ProjectName, err)
}
opts.ProjectID = project.ID
}

if opts.EnvironmentID == "" {
environments, err := f.ApiClient.ListEnvironments(context.Background(), opts.ProjectID)
if err != nil {
return fmt.Errorf("list environments for project<%s> failed: %w", opts.ProjectID, err)
}

if len(environments) == 0 {
return fmt.Errorf("no environment found in project %s", opts.ProjectID)
}

opts.EnvironmentID = environments[0].ID
}

exportedTemplate, err := f.ApiClient.ExportProject(context.Background(), opts.ProjectID, opts.EnvironmentID)
if err != nil {
return fmt.Errorf("export environment<%s> of project<%s> failed: %w", opts.EnvironmentID, opts.ProjectID, err)
}

for _, warning := range exportedTemplate.Warnings {
f.Log.Warn(warning)
}

fmt.Println(exportedTemplate.ResourceYAML)

return nil
}
2 changes: 2 additions & 0 deletions internal/cmd/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

projectCreateCmd "github.com/zeabur/cli/internal/cmd/project/create"
projectDeleteCmd "github.com/zeabur/cli/internal/cmd/project/delete"
projectExportCmd "github.com/zeabur/cli/internal/cmd/project/export"
projectGetCmd "github.com/zeabur/cli/internal/cmd/project/get"
projectListCmd "github.com/zeabur/cli/internal/cmd/project/list"
)
Expand All @@ -23,6 +24,7 @@ func NewCmdProject(f *cmdutil.Factory) *cobra.Command {
cmd.AddCommand(projectListCmd.NewCmdList(f))
cmd.AddCommand(projectCreateCmd.NewCmdCreate(f))
cmd.AddCommand(projectDeleteCmd.NewCmdDelete(f))
cmd.AddCommand(projectExportCmd.NewCmdExport(f))

return cmd
}
1 change: 1 addition & 0 deletions pkg/api/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type (
GetProject(ctx context.Context, id string, ownerName string, name string) (*model.Project, error)
CreateProject(ctx context.Context, region string, name *string) (*model.Project, error)
DeleteProject(ctx context.Context, id string) error
ExportProject(ctx context.Context, id string, environmentID string) (*model.ExportedTemplate, error)

GetRegions(ctx context.Context) ([]model.Region, error)
}
Expand Down
18 changes: 18 additions & 0 deletions pkg/api/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,24 @@ func (c *client) GetProject(ctx context.Context, id string, ownerUsername string
return c.getProjectByID(ctx, id)
}

func (c *client) ExportProject(ctx context.Context, id string, environmentID string) (*model.ExportedTemplate, error) {
var query struct {
Project struct {
ExportedTemplate model.ExportedTemplate `graphql:"exportedTemplate(environmentID: $environmentID)"`
} `graphql:"project(_id: $id)"`
}

err := c.Query(ctx, &query, V{
"id": ObjectID(id),
"environmentID": environmentID,
})
if err != nil {
return nil, err
}

return &query.Project.ExportedTemplate, nil
}

func (c *client) getProjectByID(ctx context.Context, id string) (*model.Project, error) {
var query struct {
Project model.Project `graphql:"project(_id: $id)"`
Expand Down
9 changes: 8 additions & 1 deletion pkg/model/project.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package model

import (
"github.com/zeabur/cli/pkg/util"
"time"

"github.com/zeabur/cli/pkg/util"
)

// Note: it's not recommended to embed other models in a model,
Expand Down Expand Up @@ -103,3 +104,9 @@ type Region struct {
Coordinates []float64 `graphql:"coordinates"`
Provider RegionProvider `graphql:"provider"`
}

// ExportedTemplate is the exported template of the given project.
type ExportedTemplate struct {
ResourceYAML string `graphql:"resourceYAML"`
Warnings []string `graphql:"warnings"`
}

0 comments on commit 63a211c

Please sign in to comment.