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

muesli / termenv / 5943573526

22 Aug 2023 08:11PM UTC coverage: 57.655% (-0.2%) from 57.843%
5943573526

Pull #122

github

aymanbagabas
fix(output): export output writer

Termenv output can be a buffer, ssh session, a file, or anything that
implements the io.Writer interface.

In the case of an ssh session, the std ssh library returns a
io.ReadWriter for ssh sessions and the current Termenv implementation
makes it impossible to read terminal status reports since it expects a
file in return.

In addition, the TTY() function is confusing since it implies that the
returned value is a TTY. Which is not always true until we check that
using the isTTY() function.

Deprecate TTY() in favor of Writer() which simply returns the underlying
writer. The caller then can infer the type of the writer and decide what
to do with it.

This also deprecate parts of commit <a class=hub.com/muesli/termenv/commit/669c9abfb65169a7a146968e38702d3d80327a42">669c9abfb https://github.com/muesli/termenv/commit/669c9abfb65169a7a146968e38702d3d80327a42
Pull Request #122: fix(output): export output writer

56 of 56 new or added lines in 3 files covered. (100.0%)

531 of 921 relevant lines covered (57.65%)

8.83 hits per line

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

50.59
/screen.go
1
package termenv
2

3
import (
4
        "fmt"
5
        "strings"
6
)
7

8
// Sequence definitions.
9
const (
10
        // Cursor positioning.
11
        CursorUpSeq              = "%dA"
12
        CursorDownSeq            = "%dB"
13
        CursorForwardSeq         = "%dC"
14
        CursorBackSeq            = "%dD"
15
        CursorNextLineSeq        = "%dE"
16
        CursorPreviousLineSeq    = "%dF"
17
        CursorHorizontalSeq      = "%dG"
18
        CursorPositionSeq        = "%d;%dH"
19
        EraseDisplaySeq          = "%dJ"
20
        EraseLineSeq             = "%dK"
21
        ScrollUpSeq              = "%dS"
22
        ScrollDownSeq            = "%dT"
23
        SaveCursorPositionSeq    = "s"
24
        RestoreCursorPositionSeq = "u"
25
        ChangeScrollingRegionSeq = "%d;%dr"
26
        InsertLineSeq            = "%dL"
27
        DeleteLineSeq            = "%dM"
28

29
        // Explicit values for EraseLineSeq.
30
        EraseLineRightSeq  = "0K"
31
        EraseLineLeftSeq   = "1K"
32
        EraseEntireLineSeq = "2K"
33

34
        // Mouse.
35
        EnableMousePressSeq         = "?9h" // press only (X10)
36
        DisableMousePressSeq        = "?9l"
37
        EnableMouseSeq              = "?1000h" // press, release, wheel
38
        DisableMouseSeq             = "?1000l"
39
        EnableMouseHiliteSeq        = "?1001h" // highlight
40
        DisableMouseHiliteSeq       = "?1001l"
41
        EnableMouseCellMotionSeq    = "?1002h" // press, release, move on pressed, wheel
42
        DisableMouseCellMotionSeq   = "?1002l"
43
        EnableMouseAllMotionSeq     = "?1003h" // press, release, move, wheel
44
        DisableMouseAllMotionSeq    = "?1003l"
45
        EnableMouseExtendedModeSeq  = "?1006h" // press, release, move, wheel, extended coordinates
46
        DisableMouseExtendedModeSeq = "?1006l"
47
        EnableMousePixelsModeSeq    = "?1016h" // press, release, move, wheel, extended pixel coordinates
48
        DisableMousePixelsModeSeq   = "?1016l"
49

50
        // Screen.
51
        RestoreScreenSeq = "?47l"
52
        SaveScreenSeq    = "?47h"
53
        AltScreenSeq     = "?1049h"
54
        ExitAltScreenSeq = "?1049l"
55

56
        // Bracketed paste.
57
        // https://en.wikipedia.org/wiki/Bracketed-paste
58
        EnableBracketedPasteSeq  = "?2004h"
59
        DisableBracketedPasteSeq = "?2004l"
60
        StartBracketedPasteSeq   = "200~"
61
        EndBracketedPasteSeq     = "201~"
62

63
        // Session.
64
        SetWindowTitleSeq     = "2;%s" + string(BEL)
65
        SetForegroundColorSeq = "10;%s" + string(BEL)
66
        SetBackgroundColorSeq = "11;%s" + string(BEL)
67
        SetCursorColorSeq     = "12;%s" + string(BEL)
68
        ShowCursorSeq         = "?25h"
69
        HideCursorSeq         = "?25l"
70
)
71

72
// Reset the terminal to its default style, removing any active styles.
73
func (o Output) Reset() {
1✔
74
        fmt.Fprint(o.w, CSI+ResetSeq+"m")
1✔
75
}
1✔
76

77
// SetForegroundColor sets the default foreground color.
78
func (o Output) SetForegroundColor(color Color) {
1✔
79
        fmt.Fprintf(o.w, OSC+SetForegroundColorSeq, color)
1✔
80
}
1✔
81

82
// SetBackgroundColor sets the default background color.
83
func (o Output) SetBackgroundColor(color Color) {
1✔
84
        fmt.Fprintf(o.w, OSC+SetBackgroundColorSeq, color)
1✔
85
}
1✔
86

87
// SetCursorColor sets the cursor color.
88
func (o Output) SetCursorColor(color Color) {
1✔
89
        fmt.Fprintf(o.w, OSC+SetCursorColorSeq, color)
1✔
90
}
1✔
91

92
// RestoreScreen restores a previously saved screen state.
93
func (o Output) RestoreScreen() {
1✔
94
        fmt.Fprint(o.w, CSI+RestoreScreenSeq)
1✔
95
}
1✔
96

97
// SaveScreen saves the screen state.
98
func (o Output) SaveScreen() {
1✔
99
        fmt.Fprint(o.w, CSI+SaveScreenSeq)
1✔
100
}
1✔
101

102
// AltScreen switches to the alternate screen buffer. The former view can be
103
// restored with ExitAltScreen().
104
func (o Output) AltScreen() {
1✔
105
        fmt.Fprint(o.w, CSI+AltScreenSeq)
1✔
106
}
1✔
107

108
// ExitAltScreen exits the alternate screen buffer and returns to the former
109
// terminal view.
110
func (o Output) ExitAltScreen() {
1✔
111
        fmt.Fprint(o.w, CSI+ExitAltScreenSeq)
1✔
112
}
1✔
113

114
// ClearScreen clears the visible portion of the terminal.
115
func (o Output) ClearScreen() {
1✔
116
        fmt.Fprintf(o.w, CSI+EraseDisplaySeq, 2)
1✔
117
        o.MoveCursor(1, 1)
1✔
118
}
1✔
119

120
// MoveCursor moves the cursor to a given position.
121
func (o Output) MoveCursor(row int, column int) {
2✔
122
        fmt.Fprintf(o.w, CSI+CursorPositionSeq, row, column)
2✔
123
}
2✔
124

125
// HideCursor hides the cursor.
126
func (o Output) HideCursor() {
1✔
127
        fmt.Fprint(o.w, CSI+HideCursorSeq)
1✔
128
}
1✔
129

130
// ShowCursor shows the cursor.
131
func (o Output) ShowCursor() {
1✔
132
        fmt.Fprint(o.w, CSI+ShowCursorSeq)
1✔
133
}
1✔
134

135
// SaveCursorPosition saves the cursor position.
136
func (o Output) SaveCursorPosition() {
1✔
137
        fmt.Fprint(o.w, CSI+SaveCursorPositionSeq)
1✔
138
}
1✔
139

140
// RestoreCursorPosition restores a saved cursor position.
141
func (o Output) RestoreCursorPosition() {
1✔
142
        fmt.Fprint(o.w, CSI+RestoreCursorPositionSeq)
1✔
143
}
1✔
144

145
// CursorUp moves the cursor up a given number of lines.
146
func (o Output) CursorUp(n int) {
1✔
147
        fmt.Fprintf(o.w, CSI+CursorUpSeq, n)
1✔
148
}
1✔
149

150
// CursorDown moves the cursor down a given number of lines.
151
func (o Output) CursorDown(n int) {
1✔
152
        fmt.Fprintf(o.w, CSI+CursorDownSeq, n)
1✔
153
}
1✔
154

155
// CursorForward moves the cursor up a given number of lines.
156
func (o Output) CursorForward(n int) {
1✔
157
        fmt.Fprintf(o.w, CSI+CursorForwardSeq, n)
1✔
158
}
1✔
159

160
// CursorBack moves the cursor backwards a given number of cells.
161
func (o Output) CursorBack(n int) {
1✔
162
        fmt.Fprintf(o.w, CSI+CursorBackSeq, n)
1✔
163
}
1✔
164

165
// CursorNextLine moves the cursor down a given number of lines and places it at
166
// the beginning of the line.
167
func (o Output) CursorNextLine(n int) {
1✔
168
        fmt.Fprintf(o.w, CSI+CursorNextLineSeq, n)
1✔
169
}
1✔
170

171
// CursorPrevLine moves the cursor up a given number of lines and places it at
172
// the beginning of the line.
173
func (o Output) CursorPrevLine(n int) {
1✔
174
        fmt.Fprintf(o.w, CSI+CursorPreviousLineSeq, n)
1✔
175
}
1✔
176

177
// ClearLine clears the current line.
178
func (o Output) ClearLine() {
1✔
179
        fmt.Fprint(o.w, CSI+EraseEntireLineSeq)
1✔
180
}
1✔
181

182
// ClearLineLeft clears the line to the left of the cursor.
183
func (o Output) ClearLineLeft() {
1✔
184
        fmt.Fprint(o.w, CSI+EraseLineLeftSeq)
1✔
185
}
1✔
186

187
// ClearLineRight clears the line to the right of the cursor.
188
func (o Output) ClearLineRight() {
1✔
189
        fmt.Fprint(o.w, CSI+EraseLineRightSeq)
1✔
190
}
1✔
191

192
// ClearLines clears a given number of lines.
193
func (o Output) ClearLines(n int) {
1✔
194
        clearLine := fmt.Sprintf(CSI+EraseLineSeq, 2)
1✔
195
        cursorUp := fmt.Sprintf(CSI+CursorUpSeq, 1)
1✔
196
        fmt.Fprint(o.w, clearLine+strings.Repeat(cursorUp+clearLine, n))
1✔
197
}
1✔
198

199
// ChangeScrollingRegion sets the scrolling region of the terminal.
200
func (o Output) ChangeScrollingRegion(top, bottom int) {
1✔
201
        fmt.Fprintf(o.w, CSI+ChangeScrollingRegionSeq, top, bottom)
1✔
202
}
1✔
203

204
// InsertLines inserts the given number of lines at the top of the scrollable
205
// region, pushing lines below down.
206
func (o Output) InsertLines(n int) {
1✔
207
        fmt.Fprintf(o.w, CSI+InsertLineSeq, n)
1✔
208
}
1✔
209

210
// DeleteLines deletes the given number of lines, pulling any lines in
211
// the scrollable region below up.
212
func (o Output) DeleteLines(n int) {
1✔
213
        fmt.Fprintf(o.w, CSI+DeleteLineSeq, n)
1✔
214
}
1✔
215

216
// EnableMousePress enables X10 mouse mode. Button press events are sent only.
217
func (o Output) EnableMousePress() {
1✔
218
        fmt.Fprint(o.w, CSI+EnableMousePressSeq)
1✔
219
}
1✔
220

221
// DisableMousePress disables X10 mouse mode.
222
func (o Output) DisableMousePress() {
1✔
223
        fmt.Fprint(o.w, CSI+DisableMousePressSeq)
1✔
224
}
1✔
225

226
// EnableMouse enables Mouse Tracking mode.
227
func (o Output) EnableMouse() {
1✔
228
        fmt.Fprint(o.w, CSI+EnableMouseSeq)
1✔
229
}
1✔
230

231
// DisableMouse disables Mouse Tracking mode.
232
func (o Output) DisableMouse() {
1✔
233
        fmt.Fprint(o.w, CSI+DisableMouseSeq)
1✔
234
}
1✔
235

236
// EnableMouseHilite enables Hilite Mouse Tracking mode.
237
func (o Output) EnableMouseHilite() {
1✔
238
        fmt.Fprint(o.w, CSI+EnableMouseHiliteSeq)
1✔
239
}
1✔
240

241
// DisableMouseHilite disables Hilite Mouse Tracking mode.
242
func (o Output) DisableMouseHilite() {
1✔
243
        fmt.Fprint(o.w, CSI+DisableMouseHiliteSeq)
1✔
244
}
1✔
245

246
// EnableMouseCellMotion enables Cell Motion Mouse Tracking mode.
247
func (o Output) EnableMouseCellMotion() {
1✔
248
        fmt.Fprint(o.w, CSI+EnableMouseCellMotionSeq)
1✔
249
}
1✔
250

251
// DisableMouseCellMotion disables Cell Motion Mouse Tracking mode.
252
func (o Output) DisableMouseCellMotion() {
1✔
253
        fmt.Fprint(o.w, CSI+DisableMouseCellMotionSeq)
1✔
254
}
1✔
255

256
// EnableMouseAllMotion enables All Motion Mouse mode.
257
func (o Output) EnableMouseAllMotion() {
1✔
258
        fmt.Fprint(o.w, CSI+EnableMouseAllMotionSeq)
1✔
259
}
1✔
260

261
// DisableMouseAllMotion disables All Motion Mouse mode.
262
func (o Output) DisableMouseAllMotion() {
1✔
263
        fmt.Fprint(o.w, CSI+DisableMouseAllMotionSeq)
1✔
264
}
1✔
265

266
// EnableMouseExtendedMotion enables Extended Mouse mode (SGR). This should be
267
// enabled in conjunction with EnableMouseCellMotion, and EnableMouseAllMotion.
268
func (o Output) EnableMouseExtendedMode() {
1✔
269
        fmt.Fprint(o.w, CSI+EnableMouseExtendedModeSeq)
1✔
270
}
1✔
271

272
// DisableMouseExtendedMotion disables Extended Mouse mode (SGR).
273
func (o Output) DisableMouseExtendedMode() {
1✔
274
        fmt.Fprint(o.w, CSI+DisableMouseExtendedModeSeq)
1✔
275
}
1✔
276

277
// EnableMousePixelsMotion enables Pixel Motion Mouse mode (SGR-Pixels). This
278
// should be enabled in conjunction with EnableMouseCellMotion, and
279
// EnableMouseAllMotion.
280
func (o Output) EnableMousePixelsMode() {
1✔
281
        fmt.Fprint(o.w, CSI+EnableMousePixelsModeSeq)
1✔
282
}
1✔
283

284
// DisableMousePixelsMotion disables Pixel Motion Mouse mode (SGR-Pixels).
285
func (o Output) DisableMousePixelsMode() {
1✔
286
        fmt.Fprint(o.w, CSI+DisableMousePixelsModeSeq)
1✔
287
}
1✔
288

289
// SetWindowTitle sets the terminal window title.
290
func (o Output) SetWindowTitle(title string) {
1✔
291
        fmt.Fprintf(o.w, OSC+SetWindowTitleSeq, title)
1✔
292
}
1✔
293

294
// EnableBracketedPaste enables bracketed paste.
295
func (o Output) EnableBracketedPaste() {
×
296
        fmt.Fprintf(o.w, CSI+EnableBracketedPasteSeq)
×
297
}
×
298

299
// DisableBracketedPaste disables bracketed paste.
300
func (o Output) DisableBracketedPaste() {
×
301
        fmt.Fprintf(o.w, CSI+DisableBracketedPasteSeq)
×
302
}
×
303

304
// Legacy functions.
305

306
// Reset the terminal to its default style, removing any active styles.
307
//
308
// Deprecated: please use termenv.Output instead.
309
func Reset() {
×
310
        output.Reset()
×
311
}
×
312

313
// SetForegroundColor sets the default foreground color.
314
//
315
// Deprecated: please use termenv.Output instead.
316
func SetForegroundColor(color Color) {
×
317
        output.SetForegroundColor(color)
×
318
}
×
319

320
// SetBackgroundColor sets the default background color.
321
//
322
// Deprecated: please use termenv.Output instead.
323
func SetBackgroundColor(color Color) {
×
324
        output.SetBackgroundColor(color)
×
325
}
×
326

327
// SetCursorColor sets the cursor color.
328
//
329
// Deprecated: please use termenv.Output instead.
330
func SetCursorColor(color Color) {
×
331
        output.SetCursorColor(color)
×
332
}
×
333

334
// RestoreScreen restores a previously saved screen state.
335
//
336
// Deprecated: please use termenv.Output instead.
337
func RestoreScreen() {
×
338
        output.RestoreScreen()
×
339
}
×
340

341
// SaveScreen saves the screen state.
342
//
343
// Deprecated: please use termenv.Output instead.
344
func SaveScreen() {
×
345
        output.SaveScreen()
×
346
}
×
347

348
// AltScreen switches to the alternate screen buffer. The former view can be
349
// restored with ExitAltScreen().
350
//
351
// Deprecated: please use termenv.Output instead.
352
func AltScreen() {
×
353
        output.AltScreen()
×
354
}
×
355

356
// ExitAltScreen exits the alternate screen buffer and returns to the former
357
// terminal view.
358
//
359
// Deprecated: please use termenv.Output instead.
360
func ExitAltScreen() {
×
361
        output.ExitAltScreen()
×
362
}
×
363

364
// ClearScreen clears the visible portion of the terminal.
365
//
366
// Deprecated: please use termenv.Output instead.
367
func ClearScreen() {
×
368
        output.ClearScreen()
×
369
}
×
370

371
// MoveCursor moves the cursor to a given position.
372
//
373
// Deprecated: please use termenv.Output instead.
374
func MoveCursor(row int, column int) {
×
375
        output.MoveCursor(row, column)
×
376
}
×
377

378
// HideCursor hides the cursor.
379
//
380
// Deprecated: please use termenv.Output instead.
381
func HideCursor() {
×
382
        output.HideCursor()
×
383
}
×
384

385
// ShowCursor shows the cursor.
386
//
387
// Deprecated: please use termenv.Output instead.
388
func ShowCursor() {
×
389
        output.ShowCursor()
×
390
}
×
391

392
// SaveCursorPosition saves the cursor position.
393
//
394
// Deprecated: please use termenv.Output instead.
395
func SaveCursorPosition() {
×
396
        output.SaveCursorPosition()
×
397
}
×
398

399
// RestoreCursorPosition restores a saved cursor position.
400
//
401
// Deprecated: please use termenv.Output instead.
402
func RestoreCursorPosition() {
×
403
        output.RestoreCursorPosition()
×
404
}
×
405

406
// CursorUp moves the cursor up a given number of lines.
407
//
408
// Deprecated: please use termenv.Output instead.
409
func CursorUp(n int) {
×
410
        output.CursorUp(n)
×
411
}
×
412

413
// CursorDown moves the cursor down a given number of lines.
414
//
415
// Deprecated: please use termenv.Output instead.
416
func CursorDown(n int) {
×
417
        output.CursorDown(n)
×
418
}
×
419

420
// CursorForward moves the cursor up a given number of lines.
421
//
422
// Deprecated: please use termenv.Output instead.
423
func CursorForward(n int) {
×
424
        output.CursorForward(n)
×
425
}
×
426

427
// CursorBack moves the cursor backwards a given number of cells.
428
//
429
// Deprecated: please use termenv.Output instead.
430
func CursorBack(n int) {
×
431
        output.CursorBack(n)
×
432
}
×
433

434
// CursorNextLine moves the cursor down a given number of lines and places it at
435
// the beginning of the line.
436
//
437
// Deprecated: please use termenv.Output instead.
438
func CursorNextLine(n int) {
×
439
        output.CursorNextLine(n)
×
440
}
×
441

442
// CursorPrevLine moves the cursor up a given number of lines and places it at
443
// the beginning of the line.
444
//
445
// Deprecated: please use termenv.Output instead.
446
func CursorPrevLine(n int) {
×
447
        output.CursorPrevLine(n)
×
448
}
×
449

450
// ClearLine clears the current line.
451
//
452
// Deprecated: please use termenv.Output instead.
453
func ClearLine() {
×
454
        output.ClearLine()
×
455
}
×
456

457
// ClearLineLeft clears the line to the left of the cursor.
458
//
459
// Deprecated: please use termenv.Output instead.
460
func ClearLineLeft() {
×
461
        output.ClearLineLeft()
×
462
}
×
463

464
// ClearLineRight clears the line to the right of the cursor.
465
//
466
// Deprecated: please use termenv.Output instead.
467
func ClearLineRight() {
×
468
        output.ClearLineRight()
×
469
}
×
470

471
// ClearLines clears a given number of lines.
472
//
473
// Deprecated: please use termenv.Output instead.
474
func ClearLines(n int) {
×
475
        output.ClearLines(n)
×
476
}
×
477

478
// ChangeScrollingRegion sets the scrolling region of the terminal.
479
//
480
// Deprecated: please use termenv.Output instead.
481
func ChangeScrollingRegion(top, bottom int) {
×
482
        output.ChangeScrollingRegion(top, bottom)
×
483
}
×
484

485
// InsertLines inserts the given number of lines at the top of the scrollable
486
// region, pushing lines below down.
487
//
488
// Deprecated: please use termenv.Output instead.
489
func InsertLines(n int) {
×
490
        output.InsertLines(n)
×
491
}
×
492

493
// DeleteLines deletes the given number of lines, pulling any lines in
494
// the scrollable region below up.
495
//
496
// Deprecated: please use termenv.Output instead.
497
func DeleteLines(n int) {
×
498
        output.DeleteLines(n)
×
499
}
×
500

501
// EnableMousePress enables X10 mouse mode. Button press events are sent only.
502
//
503
// Deprecated: please use termenv.Output instead.
504
func EnableMousePress() {
×
505
        output.EnableMousePress()
×
506
}
×
507

508
// DisableMousePress disables X10 mouse mode.
509
//
510
// Deprecated: please use termenv.Output instead.
511
func DisableMousePress() {
×
512
        output.DisableMousePress()
×
513
}
×
514

515
// EnableMouse enables Mouse Tracking mode.
516
//
517
// Deprecated: please use termenv.Output instead.
518
func EnableMouse() {
×
519
        output.EnableMouse()
×
520
}
×
521

522
// DisableMouse disables Mouse Tracking mode.
523
//
524
// Deprecated: please use termenv.Output instead.
525
func DisableMouse() {
×
526
        output.DisableMouse()
×
527
}
×
528

529
// EnableMouseHilite enables Hilite Mouse Tracking mode.
530
//
531
// Deprecated: please use termenv.Output instead.
532
func EnableMouseHilite() {
×
533
        output.EnableMouseHilite()
×
534
}
×
535

536
// DisableMouseHilite disables Hilite Mouse Tracking mode.
537
//
538
// Deprecated: please use termenv.Output instead.
539
func DisableMouseHilite() {
×
540
        output.DisableMouseHilite()
×
541
}
×
542

543
// EnableMouseCellMotion enables Cell Motion Mouse Tracking mode.
544
//
545
// Deprecated: please use termenv.Output instead.
546
func EnableMouseCellMotion() {
×
547
        output.EnableMouseCellMotion()
×
548
}
×
549

550
// DisableMouseCellMotion disables Cell Motion Mouse Tracking mode.
551
//
552
// Deprecated: please use termenv.Output instead.
553
func DisableMouseCellMotion() {
×
554
        output.DisableMouseCellMotion()
×
555
}
×
556

557
// EnableMouseAllMotion enables All Motion Mouse mode.
558
//
559
// Deprecated: please use termenv.Output instead.
560
func EnableMouseAllMotion() {
×
561
        output.EnableMouseAllMotion()
×
562
}
×
563

564
// DisableMouseAllMotion disables All Motion Mouse mode.
565
//
566
// Deprecated: please use termenv.Output instead.
567
func DisableMouseAllMotion() {
×
568
        output.DisableMouseAllMotion()
×
569
}
×
570

571
// SetWindowTitle sets the terminal window title.
572
//
573
// Deprecated: please use termenv.Output instead.
574
func SetWindowTitle(title string) {
×
575
        output.SetWindowTitle(title)
×
576
}
×
577

578
// EnableBracketedPaste enables bracketed paste.
579
//
580
// Deprecated: please use termenv.Output instead.
581
func EnableBracketedPaste() {
×
582
        output.EnableBracketedPaste()
×
583
}
×
584

585
// DisableBracketedPaste disables bracketed paste.
586
//
587
// Deprecated: please use termenv.Output instead.
588
func DisableBracketedPaste() {
×
589
        output.DisableBracketedPaste()
×
590
}
×
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

© 2025 Coveralls, Inc