Skip to content

Commit 7d15349

Browse files
committed
ci(cli): Re-enable E2E tests
1 parent 7af9370 commit 7d15349

22 files changed

+301
-153
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: celest_cli (E2E)
2+
on:
3+
pull_request:
4+
paths:
5+
- ".github/workflows/apps_cli_e2e.yaml"
6+
- "apps/cli/lib/src/version.dart"
7+
- "apps/cli/test/e2e/**"
8+
push:
9+
branches:
10+
- main
11+
paths:
12+
- "apps/cli/**"
13+
14+
# Prevent duplicate runs due to Graphite
15+
# https://graphite.dev/docs/troubleshooting#why-are-my-actions-running-twice
16+
concurrency:
17+
group: ${{ github.repository }}-${{ github.workflow }}-${{ github.ref }}-${{ github.ref == 'refs/heads/main' && github.sha || ''}}
18+
cancel-in-progress: true
19+
20+
# Uncomment if using self-hosted runners for consistency with other workflows which run setup-dart with OIDC enabled.
21+
# permissions:
22+
# contents: read
23+
# id-token: write
24+
25+
env:
26+
CELEST_LOCAL_PATH: ${{ github.workspace }}
27+
28+
jobs:
29+
test:
30+
strategy:
31+
fail-fast: false
32+
matrix:
33+
os:
34+
- ubuntu-large
35+
- macos-latest-xlarge
36+
- windows-large
37+
runs-on: ${{ matrix.os }}
38+
timeout-minutes: 30
39+
steps:
40+
- name: Git Checkout
41+
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # 4.1.7
42+
- name: Setup Flutter
43+
uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # 2.16.0
44+
with:
45+
cache: true
46+
- name: Setup Deps
47+
if: runner.os == 'Linux'
48+
run: tool/setup-ci.sh
49+
- name: Get Packages
50+
working-directory: apps/cli
51+
run: dart pub upgrade
52+
- name: Test
53+
working-directory: apps/cli
54+
run: dart test -t e2e-local --fail-fast

apps/cli/lib/src/commands/init_command.dart

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,15 @@ import 'package:celest_cli/src/init/project_init.dart';
77
import 'package:mason_logger/mason_logger.dart';
88

99
final class InitCommand extends CelestCommand with Configure, ProjectCreator {
10-
InitCommand();
10+
InitCommand() {
11+
argParser.addFlag(
12+
'precache',
13+
help: 'Precache assets and warm up analyzer in the background.',
14+
negatable: true,
15+
hide: true,
16+
defaultsTo: true,
17+
);
18+
}
1119

1220
@override
1321
String get description => 'Creates a new Celest project.';
@@ -32,18 +40,20 @@ final class InitCommand extends CelestCommand with Configure, ProjectCreator {
3240
'celest_cli:celest',
3341
'precache',
3442
projectPaths.projectRoot,
43+
if (verbose) '--verbose',
3544
],
3645
CliRuntime.local => <String>[
3746
platform.resolvedExecutable,
38-
'run',
3947
platform.script.toFilePath(),
4048
'precache',
4149
projectPaths.projectRoot,
50+
if (verbose) '--verbose',
4251
],
4352
CliRuntime.aot => <String>[
4453
platform.resolvedExecutable,
4554
'precache',
4655
projectPaths.projectRoot,
56+
if (verbose) '--verbose',
4757
],
4858
};
4959
try {
@@ -59,13 +69,17 @@ final class InitCommand extends CelestCommand with Configure, ProjectCreator {
5969
}
6070
}
6171

72+
bool get precache => argResults!.flag('precache');
73+
6274
@override
6375
Future<int> run() async {
6476
await super.run();
6577

6678
await checkForLatestVersion();
6779
await configure();
68-
await _precacheInBackground();
80+
if (precache) {
81+
await _precacheInBackground();
82+
}
6983

7084
final projectRoot = projectPaths.projectRoot;
7185

@@ -82,10 +96,10 @@ final class InitCommand extends CelestCommand with Configure, ProjectCreator {
8296
}
8397
stdout.writeln();
8498
cliLogger.success('🚀 To start a local development server, run:');
85-
stdout
86-
..writeln()
87-
..writeln(' $command')
88-
..writeln();
99+
cliLogger
100+
..write(Platform.lineTerminator)
101+
..write(' $command${Platform.lineTerminator}')
102+
..write(Platform.lineTerminator);
89103

90104
return 0;
91105
}

apps/cli/lib/src/commands/precache_command.dart

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import 'dart:isolate';
22

33
import 'package:celest_cli/src/analyzer/celest_analyzer.dart';
4+
import 'package:celest_cli/src/cli/cli.dart';
45
import 'package:celest_cli/src/commands/celest_command.dart';
6+
import 'package:celest_cli/src/context.dart' as ctx;
57
import 'package:celest_cli/src/context.dart';
68
import 'package:celest_cli/src/pub/pub_cache.dart';
79

@@ -10,7 +12,8 @@ final class PrecacheCommand extends CelestCommand {
1012
String get name => 'precache';
1113

1214
@override
13-
String get description => 'Precaches assets for a Celest Cloud project.';
15+
String get description =>
16+
'Precaches assets and warms up the analyzer for a Celest project.';
1417

1518
@override
1619
bool get hidden => true;
@@ -20,7 +23,12 @@ final class PrecacheCommand extends CelestCommand {
2023

2124
static Future<void> _warmUp() async {
2225
final projectRoot = projectPaths.projectRoot;
23-
await Isolate.run(() => CelestAnalyzer.warmUp(projectRoot));
26+
final verbose = ctx.verbose;
27+
await Isolate.run(() async {
28+
await Cli.configure(verbose: verbose);
29+
await init(projectRoot: projectRoot);
30+
await CelestAnalyzer.warmUp(projectRoot);
31+
});
2432
}
2533

2634
@override

apps/cli/lib/src/init/migrations/add_generated_folder.dart

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,29 @@
22

33
import 'package:celest_cli/src/context.dart';
44
import 'package:celest_cli/src/init/project_migration.dart';
5-
import 'package:file/file.dart';
65

76
final class GeneratedFolder extends ProjectMigration {
8-
const GeneratedFolder(super.projectRoot);
7+
GeneratedFolder(super.projectRoot);
8+
9+
late final _readmeFile = fileSystem
10+
.directory(projectRoot)
11+
.childDirectory('generated')
12+
.childFile('README.md');
913

1014
@override
11-
bool get needsMigration => false;
15+
bool get needsMigration => !_readmeFile.existsSync();
1216

1317
@override
1418
String get name => 'core.layout.generated';
1519

1620
@override
1721
Future<ProjectMigrationResult> create() async {
18-
final generatedDir =
19-
fileSystem.directory(projectRoot).childDirectory('generated');
20-
await _createIfNotExists(
21-
generatedDir.childFile('README.md'),
22-
generated_README,
23-
);
22+
await _readmeFile.create(recursive: true);
23+
await _readmeFile.writeAsString(generated_README);
2424
return const ProjectMigrationSuccess();
2525
}
2626
}
2727

28-
Future<void> _createIfNotExists(File file, String content) async {
29-
if (!file.existsSync()) {
30-
await file.create(recursive: true);
31-
await file.writeAsString(content);
32-
}
33-
}
34-
3528
const generated_README = '''
3629
# Generated Celest code
3730
@@ -40,6 +33,4 @@ your backend.
4033
4134
This code can be safely checked into version control, but it should not be
4235
modified directly.
43-
44-
It is planned to replace this directory with macros when they become stable.
4536
''';

apps/cli/lib/src/init/project_init.dart

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,13 @@ base mixin Configure on CelestCommand {
109109
currentProgress?.complete();
110110
currentProgress = cliLogger.progress('Generating project');
111111
case CreatedProject():
112-
currentProgress?.complete('Project successfully generated');
112+
currentProgress?.complete('Project generated successfully');
113113
currentProgress = null;
114114
case MigratingProject():
115115
currentProgress?.complete();
116116
currentProgress = cliLogger.progress('Migrating project');
117117
case MigratedProject():
118-
currentProgress?.complete('Project successfully migrated');
118+
currentProgress?.complete('Project migrated successfully');
119119
currentProgress = null;
120120
case Initialized(needsAnalyzerMigration: final needsMigration):
121121
currentProgress?.complete();
@@ -292,23 +292,24 @@ base mixin Configure on CelestCommand {
292292
// TODO(dnys1): Improve logic here so that we don't run pub upgrade if
293293
// the dependencies in the lockfile are already up to date.
294294
Future<void> _pubUpgrade() async {
295-
await Future.wait([
296-
runPub(
297-
action: PubAction.upgrade,
298-
workingDirectory: projectPaths.projectRoot,
299-
),
300-
runPub(
301-
action: PubAction.get,
302-
workingDirectory: projectPaths.clientRoot,
303-
),
304-
]);
295+
await runPub(
296+
action: PubAction.upgrade,
297+
workingDirectory: projectPaths.projectRoot,
298+
);
305299
// Run serially to avoid `flutter pub` locks.
306300
if (celestProject.parentProject case final parentProject?) {
307301
await runPub(
308-
exe: parentProject.type.name,
302+
exe: parentProject.type.executable,
309303
action: PubAction.get,
310304
workingDirectory: parentProject.path,
311305
);
312306
}
307+
308+
// Get dependencies in client so that the analyzer does not show red
309+
// everywhere, but ignore to avoid blocking the current command.
310+
runPub(
311+
action: PubAction.get,
312+
workingDirectory: projectPaths.clientRoot,
313+
).ignore();
313314
}
314315
}

apps/cli/lib/src/project/celest_project.dart

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import 'dart:io';
22
import 'dart:isolate';
33

44
import 'package:analyzer/dart/analysis/analysis_context.dart';
5-
import 'package:analyzer/dart/analysis/results.dart';
5+
import 'package:analyzer/dart/analysis/features.dart';
6+
import 'package:analyzer/dart/analysis/utilities.dart';
67
import 'package:analyzer/dart/ast/ast.dart';
78
import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
89
import 'package:analyzer/src/dart/analysis/byte_store.dart';
@@ -18,6 +19,7 @@ import 'package:celest_cli/src/env/env_manager.dart';
1819
import 'package:celest_cli/src/project/project_paths.dart';
1920
import 'package:celest_cli/src/pub/cached_pubspec.dart';
2021
import 'package:celest_cli/src/sdk/dart_sdk.dart';
22+
import 'package:celest_cli/src/utils/error.dart';
2123
import 'package:celest_cli/src/utils/run.dart';
2224
import 'package:logging/logging.dart';
2325
import 'package:meta/meta.dart';
@@ -225,36 +227,39 @@ final class CelestProject {
225227
// the project is generated.
226228
throw StateError('No project.dart file found in the project root.');
227229
}
228-
final projectLibrary = analysisContext.currentSession.getParsedLibrary(
229-
projectDart.path,
230+
231+
final parseResult = parseFile(
232+
path: projectDart.path,
233+
featureSet: FeatureSet.fromEnableFlags2(
234+
sdkLanguageVersion: Sdk.current.version,
235+
flags: _analysisOptions.enabledExperiments,
236+
),
237+
throwIfDiagnostics: true,
230238
);
231-
switch (projectLibrary) {
232-
case ParsedLibraryResult(:final units):
233-
final declarations = units
234-
.expand((unit) => unit.unit.declarations)
235-
.whereType<TopLevelVariableDeclaration>()
236-
.expand((declaration) => declaration.variables.variables);
237-
for (final declaration in declarations) {
238-
if (declaration.initializer
239-
case MethodInvocation(
240-
methodName: SimpleIdentifier(name: 'Project'),
241-
:final argumentList,
239+
final projectLibrary = parseResult.unit;
240+
241+
final declarations = projectLibrary.declarations
242+
.whereType<TopLevelVariableDeclaration>()
243+
.expand((declaration) => declaration.variables.variables);
244+
for (final declaration in declarations) {
245+
if (declaration.initializer
246+
case MethodInvocation(
247+
methodName: SimpleIdentifier(name: 'Project'),
248+
:final argumentList,
249+
)) {
250+
for (final argument in argumentList.arguments) {
251+
if (argument
252+
case NamedExpression(
253+
name: Label(label: SimpleIdentifier(name: 'name')),
254+
expression: SimpleStringLiteral(value: final projectName),
242255
)) {
243-
for (final argument in argumentList.arguments) {
244-
if (argument
245-
case NamedExpression(
246-
name: Label(label: SimpleIdentifier(name: 'name')),
247-
expression: SimpleStringLiteral(value: final projectName),
248-
)) {
249-
return projectName;
250-
}
251-
}
256+
return projectName;
252257
}
253258
}
254-
throw StateError('No Project(name: "name") found in project.dart');
255-
default:
256-
throw StateError('Failed to parse project.dart');
259+
}
257260
}
261+
262+
throw StateError('No Project(name: "name") found in project.dart');
258263
}
259264

260265
Future<void> close() async {
@@ -291,3 +296,11 @@ extension CelestProjectUriStorage on IsolatedNativeStorage {
291296
return uri;
292297
}
293298
}
299+
300+
extension SdkExe on SdkType {
301+
String get executable => switch (this) {
302+
SdkType.dart => Sdk.current.dart,
303+
SdkType.flutter => Sdk.current.flutter!,
304+
_ => unreachable(),
305+
};
306+
}

apps/cli/lib/src/pub/pub_action.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:async';
22

33
import 'package:celest_cli/src/context.dart';
44
import 'package:celest_cli/src/exceptions.dart';
5+
import 'package:celest_cli/src/project/celest_project.dart';
56
import 'package:celest_cli/src/sdk/dart_sdk.dart';
67
import 'package:celest_core/_internal.dart';
78
import 'package:cli_script/cli_script.dart';
@@ -48,8 +49,8 @@ Future<void> runPub({
4849
required String workingDirectory,
4950
}) async {
5051
exe ??= kDebugMode
51-
? platform.resolvedExecutable
52-
: (await celestProject.determineProjectType()).name;
52+
? Sdk.current.dart
53+
: (await celestProject.determineProjectType()).executable;
5354

5455
final command = <String>[exe, 'pub', action.name];
5556
final logger = Logger(command.join(' '));

apps/cli/lib/src/sdk/dart_sdk.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ class Sdk {
9999

100100
String get dart => p.join(sdkPath, 'bin', 'dart');
101101

102+
String? get flutter {
103+
if (flutterSdkRoot case final flutterRoot?) {
104+
return p.join(flutterRoot, 'bin', 'flutter');
105+
}
106+
return null;
107+
}
108+
102109
String get dartAotRuntime => p.join(sdkPath, 'bin', 'dartaotruntime');
103110

104111
String get analysisServerSnapshot =>

0 commit comments

Comments
 (0)