runFlashDsl function
Future<DslRunResult>
runFlashDsl(
- void builder(
- App app
- String? apiKey,
- String? baseUrl,
- String? projectName,
- String? projectId,
- bool findOrCreate = false,
- bool allowNewProject = false,
- bool dryRun = false,
- String? commitMessage,
- PipelineSource? source,
- bool validationFilter(
- ProjectError error
- bool refreshContext = false,
- String? contextDir,
- void logger(
- String message
- @visibleForTesting Flash? sdk,
- @visibleForTesting Future<
List< validateOverride()?,ProjectError> > - @visibleForTesting Future<
GeneratedCodeSnapshotExportResult> generatedCodeSnapshotExporter(})?,
Builds, compiles, validates, and pushes a DSL app to FlutterFlow.
Resolution order:
apiKey,baseUrl,projectName,projectId,commitMessage- current-directory
.env - process environment
- inferred project name from the DSL app
Implementation
Future<DslRunResult> runFlashDsl(
void Function(App app) builder, {
String? apiKey,
String? baseUrl,
String? projectName,
String? projectId,
bool findOrCreate = false,
bool allowNewProject = false,
bool dryRun = false,
String? commitMessage,
PipelineSource? source,
bool Function(ProjectError error)? validationFilter,
bool refreshContext = false,
String? contextDir,
void Function(String message)? logger,
@visibleForTesting Flash? sdk,
@visibleForTesting
Future<List<ProjectError>> Function(FFProject)? validateOverride,
@visibleForTesting
Future<GeneratedCodeSnapshotExportResult> Function(
String workspacePath, {
required String projectId,
required String? apiKey,
required String? baseUrl,
SnapshotLogger? infoLogger,
SnapshotLogger? warningLogger,
})?
generatedCodeSnapshotExporter,
}) async {
final log = logger ?? _defaultLogger;
final app = App();
builder(app);
final env = loadMergedEnv();
// Use validating resolvers so blank explicit values throw ConfigException
// instead of being silently treated as missing.
final resolvedApiKey = resolveApiKey(flagValue: apiKey, env: env);
final resolvedBaseUrl = resolveBaseUrl(flagValue: baseUrl, env: env);
final resolvedProjectId = projectId ?? env['FF_DSL_PROJECT_ID'];
final resolvedProjectName =
projectName ?? env['FF_DSL_PROJECT_NAME'] ?? _inferProjectName(app);
final resolvedFindOrCreate =
findOrCreate || _parseBool(env['FF_DSL_FIND_OR_CREATE']);
final resolvedAllowNewProject =
allowNewProject || _parseBool(env['FF_DSL_ALLOW_NEW_PROJECT']);
final resolvedDryRun = dryRun || _parseBool(env['FF_DSL_DRY_RUN']);
final resolvedCommitMessage =
commitMessage ??
env['FF_DSL_COMMIT_MESSAGE'] ??
'Compile $resolvedProjectName from Flash DSL';
final resolvedSource = source ?? _defaultSource();
if (sdk == null && (resolvedApiKey == null || resolvedApiKey.isEmpty)) {
throw ConfigException(
'FF_API_KEY is not set. Pass apiKey: or set FF_API_KEY in the '
'environment or .env file.',
);
}
final compileTask = _CompileDslTask(app);
final workspaceState = readWorkspaceState(directory: contextDir);
final wasUnboundWorkspace = workspaceState?.projectId == null;
if (workspaceState?.projectId case final workspaceProjectId?) {
log('Workspace binding: $workspaceProjectId.');
}
final pipelineProject = _resolveProjectTarget(
projectId: resolvedProjectId,
projectName: resolvedProjectName,
findOrCreate: resolvedFindOrCreate,
);
log(
'Resolved target mode: ${_projectTargetMode(pipelineProject)} '
'(${_describeProjectTarget(pipelineProject)}).',
);
final pipelineResult =
await FlashPipeline(
apiKey: resolvedApiKey,
baseUrl: resolvedBaseUrl,
project: pipelineProject,
tasks: [compileTask],
source: resolvedSource,
commitMessage: resolvedCommitMessage,
dryRun: resolvedDryRun,
allowNewProject: resolvedAllowNewProject,
validationFilter: validationFilter,
refreshContext: refreshContext,
contextDir: contextDir,
// ignore: invalid_use_of_visible_for_testing_member
sdk: sdk,
// ignore: invalid_use_of_visible_for_testing_member
validateOverride: validateOverride,
).run();
for (final task in pipelineResult.taskResults) {
log(task.summary);
}
if (!pipelineResult.success ||
(!pipelineResult.dryRun && !pipelineResult.pushed)) {
throw DslRunException(pipelineResult);
}
final compileResult = compileTask.compileResult;
if (compileResult == null) {
throw StateError(
'Flash DSL pipeline succeeded without producing a compile result.',
);
}
final result = DslRunResult(
app: app,
compileResult: compileResult,
projectId: pipelineResult.projectId,
commitId: pipelineResult.commitId,
pushed: pipelineResult.pushed,
dryRun: pipelineResult.dryRun,
taskSummaries: List.unmodifiable(
pipelineResult.taskResults.map((task) => task.summary),
),
);
if (!result.dryRun && result.pushed && wasUnboundWorkspace) {
final exportResult = await (generatedCodeSnapshotExporter ??
maybeExportGeneratedCodeSnapshot)(
contextDir ?? Directory.current.path,
projectId: result.projectId,
apiKey: resolvedApiKey,
baseUrl: resolvedBaseUrl,
infoLogger: log,
warningLogger: log,
);
if (!exportResult.success) {
markGeneratedCodeStale(
projectId: result.projectId,
changeSummary: pipelineResult.changeSummary,
commitId: result.commitId,
directory: contextDir,
);
}
} else if (!result.dryRun && result.pushed) {
markGeneratedCodeStale(
projectId: result.projectId,
changeSummary: pipelineResult.changeSummary,
commitId: result.commitId,
directory: contextDir,
);
}
log(
result.dryRun
? 'Dry run succeeded for project ${result.projectId}.'
: 'Pushed project ${result.projectId}'
'${result.commitId == null ? '' : ' (commit ${result.commitId})'}.',
);
return result;
}