Skip to content
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
55 changes: 0 additions & 55 deletions cmd/sync/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"github.com/launchdarkly/ldcli/internal/output"
"github.com/launchdarkly/ldcli/internal/resources"
syncdomain "github.com/launchdarkly/ldcli/internal/sync"
synclink "github.com/launchdarkly/ldcli/internal/sync/link"
syncprompt "github.com/launchdarkly/ldcli/internal/sync/prompt"
)

Expand Down Expand Up @@ -68,7 +67,6 @@ func NewPromptCmd(client resources.Client) *cobra.Command {
newAddCmd(client),
newAttachCmd(client),
newDetachCmd(client),
newLinkCmd(client),
)
cmd.SetUsageTemplate(resourcescmd.SubcommandUsageTemplate())

Expand Down Expand Up @@ -270,37 +268,6 @@ func newDetachCmd(client resources.Client) *cobra.Command {
return cmd
}

func newLinkCmd(client resources.Client) *cobra.Command {
cmd := &cobra.Command{
Use: "link <file>",
Short: "Link an external prompt file",
Example: ` # Link a Markdown file as a new variation
ldcli sync prompts link prompts/support.md \
--format plain-markdown \
--to production/support/default \
--model-config-key claude \
--yes --no-input`,
Args: validatedArgs(cobra.ExactArgs(1)),
RunE: runCommand(client, syncdomain.ScopePrompts, func(cmd *cobra.Command, args []string) (syncprompt.CommandAction, error) {
format, _ := cmd.Flags().GetString(formatFlag)
target, err := linkTarget(cmd)
if err != nil {
return nil, err
}
return syncprompt.LinkAction{File: args[0], Format: format, ProjectKey: targetFilter(cmd).Project, Target: target}, nil
}),
}
addTargetFlags(cmd, targetFlagHelp{project: questionFlagHelp.project})
cmd.Flags().String(formatFlag, "", "Format adapter (for example, plain-markdown)")
cmd.Flags().String(toFlag, "", "New variation (project-key/config-key/variation-key)")
cmd.Flags().String(modelConfigKeyFlag, "", "Model config key for the new variation")
cmd.Flags().String(nameFlag, "", "Variation name when absent from the linked file")
cmd.Flags().String(contentFlag, "", "Prompt content when absent from the linked file")
_ = cmd.MarkFlagRequired(formatFlag)
addApplyFlags(cmd, syncdomain.ScopePrompts, false)
return cmd
}

// addApplyFlags registers the flags of a command that applies a plan. Only
// the prompts scope has --resolve, which names variations.
func addApplyFlags(cmd *cobra.Command, scope syncdomain.Scope, dryRun bool) {
Expand Down Expand Up @@ -434,28 +401,6 @@ func optionalVariationFlag(cmd *cobra.Command, name string) (*syncdomain.Resourc
return &variation, nil
}

func linkTarget(cmd *cobra.Command) (*synclink.Target, error) {
variation, err := optionalVariationFlag(cmd, toFlag)
if err != nil {
return nil, err
}
modelConfig, _ := cmd.Flags().GetString(modelConfigKeyFlag)
name, _ := cmd.Flags().GetString(nameFlag)
content, _ := cmd.Flags().GetString(contentFlag)
if variation == nil {
if modelConfig != "" || name != "" || content != "" {
return nil, fmt.Errorf("--model-config-key, --name, and --content require --to")
}
return nil, nil
}
return &synclink.Target{
Variation: *variation,
ModelConfigKey: modelConfig,
Name: name,
Content: content,
}, nil
}

func conflictPolicy(cmd *cobra.Command) (syncprompt.ConflictPolicy, error) {
var policy syncprompt.ConflictPolicy
if cmd.Flags().Lookup(conflictFlag) == nil {
Expand Down
10 changes: 2 additions & 8 deletions cmd/sync/prompt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,17 @@ func TestPromptCommandUsesActionSubcommands(t *testing.T) {
command := NewPromptCmd(nil)

assert.Equal(t, "prompts", command.Use)
for _, name := range []string{"watch", "add", "attach", "detach", "link"} {
for _, name := range []string{"watch", "add", "attach", "detach"} {
child, _, err := command.Find([]string{name})
require.NoError(t, err)
assert.Equal(t, name, child.Name())
}
for _, name := range []string{"add", "attach-tool", "attach-skill", "detach", "link", "watch"} {
for _, name := range []string{"add", "attach-tool", "attach-skill", "detach", "watch"} {
assert.Nil(t, command.Flags().Lookup(name), "legacy --%s should not exist", name)
}
add, _, err := command.Find([]string{"add"})
require.NoError(t, err)
assert.Equal(t, "add [project-key/config-key/variation-key...]", add.Use)
link, _, err := command.Find([]string{"link"})
require.NoError(t, err)
assert.NotNil(t, link.Flags().Lookup(modelConfigKeyFlag))
assert.Nil(t, link.Flags().Lookup("model-config"))
}

func TestSyncCommandIncludesExamples(t *testing.T) {
Expand All @@ -57,7 +53,6 @@ func TestPromptCommandHelpIncludesExamples(t *testing.T) {
"attach tool": {"attach", "tool"},
"attach skill": {"attach", "skill"},
"detach": {"detach"},
"link": {"link"},
}

for name, path := range tests {
Expand Down Expand Up @@ -112,7 +107,6 @@ func TestPromptCommandsRegisterTargetFlags(t *testing.T) {
"add": {path: []string{"add"}, help: questionFlagHelp},
"detach": {path: []string{"detach"}, help: questionFlagHelp},
"attach tool": {path: []string{"attach", "tool"}, help: targetFlagHelp{project: questionFlagHelp.project}},
"link": {path: []string{"link"}, help: targetFlagHelp{project: questionFlagHelp.project}},
}

for name, test := range tests {
Expand Down
25 changes: 9 additions & 16 deletions cmd/sync/scope_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,14 @@ var syncCommandFlags = map[string][]string{
"sync prompts attach tool": {"conflict", "diff", "no-input", "project", "resolve", "to", "yes"},
"sync prompts attach skill": {"conflict", "diff", "no-input", "project", "resolve", "to", "yes"},
"sync prompts detach": {"archive", "config-key", "key", "no-input", "project", "yes"},
"sync prompts link": {
"conflict", "content", "diff", "format", "model-config-key", "name", "no-input", "project", "resolve", "to", "yes",
},
"sync tools": {"conflict", "diff", "dry-run", "key", "no-input", "project", "yes"},
"sync tools watch": {"conflict", "diff", "key", "no-input", "project", "yes"},
"sync tools add": {"description", "diff", "dry-run", "json-schema", "key", "no-input", "project", "yes"},
"sync tools detach": {"key", "no-input", "project", "yes"},
"sync skills": {"conflict", "diff", "dry-run", "key", "no-input", "project", "yes"},
"sync skills watch": {"conflict", "diff", "key", "no-input", "project", "yes"},
"sync skills add": {"content", "description", "diff", "dry-run", "key", "name", "no-input", "project", "yes"},
"sync skills detach": {"key", "no-input", "project", "yes"},
"sync tools": {"conflict", "diff", "dry-run", "key", "no-input", "project", "yes"},
"sync tools watch": {"conflict", "diff", "key", "no-input", "project", "yes"},
"sync tools add": {"description", "diff", "dry-run", "json-schema", "key", "no-input", "project", "yes"},
"sync tools detach": {"key", "no-input", "project", "yes"},
"sync skills": {"conflict", "diff", "dry-run", "key", "no-input", "project", "yes"},
"sync skills watch": {"conflict", "diff", "key", "no-input", "project", "yes"},
"sync skills add": {"content", "description", "diff", "dry-run", "key", "name", "no-input", "project", "yes"},
"sync skills detach": {"key", "no-input", "project", "yes"},
}

func TestSyncCommandsHaveExactFlags(t *testing.T) {
Expand Down Expand Up @@ -75,11 +72,7 @@ func TestSyncCommandsReadSyncFlagsOnlyFromTheCommandLine(t *testing.T) {

for _, command := range runnableSyncCommands(NewSyncCmd(nil, nil)) {
require.NoError(t, command.ParseFlags(nil))
var args []string
if command.Name() == "link" {
args = []string{"prompt.md"}
}
require.NoError(t, command.Args(command, args), command.CommandPath())
require.NoError(t, command.Args(command, nil), command.CommandPath())
command.LocalNonPersistentFlags().VisitAll(func(flag *pflag.Flag) {
assert.False(t, flag.Changed, "%s --%s", command.CommandPath(), flag.Name)
})
Expand Down
43 changes: 0 additions & 43 deletions internal/sync/detach/detach_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
syncapi "github.com/launchdarkly/ldcli/internal/sync/api"
synclocal "github.com/launchdarkly/ldcli/internal/sync/local"
syncmanifest "github.com/launchdarkly/ldcli/internal/sync/manifest"
syncreference "github.com/launchdarkly/ldcli/internal/sync/reference"
)

func TestLoadResourcesUnionsLocalAndManifestResources(t *testing.T) {
Expand Down Expand Up @@ -97,48 +96,6 @@ func TestDetachResourcesKeepsAttachmentManifestEntries(t *testing.T) {
require.NoError(t, err, "the tool file stays")
}

func TestDetachResourcesRemovesWrapperAndManifestButKeepsReferencedFile(t *testing.T) {
root := t.TempDir()
referencePath := filepath.Join(root, "prompts", "prompt.md")
require.NoError(t, os.MkdirAll(filepath.Dir(referencePath), 0o755))
require.NoError(t, os.WriteFile(referencePath, []byte("Keep me.\n"), 0o644))

store := synclocal.NewStore(root)
variation := testVariation("prompt")
_, err := store.Add([]synclocal.VariationFile{{
ProjectKey: "project", ConfigKey: "config", Variation: variation,
Ref: &synclocal.Reference{File: "prompts/prompt.md", Format: syncreference.PlainMarkdown},
}})
require.NoError(t, err)

manifestStore := newMemoryManifestStore()
original := syncmanifest.Manifest{
Resources: []syncmanifest.Resource{{
ResourceKind: syncdomain.KindVariation, ProjectKey: "project", LookupKey: "config/prompt",
Fingerprint: testFingerprint(),
}},
}
require.NoError(t, manifestStore.Write(original))

resource := syncdomain.ResourceID{Kind: syncdomain.KindVariation, ProjectKey: "project", LookupKey: "config/prompt"}
err = detachResources(
Options{RepositoryRoot: root, Store: store, Baselines: manifestStore},
syncmanifest.Baseline{Lock: original},
[]syncdomain.ResourceID{resource},
)

require.NoError(t, err)
exists, err := store.VariationExists("project", "config", "prompt")
require.NoError(t, err)
assert.False(t, exists)
_, err = os.Stat(referencePath)
require.NoError(t, err)
baseline, err := manifestStore.Load([]string{"project"})
manifest := baseline.Lock
require.NoError(t, err)
assert.Empty(t, manifest.Resources)
}

func TestDetachResourcesRemovesManifestEntryWhenWrapperWasAlreadyDeleted(t *testing.T) {
root := t.TempDir()
store := synclocal.NewStore(root)
Expand Down
Loading
Loading