@@ -34,6 +34,9 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand {
3434 /// Packages with entries in CODEOWNERS.
3535 final List <String > _ownedPackages = < String > [];
3636
37+ /// Packages with entries in labeler.yml.
38+ final List <String > _autoLabeledPackages = < String > [];
39+
3740 @override
3841 final String name = 'repo-package-info-check' ;
3942
@@ -42,7 +45,7 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand {
4245
4346 @override
4447 final String description =
45- 'Checks that all packages are listed correctly in the repo README .' ;
48+ 'Checks that all packages are listed correctly in repo metadata .' ;
4649
4750 @override
4851 final bool hasLongOutput = false ;
@@ -98,6 +101,23 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand {
98101 }
99102 _ownedPackages.add (name);
100103 }
104+
105+ // Extract all of the lebeler.yml package entries.
106+ // Validate the match rules rather than the label itself, as the labels
107+ // don't always correspond 1:1 to packages and package names.
108+ final RegExp packageGlobPattern =
109+ RegExp (r'^\s*-\s*(?:third_party/)?packages/([^*]*)/' );
110+ for (final String line in _repoRoot
111+ .childDirectory ('.github' )
112+ .childFile ('labeler.yml' )
113+ .readAsLinesSync ()) {
114+ final RegExpMatch ? match = packageGlobPattern.firstMatch (line);
115+ if (match == null ) {
116+ continue ;
117+ }
118+ final String name = match.group (1 )! ;
119+ _autoLabeledPackages.add (name);
120+ }
101121 }
102122
103123 @override
@@ -115,92 +135,110 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand {
115135 errors.add ('Missing CODEOWNERS entry' );
116136 }
117137
138+ // All packages should have an auto-applied label. For plugins, only the
139+ // group needs a rule, so check the app-facing package.
140+ if (! (package.isFederated && ! package.isAppFacing) &&
141+ ! _autoLabeledPackages.contains (packageName)) {
142+ printError ('${indentation }Missing a rule in .github/labeler.yml.' );
143+ errors.add ('Missing auto-labeler entry' );
144+ }
145+
118146 // The content of ci_config.yaml must be valid if there is one.
119147 if (package.ciConfigFile.existsSync ()) {
120148 errors.addAll (
121149 _validateCiConfig (package.ciConfigFile, mainPackage: package));
122150 }
123151
124- // Any published package should be in the README table.
152+ // All published packages should have a README.md entry.
153+ if (package.isPublishable ()) {
154+ errors.addAll (_validateRootReadme (package));
155+ }
156+
157+ return errors.isEmpty
158+ ? PackageResult .success ()
159+ : PackageResult .fail (errors);
160+ }
161+
162+ List <String > _validateRootReadme (RepositoryPackage package) {
163+ final List <String > errors = < String > [];
164+
125165 // For federated plugins, only the app-facing package is listed.
126- if (package.isPublishable () &&
127- ( ! package.isFederated || package.isAppFacing)) {
128- final List < String > ? cells = _readmeTableEntries[packageName];
166+ if (package.isFederated && ! package.isAppFacing) {
167+ return errors;
168+ }
129169
130- if (cells == null ) {
131- printError ('${indentation }Missing repo root README.md table entry' );
132- errors.add ('Missing repo root README.md table entry' );
133- } else {
134- // Extract the two parts of a "[label](link)" .md link.
135- final RegExp mdLinkPattern = RegExp (r'^\[(.*)\]\((.*)\)$' );
136- // Possible link targets.
137- for (final String cell in cells) {
138- final RegExpMatch ? match = mdLinkPattern.firstMatch (cell);
139- if (match == null ) {
170+ final String packageName = package.directory.basename;
171+ final List <String >? cells = _readmeTableEntries[packageName];
172+ if (cells == null ) {
173+ printError ('${indentation }Missing repo root README.md table entry' );
174+ errors.add ('Missing repo root README.md table entry' );
175+ } else {
176+ // Extract the two parts of a "[label](link)" .md link.
177+ final RegExp mdLinkPattern = RegExp (r'^\[(.*)\]\((.*)\)$' );
178+ // Possible link targets.
179+ for (final String cell in cells) {
180+ final RegExpMatch ? match = mdLinkPattern.firstMatch (cell);
181+ if (match == null ) {
182+ printError (
183+ '${indentation }Invalid repo root README.md table entry: "$cell "' );
184+ errors.add ('Invalid root README.md table entry' );
185+ } else {
186+ final String encodedIssueTag =
187+ Uri .encodeComponent (_issueTagForPackage (packageName));
188+ final String encodedPRTag =
189+ Uri .encodeComponent (_prTagForPackage (packageName));
190+ final String anchor = match.group (1 )! ;
191+ final String target = match.group (2 )! ;
192+
193+ // The anchor should be one of:
194+ // - The package name (optionally with any underscores escaped)
195+ // - An image with a name-based link
196+ // - An image with a tag-based link
197+ final RegExp packageLink =
198+ RegExp (r'^!\[.*\]\(https://img.shields.io/pub/.*/'
199+ '$packageName '
200+ r'(?:\.svg)?\)$' );
201+ final RegExp issueTagLink = RegExp (
202+ r'^!\[.*\]\(https://img.shields.io/github/issues/flutter/flutter/'
203+ '$encodedIssueTag '
204+ r'\?label=\)$' );
205+ final RegExp prTagLink = RegExp (
206+ r'^!\[.*\]\(https://img.shields.io/github/issues-pr/flutter/packages/'
207+ '$encodedPRTag '
208+ r'\?label=\)$' );
209+ if (! (anchor == packageName ||
210+ anchor == packageName.replaceAll ('_' , r'\_' ) ||
211+ packageLink.hasMatch (anchor) ||
212+ issueTagLink.hasMatch (anchor) ||
213+ prTagLink.hasMatch (anchor))) {
140214 printError (
141- '${indentation }Invalid repo root README.md table entry: "$cell "' );
142- errors.add ('Invalid root README.md table entry' );
143- } else {
144- final String encodedIssueTag =
145- Uri .encodeComponent (_issueTagForPackage (packageName));
146- final String encodedPRTag =
147- Uri .encodeComponent (_prTagForPackage (packageName));
148- final String anchor = match.group (1 )! ;
149- final String target = match.group (2 )! ;
150-
151- // The anchor should be one of:
152- // - The package name (optionally with any underscores escaped)
153- // - An image with a name-based link
154- // - An image with a tag-based link
155- final RegExp packageLink =
156- RegExp (r'^!\[.*\]\(https://img.shields.io/pub/.*/'
157- '$packageName '
158- r'(?:\.svg)?\)$' );
159- final RegExp issueTagLink = RegExp (
160- r'^!\[.*\]\(https://img.shields.io/github/issues/flutter/flutter/'
161- '$encodedIssueTag '
162- r'\?label=\)$' );
163- final RegExp prTagLink = RegExp (
164- r'^!\[.*\]\(https://img.shields.io/github/issues-pr/flutter/packages/'
165- '$encodedPRTag '
166- r'\?label=\)$' );
167- if (! (anchor == packageName ||
168- anchor == packageName.replaceAll ('_' , r'\_' ) ||
169- packageLink.hasMatch (anchor) ||
170- issueTagLink.hasMatch (anchor) ||
171- prTagLink.hasMatch (anchor))) {
172- printError (
173- '${indentation }Incorrect anchor in root README.md table: "$anchor "' );
174- errors.add ('Incorrect anchor in root README.md table' );
175- }
176-
177- // The link should be one of:
178- // - a relative link to the in-repo package
179- // - a pub.dev link to the package
180- // - a github label link to the package's label
181- final RegExp pubDevLink =
182- RegExp ('^https://pub.dev/packages/$packageName (?:/score)?\$ ' );
183- final RegExp gitHubIssueLink = RegExp (
184- '^https://github.com/flutter/flutter/labels/$encodedIssueTag \$ ' );
185- final RegExp gitHubPRLink = RegExp (
186- '^https://github.com/flutter/packages/labels/$encodedPRTag \$ ' );
187- if (! (target == './packages/$packageName /' ||
188- target == './third_party/packages/$packageName /' ||
189- pubDevLink.hasMatch (target) ||
190- gitHubIssueLink.hasMatch (target) ||
191- gitHubPRLink.hasMatch (target))) {
192- printError (
193- '${indentation }Incorrect link in root README.md table: "$target "' );
194- errors.add ('Incorrect link in root README.md table' );
195- }
215+ '${indentation }Incorrect anchor in root README.md table: "$anchor "' );
216+ errors.add ('Incorrect anchor in root README.md table' );
217+ }
218+
219+ // The link should be one of:
220+ // - a relative link to the in-repo package
221+ // - a pub.dev link to the package
222+ // - a github label link to the package's label
223+ final RegExp pubDevLink =
224+ RegExp ('^https://pub.dev/packages/$packageName (?:/score)?\$ ' );
225+ final RegExp gitHubIssueLink = RegExp (
226+ '^https://github.com/flutter/flutter/labels/$encodedIssueTag \$ ' );
227+ final RegExp gitHubPRLink = RegExp (
228+ '^https://github.com/flutter/packages/labels/$encodedPRTag \$ ' );
229+ if (! (target == './packages/$packageName /' ||
230+ target == './third_party/packages/$packageName /' ||
231+ pubDevLink.hasMatch (target) ||
232+ gitHubIssueLink.hasMatch (target) ||
233+ gitHubPRLink.hasMatch (target))) {
234+ printError (
235+ '${indentation }Incorrect link in root README.md table: "$target "' );
236+ errors.add ('Incorrect link in root README.md table' );
196237 }
197238 }
198239 }
199240 }
200-
201- return errors.isEmpty
202- ? PackageResult .success ()
203- : PackageResult .fail (errors);
241+ return errors;
204242 }
205243
206244 List <String > _validateCiConfig (File ciConfig,
0 commit comments