Skip to content

Commit 53aa5b2

Browse files
authored
Support codecov (with configuration) for test_with_coverage (#405)
1 parent 1f840af commit 53aa5b2

File tree

12 files changed

+176
-75
lines changed

12 files changed

+176
-75
lines changed

.github/workflows/dart.yml

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mono_repo.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
merge_stages:
33
- smoke_test
44

5+
coverage_service:
6+
- coveralls
7+
- codecov
8+
59
github:
610
# Setting just `cron` keeps the defaults for `push` and `pull_request`
711
cron: '0 0 * * 0' # “At 00:00 (UTC) on Sunday.”

mono_repo/CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
## 6.4.0-dev
33

44
- Added support for `test_with_coverage`.
5-
Uses `package:coverage` and [Coveralls](https://coveralls.io) to track test
6-
code coverage.
5+
Uses `package:coverage` and supports [Coveralls](https://coveralls.io)
6+
(the default) and [Codecov](https://codecov.com/) to track test code coverage.
77
- Added `--verbose` flag. Helps when debugging failures.
88

99
## 6.3.0

mono_repo/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,17 @@ self_validate: analyze
137137
# Use this key to merge stages across packages to create fewer jobs
138138
merge_stages:
139139
- analyze
140+
141+
# When using `test_with_coverage`, this setting configures the service that
142+
# results are uploaded to.
143+
# Note: you can configure both options, but this would be unusual.
144+
# Note: you can configure this key with no values, to just generate the files
145+
# locally. This may be to enable other, custom processing.
146+
coverage_service:
147+
# https://coveralls.io/ - the default
148+
- coveralls
149+
# https://codecov.io/ – the other option
150+
- codecov
140151
```
141152
142153
### Adding a package config

mono_repo/lib/src/basic_config.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'coverage_processor.dart';
6+
7+
/// Represents top-level configuration values that are needed by specific
8+
/// jobs or actions.
9+
///
10+
/// Meant to be minimal and expanded on an as-needed basis.
11+
abstract class BasicConfiguration {
12+
Set<CoverageProcessor> get coverageProcessors;
13+
}

mono_repo/lib/src/commands/github/action_info.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ enum ActionInfo implements Comparable<ActionInfo> {
2929
repo: 'coverallsapp/github-action',
3030
version: 'master',
3131
completionJobFactory: _coverageCompletionJob,
32+
),
33+
34+
/// See https://github.com/marketplace/actions/codecov
35+
codecov(
36+
name: 'Upload coverage to codecov.io',
37+
repo: 'codecov/codecov-action',
38+
version: 'master',
3239
);
3340

3441
const ActionInfo({

mono_repo/lib/src/commands/github/github_yaml.dart

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'dart:collection';
66

7+
import '../../basic_config.dart';
78
import '../../ci_shared.dart';
89
import '../../github_config.dart';
910
import '../../mono_config.dart';
@@ -195,7 +196,7 @@ Iterable<_MapEntryWithStage> _listJobs(
195196

196197
for (var job in jobs) {
197198
if (job is _SelfValidateJob) {
198-
yield jobEntry(_selfValidateJob(), job.stageName);
199+
yield jobEntry(_selfValidateJob(rootConfig.monoConfig), job.stageName);
199200
continue;
200201
}
201202

@@ -331,6 +332,7 @@ extension on CIJobEntry {
331332
job.flavor,
332333
job.sdk,
333334
commandEntries,
335+
config: rootConfig.monoConfig,
334336
additionalCacheKeys: {
335337
'packages': packages.join('-'),
336338
'commands': commands.join('-'),
@@ -373,6 +375,7 @@ Job _githubJob(
373375
PackageFlavor packageFlavor,
374376
String sdkVersion,
375377
List<_CommandEntryBase> runCommands, {
378+
required BasicConfiguration config,
376379
Map<String, String>? additionalCacheKeys,
377380
}) =>
378381
Job(
@@ -392,7 +395,7 @@ Job _githubJob(
392395
ActionInfo.checkout.usage(
393396
id: 'checkout',
394397
),
395-
for (var command in runCommands) ...command.runContent,
398+
for (var command in runCommands) ...command.runContent(config),
396399
],
397400
);
398401

@@ -413,7 +416,8 @@ class _CommandEntryBase {
413416

414417
_CommandEntryBase(this.name, this.run);
415418

416-
Iterable<Step> get runContent => [Step.run(name: name, run: run)];
419+
Iterable<Step> runContent(BasicConfiguration config) =>
420+
[Step.run(name: name, run: run)];
417421
}
418422

419423
class _CommandEntry extends _CommandEntryBase {
@@ -432,15 +436,15 @@ class _CommandEntry extends _CommandEntryBase {
432436
});
433437

434438
@override
435-
Iterable<Step> get runContent => [
439+
Iterable<Step> runContent(BasicConfiguration config) => [
436440
Step.run(
437441
id: id,
438442
name: name,
439443
ifContent: ifCondition,
440444
workingDirectory: workingDirectory,
441445
run: run,
442446
),
443-
...?type?.afterEachSteps(workingDirectory),
447+
...?type?.afterEachSteps(workingDirectory, config),
444448
];
445449
}
446450

@@ -488,7 +492,7 @@ String _maxLength(String input) {
488492
return input.substring(0, 512 - hash.length) + hash;
489493
}
490494

491-
Job _selfValidateJob() => _githubJob(
495+
Job _selfValidateJob(BasicConfiguration config) => _githubJob(
492496
selfValidateJobName,
493497
_ubuntuLatest,
494498
PackageFlavor.dart,
@@ -497,6 +501,7 @@ Job _selfValidateJob() => _githubJob(
497501
for (var command in selfValidateCommands)
498502
_CommandEntryBase(selfValidateJobName, command),
499503
],
504+
config: config,
500505
);
501506

502507
const _ubuntuLatest = 'ubuntu-latest';
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'commands/github/action_info.dart';
6+
7+
enum CoverageProcessor {
8+
coveralls(ActionInfo.coveralls),
9+
codecov(ActionInfo.codecov);
10+
11+
final ActionInfo actionInfo;
12+
13+
const CoverageProcessor(this.actionInfo);
14+
}

mono_repo/lib/src/mono_config.dart

Lines changed: 46 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import 'package:json_annotation/json_annotation.dart';
66
import 'package:path/path.dart' as p;
77

8+
import 'basic_config.dart';
9+
import 'coverage_processor.dart';
810
import 'github_config.dart';
911
import 'yaml.dart';
1012

@@ -18,6 +20,7 @@ const _allowedMonoConfigKeys = {
1820
'pretty_ansi',
1921
'pub_action',
2022
'self_validate',
23+
'coverage_service',
2124
};
2225

2326
const _defaultPubAction = 'upgrade';
@@ -27,41 +30,25 @@ const _allowedPubActions = {
2730
_defaultPubAction,
2831
};
2932

30-
class MonoConfig {
33+
class MonoConfig implements BasicConfiguration {
3134
final Map<String, ConditionalStage> githubConditionalStages;
3235
final Set<String> mergeStages;
3336
final bool prettyAnsi;
3437
final String pubAction;
3538
final String? selfValidateStage;
3639
final GitHubConfig github;
37-
38-
factory MonoConfig({
39-
required Set<String> mergeStages,
40-
required bool prettyAnsi,
41-
required String pubAction,
42-
required String? selfValidateStage,
43-
required Map github,
44-
}) {
45-
final githubConditionalStages = _readConditionalStages(github);
46-
47-
return MonoConfig._(
48-
githubConditionalStages: githubConditionalStages,
49-
mergeStages: mergeStages,
50-
prettyAnsi: prettyAnsi,
51-
pubAction: pubAction,
52-
selfValidateStage: selfValidateStage,
53-
github: GitHubConfig.fromJson(github),
54-
);
55-
}
40+
@override
41+
final Set<CoverageProcessor> coverageProcessors;
5642

5743
MonoConfig._({
58-
required this.githubConditionalStages,
5944
required this.mergeStages,
6045
required this.prettyAnsi,
6146
required this.pubAction,
6247
required this.selfValidateStage,
63-
required this.github,
64-
});
48+
required Map github,
49+
required this.coverageProcessors,
50+
}) : githubConditionalStages = _readConditionalStages(github),
51+
github = GitHubConfig.fromJson(github);
6552

6653
factory MonoConfig.fromJson(Map json) {
6754
final unsupportedKeys =
@@ -135,53 +122,63 @@ class MonoConfig {
135122
);
136123
}
137124

138-
final mergeStages = json['merge_stages'] ?? [];
125+
final mergeStages = _asList(json, 'merge_stages');
139126

140-
if (mergeStages is List) {
141-
if (mergeStages.any((v) => v is! String)) {
142-
throw CheckedFromJsonException(
143-
json,
144-
'merge_stages',
145-
'MonoConfig',
146-
'All values must be strings.',
147-
);
148-
}
127+
final coverageServices = _asList(json, 'coverage_service');
149128

150-
return MonoConfig(
151-
mergeStages: Set.from(mergeStages),
152-
prettyAnsi: prettyAnsi,
153-
pubAction: pubAction,
154-
selfValidateStage: _selfValidateFromValue(selfValidate),
155-
github: github,
156-
);
157-
} else {
158-
throw CheckedFromJsonException(
159-
json,
160-
'merge_stages',
161-
'MonoConfig',
162-
'`merge_stages` must be an array.',
163-
);
164-
}
129+
return MonoConfig._(
130+
mergeStages: Set.from(mergeStages),
131+
prettyAnsi: prettyAnsi,
132+
pubAction: pubAction,
133+
selfValidateStage: _selfValidateFromValue(selfValidate),
134+
github: github,
135+
coverageProcessors: coverageServices
136+
.map((e) => CoverageProcessor.values.byName(e))
137+
.toSet(),
138+
);
165139
}
166140

167141
factory MonoConfig.fromRepo({String? rootDirectory}) {
168142
rootDirectory ??= p.current;
169143

170144
final yaml = yamlMapOrNull(rootDirectory, _monoConfigFileName);
171145
if (yaml == null || yaml.isEmpty) {
172-
return MonoConfig(
146+
return MonoConfig._(
173147
mergeStages: <String>{},
174148
pubAction: _defaultPubAction,
175149
prettyAnsi: true,
176150
selfValidateStage: null,
177151
github: {},
152+
coverageProcessors: {CoverageProcessor.coveralls},
178153
);
179154
}
180155

181156
return createWithCheck(() => MonoConfig.fromJson(yaml));
182157
}
183158
}
184159

160+
List<String> _asList(Map json, String key) {
161+
final value = json[key] ?? <String>[];
162+
163+
if (value is List) {
164+
if (value.any((v) => v is! String)) {
165+
throw CheckedFromJsonException(
166+
json,
167+
key,
168+
'MonoConfig',
169+
'All values must be strings.',
170+
);
171+
}
172+
return List.from(value);
173+
}
174+
throw CheckedFromJsonException(
175+
json,
176+
key,
177+
'MonoConfig',
178+
'`$key` must be an array.',
179+
);
180+
}
181+
185182
/// Parses the `stages` key from a CI config map, into a Map from stage name
186183
/// to [ConditionalStage] instance.
187184
Map<String, ConditionalStage> _readConditionalStages(

0 commit comments

Comments
 (0)