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 = ¬es 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 }