[tool] Add a package-level pre-publish hook (#7156)

Adds the ability for a package to specify a script that should be run before publishing. To minimize the chance of such a script breaking things only in the post-submit `release` step, if the script is present it will also be run during `publish-check`.

These should be used with caution since they can cause the published artifacts to be different from that is checked in, but in the intended use case of extension builds this risk is far preferable to the risks associated with checking in binaries that were built on local, ad-hoc basis. (Longer term, we may need an alternate solution however, as generating artifacts in CI can have its own supply chain validation issues.)

Also does some minor refactoring to custom test script code to make it follow the same pattern as this new code.

Fixes https://github.com/flutter/flutter/issues/150210
This commit is contained in:
stuartmorgan
2024-07-25 16:06:18 -04:00
committed by GitHub
parent 94f8b2fb27
commit 50238e7dd3
6 changed files with 244 additions and 7 deletions

View File

@ -369,6 +369,88 @@ void main() {
));
});
group('pre-publish script', () {
test('runs if present', () async {
final RepositoryPackage package =
createFakePackage('a_package', packagesDir, examples: <String>[]);
package.prePublishScript.createSync(recursive: true);
final List<String> output = await runCapturingPrint(runner, <String>[
'publish-check',
]);
expect(
output,
containsAllInOrder(<Matcher>[
contains('Running pre-publish hook tool/pre_publish.dart...'),
]),
);
expect(
processRunner.recordedCalls,
containsAllInOrder(<ProcessCall>[
ProcessCall(
'dart',
const <String>[
'pub',
'get',
],
package.directory.path),
ProcessCall(
'dart',
const <String>[
'run',
'tool/pre_publish.dart',
],
package.directory.path),
]));
});
test('causes command failure if it fails', () async {
final RepositoryPackage package = createFakePackage(
'a_package', packagesDir,
isFlutter: true, examples: <String>[]);
package.prePublishScript.createSync(recursive: true);
processRunner.mockProcessesForExecutable['dart'] = <FakeProcessInfo>[
FakeProcessInfo(MockProcess(exitCode: 1),
<String>['run']), // run tool/pre_publish.dart
];
Error? commandError;
final List<String> output = await runCapturingPrint(runner, <String>[
'publish-check',
], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(<Matcher>[
contains('Pre-publish script failed.'),
]),
);
expect(
processRunner.recordedCalls,
containsAllInOrder(<ProcessCall>[
ProcessCall(
getFlutterCommand(mockPlatform),
const <String>[
'pub',
'get',
],
package.directory.path),
ProcessCall(
'dart',
const <String>[
'run',
'tool/pre_publish.dart',
],
package.directory.path),
]));
});
});
test(
'--machine: Log JSON with status:no-publish and correct human message, if there are no packages need to be published. ',
() async {