Skip to content

Commit aec7183

Browse files
authored
apps init: show template ref in header and clone spinner (#5249)
## Summary Removes the standalone `Using AppKit template version X` log line from `databricks apps init`. The resolved ref now appears: - On the interactive header (before the project-name prompt) as a dimmed `Template version 0.24.0` line, so the user can cancel before committing to a name. - On the clone spinner and done line as a suffix, e.g. `Cloning template (version 0.24.0)...` / `✔ Cloning template (version 0.24.0)`. The label tracks the source of the ref: | Invocation | Label | |---|---| | auto-resolved (default) / `--version X` | `version X` | | `--branch X` (default or custom template) | `branch X` | | `--template URL` with no branch | (no label) | On a fallback to the embedded AppKit version, the spinner reflects the version actually cloned. **Before** <img width="409" height="102" alt="image" src="https://github.com/user-attachments/assets/910e3685-93e7-4adb-9afd-9d547ca4d64b" /> **After** <img width="306" height="56" alt="image" src="https://github.com/user-attachments/assets/05755405-2874-4ad3-899d-0f7ad405f71c" /> <img width="436" height="162" alt="image" src="https://github.com/user-attachments/assets/23d25c7d-25fd-4c83-9043-6f2c1004ebe6" /> ## Test plan - [x] `dbs apps init --name foo` — version appears on the spinner, not as a separate line - [x] `dbs apps init` (interactive) — header shows the version before the name prompt; cancel before naming works - [x] `dbs apps init --version 0.23.0 --name foo` — spinner shows `(version 0.23.0)` - [x] `dbs apps init --branch some-branch --name foo` — spinner shows `(branch some-branch)` - [x] `dbs apps init --template <URL> --name foo` — no ref label (current behavior preserved)
1 parent f961293 commit aec7183

2 files changed

Lines changed: 43 additions & 12 deletions

File tree

cmd/apps/init.go

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ func cloneRepo(ctx context.Context, repoURL, branch string) (string, error) {
548548
// Used by commands that don't benefit from background cloning (e.g., manifest).
549549
func resolveTemplate(ctx context.Context, templatePath, branch, subdir string) (string, func(), error) {
550550
ch := resolveTemplateAsync(ctx, templatePath, branch, subdir)
551-
return awaitTemplate(ctx, ch)
551+
return awaitTemplate(ctx, ch, "")
552552
}
553553

554554
// templateResult holds the outcome of a background template resolution.
@@ -599,18 +599,24 @@ func resolveTemplateAsync(ctx context.Context, templatePath, branch, subdir stri
599599
// awaitTemplate waits for the background clone to finish.
600600
// If the result is already available it returns immediately with a
601601
// checkmark; otherwise it shows a spinner while waiting.
602-
func awaitTemplate(ctx context.Context, ch <-chan templateResult) (string, func(), error) {
602+
// refLabel, if non-empty (e.g. "version 0.24.0" or "branch feature-x"),
603+
// is appended to spinner and done messages.
604+
func awaitTemplate(ctx context.Context, ch <-chan templateResult, refLabel string) (string, func(), error) {
605+
suffix := ""
606+
if refLabel != "" {
607+
suffix = " (" + refLabel + ")"
608+
}
603609
select {
604610
case res := <-ch:
605611
// Clone finished while the user was typing — print completion.
606612
if res.err == nil && res.cleanup != nil {
607-
prompt.PrintDone(ctx, "Template cloned")
613+
prompt.PrintDone(ctx, "Template cloned"+suffix)
608614
}
609615
return res.path, res.cleanup, res.err
610616
default:
611617
// Still cloning — show a spinner for the remaining wait.
612618
var res templateResult
613-
err := prompt.RunWithSpinnerCtx(ctx, "Cloning template...", func() error {
619+
err := prompt.RunWithSpinnerCtx(ctx, "Cloning template"+suffix+"...", func() error {
614620
res = <-ch
615621
return res.err
616622
})
@@ -808,25 +814,36 @@ func runCreate(ctx context.Context, opts createOptions) error {
808814
templateSrc = env.Get(ctx, templatePathEnvVar)
809815
}
810816

811-
// Resolve the git reference (branch/tag) to use for default appkit template
817+
// Resolve the git reference (branch/tag) to use for default appkit template.
818+
// refLabel is a human-readable description of the ref we're cloning
819+
// (e.g. "version 0.24.0", "branch feature-x"). It's surfaced in the
820+
// interactive header and the clone spinner so the user can cancel before
821+
// naming the project. Empty when there's nothing meaningful to show
822+
// (e.g. a custom --template URL with no explicit branch).
812823
gitRef := opts.branch
824+
var refLabel string
813825
usingDefaultTemplate := templateSrc == ""
814826
if usingDefaultTemplate {
815827
// Using default appkit template - resolve version
816828
switch {
817829
case opts.branch != "":
818830
// --branch takes precedence (already set in gitRef)
831+
refLabel = "branch " + opts.branch
819832
case opts.version != "":
820833
gitRef = normalizeVersion(opts.version)
834+
refLabel = "version " + opts.version
821835
default:
822-
appkitVersion, err := clicompat.ResolveAppKitVersion(ctx)
836+
resolved, err := clicompat.ResolveAppKitVersion(ctx)
823837
if err != nil {
824838
return fmt.Errorf("could not resolve AppKit template version: %w; use --version to specify a version manually", err)
825839
}
826-
gitRef = normalizeVersion(appkitVersion)
827-
cmdio.LogString(ctx, "Using AppKit template version "+appkitVersion)
840+
gitRef = normalizeVersion(resolved)
841+
refLabel = "version " + resolved
828842
}
829843
templateSrc = appkitRepoURL
844+
} else if opts.branch != "" {
845+
// Custom template with an explicit branch — show it for traceability.
846+
refLabel = "branch " + opts.branch
830847
}
831848

832849
// Start cloning in the background so it runs while the user types the name.
@@ -880,6 +897,11 @@ func runCreate(ctx context.Context, opts createOptions) error {
880897
if !isInteractive {
881898
return errors.New("--name is required in non-interactive mode")
882899
}
900+
// Print the AppKit header once so it covers both the in-place
901+
// scaffold-location prompt below and the project-name prompt that
902+
// may follow, and so the resolved template ref is visible before
903+
// the user commits to either path.
904+
prompt.PrintHeader(ctx, refLabel)
883905
// Offer in-place scaffolding when the current directory is empty
884906
// (modulo .git) and its basename is a valid app name. Skipped when
885907
// --output-dir was set, since in-place targets cwd and would silently
@@ -927,7 +949,7 @@ func runCreate(ctx context.Context, opts createOptions) error {
927949
}
928950

929951
// Step 2: Wait for template (may already be done if the user took time typing the name)
930-
resolvedPath, cleanup, err := awaitTemplate(ctx, templateCh)
952+
resolvedPath, cleanup, err := awaitTemplate(ctx, templateCh, refLabel)
931953
// Only fall back to the embedded version when the version was auto-resolved
932954
// from the manifest, not when the user explicitly passed --version or --branch.
933955
versionAutoResolved := opts.version == "" && opts.branch == ""
@@ -937,7 +959,8 @@ func runCreate(ctx context.Context, opts createOptions) error {
937959
log.Warnf(ctx, "Template version not found, falling back to embedded version %s", fallbackVersion)
938960
fallbackRef := normalizeVersion(fallbackVersion)
939961
templateCh = resolveTemplateAsync(ctx, templateSrc, fallbackRef, appkitTemplateDir)
940-
resolvedPath, cleanup, err = awaitTemplate(ctx, templateCh)
962+
refLabel = "version " + fallbackVersion
963+
resolvedPath, cleanup, err = awaitTemplate(ctx, templateCh, refLabel)
941964
} else if fbErr != nil {
942965
log.Warnf(ctx, "Could not resolve embedded AppKit version: %v", fbErr)
943966
}

libs/apps/prompt/prompt.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,10 @@ func ShouldOfferInPlace(cwd string) (string, bool) {
233233
}
234234

235235
// PrintHeader prints the AppKit header banner.
236-
func PrintHeader(ctx context.Context) {
236+
// If refLabel is non-empty (e.g. "version 0.24.0" or "branch feature-x"),
237+
// an extra dimmed line shows the resolved template ref so the user can
238+
// decide whether to continue before naming the project.
239+
func PrintHeader(ctx context.Context, refLabel string) {
237240
headerStyle := lipgloss.NewStyle().
238241
Foreground(colorRed).
239242
Bold(true)
@@ -244,6 +247,9 @@ func PrintHeader(ctx context.Context) {
244247
cmdio.LogString(ctx, "")
245248
cmdio.LogString(ctx, headerStyle.Render("◆ Create a new Databricks AppKit project"))
246249
cmdio.LogString(ctx, subtitleStyle.Render(" Full-stack TypeScript • React • Tailwind CSS"))
250+
if refLabel != "" {
251+
cmdio.LogString(ctx, subtitleStyle.Render(" Template "+refLabel))
252+
}
247253
cmdio.LogString(ctx, "")
248254
}
249255

@@ -282,8 +288,10 @@ func validateProjectNameForPrompt(s, outputDir string) error {
282288
// Used as the first step before resolving templates.
283289
// outputDir is used to check if the destination directory already exists,
284290
// and to reject the in-place sentinel "." when --output-dir is set.
291+
// The caller is responsible for printing the AppKit header before invoking
292+
// this function so the header also covers preceding prompts (e.g. the
293+
// in-place scaffold-location chooser).
285294
func PromptForProjectName(ctx context.Context, outputDir string) (string, error) {
286-
PrintHeader(ctx)
287295
theme := AppkitTheme()
288296

289297
var name string

0 commit comments

Comments
 (0)