Skip to content

Commit ea6960e

Browse files
Andrea Falzettifelladrin
Andrea Falzetti
andcommitted
gp rebuild improvements
Co-authored-by: Victor Nogueira <[email protected]>
1 parent ba6ce0e commit ea6960e

File tree

2 files changed

+91
-67
lines changed

2 files changed

+91
-67
lines changed

components/gitpod-cli/cmd/rebuild.go

+74-56
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import (
99
"fmt"
1010
"os"
1111
"os/exec"
12+
"os/signal"
1213
"path/filepath"
1314
"strings"
15+
"syscall"
1416
"time"
1517

1618
"github.com/gitpod-io/gitpod/gitpod-cli/pkg/supervisor"
@@ -19,8 +21,8 @@ import (
1921
"github.com/spf13/cobra"
2022
)
2123

22-
func TerminateExistingContainer() error {
23-
cmd := exec.Command("docker", "ps", "-q", "-f", "label=gp-rebuild")
24+
func TerminateExistingContainer(ctx context.Context) error {
25+
cmd := exec.CommandContext(ctx, "docker", "ps", "-q", "-f", "label=gp-rebuild")
2426
containerIds, err := cmd.Output()
2527
if err != nil {
2628
return err
@@ -31,13 +33,13 @@ func TerminateExistingContainer() error {
3133
continue
3234
}
3335

34-
cmd = exec.Command("docker", "stop", id)
36+
cmd = exec.CommandContext(ctx, "docker", "stop", id)
3537
err := cmd.Run()
3638
if err != nil {
3739
return err
3840
}
3941

40-
cmd = exec.Command("docker", "rm", "-f", id)
42+
cmd = exec.CommandContext(ctx, "docker", "rm", "-f", id)
4143
err = cmd.Run()
4244
if err != nil {
4345
return err
@@ -47,17 +49,15 @@ func TerminateExistingContainer() error {
4749
return nil
4850
}
4951

50-
func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClient, event *utils.EventTracker) error {
52+
func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClient, event *utils.EventTracker) (string, error) {
5153
wsInfo, err := supervisorClient.Info.WorkspaceInfo(ctx, &api.WorkspaceInfoRequest{})
5254
if err != nil {
53-
event.Set("ErrorCode", utils.SystemErrorCode)
54-
return err
55+
return utils.Outcome_SystemErr, err
5556
}
5657

5758
tmpDir, err := os.MkdirTemp("", "gp-rebuild-*")
5859
if err != nil {
59-
event.Set("ErrorCode", utils.SystemErrorCode)
60-
return err
60+
return utils.Outcome_SystemErr, err
6161
}
6262
defer os.RemoveAll(tmpDir)
6363

@@ -68,7 +68,7 @@ func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClie
6868
fmt.Println("For help check out the reference page:")
6969
fmt.Println("https://www.gitpod.io/docs/references/gitpod-yml#gitpodyml")
7070
event.Set("ErrorCode", utils.RebuildErrorCode_MalformedGitpodYaml)
71-
return err
71+
return utils.Outcome_UserErr, err
7272
}
7373

7474
if gitpodConfig == nil {
@@ -79,7 +79,7 @@ func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClie
7979
fmt.Println("Alternatively, check out the following docs for getting started configuring your project")
8080
fmt.Println("https://www.gitpod.io/docs/configure#configure-gitpod")
8181
event.Set("ErrorCode", utils.RebuildErrorCode_MissingGitpodYaml)
82-
return err
82+
return utils.Outcome_UserErr, nil
8383
}
8484

8585
var baseimage string
@@ -93,13 +93,11 @@ func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClie
9393

9494
if _, err := os.Stat(dockerfilePath); os.IsNotExist(err) {
9595
fmt.Println("Your .gitpod.yml points to a Dockerfile that doesn't exist: " + dockerfilePath)
96-
event.Set("ErrorCode", utils.RebuildErrorCode_DockerfileNotFound).Send(ctx)
97-
return err
96+
return utils.Outcome_UserErr, err
9897
}
9998
dockerfile, err := os.ReadFile(dockerfilePath)
10099
if err != nil {
101-
event.Set("ErrorCode", utils.RebuildErrorCode_DockerfileCannotRead)
102-
return err
100+
return utils.Outcome_SystemErr, err
103101
}
104102
if string(dockerfile) == "" {
105103
fmt.Println("Your Gitpod's Dockerfile is empty")
@@ -108,14 +106,13 @@ func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClie
108106
fmt.Println("https://www.gitpod.io/docs/configure/workspaces/workspace-image#use-a-custom-dockerfile")
109107
fmt.Println("")
110108
fmt.Println("Once you configure your Dockerfile, re-run this command to validate your changes")
111-
event.Set("ErrorCode", utils.RebuildErrorCode_DockerfileEmpty)
112-
return err
109+
return utils.Outcome_UserErr, nil
113110
}
114111
baseimage = "\n" + string(dockerfile) + "\n"
115112
default:
116113
fmt.Println("Check your .gitpod.yml and make sure the image property is configured correctly")
117114
event.Set("ErrorCode", utils.RebuildErrorCode_MalformedGitpodYaml)
118-
return err
115+
return utils.Outcome_UserErr, nil
119116
}
120117

121118
if baseimage == "" {
@@ -124,94 +121,107 @@ func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClie
124121
fmt.Println("")
125122
fmt.Println("https://www.gitpod.io/docs/configure/workspaces/workspace-image#use-a-public-docker-image")
126123
event.Set("ErrorCode", utils.RebuildErrorCode_NoCustomImage)
127-
return err
124+
return utils.Outcome_UserErr, nil
128125
}
129126

130-
err = os.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(baseimage), 0644)
127+
tmpDockerfile := filepath.Join(tmpDir, "Dockerfile")
128+
129+
err = os.WriteFile(tmpDockerfile, []byte(baseimage), 0644)
131130
if err != nil {
132131
fmt.Println("Could not write the temporary Dockerfile")
133-
event.Set("ErrorCode", utils.RebuildErrorCode_DockerfileCannotWirte)
134-
return err
132+
return utils.Outcome_SystemErr, err
135133
}
136134

137135
dockerPath, err := exec.LookPath("docker")
138136
if err != nil {
139137
fmt.Println("Docker is not installed in your workspace")
140138
event.Set("ErrorCode", utils.RebuildErrorCode_DockerNotFound)
141-
return err
139+
return utils.Outcome_SystemErr, err
142140
}
143141

144142
tag := "gp-rebuild-temp-build"
145143

146-
dockerCmd := exec.Command(dockerPath, "build", "-t", tag, "--progress=tty", ".")
147-
dockerCmd.Dir = tmpDir
144+
dockerCmd := exec.CommandContext(ctx, dockerPath, "build", "-f", tmpDockerfile, "-t", tag, wsInfo.CheckoutLocation)
148145
dockerCmd.Stdout = os.Stdout
149146
dockerCmd.Stderr = os.Stderr
150147

151148
imageBuildStartTime := time.Now()
152149
err = dockerCmd.Run()
153150
if _, ok := err.(*exec.ExitError); ok {
154151
fmt.Println("Image Build Failed")
155-
event.Set("ErrorCode", utils.RebuildErrorCode_DockerBuildFailed)
156-
return err
152+
event.Set("ErrorCode", utils.RebuildErrorCode_ImageBuildFailed)
153+
return utils.Outcome_UserErr, nil
157154
} else if err != nil {
158155
fmt.Println("Docker error")
159156
event.Set("ErrorCode", utils.RebuildErrorCode_DockerErr)
160-
return err
157+
return utils.Outcome_SystemErr, err
161158
}
162159
ImageBuildDuration := time.Since(imageBuildStartTime).Milliseconds()
163160
event.Set("ImageBuildDuration", ImageBuildDuration)
164161

165-
err = TerminateExistingContainer()
162+
err = TerminateExistingContainer(ctx)
166163
if err != nil {
167-
event.Set("ErrorCode", utils.SystemErrorCode)
168-
return err
169-
}
170-
171-
messages := []string{
172-
"\n\nYou are now connected to the container",
173-
"You can inspect the container and make sure the necessary tools & libraries are installed.",
174-
"When you are done, just type exit to return to your Gitpod workspace\n",
164+
return utils.Outcome_SystemErr, err
175165
}
176166

177-
welcomeMessage := strings.Join(messages, "\n")
167+
welcomeMessage := strings.Join([]string{
168+
"\n\nYou are now connected to the container.",
169+
"Check if all tools and libraries you need are properly installed.",
170+
"When you are done, type \"exit\" to return to your Gitpod workspace.\n",
171+
}, "\n")
178172

179-
dockerRunCmd := exec.Command(
173+
dockerRunCmd := exec.CommandContext(ctx,
180174
dockerPath,
181175
"run",
182176
"--rm",
177+
"-v", "/workspace:/workspace",
183178
"--label", "gp-rebuild=true",
184-
"-it",
185-
tag,
186-
"bash",
179+
"-it", tag,
180+
"sh",
187181
"-c",
188-
fmt.Sprintf("echo '%s'; bash", welcomeMessage),
182+
fmt.Sprintf(`
183+
echo "%s";
184+
cd "%s";
185+
if [ -x "$(command -v $SHELL)" ]; then
186+
$SHELL;
187+
else
188+
if [ -x "$(command -v bash)" ]; then
189+
bash;
190+
else
191+
sh;
192+
fi;
193+
fi;
194+
`, welcomeMessage, wsInfo.CheckoutLocation),
189195
)
190196

191197
dockerRunCmd.Stdout = os.Stdout
192198
dockerRunCmd.Stderr = os.Stderr
193199
dockerRunCmd.Stdin = os.Stdin
194200

195-
err = dockerRunCmd.Run()
196-
if _, ok := err.(*exec.ExitError); ok {
197-
fmt.Println("Docker Run Command Failed")
201+
err = dockerRunCmd.Start()
202+
if err != nil {
203+
fmt.Println("Failed to run docker container")
198204
event.Set("ErrorCode", utils.RebuildErrorCode_DockerRunFailed)
199-
return err
200-
} else if err != nil {
201-
fmt.Println("Docker error")
202-
event.Set("ErrorCode", utils.RebuildErrorCode_DockerErr)
203-
return err
205+
return utils.Outcome_UserErr, err
204206
}
205207

206-
return nil
208+
_ = dockerRunCmd.Wait()
209+
210+
return utils.Outcome_Success, nil
207211
}
208212

209213
var buildCmd = &cobra.Command{
210214
Use: "rebuild",
211215
Short: "Re-builds the workspace image (useful to debug a workspace custom image)",
212216
Hidden: false,
213217
Run: func(cmd *cobra.Command, args []string) {
214-
ctx := context.Background()
218+
ctx, cancel := context.WithCancel(context.Background())
219+
sigChan := make(chan os.Signal, 1)
220+
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
221+
go func() {
222+
<-sigChan
223+
cancel()
224+
}()
215225
supervisorClient, err := supervisor.New(ctx)
216226
if err != nil {
217227
utils.LogError(ctx, err, "Could not get workspace info required to build", supervisorClient)
@@ -223,10 +233,18 @@ var buildCmd = &cobra.Command{
223233
Command: cmd.Name(),
224234
})
225235

226-
err = runRebuild(ctx, supervisorClient, event)
227-
if err != nil && event.Data.ErrorCode == "" {
228-
event.Set("ErrorCode", utils.SystemErrorCode)
236+
outcome, err := runRebuild(ctx, supervisorClient, event)
237+
event.Set("Outcome", outcome)
238+
239+
if outcome != utils.Outcome_Success && event.Data.ErrorCode == "" {
240+
switch outcome {
241+
case utils.Outcome_UserErr:
242+
event.Set("ErrorCode", utils.UserErrorCode)
243+
case utils.Outcome_SystemErr:
244+
event.Set("ErrorCode", utils.SystemErrorCode)
245+
}
229246
}
247+
230248
event.Send(ctx)
231249

232250
if err != nil {

components/gitpod-cli/pkg/utils/trackEvent.go

+17-11
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,25 @@ import (
1515
log "github.com/sirupsen/logrus"
1616
)
1717

18+
const (
19+
Outcome_Success = "success"
20+
Outcome_UserErr = "user_error"
21+
Outcome_SystemErr = "system_error"
22+
)
23+
1824
const (
1925
// System
2026
SystemErrorCode = "system_error"
27+
UserErrorCode = "user_error"
2128

2229
// Rebuild
23-
RebuildErrorCode_DockerBuildFailed = "rebuild_docker_build_failed"
24-
RebuildErrorCode_DockerErr = "rebuild_docker_err"
25-
RebuildErrorCode_DockerfileCannotRead = "rebuild_dockerfile_cannot_read"
26-
RebuildErrorCode_DockerfileCannotWirte = "rebuild_dockerfile_cannot_write"
27-
RebuildErrorCode_DockerfileEmpty = "rebuild_dockerfile_empty"
28-
RebuildErrorCode_DockerfileNotFound = "rebuild_dockerfile_not_found"
29-
RebuildErrorCode_DockerNotFound = "rebuild_docker_not_found"
30-
RebuildErrorCode_DockerRunFailed = "rebuild_docker_run_failed"
31-
RebuildErrorCode_MalformedGitpodYaml = "rebuild_malformed_gitpod_yaml"
32-
RebuildErrorCode_MissingGitpodYaml = "rebuild_missing_gitpod_yaml"
33-
RebuildErrorCode_NoCustomImage = "rebuild_no_custom_image"
30+
RebuildErrorCode_ImageBuildFailed = "rebuild_image_build_failed"
31+
RebuildErrorCode_DockerErr = "rebuild_docker_err"
32+
RebuildErrorCode_DockerNotFound = "rebuild_docker_not_found"
33+
RebuildErrorCode_DockerRunFailed = "rebuild_docker_run_failed"
34+
RebuildErrorCode_MalformedGitpodYaml = "rebuild_malformed_gitpod_yaml"
35+
RebuildErrorCode_MissingGitpodYaml = "rebuild_missing_gitpod_yaml"
36+
RebuildErrorCode_NoCustomImage = "rebuild_no_custom_image"
3437
)
3538

3639
type TrackCommandUsageParams struct {
@@ -41,6 +44,7 @@ type TrackCommandUsageParams struct {
4144
InstanceId string `json:"instanceId,omitempty"`
4245
Timestamp int64 `json:"timestamp,omitempty"`
4346
ImageBuildDuration int64 `json:"imageBuildDuration,omitempty"`
47+
Outcome string `json:"outcome,omitempty"`
4448
}
4549

4650
type EventTracker struct {
@@ -96,6 +100,8 @@ func (t *EventTracker) Set(key string, value interface{}) *EventTracker {
96100
t.Data.InstanceId = value.(string)
97101
case "ImageBuildDuration":
98102
t.Data.ImageBuildDuration = value.(int64)
103+
case "Outcome":
104+
t.Data.Outcome = value.(string)
99105
}
100106
return t
101107
}

0 commit comments

Comments
 (0)