Skip to content

Commit 84093ed

Browse files
committed
feat: add init manifest flag
1 parent 5e4bc81 commit 84093ed

4 files changed

Lines changed: 154 additions & 0 deletions

File tree

cmd/apps/apps.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const ManagementGroupID = "management"
1111
func Commands() []*cobra.Command {
1212
return []*cobra.Command{
1313
newInitCmd(),
14+
newManifestCmd(),
1415
newDevRemoteCmd(),
1516
newLogsCommand(),
1617
newRunLocal(),

cmd/apps/init.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package apps
33
import (
44
"bytes"
55
"context"
6+
"encoding/json"
67
"errors"
78
"fmt"
89
"os"
@@ -501,6 +502,64 @@ func resolveTemplate(ctx context.Context, templatePath, branch, subdir string) (
501502
return tempDir, cleanup, nil
502503
}
503504

505+
// runManifestOnly resolves the template, loads appkit.plugins.json if present, and prints it to stdout (or a message if not found).
506+
func runManifestOnly(ctx context.Context, templatePath, branch, version string) error {
507+
templateSrc := templatePath
508+
if templateSrc == "" {
509+
templateSrc = os.Getenv(templatePathEnvVar)
510+
}
511+
gitRef := branch
512+
usingDefaultTemplate := templateSrc == ""
513+
if usingDefaultTemplate {
514+
switch {
515+
case branch != "":
516+
case version != "":
517+
gitRef = normalizeVersion(version)
518+
default:
519+
gitRef = appkitDefaultBranch
520+
}
521+
templateSrc = appkitRepoURL
522+
}
523+
524+
branchForClone := branch
525+
subdirForClone := ""
526+
if usingDefaultTemplate {
527+
branchForClone = gitRef
528+
subdirForClone = appkitTemplateDir
529+
}
530+
resolvedPath, cleanup, err := resolveTemplate(ctx, templateSrc, branchForClone, subdirForClone)
531+
if err != nil {
532+
return err
533+
}
534+
if cleanup != nil {
535+
defer cleanup()
536+
}
537+
538+
templateDir := filepath.Join(resolvedPath, "generic")
539+
if _, err := os.Stat(templateDir); os.IsNotExist(err) {
540+
templateDir = resolvedPath
541+
if _, err := os.Stat(templateDir); os.IsNotExist(err) {
542+
return fmt.Errorf("template not found at %s (also checked %s/generic)", resolvedPath, resolvedPath)
543+
}
544+
}
545+
546+
if manifest.HasManifest(templateDir) {
547+
m, err := manifest.Load(templateDir)
548+
if err != nil {
549+
return fmt.Errorf("load manifest: %w", err)
550+
}
551+
enc, err := json.MarshalIndent(m, "", " ")
552+
if err != nil {
553+
return fmt.Errorf("encode manifest: %w", err)
554+
}
555+
fmt.Fprintln(os.Stdout, string(enc))
556+
return nil
557+
}
558+
559+
fmt.Fprintln(os.Stdout, "No appkit.plugins.json manifest found in this template.")
560+
return nil
561+
}
562+
504563
func runCreate(ctx context.Context, opts createOptions) error {
505564
var selectedPlugins []string
506565
var resourceValues map[string]string

cmd/apps/init_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package apps
22

33
import (
4+
"bytes"
45
"context"
56
"errors"
7+
"io"
8+
"os"
9+
"path/filepath"
610
"testing"
711

812
"github.com/databricks/cli/libs/apps/manifest"
@@ -453,3 +457,45 @@ func TestAppendUniqueNoValues(t *testing.T) {
453457
result := appendUnique([]string{"a", "b"})
454458
assert.Equal(t, []string{"a", "b"}, result)
455459
}
460+
461+
func TestRunManifestOnlyFound(t *testing.T) {
462+
dir := t.TempDir()
463+
manifestPath := filepath.Join(dir, manifest.ManifestFileName)
464+
content := `{"$schema":"https://example.com/schema","version":"1.0","plugins":{"analytics":{"name":"analytics","resources":{"required":[],"optional":[]}}}}`
465+
require.NoError(t, os.WriteFile(manifestPath, []byte(content), 0o644))
466+
467+
old := os.Stdout
468+
r, w, err := os.Pipe()
469+
require.NoError(t, err)
470+
os.Stdout = w
471+
472+
err = runManifestOnly(context.Background(), dir, "", "")
473+
w.Close()
474+
os.Stdout = old
475+
require.NoError(t, err)
476+
477+
var buf bytes.Buffer
478+
_, _ = io.Copy(&buf, r)
479+
out := buf.String()
480+
assert.Contains(t, out, `"version": "1.0"`)
481+
assert.Contains(t, out, `"analytics"`)
482+
}
483+
484+
func TestRunManifestOnlyNotFound(t *testing.T) {
485+
dir := t.TempDir()
486+
487+
old := os.Stdout
488+
r, w, err := os.Pipe()
489+
require.NoError(t, err)
490+
os.Stdout = w
491+
492+
err = runManifestOnly(context.Background(), dir, "", "")
493+
w.Close()
494+
os.Stdout = old
495+
require.NoError(t, err)
496+
497+
var buf bytes.Buffer
498+
_, _ = io.Copy(&buf, r)
499+
out := buf.String()
500+
assert.Equal(t, "No appkit.plugins.json manifest found in this template.\n", out)
501+
}

cmd/apps/manifest.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package apps
2+
3+
import (
4+
"errors"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
func newManifestCmd() *cobra.Command {
10+
var (
11+
templatePath string
12+
branch string
13+
version string
14+
)
15+
16+
cmd := &cobra.Command{
17+
Use: "manifest",
18+
Short: "Print the template's appkit.plugins.json manifest to stdout",
19+
Long: `Resolves a template (default AppKit repo or --template URL), locates appkit.plugins.json,
20+
and prints its contents to stdout. No workspace authentication is required.
21+
22+
Use the same --template, --branch, and --version flags as "databricks apps init" to target
23+
a specific template. Without --template, uses the default AppKit template (main branch).
24+
25+
Examples:
26+
# Default template manifest
27+
databricks apps manifest
28+
29+
# Specific version of default template
30+
databricks apps manifest --version v0.2.0
31+
32+
# Manifest from a GitHub repo
33+
databricks apps manifest --template https://github.com/user/repo --branch main`,
34+
Args: cobra.NoArgs,
35+
RunE: func(cmd *cobra.Command, args []string) error {
36+
ctx := cmd.Context()
37+
if cmd.Flags().Changed("branch") && cmd.Flags().Changed("version") {
38+
return errors.New("--branch and --version are mutually exclusive")
39+
}
40+
return runManifestOnly(ctx, templatePath, branch, version)
41+
},
42+
}
43+
44+
cmd.Flags().StringVar(&templatePath, "template", "", "Template path (local directory or GitHub URL)")
45+
cmd.Flags().StringVar(&branch, "branch", "", "Git branch or tag (for GitHub templates, mutually exclusive with --version)")
46+
cmd.Flags().StringVar(&version, "version", "", "AppKit version for default template (default: main, use 'latest' for main branch)")
47+
return cmd
48+
}

0 commit comments

Comments
 (0)