Skip to content

Commit

Permalink
Merge branch 'main' into TF-1450
Browse files Browse the repository at this point in the history
# Conflicts:
#	CHANGELOG.md
  • Loading branch information
mrinalirao committed Nov 2, 2022
2 parents f656b57 + 804748d commit 15525b2
Show file tree
Hide file tree
Showing 20 changed files with 683 additions and 108 deletions.
14 changes: 13 additions & 1 deletion CHANGELOG.md
Expand Up @@ -2,9 +2,21 @@

## Enhancements

* Add `NotificationTriggerAssessmentCheckFailed` notification trigger type by @rexredinger [#549](https://github.com/hashicorp/go-tfe/pull/549)
* Add OPA support to the Policy Set API's by @mrinalirao [#575](https://github.com/hashicorp/go-tfe/pull/575)

# v1.12.0

## Enhancements

* Add `search[wildcard-name]` to `WorkspaceListOptions` by @laurenolivia [#569](https://github.com/hashicorp/go-tfe/pull/569)
* Add `NotificationTriggerAssessmentCheckFailed` notification trigger type by @rexredinger [#549](https://github.com/hashicorp/go-tfe/pull/549)
* Add `RemoteTFEVersion()` to the `Client` interface, which exposes the `X-TFE-Version` header set by a remote TFE instance by @sebasslash [#563](https://github.com/hashicorp/go-tfe/pull/563)
* Validate the module version as a version instead of an ID [#409](https://github.com/hashicorp/go-tfe/pull/409)
* Add `AllowForceDeleteWorkspaces` setting to `Organizations` by @JarrettSpiker [#539](https://github.com/hashicorp/go-tfe/pull/539)
* Add `SafeDelete` and `SafeDeleteID` APIs to `Workspaces` by @JarrettSpiker [#539](https://github.com/hashicorp/go-tfe/pull/539)
* Add `ForceExecute()` to `Runs` to allow force executing a run by @annawinkler [#570](https://github.com/hashicorp/go-tfe/pull/570)
* Pre-plan and Pre-Apply Run Tasks are now generally available (beta comments removed) by @glennsarti [#555](https://github.com/hashicorp/go-tfe/pull/555)

# v1.11.0

## Enhancements
Expand Down
3 changes: 2 additions & 1 deletion configuration_version_integration_test.go
Expand Up @@ -263,7 +263,8 @@ func TestConfigurationVersionsArchive(t *testing.T) {
// configuration version should not be archived, since it's the latest version
err = client.ConfigurationVersions.Archive(ctx, cv.ID)
assert.Error(t, err)
assert.EqualError(t, err, "transition not allowed")
assert.ErrorContains(t, err, "transition not allowed")
assert.ErrorContains(t, err, "configuration could not be archived because it is current")

// create subsequent version, since the latest configuration version cannot be archived
newCv, newCvCleanup := createConfigurationVersion(t, client, w)
Expand Down
33 changes: 23 additions & 10 deletions docs/CONTRIBUTING.md
Expand Up @@ -25,20 +25,10 @@ There are instances where several new resources being added (i.e Workspace Run T

The test suite contains many acceptance tests that are run against the latest version of Terraform Enterprise. You can read more about running the tests against your own Terraform Enterprise environment in [TESTS.md](TESTS.md). Our CI system (Github Actions) will not test your fork until a one-time approval takes place.

<<<<<<< HEAD
<<<<<<< HEAD
=======
## Test Splitting

Our CI workflow makes use of multiple nodes to run our tests in a more efficient manner. To prevent your test from running across all nodes, you **must** add `skipIfNotCINode(t)` to your top level test before any other helper or test logic.

>>>>>>> e307d93 (rename from checktestnode to skipIfNotCINode)
=======
## Test Splitting

Our CI workflow makes use of multiple nodes to run our tests in a more efficient manner. To prevent your test from running across all nodes, you **must** add `checkTestNodeEnv(t)` to your top level test before any other helper or test logic.

>>>>>>> d0e4157 (Update contributing docs to mention test splitting)
## Editor Settings

We've included VSCode settings to assist with configuring the go extension. For other editors that integrate with the [Go Language Server](https://github.com/golang/tools/tree/master/gopls), the main thing to do is to add the `integration` build tags so that the test files are found by the language server. See `.vscode/settings.json` for more details.
Expand Down Expand Up @@ -412,3 +402,26 @@ func validateExampleIncludeParams(params []ExampleIncludeOpt) error {
return nil
}
```

## Rebasing a fork to trigger CI (Maintainers Only)

Pull requests that originate from a fork will not have access to this repository's secrets, thus resulting in the inability to test against our CI instance. In order to trigger the CI action workflow, there is a handy script `./scripts/rebase-fork.sh` that automates the steps for you. It will:

* Checkout the fork PR locally onto your machine and create a new branch prefixed as follows: `local/{name_of_fork_branch}`
* Push your newly created branch to Github, appending an empty commit stating the original branch that was rebased.
* Copy the contents of the fork's pull request (title and description) and create a new pull request, triggering the CI workflow.

**Important**: This script does not handle subsequent commits to the original PR and would require you to rebase them manually. Therefore, it is important that authors include test results in their description and changes are approved before this script is executed.

This script depends on `gh` and `jq`. It also requires you to `gh auth login`, providing a SSO-authorized personal access token with the following scopes enabled:

- repo
- read:org
- read:discussion

### Example Usage

```sh
./scripts/rebase-fork.sh 557
```

1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -9,6 +9,7 @@ require (
github.com/hashicorp/go-retryablehttp v0.7.1
github.com/hashicorp/go-slug v0.10.0
github.com/hashicorp/go-uuid v1.0.3
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d
github.com/stretchr/testify v1.8.1
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Expand Up @@ -18,6 +18,8 @@ github.com/hashicorp/go-slug v0.10.0 h1:mh4DDkBJTh9BuEjY/cv8PTo7k9OjT4PcW8PgZnJ4
github.com/hashicorp/go-slug v0.10.0/go.mod h1:Ib+IWBYfEfJGI1ZyXMGNbu2BU+aa3Dzu41RKLH301v4=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d h1:9ARUJJ1VVynB176G1HCwleORqCaXm/Vx0uUi0dL26I0=
github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d/go.mod h1:Yog5+CPEM3c99L1CL2CFCYoSzgWm5vTU58idbRUaLik=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down
4 changes: 2 additions & 2 deletions helper_test.go
Expand Up @@ -1599,10 +1599,10 @@ func createWorkspaceWithOptions(t *testing.T, client *Client, org *Organization,
}

return w, func() {
if err := client.Workspaces.Delete(ctx, org.Name, w.Name); err != nil {
if err := client.Workspaces.DeleteByID(ctx, w.ID); err != nil {
t.Errorf("Error destroying workspace! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"Workspace: %s\nError: %s", w.Name, err)
"Workspace: %s\nError: %s", w.ID, err)
}

if orgCleanup != nil {
Expand Down
14 changes: 14 additions & 0 deletions mocks/run_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions mocks/workspace_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions organization.go
Expand Up @@ -78,6 +78,9 @@ type Organization struct {
TrialExpiresAt time.Time `jsonapi:"attr,trial-expires-at,iso8601"`
TwoFactorConformant bool `jsonapi:"attr,two-factor-conformant"`
SendPassingStatusesForUntriggeredSpeculativePlans bool `jsonapi:"attr,send-passing-statuses-for-untriggered-speculative-plans"`
// Note: This will be false for TFE versions older than v202211, where the setting was introduced.
// On those TFE versions, safe delete does not exist, so ALL deletes will be force deletes.
AllowForceDeleteWorkspaces bool `jsonapi:"attr,allow-force-delete-workspaces"`
}

// Capacity represents the current run capacity of an organization.
Expand Down Expand Up @@ -166,6 +169,9 @@ type OrganizationCreateOptions struct {

// Optional: SendPassingStatusesForUntriggeredSpeculativePlans toggles behavior of untriggered speculative plans to send status updates to version control systems like GitHub.
SendPassingStatusesForUntriggeredSpeculativePlans *bool `jsonapi:"attr,send-passing-statuses-for-untriggered-speculative-plans,omitempty"`

// Optional: AllowForceDeleteWorkspaces toggles behavior of allowing workspace admins to delete workspaces with resources under management.
AllowForceDeleteWorkspaces *bool `jsonapi:"attr,allow-force-delete-workspaces,omitempty"`
}

// OrganizationUpdateOptions represents the options for updating an organization.
Expand Down Expand Up @@ -202,6 +208,9 @@ type OrganizationUpdateOptions struct {

// SendPassingStatusesForUntriggeredSpeculativePlans toggles behavior of untriggered speculative plans to send status updates to version control systems like GitHub.
SendPassingStatusesForUntriggeredSpeculativePlans *bool `jsonapi:"attr,send-passing-statuses-for-untriggered-speculative-plans,omitempty"`

// Optional: AllowForceDeleteWorkspaces toggles behavior of allowing workspace admins to delete workspaces with resources under management.
AllowForceDeleteWorkspaces *bool `jsonapi:"attr,allow-force-delete-workspaces,omitempty"`
}

// ReadRunQueueOptions represents the options for showing the queue.
Expand Down
36 changes: 36 additions & 0 deletions organization_integration_test.go
Expand Up @@ -565,7 +565,43 @@ func TestOrganizationsReadRunTasksEntitlement(t *testing.T) {
assert.NotEmpty(t, entitlements.ID)
assert.True(t, entitlements.RunTasks)
})
}

func TestOrganizationsAllowForceDeleteSetting(t *testing.T) {
skipIfNotCINode(t)

client := testClient(t)
ctx := context.Background()

t.Run("creates and updates allow force delete", func(t *testing.T) {
options := OrganizationCreateOptions{
Name: String(randomString(t)),
Email: String(randomString(t) + "@tfe.local"),
AllowForceDeleteWorkspaces: Bool(true),
}

org, err := client.Organizations.Create(ctx, options)
require.NoError(t, err)

t.Cleanup(func() {
err := client.Organizations.Delete(ctx, org.Name)
if err != nil {
t.Errorf("error deleting organization (%s): %s", org.Name, err)
}
})

assert.Equal(t, *options.Name, org.Name)
assert.Equal(t, *options.Email, org.Email)
assert.True(t, org.AllowForceDeleteWorkspaces)

org, err = client.Organizations.Update(ctx, org.Name, OrganizationUpdateOptions{AllowForceDeleteWorkspaces: Bool(false)})
require.NoError(t, err)
assert.False(t, org.AllowForceDeleteWorkspaces)

org, err = client.Organizations.Read(ctx, org.Name)
require.NoError(t, err)
assert.False(t, org.AllowForceDeleteWorkspaces)
})
}

func orgItemsContainsName(items []*Organization, name string) bool {
Expand Down
4 changes: 2 additions & 2 deletions registry_module.go
Expand Up @@ -407,7 +407,7 @@ func (r *registryModules) DeleteVersion(ctx context.Context, moduleID RegistryMo
if !validString(&version) {
return ErrRequiredVersion
}
if !validStringID(&version) {
if !validVersion(version) {
return ErrInvalidVersion
}

Expand Down Expand Up @@ -499,7 +499,7 @@ func (o RegistryModuleCreateVersionOptions) valid() error {
if !validString(o.Version) {
return ErrRequiredVersion
}
if !validStringID(o.Version) {
if !validVersion(*o.Version) {
return ErrInvalidVersion
}
return nil
Expand Down
55 changes: 55 additions & 0 deletions registry_module_integration_test.go
Expand Up @@ -272,6 +272,21 @@ func TestRegistryModulesCreateVersion(t *testing.T) {
})
})

t.Run("with prerelease and metadata version", func(t *testing.T) {
options := RegistryModuleCreateVersionOptions{
Version: String("1.2.3-alpha+feature"),
}

rmv, err := client.RegistryModules.CreateVersion(ctx, RegistryModuleID{
Organization: orgTest.Name,
Name: registryModuleTest.Name,
Provider: registryModuleTest.Provider,
}, options)
require.NoError(t, err)
assert.NotEmpty(t, rmv.ID)
assert.Equal(t, *options.Version, rmv.Version)
})

t.Run("with invalid options", func(t *testing.T) {
t.Run("without version", func(t *testing.T) {
options := RegistryModuleCreateVersionOptions{}
Expand Down Expand Up @@ -825,6 +840,46 @@ func TestRegistryModulesDeleteVersion(t *testing.T) {
assert.Equal(t, registryModuleTest.VersionStatuses, rm.VersionStatuses)
})

t.Run("with prerelease and metadata version", func(t *testing.T) {
options := RegistryModuleCreateVersionOptions{
Version: String("1.2.3-alpha+feature"),
}
rmv, err := client.RegistryModules.CreateVersion(ctx, RegistryModuleID{
Organization: orgTest.Name,
Name: registryModuleTest.Name,
Provider: registryModuleTest.Provider,
}, options)
require.NoError(t, err)
require.NotEmpty(t, rmv.Version)

rm, err := client.RegistryModules.Read(ctx, RegistryModuleID{
Organization: orgTest.Name,
Name: registryModuleTest.Name,
Provider: registryModuleTest.Provider,
})
require.NoError(t, err)
require.NotEmpty(t, rm.VersionStatuses)
require.Equal(t, 2, len(rm.VersionStatuses))

err = client.RegistryModules.DeleteVersion(ctx, RegistryModuleID{
Organization: orgTest.Name,
Name: registryModuleTest.Name,
Provider: registryModuleTest.Provider,
}, rmv.Version)
require.NoError(t, err)

rm, err = client.RegistryModules.Read(ctx, RegistryModuleID{
Organization: orgTest.Name,
Name: registryModuleTest.Name,
Provider: registryModuleTest.Provider,
})
require.NoError(t, err)
assert.NotEmpty(t, rm.VersionStatuses)
assert.Equal(t, 1, len(rm.VersionStatuses))
assert.NotEqual(t, registryModuleTest.VersionStatuses[0].Version, rmv.Version)
assert.Equal(t, registryModuleTest.VersionStatuses, rm.VersionStatuses)
})

t.Run("without a name", func(t *testing.T) {
err := client.RegistryModules.DeleteVersion(ctx, RegistryModuleID{
Organization: orgTest.Name,
Expand Down
23 changes: 23 additions & 0 deletions run.go
Expand Up @@ -36,6 +36,9 @@ type Runs interface {
// Force-cancel a run by its ID.
ForceCancel(ctx context.Context, runID string, options RunForceCancelOptions) error

// Force execute a run by its ID.
ForceExecute(ctx context.Context, runID string) error

// Discard a run by its ID.
Discard(ctx context.Context, runID string, options RunDiscardOptions) error
}
Expand Down Expand Up @@ -464,6 +467,26 @@ func (s *runs) ForceCancel(ctx context.Context, runID string, options RunForceCa
return req.Do(ctx, nil)
}

// ForceExecute is used to forcefully execute a run by its ID.
//
// Note: While useful at times, force-executing a run circumvents the typical
// workflow of applying runs using Terraform Cloud. It is not intended for
// regular use. If you find yourself using it frequently, please reach out to
// HashiCorp Support for help in developing an alternative approach.
func (s *runs) ForceExecute(ctx context.Context, runID string) error {
if !validStringID(&runID) {
return ErrInvalidRunID
}

u := fmt.Sprintf("runs/%s/actions/force-execute", url.QueryEscape(runID))
req, err := s.client.NewRequest("POST", u, nil)
if err != nil {
return err
}

return req.Do(ctx, nil)
}

// Discard a run by its ID.
func (s *runs) Discard(ctx context.Context, runID string, options RunDiscardOptions) error {
if !validStringID(&runID) {
Expand Down

0 comments on commit 15525b2

Please sign in to comment.