mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: notify on workspace update (#15979)
Relates to https://github.com/coder/coder/issues/15845 When the `/workspace/<name>/builds` endpoint is hit, we check if the requested template version is different to the previously used template version. If these values differ, we can assume that the workspace has been manually updated and send the appropriate notification. Automatic updates happen in the lifecycle executor and bypasses this endpoint entirely.
This commit is contained in:
@@ -27,6 +27,8 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/database/dbtestutil"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/coderd/notifications"
|
||||
"github.com/coder/coder/v2/coderd/notifications/notificationstest"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/provisioner/echo"
|
||||
@@ -560,6 +562,104 @@ func TestWorkspaceBuildResources(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestWorkspaceBuildWithUpdatedTemplateVersionSendsNotification(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("OnlyOneNotification", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
notify := ¬ificationstest.FakeEnqueuer{}
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, NotificationsEnqueuer: notify})
|
||||
first := coderdtest.CreateFirstUser(t, client)
|
||||
userClient, user := coderdtest.CreateAnotherUser(t, client, first.OrganizationID)
|
||||
|
||||
// Create a template with an initial version
|
||||
version := coderdtest.CreateTemplateVersion(t, client, first.OrganizationID, nil)
|
||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
||||
template := coderdtest.CreateTemplate(t, client, first.OrganizationID, version.ID)
|
||||
|
||||
// Create a workspace using this template
|
||||
workspace := coderdtest.CreateWorkspace(t, userClient, template.ID)
|
||||
coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, workspace.LatestBuild.ID)
|
||||
coderdtest.MustTransitionWorkspace(t, userClient, workspace.ID, database.WorkspaceTransitionStart, database.WorkspaceTransitionStop)
|
||||
|
||||
// Create a new version of the template
|
||||
newVersion := coderdtest.CreateTemplateVersion(t, client, first.OrganizationID, nil, func(ctvr *codersdk.CreateTemplateVersionRequest) {
|
||||
ctvr.TemplateID = template.ID
|
||||
})
|
||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, newVersion.ID)
|
||||
|
||||
// Create a workspace build using this new template version
|
||||
build := coderdtest.CreateWorkspaceBuild(t, userClient, workspace, database.WorkspaceTransitionStart, func(cwbr *codersdk.CreateWorkspaceBuildRequest) {
|
||||
cwbr.TemplateVersionID = newVersion.ID
|
||||
})
|
||||
coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, build.ID)
|
||||
coderdtest.MustTransitionWorkspace(t, userClient, workspace.ID, database.WorkspaceTransitionStart, database.WorkspaceTransitionStop)
|
||||
|
||||
// Create the workspace build _again_. We are doing this to ensure we only create 1 notification.
|
||||
build = coderdtest.CreateWorkspaceBuild(t, userClient, workspace, database.WorkspaceTransitionStart, func(cwbr *codersdk.CreateWorkspaceBuildRequest) {
|
||||
cwbr.TemplateVersionID = newVersion.ID
|
||||
})
|
||||
coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, build.ID)
|
||||
coderdtest.MustTransitionWorkspace(t, userClient, workspace.ID, database.WorkspaceTransitionStart, database.WorkspaceTransitionStop)
|
||||
|
||||
// Ensure we receive only 1 workspace manually updated notification
|
||||
sent := notify.Sent(notificationstest.WithTemplateID(notifications.TemplateWorkspaceManuallyUpdated))
|
||||
require.Len(t, sent, 1)
|
||||
require.Equal(t, user.ID, sent[0].UserID)
|
||||
require.Contains(t, sent[0].Targets, template.ID)
|
||||
require.Contains(t, sent[0].Targets, workspace.ID)
|
||||
require.Contains(t, sent[0].Targets, workspace.OrganizationID)
|
||||
require.Contains(t, sent[0].Targets, workspace.OwnerID)
|
||||
})
|
||||
|
||||
t.Run("ToCorrectUser", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
notify := ¬ificationstest.FakeEnqueuer{}
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, NotificationsEnqueuer: notify})
|
||||
first := coderdtest.CreateFirstUser(t, client)
|
||||
userClient, user := coderdtest.CreateAnotherUser(t, client, first.OrganizationID)
|
||||
|
||||
// Create a template with an initial version
|
||||
version := coderdtest.CreateTemplateVersion(t, client, first.OrganizationID, nil)
|
||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
||||
template := coderdtest.CreateTemplate(t, client, first.OrganizationID, version.ID)
|
||||
|
||||
// Create a workspace using this template
|
||||
workspace := coderdtest.CreateWorkspace(t, userClient, template.ID)
|
||||
coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, workspace.LatestBuild.ID)
|
||||
coderdtest.MustTransitionWorkspace(t, userClient, workspace.ID, database.WorkspaceTransitionStart, database.WorkspaceTransitionStop)
|
||||
|
||||
// Create a new version of the template
|
||||
newVersion := coderdtest.CreateTemplateVersion(t, client, first.OrganizationID, nil, func(ctvr *codersdk.CreateTemplateVersionRequest) {
|
||||
ctvr.TemplateID = template.ID
|
||||
})
|
||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, newVersion.ID)
|
||||
|
||||
// Create a workspace build using this new template version from a different user
|
||||
ctx := testutil.Context(t, testutil.WaitShort)
|
||||
build, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
|
||||
Transition: codersdk.WorkspaceTransitionStart,
|
||||
TemplateVersionID: newVersion.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, build.ID)
|
||||
coderdtest.MustTransitionWorkspace(t, userClient, workspace.ID, database.WorkspaceTransitionStart, database.WorkspaceTransitionStop)
|
||||
|
||||
// Ensure we receive only 1 workspace manually updated notification and to the right user
|
||||
sent := notify.Sent(notificationstest.WithTemplateID(notifications.TemplateWorkspaceManuallyUpdated))
|
||||
require.Len(t, sent, 1)
|
||||
require.Equal(t, user.ID, sent[0].UserID)
|
||||
require.Contains(t, sent[0].Targets, template.ID)
|
||||
require.Contains(t, sent[0].Targets, workspace.ID)
|
||||
require.Contains(t, sent[0].Targets, workspace.OrganizationID)
|
||||
require.Contains(t, sent[0].Targets, workspace.OwnerID)
|
||||
})
|
||||
}
|
||||
|
||||
func assertWorkspaceResource(t *testing.T, actual codersdk.WorkspaceResource, name, aType string, numAgents int) {
|
||||
assert.Equal(t, name, actual.Name)
|
||||
assert.Equal(t, aType, actual.Type)
|
||||
|
||||
Reference in New Issue
Block a user