Skip to content

Commit

Permalink
Merge pull request #361 from hashicorp/1.0.0
Browse files Browse the repository at this point in the history
1.0.0 release
  • Loading branch information
sebasslash committed Mar 17, 2022
2 parents 27f258e + b22204a commit e14f543
Show file tree
Hide file tree
Showing 137 changed files with 5,151 additions and 3,149 deletions.
20 changes: 19 additions & 1 deletion .golangci.yml
Expand Up @@ -10,10 +10,14 @@ linters:
- nestif #https://github.com/nakabonne/nestif
- exportloopref #https://github.com/kyoh86/exportloopref
- bodyclose #https://github.com/timakin/bodyclose
- goconst #https://github.com/jgautheron/goconst
- errcheck #https://github.com/kisielk/errcheck
- stylecheck #https://github.com/dominikh/go-tools/tree/master/stylecheck
- revive #golint is deprecated and golangci-lint recommends to use revive instead https://github.com/mgechev/revive
#other deprecated lint libraries: maligned, scopelint, interfacer
- gocritic #https://github.com/go-critic/go-critic
- unparam #https://github.com/mvdan/unparam
- misspell #https://github.com/client9/misspell
issues:
exclude-rules:
- path: _test\.go
Expand All @@ -25,6 +29,20 @@ linters-settings:
# https://github.com/kisielk/errcheck#excluding-functions
check-type-assertions: true
check-blank: true
goconst:
min-len: 20
min-occurrences: 5
ignore-calls: false
gocritic:
enabled-tags:
- diagnostic
- opinionated
- performance
disabled-checks:
- unnamedResult
- hugeParam
- singleCaseSwitch
- ifElseChain
revive:
# see https://github.com/mgechev/revive#available-rules for details.
ignore-generated-header: false #recommended in their configuration
Expand All @@ -33,4 +51,4 @@ linters-settings:
- name: indent-error-flow #Prevents redundant else statements
severity: warning
- name: useless-break
severity: warning
severity: warning
23 changes: 23 additions & 0 deletions CHANGELOG.md
@@ -0,0 +1,23 @@
# v1.0.0

## Breaking Changes
* Renamed methods named Generate to Create for `AgentTokens`, `OrganizationTokens`, `TeamTokens`, `UserTokens` by @sebasslash [#327](https://github.com/hashicorp/go-tfe/pull/327)
* Methods that express an action on a relationship have been prefixed with a verb, e.g `Current()` is now `ReadCurrent()` by @sebasslash [#327](https://github.com/hashicorp/go-tfe/pull/327)
* All list option structs are now pointers @uturunku1 [#309](https://github.com/hashicorp/go-tfe/pull/309)
* All errors have been refactored into constants in `errors.go` @uturunku1 [#310](https://github.com/hashicorp/go-tfe/pull/310)
* The `ID` field in Create/Update option structs has been renamed to `Type` in accordance with the JSON:API spec by @omarismail, @uturunku1 [#190](https://github.com/hashicorp/go-tfe/pull/190), [#323](https://github.com/hashicorp/go-tfe/pull/323), [#332](https://github.com/hashicorp/go-tfe/pull/332)
* Nested URL params (consisting of an organization, module and provider name) used to identify a `RegistryModule` have been refactored into a struct `RegistryModuleID` by @sebasslash [#337](https://github.com/hashicorp/go-tfe/pull/337)


## Enhancements
* Added missing include fields for `AdminRuns`, `AgentPools`, `ConfigurationVersions`, `OAuthClients`, `Organizations`, `PolicyChecks`, `PolicySets`, `Policies` and `RunTriggers` by @uturunku1 [#339](https://github.com/hashicorp/go-tfe/pull/339)
* Cleanup documentation and improve consistency by @uturunku1 [#331](https://github.com/hashicorp/go-tfe/pull/331)
* Add more linters to our CI pipeline by @sebasslash [#326](https://github.com/hashicorp/go-tfe/pull/326)
* Resolve `TFE_HOSTNAME` as fallback for `TFE_ADDRESS` by @sebasslash [#340](https://github.com/hashicorp/go-tfe/pull/326)
* Adds a `fetching` status to `RunStatus` and adds the `Archive` method to the ConfigurationVersions interface by @mpminardi [#338](https://github.com/hashicorp/go-tfe/pull/338)
* Added a `Download` method to the `ConfigurationVersions` interface by @tylerwolf [#358](https://github.com/hashicorp/go-tfe/pull/358)
* API Coverage documentation by @laurenolivia [#334](https://github.com/hashicorp/go-tfe/pull/334)

## Bug Fixes
* Fixed invalid memory address error when `AdminSMTPSettingsUpdateOptions.Auth` field is empty and accessed by @uturunku1 [#335](https://github.com/hashicorp/go-tfe/pull/335)

50 changes: 12 additions & 38 deletions README.md
Expand Up @@ -16,11 +16,9 @@ documentation and API, the platform will always be stated as 'Terraform
Enterprise' - but a feature will be explicitly noted as only supported in one or
the other, if applicable (rare).

Note this client is in beta and is subject to change (though it is generally
quite stable). We will indicate any breaking changes by releasing new versions.
Until the release of v1.0, any minor version changes will indicate possible
breaking changes. Patch version changes will be used for both bugfixes and
non-breaking changes.
## Version Information

Almost always, minor version changes will indicate backwards-compatible features and enhancements. Occasionally, function signature changes that reflect a bug fix may appear as a minor version change. Patch version changes will be used for bug fixes, performance improvements, and otherwise unimpactful changes.

## Installation

Expand Down Expand Up @@ -50,56 +48,32 @@ if err != nil {
log.Fatal(err)
}

orgs, err := client.Organizations.List(context.Background(), tfe.OrganizationListOptions{})
orgs, err := client.Organizations.List(context.Background(), nil)
if err != nil {
log.Fatal(err)
}
```

## Documentation

For complete usage of the API client, see the full [package docs](https://pkg.go.dev/github.com/hashicorp/go-tfe).
For complete usage of the API client, see the [full package docs](https://pkg.go.dev/github.com/hashicorp/go-tfe).

## API Coverage

This API client covers most of the existing Terraform Cloud API calls and is updated regularly to add new or missing endpoints. For a complete list of what is supported/unsupported, please [refer to this page](docs/COVERAGE.md).

## Examples

See the [examples directory](https://github.com/hashicorp/go-tfe/tree/main/examples).

## Running tests

See [TESTS.md](TESTS.md).
See [TESTS.md](docs/TESTS.md).

## Issues and Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md)
See [CONTRIBUTING.md](docs/CONTRIBUTING.md)

## Releases

Documentation updates and test fixes that only touch test files don't require a release or tag. You can just merge these changes into `main` once they have been approved.

### Creating a release

1. [Create a new release in GitHub](https://help.github.com/en/github/administering-a-repository/creating-releases) by clicking on "Releases" and then "Draft a new release"
1. Set the `Tag version` to a new tag, using [Semantic Versioning](https://semver.org/) as a guideline.
1. Set the `Target` as `main`.
1. Set the `Release title` to the tag you created, `vX.Y.Z`
1. Use the description section to describe why you're releasing and what changes you've made. You should include links to merged PRs. Use the following headers in the description of your release:
- BREAKING CHANGES: Use this for any changes that aren't backwards compatible. Include details on how to handle these changes.
- FEATURES: Use this for any large new features added,
- ENHANCEMENTS: Use this for smaller new features added
- BUG FIXES: Use this for any bugs that were fixed.
- NOTES: Use this section if you need to include any additional notes on things like upgrading, upcoming deprecations, or any other information you might want to highlight.

Markdown example:

```markdown
ENHANCEMENTS
* Add description of new small feature (#3)[link-to-pull-request]

BUG FIXES
* Fix description of a bug (#2)[link-to-pull-request]
* Fix description of another bug (#1)[link-to-pull-request]
```

1. Don't attach any binaries. The zip and tar.gz assets are automatically created and attached after you publish your release.
1. Click "Publish release" to save and publish your release.

See [RELEASES.md](docs/RELEASES.md)
67 changes: 52 additions & 15 deletions admin_organization.go
Expand Up @@ -15,7 +15,7 @@ var _ AdminOrganizations = (*adminOrganizations)(nil)
// TFE API docs: https://www.terraform.io/docs/cloud/api/admin/organizations.html
type AdminOrganizations interface {
// List all the organizations visible to the current user.
List(ctx context.Context, options AdminOrganizationListOptions) (*AdminOrganizationList, error)
List(ctx context.Context, options *AdminOrganizationListOptions) (*AdminOrganizationList, error)

// Read attributes of an existing organization via admin API.
Read(ctx context.Context, organization string) (*AdminOrganization, error)
Expand All @@ -27,7 +27,7 @@ type AdminOrganizations interface {
Delete(ctx context.Context, organization string) error

// ListModuleConsumers lists specific organizations in the Terraform Enterprise installation that have permission to use an organization's modules.
ListModuleConsumers(ctx context.Context, organization string, options AdminOrganizationListModuleConsumersOptions) (*AdminOrganizationList, error)
ListModuleConsumers(ctx context.Context, organization string, options *AdminOrganizationListModuleConsumersOptions) (*AdminOrganizationList, error)

// UpdateModuleConsumers specifies a list of organizations that can use modules from the sharing organization's private registry. Setting a list of module consumers will turn off global module sharing for an organization.
UpdateModuleConsumers(ctx context.Context, organization string, consumerOrganizations []string) error
Expand Down Expand Up @@ -72,17 +72,22 @@ type AdminOrganizationList struct {
Items []*AdminOrganization
}

// AdminOrgIncludeOpt represents the available options for include query params.
// https://www.terraform.io/docs/cloud/api/admin/organizations.html#available-related-resources
type AdminOrgIncludeOpt string

const AdminOrgOwners AdminOrgIncludeOpt = "owners"

// AdminOrganizationListOptions represents the options for listing organizations via Admin API.
type AdminOrganizationListOptions struct {
ListOptions

// A query string used to filter organizations.
// Optional: A query string used to filter organizations.
// Any organizations with a name or notification email partially matching this value will be returned.
Query *string `url:"q,omitempty"`

// A list of relations to include. See available resources
Query string `url:"q,omitempty"`
// Optional: A list of relations to include. See available resources
// https://www.terraform.io/docs/cloud/api/admin/organizations.html#available-related-resources
Include *string `url:"include"`
Include []AdminOrgIncludeOpt `url:"include,omitempty"`
}

// AdminOrganizationListModuleConsumersOptions represents the options for listing organization module consumers through the Admin API
Expand All @@ -95,9 +100,12 @@ type AdminOrganizationID struct {
}

// List all the organizations visible to the current user.
func (s *adminOrganizations) List(ctx context.Context, options AdminOrganizationListOptions) (*AdminOrganizationList, error) {
url := "admin/organizations"
req, err := s.client.newRequest("GET", url, &options)
func (s *adminOrganizations) List(ctx context.Context, options *AdminOrganizationListOptions) (*AdminOrganizationList, error) {
if err := options.valid(); err != nil {
return nil, err
}
u := "admin/organizations"
req, err := s.client.newRequest("GET", u, options)
if err != nil {
return nil, err
}
Expand All @@ -111,14 +119,15 @@ func (s *adminOrganizations) List(ctx context.Context, options AdminOrganization
return orgl, nil
}

func (s *adminOrganizations) ListModuleConsumers(ctx context.Context, organization string, options AdminOrganizationListModuleConsumersOptions) (*AdminOrganizationList, error) {
// ListModuleConsumers lists specific organizations in the Terraform Enterprise installation that have permission to use an organization's modules.
func (s *adminOrganizations) ListModuleConsumers(ctx context.Context, organization string, options *AdminOrganizationListModuleConsumersOptions) (*AdminOrganizationList, error) {
if !validStringID(&organization) {
return nil, ErrInvalidOrg
}

url := fmt.Sprintf("admin/organizations/%s/relationships/module-consumers", url.QueryEscape(organization))
u := fmt.Sprintf("admin/organizations/%s/relationships/module-consumers", url.QueryEscape(organization))

req, err := s.client.newRequest("GET", url, nil)
req, err := s.client.newRequest("GET", u, nil)
if err != nil {
return nil, err
}
Expand All @@ -132,6 +141,7 @@ func (s *adminOrganizations) ListModuleConsumers(ctx context.Context, organizati
return orgl, nil
}

// Read an organization by its name.
func (s *adminOrganizations) Read(ctx context.Context, organization string) (*AdminOrganization, error) {
if !validStringID(&organization) {
return nil, ErrInvalidOrg
Expand All @@ -152,6 +162,7 @@ func (s *adminOrganizations) Read(ctx context.Context, organization string) (*Ad
return org, nil
}

// Update an organization by its name.
func (s *adminOrganizations) Update(ctx context.Context, organization string, options AdminOrganizationUpdateOptions) (*AdminOrganization, error) {
if !validStringID(&organization) {
return nil, ErrInvalidOrg
Expand All @@ -172,12 +183,13 @@ func (s *adminOrganizations) Update(ctx context.Context, organization string, op
return org, nil
}

// UpdateModuleConsumers updates an organization to specify a list of organizations that can use modules from the sharing organization's private registry.
func (s *adminOrganizations) UpdateModuleConsumers(ctx context.Context, organization string, consumerOrganizationIDs []string) error {
if !validStringID(&organization) {
return ErrInvalidOrg
}

url := fmt.Sprintf("admin/organizations/%s/relationships/module-consumers", url.QueryEscape(organization))
u := fmt.Sprintf("admin/organizations/%s/relationships/module-consumers", url.QueryEscape(organization))

var organizations []*AdminOrganizationID
for _, id := range consumerOrganizationIDs {
Expand All @@ -187,7 +199,7 @@ func (s *adminOrganizations) UpdateModuleConsumers(ctx context.Context, organiza
organizations = append(organizations, &AdminOrganizationID{ID: id})
}

req, err := s.client.newRequest("PATCH", url, organizations)
req, err := s.client.newRequest("PATCH", u, organizations)
if err != nil {
return err
}
Expand All @@ -214,3 +226,28 @@ func (s *adminOrganizations) Delete(ctx context.Context, organization string) er

return s.client.do(ctx, req, nil)
}

func (o *AdminOrganizationListOptions) valid() error {
if o == nil {
return nil // nothing to validate
}

if err := validateAdminOrgIncludeParams(o.Include); err != nil {
return err
}

return nil
}

func validateAdminOrgIncludeParams(params []AdminOrgIncludeOpt) error {
for _, p := range params {
switch p {
case AdminOrgOwners:
// do nothing
default:
return ErrInvalidIncludeValue
}
}

return nil
}
18 changes: 9 additions & 9 deletions admin_organization_integration_test.go
Expand Up @@ -22,7 +22,7 @@ func TestAdminOrganizations_List(t *testing.T) {
defer orgTestCleanup()

t.Run("with no list options", func(t *testing.T) {
adminOrgList, err := client.Admin.Organizations.List(ctx, AdminOrganizationListOptions{})
adminOrgList, err := client.Admin.Organizations.List(ctx, nil)
require.NoError(t, err)

// Given that org creation occurs on every test, the ordering is not
Expand All @@ -36,8 +36,8 @@ func TestAdminOrganizations_List(t *testing.T) {
_, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()

adminOrgList, err := client.Admin.Organizations.List(ctx, AdminOrganizationListOptions{
Query: &org.Name,
adminOrgList, err := client.Admin.Organizations.List(ctx, &AdminOrganizationListOptions{
Query: org.Name,
})
assert.NoError(t, err)
assert.Equal(t, true, adminOrgItemsContainsName(adminOrgList.Items, org.Name))
Expand All @@ -48,8 +48,8 @@ func TestAdminOrganizations_List(t *testing.T) {
t.Run("with list options and org name that doesn't exist", func(t *testing.T) {
randomName := "random-org-name"

adminOrgList, err := client.Admin.Organizations.List(ctx, AdminOrganizationListOptions{
Query: &randomName,
adminOrgList, err := client.Admin.Organizations.List(ctx, &AdminOrganizationListOptions{
Query: randomName,
})
assert.NoError(t, err)
assert.Equal(t, false, adminOrgItemsContainsName(adminOrgList.Items, org.Name))
Expand All @@ -58,8 +58,8 @@ func TestAdminOrganizations_List(t *testing.T) {
})

t.Run("with owners included", func(t *testing.T) {
adminOrgList, err := client.Admin.Organizations.List(ctx, AdminOrganizationListOptions{
Include: String("owners"),
adminOrgList, err := client.Admin.Organizations.List(ctx, &AdminOrganizationListOptions{
Include: []AdminOrgIncludeOpt{AdminOrgOwners},
})
assert.NoError(t, err)

Expand Down Expand Up @@ -170,7 +170,7 @@ func TestAdminOrganizations_ModuleConsumers(t *testing.T) {
err := client.Admin.Organizations.UpdateModuleConsumers(ctx, org1.Name, []string{org2.Name})
assert.NoError(t, err)

adminModuleConsumerList, err := client.Admin.Organizations.ListModuleConsumers(ctx, org1.Name, AdminOrganizationListModuleConsumersOptions{})
adminModuleConsumerList, err := client.Admin.Organizations.ListModuleConsumers(ctx, org1.Name, nil)
require.NoError(t, err)

assert.Equal(t, len(adminModuleConsumerList.Items), 1)
Expand All @@ -182,7 +182,7 @@ func TestAdminOrganizations_ModuleConsumers(t *testing.T) {
err = client.Admin.Organizations.UpdateModuleConsumers(ctx, org1.Name, []string{org3.Name})
assert.NoError(t, err)

adminModuleConsumerList, err = client.Admin.Organizations.ListModuleConsumers(ctx, org1.Name, AdminOrganizationListModuleConsumersOptions{})
adminModuleConsumerList, err = client.Admin.Organizations.ListModuleConsumers(ctx, org1.Name, nil)
require.NoError(t, err)

assert.Equal(t, len(adminModuleConsumerList.Items), 1)
Expand Down

0 comments on commit e14f543

Please sign in to comment.