github.com/pluralsh/plural-cli@v0.9.5/pkg/api/repos.go (about)

     1  package api
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	_ "github.com/AlecAivazis/survey/v2"
    11  	"sigs.k8s.io/yaml"
    12  
    13  	"github.com/pluralsh/gqlclient"
    14  	"github.com/pluralsh/gqlclient/pkg/utils"
    15  	fileutils "github.com/pluralsh/plural-cli/pkg/utils"
    16  	"github.com/samber/lo"
    17  )
    18  
    19  type ResourceDefinitionInput struct {
    20  	Name string
    21  	Spec []Specification
    22  }
    23  
    24  type Specification struct {
    25  	Name     string
    26  	Type     string
    27  	Inner    string `json:"inner,omitempty"`
    28  	Required bool
    29  	Spec     []Specification `json:"spec,omitempty"`
    30  }
    31  
    32  type IntegrationInput struct {
    33  	Name        string
    34  	Description string
    35  	Icon        string
    36  	SourceURL   string `json:"sourceUrl,omitempty"`
    37  	Spec        string
    38  	Type        string `json:"type,omitempty"`
    39  	Tags        []Tag  `json:"tags,omitempty" yaml:"tags"`
    40  }
    41  
    42  type OauthSettings struct {
    43  	UriFormat  string `yaml:"uriFormat"`
    44  	AuthMethod string `yaml:"authMethod"`
    45  }
    46  
    47  type RepositoryInput struct {
    48  	Name          string
    49  	Description   string
    50  	ReleaseStatus string `json:"releaseStatus,omitempty" yaml:"releaseStatus,omitempty"`
    51  	Private       bool   `json:"private" yaml:"private,omitempty"`
    52  	Tags          []Tag  `json:"tags,omitempty" yaml:"tags"`
    53  	Icon          string `json:"icon,omitempty" yaml:"icon"`
    54  	DarkIcon      string `json:"darkIcon,omitempty" yaml:"darkIcon"`
    55  	Docs          string `json:"docs,omitempty" yaml:"docs"`
    56  	Contributors  []string
    57  	Category      string
    58  	Notes         string         `json:"notes,omitempty" yaml:"notes"`
    59  	GitUrl        string         `json:"gitUrl" yaml:"gitUrl"`
    60  	Homepage      string         `json:"homepage" yaml:"homepage"`
    61  	OauthSettings *OauthSettings `yaml:"oauthSettings,omitempty"`
    62  }
    63  
    64  type LockAttributes struct {
    65  	Lock string
    66  }
    67  
    68  type ScaffoldInputs struct {
    69  	Application string `survey:"application"`
    70  	Publisher   string `survey:"publisher"`
    71  	Category    string `survey:"category"`
    72  	Ingress     bool   `survey:"ingress"`
    73  	Postgres    bool   `survey:"postgres"`
    74  }
    75  
    76  func (client *client) GetRepository(repo string) (*Repository, error) {
    77  	resp, err := client.pluralClient.GetRepository(client.ctx, &repo)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	return convertRepository(resp.Repository), nil
    83  }
    84  
    85  func convertRepository(repo *gqlclient.RepositoryFragment) *Repository {
    86  	return &Repository{
    87  		Id:          repo.ID,
    88  		Name:        repo.Name,
    89  		Description: utils.ConvertStringPointer(repo.Description),
    90  		Icon:        utils.ConvertStringPointer(repo.Icon),
    91  		DarkIcon:    utils.ConvertStringPointer(repo.DarkIcon),
    92  		Notes:       utils.ConvertStringPointer(repo.Notes),
    93  		Publisher: &Publisher{
    94  			Name: repo.Publisher.Name,
    95  		},
    96  	}
    97  }
    98  
    99  func (client *client) CreateRepository(name, publisher string, input *gqlclient.RepositoryAttributes) error {
   100  	var uploads []gqlclient.Upload
   101  
   102  	iconUpload, err := getIconReader(input.Icon, "icon")
   103  	if err != nil {
   104  		return err
   105  	}
   106  
   107  	if iconUpload != nil {
   108  		input.Icon = lo.ToPtr("icon")
   109  		uploads = append(uploads, *iconUpload)
   110  	}
   111  
   112  	darkIconUpload, err := getIconReader(input.DarkIcon, "darkicon")
   113  	if err != nil {
   114  		return err
   115  	}
   116  
   117  	if darkIconUpload != nil {
   118  		input.DarkIcon = lo.ToPtr("darkicon")
   119  		uploads = append(uploads, *darkIconUpload)
   120  	}
   121  
   122  	if input.Docs != nil && *input.Docs != "" {
   123  		tarFile, err := tarDir(name, *input.Docs, "")
   124  		if err != nil {
   125  			return err
   126  		}
   127  		defer os.Remove(tarFile)
   128  
   129  		docsUpload, err := getIconReader(lo.ToPtr(tarFile), "docs")
   130  		if err != nil {
   131  			return err
   132  		}
   133  		input.Docs = lo.ToPtr("docs")
   134  		uploads = append(uploads, *docsUpload)
   135  	}
   136  
   137  	if input.Notes != nil && *input.Notes != "" {
   138  		file, _ := filepath.Abs(*input.Notes)
   139  		notes, err := fileutils.ReadFile(file)
   140  		if err != nil {
   141  			return err
   142  		}
   143  
   144  		input.Notes = &notes
   145  	}
   146  
   147  	_, err = client.pluralClient.CreateRepository(context.Background(), name, publisher, *input, gqlclient.WithFiles(uploads))
   148  	return err
   149  }
   150  
   151  func (client *client) AcquireLock(repo string) (*ApplyLock, error) {
   152  	resp, err := client.pluralClient.AcquireLock(client.ctx, repo)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  
   157  	return &ApplyLock{
   158  		Id:   resp.AcquireLock.ID,
   159  		Lock: utils.ConvertStringPointer(resp.AcquireLock.Lock),
   160  	}, err
   161  }
   162  
   163  func (client *client) ReleaseLock(repo, lock string) (*ApplyLock, error) {
   164  	resp, err := client.pluralClient.ReleaseLock(client.ctx, repo, gqlclient.LockAttributes{Lock: lock})
   165  	if err != nil {
   166  		return nil, err
   167  	}
   168  
   169  	return &ApplyLock{
   170  		Id:   resp.ReleaseLock.ID,
   171  		Lock: utils.ConvertStringPointer(resp.ReleaseLock.Lock),
   172  	}, nil
   173  }
   174  
   175  func (client *client) UnlockRepository(name string) error {
   176  	_, err := client.pluralClient.UnlockRepository(client.ctx, name)
   177  	if err != nil {
   178  		return err
   179  	}
   180  
   181  	return nil
   182  }
   183  
   184  func (client *client) ListRepositories(query string) ([]*Repository, error) {
   185  	resp, err := client.pluralClient.ListRepositories(client.ctx, &query)
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  
   190  	res := make([]*Repository, 0)
   191  	for _, edge := range resp.Repositories.Edges {
   192  		rep := &Repository{
   193  			Id:          edge.Node.ID,
   194  			Name:        edge.Node.Name,
   195  			Description: utils.ConvertStringPointer(edge.Node.Description),
   196  			Icon:        utils.ConvertStringPointer(edge.Node.Icon),
   197  			DarkIcon:    utils.ConvertStringPointer(edge.Node.DarkIcon),
   198  			Notes:       utils.ConvertStringPointer(edge.Node.Notes),
   199  			Publisher: &Publisher{
   200  				Name: edge.Node.Publisher.Name,
   201  			},
   202  			Recipes: []*Recipe{},
   203  		}
   204  		for _, rcp := range edge.Node.Recipes {
   205  			rep.Recipes = append(rep.Recipes, &Recipe{Name: rcp.Name})
   206  		}
   207  		res = append(res, rep)
   208  	}
   209  
   210  	return res, err
   211  }
   212  
   213  func (client *client) InstallVersion(tp, repo, name, vsn string) error {
   214  	tp = strings.ToUpper(tp)
   215  	dt := gqlclient.DependencyType(tp)
   216  	if !dt.IsValid() {
   217  		return fmt.Errorf("invalid package type %s", tp)
   218  	}
   219  
   220  	_, err := client.pluralClient.InstallVersion(context.Background(), dt, repo, name, vsn)
   221  	return err
   222  }
   223  
   224  func (client *client) Release(name string, tags []string) error {
   225  	_, err := client.pluralClient.Release(context.Background(), name, tags)
   226  	return err
   227  }
   228  
   229  func (client *client) Scaffolds(in *ScaffoldInputs) ([]*ScaffoldFile, error) {
   230  	scaffolds, err := client.pluralClient.Scaffolds(context.Background(), in.Application, in.Publisher, gqlclient.Category(strings.ToUpper(in.Category)), &in.Ingress, &in.Postgres)
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  
   235  	resp := make([]*ScaffoldFile, 0)
   236  
   237  	for _, scaffold := range scaffolds.Scaffold {
   238  		resp = append(resp, &ScaffoldFile{
   239  			Path:    utils.ConvertStringPointer(scaffold.Path),
   240  			Content: utils.ConvertStringPointer(scaffold.Content),
   241  		})
   242  	}
   243  
   244  	return resp, err
   245  }
   246  
   247  func getIconReader(icon *string, field string) (*gqlclient.Upload, error) {
   248  	if icon == nil {
   249  		return nil, nil
   250  	}
   251  	if *icon == "" {
   252  		return nil, nil
   253  	}
   254  
   255  	file, err := filepath.Abs(*icon)
   256  	if err != nil {
   257  		return nil, err
   258  	}
   259  	f, err := os.Open(file)
   260  	if err != nil {
   261  		return nil, err
   262  	}
   263  
   264  	return &gqlclient.Upload{
   265  		Field: field,
   266  		Name:  file,
   267  		R:     f,
   268  	}, nil
   269  }
   270  
   271  func ConstructRepositoryInput(marshalled []byte) (input *RepositoryInput, err error) {
   272  	input = &RepositoryInput{}
   273  	err = yaml.Unmarshal(marshalled, input)
   274  	return
   275  }
   276  
   277  func ConstructGqlClientRepositoryInput(marshalled []byte) (*gqlclient.RepositoryAttributes, error) {
   278  	repoInput, err := ConstructRepositoryInput(marshalled)
   279  	if err != nil {
   280  		return nil, err
   281  	}
   282  
   283  	category := gqlclient.Category(repoInput.Category)
   284  
   285  	var releaseStatus *gqlclient.ReleaseStatus
   286  	if repoInput.ReleaseStatus != "" {
   287  		releaseStatus = lo.ToPtr(gqlclient.ReleaseStatus(repoInput.ReleaseStatus))
   288  	}
   289  
   290  	resp := &gqlclient.RepositoryAttributes{
   291  		Category:      &category,
   292  		DarkIcon:      &repoInput.DarkIcon,
   293  		Description:   &repoInput.Description,
   294  		ReleaseStatus: releaseStatus,
   295  		Contributors:  lo.ToSlicePtr(repoInput.Contributors),
   296  		GitURL:        &repoInput.GitUrl,
   297  		Homepage:      &repoInput.Homepage,
   298  		Icon:          &repoInput.Icon,
   299  		Docs:          &repoInput.Docs,
   300  		Name:          &repoInput.Name,
   301  		Notes:         &repoInput.Notes,
   302  		Private:       &repoInput.Private,
   303  		Tags:          []*gqlclient.TagAttributes{},
   304  	}
   305  	if repoInput.OauthSettings != nil {
   306  		resp.OauthSettings = &gqlclient.OauthSettingsAttributes{
   307  			AuthMethod: gqlclient.OidcAuthMethod(repoInput.OauthSettings.AuthMethod),
   308  			URIFormat:  repoInput.OauthSettings.UriFormat,
   309  		}
   310  	}
   311  	for _, tag := range repoInput.Tags {
   312  		resp.Tags = append(resp.Tags, &gqlclient.TagAttributes{
   313  			Tag: tag.Tag,
   314  		})
   315  	}
   316  
   317  	return resp, nil
   318  }