fetchBreakingChangeIssues method
Fetch closed issues labelled with breaking-change indicators.
Searches for issues with the labels: breaking-change,
breaking change, and breaking. Only closed issues are returned
because open issues represent unreleased changes.
Returns an empty list on failure.
Implementation
Future<List<Map<String, dynamic>>> fetchBreakingChangeIssues(
String owner,
String repo,
) async {
final cacheKey = 'github_breaking_issues_${owner}_$repo';
final cached = await _cache.get(cacheKey);
if (cached != null) {
final entries = cached['entries'] as List<dynamic>? ?? [];
return entries.cast<Map<String, dynamic>>();
}
final allIssues = <Map<String, dynamic>>[];
// Try several common label conventions.
final labels = ['breaking-change', 'breaking change', 'breaking'];
for (final label in labels) {
try {
final encodedLabel = Uri.encodeComponent(label);
final response = await _http.get(
'$_apiBase/repos/$owner/$repo/issues'
'?labels=$encodedLabel&state=closed&per_page=100',
);
if (!response.isSuccess) continue;
final issues = response.jsonList
.map((e) => e as Map<String, dynamic>)
.toList();
// De-duplicate by issue number.
final existingNumbers =
allIssues.map((i) => i['number'] as int).toSet();
for (final issue in issues) {
final number = issue['number'] as int?;
if (number != null && !existingNumbers.contains(number)) {
allIssues.add(issue);
existingNumbers.add(number);
}
}
} catch (e) {
Logger.warn(
'Failed to fetch issues with label "$label" for $owner/$repo: $e',
);
}
}
Logger.debug(
'Found ${allIssues.length} breaking-change issues for $owner/$repo',
);
await _cache.set(
cacheKey,
{'entries': allIssues},
CacheManager.changelogTtl,
);
return allIssues;
}