Add check for API leaks to the Health workflow (#251)
* Add checks for API leaks
* Fixes
* More fixes
* Fix SDK version in testdata
* Install dart_apitool on leaking in action
* Update tests
* Fix message
* Add exports
* Fix analyze issues
* Reset tests after adding a period
diff --git a/.github/workflows/health.yaml b/.github/workflows/health.yaml
index 74b0b00..db945f0 100644
--- a/.github/workflows/health.yaml
+++ b/.github/workflows/health.yaml
@@ -21,9 +21,9 @@
# uses: dart-lang/ecosystem/.github/workflows/health.yaml@main
# with:
# sdk: beta
-# checks: "version,changelog,license,coverage,breaking,do-not-submit"
+# checks: "version,changelog,license,coverage,breaking,do-not-submit,leaking"
# fail_on: "version,changelog,do-not-submit"
-# warn_on: "license,coverage,breaking"
+# warn_on: "license,coverage,breaking,leaking"
# coverage_web: false
# upload_coverage: false
# use-flutter: true
@@ -54,18 +54,18 @@
# Restrict the checks to any subset of version, changelog, and license if
# needed.
checks:
- description: What to check for in the PR health check - any subset of "version,changelog,license,coverage,breaking,do-not-submit"
- default: "version,changelog,license,coverage,breaking,do-not-submit"
+ description: What to check for in the PR health check - any subset of "version,changelog,license,coverage,breaking,do-not-submit,leaking"
+ default: "version,changelog,license,coverage,breaking,do-not-submit,leaking"
type: string
required: false
fail_on:
- description: Which checks should lead to failure - any subset of "version,changelog,license,coverage,breaking,do-not-submit"
+ description: Which checks should lead to failure - any subset of "version,changelog,license,coverage,breaking,do-not-submit,leaking"
default: "version,changelog,do-not-submit"
type: string
required: false
warn_on:
- description: Which checks should not fail, but only warn - any subset of "version,changelog,license,coverage,breaking,do-not-submit"
- default: "license,coverage,breaking"
+ description: Which checks should not fail, but only warn - any subset of "version,changelog,license,coverage,breaking,do-not-submit,leaking"
+ default: "license,coverage,breaking,leaking"
type: string
required: false
local_debug:
@@ -198,8 +198,21 @@
ignore_packages: ${{ inputs.ignore_packages }}
checkout_submodules: ${{ inputs.checkout_submodules }}
+ leaking:
+ if: ${{ contains(inputs.checks, 'leaking') }}
+ uses: ./.github/workflows/health_base.yaml
+ with:
+ sdk: ${{ inputs.sdk }}
+ check: leaking
+ fail_on: ${{ inputs.fail_on }}
+ warn_on: ${{ inputs.warn_on }}
+ local_debug: ${{ inputs.local_debug }}
+ use-flutter: ${{ inputs.use-flutter }}
+ ignore_packages: ${{ inputs.ignore_packages }}
+ checkout_submodules: ${{ inputs.checkout_submodules }}
+
comment:
- needs: [version, changelog, license, coverage, breaking, do-not-submit]
+ needs: [version, changelog, license, coverage, breaking, do-not-submit, leaking]
if: always()
# These permissions are required for us to create comments on PRs.
permissions:
diff --git a/.github/workflows/health_base.yaml b/.github/workflows/health_base.yaml
index 6ae942c..fdf1f48 100644
--- a/.github/workflows/health_base.yaml
+++ b/.github/workflows/health_base.yaml
@@ -16,17 +16,17 @@
required: false
type: string
check:
- description: What to check for in the PR health check - any of "version,changelog,license,coverage,breaking,do-not-submit"
+ description: What to check for in the PR health check - any of "version,changelog,license,coverage,breaking,do-not-submit,leaking"
type: string
required: true
fail_on:
- description: Which checks should lead to failure - any subset of "version,changelog,license,coverage,breaking,do-not-submit"
+ description: Which checks should lead to failure - any subset of "version,changelog,license,coverage,breaking,do-not-submit,leaking"
default: "version,changelog,do-not-submit"
type: string
required: false
warn_on:
- description: Which checks should not fail, but only warn - any subset of "version,changelog,license,coverage,breaking,do-not-submit"
- default: "license,coverage,breaking"
+ description: Which checks should not fail, but only warn - any subset of "version,changelog,license,coverage,breaking,do-not-submit,leaking"
+ default: "license,coverage,breaking,leaking"
type: string
required: false
local_debug:
@@ -123,7 +123,7 @@
- name: Install api_tool
run: dart pub global activate dart_apitool
- if: ${{ inputs.check == 'breaking' }}
+ if: ${{ inputs.check == 'breaking' || inputs.check == 'leaking' }}
- name: Check PR health
id: healthstep
diff --git a/.github/workflows/health_internal.yaml b/.github/workflows/health_internal.yaml
index 270a0b8..26ed3ce 100644
--- a/.github/workflows/health_internal.yaml
+++ b/.github/workflows/health_internal.yaml
@@ -12,8 +12,8 @@
local_debug: true
coverage_web: false
upload_coverage: false
- checks: version,changelog,license,coverage,breaking,do-not-submit
+ checks: version,changelog,license,coverage,breaking,do-not-submit,leaking
fail_on: version,changelog,do-not-submit
- warn_on: license,coverage,breaking
+ warn_on: license,coverage,breaking,leaking
ignore_license: 'pkgs/firehose/test_data'
- ignore_coverage: 'pkgs/firehose/bin'
+ ignore_coverage: 'pkgs/firehose/bin,pkgs/firehose/test_data'
diff --git a/.vscode/launch.json b/.vscode/launch.json
index b76d2fd..cfe3049 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -17,7 +17,7 @@
},
"args": [
"--checks",
- "version,changelog,license,coverage,do-not-submit"
+ "version,changelog,license,coverage,do-not-submit,leaking"
]
}
]
diff --git a/pkgs/firehose/CHANGELOG.md b/pkgs/firehose/CHANGELOG.md
index 9711bd9..2e49ae3 100644
--- a/pkgs/firehose/CHANGELOG.md
+++ b/pkgs/firehose/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.9.0
+
+- Add `leaking` check to the health workflow.
+
## 0.8.0
- Only check text files for do not submit strings.
diff --git a/pkgs/firehose/README.md b/pkgs/firehose/README.md
index 30d7abd..9ea55a5 100644
--- a/pkgs/firehose/README.md
+++ b/pkgs/firehose/README.md
@@ -166,6 +166,7 @@
* How the test coverage is affected by the PR.
* The package versioning takes into account any breaking changes in the PR.
* The PR contains `DO_NOT_SUBMIT` strings in the files or the description.
+* Any symbols are visible in the public API, but not exported.
This tool can work with either single package repos or with mono-repos (repos
containing several packages).
@@ -192,9 +193,9 @@
| Name | Type | Description | Example |
| ------------- | ------------- | ------------- | ------------- |
-| checks | List of strings | What to check for in the PR health check | `"version,changelog,license,coverage,breaking,do-not-submit"` |
+| checks | List of strings | What to check for in the PR health check | `"version,changelog,license,coverage,breaking,do-not-submit,leaking"` |
| fail_on | List of strings | Which checks should lead to failure | `"version,changelog,do-not-submit"` |
-| warn_on | List of strings | Which checks should not fail, but only warn | `"license,coverage,breaking"` |
+| warn_on | List of strings | Which checks should not fail, but only warn | `"license,coverage,breaking,leaking"` |
| upload_coverage | boolean | Whether to upload the coverage to [coveralls](https://coveralls.io/) | `true` |
| coverage_web | boolean | Whether to run `dart test -p chrome` for coverage | `false` |
| use-flutter | boolean | Whether to setup Flutter in this workflow | `false` |
diff --git a/pkgs/firehose/bin/firehose.dart b/pkgs/firehose/bin/firehose.dart
index 65d0000..82bb7dd 100644
--- a/pkgs/firehose/bin/firehose.dart
+++ b/pkgs/firehose/bin/firehose.dart
@@ -6,7 +6,6 @@
import 'package:args/args.dart';
import 'package:firehose/firehose.dart';
-import 'package:firehose/src/github.dart';
import 'package:glob/glob.dart';
const helpFlag = 'help';
diff --git a/pkgs/firehose/bin/health.dart b/pkgs/firehose/bin/health.dart
index 5a36b21..697dd74 100644
--- a/pkgs/firehose/bin/health.dart
+++ b/pkgs/firehose/bin/health.dart
@@ -9,6 +9,7 @@
import 'package:firehose/src/health/health.dart';
void main(List<String> arguments) async {
+ var checkTypes = Check.values.map((c) => c.name);
var argParser = ArgParser()
..addOption(
'check',
@@ -49,7 +50,8 @@
help: 'Whether to run web tests for coverage',
);
final parsedArgs = argParser.parse(arguments);
- final check = parsedArgs['check'] as String;
+ final checkStr = parsedArgs['check'] as String;
+ final check = Check.values.firstWhere((c) => c.name == checkStr);
final warnOn = parsedArgs['warn_on'] as List<String>;
final failOn = parsedArgs['fail_on'] as List<String>;
final ignorePackages = _listNonEmpty(parsedArgs, 'ignore_packages');
diff --git a/pkgs/firehose/lib/firehose.dart b/pkgs/firehose/lib/firehose.dart
index 5c702f6..618dbb6 100644
--- a/pkgs/firehose/lib/firehose.dart
+++ b/pkgs/firehose/lib/firehose.dart
@@ -14,6 +14,11 @@
import 'src/repo.dart';
import 'src/utils.dart';
+export 'src/changelog.dart' show Changelog;
+export 'src/github.dart' show FileStatus, GitFile, GithubApi;
+export 'src/repo.dart' show Package, Repository;
+export 'src/utils.dart' show Severity;
+
const String _botSuffix = '[bot]';
const String _githubActionsUser = 'github-actions[bot]';
diff --git a/pkgs/firehose/lib/src/health/health.dart b/pkgs/firehose/lib/src/health/health.dart
index dc9343d..e0cc3b0 100644
--- a/pkgs/firehose/lib/src/health/health.dart
+++ b/pkgs/firehose/lib/src/health/health.dart
@@ -14,33 +14,26 @@
import 'package:pub_semver/pub_semver.dart';
import '../../firehose.dart';
-import '../github.dart';
-import '../repo.dart';
import '../utils.dart';
import 'changelog.dart';
import 'coverage.dart';
import 'license.dart';
-const String _publishBotTag2 = '### Package publish validation';
+enum Check {
+ version('### Package publish validation', 'version'),
+ license('### License Headers', 'license'),
+ changelog('### Changelog Entry', 'changelog'),
+ coverage('### Coverage', 'coverage'),
+ breaking('### Breaking changes', 'breaking'),
+ leaking('### API leaks', 'leaking'),
+ donotsubmit('### Do Not Submit', 'do-not-submit');
-const String _licenseBotTag = '### License Headers';
+ final String tag;
-const String _changelogBotTag = '### Changelog Entry';
+ final String name;
-const String _doNotSubmitBotTag = '### Do Not Submit';
-
-const String _coverageBotTag = '### Coverage';
-
-const String _breakingBotTag = '### Breaking changes';
-
-const checkTypes = <String>[
- 'version',
- 'license',
- 'changelog',
- 'coverage',
- 'breaking',
- 'do-not-submit',
-];
+ const Check(this.tag, this.name);
+}
class Health {
final Directory directory;
@@ -78,7 +71,7 @@
);
final GithubApi github;
- final String check;
+ final Check check;
final List<String> warnOn;
final List<String> failOn;
final bool coverageweb;
@@ -94,7 +87,8 @@
if (!expectEnv(github.issueNumber?.toString(), 'ISSUE_NUMBER')) return;
if (!expectEnv(github.sha, 'GITHUB_SHA')) return;
- print('Start health check for the check $check with');
+ var checkName = check.name;
+ print('Start health check for the check $checkName with');
print(' warnOn: $warnOn');
print(' failOn: $failOn');
print(' coverageweb: $coverageweb');
@@ -103,44 +97,35 @@
print(' ignoredForCoverage: $ignoredFilesForCoverage');
print(' baseDirectory: $baseDirectory');
print(' experiments: $experiments');
- print('Checking for $check');
- if (!github.prLabels.contains('skip-$check-check')) {
+ print('Checking for $checkName');
+ if (!github.prLabels.contains('skip-$checkName-check')) {
final firstResult = await checkFor(check)();
final HealthCheckResult finalResult;
- if (warnOn.contains(check) && firstResult.severity == Severity.error) {
+ if (warnOn.contains(check.name) &&
+ firstResult.severity == Severity.error) {
finalResult = firstResult.withSeverity(Severity.warning);
- } else if (failOn.contains(check) &&
+ } else if (failOn.contains(check.name) &&
firstResult.severity == Severity.warning) {
finalResult = firstResult.withSeverity(Severity.error);
} else {
finalResult = firstResult;
}
await writeInComment(github, finalResult);
- print('\n\n${finalResult.severity.name.toUpperCase()}: $check done.\n\n');
+ var severity = finalResult.severity.name.toUpperCase();
+ print('\n\n$severity: $checkName done.\n\n');
} else {
- print('Skipping $check, as the skip tag is present.');
+ print('Skipping $checkName, as the skip tag is present.');
}
}
- String tagFor(String checkType) => switch (checkType) {
- 'version' => _publishBotTag2,
- 'license' => _licenseBotTag,
- 'changelog' => _changelogBotTag,
- 'coverage' => _coverageBotTag,
- 'breaking' => _breakingBotTag,
- 'do-not-submit' => _doNotSubmitBotTag,
- String() => throw ArgumentError('Invalid check type $checkType'),
- };
-
- Future<HealthCheckResult> Function() checkFor(String checkType) =>
- switch (checkType) {
- 'version' => validateCheck,
- 'license' => licenseCheck,
- 'changelog' => changelogCheck,
- 'coverage' => coverageCheck,
- 'breaking' => breakingCheck,
- 'do-not-submit' => doNotSubmitCheck,
- String() => throw ArgumentError('Invalid check type $checkType'),
+ Future<HealthCheckResult> Function() checkFor(Check check) => switch (check) {
+ Check.version => validateCheck,
+ Check.license => licenseCheck,
+ Check.changelog => changelogCheck,
+ Check.coverage => coverageCheck,
+ Check.breaking => breakingCheck,
+ Check.donotsubmit => doNotSubmitCheck,
+ Check.leaking => leakingCheck,
};
Future<HealthCheckResult> validateCheck() async {
@@ -157,7 +142,7 @@
''';
return HealthCheckResult(
- 'version',
+ Check.version,
results.severity,
markdownTable,
);
@@ -173,7 +158,7 @@
var baseRelativePath = path.relative(
path.join(baseDirectory.path, relativePath),
from: directory.path);
- var tempDirectory = Directory.systemTemp..createSync();
+ var tempDirectory = Directory.systemTemp.createTempSync();
var reportPath = path.join(tempDirectory.path, 'report.json');
var runApiTool = Process.runSync(
'dart',
@@ -209,7 +194,7 @@
);
}
return HealthCheckResult(
- 'breaking',
+ Check.breaking,
changeForPackage.values.any((element) => !element.versionIsFine)
? Severity.warning
: Severity.info,
@@ -235,6 +220,54 @@
return breakingLevel;
}
+ Future<HealthCheckResult> leakingCheck() async {
+ final filesInPR = await github.listFilesForPR(directory, ignoredPackages);
+ final leaksForPackage = <Package, List<String>>{};
+ for (var package in packagesContaining(filesInPR, ignoredPackages)) {
+ print('Look for leaks in $package');
+ var relativePath =
+ path.relative(package.directory.path, from: directory.path);
+ var tempDirectory = Directory.systemTemp.createTempSync();
+ var reportPath = path.join(tempDirectory.path, 'leaks.json');
+ var runApiTool = Process.runSync(
+ 'dart',
+ [
+ ...['pub', 'global', 'run'],
+ 'dart_apitool:main',
+ 'extract',
+ ...['--input', relativePath],
+ ...['--output', reportPath],
+ '--set-exit-on-missing-export',
+ ],
+ workingDirectory: directory.path,
+ );
+ print(runApiTool.stderr);
+ print(runApiTool.stdout);
+
+ var fullReportString = File(reportPath).readAsStringSync();
+ var decoded = jsonDecode(fullReportString) as Map<String, dynamic>;
+ var leaks = decoded['missingEntryPoints'] as List<dynamic>;
+
+ print('Leaking symbols in API:\n$leaks');
+ if (leaks.isNotEmpty) {
+ leaksForPackage[package] = leaks.cast();
+ }
+ }
+ return HealthCheckResult(
+ Check.leaking,
+ leaksForPackage.values.any((leaks) => leaks.isNotEmpty)
+ ? Severity.warning
+ : Severity.success,
+ '''
+The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.
+
+| Package | Leaked API symbols |
+| :--- | :--- |
+${leaksForPackage.entries.map((e) => '|${e.key.name}|${e.value.join('<br>')}|').join('\n')}
+''',
+ );
+ }
+
Future<HealthCheckResult> licenseCheck() async {
var files = await github.listFilesForPR(directory, ignoredPackages);
var allFilePaths = await getFilesWithoutLicenses(
@@ -276,7 +309,7 @@
''';
return HealthCheckResult(
- 'license',
+ Check.license,
changedFilesPaths.isNotEmpty ? Severity.error : Severity.success,
markdownResult,
);
@@ -298,7 +331,7 @@
''';
return HealthCheckResult(
- 'changelog',
+ Check.changelog,
filePaths.isNotEmpty ? Severity.error : Severity.success,
markdownResult,
);
@@ -335,7 +368,7 @@
final hasDNS = filesWithDNS.isNotEmpty || bodyContainsDNS;
return HealthCheckResult(
- 'do-not-submit',
+ Check.donotsubmit,
hasDNS ? Severity.error : Severity.success,
hasDNS ? markdownResult : null,
);
@@ -359,7 +392,7 @@
''';
return HealthCheckResult(
- 'coverage',
+ Check.coverage,
Severity.values[coverage.coveragePerFile.values
.map((change) => change.severity.index)
.fold(0, max)],
@@ -381,11 +414,11 @@
$markdown
-${isWorseThanInfo ? 'This check can be disabled by tagging the PR with `skip-${result.name}-check`' : ''}
+${isWorseThanInfo ? 'This check can be disabled by tagging the PR with `skip-${result.check.name}-check`.' : ''}
</details>
''';
- markdownSummary = '${tagFor(result.name)} ${result.severity.emoji}\n\n$s';
+ markdownSummary = '${check.tag} ${result.severity.emoji}\n\n$s';
} else {
markdownSummary = '';
}
@@ -426,14 +459,14 @@
}
class HealthCheckResult {
- final String name;
+ final Check check;
final Severity severity;
final String? markdown;
- HealthCheckResult(this.name, this.severity, this.markdown);
+ HealthCheckResult(this.check, this.severity, this.markdown);
HealthCheckResult withSeverity(Severity severity) => HealthCheckResult(
- name,
+ check,
severity,
markdown,
);
diff --git a/pkgs/firehose/pubspec.yaml b/pkgs/firehose/pubspec.yaml
index 89be06a..e7ec8bd 100644
--- a/pkgs/firehose/pubspec.yaml
+++ b/pkgs/firehose/pubspec.yaml
@@ -1,6 +1,6 @@
name: firehose
description: A tool to automate publishing of Pub packages from GitHub actions.
-version: 0.8.0
+version: 0.9.0
repository: https://github.com/dart-lang/ecosystem/tree/main/pkgs/firehose
environment:
diff --git a/pkgs/firehose/test/health_test.dart b/pkgs/firehose/test/health_test.dart
index 41f408e..8ab040d 100644
--- a/pkgs/firehose/test/health_test.dart
+++ b/pkgs/firehose/test/health_test.dart
@@ -30,13 +30,23 @@
FileStatus.added,
directory,
),
+ GitFile(
+ 'pkgs/package5/lib/src/package5_base.dart',
+ FileStatus.modified,
+ directory,
+ ),
+ GitFile(
+ 'pkgs/package5/pubspec.yaml',
+ FileStatus.modified,
+ directory,
+ ),
]);
await Process.run('dart', ['pub', 'global', 'activate', 'dart_apitool']);
await Process.run('dart', ['pub', 'global', 'activate', 'coverage']);
- for (var check in checkTypes) {
+ for (var check in Check.values) {
test(
- 'Check health workflow "$check" against golden files',
+ 'Check health workflow "${check.name}" against golden files',
() async => await checkGolden(check, fakeGithubApi, directory),
timeout: const Timeout(Duration(minutes: 2)),
);
@@ -44,7 +54,7 @@
test('Ignore license test', () async {
await checkGolden(
- 'license',
+ Check.license,
fakeGithubApi,
directory,
suffix: '_ignore_license',
@@ -55,7 +65,7 @@
test(
'Ignore packages test',
() async {
- for (var check in checkTypes) {
+ for (var check in Check.values) {
await checkGolden(
check,
fakeGithubApi,
@@ -70,14 +80,15 @@
}
Future<void> checkGolden(
- String check,
+ Check check,
FakeGithubApi fakeGithubApi,
Directory directory, {
String suffix = '',
List<String> ignoredLicense = const [],
List<String> ignoredPackage = const [],
}) async {
- final commentPath = p.join(Directory.systemTemp.path, 'comment_$check.md');
+ final commentPath = p.join(
+ Directory.systemTemp.createTempSync().path, 'comment_${check.name}.md');
await Health(
directory,
check,
@@ -94,7 +105,7 @@
).healthCheck();
var comment = await File(commentPath).readAsString();
var goldenFile =
- File(p.join('test_data', 'golden', 'comment_$check$suffix.md'));
+ File(p.join('test_data', 'golden', 'comment_${check.name}$suffix.md'));
if (Platform.environment['RESET_GOLDEN'] == '1') {
goldenFile.writeAsStringSync(comment);
} else {
diff --git a/pkgs/firehose/test_data/base_test_repo/pkgs/package5/lib/package5.dart b/pkgs/firehose/test_data/base_test_repo/pkgs/package5/lib/package5.dart
new file mode 100644
index 0000000..950f4cb
--- /dev/null
+++ b/pkgs/firehose/test_data/base_test_repo/pkgs/package5/lib/package5.dart
@@ -0,0 +1,8 @@
+/// Support for doing something awesome.
+///
+/// More dartdocs go here.
+library;
+
+export 'src/package5_base.dart' show Awesome;
+
+// TODO: Export any libraries intended for clients of this package.
diff --git a/pkgs/firehose/test_data/base_test_repo/pkgs/package5/lib/src/package5_base.dart b/pkgs/firehose/test_data/base_test_repo/pkgs/package5/lib/src/package5_base.dart
new file mode 100644
index 0000000..e8a6f15
--- /dev/null
+++ b/pkgs/firehose/test_data/base_test_repo/pkgs/package5/lib/src/package5_base.dart
@@ -0,0 +1,6 @@
+// TODO: Put public facing types in this file.
+
+/// Checks if you are awesome. Spoiler: you are.
+class Awesome {
+ bool get isAwesome => true;
+}
diff --git a/pkgs/firehose/test_data/base_test_repo/pkgs/package5/pubspec.yaml b/pkgs/firehose/test_data/base_test_repo/pkgs/package5/pubspec.yaml
new file mode 100644
index 0000000..014e843
--- /dev/null
+++ b/pkgs/firehose/test_data/base_test_repo/pkgs/package5/pubspec.yaml
@@ -0,0 +1,15 @@
+name: package5
+description: A starting point for Dart libraries or applications.
+version: 1.0.0
+# repository: https://github.com/my_org/my_repo
+
+environment:
+ sdk: ^3.0.0
+
+# Add regular dependencies here.
+dependencies:
+ # path: ^1.8.0
+
+dev_dependencies:
+ lints: ^3.0.0
+ test: ^1.24.0
diff --git a/pkgs/firehose/test_data/golden/comment_breaking.md b/pkgs/firehose/test_data/golden/comment_breaking.md
index 422549b..4bfe13d 100644
--- a/pkgs/firehose/test_data/golden/comment_breaking.md
+++ b/pkgs/firehose/test_data/golden/comment_breaking.md
@@ -9,8 +9,9 @@
| :--- | :--- | ---: | ---: | ---: | ---: |
|package1|None|1.0.0|1.0.0|1.0.0|:heavy_check_mark:|
|package2|Non-Breaking|1.0.0|1.0.0|**1.1.0** <br> Got "1.0.0" expected >= "1.1.0" (non-breaking changes)|:warning:|
+|package5|Non-Breaking|1.0.0|1.2.0|1.1.0|:heavy_check_mark:|
-This check can be disabled by tagging the PR with `skip-breaking-check`
+This check can be disabled by tagging the PR with `skip-breaking-check`.
</details>
diff --git a/pkgs/firehose/test_data/golden/comment_breaking_ignore_package.md b/pkgs/firehose/test_data/golden/comment_breaking_ignore_package.md
index d336860..121b540 100644
--- a/pkgs/firehose/test_data/golden/comment_breaking_ignore_package.md
+++ b/pkgs/firehose/test_data/golden/comment_breaking_ignore_package.md
@@ -8,8 +8,9 @@
| Package | Change | Current Version | New Version | Needed Version | Looking good? |
| :--- | :--- | ---: | ---: | ---: | ---: |
|package2|Non-Breaking|1.0.0|1.0.0|**1.1.0** <br> Got "1.0.0" expected >= "1.1.0" (non-breaking changes)|:warning:|
+|package5|Non-Breaking|1.0.0|1.2.0|1.1.0|:heavy_check_mark:|
-This check can be disabled by tagging the PR with `skip-breaking-check`
+This check can be disabled by tagging the PR with `skip-breaking-check`.
</details>
diff --git a/pkgs/firehose/test_data/golden/comment_changelog.md b/pkgs/firehose/test_data/golden/comment_changelog.md
index dfbadb2..2fae543 100644
--- a/pkgs/firehose/test_data/golden/comment_changelog.md
+++ b/pkgs/firehose/test_data/golden/comment_changelog.md
@@ -13,6 +13,6 @@
Changes to files need to be [accounted for](https://github.com/dart-lang/ecosystem/wiki/Changelog) in their respective changelogs.
-This check can be disabled by tagging the PR with `skip-changelog-check`
+This check can be disabled by tagging the PR with `skip-changelog-check`.
</details>
diff --git a/pkgs/firehose/test_data/golden/comment_changelog_ignore_package.md b/pkgs/firehose/test_data/golden/comment_changelog_ignore_package.md
index d7b7d12..00fa903 100644
--- a/pkgs/firehose/test_data/golden/comment_changelog_ignore_package.md
+++ b/pkgs/firehose/test_data/golden/comment_changelog_ignore_package.md
@@ -12,6 +12,6 @@
Changes to files need to be [accounted for](https://github.com/dart-lang/ecosystem/wiki/Changelog) in their respective changelogs.
-This check can be disabled by tagging the PR with `skip-changelog-check`
+This check can be disabled by tagging the PR with `skip-changelog-check`.
</details>
diff --git a/pkgs/firehose/test_data/golden/comment_coverage.md b/pkgs/firehose/test_data/golden/comment_coverage.md
index c594cbf..acd10c8 100644
--- a/pkgs/firehose/test_data/golden/comment_coverage.md
+++ b/pkgs/firehose/test_data/golden/comment_coverage.md
@@ -9,10 +9,11 @@
| :--- | :--- |
|pkgs/package1/bin/package1.dart| :broken_heart: Not covered |
|pkgs/package2/lib/anotherLib.dart| :green_heart: 100 % |
+|pkgs/package5/lib/src/package5_base.dart| :broken_heart: Not covered |
This check for [test coverage](https://github.com/dart-lang/ecosystem/wiki/Test-Coverage) is informational (issues shown here will not fail the PR).
-This check can be disabled by tagging the PR with `skip-coverage-check`
+This check can be disabled by tagging the PR with `skip-coverage-check`.
</details>
diff --git a/pkgs/firehose/test_data/golden/comment_coverage_ignore_package.md b/pkgs/firehose/test_data/golden/comment_coverage_ignore_package.md
index c6bdd11..c492d00 100644
--- a/pkgs/firehose/test_data/golden/comment_coverage_ignore_package.md
+++ b/pkgs/firehose/test_data/golden/comment_coverage_ignore_package.md
@@ -1,6 +1,6 @@
-### Coverage :heavy_check_mark:
+### Coverage :warning:
-<details>
+<details open>
<summary>
Details
</summary>
@@ -8,10 +8,11 @@
| File | Coverage |
| :--- | :--- |
|pkgs/package2/lib/anotherLib.dart| :green_heart: 100 % |
+|pkgs/package5/lib/src/package5_base.dart| :broken_heart: Not covered |
This check for [test coverage](https://github.com/dart-lang/ecosystem/wiki/Test-Coverage) is informational (issues shown here will not fail the PR).
-
+This check can be disabled by tagging the PR with `skip-coverage-check`.
</details>
diff --git a/pkgs/firehose/test_data/golden/comment_do-not-submit.md b/pkgs/firehose/test_data/golden/comment_do-not-submit.md
index 8daf42d..4df7261 100644
--- a/pkgs/firehose/test_data/golden/comment_do-not-submit.md
+++ b/pkgs/firehose/test_data/golden/comment_do-not-submit.md
@@ -12,6 +12,6 @@
|pkgs/package1/bin/package1.dart|
-This check can be disabled by tagging the PR with `skip-do-not-submit-check`
+This check can be disabled by tagging the PR with `skip-do-not-submit-check`.
</details>
diff --git a/pkgs/firehose/test_data/golden/comment_leaking.md b/pkgs/firehose/test_data/golden/comment_leaking.md
new file mode 100644
index 0000000..64d3793
--- /dev/null
+++ b/pkgs/firehose/test_data/golden/comment_leaking.md
@@ -0,0 +1,17 @@
+### API leaks :warning:
+
+<details open>
+<summary>
+Details
+</summary>
+
+The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.
+
+| Package | Leaked API symbols |
+| :--- | :--- |
+|package5|NonExported<br>NonExported2<br>TransitiveNonExported|
+
+
+This check can be disabled by tagging the PR with `skip-leaking-check`.
+</details>
+
diff --git a/pkgs/firehose/test_data/golden/comment_leaking_ignore_package.md b/pkgs/firehose/test_data/golden/comment_leaking_ignore_package.md
new file mode 100644
index 0000000..64d3793
--- /dev/null
+++ b/pkgs/firehose/test_data/golden/comment_leaking_ignore_package.md
@@ -0,0 +1,17 @@
+### API leaks :warning:
+
+<details open>
+<summary>
+Details
+</summary>
+
+The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.
+
+| Package | Leaked API symbols |
+| :--- | :--- |
+|package5|NonExported<br>NonExported2<br>TransitiveNonExported|
+
+
+This check can be disabled by tagging the PR with `skip-leaking-check`.
+</details>
+
diff --git a/pkgs/firehose/test_data/golden/comment_license.md b/pkgs/firehose/test_data/golden/comment_license.md
index a53ef1c..ad5231b 100644
--- a/pkgs/firehose/test_data/golden/comment_license.md
+++ b/pkgs/firehose/test_data/golden/comment_license.md
@@ -15,6 +15,7 @@
| :--- |
|pkgs/package1/bin/package1.dart|
|pkgs/package2/lib/anotherLib.dart|
+|pkgs/package5/lib/src/package5_base.dart|
All source files should start with a [license header](https://github.com/dart-lang/ecosystem/wiki/License-Header).
@@ -32,11 +33,12 @@
|pkgs/package3/bin/package3.dart|
|pkgs/package3/lib/package3.dart|
|pkgs/package3/test/package3_test.dart|
+|pkgs/package5/lib/package5.dart|
</details>
-This check can be disabled by tagging the PR with `skip-license-check`
+This check can be disabled by tagging the PR with `skip-license-check`.
</details>
diff --git a/pkgs/firehose/test_data/golden/comment_license_ignore_license.md b/pkgs/firehose/test_data/golden/comment_license_ignore_license.md
index 4fa23f1..cfb1871 100644
--- a/pkgs/firehose/test_data/golden/comment_license_ignore_license.md
+++ b/pkgs/firehose/test_data/golden/comment_license_ignore_license.md
@@ -15,6 +15,7 @@
| :--- |
|pkgs/package1/bin/package1.dart|
|pkgs/package2/lib/anotherLib.dart|
+|pkgs/package5/lib/src/package5_base.dart|
All source files should start with a [license header](https://github.com/dart-lang/ecosystem/wiki/License-Header).
@@ -29,11 +30,12 @@
|pkgs/package1/test/package1_test.dart|
|pkgs/package2/lib/package2.dart|
|pkgs/package2/test/package2_test.dart|
+|pkgs/package5/lib/package5.dart|
</details>
-This check can be disabled by tagging the PR with `skip-license-check`
+This check can be disabled by tagging the PR with `skip-license-check`.
</details>
diff --git a/pkgs/firehose/test_data/golden/comment_license_ignore_package.md b/pkgs/firehose/test_data/golden/comment_license_ignore_package.md
index 59c637d..47860a9 100644
--- a/pkgs/firehose/test_data/golden/comment_license_ignore_package.md
+++ b/pkgs/firehose/test_data/golden/comment_license_ignore_package.md
@@ -14,6 +14,7 @@
| Files |
| :--- |
|pkgs/package2/lib/anotherLib.dart|
+|pkgs/package5/lib/src/package5_base.dart|
All source files should start with a [license header](https://github.com/dart-lang/ecosystem/wiki/License-Header).
@@ -29,11 +30,12 @@
|pkgs/package3/bin/package3.dart|
|pkgs/package3/lib/package3.dart|
|pkgs/package3/test/package3_test.dart|
+|pkgs/package5/lib/package5.dart|
</details>
-This check can be disabled by tagging the PR with `skip-license-check`
+This check can be disabled by tagging the PR with `skip-license-check`.
</details>
diff --git a/pkgs/firehose/test_data/golden/comment_version.md b/pkgs/firehose/test_data/golden/comment_version.md
index c03092a..e01840e 100644
--- a/pkgs/firehose/test_data/golden/comment_version.md
+++ b/pkgs/firehose/test_data/golden/comment_version.md
@@ -10,10 +10,11 @@
| package:package1 | 1.0.0 | (error) pub publish dry-run failed; add the `publish-ignore-warnings` label to ignore |
| package:package2 | 1.0.0 | (error) pub publish dry-run failed; add the `publish-ignore-warnings` label to ignore |
| package:package3 | 1.0.0 | (error) pub publish dry-run failed; add the `publish-ignore-warnings` label to ignore |
+| package:package5 | 1.2.0 | (error) pubspec version (1.2.0) and changelog (null) don't agree |
Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.
-This check can be disabled by tagging the PR with `skip-version-check`
+This check can be disabled by tagging the PR with `skip-version-check`.
</details>
diff --git a/pkgs/firehose/test_data/golden/comment_version_ignore_package.md b/pkgs/firehose/test_data/golden/comment_version_ignore_package.md
index 17ab16e..697af42 100644
--- a/pkgs/firehose/test_data/golden/comment_version_ignore_package.md
+++ b/pkgs/firehose/test_data/golden/comment_version_ignore_package.md
@@ -9,10 +9,11 @@
| :--- | ---: | :--- |
| package:package2 | 1.0.0 | (error) pub publish dry-run failed; add the `publish-ignore-warnings` label to ignore |
| package:package3 | 1.0.0 | (error) pub publish dry-run failed; add the `publish-ignore-warnings` label to ignore |
+| package:package5 | 1.2.0 | (error) pubspec version (1.2.0) and changelog (null) don't agree |
Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.
-This check can be disabled by tagging the PR with `skip-version-check`
+This check can be disabled by tagging the PR with `skip-version-check`.
</details>
diff --git a/pkgs/firehose/test_data/test_repo/pkgs/package5/lib/package5.dart b/pkgs/firehose/test_data/test_repo/pkgs/package5/lib/package5.dart
new file mode 100644
index 0000000..950f4cb
--- /dev/null
+++ b/pkgs/firehose/test_data/test_repo/pkgs/package5/lib/package5.dart
@@ -0,0 +1,8 @@
+/// Support for doing something awesome.
+///
+/// More dartdocs go here.
+library;
+
+export 'src/package5_base.dart' show Awesome;
+
+// TODO: Export any libraries intended for clients of this package.
diff --git a/pkgs/firehose/test_data/test_repo/pkgs/package5/lib/src/package5_base.dart b/pkgs/firehose/test_data/test_repo/pkgs/package5/lib/src/package5_base.dart
new file mode 100644
index 0000000..fcca7d7
--- /dev/null
+++ b/pkgs/firehose/test_data/test_repo/pkgs/package5/lib/src/package5_base.dart
@@ -0,0 +1,17 @@
+// TODO: Put public facing types in this file.
+
+/// Checks if you are awesome. Spoiler: you are.
+class Awesome {
+ bool get isAwesome => true;
+
+ NonExported get myClass => NonExported();
+ NonExported2 get myClass2 => NonExported2();
+}
+
+class NonExported {}
+
+class NonExported2 {
+ TransitiveNonExported get myClass => TransitiveNonExported();
+}
+
+class TransitiveNonExported {}
diff --git a/pkgs/firehose/test_data/test_repo/pkgs/package5/pubspec.yaml b/pkgs/firehose/test_data/test_repo/pkgs/package5/pubspec.yaml
new file mode 100644
index 0000000..10fbd15
--- /dev/null
+++ b/pkgs/firehose/test_data/test_repo/pkgs/package5/pubspec.yaml
@@ -0,0 +1,15 @@
+name: package5
+description: A starting point for Dart libraries or applications.
+version: 1.2.0
+# repository: https://github.com/my_org/my_repo
+
+environment:
+ sdk: ^3.0.0
+
+# Add regular dependencies here.
+dependencies:
+ # path: ^1.8.0
+
+dev_dependencies:
+ lints: ^3.0.0
+ test: ^1.24.0