blob: 4640d8693f586d99113a691aa04970c6dd949c0f [file] [log] [blame] [edit]
import 'dart:io';
import 'package:devtools_repo/repo_tool.dart';
import 'package:devtools_shared/devtools_shared.dart';
import 'package:json_annotation/json_annotation.dart';
part 'release_note_classes.g.dart';
@JsonSerializable()
class ReleaseNotes {
ReleaseNotes({
required this.releases,
});
List<Release> releases;
String toMarkdown() {
String markdown = '';
for (var release in releases) {
markdown += release.toMarkdown();
markdown += '\n';
}
return markdown;
}
factory ReleaseNotes.fromJson(Map<String, dynamic> json) =>
_$ReleaseNotesFromJson(json);
Map<String, dynamic> toJson() => _$ReleaseNotesToJson(this);
}
@JsonSerializable()
class Release {
Release({
required this.version,
required this.sections,
}) {
for (var element in sections) {
_sectionMap[element.name] = element;
}
}
final SemanticVersion version;
List<ReleaseSection> sections = [];
final Map<String, ReleaseSection> _sectionMap = {};
void addNote(String sectionName, ReleaseNote note) {
_sectionMap[sectionName]!.notes.add(note);
}
String toMarkdown() {
String markdown = '';
markdown += '# DevTools $version release notes\n\n';
sections.forEach((section) {
markdown += '# ${section.name}\n\n';
for (var note in section.notes) {
markdown += note.toMarkdown();
}
markdown += '\n';
});
return markdown;
}
factory Release.fromJson(Map<String, dynamic> json) =>
_$ReleaseFromJson(json);
Map<String, dynamic> toJson() => _$ReleaseToJson(this);
}
@JsonSerializable()
class ReleaseSection {
ReleaseSection({
required this.name,
List<ReleaseNote>? notes,
}) : notes = notes ?? [];
ReleaseSection.emptyNotes({
required this.name,
}) : notes = [];
final String name;
final List<ReleaseNote> notes;
factory ReleaseSection.fromJson(Map<String, dynamic> json) =>
_$ReleaseSectionFromJson(json);
Map<String, dynamic> toJson() => _$ReleaseSectionToJson(this);
}
@JsonSerializable()
class ReleaseNote {
ReleaseNote({
required this.message,
this.imageNames,
this.githubPullRequestUrls,
}) {
if (imageNames != null) {
for (var name in imageNames!) {
final path = "release_notes/files/$name";
//TODO: get the proper path?
if (!File(path).existsSync()) {
throw Exception(
"Could not find image file $path for note: \n${toMarkdown()}");
}
}
}
}
List<String>? githubPullRequestUrls;
final String message;
final List<String>? imageNames;
String toMarkdown() {
String markdown = '';
markdown += '- $message';
if (githubPullRequestUrls != null) {
List<String> prUrls = [];
for (var url in githubPullRequestUrls!) {
final match = RegExp(
r'^https://github.com/flutter/devtools/pull/(?<pr_number>\d+)$')
.firstMatch(url);
if (match == null) {
throw Exception(
"Invalid github PR Url($url) found in message: $message}");
}
final prNumber = match.namedGroup('pr_number');
prUrls.add('[#$prNumber]($url)');
}
markdown += ' - ${prUrls.join(", ")}';
}
markdown += '\n';
if (imageNames != null) {
for (var imageName in imageNames!) {
markdown += '![](files/$imageName)\n';
}
}
return markdown;
}
factory ReleaseNote.fromJson(Map<String, dynamic> json) =>
_$ReleaseNoteFromJson(json);
Map<String, dynamic> toJson() => _$ReleaseNoteToJson(this);
}
// # Sementic line breaks of 80 chars or fewer
// # each line requires an PR command