@@ -24,14 +24,33 @@ import (
2424)
2525
2626const (
27- templatePathEnvVar = "DATABRICKS_APPKIT_TEMPLATE_PATH"
28- defaultTemplateURL = "https://github.com/databricks/appkit/tree/main/template"
27+ templatePathEnvVar = "DATABRICKS_APPKIT_TEMPLATE_PATH"
28+ appkitRepoURL = "https://github.com/databricks/appkit"
29+ appkitTemplateDir = "template"
30+ appkitDefaultBranch = "main"
2931)
3032
33+ // normalizeVersion ensures the version string has a "v" prefix if it looks like a semver.
34+ // Examples: "0.3.0" -> "v0.3.0", "v0.3.0" -> "v0.3.0", "latest" -> "main"
35+ func normalizeVersion (version string ) string {
36+ if version == "" {
37+ return version
38+ }
39+ if version == "latest" {
40+ return appkitDefaultBranch
41+ }
42+ // If it starts with a digit, prepend "v"
43+ if len (version ) > 0 && version [0 ] >= '0' && version [0 ] <= '9' {
44+ return "v" + version
45+ }
46+ return version
47+ }
48+
3149func newInitCmd () * cobra.Command {
3250 var (
3351 templatePath string
3452 branch string
53+ version string
3554 name string
3655 warehouseID string
3756 description string
@@ -51,10 +70,19 @@ When run without arguments, uses the default AppKit template and an interactive
5170guides you through the setup. When run with --name, runs in non-interactive mode
5271(all required flags must be provided).
5372
73+ By default, the command uses the latest released version of AppKit. Use --version
74+ to specify a different version, or --version latest to use the main branch.
75+
5476Examples:
5577 # Interactive mode with default template (recommended)
5678 databricks apps init
5779
80+ # Use a specific AppKit version
81+ databricks apps init --version v0.2.0
82+
83+ # Use the latest development version (main branch)
84+ databricks apps init --version latest
85+
5886 # Non-interactive with flags
5987 databricks apps init --name my-app
6088
@@ -80,9 +108,16 @@ Environment variables:
80108 PreRunE : root .MustWorkspaceClient ,
81109 RunE : func (cmd * cobra.Command , args []string ) error {
82110 ctx := cmd .Context ()
111+
112+ // Validate mutual exclusivity of --branch and --version
113+ if cmd .Flags ().Changed ("branch" ) && cmd .Flags ().Changed ("version" ) {
114+ return errors .New ("--branch and --version are mutually exclusive" )
115+ }
116+
83117 return runCreate (ctx , createOptions {
84118 templatePath : templatePath ,
85119 branch : branch ,
120+ version : version ,
86121 name : name ,
87122 nameProvided : cmd .Flags ().Changed ("name" ),
88123 warehouseID : warehouseID ,
@@ -99,7 +134,8 @@ Environment variables:
99134 }
100135
101136 cmd .Flags ().StringVar (& templatePath , "template" , "" , "Template path (local directory or GitHub URL)" )
102- cmd .Flags ().StringVar (& branch , "branch" , "" , "Git branch or tag (for GitHub templates)" )
137+ cmd .Flags ().StringVar (& branch , "branch" , "" , "Git branch or tag (for GitHub templates, mutually exclusive with --version)" )
138+ cmd .Flags ().StringVar (& version , "version" , "" , "AppKit version to use (default: latest release, use 'latest' for main branch)" )
103139 cmd .Flags ().StringVar (& name , "name" , "" , "Project name (prompts if not provided)" )
104140 cmd .Flags ().StringVar (& warehouseID , "warehouse-id" , "" , "SQL warehouse ID" )
105141 cmd .Flags ().StringVar (& description , "description" , "" , "App description" )
@@ -114,6 +150,7 @@ Environment variables:
114150type createOptions struct {
115151 templatePath string
116152 branch string
153+ version string
117154 name string
118155 nameProvided bool // true if --name flag was explicitly set (enables "flags mode")
119156 warehouseID string
@@ -377,18 +414,23 @@ func cloneRepo(ctx context.Context, repoURL, branch string) (string, error) {
377414}
378415
379416// resolveTemplate resolves a template path, handling both local paths and GitHub URLs.
417+ // branch is used for cloning (can contain "/" for feature branches).
418+ // subdir is an optional subdirectory within the repo to use (for default appkit template).
380419// Returns the local path to use, a cleanup function (for temp dirs), and any error.
381- func resolveTemplate (ctx context.Context , templatePath , branch string ) (localPath string , cleanup func (), err error ) {
420+ func resolveTemplate (ctx context.Context , templatePath , branch , subdir string ) (localPath string , cleanup func (), err error ) {
382421 // Case 1: Local path - return as-is
383422 if ! strings .HasPrefix (templatePath , "https://" ) {
384423 return templatePath , nil , nil
385424 }
386425
387426 // Case 2: GitHub URL - parse and clone
388- repoURL , subdir , urlBranch := git .ParseGitHubURL (templatePath )
427+ repoURL , urlSubdir , urlBranch := git .ParseGitHubURL (templatePath )
389428 if branch == "" {
390429 branch = urlBranch // Use branch from URL if not overridden by flag
391430 }
431+ if subdir == "" {
432+ subdir = urlSubdir // Use subdir from URL if not overridden
433+ }
392434
393435 // Clone to temp dir with spinner
394436 var tempDir string
@@ -427,9 +469,22 @@ func runCreate(ctx context.Context, opts createOptions) error {
427469 if templateSrc == "" {
428470 templateSrc = os .Getenv (templatePathEnvVar )
429471 }
430- if templateSrc == "" {
431- // Use default template from GitHub
432- templateSrc = defaultTemplateURL
472+
473+ // Resolve the git reference (branch/tag) to use for default appkit template
474+ gitRef := opts .branch
475+ usingDefaultTemplate := templateSrc == ""
476+ if usingDefaultTemplate {
477+ // Using default appkit template - resolve version
478+ switch {
479+ case opts .branch != "" :
480+ // --branch takes precedence (already set in gitRef)
481+ case opts .version != "" :
482+ gitRef = normalizeVersion (opts .version )
483+ default :
484+ // Default: use main branch
485+ gitRef = appkitDefaultBranch
486+ }
487+ templateSrc = appkitRepoURL
433488 }
434489
435490 // Step 1: Get project name first (needed before we can check destination)
@@ -465,7 +520,15 @@ func runCreate(ctx context.Context, opts createOptions) error {
465520 }
466521
467522 // Step 2: Resolve template (handles GitHub URLs by cloning)
468- resolvedPath , cleanup , err := resolveTemplate (ctx , templateSrc , opts .branch )
523+ // For custom templates, --branch can override the URL's branch
524+ // For default appkit template, pass gitRef directly (supports branches with "/" in name)
525+ branchForClone := opts .branch
526+ subdirForClone := ""
527+ if usingDefaultTemplate {
528+ branchForClone = gitRef
529+ subdirForClone = appkitTemplateDir
530+ }
531+ resolvedPath , cleanup , err := resolveTemplate (ctx , templateSrc , branchForClone , subdirForClone )
469532 if err != nil {
470533 return err
471534 }
0 commit comments