-
Notifications
You must be signed in to change notification settings - Fork 237
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #842 from CircleCI-Public/main
Merge main in develop
- Loading branch information
Showing
15 changed files
with
577 additions
and
42 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package project | ||
|
||
// ProjectEnvironmentVariable is a Environment Variable of a Project | ||
type ProjectEnvironmentVariable struct { | ||
Name string | ||
Value string | ||
} | ||
|
||
// ProjectClient is the interface to interact with project and it's | ||
// components. | ||
type ProjectClient interface { | ||
ListAllEnvironmentVariables(vcs, org, project string) ([]*ProjectEnvironmentVariable, error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package project | ||
|
||
import ( | ||
"fmt" | ||
"net/url" | ||
|
||
"github.com/CircleCI-Public/circleci-cli/api/rest" | ||
"github.com/CircleCI-Public/circleci-cli/settings" | ||
) | ||
|
||
type projectRestClient struct { | ||
token string | ||
server string | ||
client *rest.Client | ||
} | ||
|
||
var _ ProjectClient = &projectRestClient{} | ||
|
||
type listProjectEnvVarsParams struct { | ||
vcs string | ||
org string | ||
project string | ||
pageToken string | ||
} | ||
|
||
type projectEnvVarResponse struct { | ||
Name string | ||
Value string | ||
} | ||
|
||
type listAllProjectEnvVarsResponse struct { | ||
Items []projectEnvVarResponse | ||
NextPageToken string `json:"next_page_token"` | ||
} | ||
|
||
// NewProjectRestClient returns a new projectRestClient satisfying the api.ProjectInterface | ||
// interface via the REST API. | ||
func NewProjectRestClient(config settings.Config) (*projectRestClient, error) { | ||
serverURL, err := config.ServerURL() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
client := &projectRestClient{ | ||
token: config.Token, | ||
server: serverURL.String(), | ||
client: rest.New(config.Host, &config), | ||
} | ||
|
||
return client, nil | ||
} | ||
|
||
// ListAllEnvironmentVariables returns all of the environment variables owned by the | ||
// given project. Note that pagination is not supported - we get all | ||
// pages of env vars and return them all. | ||
func (p *projectRestClient) ListAllEnvironmentVariables(vcs, org, project string) ([]*ProjectEnvironmentVariable, error) { | ||
res := make([]*ProjectEnvironmentVariable, 0) | ||
var nextPageToken string | ||
for { | ||
resp, err := p.listEnvironmentVariables(&listProjectEnvVarsParams{ | ||
vcs: vcs, | ||
org: org, | ||
project: project, | ||
pageToken: nextPageToken, | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
for _, ev := range resp.Items { | ||
res = append(res, &ProjectEnvironmentVariable{ | ||
Name: ev.Name, | ||
Value: ev.Value, | ||
}) | ||
} | ||
|
||
if resp.NextPageToken == "" { | ||
break | ||
} | ||
|
||
nextPageToken = resp.NextPageToken | ||
} | ||
return res, nil | ||
} | ||
|
||
func (c *projectRestClient) listEnvironmentVariables(params *listProjectEnvVarsParams) (*listAllProjectEnvVarsResponse, error) { | ||
path := fmt.Sprintf("project/%s/%s/%s/envvar", params.vcs, params.org, params.project) | ||
urlParams := url.Values{} | ||
if params.pageToken != "" { | ||
urlParams.Add("page-token", params.pageToken) | ||
} | ||
|
||
req, err := c.client.NewRequest("GET", &url.URL{Path: path, RawQuery: urlParams.Encode()}, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var resp listAllProjectEnvVarsResponse | ||
_, err = c.client.DoRequest(req, &resp) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &resp, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
package project_test | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"net/http/httptest" | ||
"net/url" | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/CircleCI-Public/circleci-cli/api/project" | ||
"github.com/CircleCI-Public/circleci-cli/settings" | ||
"github.com/CircleCI-Public/circleci-cli/version" | ||
"gotest.tools/v3/assert" | ||
) | ||
|
||
func getProjectRestClient(server *httptest.Server) (project.ProjectClient, error) { | ||
client := &http.Client{} | ||
|
||
return project.NewProjectRestClient(settings.Config{ | ||
RestEndpoint: "api/v2", | ||
Host: server.URL, | ||
HTTPClient: client, | ||
Token: "token", | ||
}) | ||
} | ||
|
||
func Test_projectRestClient_ListAllEnvironmentVariables(t *testing.T) { | ||
const ( | ||
vcsType = "github" | ||
orgName = "test-org" | ||
projName = "test-proj" | ||
) | ||
tests := []struct { | ||
name string | ||
handler http.HandlerFunc | ||
want []*project.ProjectEnvironmentVariable | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "Should handle a successful request with ListAllEnvironmentVariables", | ||
handler: func(w http.ResponseWriter, r *http.Request) { | ||
assert.Equal(t, r.Header.Get("circle-token"), "token") | ||
assert.Equal(t, r.Header.Get("accept"), "application/json") | ||
assert.Equal(t, r.Header.Get("user-agent"), version.UserAgent()) | ||
|
||
assert.Equal(t, r.Method, "GET") | ||
assert.Equal(t, r.URL.Path, fmt.Sprintf("/api/v2/project/%s/%s/%s/envvar", vcsType, orgName, projName)) | ||
|
||
w.Header().Set("Content-Type", "application/json") | ||
w.WriteHeader(http.StatusOK) | ||
_, err := w.Write([]byte(` | ||
{ | ||
"items": [{ | ||
"name": "foo", | ||
"value": "xxxx1234" | ||
}], | ||
"next_page_token": "" | ||
}`)) | ||
assert.NilError(t, err) | ||
}, | ||
want: []*project.ProjectEnvironmentVariable{ | ||
{ | ||
Name: "foo", | ||
Value: "xxxx1234", | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "Should handle a request containing next_page_token with ListAllEnvironmentVariables", | ||
handler: func(w http.ResponseWriter, r *http.Request) { | ||
u, err := url.ParseQuery(r.URL.RawQuery) | ||
assert.NilError(t, err) | ||
|
||
w.Header().Set("content-type", "application/json") | ||
w.WriteHeader(http.StatusOK) | ||
if tk := u.Get("page-token"); tk == "" { | ||
_, err := w.Write([]byte(` | ||
{ | ||
"items": [ | ||
{ | ||
"name": "foo1", | ||
"value": "xxxx1234" | ||
}, | ||
{ | ||
"name": "foo2", | ||
"value": "xxxx2345" | ||
} | ||
], | ||
"next_page_token": "pagetoken" | ||
}`)) | ||
assert.NilError(t, err) | ||
} else { | ||
assert.Equal(t, tk, "pagetoken") | ||
_, err := w.Write([]byte(` | ||
{ | ||
"items": [ | ||
{ | ||
"name": "bar1", | ||
"value": "xxxxabcd" | ||
}, | ||
{ | ||
"name": "bar2", | ||
"value": "xxxxbcde" | ||
} | ||
], | ||
"next_page_token": "" | ||
}`)) | ||
assert.NilError(t, err) | ||
} | ||
}, | ||
want: []*project.ProjectEnvironmentVariable{ | ||
{ | ||
Name: "foo1", | ||
Value: "xxxx1234", | ||
}, | ||
{ | ||
Name: "foo2", | ||
Value: "xxxx2345", | ||
}, | ||
{ | ||
Name: "bar1", | ||
Value: "xxxxabcd", | ||
}, | ||
{ | ||
Name: "bar2", | ||
Value: "xxxxbcde", | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "Should handle an error request with ListAllEnvironmentVariables", | ||
handler: func(w http.ResponseWriter, _ *http.Request) { | ||
w.Header().Set("content-type", "application/json") | ||
w.WriteHeader(http.StatusInternalServerError) | ||
_, err := w.Write([]byte(`{"message": "error"}`)) | ||
assert.NilError(t, err) | ||
}, | ||
wantErr: true, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
server := httptest.NewServer(tt.handler) | ||
defer server.Close() | ||
|
||
p, err := getProjectRestClient(server) | ||
assert.NilError(t, err) | ||
|
||
got, err := p.ListAllEnvironmentVariables(vcsType, orgName, projName) | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("projectRestClient.ListAllEnvironmentVariables() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if !reflect.DeepEqual(got, tt.want) { | ||
t.Errorf("projectRestClient.ListAllEnvironmentVariables() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.