Skip to content

Commit

Permalink
Add support for attaching a VCS in CreateWorkspace (#321)
Browse files Browse the repository at this point in the history
- Introduce the function CreateWorkspace that creates both the workspace
  resource and potentially tries to connect it immediately (inside a
  transaction) if a repository was provided.
- Fixed newChildApp to make the Authorizer use the transaction.
- Added support to specify a branch for the repository.
  • Loading branch information
fsaintjacques authored Mar 5, 2023
1 parent dfcf3ec commit 2c04182
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 19 deletions.
2 changes: 1 addition & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func newChildApp(parent *Application, opts Options, db otf.DB) *Application {
cache: opts.Cache,
PubSubService: opts.PubSub,
Service: opts.CloudService,
Authorizer: opts.Authorizer,
Authorizer: otf.NewAuthorizer(opts.Logger, db),
StateVersionService: opts.StateVersionService,
RunFactory: parent.RunFactory,
proxy: parent.proxy,
Expand Down
17 changes: 16 additions & 1 deletion http/workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,21 @@ func (s *Server) CreateWorkspace(w http.ResponseWriter, r *http.Request) {
return
}

ws, err := s.Application.CreateWorkspace(r.Context(), otf.CreateWorkspaceOptions{
var repo *otf.WorkspaceRepo
if opts.VCSRepo != nil {
repo = new(otf.WorkspaceRepo)
if identifier := opts.VCSRepo.Identifier; identifier != nil {
repo.Identifier = *identifier
}
if branch := opts.VCSRepo.Branch; branch != nil {
repo.Branch = *branch
}
if providerID := opts.VCSRepo.OAuthTokenID; providerID != nil {
repo.ProviderID = *providerID
}
}

ws, err := otf.CreateWorkspace(r.Context(), s.Application, otf.CreateWorkspaceOptions{
AllowDestroyPlan: opts.AllowDestroyPlan,
AutoApply: opts.AutoApply,
Description: opts.Description,
Expand All @@ -154,6 +168,7 @@ func (s *Server) CreateWorkspace(w http.ResponseWriter, r *http.Request) {
TerraformVersion: opts.TerraformVersion,
TriggerPrefixes: opts.TriggerPrefixes,
WorkingDirectory: opts.WorkingDirectory,
Repo: repo,
})
if err != nil {
writeError(w, http.StatusNotFound, err)
Expand Down
12 changes: 1 addition & 11 deletions sql/workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,7 @@ func (db *DB) CreateWorkspace(ctx context.Context, ws *otf.Workspace) error {
if err != nil {
return Error(err)
}
if ws.Repo() != nil {
_, err = tx.InsertWorkspaceRepo(ctx, pggen.InsertWorkspaceRepoParams{
Branch: String(ws.Repo().Branch),
WebhookID: UUID(ws.Repo().WebhookID),
VCSProviderID: String(ws.Repo().ProviderID),
WorkspaceID: String(ws.ID()),
})
if err != nil {
return Error(err)
}
}

return nil
})
if err != nil {
Expand Down
36 changes: 35 additions & 1 deletion workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ package otf

import (
"context"
"errors"
"time"

"github.com/google/uuid"
"github.com/leg100/otf/rbac"
"github.com/leg100/otf/semver"
"github.com/pkg/errors"
)

const (
Expand Down Expand Up @@ -344,6 +344,40 @@ type WorkspaceStore interface {
WorkspacePermissionService
}

func CreateWorkspace(ctx context.Context, app Application, opts CreateWorkspaceOptions) (*Workspace, error) {
var (
ws *Workspace
err error
)

err = app.Tx(ctx, func(a Application) error {
// First create the workspace.
ws, err = a.CreateWorkspace(ctx, opts)
if err != nil {
return err
}

// If needed, connect the VCS repository.
if repo := opts.Repo; repo != nil {
err = a.ConnectWorkspace(ctx, ws.ID(), ConnectWorkspaceOptions{
ProviderID: repo.ProviderID,
Identifier: repo.Identifier,
Branch: repo.Branch,
})
if err != nil {
return errors.Wrap(err, "connecting workspace")
}
}

return nil
})
if err != nil {
return nil, err
}

return ws, nil
}

// CurrentRunService provides interaction with the current run for a workspace,
// i.e. the current, or most recently current, non-speculative, run.
type CurrentRunService interface {
Expand Down
24 changes: 19 additions & 5 deletions workspace/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,40 @@ type Connector struct {
}

func (c *Connector) Connect(ctx context.Context, workspaceID string, opts otf.ConnectWorkspaceOptions) error {
client, err := c.GetVCSClient(ctx, opts.ProviderID)
provider, err := c.GetVCSProvider(ctx, opts.ProviderID)
if err != nil {
return err
return errors.Wrap(err, "retrieving provider")
}

client, err := provider.NewClient(ctx)
if err != nil {
return errors.Wrap(err, "creating vcs client")
}

repo, err := client.GetRepository(ctx, opts.Identifier)
if err != nil {
return errors.Wrap(err, "retrieving repository info")
}

branch := opts.Branch
if branch == "" {
branch = repo.Branch
}

hookCallback := func(ctx context.Context, tx otf.Database, hookID uuid.UUID) error {
return sql.CreateWorkspaceRepo(ctx, tx, workspaceID, otf.WorkspaceRepo{
Branch: repo.Branch,
err := sql.CreateWorkspaceRepo(ctx, tx, workspaceID, otf.WorkspaceRepo{
Branch: branch,
ProviderID: opts.ProviderID,
WebhookID: hookID,
})
if err != nil {
return errors.Wrap(err, "creating workspace")
}
return nil
}
err = c.Hook(ctx, otf.HookOptions{
Identifier: opts.Identifier,
Cloud: opts.Cloud,
Cloud: provider.CloudConfig().Name,
HookCallback: hookCallback,
Client: client,
})
Expand Down
1 change: 1 addition & 0 deletions workspace_connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ type WorkspaceConnector interface {
type ConnectWorkspaceOptions struct {
Identifier string `schema:"identifier,required"` // repo id: <owner>/<repo>
ProviderID string `schema:"vcs_provider_id,required"`
Branch string // branch of the VCS
Cloud string // cloud host of the repo
}

0 comments on commit 2c04182

Please sign in to comment.