Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,12 @@ tasks:
dir: pkg/agent/tunnel
cmd: |
# sudo apt install protobuf-compiler
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.5.1
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.4
# Versions must match those recorded in the generated .pb.go headers;
# regenerating with a different one rewrites the whole file.
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.6.2
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.11
# protoc resolves plugins via PATH, and `go install` targets GOPATH/bin.
export PATH="$(go env GOPATH)/bin:$PATH"
protoc -I . tunnel.proto --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative

cli:test:
Expand Down
19 changes: 18 additions & 1 deletion cmd/provider/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package provider
import (
"context"
"fmt"
"os"
"strings"

"github.com/devsy-org/devsy/cmd/flags"
Expand All @@ -11,6 +12,7 @@ import (
"github.com/devsy-org/devsy/pkg/flags/names"
"github.com/devsy-org/devsy/pkg/log"
"github.com/devsy-org/devsy/pkg/provider"
"github.com/devsy-org/devsy/pkg/status"
"github.com/devsy-org/devsy/pkg/types"
"github.com/devsy-org/devsy/pkg/workspace"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -85,18 +87,31 @@ func (cmd *AddCmd) Run(ctx context.Context, devsyConfig *config.Config, args []s
return err
}

reporter, err := newStatusReporter(cmd.ResultFormat, os.Stdout)
if err != nil {
return err
}

status.Enter(reporter, status.PhaseInstallingProvider, providerName)
providerConfig, options, err := cmd.resolveProviderConfig(ctx, devsyConfig, providerName, args)
if err != nil {
status.Fail(reporter, status.PhaseInstallingProvider, err)
return err
}
status.Leave(reporter, status.PhaseInstallingProvider, providerConfig.Name)

log.Infof("installed provider: providerName=%s", providerConfig.Name)
if !cmd.Use {
log.Infof("To initialize the provider, run: devsy provider init %s", providerConfig.Name)
// No PhaseReady: installed but not initialized.
return nil
}

return cmd.useProvider(ctx, devsyConfig, providerConfig, options)
if err := cmd.useProvider(ctx, devsyConfig, providerConfig, options, reporter); err != nil {
return err
}
status.Leave(reporter, status.PhaseReady, providerConfig.Name)
return nil
}

func validateOptionalProviderName(providerName string) error {
Expand Down Expand Up @@ -158,6 +173,7 @@ func (cmd *AddCmd) useProvider(
devsyConfig *config.Config,
providerConfig *provider.ProviderConfig,
options []string,
reporter status.Reporter,
) error {
// First add: there are no prior user values to merge, so
// DiscardPriorValues is moot. Set it explicitly so future readers
Expand All @@ -168,6 +184,7 @@ func (cmd *AddCmd) useProvider(
UserOptions: options,
DiscardPriorValues: true,
SingleMachine: &cmd.SingleMachine,
Reporter: reporter,
})
if configureErr != nil {
devsyConfig, err := config.LoadConfig(cmd.Context, "")
Expand Down
20 changes: 19 additions & 1 deletion cmd/provider/configure_shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/devsy-org/devsy/pkg/log"
options2 "github.com/devsy-org/devsy/pkg/options"
provider2 "github.com/devsy-org/devsy/pkg/provider"
"github.com/devsy-org/devsy/pkg/status"
)

// ProviderOptionsConfig parameterizes ConfigureProvider.
Expand All @@ -32,6 +33,15 @@ type ProviderOptionsConfig struct {
SkipInit bool
SkipSubOptions bool
SingleMachine *bool

Reporter status.Reporter
}

func (cfg ProviderOptionsConfig) reporter() status.Reporter {
if cfg.Reporter == nil {
return status.Nop()
}
return cfg.Reporter
}

func ConfigureProvider(ctx context.Context, cfg ProviderOptionsConfig) error {
Expand Down Expand Up @@ -91,13 +101,18 @@ func configureProviderOptions(
}

// fill defaults
reporter := cfg.reporter()
status.Enter(reporter, status.PhaseResolvingOptions, cfg.Provider.Name)
devsyConfig, err = options2.ResolveOptions(
ctx, devsyConfig, cfg.Provider, options,
cfg.SkipRequired, cfg.SkipSubOptions, cfg.SingleMachine,
)
if err != nil {
return nil, fmt.Errorf("resolve options: %w", err)
err = fmt.Errorf("resolve options: %w", err)
status.Fail(reporter, status.PhaseResolvingOptions, err)
return nil, err
}
status.Leave(reporter, status.PhaseResolvingOptions, cfg.Provider.Name)

// run init command
if !cfg.SkipInit {
Expand All @@ -107,10 +122,13 @@ func configureProviderOptions(
stderr := log.Writer(log.LevelError)
defer func() { _ = stderr.Close() }()

status.Enter(reporter, status.PhaseRunningInit, cfg.Provider.Name)
err = initProvider(ctx, devsyConfig, cfg.Provider, initIO{stdout: stdout, stderr: stderr})
if err != nil {
status.Fail(reporter, status.PhaseRunningInit, err)
return nil, err
}
status.Leave(reporter, status.PhaseRunningInit, cfg.Provider.Name)
}

return devsyConfig, nil
Expand Down
16 changes: 14 additions & 2 deletions cmd/provider/init.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package provider

import (
"os"

"github.com/devsy-org/devsy/cmd/completion"
"github.com/devsy-org/devsy/cmd/flags"
"github.com/devsy-org/devsy/pkg/config"
cliflags "github.com/devsy-org/devsy/pkg/flags"
"github.com/devsy-org/devsy/pkg/flags/names"
"github.com/devsy-org/devsy/pkg/status"
"github.com/devsy-org/devsy/pkg/workspace"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -39,14 +42,23 @@ func NewInitCmd(f *flags.GlobalFlags) *cobra.Command {
if err != nil {
return err
}
return ConfigureProvider(cobraCmd.Context(), ProviderOptionsConfig{
reporter, err := newStatusReporter(cmd.ResultFormat, os.Stdout)
if err != nil {
return err
}
if err := ConfigureProvider(cobraCmd.Context(), ProviderOptionsConfig{
Provider: p.Config,
ContextName: devsyConfig.DefaultContext,
UserOptions: cmd.Options,
DiscardPriorValues: cmd.Reset,
SkipInit: cmd.SkipInit,
SingleMachine: &cmd.SingleMachine,
})
Reporter: reporter,
}); err != nil {
return err
}
status.Leave(reporter, status.PhaseReady, name)
return nil
},
ValidArgsFunction: func(
rootCmd *cobra.Command,
Expand Down
18 changes: 17 additions & 1 deletion cmd/provider/set_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package provider
import (
"context"
"fmt"
"os"

"github.com/devsy-org/devsy/cmd/flags"
"github.com/devsy-org/devsy/pkg/config"
cliflags "github.com/devsy-org/devsy/pkg/flags"
"github.com/devsy-org/devsy/pkg/flags/names"
"github.com/devsy-org/devsy/pkg/log"
"github.com/devsy-org/devsy/pkg/status"
"github.com/devsy-org/devsy/pkg/workspace"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -67,14 +69,23 @@ func (cmd *SetSourceCmd) Run(ctx context.Context, devsyConfig *config.Config, ar
providerSource = args[1]
}

reporter, err := newStatusReporter(cmd.ResultFormat, os.Stdout)
if err != nil {
return err
}

status.Enter(reporter, status.PhaseInstallingProvider, args[0])
providerConfig, err := workspace.UpdateProvider(ctx, devsyConfig, args[0], providerSource)
if err != nil {
status.Fail(reporter, status.PhaseInstallingProvider, err)
return err
}
status.Leave(reporter, status.PhaseInstallingProvider, providerConfig.Name)

log.Infof("updated provider: providerName=%s", providerConfig.Name)
if !cmd.Use {
log.Infof("To initialize the provider, run: devsy provider init %s", providerConfig.Name)
// No PhaseReady: not ready until a following `provider init` runs.
return nil
}

Expand All @@ -85,11 +96,16 @@ func (cmd *SetSourceCmd) Run(ctx context.Context, devsyConfig *config.Config, ar
Provider: providerConfig,
ContextName: devsyConfig.DefaultContext,
UserOptions: cmd.Options,
Reporter: reporter,
}); err != nil {
return fmt.Errorf("configure provider: %w", err)
}

return writeDefaultProvider(cmd.Context, providerConfig.Name)
if err := writeDefaultProvider(cmd.Context, providerConfig.Name); err != nil {
return err
}
status.Leave(reporter, status.PhaseReady, providerConfig.Name)
return nil
}

func (cmd *SetSourceCmd) runPinVersion(
Expand Down
60 changes: 60 additions & 0 deletions cmd/provider/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package provider

import (
"io"

config2 "github.com/devsy-org/devsy/pkg/devcontainer/config"
"github.com/devsy-org/devsy/pkg/log"
"github.com/devsy-org/devsy/pkg/output"
"github.com/devsy-org/devsy/pkg/status"
)

// newStatusReporter drives provider progress output: one NDJSON status line
// per phase transition in JSON mode, human-readable info lines otherwise.
// Mirrors cmd/workspace/up's reporter so both pipelines look the same to a
// consumer reading the stream.
func newStatusReporter(resultFormat string, out io.Writer) (status.Reporter, error) {
mode, err := output.ResolveMode(resultFormat)
if err != nil {
return nil, err
}

var r status.Reporter = plainStatusReporter{}
if mode == output.ModeJSON {
r = &jsonStatusReporter{out: out}
}
return status.ForPipeline(r, status.PipelineProvider), nil
}

type jsonStatusReporter struct {
out io.Writer
}

func (r *jsonStatusReporter) Report(e status.Event) {
_ = config2.WriteStatusJSON(r.out, e)
}

type plainStatusReporter struct{}

func (plainStatusReporter) Report(e status.Event) {
switch {
case e.Phase == status.PhaseFailed:
log.Errorf("provider: phase %q failed: %s", e.Step, e.Err)
case e.Started:
log.Infof("provider: %s", phaseLabel(e.Phase))
}
}

var phaseLabels = map[status.Phase]string{
status.PhaseInstallingProvider: "installing provider",
status.PhaseResolvingOptions: "resolving options",
status.PhaseRunningInit: "running provider init",
status.PhaseReady: "ready",
}

func phaseLabel(p status.Phase) string {
if label, ok := phaseLabels[p]; ok {
return label
}
return string(p)
}
5 changes: 3 additions & 2 deletions cmd/workspace/up/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import (

// newStatusReporter drives `up`'s progress output.
func newStatusReporter(emitJSON bool, out io.Writer) status.Reporter {
var r status.Reporter = plainStatusReporter{}
if emitJSON {
return &jsonStatusReporter{out: out}
r = &jsonStatusReporter{out: out}
}
return plainStatusReporter{}
return status.ForPipeline(r, status.PipelineWorkspaceUp)
}

// jsonStatusReporter serializes write events.
Expand Down
5 changes: 4 additions & 1 deletion desktop/e2e/app.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import type { ElectronApplication, Page } from "@playwright/test"
import { expect, test } from "@playwright/test"
import { launchApp } from "./electron-app.js"
import { launchApp, resetMockState } from "./electron-app.js"

let app: ElectronApplication
let page: Page

test.beforeAll(async () => {
// The badge counts below assert the mock's default fixture exactly, so
// start from a clean slate rather than inheriting another spec's CRUD.
resetMockState()
;({ app, page } = await launchApp())
})

Expand Down
Loading
Loading