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

JuliaLang / julia / #37997

29 Jan 2025 02:08AM UTC coverage: 17.283% (-68.7%) from 85.981%
#37997

push

local

web-flow
bpart: Start enforcing min_world for global variable definitions (#57150)

This is the analog of #57102 for global variables. Unlike for consants,
there is no automatic global backdate mechanism. The reasoning for this
is that global variables can be declared at any time, unlike constants
which can only be decalared once their value is available. As a result
code patterns using `Core.eval` to declare globals are rarer and likely
incorrect.

1 of 22 new or added lines in 3 files covered. (4.55%)

31430 existing lines in 188 files now uncovered.

7903 of 45728 relevant lines covered (17.28%)

98663.7 hits per line

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

0.0
/base/abstractarraymath.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
 ## Basic functions ##
4

UNCOV
5
isreal(x::AbstractArray) = all(isreal,x)
×
UNCOV
6
iszero(x::AbstractArray) = all(iszero,x)
×
7
isreal(x::AbstractArray{<:Real}) = true
×
8

9
## Constructors ##
10

11
"""
12
    vec(a::AbstractArray) -> AbstractVector
13

14
Reshape the array `a` as a one-dimensional column vector. Return `a` if it is
15
already an `AbstractVector`. The resulting array
16
shares the same underlying data as `a`, so it will only be mutable if `a` is
17
mutable, in which case modifying one will also modify the other.
18

19
# Examples
20
```jldoctest
21
julia> a = [1 2 3; 4 5 6]
22
2×3 Matrix{Int64}:
23
 1  2  3
24
 4  5  6
25

26
julia> vec(a)
27
6-element Vector{Int64}:
28
 1
29
 4
30
 2
31
 5
32
 3
33
 6
34

35
julia> vec(1:3)
36
1:3
37
```
38

39
See also [`reshape`](@ref), [`dropdims`](@ref).
40
"""
UNCOV
41
vec(a::AbstractArray) = reshape(a,length(a))
×
UNCOV
42
vec(a::AbstractVector) = a
×
43

44
_sub(::Tuple{}, ::Tuple{}) = ()
×
UNCOV
45
_sub(t::Tuple, ::Tuple{}) = t
×
UNCOV
46
_sub(t::Tuple, s::Tuple) = _sub(tail(t), tail(s))
×
47

48
"""
49
    dropdims(A; dims)
50

51
Return an array with the same data as `A`, but with the dimensions specified by
52
`dims` removed. `size(A,d)` must equal 1 for every `d` in `dims`,
53
and repeated dimensions or numbers outside `1:ndims(A)` are forbidden.
54

55
The result shares the same underlying data as `A`, such that the
56
result is mutable if and only if `A` is mutable, and setting elements of one
57
alters the values of the other.
58

59
See also: [`reshape`](@ref), [`vec`](@ref).
60

61
# Examples
62
```jldoctest
63
julia> a = reshape(Vector(1:4),(2,2,1,1))
64
2×2×1×1 Array{Int64, 4}:
65
[:, :, 1, 1] =
66
 1  3
67
 2  4
68

69
julia> b = dropdims(a; dims=3)
70
2×2×1 Array{Int64, 3}:
71
[:, :, 1] =
72
 1  3
73
 2  4
74

75
julia> b[1,1,1] = 5; a
76
2×2×1×1 Array{Int64, 4}:
77
[:, :, 1, 1] =
78
 5  3
79
 2  4
80
```
81
"""
UNCOV
82
dropdims(A; dims) = _dropdims(A, dims)
×
UNCOV
83
function _dropdims(A::AbstractArray, dims::Dims)
×
UNCOV
84
    for i in eachindex(dims)
×
UNCOV
85
        1 <= dims[i] <= ndims(A) || throw(ArgumentError("dropped dims must be in range 1:ndims(A)"))
×
UNCOV
86
        length(axes(A, dims[i])) == 1 || throw(ArgumentError("dropped dims must all be size 1"))
×
UNCOV
87
        for j = 1:i-1
×
UNCOV
88
            dims[j] == dims[i] && throw(ArgumentError("dropped dims must be unique"))
×
UNCOV
89
        end
×
UNCOV
90
    end
×
UNCOV
91
    ax = _foldoneto((ds, d) -> d in dims ? ds : (ds..., axes(A,d)), (), Val(ndims(A)))
×
UNCOV
92
    reshape(A, ax::typeof(_sub(axes(A), dims)))
×
93
end
UNCOV
94
_dropdims(A::AbstractArray, dim::Integer) = _dropdims(A, (Int(dim),))
×
95

96

97
"""
98
    insertdims(A; dims)
99

100
Inverse of [`dropdims`](@ref); return an array with new singleton dimensions
101
at every dimension in `dims`.
102

103
Repeated dimensions are forbidden and the largest entry in `dims` must be
104
less than or equal than `ndims(A) + length(dims)`.
105

106
The result shares the same underlying data as `A`, such that the
107
result is mutable if and only if `A` is mutable, and setting elements of one
108
alters the values of the other.
109

110
See also: [`dropdims`](@ref), [`reshape`](@ref), [`vec`](@ref).
111
# Examples
112
```jldoctest
113
julia> x = [1 2 3; 4 5 6]
114
2×3 Matrix{Int64}:
115
 1  2  3
116
 4  5  6
117

118
julia> insertdims(x, dims=3)
119
2×3×1 Array{Int64, 3}:
120
[:, :, 1] =
121
 1  2  3
122
 4  5  6
123

124
julia> insertdims(x, dims=(1,2,5)) == reshape(x, 1, 1, 2, 3, 1)
125
true
126

127
julia> dropdims(insertdims(x, dims=(1,2,5)), dims=(1,2,5))
128
2×3 Matrix{Int64}:
129
 1  2  3
130
 4  5  6
131
```
132

133
!!! compat "Julia 1.12"
134
    Requires Julia 1.12 or later.
135
"""
UNCOV
136
insertdims(A; dims) = _insertdims(A, dims)
×
UNCOV
137
function _insertdims(A::AbstractArray{T, N}, dims::NTuple{M, Int}) where {T, N, M}
×
UNCOV
138
    for i in eachindex(dims)
×
UNCOV
139
        1 ≤ dims[i] || throw(ArgumentError("the smallest entry in dims must be ≥ 1."))
×
UNCOV
140
        dims[i] ≤ N+M || throw(ArgumentError("the largest entry in dims must be not larger than the dimension of the array and the length of dims added"))
×
UNCOV
141
        for j = 1:i-1
×
UNCOV
142
            dims[j] == dims[i] && throw(ArgumentError("inserted dims must be unique"))
×
UNCOV
143
        end
×
UNCOV
144
    end
×
145

146
    # acc is a tuple, where the first entry is the final shape
147
    # the second entry off acc is a counter for the axes of A
UNCOV
148
    inds= Base._foldoneto((acc, i) ->
×
149
                            i ∈ dims
150
                                ? ((acc[1]..., Base.OneTo(1)), acc[2])
151
                                : ((acc[1]..., axes(A, acc[2])), acc[2] + 1),
152
                            ((), 1), Val(N+M))
UNCOV
153
    new_shape = inds[1]
×
UNCOV
154
    return reshape(A, new_shape)
×
155
end
UNCOV
156
_insertdims(A::AbstractArray, dim::Integer) = _insertdims(A, (Int(dim),))
×
157

158

159

160
## Unary operators ##
161

162
"""
163
    conj!(A)
164

165
Transform an array to its complex conjugate in-place.
166

167
See also [`conj`](@ref).
168

169
# Examples
170
```jldoctest
171
julia> A = [1+im 2-im; 2+2im 3+im]
172
2×2 Matrix{Complex{Int64}}:
173
 1+1im  2-1im
174
 2+2im  3+1im
175

176
julia> conj!(A);
177

178
julia> A
179
2×2 Matrix{Complex{Int64}}:
180
 1-1im  2+1im
181
 2-2im  3-1im
182
```
183
"""
UNCOV
184
conj!(A::AbstractArray{<:Number}) = (@inbounds broadcast!(conj, A, A); A)
×
UNCOV
185
conj!(x::AbstractArray{<:Real}) = x
×
UNCOV
186
conj!(A::AbstractArray) = (foreach(conj!, A); A)
×
187

188
"""
189
    conj(A::AbstractArray)
190

191
Return an array containing the complex conjugate of each entry in array `A`.
192

193
Equivalent to `conj.(A)`, except that when `eltype(A) <: Real`
194
`A` is returned without copying, and that when `A` has zero dimensions,
195
a 0-dimensional array is returned (rather than a scalar).
196

197
# Examples
198
```jldoctest
199
julia> conj([1, 2im, 3 + 4im])
200
3-element Vector{Complex{Int64}}:
201
 1 + 0im
202
 0 - 2im
203
 3 - 4im
204

205
julia> conj(fill(2 - im))
206
0-dimensional Array{Complex{Int64}, 0}:
207
2 + 1im
208
```
209
"""
UNCOV
210
conj(A::AbstractArray) = broadcast_preserving_zero_d(conj, A)
×
UNCOV
211
conj(A::AbstractArray{<:Real}) = A
×
212

213
"""
214
    real(A::AbstractArray)
215

216
Return an array containing the real part of each entry in array `A`.
217

218
Equivalent to `real.(A)`, except that when `eltype(A) <: Real`
219
`A` is returned without copying, and that when `A` has zero dimensions,
220
a 0-dimensional array is returned (rather than a scalar).
221

222
# Examples
223
```jldoctest
224
julia> real([1, 2im, 3 + 4im])
225
3-element Vector{Int64}:
226
 1
227
 0
228
 3
229

230
julia> real(fill(2 - im))
231
0-dimensional Array{Int64, 0}:
232
2
233
```
234
"""
UNCOV
235
real(A::AbstractArray) = broadcast_preserving_zero_d(real, A)
×
UNCOV
236
real(A::AbstractArray{<:Real}) = A
×
237

238
"""
239
    imag(A::AbstractArray)
240

241
Return an array containing the imaginary part of each entry in array `A`.
242

243
Equivalent to `imag.(A)`, except that when `A` has zero dimensions,
244
a 0-dimensional array is returned (rather than a scalar).
245

246
# Examples
247
```jldoctest
248
julia> imag([1, 2im, 3 + 4im])
249
3-element Vector{Int64}:
250
 0
251
 2
252
 4
253

254
julia> imag(fill(2 - im))
255
0-dimensional Array{Int64, 0}:
256
-1
257
```
258
"""
UNCOV
259
imag(A::AbstractArray) = broadcast_preserving_zero_d(imag, A)
×
UNCOV
260
imag(A::AbstractArray{<:Real}) = zero(A)
×
261

262
"""
263
    reim(A::AbstractArray)
264

265
Return a tuple of two arrays containing respectively the real and the imaginary
266
part of each entry in `A`.
267

268
Equivalent to `(real.(A), imag.(A))`, except that when `eltype(A) <: Real`
269
`A` is returned without copying to represent the real part, and that when `A` has
270
zero dimensions, a 0-dimensional array is returned (rather than a scalar).
271

272
# Examples
273
```jldoctest
274
julia> reim([1, 2im, 3 + 4im])
275
([1, 0, 3], [0, 2, 4])
276

277
julia> reim(fill(2 - im))
278
(fill(2), fill(-1))
279
```
280
"""
281
reim(A::AbstractArray)
282

UNCOV
283
-(A::AbstractArray) = broadcast_preserving_zero_d(-, A)
×
284

UNCOV
285
+(x::AbstractArray{<:Number}) = x
×
UNCOV
286
*(x::AbstractArray{<:Number,2}) = x
×
287

288
# index A[:,:,...,i,:,:,...] where "i" is in dimension "d"
289

290
"""
291
    selectdim(A, d::Integer, i)
292

293
Return a view of all the data of `A` where the index for dimension `d` equals `i`.
294

295
Equivalent to `view(A,:,:,...,i,:,:,...)` where `i` is in position `d`.
296

297
See also: [`eachslice`](@ref).
298

299
# Examples
300
```jldoctest
301
julia> A = [1 2 3 4; 5 6 7 8]
302
2×4 Matrix{Int64}:
303
 1  2  3  4
304
 5  6  7  8
305

306
julia> selectdim(A, 2, 3)
307
2-element view(::Matrix{Int64}, :, 3) with eltype Int64:
308
 3
309
 7
310

311
julia> selectdim(A, 2, 3:4)
312
2×2 view(::Matrix{Int64}, :, 3:4) with eltype Int64:
313
 3  4
314
 7  8
315
```
316
"""
UNCOV
317
@inline selectdim(A::AbstractArray, d::Integer, i) = _selectdim(A, d, i, _setindex(i, d, map(Slice, axes(A))...))
×
UNCOV
318
@noinline function _selectdim(A, d, i, idxs)
×
UNCOV
319
    d >= 1 || throw(ArgumentError("dimension must be ≥ 1, got $d"))
×
UNCOV
320
    nd = ndims(A)
×
UNCOV
321
    d > nd && (i == 1 || throw(BoundsError(A, (ntuple(Returns(Colon()),d-1)..., i))))
×
UNCOV
322
    return view(A, idxs...)
×
323
end
324

UNCOV
325
function circshift(a::AbstractArray, shiftamt::Real)
×
UNCOV
326
    circshift!(similar(a), a, (Integer(shiftamt),))
×
327
end
UNCOV
328
circshift(a::AbstractArray, shiftamt::DimsInteger) = circshift!(similar(a), a, shiftamt)
×
329
"""
330
    circshift(A, shifts)
331

332
Circularly shift, i.e. rotate, the data in `A`. The second argument is a tuple or
333
vector giving the amount to shift in each dimension, or an integer to shift only in the
334
first dimension.
335

336
The generated code is most efficient when the shift amounts are known at compile-time, i.e.,
337
compile-time constants.
338

339
See also: [`circshift!`](@ref), [`circcopy!`](@ref), [`bitrotate`](@ref), [`<<`](@ref).
340

341
# Examples
342
```jldoctest
343
julia> b = reshape(Vector(1:16), (4,4))
344
4×4 Matrix{Int64}:
345
 1  5   9  13
346
 2  6  10  14
347
 3  7  11  15
348
 4  8  12  16
349

350
julia> circshift(b, (0,2))
351
4×4 Matrix{Int64}:
352
  9  13  1  5
353
 10  14  2  6
354
 11  15  3  7
355
 12  16  4  8
356

357
julia> circshift(b, (-1,0))
358
4×4 Matrix{Int64}:
359
 2  6  10  14
360
 3  7  11  15
361
 4  8  12  16
362
 1  5   9  13
363

364
julia> a = BitArray([true, true, false, false, true])
365
5-element BitVector:
366
 1
367
 1
368
 0
369
 0
370
 1
371

372
julia> circshift(a, 1)
373
5-element BitVector:
374
 1
375
 1
376
 1
377
 0
378
 0
379

380
julia> circshift(a, -1)
381
5-element BitVector:
382
 1
383
 0
384
 0
385
 1
386
 1
387

388
julia> x = (1, 2, 3, 4, 5)
389
(1, 2, 3, 4, 5)
390

391
julia> circshift(x, 4)
392
(2, 3, 4, 5, 1)
393

394
julia> z = (1, 'a', -7.0, 3)
395
(1, 'a', -7.0, 3)
396

397
julia> circshift(z, -1)
398
('a', -7.0, 3, 1)
399
```
400
"""
UNCOV
401
function circshift(a::AbstractArray, shiftamt)
×
UNCOV
402
    circshift!(similar(a), a, map(Integer, (shiftamt...,)))
×
403
end
404

405
## Other array functions ##
406

407
"""
408
    repeat(A::AbstractArray, counts::Integer...)
409

410
Construct an array by repeating array `A` a given number of times in each dimension, specified by `counts`.
411

412
See also: [`fill`](@ref), [`Iterators.repeated`](@ref), [`Iterators.cycle`](@ref).
413

414
# Examples
415
```jldoctest
416
julia> repeat([1, 2, 3], 2)
417
6-element Vector{Int64}:
418
 1
419
 2
420
 3
421
 1
422
 2
423
 3
424

425
julia> repeat([1, 2, 3], 2, 3)
426
6×3 Matrix{Int64}:
427
 1  1  1
428
 2  2  2
429
 3  3  3
430
 1  1  1
431
 2  2  2
432
 3  3  3
433
```
434
"""
UNCOV
435
function repeat(A::AbstractArray, counts...)
×
UNCOV
436
    return repeat(A, outer=counts)
×
437
end
438

439
"""
440
    repeat(A::AbstractArray; inner=ntuple(Returns(1), ndims(A)), outer=ntuple(Returns(1), ndims(A)))
441

442
Construct an array by repeating the entries of `A`. The i-th element of `inner` specifies
443
the number of times that the individual entries of the i-th dimension of `A` should be
444
repeated. The i-th element of `outer` specifies the number of times that a slice along the
445
i-th dimension of `A` should be repeated. If `inner` or `outer` are omitted, no repetition
446
is performed.
447

448
# Examples
449
```jldoctest
450
julia> repeat(1:2, inner=2)
451
4-element Vector{Int64}:
452
 1
453
 1
454
 2
455
 2
456

457
julia> repeat(1:2, outer=2)
458
4-element Vector{Int64}:
459
 1
460
 2
461
 1
462
 2
463

464
julia> repeat([1 2; 3 4], inner=(2, 1), outer=(1, 3))
465
4×6 Matrix{Int64}:
466
 1  2  1  2  1  2
467
 1  2  1  2  1  2
468
 3  4  3  4  3  4
469
 3  4  3  4  3  4
470
```
471
"""
UNCOV
472
function repeat(A::AbstractArray; inner = nothing, outer = nothing)
×
UNCOV
473
    return _RepeatInnerOuter.repeat(A, inner=inner, outer=outer)
×
474
end
475

476
module _RepeatInnerOuter
477

UNCOV
478
function repeat(arr; inner=nothing, outer=nothing)
×
UNCOV
479
    check(arr, inner, outer)
×
UNCOV
480
    arr, inner, outer = resolve(arr, inner, outer)
×
UNCOV
481
    repeat_inner_outer(arr, inner, outer)
×
482
end
483

UNCOV
484
to_tuple(t::Tuple) = t
×
UNCOV
485
to_tuple(x::Integer) = (x,)
×
UNCOV
486
to_tuple(itr) = tuple(itr...)
×
487

UNCOV
488
function pad(a, b)
×
UNCOV
489
    N = max(length(a), length(b))
×
UNCOV
490
    Base.fill_to_length(a, 1, Val(N)), Base.fill_to_length(b, 1, Val(N))
×
491
end
UNCOV
492
function pad(a, b, c)
×
UNCOV
493
    N = max(max(length(a), length(b)), length(c))
×
UNCOV
494
    Base.fill_to_length(a, 1, Val(N)), Base.fill_to_length(b, 1, Val(N)), Base.fill_to_length(c, 1, Val(N))
×
495
end
496

UNCOV
497
function resolve(arr::AbstractArray{<:Any, N}, inner::NTuple{N, Any}, outer::NTuple{N,Any}) where {N}
×
UNCOV
498
    arr, inner, outer
×
499
end
UNCOV
500
function resolve(arr, inner, outer)
×
UNCOV
501
    dims, inner, outer = pad(size(arr), to_tuple(inner), to_tuple(outer))
×
UNCOV
502
    reshape(arr, dims), inner, outer
×
503
end
UNCOV
504
function resolve(arr, inner::Nothing, outer::Nothing)
×
UNCOV
505
    return arr, inner, outer
×
506
end
UNCOV
507
function resolve(arr, inner::Nothing, outer)
×
UNCOV
508
    dims, outer = pad(size(arr), to_tuple(outer))
×
UNCOV
509
    reshape(arr, dims), inner, outer
×
510
end
UNCOV
511
function resolve(arr, inner, outer::Nothing)
×
UNCOV
512
    dims, inner = pad(size(arr), to_tuple(inner))
×
UNCOV
513
    reshape(arr, dims), inner, outer
×
514
end
515

UNCOV
516
function check(arr, inner, outer)
×
UNCOV
517
    if inner !== nothing
×
518
        # TODO: Currently one based indexing is demanded for inner !== nothing,
519
        # but not for outer !== nothing. Decide for something consistent.
UNCOV
520
        Base.require_one_based_indexing(arr)
×
UNCOV
521
        if !all(n -> n isa Integer, inner)
×
522
            throw(ArgumentError("repeat requires integer counts, got inner = $inner"))
×
523
        end
UNCOV
524
        if any(<(0), inner)
×
UNCOV
525
            throw(ArgumentError("no inner repetition count may be negative; got $inner"))
×
526
        end
UNCOV
527
        if length(inner) < ndims(arr)
×
UNCOV
528
            throw(ArgumentError("number of inner repetitions ($(length(inner))) cannot be less than number of dimensions of input array ($(ndims(arr)))"))
×
529
        end
530
    end
UNCOV
531
    if outer !== nothing
×
UNCOV
532
        if !all(n -> n isa Integer, outer)
×
533
            throw(ArgumentError("repeat requires integer counts, got outer = $outer"))
×
534
        end
UNCOV
535
        if any(<(0), outer)
×
536
            throw(ArgumentError("no outer repetition count may be negative; got $outer"))
×
537
        end
UNCOV
538
        if (length(outer) < ndims(arr)) && (inner !== nothing)
×
UNCOV
539
            throw(ArgumentError("number of outer repetitions ($(length(outer))) cannot be less than number of dimensions of input array ($(ndims(arr)))"))
×
540
        end
541
    end
542
end
543

UNCOV
544
repeat_inner_outer(arr, inner::Nothing, outer::Nothing) = arr
×
UNCOV
545
repeat_inner_outer(arr, ::Nothing, outer) = repeat_outer(arr, outer)
×
UNCOV
546
repeat_inner_outer(arr, inner, ::Nothing) = repeat_inner(arr, inner)
×
UNCOV
547
repeat_inner_outer(arr, inner, outer) = repeat_outer(repeat_inner(arr, inner), outer)
×
548

UNCOV
549
function repeat_outer(a::AbstractMatrix, (m,n)::NTuple{2, Any})
×
UNCOV
550
    o, p = size(a,1), size(a,2)
×
UNCOV
551
    b = similar(a, o*m, p*n)
×
UNCOV
552
    for j=1:n
×
UNCOV
553
        d = (j-1)*p+1
×
UNCOV
554
        R = d:d+p-1
×
UNCOV
555
        for i=1:m
×
UNCOV
556
            c = (i-1)*o+1
×
UNCOV
557
            @inbounds b[c:c+o-1, R] = a
×
UNCOV
558
        end
×
UNCOV
559
    end
×
UNCOV
560
    return b
×
561
end
562

UNCOV
563
function repeat_outer(a::AbstractVector, (m,)::Tuple{Any})
×
UNCOV
564
    o = length(a)
×
UNCOV
565
    b = similar(a, o*m)
×
UNCOV
566
    for i=1:m
×
UNCOV
567
        c = (i-1)*o+1
×
UNCOV
568
        @inbounds b[c:c+o-1] = a
×
UNCOV
569
    end
×
UNCOV
570
    return b
×
571
end
572

UNCOV
573
function repeat_outer(arr::AbstractArray{<:Any,N}, dims::NTuple{N,Any}) where {N}
×
UNCOV
574
    insize  = size(arr)
×
UNCOV
575
    outsize = map(*, insize, dims)
×
UNCOV
576
    out = similar(arr, outsize)
×
UNCOV
577
    for I in CartesianIndices(arr)
×
UNCOV
578
        for J in CartesianIndices(dims)
×
UNCOV
579
            TIJ = map(Tuple(I), Tuple(J), insize) do i, j, d
×
UNCOV
580
                i + d * (j-1)
×
581
            end
UNCOV
582
            IJ = CartesianIndex(TIJ)
×
UNCOV
583
            @inbounds out[IJ] = arr[I]
×
UNCOV
584
        end
×
UNCOV
585
    end
×
UNCOV
586
    return out
×
587
end
588

UNCOV
589
function repeat_inner(arr, inner)
×
UNCOV
590
    outsize = map(*, size(arr), inner)
×
UNCOV
591
    out = similar(arr, outsize)
×
UNCOV
592
    for I in CartesianIndices(arr)
×
UNCOV
593
        for J in CartesianIndices(inner)
×
UNCOV
594
            TIJ = map(Tuple(I), Tuple(J), inner) do i, j, d
×
UNCOV
595
                (i-1) * d + j
×
596
            end
UNCOV
597
            IJ = CartesianIndex(TIJ)
×
UNCOV
598
            @inbounds out[IJ] = arr[I]
×
UNCOV
599
        end
×
UNCOV
600
    end
×
UNCOV
601
    return out
×
602
end
603

604
end#module
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