@@ -2,7 +2,6 @@ package ld
22
33import (
44 "bytes"
5- "context"
65 "encoding/csv"
76 "encoding/json"
87 "errors"
@@ -21,14 +20,13 @@ import (
2120 h "github.com/hashicorp/go-retryablehttp"
2221 "github.com/olekukonko/tablewriter"
2322
24- ldapi "github.com/launchdarkly/api-client-go/v7 "
23+ ldapi "github.com/launchdarkly/api-client-go/v15 "
2524 jsonpatch "github.com/launchdarkly/json-patch"
2625 "github.com/launchdarkly/ld-find-code-refs/v2/internal/log"
2726 "github.com/launchdarkly/ld-find-code-refs/v2/internal/validation"
2827)
2928
3029type ApiClient struct {
31- ldClient * ldapi.APIClient
3230 httpClient * h.Client
3331 Options ApiOptions
3432}
@@ -42,10 +40,10 @@ type ApiOptions struct {
4240}
4341
4442const (
45- apiVersion = "20210729 "
43+ apiVersion = "20220603 "
4644 apiVersionHeader = "LD-API-Version"
4745 v2ApiPath = "/api/v2"
48- reposPath = v2ApiPath + "/code-refs/repositories"
46+ reposPath = "/code-refs/repositories"
4947)
5048
5149type ConfigurationError struct {
@@ -113,62 +111,113 @@ func InitApiClient(options ApiOptions) ApiClient {
113111 client .Backoff = RateLimitBackoff (time .Now , h .LinearJitterBackoff )
114112
115113 return ApiClient {
116- ldClient : ldapi .NewAPIClient (& ldapi.Configuration {
117- HTTPClient : client .StandardClient (),
118- UserAgent : options .UserAgent ,
119- Servers : []ldapi.ServerConfiguration {{
120- URL : options .BaseUri ,
121- }},
122- DefaultHeader : map [string ]string {
123- apiVersionHeader : apiVersion ,
124- },
125- }),
126114 httpClient : client ,
127115 Options : options ,
128116 }
129117}
130118
119+ // path should have leading slash
120+ func (c ApiClient ) getPath (path string ) string {
121+ return fmt .Sprintf ("%s%s%s" , c .Options .BaseUri , v2ApiPath , path )
122+ }
123+
131124func (c ApiClient ) GetFlagKeyList (projKey string ) ([]string , error ) {
132- auth := map [string ]ldapi.APIKey {
133- "ApiKey" : {Key : c .Options .ApiKey },
125+ env , err := c .getProjectEnvironment (projKey )
126+ if err != nil {
127+ return nil , err
134128 }
135- ctx := context .WithValue (context .Background (), ldapi .ContextAPIKeys , auth )
136129
137- project , _ , err := c .ldClient .ProjectsApi .GetProject (ctx , projKey ).Execute () //nolint:bodyclose
130+ params := url.Values {}
131+ if env != nil {
132+ params .Add ("env" , env .Key )
133+ }
134+ activeFlags , err := c .getFlags (projKey , params )
138135 if err != nil {
139136 return nil , err
140137 }
141138
142- flagReq := c .ldClient .FeatureFlagsApi .GetFeatureFlags (ctx , projKey ).Summary (true )
143- archiveReq := c .ldClient .FeatureFlagsApi .GetFeatureFlags (ctx , projKey ).Summary (true ).Filter ("state:archived" )
139+ params .Add ("filter" , "state:archived" )
140+ archivedFlags , err := c .getFlags (projKey , params )
141+ if err != nil {
142+ return nil , err
143+ }
144+ flags := make ([]ldapi.FeatureFlag , 0 , len (activeFlags )+ len (archivedFlags ))
145+ flags = append (flags , activeFlags ... )
146+ flags = append (flags , archivedFlags ... )
144147
145- if len (project .Environments ) > 0 {
146- // The first environment allows filtering when retrieving flags.
147- firstEnv := project .Environments [0 ]
148- flagReq = flagReq .Env (firstEnv .Key )
149- archiveReq = archiveReq .Env (firstEnv .Key )
148+ flagKeys := make ([]string , 0 , len (flags ))
149+ for _ , flag := range flags {
150+ flagKeys = append (flagKeys , flag .Key )
150151 }
151152
152- flags , _ , err := flagReq .Execute () //nolint:bodyclose
153+ return flagKeys , nil
154+ }
155+
156+ // Get the first environment we can find for a project
157+ func (c ApiClient ) getProjectEnvironment (projKey string ) (* ldapi.Environment , error ) {
158+ urlStr := c .getPath (fmt .Sprintf ("/projects/%s/environments" , projKey ))
159+ req , err := h .NewRequest (http .MethodGet , urlStr , nil )
153160 if err != nil {
154161 return nil , err
155162 }
156163
157- archivedFlags , _ , err := archiveReq .Execute () //nolint:bodyclose
164+ params := url.Values {}
165+ params .Add ("limit" , "1" )
166+ req .URL .RawQuery = params .Encode ()
167+
168+ res , err := c .do (req )
158169 if err != nil {
159170 return nil , err
160171 }
161172
162- flagKeys := make ([]string , 0 , len (flags .Items ))
163- for _ , flag := range append (flags .Items , archivedFlags .Items ... ) {
164- flagKeys = append (flagKeys , flag .Key )
173+ resBytes , err := io .ReadAll (res .Body )
174+ if res != nil {
175+ defer res .Body .Close ()
176+ }
177+ if err != nil {
178+ return nil , err
165179 }
166180
167- return flagKeys , nil
181+ var collection ldapi.Environments
182+ if err := json .Unmarshal (resBytes , & collection ); err != nil {
183+ return nil , err
184+ }
185+ if len (collection .Items ) == 0 {
186+ return nil , nil
187+ }
188+
189+ env := collection .Items [0 ]
190+
191+ return & env , nil
168192}
169193
170- func (c ApiClient ) repoUrl () string {
171- return fmt .Sprintf ("%s%s" , c .Options .BaseUri , reposPath )
194+ func (c ApiClient ) getFlags (projKey string , params url.Values ) ([]ldapi.FeatureFlag , error ) {
195+ url := c .getPath (fmt .Sprintf ("/flags/%s" , projKey ))
196+ req , err := h .NewRequest (http .MethodGet , url , nil )
197+ if err != nil {
198+ return nil , err
199+ }
200+ req .URL .RawQuery = params .Encode ()
201+
202+ res , err := c .do (req )
203+ if err != nil {
204+ return nil , err
205+ }
206+
207+ resBytes , err := io .ReadAll (res .Body )
208+ if res != nil {
209+ defer res .Body .Close ()
210+ }
211+ if err != nil {
212+ return nil , err
213+ }
214+
215+ var flags ldapi.FeatureFlags
216+ if err := json .Unmarshal (resBytes , & flags ); err != nil {
217+ return nil , err
218+ }
219+
220+ return flags .Items , nil
172221}
173222
174223func (c ApiClient ) patchCodeReferenceRepository (currentRepo , repo RepoParams ) error {
@@ -187,7 +236,7 @@ func (c ApiClient) patchCodeReferenceRepository(currentRepo, repo RepoParams) er
187236 return err
188237 }
189238
190- req , err := h .NewRequest ("PATCH" , fmt .Sprintf ("%s/%s" , c . repoUrl () , repo .Name ), bytes .NewBuffer (patch ))
239+ req , err := h .NewRequest ("PATCH" , c . getPath ( fmt .Sprintf ("%s/%s" , reposPath , repo .Name ) ), bytes .NewBuffer (patch ))
191240 if err != nil {
192241 return err
193242 }
@@ -202,7 +251,7 @@ func (c ApiClient) patchCodeReferenceRepository(currentRepo, repo RepoParams) er
202251}
203252
204253func (c ApiClient ) getCodeReferenceRepository (name string ) (* RepoRep , error ) {
205- req , err := h .NewRequest ("GET" , fmt .Sprintf ("%s/%s" , c . repoUrl () , name ), nil )
254+ req , err := h .NewRequest ("GET" , c . getPath ( fmt .Sprintf ("%s/%s" , reposPath , name ) ), nil )
206255 if err != nil {
207256 return nil , err
208257 }
@@ -228,7 +277,7 @@ func (c ApiClient) getCodeReferenceRepository(name string) (*RepoRep, error) {
228277}
229278
230279func (c ApiClient ) GetCodeReferenceRepositoryBranches (repoName string ) ([]BranchRep , error ) {
231- req , err := h .NewRequest ("GET" , fmt .Sprintf ("%s/%s/branches" , c . repoUrl () , repoName ), nil )
280+ req , err := h .NewRequest ("GET" , c . getPath ( fmt .Sprintf ("%s/%s/branches" , reposPath , repoName ) ), nil )
232281 if err != nil {
233282 return nil , err
234283 }
@@ -259,7 +308,7 @@ func (c ApiClient) postCodeReferenceRepository(repo RepoParams) error {
259308 return err
260309 }
261310
262- req , err := h .NewRequest ("POST" , c .repoUrl ( ), bytes .NewBuffer (repoBytes ))
311+ req , err := h .NewRequest ("POST" , c .getPath ( reposPath ), bytes .NewBuffer (repoBytes ))
263312 if err != nil {
264313 return err
265314 }
@@ -330,7 +379,7 @@ func (c ApiClient) PutCodeReferenceBranch(branch BranchRep, repoName string) err
330379 if err != nil {
331380 return err
332381 }
333- putUrl := fmt .Sprintf ("%s%s /%s/branches/%s" , c . Options . BaseUri , reposPath , repoName , url .PathEscape (branch .Name ))
382+ putUrl := c . getPath ( fmt .Sprintf ("%s/%s/branches/%s" , reposPath , repoName , url .PathEscape (branch .Name ) ))
334383 req , err := h .NewRequest ("PUT" , putUrl , bytes .NewBuffer (branchBytes ))
335384 if err != nil {
336385 return err
@@ -350,7 +399,7 @@ func (c ApiClient) PostExtinctionEvents(extinctions []ExtinctionRep, repoName, b
350399 if err != nil {
351400 return err
352401 }
353- url := fmt .Sprintf ("%s%s /%s/branches/%s/extinction-events" , c . Options . BaseUri , reposPath , repoName , url .PathEscape (branchName ))
402+ url := c . getPath ( fmt .Sprintf ("%s/%s/branches/%s/extinction-events" , reposPath , repoName , url .PathEscape (branchName ) ))
354403 req , err := h .NewRequest ("POST" , url , bytes .NewBuffer (data ))
355404 if err != nil {
356405 return err
@@ -370,7 +419,7 @@ func (c ApiClient) PostDeleteBranchesTask(repoName string, branches []string) er
370419 if err != nil {
371420 return err
372421 }
373- url := fmt .Sprintf ("%s%s /%s/branch-delete-tasks" , c . Options . BaseUri , reposPath , repoName )
422+ url := c . getPath ( fmt .Sprintf ("%s/%s/branch-delete-tasks" , reposPath , repoName ) )
374423 req , err := h .NewRequest ("POST" , url , bytes .NewBuffer (body ))
375424 if err != nil {
376425 return err
0 commit comments