Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add v3.0.0 Breaking Changes To Provider Schema #521

Merged
merged 17 commits into from
Sep 4, 2020
118 changes: 118 additions & 0 deletions github/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,124 @@ type Owner struct {
IsOrganization bool
}

func RateLimitedHTTPClient(client *http.Client) *http.Client {

client.Transport = NewEtagTransport(client.Transport)
client.Transport = NewRateLimitTransport(client.Transport)
client.Transport = logging.NewTransport("Github", client.Transport)

return client

}

func (c *Config) AuthenticatedHTTPClient() *http.Client {

ctx := context.Background()
tokenSource := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: c.Token},
)
client := oauth2.NewClient(ctx, tokenSource)

return RateLimitedHTTPClient(client)

}

func (c *Config) AnonymousHTTPClient() *http.Client {
client := &http.Client{Transport: &http.Transport{}}
return RateLimitedHTTPClient(client)
}

func (c *Config) NewGraphQLClient(client *http.Client) (*githubv4.Client, error) {

uv4, err := url.Parse(c.BaseURL)
if err != nil {
return nil, err
}
uv4.Path = path.Join(uv4.Path, "graphql")

return githubv4.NewEnterpriseClient(uv4.String(), client), nil

}

func (c *Config) NewRESTClient(client *http.Client) (*github.Client, error) {

uv3, err := url.Parse(c.BaseURL)
if err != nil {
return nil, err
}

if uv3.String() != "https://api.github.com/" {
uv3.Path = uv3.Path + "api/v3/"
}

v3client, err := github.NewEnterpriseClient(uv3.String(), "", client)
if err != nil {
return nil, err
}

v3client.BaseURL = uv3

return v3client, nil

}

func (c *Config) ConfigureOwner(owner *Owner) (*Owner, error) {

ctx := context.Background()
owner.name = c.Owner
if owner.name == "" {
// Discover authenticated user
user, _, err := owner.v3client.Users.Get(ctx, "")
if err != nil {
return nil, err
}
owner.name = user.GetLogin()
} else {
remoteOrg, _, err := owner.v3client.Organizations.Get(ctx, owner.name)
if err == nil {
if remoteOrg != nil {
owner.id = remoteOrg.GetID()
owner.IsOrganization = true
}
}
}

return owner, nil
}

// Meta returns the meta parameter that is passed into subsequent resources
// https://godoc.org/github.com/hashicorp/terraform-plugin-sdk/helper/schema#ConfigureFunc
func (c *Config) Meta() (interface{}, error) {

var client *http.Client
if c.Anonymous {
client = c.AnonymousHTTPClient()
} else {
client = c.AuthenticatedHTTPClient()
}

v3client, err := c.NewRESTClient(client)
if err != nil {
return nil, err
}

v4client, err := c.NewGraphQLClient(client)
if err != nil {
return nil, err
}

var owner Owner
owner.v4client = v4client
owner.v3client = v3client

if c.Anonymous {
return &owner, nil
} else {
return c.ConfigureOwner(&owner)
}

}

// Clients configures and returns a fully initialized GithubClient and Githubv4Client
func (c *Config) Clients() (interface{}, error) {
var owner Owner
Expand Down
217 changes: 149 additions & 68 deletions github/config_test.go
Original file line number Diff line number Diff line change
@@ -1,82 +1,163 @@
package github

import (
"context"
"testing"

"github.com/shurcooL/githubv4"
)

func TestConfigClients(t *testing.T) {

t.Run("returns a client for the v3 REST API", func(t *testing.T) {
// config := Config{
// Token: "token",
// Individual: true,
// }
//
// meta, err := config.Clients()
// if err != nil {
// t.Fatalf("failed to return clients without error: %s", err.Error())
// }
//
// if client := meta.(*Owner).v3client; client == nil {
// t.Fatalf("failed to return a v3 client")
// }
func TestAccConfigMeta(t *testing.T) {

if testToken == "" {
return
}

t.Run("returns an anonymous client for the v3 REST API", func(t *testing.T) {

config := Config{Anonymous: true, BaseURL: "https://api.github.com/"}
meta, err := config.Meta()
if err != nil {
t.Fatalf("failed to return meta without error: %s", err.Error())
}

ctx := context.Background()
client := meta.(*Owner).v3client
_, _, err = client.APIMeta(ctx)
if err != nil {
t.Fatalf("failed to validate returned client without error: %s", err.Error())
}

})

t.Run("returns an anonymous client for the v4 GraphQL API", func(t *testing.T) {

// https://developer.github.com/v4/guides/forming-calls/#authenticating-with-graphql
t.Skip("anonymous client for the v4 GraphQL API is unsupported")

})

t.Run("returns a v3 REST API client to manage individual resources", func(t *testing.T) {

config := Config{
Token: testToken,
BaseURL: "https://api.github.com/",
Anonymous: false,
}
meta, err := config.Meta()
if err != nil {
t.Fatalf("failed to return meta without error: %s", err.Error())
}

ctx := context.Background()
client := meta.(*Owner).v3client
_, _, err = client.APIMeta(ctx)
if err != nil {
t.Fatalf("failed to validate returned client without error: %s", err.Error())
}

})

t.Run("returns a v4 GraphQL API client to manage individual resources", func(t *testing.T) {

config := Config{
Token: testToken,
BaseURL: "https://api.github.com/",
Anonymous: false,
}
meta, err := config.Meta()
if err != nil {
t.Fatalf("failed to return meta without error: %s", err.Error())
}

client := meta.(*Owner).v4client
var query struct {
Meta struct {
GitHubServicesSha githubv4.String
}
}
err = client.Query(context.Background(), &query, nil)
if err != nil {
t.Fatalf("failed to validate returned client without error: %s", err.Error())
}

})

t.Run("returns a client for the v4 GraphQL API", func(t *testing.T) {
// config := Config{
// Token: "token",
// Individual: true,
// }
//
// meta, err := config.Clients()
// if err != nil {
// t.Fatalf("failed to return clients without error: %s", err.Error())
// }
//
// if client := meta.(*Owner).v4client; client == nil {
// t.Fatalf("failed to return a v4 client")
// }
t.Run("returns a v3 REST API client to manage organization resources", func(t *testing.T) {

config := Config{
Token: testToken,
BaseURL: "https://api.github.com/",
Organization: testOrganization,
Anonymous: false,
}
meta, err := config.Meta()
if err != nil {
t.Fatalf("failed to return meta without error: %s", err.Error())
}

ctx := context.Background()
client := meta.(*Owner).v3client
_, _, err = client.Organizations.Get(ctx, testOrganization)
if err != nil {
t.Fatalf("failed to validate returned client without error: %s", err.Error())
}

})

t.Run("returns clients configured as anonymous", func(t *testing.T) {
// config := Config{
// Token: "",
// Anonymous: true,
// Individual: true,
// }
//
// meta, err := config.Clients()
// if err != nil {
// t.Fatalf("failed to return clients without error: %s", err.Error())
// }
//
// if client := meta.(*Owner).v4client; client == nil {
// t.Fatalf("failed to return a v4 client")
// }
//
// if client := meta.(*Owner).v3client; client == nil {
// t.Fatalf("failed to return a v3 client")
// }
t.Run("returns a v4 GraphQL API client to manage organization resources", func(t *testing.T) {

config := Config{
Token: testToken,
BaseURL: "https://api.github.com/",
Organization: testOrganization,
Anonymous: false,
}
meta, err := config.Meta()
if err != nil {
t.Fatalf("failed to return meta without error: %s", err.Error())
}

client := meta.(*Owner).v4client

var query struct {
Organization struct {
ViewerCanAdminister githubv4.Boolean
} `graphql:"organization(login: $login)"`
}
variables := map[string]interface{}{
"login": githubv4.String(testOrganization),
}
err = client.Query(context.Background(), &query, variables)
if err != nil {
t.Fatalf("failed to validate returned client without error: %s", err.Error())
}

if query.Organization.ViewerCanAdminister != true {
t.Fatalf("unexpected response when validating client")
}

})

t.Run("returns clients configured as individual", func(t *testing.T) {
// config := Config{
// Organization: "",
// Anonymous: true,
// Individual: true,
// }
//
// meta, err := config.Clients()
// if err != nil {
// t.Fatalf("failed to return clients without error: %s", err.Error())
// }
//
// if client := meta.(*Owner).v4client; client == nil {
// t.Fatalf("failed to return a v4 client")
// }
//
// if client := meta.(*Owner).v3client; client == nil {
// t.Fatalf("failed to return a v3 client")
// }
t.Run("manages individual resources for a GHES deployment", func(t *testing.T) {
jcudit marked this conversation as resolved.
Show resolved Hide resolved

config := Config{
Token: testTokenGHES,
BaseURL: testBaseURLGHES,
Anonymous: false,
}
meta, err := config.Meta()
if err != nil {
t.Fatalf("failed to return meta without error: %s", err.Error())
}

ctx := context.Background()
client := meta.(*Owner).v3client
_, _, err = client.APIMeta(ctx)
if err != nil {
t.Fatalf("failed to validate returned client without error: %s", err.Error())
}

})

}
Loading