diff --git a/CHANGELOG.md b/CHANGELOG.md index 095c60237671d5..9deb18d283bb89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. +## June 2021 + +- Better reflect incremental prebuilds in prebuilt workspace logs ([#4293](https://github.com/gitpod-io/gitpod/pull/4293)) +- Run shellcheck against scripts ([#4280](https://github.com/gitpod-io/gitpod/pull/4280)) +- Implement new Project and Team DB tables and entities ([#4368](https://github.com/gitpod-io/gitpod/pull/4368)) +- On gitpod.io 404 redirect to www.gitpod.io ([#4364](https://github.com/gitpod-io/gitpod/pull/4364)) +- Fix disk space leak in ws-manager ([#4388](https://github.com/gitpod-io/gitpod/pull/4388)) +- Fix memory leak in ws-manager ([#4384](https://github.com/gitpod-io/gitpod/pull/4384)) +- Handle GitHub issues page context URL ([#4370](https://github.com/gitpod-io/gitpod/pull/4370)) +- Fix issues blocking SSH from local terminal ([#4358](https://github.com/gitpod-io/gitpod/pull/4358)) +- Fix remote tracking branch for issue context ([#4367](https://github.com/gitpod-io/gitpod/pull/4367)) +- Fix opening empty repositories ([#4337](https://github.com/gitpod-io/gitpod/pull/4337)) ## May 2021 diff --git a/components/supervisor/pkg/supervisor/tasks.go b/components/supervisor/pkg/supervisor/tasks.go index 87b96392a2e43a..e4aa8dc40c5113 100644 --- a/components/supervisor/pkg/supervisor/tasks.go +++ b/components/supervisor/pkg/supervisor/tasks.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "os" + "regexp" "strconv" "strings" "sync" @@ -377,9 +378,16 @@ func (tm *tasksManager) watch(task *task, terminal *terminal.Term) { go func() { defer stdout.Close() - fileName := tm.prebuildLogFileName(task) - // TODO(janx): If the file already exists (from a parent prebuild), extract its "time saved", and log that below - // (instead, or in addition to, the incremental prebuild time). + var ( + fileName = tm.prebuildLogFileName(task) + oldFileName = fileName + "-old" + ) + if _, err := os.Stat(fileName); err == nil { + // If the file already exists (from a parent prebuild), temporarily move it so that it doesn't get truncated. + // On the off chance that renaming fails here, we silently ignore that -- the new prebuild logs simply won't reflect + // the older logs and elapsed time (`importParentLogAndGetDuration` is always safe thanks to its initial `os.Stat`). + _ = os.Rename(fileName, oldFileName) + } file, err := os.Create(fileName) var fileWriter *bufio.Writer if err != nil { @@ -391,12 +399,17 @@ func (tm *tasksManager) watch(task *task, terminal *terminal.Term) { fileWriter = bufio.NewWriter(file) defer fileWriter.Flush() } + // Import any parent prebuild logs and parse their total duration if available + parentElapsed := importParentLogAndGetDuration(oldFileName, fileWriter) buf := make([]byte, 4096) for { n, err := stdout.Read(buf) if err == io.EOF { elapsed := time.Since(start) + if parentElapsed > elapsed { + elapsed = parentElapsed + } duration := "" if elapsed >= 1*time.Minute { elapsedInMinutes := strconv.Itoa(int(elapsed.Minutes())) @@ -425,6 +438,46 @@ func (tm *tasksManager) watch(task *task, terminal *terminal.Term) { }() } +func importParentLogAndGetDuration(fn string, out io.Writer) time.Duration { + if _, err := os.Stat(fn); err != nil { + return 0 + } + defer os.Remove(fn) + + file, err := os.Open(fn) + if err != nil { + return 0 + } + defer file.Close() + + defer out.Write([]byte("♻️ Re-running task as an incremental workspace prebuild\n\n")) + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + l := scanner.Text() + if strings.Contains(l, "🤙 This task ran as a workspace prebuild") { + break + } + out.Write([]byte(l + "\n")) + } + if !scanner.Scan() { + return 0 + } + reg, err := regexp.Compile(`🎉 Well done on saving (\d+) minute`) + if err != nil { + return 0 + } + res := reg.FindStringSubmatch(scanner.Text()) + if res == nil { + return 0 + } + elapsedInMinutes, err := strconv.Atoi(res[1]) + if err != nil { + return 0 + } + return time.Duration(elapsedInMinutes) * time.Minute +} + type composeCommandOptions struct { commands []*string format string