Skip to content

Commit

Permalink
Merge pull request #128 from hashicorp/lafentres/add-registry-modules
Browse files Browse the repository at this point in the history
Add support for registry modules & destination type email for notification configurations
  • Loading branch information
lafentres authored Jul 15, 2020
2 parents df39b50 + 1f69337 commit 6fdf7df
Show file tree
Hide file tree
Showing 10 changed files with 1,207 additions and 44 deletions.
64 changes: 41 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,40 @@ version changes will be used for both bugfixes and non-breaking changes.

Currently the following endpoints are supported:

- [x] [Accounts](https://www.terraform.io/docs/enterprise/api/account.html)
- [x] [Configuration Versions](https://www.terraform.io/docs/enterprise/api/configuration-versions.html)
- [x] [OAuth Clients](https://www.terraform.io/docs/enterprise/api/oauth-clients.html)
- [x] [OAuth Tokens](https://www.terraform.io/docs/enterprise/api/oauth-tokens.html)
- [x] [Organizations](https://www.terraform.io/docs/enterprise/api/organizations.html)
- [x] [Accounts](https://www.terraform.io/docs/cloud/api/account.html)
- [x] [Applies](https://www.terraform.io/docs/cloud/api/applies.html)
- [x] [Configuration Versions](https://www.terraform.io/docs/cloud/api/configuration-versions.html)
- [x] [Cost Estimates](https://www.terraform.io/docs/cloud/api/cost-estimates.html)
- [ ] [IP Ranges](https://www.terraform.io/docs/cloud/api/ip-ranges.html)
- [x] [Notification Configurations](https://www.terraform.io/docs/cloud/api/notification-configurations.html)
- [x] [OAuth Clients](https://www.terraform.io/docs/cloud/api/oauth-clients.html)
- [x] [OAuth Tokens](https://www.terraform.io/docs/cloud/api/oauth-tokens.html)
- [x] [Organizations](https://www.terraform.io/docs/cloud/api/organizations.html)
- [x] [Organization Memberships](https://www.terraform.io/docs/cloud/api/organization-memberships.html)
- [x] [Organization Tokens](https://www.terraform.io/docs/enterprise/api/organization-tokens.html)
- [x] [Policies](https://www.terraform.io/docs/enterprise/api/policies.html)
- [x] [Policy Set Parameters](https://www.terraform.io/docs/enterprise/api/policy-set-params.html)
- [x] [Policy Sets](https://www.terraform.io/docs/enterprise/api/policy-sets.html)
- [x] [Policy Checks](https://www.terraform.io/docs/enterprise/api/policy-checks.html)
- [ ] [Registry Modules](https://www.terraform.io/docs/enterprise/api/modules.html)
- [x] [Runs](https://www.terraform.io/docs/enterprise/api/run.html)
- [x] [Organization Tokens](https://www.terraform.io/docs/cloud/api/organization-tokens.html)
- [x] [Plan Exports](https://www.terraform.io/docs/cloud/api/plan-exports.html)
- [x] [Plans](https://www.terraform.io/docs/cloud/api/plans.html)
- [x] [Policies](https://www.terraform.io/docs/cloud/api/policies.html)
- [x] [Policy Checks](https://www.terraform.io/docs/cloud/api/policy-checks.html)
- [x] [Policy Sets](https://www.terraform.io/docs/cloud/api/policy-sets.html)
- [x] [Policy Set Parameters](https://www.terraform.io/docs/cloud/api/policy-set-params.html)
- [x] [Policy Checks](https://www.terraform.io/docs/cloud/api/policy-checks.html)
- [x] [Registry Modules](https://www.terraform.io/docs/cloud/api/modules.html)
- [x] [Runs](https://www.terraform.io/docs/cloud/api/run.html)
- [x] [Run Triggers](https://www.terraform.io/docs/cloud/api/run-triggers.html)
- [x] [SSH Keys](https://www.terraform.io/docs/enterprise/api/ssh-keys.html)
- [x] [State Versions](https://www.terraform.io/docs/enterprise/api/state-versions.html)
- [x] [Team Access](https://www.terraform.io/docs/enterprise/api/team-access.html)
- [x] [Team Memberships](https://www.terraform.io/docs/enterprise/api/team-members.html)
- [x] [Team Tokens](https://www.terraform.io/docs/enterprise/api/team-tokens.html)
- [x] [Teams](https://www.terraform.io/docs/enterprise/api/teams.html)
- [x] [Workspace Variables](https://www.terraform.io/docs/enterprise/api/workspace-variables.html)
- [x] [Workspaces](https://www.terraform.io/docs/enterprise/api/workspaces.html)
- [ ] [Admin](https://www.terraform.io/docs/enterprise/api/admin/index.html)
- [x] [SSH Keys](https://www.terraform.io/docs/cloud/api/ssh-keys.html)
- [x] [State Versions](https://www.terraform.io/docs/cloud/api/state-versions.html)
- [ ] [State Version Outputs](https://www.terraform.io/docs/cloud/api/state-version-outputs.html)
- [x] [Team Access](https://www.terraform.io/docs/cloud/api/team-access.html)
- [x] [Team Memberships](https://www.terraform.io/docs/cloud/api/team-members.html)
- [x] [Team Tokens](https://www.terraform.io/docs/cloud/api/team-tokens.html)
- [x] [Teams](https://www.terraform.io/docs/cloud/api/teams.html)
- [ ] [User Tokens](https://www.terraform.io/docs/cloud/api/user-tokens.html)
- [x] [Users](https://www.terraform.io/docs/cloud/api/users.html)
- [ ] [DEPRECATED] [Variables](https://www.terraform.io/docs/cloud/api/variables.html)
- [x] [Workspaces](https://www.terraform.io/docs/cloud/api/workspaces.html)
- [x] [Workspace Variables](https://www.terraform.io/docs/cloud/api/workspace-variables.html)
- [ ] [Admin](https://www.terraform.io/docs/cloud/api/admin/index.html)

## Installation

Expand Down Expand Up @@ -131,13 +142,19 @@ func main() {

## Running tests

### 1. (Optional) Create a policy sets repo
### 1. (Optional) Create repositories for policy sets and registry modules

If you are planning to run the full suite of tests or work on policy sets, you'll need to set up a policy set repository in GitHub.
If you are planning to run the full suite of tests or work on policy sets or registry modules, you'll need to set up repositories for them in GitHub.

Your policy set repository will need the following:
1. A policy set stored in a subdirectory `policy-sets/foo`
1. A branch other than master named `policies`

Your registry module repository will need to be a [valid module](https://www.terraform.io/docs/cloud/registry/publish.html#preparing-a-module-repository).
It will need the following:
1. To be named `terraform-<PROVIDER>-<NAME>`
1. At least one valid SemVer tag in the format `x.y.z`
[terraform-random-module](ttps://github.com/caseylang/terraform-random-module) is a good example repo.

### 2. Set up environment variables

Expand All @@ -150,6 +167,7 @@ and token.
##### Optional:
1. `GITHUB_TOKEN` - [GitHub personal access token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line). Required for running any tests that use VCS (OAuth clients, policy sets, etc).
1. `GITHUB_POLICY_SET_IDENTIFIER` - GitHub policy set repository identifier in the format `username/repository`. Required for running policy set tests.
1. `GITHUB_REGISTRY_MODULE_IDENTIFIER` - GitHub registry module repository identifier in the format `username/repository`. Required for running registry module tests.

You can set your environment variables up however you prefer. The following are instructions for setting up environment variables using [envchain](https://github.com/sorah/envchain).
1. Make sure you have envchain installed. [Instructions for this can be found in the envchain README](https://github.com/sorah/envchain#installation).
Expand Down
93 changes: 86 additions & 7 deletions helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,25 +90,29 @@ func createUploadedConfigurationVersion(t *testing.T, client *Client, w *Workspa
return cv, cvCleanup
}

func createNotificationConfiguration(t *testing.T, client *Client, w *Workspace) (*NotificationConfiguration, func()) {
func createNotificationConfiguration(t *testing.T, client *Client, w *Workspace, options *NotificationConfigurationCreateOptions) (*NotificationConfiguration, func()) {
var wCleanup func()

if w == nil {
w, wCleanup = createWorkspace(t, client, nil)
}

ctx := context.Background()
nc, err := client.NotificationConfigurations.Create(
ctx,
w.ID,
NotificationConfigurationCreateOptions{
if options == nil {
options = &NotificationConfigurationCreateOptions{
DestinationType: NotificationDestination(NotificationDestinationTypeGeneric),
Enabled: Bool(false),
Name: String(randomString(t)),
Token: String(randomString(t)),
URL: String("http://example.com"),
Triggers: []string{NotificationTriggerCreated},
},
}
}

ctx := context.Background()
nc, err := client.NotificationConfigurations.Create(
ctx,
w.ID,
*options,
)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -557,6 +561,81 @@ func createPlanExport(t *testing.T, client *Client, r *Run) (*PlanExport, func()
}
}

func createRegistryModule(t *testing.T, client *Client, org *Organization) (*RegistryModule, func()) {
var orgCleanup func()

if org == nil {
org, orgCleanup = createOrganization(t, client)
}

ctx := context.Background()

options := RegistryModuleCreateOptions{
Name: String("name"),
Provider: String("provider"),
}
rm, err := client.RegistryModules.Create(ctx, org.Name, options)
if err != nil {
t.Fatal(err)
}

return rm, func() {
if err := client.RegistryModules.Delete(ctx, org.Name, rm.Name); err != nil {
t.Errorf("Error destroying registry module! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"Registry Module: %s\nError: %s", rm.Name, err)
}

if orgCleanup != nil {
orgCleanup()
}
}
}

func createRegistryModuleWithVersion(t *testing.T, client *Client, org *Organization) (*RegistryModule, func()) {
var orgCleanup func()

if org == nil {
org, orgCleanup = createOrganization(t, client)
}

ctx := context.Background()

options := RegistryModuleCreateOptions{
Name: String("name"),
Provider: String("provider"),
}
rm, err := client.RegistryModules.Create(ctx, org.Name, options)
if err != nil {
t.Fatal(err)
}

optionsModuleVersion := RegistryModuleCreateVersionOptions{
Version: String("1.0.0"),
}
_, err = client.RegistryModules.CreateVersion(ctx, org.Name, rm.Name, rm.Provider, optionsModuleVersion)
if err != nil {
t.Fatal(err)
}

rm, err = client.RegistryModules.Read(ctx, org.Name, rm.Name, rm.Provider)
if err != nil {
t.Fatal(err)
}

return rm, func() {
if err := client.RegistryModules.Delete(ctx, org.Name, rm.Name); err != nil {
t.Errorf("Error destroying registry module! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"Registry Module: %s\nError: %s", rm.Name, err)
}

if orgCleanup != nil {
orgCleanup()
}
}
}

func createSSHKey(t *testing.T, client *Client, org *Organization) (*SSHKey, func()) {
var orgCleanup func()

Expand Down
36 changes: 29 additions & 7 deletions notification_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ type NotificationDestinationType string

// List of available notification destination types.
const (
NotificationDestinationTypeSlack NotificationDestinationType = "slack"
NotificationDestinationTypeEmail NotificationDestinationType = "email"
NotificationDestinationTypeGeneric NotificationDestinationType = "generic"
NotificationDestinationTypeSlack NotificationDestinationType = "slack"
)

// NotificationConfigurationList represents a list of Notification
Expand All @@ -82,8 +83,12 @@ type NotificationConfiguration struct {
UpdatedAt time.Time `jsonapi:"attr,updated-at,iso8601"`
URL string `jsonapi:"attr,url"`

// EmailAddresses is only available for TFE users. It is not available in TFC.
EmailAddresses []string `jsonapi:"attr,email-addresses"`

// Relations
Subscribable *Workspace `jsonapi:"relation,subscribable"`
EmailUsers []*User `jsonapi:"relation,users"`
}

// DeliveryResponse represents a notification configuration delivery response.
Expand Down Expand Up @@ -141,11 +146,18 @@ type NotificationConfigurationCreateOptions struct {
// The token of the notification configuration
Token *string `jsonapi:"attr,token,omitempty"`

// The destination type of the notification configuration
// The list of run events that will trigger notifications.
Triggers []string `jsonapi:"attr,triggers,omitempty"`

// The url of the notification configuration
URL *string `jsonapi:"attr,url"`
URL *string `jsonapi:"attr,url,omitempty"`

// The list of email addresses that will receive notification emails.
// EmailAddresses is only available for TFE users. It is not available in TFC.
EmailAddresses []string `jsonapi:"attr,email-addresses,omitempty"`

// The list of users belonging to the organization that will receive notification emails.
EmailUsers []*User `jsonapi:"relation,users,omitempty"`
}

func (o NotificationConfigurationCreateOptions) valid() error {
Expand All @@ -158,8 +170,11 @@ func (o NotificationConfigurationCreateOptions) valid() error {
if !validString(o.Name) {
return errors.New("name is required")
}
if !validString(o.URL) {
return errors.New("url is required")

if *o.DestinationType == NotificationDestinationTypeGeneric || *o.DestinationType == NotificationDestinationTypeSlack {
if o.URL == nil {
return errors.New("url is required")
}
}
return nil
}
Expand Down Expand Up @@ -191,7 +206,7 @@ func (s *notificationConfigurations) Create(ctx context.Context, workspaceID str
return nc, nil
}

// Read a notitification configuration by its ID.
// Read a notification configuration by its ID.
func (s *notificationConfigurations) Read(ctx context.Context, notificationConfigurationID string) (*NotificationConfiguration, error) {
if !validStringID(&notificationConfigurationID) {
return nil, errors.New("invalid value for notification configuration ID")
Expand Down Expand Up @@ -227,11 +242,18 @@ type NotificationConfigurationUpdateOptions struct {
// The token of the notification configuration
Token *string `jsonapi:"attr,token,omitempty"`

// The destination type of the notification configuration
// The list of run events that will trigger notifications.
Triggers []string `jsonapi:"attr,triggers,omitempty"`

// The url of the notification configuration
URL *string `jsonapi:"attr,url,omitempty"`

// The list of email addresses that will receive notification emails.
// EmailAddresses is only available for TFE users. It is not available in TFC.
EmailAddresses []string `jsonapi:"attr,email-addresses,omitempty"`

// The list of users belonging to the organization that will receive notification emails.
EmailUsers []*User `jsonapi:"relation,users,omitempty"`
}

// Updates a notification configuration with the given options.
Expand Down
Loading

0 comments on commit 6fdf7df

Please sign in to comment.