Skip to content

Commit 071a143

Browse files
committed
Merge branch 'master' of https://github.com/parroty/excoveralls into parroty-master
2 parents 43157e5 + 7952661 commit 071a143

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+903
-254
lines changed

.github/workflows/tests.yml

+11-6
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,27 @@ jobs:
88
runs-on: ubuntu-20.04
99
strategy:
1010
matrix:
11-
otp: ['20.3']
12-
elixir: ['1.4', '1.5', '1.6', '1.7']
11+
include:
12+
- otp: '21.3'
13+
elixir: '1.11'
14+
- otp: '26.0'
15+
elixir: '1.15'
16+
- otp: '27.0'
17+
elixir: '1.17'
1318
env:
1419
MIX_ENV: test
1520
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1621
steps:
17-
- uses: actions/checkout@v2
22+
- uses: actions/checkout@v3
1823
- uses: erlef/setup-beam@v1
1924
with:
2025
otp-version: ${{ matrix.otp }}
2126
elixir-version: ${{ matrix.elixir }}
22-
- uses: actions/cache@v2
27+
- uses: actions/cache@v3
2328
with:
2429
path: deps
25-
key: ${{ runner.os }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
30+
key: ${{ runner.os }}-${{ matrix.elixir }}-otp${{ matrix.otp }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
2631
restore-keys: |
27-
${{ runner.os }}-mix-
32+
${{ runner.os }}-${{ matrix.elixir }}-otp${{ matrix.otp }}-mix-
2833
- run: mix deps.get
2934
- run: mix coveralls.github

CHANGELOG.md

+46
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,49 @@
1+
0.18.3
2+
------
3+
#### Changes
4+
- Avoid warning messages for Cobertura
5+
- Update Range to use function syntax (#332)
6+
7+
0.18.2
8+
------
9+
#### Enhancements
10+
- Print warnings about incorrectly used ignore-markers (#325), such as start-marker
11+
without a corresponding stop-marker, or two start-markers without a stop-marker in-between etc.
12+
13+
#### Changes
14+
- Fix Elixir 1.17 single-quoted string warning (#327)
15+
16+
0.18.1
17+
------
18+
#### Changes
19+
- Use explicit steps to remove 1.16 deprecation warning in Cobertura (#322).
20+
21+
0.18.0
22+
------
23+
#### Changes
24+
- Always floor coverage instead of rounding (#310).
25+
- **Note:** If you want to keep the previous rounding behavior, please check the `floor_coverage` option.
26+
- https://github.com/parroty/excoveralls#coverage-options
27+
28+
0.17.1
29+
------
30+
#### Enhancements
31+
- Accept custom http options (#319).
32+
33+
0.17.0
34+
------
35+
#### Changes
36+
- Replace hackney with httpc (#311).
37+
- Update Elixir requirement to 1.11+ (#316).
38+
- Fix lcov 2.0 source file handling (#315).
39+
- Import .coverdata after test run and improve documentation (#309).
40+
- Fixes around `--import-cover` option.
41+
42+
0.16.1
43+
------
44+
#### Changes
45+
- Cobertura now handles defprotocol and defimpl definitions (#306).
46+
147
0.16.0
248
------
349
#### Enhancements

README.md

+89-9
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ def project do
4646
coveralls: :test,
4747
"coveralls.detail": :test,
4848
"coveralls.post": :test,
49-
"coveralls.html": :test
49+
"coveralls.html": :test,
50+
"coveralls.cobertura": :test
5051
]
5152
# if you want to use espec,
5253
# test_coverage: [tool: ExCoveralls, test_task: "espec"]
@@ -55,7 +56,7 @@ end
5556

5657
defp deps do
5758
[
58-
{:excoveralls, "~> 0.10", only: :test},
59+
{:excoveralls, "~> 0.18", only: :test},
5960
]
6061
end
6162
```
@@ -88,16 +89,20 @@ end
8889
- [[mix coveralls.html] Show coverage as HTML report](#mix-coverallshtml-show-coverage-as-html-report)
8990
- [[mix coveralls.json] Show coverage as JSON report](#mix-coverallsjson-show-coverage-as-json-report)
9091
- [[mix coveralls.xml] Show coverage as XML report](#mix-coverallsxml-show-coverage-as-xml-report)
92+
- [[mix coveralls.cobertura] Show coverage as Cobertura report](#mix-coverallscobertura-show-coverage-as-cobertura-report)
9193
- [[mix coveralls.lcov] Show coverage as lcov report (Experimental)](#mix-coverallslcov-show-coverage-as-lcov-report-experimental)
9294
- [coveralls.json](#coverallsjson)
93-
- [Stop Words](#stop-words)
94-
- [Exclude Files](#exclude-files)
95-
- [Terminal Report Output](#terminal-report-output)
96-
- [Coverage Options](#coverage-options)
95+
- [Stop Words](#stop-words)
96+
- [Exclude Files](#exclude-files)
97+
- [Terminal Report Output](#terminal-report-output)
98+
- [Coverage Options](#coverage-options)
99+
- [Other Considerations](#other-considerations)
97100
- [Ignore Lines](#ignore-lines)
101+
- [Silence OTP Cover Warnings](#silence-otp-cover-warnings)
102+
- [Merging Coverage Results](#merging-coverage-results)
98103
- [Notes](#notes)
99104
- [Todo](#todo)
100-
- [License](#license)
105+
- [License](#license)
101106

102107
### [mix coveralls] Show coverage
103108
Run the `MIX_ENV=test mix coveralls` command to show coverage information on localhost.
@@ -145,7 +150,8 @@ Usage: mix coveralls <Options>
145150
and your git repo resides in "app", then the root path should be: "/home/runs/app/" (from
146151
coveralls.io)
147152
--flagname Job flag name which will be shown in the Coveralls UI
148-
--import_cover Directory from where '.coverdata' files should be imported and their results added to the report
153+
--import-cover Directory from where '.coverdata' files should be imported and their results added to the report.
154+
Coverdata is imported after tests are run.
149155

150156
Usage: mix coveralls.detail [--filter file-name-pattern]
151157
Used to display coverage with detail
@@ -362,6 +368,13 @@ Output to the shell is the same as running the command `mix coveralls` (to suppr
362368
363369
Output reports are written to `cover/excoveralls.xml` by default, however, the path can be specified by overwriting the `"output_dir"` coverage option.
364370
371+
### [mix coveralls.cobertura] Show coverage as Cobertura report
372+
This task displays coverage information at the source-code level formatted as a [Cobertura](https://cobertura.github.io/cobertura/) document.
373+
The report follows a format supported by [Gitlab](https://docs.gitlab.com/ee/ci/testing/test_coverage_visualization.html) code coverage visualization.
374+
Output to the shell is the same as running the command `mix coveralls` (to suppress this output, add `"print_summary": false` to your project's `coveralls.json` file). In a similar manner to `mix coveralls.detail`, reported source code can be filtered by specifying arguments using the `--filter` flag.
375+
376+
Output reports are written to `cover/cobertura.xml` by default, however, the path can be specified by overwriting the `"output_dir"` coverage option.
377+
365378
### [mix coveralls.lcov] Show coverage as lcov report (Experimental)
366379
This task displays coverage information at the line level formatted as a lcov.
367380
The report follows a format supported by several code coverage services like VSCode extension(`ryanluker.vscode-coverage-gutters`).
@@ -432,6 +445,9 @@ to `false`:
432445
- When used in conjunction with `minimum_coverage`, overall project coverage is checked first before individual file coverages are checked.
433446
- `html_filter_full_covered`
434447
- A boolean, when `true` files with 100% coverage are not shown in the HTML report. Default to `false`.
448+
- `floor_coverage`
449+
- A boolean, when `false` coverage values are ceiled instead of floored, this means that a project with some lines
450+
that are not covered can still have a total 100% coverage. Default to `true`.
435451
436452
Example configuration file:
437453
@@ -461,6 +477,8 @@ Example configuration file:
461477
}
462478
```
463479
480+
## Other Considerations
481+
464482
### Ignore Lines
465483
466484
Use comments `coveralls-ignore-start` and `coveralls-ignore-stop` to ignore certain lines from code coverage calculation.
@@ -501,6 +519,68 @@ imported_info(_Text,_Module,_Imported) ->
501519
ok.
502520
```
503521
522+
### Merging Coverage Results
523+
524+
ExCoveralls can include `.coverdata` files in the result of the current test run through the `--import-cover` flag. This can be used to include coverage data from partitioned tests or integration tests that may run in a subprocess, for instance.
525+
526+
Coverage data is generated when running `mix test --cover`, optionally with the `--export-coverage` flag to specify an output name.
527+
528+
```shell
529+
$ mix test --only integration --cover --export-coverage integration-coverage
530+
Excluding tags: [:test]
531+
Including tags: [:integration]
532+
... test run omitted ...
533+
# Coverage data written to cover/integration-coverage.coverdata
534+
535+
# Report coverage, do not run integration tests
536+
$ mix coveralls --exclude integration
537+
Excluding tags: [:integration]
538+
... test run omitted ...
539+
540+
----------------
541+
COV FILE LINES RELEVANT MISSED
542+
...
543+
[TOTAL] 80.2% # <-- This result does not include coverage from integration tests
544+
----------------
545+
546+
# Report coverage, do not run integration tests, but include previously written coverdata
547+
$ mix coveralls --exclude integration --import-cover cover
548+
Excluding tags: [:integration]
549+
... test run omitted ...
550+
551+
----------------
552+
COV FILE LINES RELEVANT MISSED
553+
...
554+
[TOTAL] 95.3% # <-- This result now includes coverage from integration tests
555+
----------------
556+
```
557+
558+
Coverage data is imported after tests are run.
559+
560+
See the `mix test` [Coverage documentation](https://hexdocs.pm/mix/Mix.Tasks.Test.html#module-coverage) for more information on `.coverdata`.
561+
562+
### Configuring HTTP Options in ExCoveralls
563+
564+
You can customize the HTTP options used by [`:httpc`](https://www.erlang.org/doc/man/httpc.html) when posting results. The example below shows how to specify a custom `cacertfile`:
565+
566+
```elixir
567+
config :excoveralls,
568+
http_options: [
569+
timeout: 10_000,
570+
ssl: [
571+
# Refer to the secure coding guide:
572+
# https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/inets
573+
verify: :verify_peer,
574+
depth: 2,
575+
customize_hostname_check: [
576+
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
577+
],
578+
cacertfile: to_charlist(System.fetch_env!("TEST_COVERAGE_CACERTFILE"))
579+
]
580+
```
581+
582+
By default, ExCoveralls uses the `cacertfile` from [`castore`](https://hexdocs.pm/castore/api-reference.html) when the dependency is installed. If it's not available and you're running Erlang `25` or later, the system will attempt to use the OS certificates via [`:public_key.cacerts_load/0`](https://www.erlang.org/doc/man/public_key.html#cacerts_load-0).
583+
504584
### Notes
505585
- If mock library is used, it will show some warnings during execution.
506586
- https://github.com/eproxus/meck/pull/17
@@ -512,6 +592,6 @@ imported_info(_Text,_Module,_Imported) ->
512592
- It might not work well on projects which handle multiple project (Mix.Project) files.
513593
- Needs improvement on file-path handling.
514594
515-
## License
595+
# License
516596
517597
This source code is licensed under the MIT license. Copyright (c) 2013-present, parroty.

lib/conf/coveralls.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"coverage_options": {
1717
"treat_no_relevant_lines_as_covered": false,
1818
"output_dir": "cover/",
19-
"minimum_coverage": 0
19+
"minimum_coverage": 0,
20+
"floor_coverage": true
2021
},
2122

2223
"terminal_options": {

lib/excoveralls.ex

+7-6
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,14 @@ defmodule ExCoveralls do
4141
def start(compile_path, opts) do
4242
Cover.compile(compile_path)
4343

44-
options = ConfServer.get()
45-
if options[:import_cover] do
46-
Cover.import(options[:import_cover])
47-
end
48-
4944
fn() ->
50-
execute(ConfServer.get, compile_path, opts)
45+
options = ConfServer.get()
46+
47+
if options[:import_cover] do
48+
Cover.import(options[:import_cover])
49+
end
50+
51+
execute(options, compile_path, opts)
5152
end
5253
end
5354

lib/excoveralls/circle.ex

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ defmodule ExCoveralls.Circle do
33
Handles circle-ci integration with coveralls.
44
"""
55
alias ExCoveralls.Poster
6+
alias ExCoveralls.Stats
67

78
def execute(stats, options) do
89
json = generate_json(stats, Enum.into(options, %{}))
@@ -20,7 +21,7 @@ defmodule ExCoveralls.Circle do
2021
service_number: get_number(),
2122
service_job_id: get_job_id(),
2223
service_pull_request: get_pull_request(),
23-
source_files: stats,
24+
source_files: Stats.serialize(stats),
2425
git: generate_git_info(),
2526
parallel: options[:parallel],
2627
flag_name: options[:flagname]

lib/excoveralls/cobertura.ex

+15-9
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,12 @@ defmodule ExCoveralls.Cobertura do
156156
end
157157

158158
defp module_name(source) do
159-
case Regex.run(~r/^defmodule\s+(.*)\s+do$/m, source, capture: :all_but_first) do
160-
[module] ->
161-
module
162-
163-
_ ->
164-
[module] = Regex.run(~r/^-module\((.*)\)\.$/m, source, capture: :all_but_first)
165-
module
166-
end
159+
with nil <- Regex.run(~r/^def(?:module|protocol|impl)\s+(.*)\s+do$/m, source, capture: :all_but_first),
160+
nil <- Regex.run(~r/^-module\((.*)\)\.$/m, source, capture: :all_but_first) do
161+
"UNKNOWN_MODULE"
162+
else
163+
[module] -> module
164+
end
167165
end
168166

169167
defp package_name(path, c_paths) do
@@ -172,7 +170,7 @@ defmodule ExCoveralls.Cobertura do
172170
c_paths
173171
|> Enum.find_value(package_name, fn c_path ->
174172
if String.starts_with?(package_name, c_path) do
175-
String.slice(package_name, (String.length(c_path) + 1)..-1)
173+
String.slice(package_name, get_slice_range_for_package_name(c_path))
176174
else
177175
false
178176
end
@@ -182,6 +180,14 @@ defmodule ExCoveralls.Cobertura do
182180
|> to_charlist()
183181
end
184182

183+
# TODO: Remove when we require Elixir 1.12 as minimum and inline it with range syntax
184+
if Version.match?(System.version(), ">= 1.12.0") do
185+
# We use Range.new/3 because using x..y//step would give a syntax error on Elixir < 1.12
186+
defp get_slice_range_for_package_name(c_path), do: Range.new(String.length(c_path) + 1, -1, 1)
187+
else
188+
defp get_slice_range_for_package_name(c_path), do: Range.new(String.length(c_path) + 1, -1)
189+
end
190+
185191
defp rate(valid_lines) when length(valid_lines) == 0, do: 0.0
186192

187193
defp rate(valid_lines) do

lib/excoveralls/cover.ex

+3-7
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ defmodule ExCoveralls.Cover do
1414
{:ok, string_io} = StringIO.open("")
1515
Process.group_leader(pid, string_io)
1616

17-
:cover.compile_beam_directory(compile_path |> string_to_charlist)
17+
compile_path
18+
|> String.to_charlist()
19+
|> :cover.compile_beam_directory()
1820
end
1921

2022
@doc """
@@ -59,12 +61,6 @@ defmodule ExCoveralls.Cover do
5961
:cover.analyse(module, :calls, :line)
6062
end
6163

62-
if Version.compare(System.version, "1.3.0") == :lt do
63-
defp string_to_charlist(string), do: String.to_char_list(string)
64-
else
65-
defp string_to_charlist(string), do: String.to_charlist(string)
66-
end
67-
6864
defp file_exist?(module, path) do
6965
if File.exists?(path) do
7066
true

lib/excoveralls/drone.ex

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ defmodule ExCoveralls.Drone do
33
Handles drone-ci integration with coveralls.
44
"""
55
alias ExCoveralls.Poster
6+
alias ExCoveralls.Stats
67

78
def execute(stats, options) do
89
json = generate_json(stats, Enum.into(options, %{}))
@@ -20,7 +21,7 @@ defmodule ExCoveralls.Drone do
2021
service_number: get_build_num(),
2122
service_job_id: get_build_num(),
2223
service_pull_request: get_pull_request(),
23-
source_files: stats,
24+
source_files: Stats.serialize(stats),
2425
git: generate_git_info(),
2526
parallel: options[:parallel],
2627
flag_name: options[:flagname]

lib/excoveralls/github.ex

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ defmodule ExCoveralls.Github do
33
Handles GitHub Actions integration with coveralls.
44
"""
55
alias ExCoveralls.Poster
6+
alias ExCoveralls.Stats
67

78
def execute(stats, options) do
89
json = generate_json(stats, Enum.into(options, %{}))
@@ -20,7 +21,7 @@ defmodule ExCoveralls.Github do
2021
%{
2122
repo_token: get_env("GITHUB_TOKEN"),
2223
service_name: "github",
23-
source_files: stats,
24+
source_files: Stats.serialize(stats),
2425
parallel: options[:parallel],
2526
flag_name: options[:flagname],
2627
git: git_info()

0 commit comments

Comments
 (0)