diff --git a/.agents/skills/adding-release-notes/SKILL.md b/.agents/skills/adding-release-notes/SKILL.md new file mode 100644 index 00000000000..cfb0ae86112 --- /dev/null +++ b/.agents/skills/adding-release-notes/SKILL.md @@ -0,0 +1,75 @@ +--- +name: adding-release-notes +description: Adds user-facing change descriptions to DevTools release notes. Use when documenting improvements, fixes, or new features in the NEXT_RELEASE_NOTES.md file. +--- + +# Adding Release Notes + +This skill helps automate adding release notes to `packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md`. + +## Workflow +Copy this checklist into your response to track progress: + +```markdown +Release Notes Progress: +- [ ] Step 1: Formulate the entry (past tense, use "TODO" for PR number if unknown) +- [ ] Step 2: Determine the section (Inspector, Memory, etc.) +- [ ] Step 3: Add the entry (use scripts/add_note.dart) +- [ ] Step 4: Add images (if applicable) +``` + +## Guidelines + +### 1. Formulate the Entry +- **Tense**: Always use **past tense** (e.g., "Added", "Improved", "Fixed"). +- **Punctuation**: Always end entries with a **period**. +- **Template**: `* . [#](https://github.com/flutter/devtools/pull/)` +- **Placeholder**: Use `TODO` if you do not have a PR number yet. +- **Images**: If adding an image, indent it by two spaces to align with the bullet point, and ensure there is only one newline between the text and the image. + - Correct Format: + ```markdown + - Added support for XYZ. [#TODO](https://github.com/flutter/devtools/pull/TODO) + ![](images/my_feature.png) + ``` +- **Examples**: + - `* Added support for XYZ. [#12345](https://github.com/flutter/devtools/pull/12345)` + - `* Fixed a crash in the ABC screen. [#67890](https://github.com/flutter/devtools/pull/67890)` + +### 2. User-Facing Changes Only +- **Criteria**: Focus on **what** changed for the user, not **how** it was implemented. +- **Avoid**: Technical details like "Implemented XYZ with a new controller", "Updated the build method", or naming internal classes. +- **Example (Bad)**: `* Implemented log details search using SearchControllerMixin. [#TODO](https://github.com/flutter/devtools/pull/TODO)` +- **Example (Good)**: `* Added search support to the log details view. [#TODO](https://github.com/flutter/devtools/pull/TODO)` + +### 3. Determine Section +Match the change to the section in `NEXT_RELEASE_NOTES.md`: +- `General updates` +- `Inspector updates` +- `Performance updates` +- `CPU profiler updates` +- `Memory updates` +- `Debugger updates` +- `Network profiler updates` +- `Logging updates` +- `App size tool updates` +- `Deep links tool updates` +- `VS Code sidebar updates` +- `DevTools extension updates` +- `Advanced developer mode updates` + +### 3. Add to NEXT_RELEASE_NOTES.md +Use the provided utility script to insert the note safely. The script handles replacing the TODO placeholder if it's the first entry in that section. + +```bash +dart .agents/skills/adding-release-notes/scripts/add_note.dart "Inspector updates" "Added XYZ support" TODO +``` + +### 4. Optional: Images +Add images to `packages/devtools_app/release_notes/images/` and reference them: +```markdown +![Accessible description](images/screenshot.png "Hover description") +``` +**Constraint**: Use **dark mode** for screenshots. + +## Resources +- [README.md](../../packages/devtools_app/release_notes/README.md): Official project guidance. diff --git a/.agents/skills/adding-release-notes/scripts/add_note.dart b/.agents/skills/adding-release-notes/scripts/add_note.dart new file mode 100644 index 00000000000..ec0c22eb947 --- /dev/null +++ b/.agents/skills/adding-release-notes/scripts/add_note.dart @@ -0,0 +1,68 @@ +// Copyright 2019 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. + +import 'dart:io'; + +void main(List args) { + if (args.length < 3) { + print('Usage: dart add_note.dart
'); + exit(1); + } + + final section = args[0].trim(); + final note = args[1].trim(); + final pr = args[2].trim(); + + final filePath = 'packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md'; + final file = File(filePath); + + if (!file.existsSync()) { + print('Error: $filePath not found.'); + exit(1); + } + + var content = file.readAsStringSync(); + + if (!content.contains('## $section')) { + print("Error: Section '$section' not found."); + exit(1); + } + + final noteWithPeriod = note.endsWith('.') ? note : '$note.'; + final newEntry = '- $noteWithPeriod $prLink\n'; + + // Check for TODO placeholder. + const todoText = 'TODO: Remove this section if there are not any updates.'; + final todoPattern = RegExp( + '## ${RegExp.escape(section)}\\s*\\n\\s*${RegExp.escape(todoText)}\\s*\\n*', + ); + + if (todoPattern.hasMatch(content)) { + content = content.replaceFirst(todoPattern, '## $section\n\n$newEntry\n'); + } else { + // Append to existing list in the section. + final sectionHeader = '## $section'; + final sectionStart = content.indexOf(sectionHeader); + + // Find the next section start or the end of the file. + var nextSectionStart = content.indexOf('\n## ', sectionStart + 1); + if (nextSectionStart == -1) { + nextSectionStart = + content.indexOf('\n# Full commit history', sectionStart + 1); + } + if (nextSectionStart == -1) { + nextSectionStart = content.length; + } + + var sectionContent = + content.substring(sectionStart, nextSectionStart).trimRight(); + sectionContent += '\n$newEntry'; + + content = + '${content.substring(0, sectionStart)}$sectionContent\n${content.substring(nextSectionStart).trimLeft()}'; + } + + file.writeAsStringSync(content); + print('Successfully added note to $section.'); +} diff --git a/pubspec.lock b/pubspec.lock index 7831ae0f18f..e30fd8babfe 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -530,10 +530,10 @@ packages: dependency: transitive description: name: matcher - sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 url: "https://pub.dev" source: hosted - version: "0.12.18" + version: "0.12.19" material_color_utilities: dependency: transitive description: @@ -758,10 +758,10 @@ packages: dependency: transitive description: name: source_gen - sha256: "1d562a3c1f713904ebbed50d2760217fd8a51ca170ac4b05b0db490699dbac17" + sha256: adc962c96fffb2de1728ef396a995aaedcafbe635abdca13d2a987ce17e57751 url: "https://pub.dev" source: hosted - version: "4.2.0" + version: "4.2.1" source_map_stack_trace: dependency: transitive description: @@ -854,26 +854,26 @@ packages: dependency: transitive description: name: test - sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a" + sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7" url: "https://pub.dev" source: hosted - version: "1.29.0" + version: "1.30.0" test_api: dependency: transitive description: name: test_api - sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" url: "https://pub.dev" source: hosted - version: "0.7.9" + version: "0.7.10" test_core: dependency: transitive description: name: test_core - sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943" + sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51" url: "https://pub.dev" source: hosted - version: "0.6.15" + version: "0.6.16" typed_data: dependency: transitive description: