Skip to content

Commit

Permalink
feat: queue destroy plan in UI (#410)
Browse files Browse the repository at this point in the history
  • Loading branch information
leg100 authored Apr 26, 2023
1 parent c443fc1 commit 4aff44c
Show file tree
Hide file tree
Showing 19 changed files with 226 additions and 190 deletions.
6 changes: 3 additions & 3 deletions auth/team_web_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (

"github.com/google/uuid"
"github.com/leg100/otf"
"github.com/leg100/otf/http/html"
"github.com/leg100/otf/http/html/paths"
"github.com/leg100/otf/testutils"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -64,7 +64,7 @@ func TestTeam_WebHandlers(t *testing.T) {
r := httptest.NewRequest("GET", q, nil)
w := httptest.NewRecorder()
app.updateTeam(w, r)
html.AssertRedirect(t, w, paths.Team(team.ID))
testutils.AssertRedirect(t, w, paths.Team(team.ID))
})

t.Run("list", func(t *testing.T) {
Expand All @@ -89,7 +89,7 @@ func TestTeam_WebHandlers(t *testing.T) {
r := httptest.NewRequest("POST", q, nil)
w := httptest.NewRecorder()
app.deleteTeam(w, r)
html.AssertRedirect(t, w, paths.Teams("acme-org"))
testutils.AssertRedirect(t, w, paths.Teams("acme-org"))
})
}

Expand Down
3 changes: 3 additions & 0 deletions http/html/static/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,9 @@ a.show-underline {
display: flex;
flex-direction: column;
gap: 1em;
/* Add some white space between bottom of content and footer otherwise it
* looks wierd */
margin-bottom: 5em;
}

/* center content e.g. the login prompt */
Expand Down
7 changes: 7 additions & 0 deletions http/html/static/templates/content/workspace_edit.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
{{ $canDelete := $.CurrentUser.CanAccessWorkspace .DeleteWorkspaceAction .Policy }}
{{ $canSetPermission := $.CurrentUser.CanAccessWorkspace .SetWorkspacePermissionAction .Policy }}
{{ $canUnsetPermission := $.CurrentUser.CanAccessWorkspace .UnsetWorkspacePermissionAction .Policy }}
{{ $canCreateRun := $.CurrentUser.CanAccessWorkspace .CreateRunAction .Policy }}
<div>
{{ with .Workspace.Connection }}
<form action="{{ disconnectWorkspacePath $.Workspace.ID }}" method="POST">
Expand Down Expand Up @@ -139,6 +140,12 @@
</div>
<div class="permissions-container">
<h3>Advanced</h3>
<form action="{{ startRunWorkspacePath .Workspace.ID }}" method="POST">
<button id="queue-destroy-plan-button" class="delete" {{ insufficient $canCreateRun }} onclick="return confirm('This will destroy all infrastructure in this workspace. Please confirm.')">
Queue destroy plan
</button>
<input name="strategy" value="destroy-all" type="hidden">
</form>
<form action="{{ deleteWorkspacePath .Workspace.ID }}" method="POST">
<button id="delete-workspace-button" class="delete" {{ insufficient $canDelete }} onclick="return confirm('Are you sure you want to delete?')">
Delete workspace
Expand Down
15 changes: 0 additions & 15 deletions http/html/test_helpers.go

This file was deleted.

7 changes: 4 additions & 3 deletions integration/connect_repo_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/chromedp/chromedp"
"github.com/leg100/otf/cloud"
"github.com/leg100/otf/github"
"github.com/leg100/otf/testutils"
"github.com/stretchr/testify/require"
)

Expand All @@ -20,7 +21,7 @@ func TestConnectRepoE2E(t *testing.T) {
repo := cloud.NewTestRepo()
daemon := setup(t, nil,
github.WithRepo(repo),
github.WithArchive(readFile(t, "../testdata/github.tar.gz")),
github.WithArchive(testutils.ReadFile(t, "../testdata/github.tar.gz")),
)
user, ctx := daemon.createUserCtx(t, ctx)
org := daemon.createOrganization(t, ctx)
Expand All @@ -33,7 +34,7 @@ func TestConnectRepoE2E(t *testing.T) {
connectWorkspaceTasks(t, daemon.Hostname(), org.Name, "my-test-workspace"),
// we can now start a run via the web ui, which'll retrieve the tarball from
// the fake github server
startRunTasks(t, daemon.Hostname(), org.Name, "my-test-workspace"),
startRunTasks(t, daemon.Hostname(), org.Name, "my-test-workspace", "plan-and-apply"),
})
require.NoError(t, err)

Expand All @@ -42,7 +43,7 @@ func TestConnectRepoE2E(t *testing.T) {
// should trigger a run on the workspace.

// generate and send push event
push := readFile(t, "fixtures/github_push.json")
push := testutils.ReadFile(t, "fixtures/github_push.json")
daemon.SendEvent(t, github.PushEvent, push)

// commit-triggered run should appear as latest run on workspace
Expand Down
7 changes: 4 additions & 3 deletions integration/github_pr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/leg100/otf"
"github.com/leg100/otf/cloud"
"github.com/leg100/otf/github"
"github.com/leg100/otf/testutils"
"github.com/leg100/otf/workspace"
"github.com/stretchr/testify/require"
)
Expand All @@ -20,7 +21,7 @@ func TestIntegration_GithubPR(t *testing.T) {
repo := cloud.NewTestRepo()
daemon := setup(t, nil,
github.WithRepo(repo),
github.WithArchive(readFile(t, "../testdata/github.tar.gz")),
github.WithArchive(testutils.ReadFile(t, "../testdata/github.tar.gz")),
)

// create workspace connected to github repo
Expand All @@ -36,7 +37,7 @@ func TestIntegration_GithubPR(t *testing.T) {
require.NoError(t, err)

// a pull request is opened on github which triggers an event
push := readFile(t, "./fixtures/github_pull_opened.json")
push := testutils.ReadFile(t, "./fixtures/github_pull_opened.json")
daemon.SendEvent(t, github.PullRequest, push)

// github should receive three pending status updates followed by a final
Expand All @@ -49,7 +50,7 @@ func TestIntegration_GithubPR(t *testing.T) {
require.Equal(t, "planned: +2/~0/−0", got.GetDescription())

// the pull request is updated with another commit
update := readFile(t, "./fixtures/github_pull_update.json")
update := testutils.ReadFile(t, "./fixtures/github_pull_update.json")
daemon.SendEvent(t, github.PullRequest, update)

// github should receive three pending status updates followed by a final
Expand Down
5 changes: 3 additions & 2 deletions integration/module_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/chromedp/chromedp"
"github.com/leg100/otf/cloud"
"github.com/leg100/otf/github"
"github.com/leg100/otf/testutils"
"github.com/stretchr/testify/require"
)

Expand All @@ -23,7 +24,7 @@ func TestModuleE2E(t *testing.T) {
svc := setup(t, nil,
github.WithRepo(repo),
github.WithRefs("tags/v0.0.1", "tags/v0.0.2", "tags/v0.1.0"),
github.WithArchive(readFile(t, "./fixtures/github.module.tar.gz")),
github.WithArchive(testutils.ReadFile(t, "./fixtures/github.module.tar.gz")),
)
user, ctx := svc.createUserCtx(t, ctx)
org := svc.createOrganization(t, ctx)
Expand Down Expand Up @@ -66,7 +67,7 @@ func TestModuleE2E(t *testing.T) {
// should trigger a module version to be published.

// generate and send push tag event for v1.0.0
pushTpl := readFile(t, "fixtures/github_push_tag.json")
pushTpl := testutils.ReadFile(t, "fixtures/github_push_tag.json")
push := fmt.Sprintf(string(pushTpl), "v1.0.0", repo)
svc.SendEvent(t, github.PushEvent, []byte(push))

Expand Down
68 changes: 50 additions & 18 deletions integration/start_run_ui_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"

"github.com/chromedp/chromedp"
"github.com/leg100/otf/testutils"
"github.com/stretchr/testify/require"
)

Expand All @@ -13,29 +14,60 @@ func TestStartRunUI(t *testing.T) {
t.Parallel()

svc := setup(t, nil)

user, ctx := svc.createUserCtx(t, ctx)
org := svc.createOrganization(t, ctx)
root := newRootModule(t, svc.Hostname(), org.Name, "my-test-workspace")
ws := svc.createWorkspace(t, ctx, nil)
cv := svc.createConfigurationVersion(t, ctx, ws)
tarball := testutils.ReadFile(t, "./testdata/root.tar.gz")
svc.UploadConfig(ctx, cv.ID, tarball)

// in browser, create workspace
// now we have a config version, start a run with the plan-and-apply
// strategy
browser := createBrowserCtx(t)
err := chromedp.Run(browser,
err := chromedp.Run(browser, chromedp.Tasks{
newSession(t, ctx, svc.Hostname(), user.Username, svc.Secret),
createWorkspace(t, svc.Hostname(), org.Name, "my-test-workspace"),
)
startRunTasks(t, svc.Hostname(), ws.Organization, ws.Name, "plan-and-apply"),
})
require.NoError(t, err)

//
// start run UI functionality requires an existing config version, so
// create one first by running a plan via the CLI
//

// terraform init
svc.tfcli(t, ctx, "init", root)
out := svc.tfcli(t, ctx, "plan", root)
require.Contains(t, out, "Plan: 1 to add, 0 to change, 0 to destroy.")

// now we have a config version, start a run via the browser
err = chromedp.Run(browser, startRunTasks(t, svc.Hostname(), org.Name, "my-test-workspace"))
// now destroy resources with the destroy-all strategy
okDialog(t, browser)
err = chromedp.Run(browser, chromedp.Tasks{
// go to workspace page
chromedp.Navigate(workspaceURL(svc.Hostname(), ws.Organization, ws.Name)),
screenshot(t),
// navigate to workspace settings
chromedp.Click(`//a[text()='settings']`, chromedp.NodeVisible),
screenshot(t),
// click 'queue destroy plan' button
chromedp.Click(`//button[@id='queue-destroy-plan-button']`, chromedp.BySearch),
screenshot(t),
// confirm plan begins and ends
chromedp.WaitReady(`body`),
chromedp.WaitReady(`//*[@id='tailed-plan-logs']//text()[contains(.,'Initializing the backend')]`, chromedp.BySearch),
screenshot(t),
chromedp.WaitReady(`#plan-status.phase-status-finished`),
screenshot(t),
// wait for run to enter planned state
chromedp.WaitReady(`//*[@id='run-status']//*[normalize-space(text())='planned']`, chromedp.BySearch),
screenshot(t),
// run widget should show plan summary
matchRegex(t, `//div[@class='item']//div[@class='resource-summary']`, `\+[0-9]+ \~[0-9]+ \-[0-9]+`),
screenshot(t),
// run widget should show discard button
chromedp.WaitReady(`//button[@id='run-discard-button']`, chromedp.BySearch),
screenshot(t),
// click 'confirm & apply' button once it becomes visible
chromedp.Click(`//button[text()='apply']`, chromedp.NodeVisible, chromedp.BySearch),
screenshot(t),
// confirm apply begins and ends
chromedp.WaitReady(`//*[@id='tailed-apply-logs']//text()[contains(.,'Initializing the backend')]`, chromedp.BySearch),
chromedp.WaitReady(`#apply-status.phase-status-finished`),
// confirm run ends in applied state
chromedp.WaitReady(`//*[@id='run-status']//*[normalize-space(text())='applied']`, chromedp.BySearch),
// run widget should show apply summary
matchRegex(t, `//div[@class='item']//div[@class='resource-summary']`, `\+[0-9]+ \~[0-9]+ \-[0-9]+`),
screenshot(t),
})
require.NoError(t, err)
}
8 changes: 0 additions & 8 deletions integration/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,3 @@ resource "null_resource" "e2e" {}

return root
}

func readFile(t *testing.T, path string) []byte {
t.Helper()

contents, err := os.ReadFile(path)
require.NoError(t, err)
return contents
}
4 changes: 2 additions & 2 deletions integration/ui_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,13 @@ func createGithubVCSProviderTasks(t *testing.T, hostname, org, name string) chro
}

// startRunTasks starts a run via the UI
func startRunTasks(t *testing.T, hostname, organization string, workspaceName string) chromedp.Tasks {
func startRunTasks(t *testing.T, hostname, organization, workspaceName, strategy string) chromedp.Tasks {
return []chromedp.Action{
// go to workspace page
chromedp.Navigate(workspaceURL(hostname, organization, workspaceName)),
screenshot(t),
// select strategy for run
chromedp.SetValue(`//select[@id="start-run-strategy"]`, "plan-and-apply", chromedp.BySearch),
chromedp.SetValue(`//select[@id="start-run-strategy"]`, strategy, chromedp.BySearch),
screenshot(t),
// confirm plan begins and ends
chromedp.WaitReady(`body`),
Expand Down
3 changes: 2 additions & 1 deletion integration/webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/chromedp/chromedp"
"github.com/leg100/otf/cloud"
"github.com/leg100/otf/github"
"github.com/leg100/otf/testutils"
"github.com/stretchr/testify/require"
)

Expand All @@ -28,7 +29,7 @@ func TestWebhook(t *testing.T) {
svc := setup(t, nil,
github.WithRepo(repo),
github.WithRefs("tags/v0.0.1", "tags/v0.0.2", "tags/v0.1.0"),
github.WithArchive(readFile(t, "../testdata/github.tar.gz")),
github.WithArchive(testutils.ReadFile(t, "../testdata/github.tar.gz")),
)
user, ctx := svc.createUserCtx(t, ctx)
org := svc.createOrganization(t, ctx)
Expand Down
3 changes: 1 addition & 2 deletions organization/web_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/antchfx/htmlquery"
"github.com/leg100/otf"
"github.com/leg100/otf/http/html"
"github.com/leg100/otf/http/html/paths"
"github.com/leg100/otf/testutils"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -106,5 +105,5 @@ func TestWeb_DeleteHandler(t *testing.T) {
r := httptest.NewRequest("POST", "/?name=acme-corp", nil)
w := httptest.NewRecorder()
svc.delete(w, r)
html.AssertRedirect(t, w, paths.Organizations())
testutils.AssertRedirect(t, w, paths.Organizations())
}
Loading

0 comments on commit 4aff44c

Please sign in to comment.