From 6efcc378652c1b75635df7f9fd1f796026f770d1 Mon Sep 17 00:00:00 2001 From: Kenzie Schmoll Date: Wed, 10 May 2023 14:50:11 -0700 Subject: [PATCH 1/5] Ensure release notes show most recent notes for pre-release version --- .../lib/src/framework/about_dialog.dart | 2 +- .../release_notes/release_notes.dart | 145 +++++++++++------- .../test/shared/release_notes_test.dart | 29 ++++ 3 files changed, 123 insertions(+), 53 deletions(-) create mode 100644 packages/devtools_app/test/shared/release_notes_test.dart diff --git a/packages/devtools_app/lib/src/framework/about_dialog.dart b/packages/devtools_app/lib/src/framework/about_dialog.dart index 40063daa7ff..0803ff994b4 100644 --- a/packages/devtools_app/lib/src/framework/about_dialog.dart +++ b/packages/devtools_app/lib/src/framework/about_dialog.dart @@ -39,7 +39,7 @@ class DevToolsAboutDialog extends StatelessWidget { style: theme.linkTextStyle, ), onTap: () => - releaseNotesController.toggleReleaseNotesVisible(true), + unawaited(releaseNotesController.openLatestReleaseNotes()), ), ], ), diff --git a/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart b/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart index 6ac0d5d21a0..f107ead898a 100644 --- a/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart +++ b/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart @@ -22,7 +22,11 @@ import '../../shared/theme.dart'; final _log = Logger('release_notes'); -const debugTestReleaseNotes = false; +// This is not const because it is manipulated for testing as well as for +// local development. +bool debugTestReleaseNotes = false; + +const debugUseStagedFlutterWebsite = false; class ReleaseNotesViewer extends StatefulWidget { const ReleaseNotesViewer({ @@ -185,7 +189,7 @@ class ReleaseNotesController { static const _unsupportedPathSyntax = '{{site.url}}'; - String get _flutterDocsSite => debugTestReleaseNotes + String get _flutterDocsSite => debugUseStagedFlutterWebsite ? 'https://flutter-website-dt-staging.web.app' : 'https://docs.flutter.dev'; @@ -199,11 +203,11 @@ class ReleaseNotesController { void _init() { if (debugTestReleaseNotes || server.isDevToolsServerAvailable) { - _maybeFetchReleaseNotes(); + _maybeShowReleaseNotes(); } } - void _maybeFetchReleaseNotes() async { + void _maybeShowReleaseNotes() async { SemanticVersion previousVersion = SemanticVersion(); if (server.isDevToolsServerAvailable) { final lastReleaseNotesShownVersion = @@ -212,63 +216,100 @@ class ReleaseNotesController { previousVersion = SemanticVersion.parse(lastReleaseNotesShownVersion); } } + await _fetchAndShowReleaseNotes(versionFloor: previousVersion); + } + + /// Fetches and shows the most recent release notes for the current DevTools + /// version decreasing the patch version by 1 each time until we find release + /// notes or until we hit [versionFloor]. + Future _fetchAndShowReleaseNotes({ + SemanticVersion? versionFloor, + }) async { + versionFloor ??= SemanticVersion(); + // Parse the current version instead of using [devtools.version] directly to // strip off any build metadata (any characters following a '+' character). // Release notes will be hosted on the Flutter website with a version number // that does not contain any build metadata. - final parsedCurrentVersion = SemanticVersion.parse(devtools.version); - final parsedCurrentVersionStr = parsedCurrentVersion.toString(); - if (parsedCurrentVersion > previousVersion) { - try { - await _fetchReleaseNotes(parsedCurrentVersion); - } catch (e) { - // Fail gracefully if we cannot find release notes for the current - // version of DevTools. - _releaseNotesMarkdown.value = null; - toggleReleaseNotesVisible(false); - _log.warning( - 'Warning: could not find release notes for DevTools version ' - '$parsedCurrentVersionStr. $e', - ); + final parsedVersion = SemanticVersion.parse(devtools.version); + var notesVersion = latestVersionToCheckForReleaseNotes(parsedVersion); + try { + // Try all patch versions for this major.minor combination until we find + // release notes (e.g. 2.11.4 -> 2.11.3 -> 2.11.2 -> ...). + final attemptedVersions = []; + var attempts = notesVersion.patch; + while (attempts >= 0 && notesVersion > versionFloor) { + final versionString = notesVersion.toString(); + try { + String releaseNotesMarkdown = await http.read( + Uri.parse(_releaseNotesUrl(versionString)), + ); + // This is a workaround so that the images in release notes will appear. + // The {{site.url}} syntax is best practices for the flutter website + // repo, where these release notes are hosted, so we are performing this + // workaround on our end to ensure the images render properly. + releaseNotesMarkdown = releaseNotesMarkdown.replaceAll( + _unsupportedPathSyntax, + _flutterDocsSite, + ); + + _releaseNotesMarkdown.value = releaseNotesMarkdown; + toggleReleaseNotesVisible(true); + if (server.isDevToolsServerAvailable) { + unawaited( + server.setLastShownReleaseNotesVersion(versionString), + ); + } + return; + } catch (e) { + attempts--; + attemptedVersions.add(versionString); + if (attempts < 0) { + // ignore: avoid-throw-in-catch-block, false positive + throw Exception( + 'Could not find release notes for DevTools versions ' + '${attemptedVersions.join(', ')}.' + '\n$e', + ); + } + notesVersion = notesVersion.downgrade(downgradePatch: true); + } } + } catch (e) { + // Fail gracefully if we cannot find release notes for the current + // version of DevTools. + _releaseNotesMarkdown.value = null; + toggleReleaseNotesVisible(false); + _log.warning('Warning: $e'); } } - Future _fetchReleaseNotes(SemanticVersion version) async { - final currentVersionString = version.toString(); - - // Try all patch versions for this major.minor combination until we find - // release notes (e.g. 2.11.4 -> 2.11.3 -> 2.11.2 -> ...). - var attempts = version.patch; - while (attempts >= 0) { - final versionString = version.toString(); - try { - String releaseNotesMarkdown = await http.read( - Uri.parse(_releaseNotesUrl(versionString)), - ); - // This is a workaround so that the images in release notes will appear. - // The {{site.url}} syntax is best practices for the flutter website - // repo, where these release notes are hosted, so we are performing this - // workaround on our end to ensure the images render properly. - releaseNotesMarkdown = releaseNotesMarkdown.replaceAll( - _unsupportedPathSyntax, - _flutterDocsSite, - ); - - _releaseNotesMarkdown.value = releaseNotesMarkdown; - toggleReleaseNotesVisible(true); - unawaited( - server.setLastShownReleaseNotesVersion(currentVersionString), - ); - return; - } catch (_) { - attempts--; - if (attempts < 0) { - rethrow; - } - version = version.downgrade(downgradePatch: true); - } + @visibleForTesting + SemanticVersion latestVersionToCheckForReleaseNotes( + SemanticVersion currentVersion, + ) { + // If the current version is a pre-release, downgrade the minor to find the + // previous DevTools release, and start looking for release notes from this + // value. Release notes will never be published for pre-release versions. + if (currentVersion.isPreRelease) { + // It is very unlikely the patch value of the DevTools version will ever + // be above this number. This is a safe number to start looking for + // release notes at. + const safeStartPatch = 10; + currentVersion = SemanticVersion( + major: currentVersion.major, + minor: currentVersion.minor - 1, + patch: safeStartPatch, + ); + } + return currentVersion; + } + + Future openLatestReleaseNotes() async { + if (_releaseNotesMarkdown.value == null) { + await _fetchAndShowReleaseNotes(); } + toggleReleaseNotesVisible(true); } void toggleReleaseNotesVisible(bool visible) { diff --git a/packages/devtools_app/test/shared/release_notes_test.dart b/packages/devtools_app/test/shared/release_notes_test.dart new file mode 100644 index 00000000000..62f803875da --- /dev/null +++ b/packages/devtools_app/test/shared/release_notes_test.dart @@ -0,0 +1,29 @@ +// Copyright 2023 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:devtools_app/devtools_app.dart'; +import 'package:devtools_shared/devtools_shared.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('$ReleaseNotesController', () { + late ReleaseNotesController controller; + setUp(() { + debugTestReleaseNotes = true; + controller = ReleaseNotesController(); + }); + + test('latestVersionToCheckForReleaseNotes', () { + var version = controller.latestVersionToCheckForReleaseNotes( + SemanticVersion.parse('2.24.5-dev.1'), + ); + expect(version.toString(), '2.23.10'); + + version = controller.latestVersionToCheckForReleaseNotes( + SemanticVersion.parse('2.24.1'), + ); + expect(version.toString(), '2.24.1'); + }); + }); +} From 297c67edba221b92cf6af7b214646e8bc0671cb1 Mon Sep 17 00:00:00 2001 From: Kenzie Schmoll Date: Wed, 10 May 2023 15:21:47 -0700 Subject: [PATCH 2/5] fix comment --- .../lib/src/framework/release_notes/release_notes.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart b/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart index f107ead898a..23a02627b36 100644 --- a/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart +++ b/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart @@ -220,7 +220,7 @@ class ReleaseNotesController { } /// Fetches and shows the most recent release notes for the current DevTools - /// version decreasing the patch version by 1 each time until we find release + /// version, decreasing the patch version by 1 each time until we find release /// notes or until we hit [versionFloor]. Future _fetchAndShowReleaseNotes({ SemanticVersion? versionFloor, From a32a3ea4671b4a48e4eae1b3f886e03ecb3b76c9 Mon Sep 17 00:00:00 2001 From: Kenzie Schmoll Date: Thu, 11 May 2023 15:29:18 -0700 Subject: [PATCH 3/5] merge master --- .../lib/src/framework/release_notes/release_notes.dart | 6 +++--- packages/devtools_app/lib/src/shared/side_panel.dart | 8 +------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart b/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart index ad39222761d..ee75f880e4f 100644 --- a/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart +++ b/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart @@ -96,7 +96,7 @@ class ReleaseNotesController extends SidePanelController { _flutterDocsSite, ); - markdownText.value = releaseNotesMarkdown; + markdown.value = releaseNotesMarkdown; toggleVisibility(true); if (server.isDevToolsServerAvailable) { unawaited( @@ -121,7 +121,7 @@ class ReleaseNotesController extends SidePanelController { } catch (e) { // Fail gracefully if we cannot find release notes for the current // version of DevTools. - markdownText.value = null; + markdown.value = null; toggleVisibility(false); _log.warning('Warning: $e'); } @@ -149,7 +149,7 @@ class ReleaseNotesController extends SidePanelController { } Future openLatestReleaseNotes() async { - if (markdownText.value == null) { + if (markdown.value == null) { await _fetchAndShowReleaseNotes(); } toggleVisibility(true); diff --git a/packages/devtools_app/lib/src/shared/side_panel.dart b/packages/devtools_app/lib/src/shared/side_panel.dart index bdbd0b553d3..7faf62a59a3 100644 --- a/packages/devtools_app/lib/src/shared/side_panel.dart +++ b/packages/devtools_app/lib/src/shared/side_panel.dart @@ -194,9 +194,7 @@ class SidePanel extends AnimatedWidget { } class SidePanelController { - ValueListenable get markdown => _markdown; - - final _markdown = ValueNotifier(null); + final markdown = ValueNotifier(null); ValueListenable get isVisible => _isVisible; @@ -205,8 +203,4 @@ class SidePanelController { void toggleVisibility(bool visible) { _isVisible.value = visible; } - - set markdownText(String? markdownText) { - _markdown.value = markdownText; - } } From 446403292d4c92c9e99ceb341f5d3cab40a98b03 Mon Sep 17 00:00:00 2001 From: Kenzie Schmoll Date: Thu, 11 May 2023 15:55:32 -0700 Subject: [PATCH 4/5] formatting --- .../lib/src/framework/release_notes/release_notes.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart b/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart index ee75f880e4f..2cf4516d222 100644 --- a/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart +++ b/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart @@ -121,8 +121,8 @@ class ReleaseNotesController extends SidePanelController { } catch (e) { // Fail gracefully if we cannot find release notes for the current // version of DevTools. - markdown.value = null; - toggleVisibility(false); + markdown.value = null; + toggleVisibility(false); _log.warning('Warning: $e'); } } From 5c704de718bca960967c605f25b9b5477c3f6c72 Mon Sep 17 00:00:00 2001 From: Kenzie Schmoll Date: Fri, 12 May 2023 12:46:33 -0700 Subject: [PATCH 5/5] fixes --- .../lib/src/framework/release_notes/release_notes.dart | 4 +++- packages/devtools_app/release_notes/README.md | 7 +++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart b/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart index 2cf4516d222..03ecd9df04f 100644 --- a/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart +++ b/packages/devtools_app/lib/src/framework/release_notes/release_notes.dart @@ -59,7 +59,9 @@ class ReleaseNotesController extends SidePanelController { previousVersion = SemanticVersion.parse(lastReleaseNotesShownVersion); } } - await _fetchAndShowReleaseNotes(versionFloor: previousVersion); + await _fetchAndShowReleaseNotes( + versionFloor: debugTestReleaseNotes ? null : previousVersion, + ); } /// Fetches and shows the most recent release notes for the current DevTools diff --git a/packages/devtools_app/release_notes/README.md b/packages/devtools_app/release_notes/README.md index 88864879ef8..3b462dbb78c 100644 --- a/packages/devtools_app/release_notes/README.md +++ b/packages/devtools_app/release_notes/README.md @@ -1,5 +1,5 @@ ## Generating Release notes -- Release notes for DevTools are hosted on the flutter website (see [archive](https://docs.flutter.dev/development/tools/devtools/release-notes)). +- Release notes for DevTools are hosted on the flutter website (see [archive](https://docs.flutter.dev/tools/devtools/release-notes)). - To add release notes for the latest release, create a PR with the appropriate changes for your release. - The [NEXT_RELEASE_NOTES.md](NEXT_RELEASE_NOTES.md) file contains the running release notes for the current version. - see example [PR](https://github.com/flutter/website/pull/6791) for an idea of how to add those to the Flutter website. @@ -7,7 +7,7 @@ - Test these changes locally before creating the PR. - See [README.md](https://github.com/flutter/website/blob/main/README.md) for getting setup to run the Flutter website locally. - - Release notes can be found at [http://localhost:4002/development/tools/devtools/release-notes/](http://localhost:4002/development/tools/devtools/release-notes/) + - Release notes can be found at [http://localhost:4002/development/tools/devtools/release-notes/](http://localhost:4002/tools/devtools/release-notes/) - Once you are satisfied with the release notes - stage the Flutter website on Firebase @@ -47,7 +47,7 @@ for getting setup to run the Flutter website locally. ``` ### Testing the release notes in DevTools -- In `release_notes.dart` flip the `debugTestReleaseNotes` flag to true. +- In `release_notes.dart` flip the `debugTestReleaseNotes` and `debugUseStagedFlutterWebsite` flags to true. - from the main `devtools/` directory, run the following: ```shell @@ -64,4 +64,3 @@ Serving DevTools at http://127.0.0.1:57336. - Visit the DevTools link - verify the release notes viewer displays the new release notes as expected. -