• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

umputun / ralphex / 21743054702

06 Feb 2026 07:54AM UTC coverage: 80.111% (-0.8%) from 80.861%
21743054702

push

github

umputun
refactor: address code review findings and improve package structure

- Remove dead code: IsPlanDraft, IsTerminalSignal, NewErrorEvent, NewWarnEvent, Phase aliases
- Fix stale comments, extract magic numbers, remove redundant conditions
- Improve session manager: add error logging, convert standalone functions to methods
- Deduplicate shared code: maxScannerBuffer constant, progress file parsing, review pipeline
- Extract shared types to pkg/status (signals, Phase, Section) from processor/signals
- Merge pkg/render into pkg/input
- Move Logger interface to consumer-side in pkg/web, decoupling web from processor

195 of 205 new or added lines in 13 files covered. (95.12%)

1 existing line in 1 file now uncovered.

4463 of 5571 relevant lines covered (80.11%)

157.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.56
/pkg/web/parse.go
1
package web
2

3
import (
4
        "strings"
5
        "time"
6

7
        "github.com/umputun/ralphex/pkg/status"
8
)
9

10
// ParsedLineType indicates what kind of progress line was parsed.
11
type ParsedLineType int
12

13
// parsed line type constants.
14
const (
15
        ParsedLineSkip      ParsedLineType = iota // header line or separator, should be skipped
16
        ParsedLineSection                         // section header (--- name ---)
17
        ParsedLineTimestamp                       // timestamped content line
18
        ParsedLinePlain                           // plain text without timestamp
19
)
20

21
// ParsedLine is the result of parsing a single progress file line.
22
// callers convert this to Event objects with their own context (phase, pending section logic, etc.).
23
type ParsedLine struct {
24
        Type      ParsedLineType
25
        Text      string       // content text (without timestamp prefix for timestamped lines)
26
        Section   string       // section name (only for ParsedLineSection)
27
        Timestamp time.Time    // parsed timestamp (only for ParsedLineTimestamp)
28
        EventType EventType    // detected event type (output, error, warn, signal)
29
        Signal    string       // extracted signal name, if any
30
        Phase     status.Phase // phase derived from section name (only for ParsedLineSection)
31
}
32

33
// parseProgressLine parses a single progress file line into a ParsedLine.
34
// handles header separator detection, section headers, timestamped lines, and plain lines.
35
// inHeader indicates whether we're still in the file header section.
36
// returns the parsed result and updated inHeader state.
37
func parseProgressLine(line string, inHeader bool) (ParsedLine, bool) {
979✔
38
        // check for header separator (line of dashes without spaces, e.g. "----...----")
979✔
39
        if isHeaderSeparator(line) {
1,128✔
40
                return ParsedLine{Type: ParsedLineSkip}, false
149✔
41
        }
149✔
42

43
        // skip header lines
44
        if inHeader {
1,558✔
45
                return ParsedLine{Type: ParsedLineSkip}, true
728✔
46
        }
728✔
47

48
        // check for section header (--- section name ---)
49
        if matches := sectionRegex.FindStringSubmatch(line); matches != nil {
138✔
50
                sectionName := matches[1]
36✔
51
                return ParsedLine{
36✔
52
                        Type:    ParsedLineSection,
36✔
53
                        Text:    sectionName,
36✔
54
                        Section: sectionName,
36✔
55
                        Phase:   phaseFromSection(sectionName),
36✔
56
                }, false
36✔
57
        }
36✔
58

59
        // check for timestamped line
60
        if matches := timestampRegex.FindStringSubmatch(line); matches != nil {
127✔
61
                text := matches[2]
61✔
62

61✔
63
                ts, err := time.Parse("06-01-02 15:04:05", matches[1])
61✔
64
                if err != nil {
61✔
NEW
65
                        ts = time.Now()
×
NEW
66
                }
×
67

68
                eventType := detectEventType(text)
61✔
69
                signal := extractSignalFromText(text)
61✔
70
                if signal != "" {
74✔
71
                        eventType = EventTypeSignal
13✔
72
                }
13✔
73

74
                return ParsedLine{
61✔
75
                        Type:      ParsedLineTimestamp,
61✔
76
                        Text:      text,
61✔
77
                        Timestamp: ts,
61✔
78
                        EventType: eventType,
61✔
79
                        Signal:    signal,
61✔
80
                }, false
61✔
81
        }
82

83
        // plain line (no timestamp)
84
        return ParsedLine{
5✔
85
                Type:      ParsedLinePlain,
5✔
86
                Text:      line,
5✔
87
                EventType: EventTypeOutput,
5✔
88
        }, false
5✔
89
}
90

91
// isHeaderSeparator checks if a line is a header separator (line of dashes without spaces).
92
func isHeaderSeparator(line string) bool {
989✔
93
        return len(line) >= 3 && line[0] == '-' && line[1] == '-' && line[2] == '-' &&
989✔
94
                strings.Count(line, "-") > 20 && !strings.ContainsRune(line, ' ')
989✔
95
}
989✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc