spotube/flutter/dev/bots/test/ci_yaml_validation_test.dart
Rahul Sahani b5a8835c28 Enhance media controls and add social sharing features
Add enhanced media controls and social sharing features.

* **Enhanced Media Controls:**
  - Add volume control slider to `PlayerControls` widget in `lib/modules/player/player_controls.dart`.
  - Implement keyboard shortcuts for media controls (play/pause, next/previous track, volume up/down) in `PlayerControls` widget.
  - Add "lyrics" button to `PlayerView` widget in `lib/modules/player/player.dart`.

* **Social Sharing Features:**
  - Add feature to share the currently playing track on social media platforms in `lib/components/track_tile/track_options.dart`.
  - Add share button to `TrackPresentationTopSection` widget in `lib/components/track_presentation/presentation_top.dart`.

* **Settings:**
  - Add dark mode toggle in the settings page in `lib/pages/settings/settings.dart`.

* **CI Configuration:**
  - Add `.ci.yaml` file for continuous integration configuration.
2025-03-09 13:34:56 +05:30

162 lines
4.9 KiB
Dart

// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@TestOn('vm')
library;
import 'dart:io' as io;
import 'package:path/path.dart' as p;
import 'package:source_span/source_span.dart';
import 'package:yaml/yaml.dart';
import './common.dart';
void main() {
final String flutterRoot = () {
io.Directory current = io.Directory.current;
while (!io.File(p.join(current.path, 'DEPS')).existsSync()) {
if (current.path == current.parent.path) {
fail(
'Could not find flutter repository root (${io.Directory.current.path} -> ${current.path})',
);
}
current = current.parent;
}
return current.path;
}();
group('framework', () {
final List<_CiYamlTarget> targets = _CiYamlTarget.parseAll(p.join(flutterRoot, '.ci.yaml'));
for (final _CiYamlTarget target in targets) {
if (target.runIf == null || target.runIf!.isEmpty) {
continue;
}
setUp(() {
printOnFailure(target.span.message('One or more errors occurred validating'));
});
group(target.name, () {
test('must include .ci.yaml', () {
expect(
target.runIf,
contains('.ci.yaml'),
reason: '.ci.yaml inclusion means changes to the runIfs will trigger presubmit tests.',
);
});
test('must include DEPS', () {
expect(
target.runIf,
contains('DEPS'),
reason: 'DEPS updates (including the Dart SDK) mean presubmit tests must be run.',
);
});
test('must include the engine sources', () {
expect(
target.runIf,
contains('engine/**'),
reason: 'Engine updates means framework presubmit tests must be run.',
);
});
});
}
});
group('engine', () {
final List<_CiYamlTarget> targets = _CiYamlTarget.parseAll(
p.join(flutterRoot, 'engine', 'src', 'flutter', '.ci.yaml'),
);
for (final _CiYamlTarget target in targets) {
if (target.runIf == null || target.runIf!.isEmpty) {
continue;
}
setUp(() {
printOnFailure(target.span.message('One or more errors occurred validating'));
});
group(target.name, () {
test('must include .ci.yaml', () {
expect(
target.runIf,
contains('engine/src/flutter/.ci.yaml'),
reason: '.ci.yaml inclusion means changes to the runIfs will trigger presubmit tests.',
);
});
test('must include DEPS', () {
expect(
target.runIf,
contains('DEPS'),
reason: 'DEPS updates (including the Dart SDK) mean presubmit tests must be run.',
);
});
});
}
});
}
/// A minimal representation of an ostensibly well-formatted `.ci.yaml` file.
///
/// Due to the repository setup, it's not possible to reuse the existing
/// specifications of this file, and since the test case is only testing a
/// subset of the encoding, this class exposes only that subset.
///
/// For a discussion leading to this design decision, see
/// <https://github.com/flutter/flutter/issues/160915>.
///
/// See also:
/// - [`scheduler.proto`][1], the schema definition of the file format.
/// - [`CI_YAML.md`][2], a human-authored description of the file format.
/// - [`ci_yaml.dart`][3], where validation is performed (in `flutter/cocoon`).
///
/// [1]: https://github.com/flutter/cocoon/blob/main/app_dart/lib/src/model/proto/internal/scheduler.proto
/// [2]: https://github.com/flutter/cocoon/blob/main/CI_YAML.md
/// [3]: https://github.com/flutter/cocoon/blob/main/app_dart/lib/src/model/ci_yaml/ci_yaml.dart
final class _CiYamlTarget {
_CiYamlTarget({required this.name, required this.span, required this.runIf});
factory _CiYamlTarget.fromYamlMap(YamlMap map) {
return _CiYamlTarget(
name: map['name'] as String,
span: map.span,
runIf: () {
final YamlList? runIf = map['runIf'] as YamlList?;
if (runIf == null) {
return null;
}
return runIf.cast<String>().toList();
}(),
);
}
/// Parses a list of targets from the provided `.ci.yaml` file [path].
static List<_CiYamlTarget> parseAll(String path) {
final YamlDocument yamlDoc = loadYamlDocument(
io.File(path).readAsStringSync(),
sourceUrl: Uri.parse(path),
);
final YamlMap root = yamlDoc.contents as YamlMap;
final YamlList targets = root['targets'] as YamlList;
return targets.nodes.map((YamlNode node) {
return _CiYamlTarget.fromYamlMap(node as YamlMap);
}).toList();
}
/// Name of the target.
final String name;
/// Where the target was parsed at in the `.ci.yaml` file.
final SourceSpan span;
/// Which lines were present in a `runIf` block, if any.
final List<String>? runIf;
}