Skip to content
This repository was archived by the owner on Apr 7, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions packages/globe_cli/lib/src/commands/create_project_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import 'package:mason_logger/mason_logger.dart';
import 'package:path/path.dart' as p;
import '../command.dart';

const _templateRepo = 'https://github.com/invertase/globe';

class CreateProjectFromTemplate extends BaseGlobeCommand {
CreateProjectFromTemplate() {
argParser.addOption(
Expand Down Expand Up @@ -73,7 +75,7 @@ class CreateProjectFromTemplate extends BaseGlobeCommand {
// Initialize a new Git repository
await _runGitCommand(['init'], processWorkingDir: directory.path);
await _runGitCommand(
const ['remote', 'add', 'origin', 'https://github.com/invertase/globe'],
const ['remote', 'add', 'origin', _templateRepo],
processWorkingDir: directory.path,
);

Expand Down Expand Up @@ -106,11 +108,32 @@ class CreateProjectFromTemplate extends BaseGlobeCommand {
throw Exception('Template: $template does not exist');
}

await _copyPath(
templateDir.path,
final projectDir = Directory(
p.join(Directory.current.path, projectDirName),
);

await _copyPath(templateDir.path, projectDir.path);

// set current directory to the new project directory
Directory.current = projectDir;

scope.setTemplatePath(template, _templateRepo);

progress.complete('Project created successfully.');

// add next steps and let user to run globe deploy
logger.info('');
logger.info(styleBold.wrap('🚀 Next steps'));
logger.info('────────────────────────────────────────');
logger.info(' 1. Navigate to your project');
logger.info(' ${cyan.wrap('cd $projectDirName')}');
logger.info('');
logger.info(' 2. Deploy your project');
logger.info(' ${cyan.wrap('globe deploy')}');
logger.info('');
logger.info('${lightGray.wrap('✨ Happy building with Globe!')}');
logger.info('');

return ExitCode.success.code;
} on ProcessException catch (e) {
progress.fail('Failed to create project from template.');
Expand Down
6 changes: 6 additions & 0 deletions packages/globe_cli/lib/src/utils/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:get_it/get_it.dart';
import 'package:http/http.dart' as http;
import 'package:mason_logger/mason_logger.dart';
import 'package:path/path.dart';
Expand Down Expand Up @@ -39,6 +40,7 @@ class GlobeApi {
Map<String, String> get headers {
final currentSession = auth.currentSession;
final currentScope = GlobeScope.value;
final templateInfo = GetIt.instance.get<GlobeScope>().templateInfo;

return {
'X-Globe-Platform': 'globe_cli',
Expand All @@ -48,6 +50,10 @@ class GlobeApi {
'X-Globe-Project-Id': currentScope.projectId,
'X-Globe-Project-Slug': currentScope.projectSlug,
},
if (templateInfo != null) ...{
'X-Globe-Template-Id': templateInfo.$1,
'X-Globe-Template-Source': templateInfo.$2,
},
if (currentSession != null &&
currentSession.authenticationMethod == AuthenticationMethod.jwt)
'Authorization': 'Bearer ${currentSession.jwt}',
Expand Down
2 changes: 2 additions & 0 deletions packages/globe_cli/lib/src/utils/metadata.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class GlobeMetadata {
String get projectFileName =>
_isLocal ? 'project.local.json' : 'project.json';

static const String templateFileName = '.template';

String get sessionFileName =>
_isLocal ? 'dart_globe_auth.local.json' : 'dart_globe_auth.json';

Expand Down
31 changes: 23 additions & 8 deletions packages/globe_cli/lib/src/utils/scope.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ class GlobeScope {
required this.metadata,
});

File get _projectFile {
return File(
p.join(
_projectDirectory.path,
metadata.projectFileName,
),
);
}
late final _projectFile = File(
p.join(_projectDirectory.path, metadata.projectFileName),
);

late final _maybeTemplateFile = File(
p.join(_projectDirectory.path, GlobeMetadata.templateFileName),
);

late final List<ScopeMetadata> workspace;

Expand Down Expand Up @@ -59,6 +58,22 @@ class GlobeScope {
..writeAsStringSync(const JsonEncoder.withIndent(' ').convert(workspace));
}

void setTemplatePath(String templateName, String templateRepoUrl) {
_maybeTemplateFile
..createSync(recursive: true)
..writeAsStringSync('$templateName\n$templateRepoUrl');
}

// First param is template name, second param is template repo url
(String, String)? get templateInfo {
if (!_maybeTemplateFile.existsSync()) return null;

final template = _maybeTemplateFile.readAsLinesSync();
if (template.isEmpty) return null;

return (template[0], template[1]);
}

/// Sets the current project scope.
ScopeMetadata setScope(ScopeMetadata scope) {
workspace
Expand Down
Loading